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