1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt for Python.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28
29 #include "typesystem.h"
30 #include "typedatabase.h"
31 #include "messages.h"
32 #include <QtCore/QDebug>
33 #include <QtCore/QRegularExpression>
34 #include <QtCore/QSet>
35
36 #include <algorithm>
37 #include <limits>
38
39 static QString strings_Object = QLatin1String("Object");
40 static QString strings_String = QLatin1String("String");
41 static QString strings_char = QLatin1String("char");
42 static QString strings_jchar = QLatin1String("jchar");
43 static QString strings_jobject = QLatin1String("jobject");
44
callOperator()45 static inline QString callOperator() { return QStringLiteral("operator()"); }
46
PrimitiveTypeEntry(const QString & entryName,const QVersionNumber & vr,const TypeEntry * parent)47 PrimitiveTypeEntry::PrimitiveTypeEntry(const QString &entryName, const QVersionNumber &vr,
48 const TypeEntry *parent) :
49 TypeEntry(entryName, PrimitiveType, vr, parent),
50 m_preferredTargetLangType(true)
51 {
52 }
53
targetLangApiName() const54 QString PrimitiveTypeEntry::targetLangApiName() const
55 {
56 return m_targetLangApiName;
57 }
58
basicReferencedTypeEntry() const59 PrimitiveTypeEntry *PrimitiveTypeEntry::basicReferencedTypeEntry() const
60 {
61 if (!m_referencedTypeEntry)
62 return nullptr;
63
64 PrimitiveTypeEntry *baseReferencedTypeEntry = m_referencedTypeEntry->basicReferencedTypeEntry();
65 return baseReferencedTypeEntry ? baseReferencedTypeEntry : m_referencedTypeEntry;
66 }
67
clone() const68 TypeEntry *PrimitiveTypeEntry::clone() const
69 {
70 return new PrimitiveTypeEntry(*this);
71 }
72
73 PrimitiveTypeEntry::PrimitiveTypeEntry(const PrimitiveTypeEntry &) = default;
74
codeSnips() const75 CodeSnipList TypeEntry::codeSnips() const
76 {
77 return m_codeSnips;
78 }
79
addExtraInclude(const Include & newInclude)80 void TypeEntry::addExtraInclude(const Include &newInclude)
81 {
82 if (!m_extraIncludes.contains(newInclude))
83 m_extraIncludes.append(newInclude);
84 }
85
accessModifierString() const86 QString Modification::accessModifierString() const
87 {
88 if (isPrivate()) return QLatin1String("private");
89 if (isProtected()) return QLatin1String("protected");
90 if (isPublic()) return QLatin1String("public");
91 if (isFriendly()) return QLatin1String("friendly");
92 return QString();
93 }
94
functionModifications(const QString & signature) const95 FunctionModificationList ComplexTypeEntry::functionModifications(const QString &signature) const
96 {
97 FunctionModificationList lst;
98 for (int i = 0; i < m_functionMods.count(); ++i) {
99 const FunctionModification &mod = m_functionMods.at(i);
100 if (mod.matches(signature))
101 lst << mod;
102 }
103 return lst;
104 }
105
fieldModification(const QString & name) const106 FieldModification ComplexTypeEntry::fieldModification(const QString &name) const
107 {
108 for (const auto &fieldMod : m_fieldMods) {
109 if (fieldMod.name == name)
110 return fieldMod;
111 }
112 FieldModification mod;
113 mod.name = name;
114 mod.modifiers = FieldModification::Readable | FieldModification::Writable;
115 return mod;
116 }
117
setDefaultConstructor(const QString & defaultConstructor)118 void ComplexTypeEntry::setDefaultConstructor(const QString& defaultConstructor)
119 {
120 m_defaultConstructor = defaultConstructor;
121 }
defaultConstructor() const122 QString ComplexTypeEntry::defaultConstructor() const
123 {
124 return m_defaultConstructor;
125 }
hasDefaultConstructor() const126 bool ComplexTypeEntry::hasDefaultConstructor() const
127 {
128 return !m_defaultConstructor.isEmpty();
129 }
130
clone() const131 TypeEntry *ComplexTypeEntry::clone() const
132 {
133 return new ComplexTypeEntry(*this);
134 }
135
136 // Take over parameters relevant for typedefs
useAsTypedef(const ComplexTypeEntry * source)137 void ComplexTypeEntry::useAsTypedef(const ComplexTypeEntry *source)
138 {
139 TypeEntry::useAsTypedef(source);
140 m_qualifiedCppName = source->m_qualifiedCppName;
141 m_targetType = source->m_targetType;
142 }
143
144 ComplexTypeEntry::ComplexTypeEntry(const ComplexTypeEntry &) = default;
145
qualifiedCppName() const146 QString ContainerTypeEntry::qualifiedCppName() const
147 {
148 if (m_containerKind == StringListContainer)
149 return QLatin1String("QStringList");
150 return ComplexTypeEntry::qualifiedCppName();
151 }
152
clone() const153 TypeEntry *ContainerTypeEntry::clone() const
154 {
155 return new ContainerTypeEntry(*this);
156 }
157
158 ContainerTypeEntry::ContainerTypeEntry(const ContainerTypeEntry &) = default;
159
targetLangQualifier() const160 QString EnumTypeEntry::targetLangQualifier() const
161 {
162 const QString q = qualifier();
163 if (!q.isEmpty()) {
164 if (auto te = TypeDatabase::instance()->findType(q))
165 return te->targetLangName();
166 }
167 return q;
168 }
169
qualifier() const170 QString EnumTypeEntry::qualifier() const
171 {
172 auto parentEntry = parent();
173 return parentEntry && parentEntry->type() != TypeEntry::TypeSystemType ?
174 parentEntry->name() : QString();
175 }
176
targetLangApiName() const177 QString EnumTypeEntry::targetLangApiName() const
178 {
179 return QLatin1String("jint");
180 }
181
targetLangApiName() const182 QString FlagsTypeEntry::targetLangApiName() const
183 {
184 return QLatin1String("jint");
185 }
186
clone() const187 TypeEntry *EnumTypeEntry::clone() const
188 {
189 return new EnumTypeEntry(*this);
190 }
191
192 EnumTypeEntry::EnumTypeEntry(const EnumTypeEntry &) = default;
193
clone() const194 TypeEntry *FlagsTypeEntry::clone() const
195 {
196 return new FlagsTypeEntry(*this);
197 }
198
199 FlagsTypeEntry::FlagsTypeEntry(const FlagsTypeEntry &) = default;
200
expandCode() const201 QString TemplateInstance::expandCode() const
202 {
203 TemplateEntry *templateEntry = TypeDatabase::instance()->findTemplate(m_name);
204 if (!templateEntry)
205 qFatal("<insert-template> referring to non-existing template '%s'.", qPrintable(m_name));
206
207 QString code = templateEntry->code();
208 for (auto it = replaceRules.cbegin(), end = replaceRules.cend(); it != end; ++it)
209 code.replace(it.key(), it.value());
210 while (!code.isEmpty() && code.at(code.size() - 1).isSpace())
211 code.chop(1);
212 QString result = QLatin1String("// TEMPLATE - ") + m_name + QLatin1String(" - START");
213 if (!code.startsWith(QLatin1Char('\n')))
214 result += QLatin1Char('\n');
215 result += code;
216 result += QLatin1String("\n// TEMPLATE - ") + m_name + QLatin1String(" - END\n");
217 return result;
218 }
219
220
code() const221 QString CodeSnipAbstract::code() const
222 {
223 QString res;
224 for (const CodeSnipFragment &codeFrag : codeList)
225 res.append(codeFrag.code());
226
227 return res;
228 }
229
addCode(const QString & code)230 void CodeSnipAbstract::addCode(const QString &code)
231 {
232 codeList.append(CodeSnipFragment(fixSpaces(code)));
233 }
234
235 template <class String> // QString, QStringRef
firstNonBlank(const String & s)236 static inline int firstNonBlank(const String &s)
237 {
238 const auto it = std::find_if(s.cbegin(), s.cend(),
239 [] (QChar c) { return !c.isSpace(); });
240 return int(it - s.cbegin());
241 }
242
243 template <class String> // QString, QStringRef
isEmpty(const String & s)244 static inline bool isEmpty(const String &s)
245 {
246 return s.isEmpty()
247 || std::all_of(s.cbegin(), s.cend(),
248 [] (QChar c) { return c.isSpace(); });
249 }
250
dedent(const QString & code)251 QString CodeSnipAbstract::dedent(const QString &code)
252 {
253 if (code.isEmpty())
254 return code;
255 // Right trim if indent=0, or trim if single line
256 if (!code.at(0).isSpace() || !code.contains(QLatin1Char('\n')))
257 return code.trimmed();
258 const auto lines = code.splitRef(QLatin1Char('\n'));
259 int spacesToRemove = std::numeric_limits<int>::max();
260 for (const auto &line : lines) {
261 if (!isEmpty(line)) {
262 const int nonSpacePos = firstNonBlank(line);
263 if (nonSpacePos < spacesToRemove)
264 spacesToRemove = nonSpacePos;
265 if (spacesToRemove == 0)
266 return code;
267 }
268 }
269 QString result;
270 for (const auto &line : lines) {
271 if (!isEmpty(line) && spacesToRemove < line.size())
272 result += line.mid(spacesToRemove).toString();
273 result += QLatin1Char('\n');
274 }
275 return result;
276 }
277
fixSpaces(QString code)278 QString CodeSnipAbstract::fixSpaces(QString code)
279 {
280 code.remove(QLatin1Char('\r'));
281 // Check for XML <tag>\n<space>bla...
282 if (code.startsWith(QLatin1String("\n ")))
283 code.remove(0, 1);
284 while (!code.isEmpty() && code.back().isSpace())
285 code.chop(1);
286 code = dedent(code);
287 if (!code.isEmpty() && !code.endsWith(QLatin1Char('\n')))
288 code.append(QLatin1Char('\n'));
289 return code;
290 }
291
292 // Prepend a line to the code, observing indentation
prependCode(QString * code,QString firstLine)293 void CodeSnipAbstract::prependCode(QString *code, QString firstLine)
294 {
295 while (!code->isEmpty() && code->front() == QLatin1Char('\n'))
296 code->remove(0, 1);
297 if (!code->isEmpty() && code->front().isSpace()) {
298 const int indent = firstNonBlank(*code);
299 firstLine.prepend(QString(indent, QLatin1Char(' ')));
300 }
301 if (!firstLine.endsWith(QLatin1Char('\n')))
302 firstLine += QLatin1Char('\n');
303 code->prepend(firstLine);
304 }
305
code() const306 QString CodeSnipFragment::code() const
307 {
308 return m_instance ? m_instance->expandCode() : m_code;
309 }
310
setSignature(const QString & s,QString * errorMessage)311 bool FunctionModification::setSignature(const QString &s, QString *errorMessage)
312 {
313 if (s.startsWith(QLatin1Char('^'))) {
314 m_signaturePattern.setPattern(s);
315 if (!m_signaturePattern.isValid()) {
316 if (errorMessage) {
317 *errorMessage = QLatin1String("Invalid signature pattern: \"")
318 + s + QLatin1String("\": ") + m_signaturePattern.errorString();
319 }
320 return false;
321 }
322 } else {
323 m_signature = s;
324 }
325 return true;
326 }
327
toString() const328 QString FunctionModification::toString() const
329 {
330 QString str = signature() + QLatin1String("->");
331 if (modifiers & AccessModifierMask) {
332 switch (modifiers & AccessModifierMask) {
333 case Private: str += QLatin1String("private"); break;
334 case Protected: str += QLatin1String("protected"); break;
335 case Public: str += QLatin1String("public"); break;
336 case Friendly: str += QLatin1String("friendly"); break;
337 }
338 }
339
340 if (modifiers & Final) str += QLatin1String("final");
341 if (modifiers & NonFinal) str += QLatin1String("non-final");
342
343 if (modifiers & Readable) str += QLatin1String("readable");
344 if (modifiers & Writable) str += QLatin1String("writable");
345
346 if (modifiers & CodeInjection) {
347 for (const CodeSnip &s : snips) {
348 str += QLatin1String("\n//code injection:\n");
349 str += s.code();
350 }
351 }
352
353 if (modifiers & Rename) str += QLatin1String("renamed:") + renamedToName;
354
355 if (modifiers & Deprecated) str += QLatin1String("deprecate");
356
357 if (modifiers & ReplaceExpression) str += QLatin1String("replace-expression");
358
359 return str;
360 }
361
parseType(const QString & signature,int startPos=0,int * endPos=nullptr,QString * argumentName=nullptr)362 static AddedFunction::TypeInfo parseType(const QString& signature,
363 int startPos = 0, int *endPos = nullptr,
364 QString *argumentName = nullptr)
365 {
366 AddedFunction::TypeInfo result;
367 static const QRegularExpression regex(QLatin1String("\\w"));
368 Q_ASSERT(regex.isValid());
369 int length = signature.length();
370 int start = signature.indexOf(regex, startPos);
371 if (start == -1) {
372 if (signature.midRef(startPos + 1, 3) == QLatin1String("...")) { // varargs
373 if (endPos)
374 *endPos = startPos + 4;
375 result.name = QLatin1String("...");
376 } else { // error
377 if (endPos)
378 *endPos = length;
379 }
380 return result;
381 }
382
383 int cantStop = 0;
384 QString paramString;
385 QChar c;
386 int i = start;
387 for (; i < length; ++i) {
388 c = signature[i];
389 if (c == QLatin1Char('<'))
390 cantStop++;
391 if (c == QLatin1Char('>'))
392 cantStop--;
393 if (cantStop < 0)
394 break; // FIXME: report error?
395 if ((c == QLatin1Char(')') || c == QLatin1Char(',')) && !cantStop)
396 break;
397 paramString += signature[i];
398 }
399 if (endPos)
400 *endPos = i;
401
402 // Check default value
403 if (paramString.contains(QLatin1Char('='))) {
404 QStringList lst = paramString.split(QLatin1Char('='));
405 paramString = lst[0].trimmed();
406 result.defaultValue = lst[1].trimmed();
407 }
408
409 // check constness
410 if (paramString.startsWith(QLatin1String("const "))) {
411 result.isConstant = true;
412 paramString.remove(0, sizeof("const")/sizeof(char));
413 paramString = paramString.trimmed();
414 }
415
416 // Extract argument name from "T<bla,blub>* @foo@"
417 const int nameStartPos = paramString.indexOf(QLatin1Char('@'));
418 if (nameStartPos != -1) {
419 const int nameEndPos = paramString.indexOf(QLatin1Char('@'), nameStartPos + 1);
420 if (nameEndPos > nameStartPos) {
421 if (argumentName)
422 *argumentName = paramString.mid(nameStartPos + 1, nameEndPos - nameStartPos - 1);
423 paramString.remove(nameStartPos, nameEndPos - nameStartPos + 1);
424 paramString = paramString.trimmed();
425 }
426 }
427
428 // check reference
429 if (paramString.endsWith(QLatin1Char('&'))) {
430 result.isReference = true;
431 paramString.chop(1);
432 paramString = paramString.trimmed();
433 }
434 // check Indirections
435 while (paramString.endsWith(QLatin1Char('*'))) {
436 result.indirections++;
437 paramString.chop(1);
438 paramString = paramString.trimmed();
439 }
440 result.name = paramString;
441
442 return result;
443 }
444
AddedFunction(QString signature,const QString & returnType)445 AddedFunction::AddedFunction(QString signature, const QString &returnType) :
446 m_access(Public)
447 {
448 Q_ASSERT(!returnType.isEmpty());
449 m_returnType = parseType(returnType);
450 signature = signature.trimmed();
451 // Skip past "operator()(...)"
452 const int parenStartPos = signature.startsWith(callOperator())
453 ? callOperator().size() : 0;
454 int endPos = signature.indexOf(QLatin1Char('('), parenStartPos);
455 if (endPos < 0) {
456 m_isConst = false;
457 m_name = signature;
458 } else {
459 m_name = signature.left(endPos).trimmed();
460 int signatureLength = signature.length();
461 while (endPos < signatureLength) {
462 QString argumentName;
463 TypeInfo arg = parseType(signature, endPos, &endPos, &argumentName);
464 if (!arg.name.isEmpty())
465 m_arguments.append({argumentName, arg});
466 // end of parameters...
467 if (endPos >= signatureLength || signature[endPos] == QLatin1Char(')'))
468 break;
469 }
470 // is const?
471 m_isConst = signature.rightRef(signatureLength - endPos).contains(QLatin1String("const"));
472 }
473 }
474
475 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug d,const ReferenceCount & r)476 QDebug operator<<(QDebug d, const ReferenceCount &r)
477 {
478 QDebugStateSaver saver(d);
479 d.noquote();
480 d.nospace();
481 d << "ReferenceCount(" << r.varName << ", action=" << r.action << ')';
482 return d;
483 }
484
operator <<(QDebug d,const CodeSnip & s)485 QDebug operator<<(QDebug d, const CodeSnip &s)
486 {
487 QDebugStateSaver saver(d);
488 d.noquote();
489 d.nospace();
490 d << "CodeSnip(language=" << s.language << ", position=" << s.position << ", \"";
491 for (const auto &f : s.codeList) {
492 const QString &code = f.code();
493 const auto lines = code.splitRef(QLatin1Char('\n'));
494 for (int i = 0, size = lines.size(); i < size; ++i) {
495 if (i)
496 d << "\\n";
497 d << lines.at(i).trimmed();
498 }
499 }
500 d << '"';
501 if (!s.argumentMap.isEmpty()) {
502 d << ", argumentMap{";
503 for (auto it = s.argumentMap.cbegin(), end = s.argumentMap.cend(); it != end; ++it)
504 d << it.key() << "->\"" << it.value() << '"';
505 d << '}';
506 }
507 d << ')';
508 return d;
509 }
510
formatDebug(QDebug & d) const511 void Modification::formatDebug(QDebug &d) const
512 {
513 d << "modifiers=" << Qt::hex << Qt::showbase << modifiers << Qt::noshowbase << Qt::dec;
514 if (removal)
515 d << ", removal";
516 if (!renamedToName.isEmpty())
517 d << ", renamedToName=\"" << renamedToName << '"';
518 }
519
formatDebug(QDebug & d) const520 void FunctionModification::formatDebug(QDebug &d) const
521 {
522 if (m_signature.isEmpty())
523 d << "pattern=\"" << m_signaturePattern.pattern();
524 else
525 d << "signature=\"" << m_signature;
526 d << "\", ";
527 Modification::formatDebug(d);
528 if (!association.isEmpty())
529 d << ", association=\"" << association << '"';
530 if (m_allowThread != TypeSystem::AllowThread::Unspecified)
531 d << ", allowThread=" << int(m_allowThread);
532 if (m_thread)
533 d << ", thread";
534 if (m_exceptionHandling != TypeSystem::ExceptionHandling::Unspecified)
535 d << ", exceptionHandling=" << int(m_exceptionHandling);
536 if (!snips.isEmpty())
537 d << ", snips=(" << snips << ')';
538 if (!argument_mods.isEmpty())
539 d << ", argument_mods=(" << argument_mods << ')';
540 }
541
operator <<(QDebug d,const ArgumentOwner & a)542 QDebug operator<<(QDebug d, const ArgumentOwner &a)
543 {
544 QDebugStateSaver saver(d);
545 d.noquote();
546 d.nospace();
547 d << "ArgumentOwner(index=" << a.index << ", action=" << a.action << ')';
548 return d;
549 }
550
operator <<(QDebug d,const ArgumentModification & a)551 QDebug operator<<(QDebug d, const ArgumentModification &a)
552 {
553 QDebugStateSaver saver(d);
554 d.noquote();
555 d.nospace();
556 d << "ArgumentModification(index=" << a.index;
557 if (a.removedDefaultExpression)
558 d << ", removedDefaultExpression";
559 if (a.removed)
560 d << ", removed";
561 if (a.noNullPointers)
562 d << ", noNullPointers";
563 if (a.array)
564 d << ", array";
565 if (!a.referenceCounts.isEmpty())
566 d << ", referenceCounts=" << a.referenceCounts;
567 if (!a.modified_type.isEmpty())
568 d << ", modified_type=\"" << a.modified_type << '"';
569 if (!a.replace_value.isEmpty())
570 d << ", replace_value=\"" << a.replace_value << '"';
571 if (!a.replacedDefaultExpression.isEmpty())
572 d << ", replacedDefaultExpression=\"" << a.replacedDefaultExpression << '"';
573 if (!a.ownerships.isEmpty())
574 d << ", ownerships=" << a.ownerships;
575 if (!a.renamed_to.isEmpty())
576 d << ", renamed_to=\"" << a.renamed_to << '"';
577 d << ", owner=" << a.owner << ')';
578 return d;
579 }
580
operator <<(QDebug d,const FunctionModification & fm)581 QDebug operator<<(QDebug d, const FunctionModification &fm)
582 {
583 QDebugStateSaver saver(d);
584 d.noquote();
585 d.nospace();
586 d << "FunctionModification(";
587 fm.formatDebug(d);
588 d << ')';
589 return d;
590 }
591
operator <<(QDebug d,const AddedFunction::TypeInfo & ti)592 QDebug operator<<(QDebug d, const AddedFunction::TypeInfo &ti)
593 {
594 QDebugStateSaver saver(d);
595 d.noquote();
596 d.nospace();
597 d << "TypeInfo(";
598 if (ti.isConstant)
599 d << "const";
600 if (ti.indirections)
601 d << QByteArray(ti.indirections, '*');
602 if (ti.isReference)
603 d << " &";
604 d << ti.name;
605 if (!ti.defaultValue.isEmpty())
606 d << " = " << ti.defaultValue;
607 d << ')';
608 return d;
609 }
610
operator <<(QDebug d,const AddedFunction::Argument & a)611 QDebug operator<<(QDebug d, const AddedFunction::Argument &a)
612 {
613 QDebugStateSaver saver(d);
614 d.noquote();
615 d.nospace();
616 d << "Argument(";
617 d << a.typeInfo;
618 if (!a.name.isEmpty())
619 d << ' ' << a.name;
620 d << ')';
621 return d;
622 }
623
operator <<(QDebug d,const AddedFunction & af)624 QDebug operator<<(QDebug d, const AddedFunction &af)
625 {
626 QDebugStateSaver saver(d);
627 d.noquote();
628 d.nospace();
629 d << "AddedFunction(";
630 if (af.access() == AddedFunction::Protected)
631 d << "protected";
632 if (af.isStatic())
633 d << " static";
634 d << af.returnType() << ' ' << af.name() << '(' << af.arguments() << ')';
635 if (af.isConstant())
636 d << " const";
637 return d;
638 }
639 #endif // !QT_NO_DEBUG_STREAM
640
fromSignature(const QString & signature)641 AddedFunction::TypeInfo AddedFunction::TypeInfo::fromSignature(const QString& signature)
642 {
643 return parseType(signature);
644 }
645
buildName(const QString & entryName,const TypeEntry * parent)646 static QString buildName(const QString &entryName, const TypeEntry *parent)
647 {
648 return parent == nullptr || parent->type() == TypeEntry::TypeSystemType
649 ? entryName : parent->name() + QLatin1String("::") + entryName;
650 }
651
ComplexTypeEntry(const QString & entryName,TypeEntry::Type t,const QVersionNumber & vr,const TypeEntry * parent)652 ComplexTypeEntry::ComplexTypeEntry(const QString &entryName, TypeEntry::Type t,
653 const QVersionNumber &vr,
654 const TypeEntry *parent) :
655 TypeEntry(entryName, t, vr, parent),
656 m_qualifiedCppName(buildName(entryName, parent)),
657 m_polymorphicBase(false),
658 m_genericClass(false),
659 m_deleteInMainThread(false)
660 {
661 }
662
isComplex() const663 bool ComplexTypeEntry::isComplex() const
664 {
665 return true;
666 }
667
targetLangApiName() const668 QString ComplexTypeEntry::targetLangApiName() const
669 {
670 return strings_jobject;
671 }
672
typeName() const673 QString ContainerTypeEntry::typeName() const
674 {
675 switch (m_containerKind) {
676 case LinkedListContainer:
677 return QLatin1String("linked-list");
678 case ListContainer:
679 return QLatin1String("list");
680 case StringListContainer:
681 return QLatin1String("string-list");
682 case VectorContainer:
683 return QLatin1String("vector");
684 case StackContainer:
685 return QLatin1String("stack");
686 case QueueContainer:
687 return QLatin1String("queue");
688 case SetContainer:
689 return QLatin1String("set");
690 case MapContainer:
691 return QLatin1String("map");
692 case MultiMapContainer:
693 return QLatin1String("multi-map");
694 case HashContainer:
695 return QLatin1String("hash");
696 case MultiHashContainer:
697 return QLatin1String("multi-hash");
698 case PairContainer:
699 return QLatin1String("pair");
700 case NoContainer:
701 default:
702 return QLatin1String("?");
703 }
704 }
705
primitiveCppTypes()706 static const QSet<QString> &primitiveCppTypes()
707 {
708 static QSet<QString> result;
709 if (result.isEmpty()) {
710 static const char *cppTypes[] = {
711 "bool", "char", "double", "float", "int",
712 "long", "long long", "short",
713 "wchar_t"
714 };
715 for (const char *cppType : cppTypes)
716 result.insert(QLatin1String(cppType));
717 }
718 return result;
719 }
720
setInclude(const Include & inc)721 void TypeEntry::setInclude(const Include &inc)
722 {
723 // This is a workaround for preventing double inclusion of the QSharedPointer implementation
724 // header, which does not use header guards. In the previous parser this was not a problem
725 // because the Q_QDOC define was set, and the implementation header was never included.
726 if (inc.name().endsWith(QLatin1String("qsharedpointer_impl.h"))) {
727 QString path = inc.name();
728 path.remove(QLatin1String("_impl"));
729 m_include = Include(inc.type(), path);
730 } else {
731 m_include = inc;
732 }
733 }
734
isCppPrimitive() const735 bool TypeEntry::isCppPrimitive() const
736 {
737 if (!isPrimitive())
738 return false;
739
740 if (m_type == VoidType)
741 return true;
742
743 const PrimitiveTypeEntry *referencedType =
744 static_cast<const PrimitiveTypeEntry *>(this)->basicReferencedTypeEntry();
745 const QString &typeName = referencedType ? referencedType->name() : m_name;
746 return typeName.contains(QLatin1Char(' ')) || primitiveCppTypes().contains(typeName);
747 }
748
TypeEntry(const QString & entryName,TypeEntry::Type t,const QVersionNumber & vr,const TypeEntry * parent)749 TypeEntry::TypeEntry(const QString &entryName, TypeEntry::Type t, const QVersionNumber &vr,
750 const TypeEntry *parent) :
751 m_parent(parent),
752 m_name(buildName(entryName, parent)),
753 m_entryName(entryName),
754 m_version(vr),
755 m_type(t)
756 {
757 }
758
~TypeEntry()759 TypeEntry::~TypeEntry()
760 {
761 delete m_customConversion;
762 }
763
isChildOf(const TypeEntry * p) const764 bool TypeEntry::isChildOf(const TypeEntry *p) const
765 {
766 for (auto e = m_parent; e; e = e->parent()) {
767 if (e == p)
768 return true;
769 }
770 return false;
771 }
772
typeSystemTypeEntry() const773 const TypeSystemTypeEntry *TypeEntry::typeSystemTypeEntry() const
774 {
775 for (auto e = this; e; e = e->parent()) {
776 if (e->type() == TypeEntry::TypeSystemType)
777 return static_cast<const TypeSystemTypeEntry *>(e);
778 }
779 return nullptr;
780 }
781
targetLangEnclosingEntry() const782 const TypeEntry *TypeEntry::targetLangEnclosingEntry() const
783 {
784 auto result = m_parent;
785 while (result && result->type() != TypeEntry::TypeSystemType
786 && !NamespaceTypeEntry::isVisibleScope(result)) {
787 result = result->parent();
788 }
789 return result;
790 }
791
targetLangName() const792 QString TypeEntry::targetLangName() const
793 {
794 if (m_cachedTargetLangName.isEmpty())
795 m_cachedTargetLangName = buildTargetLangName();
796 return m_cachedTargetLangName;
797 }
798
buildTargetLangName() const799 QString TypeEntry::buildTargetLangName() const
800 {
801 QString result = m_entryName;
802 for (auto p = parent(); p && p->type() != TypeEntry::TypeSystemType; p = p->parent()) {
803 if (NamespaceTypeEntry::isVisibleScope(p)) {
804 if (!result.isEmpty())
805 result.prepend(QLatin1Char('.'));
806 QString n = p->m_entryName;
807 n.replace(QLatin1String("::"), QLatin1String(".")); // Primitive types may have "std::"
808 result.prepend(n);
809 }
810 }
811 return result;
812 }
813
sourceLocation() const814 SourceLocation TypeEntry::sourceLocation() const
815 {
816 return m_sourceLocation;
817 }
818
setSourceLocation(const SourceLocation & sourceLocation)819 void TypeEntry::setSourceLocation(const SourceLocation &sourceLocation)
820 {
821 m_sourceLocation = sourceLocation;
822 }
823
targetLangEntryName() const824 QString TypeEntry::targetLangEntryName() const
825 {
826 if (m_cachedTargetLangEntryName.isEmpty()) {
827 m_cachedTargetLangEntryName = targetLangName();
828 const int lastDot = m_cachedTargetLangEntryName.lastIndexOf(QLatin1Char('.'));
829 if (lastDot != -1)
830 m_cachedTargetLangEntryName.remove(0, lastDot + 1);
831 }
832 return m_cachedTargetLangEntryName;
833 }
834
qualifiedTargetLangName() const835 QString TypeEntry::qualifiedTargetLangName() const
836 {
837 return targetLangPackage() + QLatin1Char('.') + targetLangName();
838 }
839
hasCustomConversion() const840 bool TypeEntry::hasCustomConversion() const
841 {
842 return m_customConversion != nullptr;
843 }
844
setCustomConversion(CustomConversion * customConversion)845 void TypeEntry::setCustomConversion(CustomConversion* customConversion)
846 {
847 m_customConversion = customConversion;
848 }
849
customConversion() const850 CustomConversion* TypeEntry::customConversion() const
851 {
852 return m_customConversion;
853 }
854
clone() const855 TypeEntry *TypeEntry::clone() const
856 {
857 return new TypeEntry(*this);
858 }
859
860 // Take over parameters relevant for typedefs
useAsTypedef(const TypeEntry * source)861 void TypeEntry::useAsTypedef(const TypeEntry *source)
862 {
863 // XML Typedefs are in the global namespace for now.
864 m_parent = source->typeSystemTypeEntry();
865 m_entryName = source->m_entryName;
866 m_name = source->m_name;
867 m_targetLangPackage = source->m_targetLangPackage;
868 m_codeGeneration = source->m_codeGeneration;
869 m_version = source->m_version;
870 }
871
872 TypeEntry::TypeEntry(const TypeEntry &) = default;
873
TypeSystemTypeEntry(const QString & entryName,const QVersionNumber & vr,const TypeEntry * parent)874 TypeSystemTypeEntry::TypeSystemTypeEntry(const QString &entryName, const QVersionNumber &vr,
875 const TypeEntry *parent) :
876 TypeEntry(entryName, TypeSystemType, vr, parent)
877 {
878 }
879
clone() const880 TypeEntry *TypeSystemTypeEntry::clone() const
881 {
882 return new TypeSystemTypeEntry(*this);
883 }
884
885 TypeSystemTypeEntry::TypeSystemTypeEntry(const TypeSystemTypeEntry &) = default;
886
VoidTypeEntry()887 VoidTypeEntry::VoidTypeEntry() :
888 TypeEntry(QLatin1String("void"), VoidType, QVersionNumber(0, 0), nullptr)
889 {
890 }
891
clone() const892 TypeEntry *VoidTypeEntry::clone() const
893 {
894 return new VoidTypeEntry(*this);
895 }
896
897 VoidTypeEntry::VoidTypeEntry(const VoidTypeEntry &) = default;
898
VarargsTypeEntry()899 VarargsTypeEntry::VarargsTypeEntry() :
900 TypeEntry(QLatin1String("..."), VarargsType, QVersionNumber(0, 0), nullptr)
901 {
902 }
903
clone() const904 TypeEntry *VarargsTypeEntry::clone() const
905 {
906 return new VarargsTypeEntry(*this);
907 }
908
909 VarargsTypeEntry::VarargsTypeEntry(const VarargsTypeEntry &) = default;
910
TemplateArgumentEntry(const QString & entryName,const QVersionNumber & vr,const TypeEntry * parent)911 TemplateArgumentEntry::TemplateArgumentEntry(const QString &entryName, const QVersionNumber &vr,
912 const TypeEntry *parent) :
913 TypeEntry(entryName, TemplateArgumentType, vr, parent)
914 {
915 }
916
clone() const917 TypeEntry *TemplateArgumentEntry::clone() const
918 {
919 return new TemplateArgumentEntry(*this);
920 }
921
922 TemplateArgumentEntry::TemplateArgumentEntry(const TemplateArgumentEntry &) = default;
923
ArrayTypeEntry(const TypeEntry * nested_type,const QVersionNumber & vr,const TypeEntry * parent)924 ArrayTypeEntry::ArrayTypeEntry(const TypeEntry *nested_type, const QVersionNumber &vr,
925 const TypeEntry *parent) :
926 TypeEntry(QLatin1String("Array"), ArrayType, vr, parent),
927 m_nestedType(nested_type)
928 {
929 Q_ASSERT(m_nestedType);
930 }
931
buildTargetLangName() const932 QString ArrayTypeEntry::buildTargetLangName() const
933 {
934 return m_nestedType->targetLangName() + QLatin1String("[]");
935 }
936
targetLangApiName() const937 QString ArrayTypeEntry::targetLangApiName() const
938 {
939 return m_nestedType->isPrimitive()
940 ? m_nestedType->targetLangApiName() + QLatin1String("Array")
941 : QLatin1String("jobjectArray");
942 }
943
clone() const944 TypeEntry *ArrayTypeEntry::clone() const
945 {
946 return new ArrayTypeEntry(*this);
947 }
948
949 ArrayTypeEntry::ArrayTypeEntry(const ArrayTypeEntry &) = default;
950
EnumTypeEntry(const QString & entryName,const QVersionNumber & vr,const TypeEntry * parent)951 EnumTypeEntry::EnumTypeEntry(const QString &entryName,
952 const QVersionNumber &vr,
953 const TypeEntry *parent) :
954 TypeEntry(entryName, EnumType, vr, parent)
955 {
956 }
957
EnumValueTypeEntry(const QString & name,const QString & value,const EnumTypeEntry * enclosingEnum,bool isScopedEnum,const QVersionNumber & vr)958 EnumValueTypeEntry::EnumValueTypeEntry(const QString &name, const QString &value,
959 const EnumTypeEntry *enclosingEnum,
960 bool isScopedEnum,
961 const QVersionNumber &vr) :
962 TypeEntry(name, TypeEntry::EnumValue, vr,
963 isScopedEnum ? enclosingEnum : enclosingEnum->parent()),
964 m_value(value),
965 m_enclosingEnum(enclosingEnum)
966 {
967 }
968
clone() const969 TypeEntry *EnumValueTypeEntry::clone() const
970 {
971 return new EnumValueTypeEntry(*this);
972 }
973
974 EnumValueTypeEntry::EnumValueTypeEntry(const EnumValueTypeEntry &) = default;
975
FlagsTypeEntry(const QString & entryName,const QVersionNumber & vr,const TypeEntry * parent)976 FlagsTypeEntry::FlagsTypeEntry(const QString &entryName, const QVersionNumber &vr,
977 const TypeEntry *parent) :
978 TypeEntry(entryName, FlagsType, vr, parent)
979 {
980 }
981
buildTargetLangName() const982 QString FlagsTypeEntry::buildTargetLangName() const
983 {
984 QString on = m_originalName;
985 on.replace(QLatin1String("::"), QLatin1String("."));
986 return on;
987 }
988
ConstantValueTypeEntry(const QString & name,const TypeEntry * parent)989 ConstantValueTypeEntry::ConstantValueTypeEntry(const QString& name,
990 const TypeEntry *parent) :
991 TypeEntry(name, ConstantValueType, QVersionNumber(0, 0), parent)
992 {
993 }
994
clone() const995 TypeEntry *ConstantValueTypeEntry::clone() const
996 {
997 return new ConstantValueTypeEntry(*this);
998 }
999
1000 ConstantValueTypeEntry::ConstantValueTypeEntry(const ConstantValueTypeEntry &) = default;
1001
1002 /* A typedef entry allows for specifying template specializations in the
1003 * typesystem XML file. */
TypedefEntry(const QString & entryName,const QString & sourceType,const QVersionNumber & vr,const TypeEntry * parent)1004 TypedefEntry::TypedefEntry(const QString &entryName, const QString &sourceType,
1005 const QVersionNumber &vr, const TypeEntry *parent) :
1006 ComplexTypeEntry(entryName, TypedefType, vr, parent),
1007 m_sourceType(sourceType)
1008 {
1009 }
1010
clone() const1011 TypeEntry *TypedefEntry::clone() const
1012 {
1013 return new TypedefEntry(*this);
1014 }
1015
1016 TypedefEntry::TypedefEntry(const TypedefEntry &) = default;
1017
ContainerTypeEntry(const QString & entryName,ContainerKind containerKind,const QVersionNumber & vr,const TypeEntry * parent)1018 ContainerTypeEntry::ContainerTypeEntry(const QString &entryName, ContainerKind containerKind,
1019 const QVersionNumber &vr,
1020 const TypeEntry *parent) :
1021 ComplexTypeEntry(entryName, ContainerType, vr, parent),
1022 m_containerKind(containerKind)
1023 {
1024 setCodeGeneration(GenerateForSubclass);
1025 }
1026
SmartPointerTypeEntry(const QString & entryName,const QString & getterName,const QString & smartPointerType,const QString & refCountMethodName,const QVersionNumber & vr,const TypeEntry * parent)1027 SmartPointerTypeEntry::SmartPointerTypeEntry(const QString &entryName,
1028 const QString &getterName,
1029 const QString &smartPointerType,
1030 const QString &refCountMethodName,
1031 const QVersionNumber &vr, const TypeEntry *parent) :
1032 ComplexTypeEntry(entryName, SmartPointerType, vr, parent),
1033 m_getterName(getterName),
1034 m_smartPointerType(smartPointerType),
1035 m_refCountMethodName(refCountMethodName)
1036 {
1037 }
1038
clone() const1039 TypeEntry *SmartPointerTypeEntry::clone() const
1040 {
1041 return new SmartPointerTypeEntry(*this);
1042 }
1043
1044 SmartPointerTypeEntry::SmartPointerTypeEntry(const SmartPointerTypeEntry &) = default;
1045
matchesInstantiation(const TypeEntry * e) const1046 bool SmartPointerTypeEntry::matchesInstantiation(const TypeEntry *e) const
1047 {
1048 return m_instantiations.isEmpty() || m_instantiations.contains(e);
1049 }
1050
NamespaceTypeEntry(const QString & entryName,const QVersionNumber & vr,const TypeEntry * parent)1051 NamespaceTypeEntry::NamespaceTypeEntry(const QString &entryName, const QVersionNumber &vr,
1052 const TypeEntry *parent) :
1053 ComplexTypeEntry(entryName, NamespaceType, vr, parent)
1054 {
1055 }
1056
clone() const1057 TypeEntry *NamespaceTypeEntry::clone() const
1058 {
1059 return new NamespaceTypeEntry(*this);
1060 }
1061
setFilePattern(const QRegularExpression & r)1062 void NamespaceTypeEntry::setFilePattern(const QRegularExpression &r)
1063 {
1064 m_filePattern = r;
1065 m_hasPattern = !m_filePattern.pattern().isEmpty();
1066 if (m_hasPattern)
1067 m_filePattern.optimize();
1068 }
1069
1070 NamespaceTypeEntry::NamespaceTypeEntry(const NamespaceTypeEntry &) = default;
1071
matchesFile(const QString & needle) const1072 bool NamespaceTypeEntry::matchesFile(const QString &needle) const
1073 {
1074 return m_filePattern.match(needle).hasMatch();
1075 }
1076
isVisible() const1077 bool NamespaceTypeEntry::isVisible() const
1078 {
1079 return m_visibility == TypeSystem::Visibility::Visible
1080 || (m_visibility == TypeSystem::Visibility::Auto && !m_inlineNamespace);
1081 }
1082
isVisibleScope(const TypeEntry * e)1083 bool NamespaceTypeEntry::isVisibleScope(const TypeEntry *e)
1084 {
1085 return e->type() != TypeEntry::NamespaceType
1086 || static_cast<const NamespaceTypeEntry *>(e)->isVisible();
1087 }
1088
ValueTypeEntry(const QString & entryName,const QVersionNumber & vr,const TypeEntry * parent)1089 ValueTypeEntry::ValueTypeEntry(const QString &entryName, const QVersionNumber &vr,
1090 const TypeEntry *parent) :
1091 ComplexTypeEntry(entryName, BasicValueType, vr, parent)
1092 {
1093 }
1094
isValue() const1095 bool ValueTypeEntry::isValue() const
1096 {
1097 return true;
1098 }
1099
clone() const1100 TypeEntry *ValueTypeEntry::clone() const
1101 {
1102 return new ValueTypeEntry(*this);
1103 }
1104
1105 ValueTypeEntry::ValueTypeEntry(const ValueTypeEntry &) = default;
1106
ValueTypeEntry(const QString & entryName,Type t,const QVersionNumber & vr,const TypeEntry * parent)1107 ValueTypeEntry::ValueTypeEntry(const QString &entryName, Type t, const QVersionNumber &vr,
1108 const TypeEntry *parent) :
1109 ComplexTypeEntry(entryName, t, vr, parent)
1110 {
1111 }
1112
1113 struct CustomConversion::CustomConversionPrivate
1114 {
CustomConversionPrivateCustomConversion::CustomConversionPrivate1115 CustomConversionPrivate(const TypeEntry* ownerType)
1116 : ownerType(ownerType), replaceOriginalTargetToNativeConversions(false)
1117 {
1118 }
1119 const TypeEntry* ownerType;
1120 QString nativeToTargetConversion;
1121 bool replaceOriginalTargetToNativeConversions;
1122 TargetToNativeConversions targetToNativeConversions;
1123 };
1124
1125 struct CustomConversion::TargetToNativeConversion::TargetToNativeConversionPrivate
1126 {
TargetToNativeConversionPrivateCustomConversion::TargetToNativeConversion::TargetToNativeConversionPrivate1127 TargetToNativeConversionPrivate()
1128 : sourceType(nullptr)
1129 {
1130 }
1131 const TypeEntry* sourceType;
1132 QString sourceTypeName;
1133 QString sourceTypeCheck;
1134 QString conversion;
1135 };
1136
CustomConversion(TypeEntry * ownerType)1137 CustomConversion::CustomConversion(TypeEntry* ownerType)
1138 {
1139 m_d = new CustomConversionPrivate(ownerType);
1140 if (ownerType)
1141 ownerType->setCustomConversion(this);
1142 }
1143
~CustomConversion()1144 CustomConversion::~CustomConversion()
1145 {
1146 qDeleteAll(m_d->targetToNativeConversions);
1147 delete m_d;
1148 }
1149
ownerType() const1150 const TypeEntry* CustomConversion::ownerType() const
1151 {
1152 return m_d->ownerType;
1153 }
1154
nativeToTargetConversion() const1155 QString CustomConversion::nativeToTargetConversion() const
1156 {
1157 return m_d->nativeToTargetConversion;
1158 }
1159
setNativeToTargetConversion(const QString & nativeToTargetConversion)1160 void CustomConversion::setNativeToTargetConversion(const QString& nativeToTargetConversion)
1161 {
1162 m_d->nativeToTargetConversion = nativeToTargetConversion;
1163 }
1164
replaceOriginalTargetToNativeConversions() const1165 bool CustomConversion::replaceOriginalTargetToNativeConversions() const
1166 {
1167 return m_d->replaceOriginalTargetToNativeConversions;
1168 }
1169
setReplaceOriginalTargetToNativeConversions(bool replaceOriginalTargetToNativeConversions)1170 void CustomConversion::setReplaceOriginalTargetToNativeConversions(bool replaceOriginalTargetToNativeConversions)
1171 {
1172 m_d->replaceOriginalTargetToNativeConversions = replaceOriginalTargetToNativeConversions;
1173 }
1174
hasTargetToNativeConversions() const1175 bool CustomConversion::hasTargetToNativeConversions() const
1176 {
1177 return !(m_d->targetToNativeConversions.isEmpty());
1178 }
1179
targetToNativeConversions()1180 CustomConversion::TargetToNativeConversions& CustomConversion::targetToNativeConversions()
1181 {
1182 return m_d->targetToNativeConversions;
1183 }
1184
targetToNativeConversions() const1185 const CustomConversion::TargetToNativeConversions& CustomConversion::targetToNativeConversions() const
1186 {
1187 return m_d->targetToNativeConversions;
1188 }
1189
addTargetToNativeConversion(const QString & sourceTypeName,const QString & sourceTypeCheck,const QString & conversion)1190 void CustomConversion::addTargetToNativeConversion(const QString& sourceTypeName,
1191 const QString& sourceTypeCheck,
1192 const QString& conversion)
1193 {
1194 m_d->targetToNativeConversions.append(new TargetToNativeConversion(sourceTypeName, sourceTypeCheck, conversion));
1195 }
1196
TargetToNativeConversion(const QString & sourceTypeName,const QString & sourceTypeCheck,const QString & conversion)1197 CustomConversion::TargetToNativeConversion::TargetToNativeConversion(const QString& sourceTypeName,
1198 const QString& sourceTypeCheck,
1199 const QString& conversion)
1200 {
1201 m_d = new TargetToNativeConversionPrivate;
1202 m_d->sourceTypeName = sourceTypeName;
1203 m_d->sourceTypeCheck = sourceTypeCheck;
1204 m_d->conversion = conversion;
1205 }
1206
~TargetToNativeConversion()1207 CustomConversion::TargetToNativeConversion::~TargetToNativeConversion()
1208 {
1209 delete m_d;
1210 }
1211
sourceType() const1212 const TypeEntry* CustomConversion::TargetToNativeConversion::sourceType() const
1213 {
1214 return m_d->sourceType;
1215 }
1216
setSourceType(const TypeEntry * sourceType)1217 void CustomConversion::TargetToNativeConversion::setSourceType(const TypeEntry* sourceType)
1218 {
1219 m_d->sourceType = sourceType;
1220 }
1221
isCustomType() const1222 bool CustomConversion::TargetToNativeConversion::isCustomType() const
1223 {
1224 return !(m_d->sourceType);
1225 }
1226
sourceTypeName() const1227 QString CustomConversion::TargetToNativeConversion::sourceTypeName() const
1228 {
1229 return m_d->sourceTypeName;
1230 }
1231
sourceTypeCheck() const1232 QString CustomConversion::TargetToNativeConversion::sourceTypeCheck() const
1233 {
1234 return m_d->sourceTypeCheck;
1235 }
1236
conversion() const1237 QString CustomConversion::TargetToNativeConversion::conversion() const
1238 {
1239 return m_d->conversion;
1240 }
1241
setConversion(const QString & conversion)1242 void CustomConversion::TargetToNativeConversion::setConversion(const QString& conversion)
1243 {
1244 m_d->conversion = conversion;
1245 }
1246
FunctionTypeEntry(const QString & entryName,const QString & signature,const QVersionNumber & vr,const TypeEntry * parent)1247 FunctionTypeEntry::FunctionTypeEntry(const QString &entryName, const QString &signature,
1248 const QVersionNumber &vr,
1249 const TypeEntry *parent) :
1250 TypeEntry(entryName, FunctionType, vr, parent)
1251 {
1252 addSignature(signature);
1253 }
1254
clone() const1255 TypeEntry *FunctionTypeEntry::clone() const
1256 {
1257 return new FunctionTypeEntry(*this);
1258 }
1259
1260 FunctionTypeEntry::FunctionTypeEntry(const FunctionTypeEntry &) = default;
1261
ObjectTypeEntry(const QString & entryName,const QVersionNumber & vr,const TypeEntry * parent)1262 ObjectTypeEntry::ObjectTypeEntry(const QString &entryName, const QVersionNumber &vr,
1263 const TypeEntry *parent)
1264 : ComplexTypeEntry(entryName, ObjectType, vr, parent)
1265 {
1266 }
1267
clone() const1268 TypeEntry *ObjectTypeEntry::clone() const
1269 {
1270 return new ObjectTypeEntry(*this);
1271 }
1272
1273 ObjectTypeEntry::ObjectTypeEntry(const ObjectTypeEntry &) = default;
1274
setCode(const QString & code)1275 void DocModification::setCode(const QString &code)
1276 {
1277 m_code = CodeSnipAbstract::fixSpaces(code);
1278 }
1279