1 /****************************************************************************
2 **
3 ** Copyright (C) 2020 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 "abstractmetalang.h"
30 #include "messages.h"
31 #include "propertyspec.h"
32 #include "reporthandler.h"
33 #include "typedatabase.h"
34 #include "typesystem.h"
35 
36 #include <parser/codemodel.h>
37 
38 #ifndef QT_NO_DEBUG_STREAM
39 #  include <QtCore/QMetaEnum>
40 #  include <QtCore/QMetaObject>
41 #endif
42 
43 #include <QtCore/QRegularExpression>
44 #include <QtCore/QStack>
45 
46 #include <algorithm>
47 
48 #include <algorithm>
49 
50 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug d,const AbstractMetaAttributes * aa)51 QDebug operator<<(QDebug d, const AbstractMetaAttributes *aa)
52 {
53     QDebugStateSaver saver(d);
54     d.noquote();
55     d.nospace();
56     d << "AbstractMetaAttributes(";
57     if (aa)
58         d << aa->attributes();
59     else
60         d << '0';
61     d << ')';
62     return d;
63 }
64 #endif // !QT_NO_DEBUG_STREAM
65 
66 template <class MetaClass>
findByName(QVector<MetaClass * > haystack,QStringView needle)67 MetaClass *findByName(QVector<MetaClass *> haystack, QStringView needle)
68 {
69     for (MetaClass *c : haystack) {
70         if (c->name() == needle)
71             return c;
72     }
73     return nullptr;
74 }
75 
76 // Helper for recursing the base classes of an AbstractMetaClass.
77 // Returns the class for which the predicate is true.
78 template <class Predicate>
recurseClassHierarchy(const AbstractMetaClass * klass,Predicate pred)79 const AbstractMetaClass *recurseClassHierarchy(const AbstractMetaClass *klass,
80                                                Predicate pred)
81 {
82     if (pred(klass))
83         return klass;
84     for (auto base : klass->baseClasses()) {
85         if (auto r = recurseClassHierarchy(base, pred))
86             return r;
87     }
88     return nullptr;
89 }
90 
91 /*******************************************************************************
92  * Documentation
93  */
94 
Documentation(const QString & value,Documentation::Type t,Documentation::Format fmt)95 Documentation::Documentation(const QString &value, Documentation::Type t, Documentation::Format fmt)
96 {
97     setValue(value, t, fmt);
98 }
99 
isEmpty() const100 bool Documentation::isEmpty() const
101 {
102     for (int i = 0; i < Type::Last; i++) {
103         if (!m_data.value(static_cast<Type>(i)).isEmpty())
104             return false;
105     }
106     return true;
107 }
108 
value(Documentation::Type t) const109 QString Documentation::value(Documentation::Type t) const
110 {
111     return m_data.value(t);
112 }
113 
setValue(const QString & value,Documentation::Type t,Documentation::Format fmt)114 void Documentation::setValue(const QString &value, Documentation::Type t, Documentation::Format fmt)
115 {
116     const QString v = value.trimmed();
117     if (v.isEmpty())
118         m_data.remove(t);
119     else
120         m_data[t] = value.trimmed();
121     m_format = fmt;
122 }
123 
format() const124 Documentation::Format Documentation::format() const
125 {
126     return m_format;
127 }
128 
setFormat(Documentation::Format f)129 void Documentation::setFormat(Documentation::Format f)
130 {
131     m_format = f;
132 }
133 
134 /*******************************************************************************
135  * AbstractMetaVariable
136  */
137 
138 AbstractMetaVariable::AbstractMetaVariable() = default;
139 
~AbstractMetaVariable()140 AbstractMetaVariable::~AbstractMetaVariable()
141 {
142     delete m_type;
143 }
144 
assignMetaVariable(const AbstractMetaVariable & other)145 void AbstractMetaVariable::assignMetaVariable(const AbstractMetaVariable &other)
146 {
147     m_originalName = other.m_originalName;
148     m_name = other.m_name;
149     m_type = other.m_type->copy();
150     m_hasName = other.m_hasName;
151     m_doc = other.m_doc;
152 }
153 
154 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug d,const AbstractMetaVariable * av)155 QDebug operator<<(QDebug d, const AbstractMetaVariable *av)
156 {
157     QDebugStateSaver saver(d);
158     d.noquote();
159     d.nospace();
160     d << "AbstractMetaVariable(";
161     if (av) {
162         d << av->type()->name() << ' ' << av->name();
163     } else {
164         d << '0';
165       }
166     d << ')';
167     return d;
168 }
169 #endif // !QT_NO_DEBUG_STREAM
170 
171 /*******************************************************************************
172  * AbstractMetaAttributes
173  */
174 
175 AbstractMetaAttributes::AbstractMetaAttributes() = default;
176 AbstractMetaAttributes::~AbstractMetaAttributes() = default;
177 
assignMetaAttributes(const AbstractMetaAttributes & other)178 void AbstractMetaAttributes::assignMetaAttributes(const AbstractMetaAttributes &other)
179 {
180     m_attributes = other.m_attributes;
181     m_originalAttributes = other.m_originalAttributes;
182     m_doc = other.m_doc;
183 }
184 
185 /*******************************************************************************
186  * AbstractMetaType
187  */
188 
AbstractMetaType(const TypeEntry * t)189 AbstractMetaType::AbstractMetaType(const TypeEntry *t) :
190     m_typeEntry(t),
191     m_constant(false),
192     m_volatile(false),
193     m_cppInstantiation(true),
194     m_reserved(0)
195 {
196 }
197 
~AbstractMetaType()198 AbstractMetaType::~AbstractMetaType()
199 {
200     qDeleteAll(m_children);
201     m_instantiations.clear();
202 }
203 
package() const204 QString AbstractMetaType::package() const
205 {
206     return m_typeEntry->targetLangPackage();
207 }
208 
name() const209 QString AbstractMetaType::name() const
210 {
211     return m_typeEntry->targetLangEntryName();
212 }
213 
fullName() const214 QString AbstractMetaType::fullName() const
215 {
216     return m_typeEntry->qualifiedTargetLangName();
217 }
218 
copy() const219 AbstractMetaType *AbstractMetaType::copy() const
220 {
221     auto *cpy = new AbstractMetaType(typeEntry());
222 
223     cpy->setTypeUsagePattern(typeUsagePattern());
224     cpy->setConstant(isConstant());
225     cpy->setVolatile(isVolatile());
226     cpy->setReferenceType(referenceType());
227     cpy->setIndirectionsV(indirectionsV());
228     cpy->setInstantiations(instantiations());
229     cpy->setArrayElementCount(arrayElementCount());
230     cpy->setOriginalTypeDescription(originalTypeDescription());
231     cpy->setOriginalTemplateType(originalTemplateType() ? originalTemplateType()->copy() : nullptr);
232 
233     cpy->setArrayElementType(arrayElementType() ? arrayElementType()->copy() : nullptr);
234 
235     return cpy;
236 }
237 
238 // For applying the <array> function argument modification: change into a type
239 // where "int *" becomes "int[]".
applyArrayModification(QString * errorMessage)240 bool AbstractMetaType::applyArrayModification(QString *errorMessage)
241 {
242     if (m_pattern == AbstractMetaType::NativePointerAsArrayPattern) {
243         *errorMessage = QLatin1String("<array> modification already applied.");
244         return false;
245     }
246     if (m_arrayElementType != nullptr)  {
247         QTextStream(errorMessage) << "The type \"" << cppSignature()
248             << "\" is an array of " << m_arrayElementType->name() << '.';
249         return false;
250     }
251     if (m_indirections.isEmpty()) {
252         QTextStream(errorMessage) << "The type \"" << cppSignature()
253             << "\" does not have indirections.";
254         return false;
255     }
256     // Element type to be used for ArrayHandle<>, strip constness.
257     auto elementType = copy();
258     elementType->m_indirections.pop_front();
259     elementType->setConstant(false);
260     elementType->setVolatile(false);
261     elementType->decideUsagePattern();
262     m_arrayElementType = elementType;
263     setTypeUsagePattern(AbstractMetaType::NativePointerAsArrayPattern);
264     return true;
265 }
266 
nestedArrayTypes() const267 AbstractMetaTypeCList AbstractMetaType::nestedArrayTypes() const
268 {
269     AbstractMetaTypeCList result;
270     switch (m_pattern) {
271     case ArrayPattern:
272         for (const AbstractMetaType *t = this; t->typeUsagePattern() == ArrayPattern; ) {
273             const AbstractMetaType *elt = t->arrayElementType();
274             result.append(elt);
275             t = elt;
276         }
277         break;
278     case NativePointerAsArrayPattern:
279         result.append(m_arrayElementType);
280         break;
281     default:
282         break;
283     }
284     return result;
285 }
286 
passByConstRef() const287 bool AbstractMetaType::passByConstRef() const
288 {
289     return isConstant() && m_referenceType == LValueReference && indirections() == 0;
290 }
291 
passByValue() const292 bool AbstractMetaType::passByValue() const
293 {
294     return m_referenceType == NoReference && indirections() == 0;
295 }
296 
cppSignature() const297 QString AbstractMetaType::cppSignature() const
298 {
299     if (m_cachedCppSignature.isEmpty())
300         m_cachedCppSignature = formatSignature(false);
301     return m_cachedCppSignature;
302 }
303 
pythonSignature() const304 QString AbstractMetaType::pythonSignature() const
305 {
306     // PYSIDE-921: Handle container returntypes correctly.
307     // This is now a clean reimplementation.
308     if (m_cachedPythonSignature.isEmpty())
309         m_cachedPythonSignature = formatPythonSignature();
310     return m_cachedPythonSignature;
311 }
312 
determineUsagePattern() const313 AbstractMetaType::TypeUsagePattern AbstractMetaType::determineUsagePattern() const
314 {
315     if (m_typeEntry->isTemplateArgument())
316         return TemplateArgument;
317 
318     if (m_typeEntry->type() == TypeEntry::ConstantValueType)
319         return NonTypeTemplateArgument;
320 
321     if (m_typeEntry->isPrimitive() && (actualIndirections() == 0 || passByConstRef()))
322         return PrimitivePattern;
323 
324     if (m_typeEntry->isVoid()) {
325         return m_arrayElementCount < 0 && m_referenceType == NoReference
326             && m_indirections.isEmpty() && m_constant == 0 && m_volatile == 0
327             ? VoidPattern : NativePointerPattern;
328     }
329 
330     if (m_typeEntry->isVarargs())
331         return VarargsPattern;
332 
333     if (m_typeEntry->isEnum() && (actualIndirections() == 0 || passByConstRef()))
334         return EnumPattern;
335 
336     if (m_typeEntry->isObject()) {
337         if (indirections() == 0 && m_referenceType == NoReference)
338             return ValuePattern;
339         return ObjectPattern;
340     }
341 
342     if (m_typeEntry->isContainer() && indirections() == 0)
343         return ContainerPattern;
344 
345     if (m_typeEntry->isSmartPointer() && indirections() == 0)
346         return SmartPointerPattern;
347 
348     if (m_typeEntry->isFlags() && (actualIndirections() == 0 || passByConstRef()))
349         return FlagsPattern;
350 
351     if (m_typeEntry->isArray())
352         return ArrayPattern;
353 
354     if (m_typeEntry->isValue())
355         return indirections() == 1 ? ValuePointerPattern : ValuePattern;
356 
357     return NativePointerPattern;
358 }
359 
decideUsagePattern()360 void AbstractMetaType::decideUsagePattern()
361 {
362     TypeUsagePattern pattern = determineUsagePattern();
363     if (m_typeEntry->isObject() && indirections() == 1
364         && m_referenceType == LValueReference && isConstant()) {
365         // const-references to pointers can be passed as pointers
366         setReferenceType(NoReference);
367         setConstant(false);
368         pattern = ObjectPattern;
369     }
370     setTypeUsagePattern(pattern);
371 }
372 
hasTemplateChildren() const373 bool AbstractMetaType::hasTemplateChildren() const
374 {
375     QStack<AbstractMetaType *> children;
376     children << m_children;
377 
378     // Recursively iterate over the children / descendants of the type, to check if any of them
379     // corresponds to a template argument type.
380     while (!children.isEmpty()) {
381         AbstractMetaType *child = children.pop();
382         if (child->typeEntry()->isTemplateArgument())
383             return true;
384         children << child->m_children;
385     }
386 
387     return false;
388 }
389 
compare(const AbstractMetaType & rhs,ComparisonFlags flags) const390 bool AbstractMetaType::compare(const AbstractMetaType &rhs, ComparisonFlags flags) const
391 {
392     if (m_typeEntry != rhs.m_typeEntry
393         || m_indirections != rhs.m_indirections
394         || m_instantiations.size() != rhs.m_instantiations.size()
395         || m_arrayElementCount != rhs.m_arrayElementCount) {
396         return false;
397     }
398 
399     if (m_constant != rhs.m_constant || m_referenceType != rhs.m_referenceType) {
400         if (!flags.testFlag(ConstRefMatchesValue)
401             || !(passByValue() || passByConstRef())
402             || !(rhs.passByValue() || rhs.passByConstRef())) {
403             return false;
404         }
405     }
406 
407     if ((m_arrayElementType != nullptr) != (rhs.m_arrayElementType != nullptr)
408         || (m_arrayElementType != nullptr && !m_arrayElementType->compare(*rhs.m_arrayElementType, flags))) {
409         return false;
410     }
411     for (int i = 0, size = m_instantiations.size(); i < size; ++i) {
412         if (!m_instantiations.at(i)->compare(*rhs.m_instantiations.at(i), flags))
413                 return false;
414     }
415     return true;
416 }
417 
createVoid()418 AbstractMetaType *AbstractMetaType::createVoid()
419 {
420     static const TypeEntry *voidTypeEntry = TypeDatabase::instance()->findType(QLatin1String("void"));
421     Q_ASSERT(voidTypeEntry);
422     auto *metaType = new AbstractMetaType(voidTypeEntry);
423     metaType->decideUsagePattern();
424     return metaType;
425 }
426 
427 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug d,const AbstractMetaType * at)428 QDebug operator<<(QDebug d, const AbstractMetaType *at)
429 {
430     QDebugStateSaver saver(d);
431     d.noquote();
432     d.nospace();
433     d << "AbstractMetaType(";
434     if (at) {
435         d << at->name();
436         if (d.verbosity() > 2) {
437             d << ", typeEntry=" << at->typeEntry() << ", signature=\""
438                 << at->cppSignature() << "\", pattern="
439                 << at->typeUsagePattern();
440             const auto indirections = at->indirectionsV();
441             if (!indirections.isEmpty()) {
442                 d << ", indirections=";
443                 for (auto i : indirections)
444                     d << ' ' << TypeInfo::indirectionKeyword(i);
445             }
446             if (at->referenceType())
447                 d << ", reftype=" << at->referenceType();
448             if (at->isConstant())
449                 d << ", [const]";
450             if (at->isVolatile())
451                 d << ", [volatile]";
452             if (at->isArray()) {
453                 d << ", array of \"" << at->arrayElementType()->cppSignature()
454                     << "\", arrayElementCount="  << at->arrayElementCount();
455             }
456             const auto &instantiations = at->instantiations();
457             if (const int instantiationsSize = instantiations.size()) {
458                 d << ", instantiations[" << instantiationsSize << "]=<";
459                 for (int i = 0; i < instantiationsSize; ++i) {
460                     if (i)
461                         d << ", ";
462                     d << instantiations.at(i);
463                 }
464             }
465             d << '>';
466         }
467     } else {
468         d << '0';
469     }
470     d << ')';
471     return d;
472 }
473 #endif // !QT_NO_DEBUG_STREAM
474 
475 /*******************************************************************************
476  * AbstractMetaArgument
477  */
478 
479 AbstractMetaArgument::AbstractMetaArgument() = default;
480 
assignMetaArgument(const AbstractMetaArgument & other)481 void AbstractMetaArgument::assignMetaArgument(const AbstractMetaArgument &other)
482 {
483     assignMetaVariable(other);
484     m_expression = other.m_expression;
485     m_originalExpression = other.m_originalExpression;
486     m_argumentIndex = other.m_argumentIndex;
487 }
488 
copy() const489 AbstractMetaArgument *AbstractMetaArgument::copy() const
490 {
491     auto *copy = new AbstractMetaArgument;
492     copy->assignMetaArgument(*this);
493     return copy;
494 }
495 
496 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug d,const AbstractMetaArgument * aa)497 QDebug operator<<(QDebug d, const AbstractMetaArgument *aa)
498 {
499     QDebugStateSaver saver(d);
500     d.noquote();
501     d.nospace();
502     d << "AbstractMetaArgument(";
503     if (aa)
504         d << aa->toString();
505     else
506         d << '0';
507     d << ')';
508     return d;
509 }
510 #endif // !QT_NO_DEBUG_STREAM
511 
512 /*******************************************************************************
513  * AbstractMetaFunction
514  */
515 
AbstractMetaFunction(const AddedFunctionPtr & addedFunc)516 AbstractMetaFunction::AbstractMetaFunction(const AddedFunctionPtr &addedFunc) :
517     AbstractMetaFunction()
518 {
519     m_addedFunction = addedFunc;
520     setConstant(addedFunc->isConstant());
521     setName(addedFunc->name());
522     setOriginalName(addedFunc->name());
523     auto atts = attributes() | AbstractMetaAttributes::FinalInTargetLang;
524     switch (addedFunc->access()) {
525     case AddedFunction::InvalidAccess:
526         break;
527     case AddedFunction::Protected:
528         atts |= AbstractMetaAttributes::Protected;
529         break;
530     case AddedFunction::Public:
531         atts |= AbstractMetaAttributes::Public;
532         break;
533     }
534     if (addedFunc->isStatic())
535         atts |= AbstractMetaFunction::Static;
536     setAttributes(atts);
537 }
538 
AbstractMetaFunction()539 AbstractMetaFunction::AbstractMetaFunction()
540     : m_constant(false),
541       m_reverse(false),
542       m_explicit(false),
543       m_pointerOperator(false),
544       m_isCallOperator(false)
545 {
546 }
547 
~AbstractMetaFunction()548 AbstractMetaFunction::~AbstractMetaFunction()
549 {
550     qDeleteAll(m_arguments);
551     delete m_type;
552 }
553 
554 /*******************************************************************************
555  * Indicates that this function has a modification that removes it
556  */
isModifiedRemoved(int types) const557 bool AbstractMetaFunction::isModifiedRemoved(int types) const
558 {
559     const FunctionModificationList &mods = modifications(implementingClass());
560     for (const FunctionModification &mod : mods) {
561         if (!mod.isRemoveModifier())
562             continue;
563 
564         if ((mod.removal & types) == types)
565             return true;
566     }
567 
568     return false;
569 }
570 
operator <(const AbstractMetaFunction & other) const571 bool AbstractMetaFunction::operator<(const AbstractMetaFunction &other) const
572 {
573     return compareTo(&other) & NameLessThan;
574 }
575 
576 
577 /*!
578     Returns a mask of CompareResult describing how this function is
579     compares to another function
580 */
compareTo(const AbstractMetaFunction * other) const581 AbstractMetaFunction::CompareResult AbstractMetaFunction::compareTo(const AbstractMetaFunction *other) const
582 {
583     CompareResult result;
584 
585     // Enclosing class...
586     if (ownerClass() == other->ownerClass())
587         result |= EqualImplementor;
588 
589     // Attributes
590     if (attributes() == other->attributes())
591         result |= EqualAttributes;
592 
593     // Compare types
594     AbstractMetaType *t = type();
595     AbstractMetaType *ot = other->type();
596     if ((!t && !ot) || ((t && ot && t->name() == ot->name())))
597         result |= EqualReturnType;
598 
599     // Compare names
600     int cmp = originalName().compare(other->originalName());
601 
602     if (cmp < 0)
603         result |= NameLessThan;
604     else if (!cmp)
605         result |= EqualName;
606 
607     // compare name after modification...
608     cmp = modifiedName().compare(other->modifiedName());
609     if (!cmp)
610         result |= EqualModifiedName;
611 
612     // Compare arguments...
613     AbstractMetaArgumentList minArguments;
614     AbstractMetaArgumentList maxArguments;
615     if (arguments().size() < other->arguments().size()) {
616         minArguments = arguments();
617         maxArguments = other->arguments();
618     } else {
619         minArguments = other->arguments();
620         maxArguments = arguments();
621     }
622 
623     int minCount = minArguments.size();
624     int maxCount = maxArguments.size();
625     bool same = true;
626     for (int i = 0; i < maxCount; ++i) {
627         if (i < minCount) {
628             const AbstractMetaArgument *min_arg = minArguments.at(i);
629             const AbstractMetaArgument *max_arg = maxArguments.at(i);
630             if (min_arg->type()->name() != max_arg->type()->name()
631                 && (min_arg->defaultValueExpression().isEmpty() || max_arg->defaultValueExpression().isEmpty())) {
632                 same = false;
633                 break;
634             }
635         } else {
636             if (maxArguments.at(i)->defaultValueExpression().isEmpty()) {
637                 same = false;
638                 break;
639             }
640         }
641     }
642 
643     if (same)
644         result |= minCount == maxCount ? EqualArguments : EqualDefaultValueOverload;
645 
646     return result;
647 }
648 
copy() const649 AbstractMetaFunction *AbstractMetaFunction::copy() const
650 {
651     auto *cpy = new AbstractMetaFunction;
652     cpy->assignMetaAttributes(*this);
653     cpy->setName(name());
654     cpy->setOriginalName(originalName());
655     cpy->setOwnerClass(ownerClass());
656     cpy->setImplementingClass(implementingClass());
657     cpy->setFunctionType(functionType());
658     cpy->setDeclaringClass(declaringClass());
659     cpy->setType(type()->copy());
660     cpy->setConstant(isConstant());
661     cpy->setExceptionSpecification(m_exceptionSpecification);
662     cpy->setAllowThreadModification(m_allowThreadModification);
663     cpy->setExceptionHandlingModification(m_exceptionHandlingModification);
664     cpy->m_addedFunction = m_addedFunction;
665 
666     for (AbstractMetaArgument *arg : m_arguments)
667     cpy->addArgument(arg->copy());
668 
669     Q_ASSERT(type()->instantiations() == cpy->type()->instantiations());
670 
671     return cpy;
672 }
673 
usesRValueReferences() const674 bool AbstractMetaFunction::usesRValueReferences() const
675 {
676     if (m_functionType == MoveConstructorFunction || m_functionType == MoveAssignmentOperatorFunction)
677         return true;
678     if (m_type->referenceType() == RValueReference)
679         return true;
680     for (const AbstractMetaArgument *a : m_arguments) {
681         if (a->type()->referenceType() == RValueReference)
682             return true;
683     }
684     return false;
685 }
686 
introspectionCompatibleSignatures(const QStringList & resolvedArguments) const687 QStringList AbstractMetaFunction::introspectionCompatibleSignatures(const QStringList &resolvedArguments) const
688 {
689     AbstractMetaArgumentList arguments = this->arguments();
690     if (arguments.size() == resolvedArguments.size()) {
691         QString signature = name() + QLatin1Char('(') + resolvedArguments.join(QLatin1Char(',')) + QLatin1Char(')');
692         return QStringList(TypeDatabase::normalizedSignature(signature));
693     }
694     QStringList returned;
695 
696     AbstractMetaArgument *argument = arguments.at(resolvedArguments.size());
697     QStringList minimalTypeSignature = argument->type()->minimalSignature().split(QLatin1String("::"));
698     for (int i = 0; i < minimalTypeSignature.size(); ++i) {
699         returned += introspectionCompatibleSignatures(QStringList(resolvedArguments)
700                                                       << QStringList(minimalTypeSignature.mid(minimalTypeSignature.size() - i - 1)).join(QLatin1String("::")));
701     }
702 
703     return returned;
704 }
705 
signature() const706 QString AbstractMetaFunction::signature() const
707 {
708     if (m_cachedSignature.isEmpty()) {
709         m_cachedSignature = m_originalName;
710 
711         m_cachedSignature += QLatin1Char('(');
712 
713         for (int i = 0; i < m_arguments.count(); ++i) {
714             AbstractMetaArgument *a = m_arguments.at(i);
715             AbstractMetaType *t = a->type();
716             if (t) {
717                 if (i > 0)
718                     m_cachedSignature += QLatin1String(", ");
719                 m_cachedSignature += t->cppSignature();
720                 // We need to have the argument names in the qdoc files
721                 m_cachedSignature += QLatin1Char(' ');
722                 m_cachedSignature += a->name();
723             } else {
724                 qCWarning(lcShiboken).noquote().nospace()
725                     << QString::fromLatin1("No abstract meta type found for argument '%1' while"
726                                            "constructing signature for function '%2'.")
727                                            .arg(a->name(), name());
728             }
729         }
730         m_cachedSignature += QLatin1Char(')');
731 
732         if (isConstant())
733             m_cachedSignature += QLatin1String(" const");
734     }
735     return m_cachedSignature;
736 }
737 
actualMinimumArgumentCount() const738 int AbstractMetaFunction::actualMinimumArgumentCount() const
739 {
740     AbstractMetaArgumentList arguments = this->arguments();
741 
742     int count = 0;
743     for (int i = 0; i < arguments.size(); ++i && ++count) {
744         if (argumentRemoved(i + 1))
745             --count;
746         else if (!arguments.at(i)->defaultValueExpression().isEmpty())
747             break;
748     }
749 
750     return count;
751 }
752 
753 // Returns reference counts for argument at idx, or all arguments if idx == -2
referenceCounts(const AbstractMetaClass * cls,int idx) const754 QVector<ReferenceCount> AbstractMetaFunction::referenceCounts(const AbstractMetaClass *cls, int idx) const
755 {
756     QVector<ReferenceCount> returned;
757 
758     const FunctionModificationList &mods = this->modifications(cls);
759     for (const FunctionModification &mod : mods) {
760         for (const ArgumentModification &argumentMod : mod.argument_mods) {
761             if (argumentMod.index != idx && idx != -2)
762                 continue;
763             returned += argumentMod.referenceCounts;
764         }
765     }
766 
767     return returned;
768 }
769 
770 
argumentOwner(const AbstractMetaClass * cls,int idx) const771 ArgumentOwner AbstractMetaFunction::argumentOwner(const AbstractMetaClass *cls, int idx) const
772 {
773     const FunctionModificationList &mods = this->modifications(cls);
774     for (const FunctionModification &mod : mods) {
775         for (const ArgumentModification &argumentMod : mod.argument_mods) {
776             if (argumentMod.index != idx)
777                 continue;
778             return argumentMod.owner;
779         }
780     }
781     return ArgumentOwner();
782 }
783 
conversionRule(TypeSystem::Language language,int key) const784 QString AbstractMetaFunction::conversionRule(TypeSystem::Language language, int key) const
785 {
786     const FunctionModificationList &modifications = this->modifications(declaringClass());
787     for (const FunctionModification &modification : modifications) {
788         for (const ArgumentModification &argumentModification : modification.argument_mods) {
789             if (argumentModification.index != key)
790                 continue;
791 
792             for (const CodeSnip &snip : argumentModification.conversion_rules) {
793                 if (snip.language == language && !snip.code().isEmpty())
794                     return snip.code();
795             }
796         }
797     }
798 
799     return QString();
800 }
801 
802 // FIXME If we remove a arg. in the method at the base class, it will not reflect here.
argumentRemoved(int key) const803 bool AbstractMetaFunction::argumentRemoved(int key) const
804 {
805     const FunctionModificationList &modifications = this->modifications(declaringClass());
806     for (const FunctionModification &modification : modifications) {
807         for (const ArgumentModification &argumentModification : modification.argument_mods) {
808             if (argumentModification.index == key) {
809                 if (argumentModification.removed)
810                     return true;
811             }
812         }
813     }
814 
815     return false;
816 }
817 
targetLangOwner() const818 const AbstractMetaClass *AbstractMetaFunction::targetLangOwner() const
819 {
820     return m_class && m_class->isInvisibleNamespace()
821         ?  m_class->targetLangEnclosingClass() : m_class;
822 }
823 
isDeprecated() const824 bool AbstractMetaFunction::isDeprecated() const
825 {
826     const FunctionModificationList &modifications = this->modifications(declaringClass());
827     for (const FunctionModification &modification : modifications) {
828         if (modification.isDeprecated())
829             return true;
830     }
831     return false;
832 }
833 
834 // Auto-detect whether a function should be wrapped into
835 // Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS, that is, temporarily release
836 // the GIL (global interpreter lock). Doing so is required for any thread-wait
837 // functions, anything that might call a virtual function (potentially
838 // reimplemented in Python), and recommended for lengthy I/O or similar.
839 // It has performance costs, though.
autoDetectAllowThread() const840 bool AbstractMetaFunction::autoDetectAllowThread() const
841 {
842     // Disallow for simple getter functions.
843     const bool maybeGetter = m_constant != 0 && !isVoid() && m_arguments.isEmpty();
844     return !maybeGetter;
845 }
846 
sourceLocation() const847 SourceLocation AbstractMetaFunction::sourceLocation() const
848 {
849     return m_sourceLocation;
850 }
851 
setSourceLocation(const SourceLocation & sourceLocation)852 void AbstractMetaFunction::setSourceLocation(const SourceLocation &sourceLocation)
853 {
854     m_sourceLocation = sourceLocation;
855 }
856 
allowThreadMod(const AbstractMetaClass * klass)857 static inline TypeSystem::AllowThread allowThreadMod(const AbstractMetaClass *klass)
858 {
859     return klass->typeEntry()->allowThread();
860 }
861 
hasAllowThreadMod(const AbstractMetaClass * klass)862 static inline bool hasAllowThreadMod(const AbstractMetaClass *klass)
863 {
864     return allowThreadMod(klass) != TypeSystem::AllowThread::Unspecified;
865 }
866 
allowThread() const867 bool AbstractMetaFunction::allowThread() const
868 {
869     auto allowThreadModification = m_allowThreadModification;
870     // If there is no modification on the function, check for a base class.
871     if (m_class && allowThreadModification == TypeSystem::AllowThread::Unspecified) {
872         if (auto base = recurseClassHierarchy(m_class, hasAllowThreadMod))
873             allowThreadModification = allowThreadMod(base);
874     }
875 
876     bool result = true;
877     switch (allowThreadModification) {
878     case TypeSystem::AllowThread::Disallow:
879         result = false;
880         break;
881     case TypeSystem::AllowThread::Allow:
882         break;
883     case TypeSystem::AllowThread::Auto:
884         result = autoDetectAllowThread();
885         break;
886     case TypeSystem::AllowThread::Unspecified:
887         result = false;
888         break;
889     }
890     if (!result && ReportHandler::isDebug(ReportHandler::MediumDebug))
891         qCInfo(lcShiboken).noquote() << msgDisallowThread(this);
892     return result;
893 }
894 
ownership(const AbstractMetaClass * cls,TypeSystem::Language language,int key) const895 TypeSystem::Ownership AbstractMetaFunction::ownership(const AbstractMetaClass *cls, TypeSystem::Language language, int key) const
896 {
897     const FunctionModificationList &modifications = this->modifications(cls);
898     for (const FunctionModification &modification : modifications) {
899         for (const ArgumentModification &argumentModification : modification.argument_mods) {
900             if (argumentModification.index == key)
901                 return argumentModification.ownerships.value(language, TypeSystem::InvalidOwnership);
902         }
903     }
904 
905     return TypeSystem::InvalidOwnership;
906 }
907 
isRemovedFromAllLanguages(const AbstractMetaClass * cls) const908 bool AbstractMetaFunction::isRemovedFromAllLanguages(const AbstractMetaClass *cls) const
909 {
910     return isRemovedFrom(cls, TypeSystem::All);
911 }
912 
isRemovedFrom(const AbstractMetaClass * cls,TypeSystem::Language language) const913 bool AbstractMetaFunction::isRemovedFrom(const AbstractMetaClass *cls, TypeSystem::Language language) const
914 {
915     const FunctionModificationList &modifications = this->modifications(cls);
916     for (const FunctionModification &modification : modifications) {
917         if ((modification.removal & language) == language)
918             return true;
919     }
920 
921     return false;
922 
923 }
924 
typeReplaced(int key) const925 QString AbstractMetaFunction::typeReplaced(int key) const
926 {
927     const FunctionModificationList &modifications = this->modifications(declaringClass());
928     for (const FunctionModification &modification : modifications) {
929         for (const ArgumentModification &argumentModification : modification.argument_mods) {
930             if (argumentModification.index == key
931                 && !argumentModification.modified_type.isEmpty()) {
932                 return argumentModification.modified_type;
933             }
934         }
935     }
936 
937     return QString();
938 }
939 
isModifiedToArray(int argumentIndex) const940 bool AbstractMetaFunction::isModifiedToArray(int argumentIndex) const
941 {
942     const FunctionModificationList &modifications = this->modifications(declaringClass());
943     for (const FunctionModification &modification : modifications) {
944         for (const ArgumentModification &argumentModification : modification.argument_mods) {
945             if (argumentModification.index == argumentIndex && argumentModification.array != 0)
946                 return true;
947         }
948     }
949     return false;
950 }
951 
minimalSignature() const952 QString AbstractMetaFunction::minimalSignature() const
953 {
954     if (!m_cachedMinimalSignature.isEmpty())
955         return m_cachedMinimalSignature;
956 
957     QString minimalSignature = originalName() + QLatin1Char('(');
958     AbstractMetaArgumentList arguments = this->arguments();
959 
960     for (int i = 0; i < arguments.count(); ++i) {
961         AbstractMetaType *t = arguments.at(i)->type();
962         if (t) {
963             if (i > 0)
964                 minimalSignature += QLatin1Char(',');
965             minimalSignature += t->minimalSignature();
966         } else {
967             qCWarning(lcShiboken).noquote().nospace()
968                 << QString::fromLatin1("No abstract meta type found for argument '%1' while constructing"
969                                        " minimal signature for function '%2'.")
970                                        .arg(arguments.at(i)->name(), name());
971         }
972     }
973     minimalSignature += QLatin1Char(')');
974     if (isConstant())
975         minimalSignature += QLatin1String("const");
976 
977     minimalSignature = TypeDatabase::normalizedSignature(minimalSignature);
978     m_cachedMinimalSignature = minimalSignature;
979 
980     return minimalSignature;
981 }
982 
debugSignature() const983 QString AbstractMetaFunction::debugSignature() const
984 {
985     QString result;
986     const bool isOverride = attributes() & AbstractMetaFunction::OverriddenCppMethod;
987     const bool isFinal = attributes() & AbstractMetaFunction::FinalCppMethod;
988     if (!isOverride && !isFinal && (attributes() & AbstractMetaFunction::VirtualCppMethod))
989         result += QLatin1String("virtual ");
990     result += minimalSignature();
991     if (isOverride)
992         result += QLatin1String(" override");
993     if (isFinal)
994         result += QLatin1String(" final");
995     return result;
996 }
997 
modifications(const AbstractMetaClass * implementor) const998 FunctionModificationList AbstractMetaFunction::modifications(const AbstractMetaClass *implementor) const
999 {
1000     if (!m_addedFunction.isNull())
1001         return m_addedFunction->modifications;
1002     if (!implementor)
1003         implementor = ownerClass();
1004 
1005     if (!implementor)
1006         return TypeDatabase::instance()->functionModifications(minimalSignature());
1007 
1008     FunctionModificationList mods;
1009     while (implementor) {
1010         mods += implementor->typeEntry()->functionModifications(minimalSignature());
1011         if ((implementor == implementor->baseClass()) ||
1012             (implementor == implementingClass() && !mods.isEmpty())) {
1013                 break;
1014         }
1015         implementor = implementor->baseClass();
1016     }
1017     return mods;
1018 }
1019 
argumentName(int index,bool,const AbstractMetaClass *) const1020 QString AbstractMetaFunction::argumentName(int index,
1021                                            bool /* create */,
1022                                            const AbstractMetaClass * /* implementor */) const
1023 {
1024     return m_arguments[--index]->name();
1025 }
1026 
isCallOperator() const1027 bool AbstractMetaFunction::isCallOperator() const
1028 {
1029     return m_name == QLatin1String("operator()");
1030 }
1031 
hasInjectedCode() const1032 bool AbstractMetaFunction::hasInjectedCode() const
1033 {
1034     const FunctionModificationList &mods = modifications(ownerClass());
1035     for (const FunctionModification &mod : mods) {
1036         if (mod.isCodeInjection())
1037             return true;
1038     }
1039     return false;
1040 }
1041 
injectedCodeSnips(TypeSystem::CodeSnipPosition position,TypeSystem::Language language) const1042 CodeSnipList AbstractMetaFunction::injectedCodeSnips(TypeSystem::CodeSnipPosition position, TypeSystem::Language language) const
1043 {
1044     CodeSnipList result;
1045     const FunctionModificationList &mods = modifications(ownerClass());
1046     for (const FunctionModification &mod : mods) {
1047         if (mod.isCodeInjection()) {
1048             for (const CodeSnip &snip : mod.snips) {
1049                 if ((snip.language & language) && (snip.position == position || position == TypeSystem::CodeSnipPositionAny))
1050                     result << snip;
1051             }
1052         }
1053     }
1054     return result;
1055 }
1056 
hasSignatureModifications() const1057 bool AbstractMetaFunction::hasSignatureModifications() const
1058 {
1059     const FunctionModificationList &mods = modifications();
1060     for (const FunctionModification &mod : mods) {
1061         if (mod.isRenameModifier())
1062             return true;
1063         for (const ArgumentModification &argmod : mod.argument_mods) {
1064             // since zero represents the return type and we're
1065             // interested only in checking the function arguments,
1066             // it will be ignored.
1067             if (argmod.index > 0)
1068                 return true;
1069         }
1070     }
1071     return false;
1072 }
1073 
isConversionOperator(const QString & funcName)1074 bool AbstractMetaFunction::isConversionOperator(const QString &funcName)
1075 {
1076     static const QRegularExpression opRegEx(QStringLiteral("^operator(?:\\s+(?:const|volatile))?\\s+(\\w+\\s*)&?$"));
1077     Q_ASSERT(opRegEx.isValid());
1078     return opRegEx.match(funcName).hasMatch();
1079 }
1080 
exceptionSpecification() const1081 ExceptionSpecification AbstractMetaFunction::exceptionSpecification() const
1082 {
1083     return m_exceptionSpecification;
1084 }
1085 
setExceptionSpecification(ExceptionSpecification e)1086 void AbstractMetaFunction::setExceptionSpecification(ExceptionSpecification e)
1087 {
1088     m_exceptionSpecification = e;
1089 }
1090 
exceptionMod(const AbstractMetaClass * klass)1091 static inline TypeSystem::ExceptionHandling exceptionMod(const AbstractMetaClass *klass)
1092 {
1093     return klass->typeEntry()->exceptionHandling();
1094 }
1095 
hasExceptionMod(const AbstractMetaClass * klass)1096 static inline bool hasExceptionMod(const AbstractMetaClass *klass)
1097 {
1098     return exceptionMod(klass) != TypeSystem::ExceptionHandling::Unspecified;
1099 }
1100 
generateExceptionHandling() const1101 bool AbstractMetaFunction::generateExceptionHandling() const
1102 {
1103     switch (m_functionType) {
1104     case AbstractMetaFunction::CopyConstructorFunction:
1105     case AbstractMetaFunction::MoveConstructorFunction:
1106     case AbstractMetaFunction::AssignmentOperatorFunction:
1107     case AbstractMetaFunction::MoveAssignmentOperatorFunction:
1108     case AbstractMetaFunction::DestructorFunction:
1109         return false;
1110     default:
1111         break;
1112     }
1113 
1114     auto exceptionHandlingModification = m_exceptionHandlingModification;
1115     // If there is no modification on the function, check for a base class.
1116     if (m_class && exceptionHandlingModification == TypeSystem::ExceptionHandling::Unspecified) {
1117         if (auto base = recurseClassHierarchy(m_class, hasExceptionMod))
1118             exceptionHandlingModification = exceptionMod(base);
1119     }
1120 
1121     bool result = false;
1122     switch (exceptionHandlingModification) {
1123     case TypeSystem::ExceptionHandling::On:
1124         result = true;
1125         break;
1126     case TypeSystem::ExceptionHandling::AutoDefaultToOn:
1127         result = m_exceptionSpecification != ExceptionSpecification::NoExcept;
1128         break;
1129     case TypeSystem::ExceptionHandling::AutoDefaultToOff:
1130         result = m_exceptionSpecification == ExceptionSpecification::Throws;
1131         break;
1132     case TypeSystem::ExceptionHandling::Unspecified:
1133     case TypeSystem::ExceptionHandling::Off:
1134         break;
1135     }
1136     return result;
1137 }
1138 
isOperatorOverload(const QString & funcName)1139 bool AbstractMetaFunction::isOperatorOverload(const QString &funcName)
1140 {
1141     if (isConversionOperator(funcName))
1142         return true;
1143 
1144     static const QRegularExpression opRegEx(QLatin1String("^operator([+\\-\\*/%=&\\|\\^\\<>!][=]?"
1145                     "|\\+\\+|\\-\\-|&&|\\|\\||<<[=]?|>>[=]?|~"
1146                     "|\\[\\]|\\s+delete\\[?\\]?"
1147                     "|\\(\\)"
1148                     "|\\s+new\\[?\\]?)$"));
1149     Q_ASSERT(opRegEx.isValid());
1150     return opRegEx.match(funcName).hasMatch();
1151 }
1152 
isCastOperator() const1153 bool AbstractMetaFunction::isCastOperator() const
1154 {
1155     return originalName().startsWith(QLatin1String("operator "));
1156 }
1157 
isArithmeticOperator() const1158 bool AbstractMetaFunction::isArithmeticOperator() const
1159 {
1160     if (!isOperatorOverload())
1161         return false;
1162 
1163     QString name = originalName();
1164 
1165     // It's a dereference operator!
1166     if (name == QLatin1String("operator*") && m_arguments.isEmpty())
1167         return false;
1168 
1169     return name == QLatin1String("operator+") || name == QLatin1String("operator+=")
1170             || name == QLatin1String("operator-") || name == QLatin1String("operator-=")
1171             || name == QLatin1String("operator*") || name == QLatin1String("operator*=")
1172             || name == QLatin1String("operator/") || name == QLatin1String("operator/=")
1173             || name == QLatin1String("operator%") || name == QLatin1String("operator%=")
1174             || name == QLatin1String("operator++") || name == QLatin1String("operator--");
1175 }
1176 
isBitwiseOperator() const1177 bool AbstractMetaFunction::isBitwiseOperator() const
1178 {
1179     if (!isOperatorOverload())
1180         return false;
1181 
1182     QString name = originalName();
1183     return name == QLatin1String("operator<<") || name == QLatin1String("operator<<=")
1184             || name == QLatin1String("operator>>") || name == QLatin1String("operator>>=")
1185             || name == QLatin1String("operator&") || name == QLatin1String("operator&=")
1186             || name == QLatin1String("operator|") || name == QLatin1String("operator|=")
1187             || name == QLatin1String("operator^") || name == QLatin1String("operator^=")
1188             || name == QLatin1String("operator~");
1189 }
1190 
isComparisonOperator() const1191 bool AbstractMetaFunction::isComparisonOperator() const
1192 {
1193     if (!isOperatorOverload())
1194         return false;
1195 
1196     QString name = originalName();
1197     return name == QLatin1String("operator<") || name == QLatin1String("operator<=")
1198             || name == QLatin1String("operator>") || name == QLatin1String("operator>=")
1199             || name == QLatin1String("operator==") || name == QLatin1String("operator!=");
1200 }
1201 
isLogicalOperator() const1202 bool AbstractMetaFunction::isLogicalOperator() const
1203 {
1204     if (!isOperatorOverload())
1205         return false;
1206 
1207     QString name = originalName();
1208     return name == QLatin1String("operator!")
1209             || name == QLatin1String("operator&&")
1210             || name == QLatin1String("operator||");
1211 }
1212 
isSubscriptOperator() const1213 bool AbstractMetaFunction::isSubscriptOperator() const
1214 {
1215     if (!isOperatorOverload())
1216         return false;
1217 
1218     return originalName() == QLatin1String("operator[]");
1219 }
1220 
isAssignmentOperator() const1221 bool AbstractMetaFunction::isAssignmentOperator() const
1222 {
1223     return m_functionType == AssignmentOperatorFunction
1224         || m_functionType == MoveAssignmentOperatorFunction;
1225 }
1226 
isOtherOperator() const1227 bool AbstractMetaFunction::isOtherOperator() const
1228 {
1229     if (!isOperatorOverload())
1230         return false;
1231 
1232     return !isArithmeticOperator()
1233             && !isBitwiseOperator()
1234             && !isComparisonOperator()
1235             && !isLogicalOperator()
1236             && !isConversionOperator()
1237             && !isSubscriptOperator()
1238             && !isAssignmentOperator();
1239 }
1240 
arityOfOperator() const1241 int AbstractMetaFunction::arityOfOperator() const
1242 {
1243     if (!isOperatorOverload() || isCallOperator())
1244         return -1;
1245 
1246     int arity = m_arguments.size();
1247 
1248     // Operator overloads that are class members
1249     // implicitly includes the instance and have
1250     // one parameter less than their arity,
1251     // so we increment it.
1252     if (ownerClass() && arity < 2)
1253         arity++;
1254 
1255     return arity;
1256 }
1257 
isInplaceOperator() const1258 bool AbstractMetaFunction::isInplaceOperator() const
1259 {
1260     if (!isOperatorOverload())
1261         return false;
1262 
1263     QString name = originalName();
1264     return name == QLatin1String("operator+=") || name == QLatin1String("operator&=")
1265            || name == QLatin1String("operator-=") || name == QLatin1String("operator|=")
1266            || name == QLatin1String("operator*=") || name == QLatin1String("operator^=")
1267            || name == QLatin1String("operator/=") || name == QLatin1String("operator<<=")
1268            || name == QLatin1String("operator%=") || name == QLatin1String("operator>>=");
1269 }
1270 
isVirtual() const1271 bool AbstractMetaFunction::isVirtual() const
1272 {
1273     return attributes() & AbstractMetaAttributes::VirtualCppMethod;
1274 }
1275 
modifiedName() const1276 QString AbstractMetaFunction::modifiedName() const
1277 {
1278     if (m_cachedModifiedName.isEmpty()) {
1279         const FunctionModificationList &mods = modifications(implementingClass());
1280         for (const FunctionModification &mod : mods) {
1281             if (mod.isRenameModifier()) {
1282                 m_cachedModifiedName = mod.renamedToName;
1283                 break;
1284             }
1285         }
1286         if (m_cachedModifiedName.isEmpty())
1287             m_cachedModifiedName = name();
1288     }
1289     return m_cachedModifiedName;
1290 }
1291 
function_sorter(AbstractMetaFunction * a,AbstractMetaFunction * b)1292 bool function_sorter(AbstractMetaFunction *a, AbstractMetaFunction *b)
1293 {
1294     return a->signature() < b->signature();
1295 }
1296 
1297 AbstractMetaFunction *
find(const AbstractMetaFunctionList & haystack,const QString & needle)1298 AbstractMetaFunction::find(const AbstractMetaFunctionList &haystack,
1299                            const QString &needle)
1300 {
1301     return findByName(haystack, needle);
1302 }
1303 
overloadNumber() const1304 int AbstractMetaFunction::overloadNumber() const
1305 {
1306     if (m_cachedOverloadNumber == TypeSystem::OverloadNumberUnset) {
1307         m_cachedOverloadNumber = TypeSystem::OverloadNumberDefault;
1308         const FunctionModificationList &mods = modifications(implementingClass());
1309         for (const FunctionModification &mod : mods) {
1310             if (mod.overloadNumber() != TypeSystem::OverloadNumberUnset) {
1311                 m_cachedOverloadNumber = mod.overloadNumber();
1312                 break;
1313             }
1314         }
1315     }
1316     return m_cachedOverloadNumber;
1317 }
1318 
1319 #ifndef QT_NO_DEBUG_STREAM
formatMetaFunctionBrief(QDebug & d,const AbstractMetaFunction * af)1320 static inline void formatMetaFunctionBrief(QDebug &d, const AbstractMetaFunction *af)
1321 {
1322     d << '"' << af->debugSignature() << '"';
1323 }
1324 
formatDebugVerbose(QDebug & d) const1325 void AbstractMetaFunction::formatDebugVerbose(QDebug &d) const
1326 {
1327     d << m_functionType << ' ' << m_type << ' ' << m_name;
1328     switch (m_exceptionSpecification) {
1329     case ExceptionSpecification::Unknown:
1330         break;
1331     case ExceptionSpecification::NoExcept:
1332         d << " noexcept";
1333         break;
1334     case ExceptionSpecification::Throws:
1335         d << " throw(...)";
1336         break;
1337     }
1338     if (m_exceptionHandlingModification != TypeSystem::ExceptionHandling::Unspecified)
1339         d << " exeption-mod " << int(m_exceptionHandlingModification);
1340     d << '(';
1341     for (int i = 0, count = m_arguments.size(); i < count; ++i) {
1342         if (i)
1343             d << ", ";
1344         d <<  m_arguments.at(i);
1345     }
1346     d << "), signature=\"" << minimalSignature() << '"';
1347     if (m_constant)
1348         d << " [const]";
1349     if (m_reverse)
1350         d << " [reverse]";
1351     if (isUserAdded())
1352         d << " [userAdded]";
1353     if (m_explicit)
1354         d << " [explicit]";
1355     if (attributes().testFlag(AbstractMetaAttributes::Deprecated))
1356         d << " [deprecated]";
1357     if (m_pointerOperator)
1358         d << " [operator->]";
1359     if (m_isCallOperator)
1360         d << " [operator()]";
1361     if (m_class)
1362         d << " class: " << m_class->name();
1363     if (m_implementingClass)
1364         d << " implementing class: " << m_implementingClass->name();
1365     if (m_declaringClass)
1366         d << " declaring class: " << m_declaringClass->name();
1367 }
1368 
operator <<(QDebug d,const AbstractMetaFunction * af)1369 QDebug operator<<(QDebug d, const AbstractMetaFunction *af)
1370 {
1371     QDebugStateSaver saver(d);
1372     d.noquote();
1373     d.nospace();
1374     d << "AbstractMetaFunction(";
1375     if (af) {
1376 #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
1377         if (d.verbosity() > 2) {
1378             af->formatDebugVerbose(d);
1379         } else {
1380 #endif
1381             d << "signature=";
1382             formatMetaFunctionBrief(d, af);
1383 #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
1384         }
1385 #endif
1386     } else {
1387         d << '0';
1388     }
1389     d << ')';
1390     return d;
1391 }
1392 #endif // !QT_NO_DEBUG_STREAM
1393 
1394 /*******************************************************************************
1395  * AbstractMetaClass
1396  */
1397 
AbstractMetaClass()1398 AbstractMetaClass::AbstractMetaClass()
1399     : m_hasVirtuals(false),
1400       m_isPolymorphic(false),
1401       m_hasNonpublic(false),
1402       m_hasNonPrivateConstructor(false),
1403       m_hasPrivateConstructor(false),
1404       m_functionsFixed(false),
1405       m_hasPrivateDestructor(false),
1406       m_hasProtectedDestructor(false),
1407       m_hasVirtualDestructor(false),
1408       m_hasHashFunction(false),
1409       m_hasEqualsOperator(false),
1410       m_hasCloneOperator(false),
1411       m_isTypeDef(false),
1412       m_hasToStringCapability(false)
1413 {
1414 }
1415 
~AbstractMetaClass()1416 AbstractMetaClass::~AbstractMetaClass()
1417 {
1418     qDeleteAll(m_functions);
1419     qDeleteAll(m_fields);
1420     qDeleteAll(m_enums);
1421     qDeleteAll(m_propertySpecs);
1422     qDeleteAll(m_baseTemplateInstantiations);
1423 }
1424 
1425 /*******************************************************************************
1426  * Returns true if this class is a subclass of the given class
1427  */
inheritsFrom(const AbstractMetaClass * cls) const1428 bool AbstractMetaClass::inheritsFrom(const AbstractMetaClass *cls) const
1429 {
1430     Q_ASSERT(cls);
1431 
1432     const AbstractMetaClass *clazz = this;
1433     while (clazz) {
1434         if (clazz == cls)
1435             return true;
1436 
1437         clazz = clazz->baseClass();
1438     }
1439 
1440     return false;
1441 }
1442 
1443 /*******************************************************************************
1444  * Returns a list of all the functions with a given name
1445  */
queryFunctionsByName(const QString & name) const1446 AbstractMetaFunctionList AbstractMetaClass::queryFunctionsByName(const QString &name) const
1447 {
1448     AbstractMetaFunctionList returned;
1449     for (AbstractMetaFunction *function : m_functions) {
1450         if (function->name() == name)
1451             returned.append(function);
1452     }
1453 
1454     return returned;
1455 }
1456 
1457 /*******************************************************************************
1458  * Returns a list of all the functions retrieved during parsing which should
1459  * be added to the API.
1460  */
functionsInTargetLang() const1461 AbstractMetaFunctionList AbstractMetaClass::functionsInTargetLang() const
1462 {
1463     FunctionQueryOptions default_flags = NormalFunctions | Visible | NotRemovedFromTargetLang;
1464 
1465     // Only public functions in final classes
1466     // default_flags |= isFinal() ? WasPublic : 0;
1467     FunctionQueryOptions public_flags;
1468     if (isFinalInTargetLang())
1469         public_flags |= WasPublic;
1470 
1471     // Constructors
1472     AbstractMetaFunctionList returned = queryFunctions(Constructors | default_flags | public_flags);
1473 
1474     // Final functions
1475     returned += queryFunctions(FinalInTargetLangFunctions | NonStaticFunctions | default_flags | public_flags);
1476 
1477     // Virtual functions
1478     returned += queryFunctions(VirtualInTargetLangFunctions | NonStaticFunctions | default_flags | public_flags);
1479 
1480     // Static functions
1481     returned += queryFunctions(StaticFunctions | default_flags | public_flags);
1482 
1483     // Empty, private functions, since they aren't caught by the other ones
1484     returned += queryFunctions(Empty | Invisible);
1485 
1486     return returned;
1487 }
1488 
implicitConversions() const1489 AbstractMetaFunctionList AbstractMetaClass::implicitConversions() const
1490 {
1491     if (!hasCloneOperator() && !hasExternalConversionOperators())
1492         return AbstractMetaFunctionList();
1493 
1494     AbstractMetaFunctionList returned;
1495     const AbstractMetaFunctionList list = queryFunctions(Constructors) + externalConversionOperators();
1496 
1497     // Exclude anything that uses rvalue references, be it a move
1498     // constructor "QPolygon(QPolygon &&)" or something else like
1499     // "QPolygon(QVector<QPoint> &&)".
1500     for (AbstractMetaFunction *f : list) {
1501         if ((f->actualMinimumArgumentCount() == 1 || f->arguments().size() == 1 || f->isConversionOperator())
1502             && !f->isExplicit()
1503             && f->functionType() != AbstractMetaFunction::CopyConstructorFunction
1504             && !f->usesRValueReferences()
1505             && !f->isModifiedRemoved()
1506             && (f->originalAttributes() & Public)) {
1507             returned += f;
1508         }
1509     }
1510     return returned;
1511 }
1512 
operatorOverloads(OperatorQueryOptions query) const1513 AbstractMetaFunctionList AbstractMetaClass::operatorOverloads(OperatorQueryOptions query) const
1514 {
1515     const AbstractMetaFunctionList &list = queryFunctions(OperatorOverloads | Visible);
1516     AbstractMetaFunctionList returned;
1517     for (AbstractMetaFunction *f : list) {
1518         if (((query & ArithmeticOp) && f->isArithmeticOperator())
1519             || ((query & BitwiseOp) && f->isBitwiseOperator())
1520             || ((query & ComparisonOp) && f->isComparisonOperator())
1521             || ((query & LogicalOp) && f->isLogicalOperator())
1522             || ((query & SubscriptionOp) && f->isSubscriptOperator())
1523             || ((query & AssignmentOp) && f->isAssignmentOperator())
1524             || ((query & ConversionOp) && f->isConversionOperator())
1525             || ((query & OtherOp) && f->isOtherOperator()))
1526             returned += f;
1527     }
1528 
1529     return returned;
1530 }
1531 
hasArithmeticOperatorOverload() const1532 bool AbstractMetaClass::hasArithmeticOperatorOverload() const
1533 {
1534     for (const AbstractMetaFunction *f : m_functions) {
1535         if (f->ownerClass() == f->implementingClass() && f->isArithmeticOperator() && !f->isPrivate())
1536             return true;
1537     }
1538     return false;
1539 }
1540 
hasBitwiseOperatorOverload() const1541 bool AbstractMetaClass::hasBitwiseOperatorOverload() const
1542 {
1543     for (const AbstractMetaFunction *f : m_functions) {
1544         if (f->ownerClass() == f->implementingClass() && f->isBitwiseOperator() && !f->isPrivate())
1545             return true;
1546     }
1547     return false;
1548 }
1549 
hasComparisonOperatorOverload() const1550 bool AbstractMetaClass::hasComparisonOperatorOverload() const
1551 {
1552     for (const AbstractMetaFunction *f : m_functions) {
1553         if (f->ownerClass() == f->implementingClass() && f->isComparisonOperator() && !f->isPrivate())
1554             return true;
1555     }
1556     return false;
1557 }
1558 
hasLogicalOperatorOverload() const1559 bool AbstractMetaClass::hasLogicalOperatorOverload() const
1560 {
1561     for (const AbstractMetaFunction *f : m_functions) {
1562         if (f->ownerClass() == f->implementingClass() && f->isLogicalOperator() && !f->isPrivate())
1563             return true;
1564     }
1565     return false;
1566 }
1567 
sortFunctions()1568 void AbstractMetaClass::sortFunctions()
1569 {
1570     std::sort(m_functions.begin(), m_functions.end(), function_sorter);
1571 }
1572 
setFunctions(const AbstractMetaFunctionList & functions)1573 void AbstractMetaClass::setFunctions(const AbstractMetaFunctionList &functions)
1574 {
1575     m_functions = functions;
1576 
1577     // Functions must be sorted by name before next loop
1578     sortFunctions();
1579 
1580     for (AbstractMetaFunction *f : qAsConst(m_functions)) {
1581         f->setOwnerClass(this);
1582         if (!f->isPublic())
1583             m_hasNonpublic = true;
1584     }
1585 }
1586 
hasDefaultToStringFunction() const1587 bool AbstractMetaClass::hasDefaultToStringFunction() const
1588 {
1589     const AbstractMetaFunctionList &funcs = queryFunctionsByName(QLatin1String("toString"));
1590     for (const AbstractMetaFunction *f : funcs) {
1591         if (!f->actualMinimumArgumentCount())
1592             return true;
1593     }
1594     return false;
1595 }
1596 
addFunction(AbstractMetaFunction * function)1597 void AbstractMetaClass::addFunction(AbstractMetaFunction *function)
1598 {
1599     Q_ASSERT(!function->signature().startsWith(QLatin1Char('(')));
1600     function->setOwnerClass(this);
1601 
1602     if (!function->isDestructor())
1603         m_functions << function;
1604     else
1605         Q_ASSERT(false); //memory leak
1606 
1607     m_hasVirtuals |= function->isVirtual();
1608     m_isPolymorphic |= m_hasVirtuals;
1609     m_hasNonpublic |= !function->isPublic();
1610 }
1611 
hasSignal(const AbstractMetaFunction * other) const1612 bool AbstractMetaClass::hasSignal(const AbstractMetaFunction *other) const
1613 {
1614     if (!other->isSignal())
1615         return false;
1616 
1617     for (const AbstractMetaFunction *f : m_functions) {
1618         if (f->isSignal() && f->compareTo(other) & AbstractMetaFunction::EqualName)
1619             return other->modifiedName() == f->modifiedName();
1620     }
1621 
1622     return false;
1623 }
1624 
1625 
name() const1626 QString AbstractMetaClass::name() const
1627 {
1628     return m_typeEntry->targetLangEntryName();
1629 }
1630 
addBaseClass(AbstractMetaClass * baseClass)1631 void AbstractMetaClass::addBaseClass(AbstractMetaClass *baseClass)
1632 {
1633     Q_ASSERT(baseClass);
1634     m_baseClasses.append(baseClass);
1635     m_isPolymorphic |= baseClass->isPolymorphic();
1636 }
1637 
setBaseClass(AbstractMetaClass * baseClass)1638 void AbstractMetaClass::setBaseClass(AbstractMetaClass *baseClass)
1639 {
1640     if (baseClass) {
1641         m_baseClasses.prepend(baseClass);
1642         m_isPolymorphic |= baseClass->isPolymorphic();
1643     }
1644 }
1645 
package() const1646 QString AbstractMetaClass::package() const
1647 {
1648     return m_typeEntry->targetLangPackage();
1649 }
1650 
isNamespace() const1651 bool AbstractMetaClass::isNamespace() const
1652 {
1653     return m_typeEntry->isNamespace();
1654 }
1655 
1656 // Is an invisible namespaces whose functions/enums
1657 // should be mapped to the global space.
isInvisibleNamespace() const1658 bool AbstractMetaClass::isInvisibleNamespace() const
1659 {
1660     return m_typeEntry->isNamespace() && m_typeEntry->generateCode()
1661         && !NamespaceTypeEntry::isVisibleScope(m_typeEntry);
1662 }
1663 
qObjectPredicate(const AbstractMetaClass * c)1664 static bool qObjectPredicate(const AbstractMetaClass *c)
1665 {
1666     return c->qualifiedCppName() == QLatin1String("QObject");
1667 }
1668 
isQObject() const1669 bool AbstractMetaClass::isQObject() const
1670 {
1671     return qObjectPredicate(this) || recurseClassHierarchy(this, qObjectPredicate) != nullptr;
1672 }
1673 
qualifiedCppName() const1674 QString AbstractMetaClass::qualifiedCppName() const
1675 {
1676     return m_typeEntry->qualifiedCppName();
1677 }
1678 
hasFunction(const QString & str) const1679 bool AbstractMetaClass::hasFunction(const QString &str) const
1680 {
1681     return findFunction(str);
1682 }
1683 
findFunction(const QString & functionName) const1684 const AbstractMetaFunction *AbstractMetaClass::findFunction(const QString &functionName) const
1685 {
1686     return AbstractMetaFunction::find(m_functions, functionName);
1687 }
1688 
hasProtectedFunctions() const1689 bool AbstractMetaClass::hasProtectedFunctions() const
1690 {
1691     for (AbstractMetaFunction *func : m_functions) {
1692         if (func->isProtected())
1693             return true;
1694     }
1695     return false;
1696 }
1697 
hasProtectedFields() const1698 bool AbstractMetaClass::hasProtectedFields() const
1699 {
1700     for (const AbstractMetaField *field : m_fields) {
1701         if (field->isProtected())
1702             return true;
1703     }
1704     return false;
1705 }
1706 
hasProtectedMembers() const1707 bool AbstractMetaClass::hasProtectedMembers() const
1708 {
1709     return hasProtectedFields() || hasProtectedFunctions();
1710 }
1711 
propertySpecByName(const QString & name) const1712 QPropertySpec *AbstractMetaClass::propertySpecByName(const QString &name) const
1713 {
1714     for (auto propertySpec : m_propertySpecs) {
1715         if (name == propertySpec->name())
1716             return propertySpec;
1717     }
1718     return nullptr;
1719 }
1720 
propertySpecForRead(const QString & name) const1721 QPropertySpec *AbstractMetaClass::propertySpecForRead(const QString &name) const
1722 {
1723     for (const auto &propertySpec : m_propertySpecs) {
1724         if (name == propertySpec->read())
1725             return propertySpec;
1726     }
1727     return nullptr;
1728 }
1729 
propertySpecForWrite(const QString & name) const1730 QPropertySpec *AbstractMetaClass::propertySpecForWrite(const QString &name) const
1731 {
1732     for (const auto &propertySpec : m_propertySpecs) {
1733         if (name == propertySpec->write())
1734             return propertySpec;
1735     }
1736     return nullptr;
1737 }
1738 
propertySpecForReset(const QString & name) const1739 QPropertySpec *AbstractMetaClass::propertySpecForReset(const QString &name) const
1740 {
1741     for (const auto &propertySpec : m_propertySpecs) {
1742         if (name == propertySpec->reset())
1743             return propertySpec;
1744     }
1745     return nullptr;
1746 }
1747 
hasTemplateBaseClassInstantiations() const1748 bool AbstractMetaClass::hasTemplateBaseClassInstantiations() const
1749 {
1750     return m_templateBaseClass != nullptr && !m_baseTemplateInstantiations.isEmpty();
1751 }
1752 
templateBaseClassInstantiations() const1753 const AbstractMetaTypeList &AbstractMetaClass::templateBaseClassInstantiations() const
1754 {
1755     return m_baseTemplateInstantiations;
1756 }
1757 
setTemplateBaseClassInstantiations(const AbstractMetaTypeList & instantiations)1758 void AbstractMetaClass::setTemplateBaseClassInstantiations(const AbstractMetaTypeList &instantiations)
1759 {
1760     Q_ASSERT(m_templateBaseClass != nullptr);
1761     m_baseTemplateInstantiations = instantiations;
1762 }
1763 
1764 // Does any of the base classes require deletion in the main thread?
deleteInMainThread() const1765 bool AbstractMetaClass::deleteInMainThread() const
1766 {
1767     return typeEntry()->deleteInMainThread()
1768         || (!m_baseClasses.isEmpty() && m_baseClasses.constFirst()->deleteInMainThread());
1769 }
1770 
functions_contains(const AbstractMetaFunctionList & l,const AbstractMetaFunction * func)1771 static bool functions_contains(const AbstractMetaFunctionList &l, const AbstractMetaFunction *func)
1772 {
1773     for (const AbstractMetaFunction *f : l) {
1774         if ((f->compareTo(func) & AbstractMetaFunction::PrettySimilar) == AbstractMetaFunction::PrettySimilar)
1775             return true;
1776     }
1777     return false;
1778 }
1779 
1780 AbstractMetaField::AbstractMetaField() = default;
1781 
copy() const1782 AbstractMetaField *AbstractMetaField::copy() const
1783 {
1784     auto *returned = new AbstractMetaField;
1785     returned->assignMetaVariable(*this);
1786     returned->assignMetaAttributes(*this);
1787     returned->setEnclosingClass(nullptr);
1788     return returned;
1789 }
1790 
find(const AbstractMetaFieldList & haystack,const QString & needle)1791 AbstractMetaField *AbstractMetaField::find(const AbstractMetaFieldList &haystack,
1792                                            const QString &needle)
1793 {
1794     return findByName(haystack, needle);
1795 }
1796 /*******************************************************************************
1797  * Indicates that this field has a modification that removes it
1798  */
isModifiedRemoved(int types) const1799 bool AbstractMetaField::isModifiedRemoved(int types) const
1800 {
1801     const FieldModificationList &mods = modifications();
1802     for (const FieldModification &mod : mods) {
1803         if (!mod.isRemoveModifier())
1804             continue;
1805 
1806         if ((mod.removal & types) == types)
1807             return true;
1808     }
1809 
1810     return false;
1811 }
1812 
modifications() const1813 FieldModificationList AbstractMetaField::modifications() const
1814 {
1815     const FieldModificationList &mods = enclosingClass()->typeEntry()->fieldModifications();
1816     FieldModificationList returned;
1817 
1818     for (const FieldModification &mod : mods) {
1819         if (mod.name == name())
1820             returned += mod;
1821     }
1822 
1823     return returned;
1824 }
1825 
targetLangEnclosingClass() const1826 const AbstractMetaClass *EnclosingClassMixin::targetLangEnclosingClass() const
1827 {
1828     auto result = m_enclosingClass;
1829     while (result && !NamespaceTypeEntry::isVisibleScope(result->typeEntry()))
1830         result = result->enclosingClass();
1831     return result;
1832 }
1833 
1834 #ifndef QT_NO_DEBUG_STREAM
formatMetaAttributes(QDebug & d,AbstractMetaAttributes::Attributes value)1835 static void formatMetaAttributes(QDebug &d, AbstractMetaAttributes::Attributes value)
1836 {
1837     static const int meIndex = AbstractMetaAttributes::staticMetaObject.indexOfEnumerator("Attribute");
1838     Q_ASSERT(meIndex >= 0);
1839     const QMetaEnum me = AbstractMetaAttributes::staticMetaObject.enumerator(meIndex);
1840     d << me.valueToKeys(value);
1841 }
1842 
formatMetaField(QDebug & d,const AbstractMetaField * af)1843 static void formatMetaField(QDebug &d, const AbstractMetaField *af)
1844 {
1845     formatMetaAttributes(d, af->attributes());
1846     d << ' ' << af->type()->name() << " \"" << af->name() << '"';
1847 }
1848 
operator <<(QDebug d,const AbstractMetaField * af)1849 QDebug operator<<(QDebug d, const AbstractMetaField *af)
1850 {
1851     QDebugStateSaver saver(d);
1852     d.noquote();
1853     d.nospace();
1854     d << "AbstractMetaField(";
1855     if (af)
1856         formatMetaField(d, af);
1857     else
1858         d << '0';
1859     d << ')';
1860     return d;
1861 }
1862 
formatMetaEnumValue(QDebug & d,const AbstractMetaEnumValue * v)1863 static void formatMetaEnumValue(QDebug &d, const AbstractMetaEnumValue *v)
1864 {
1865     const QString &name = v->stringValue();
1866     if (!name.isEmpty())
1867         d << name << '=';
1868     d << v->value();
1869 }
1870 
operator <<(QDebug d,const AbstractMetaEnumValue * v)1871 QDebug operator<<(QDebug d, const AbstractMetaEnumValue *v)
1872 {
1873     QDebugStateSaver saver(d);
1874     d.noquote();
1875     d.nospace();
1876     d << "AbstractMetaEnumValue(";
1877     if (v)
1878         formatMetaEnumValue(d, v);
1879     else
1880         d << '0';
1881     d << ')';
1882     return d;
1883 }
1884 
operator <<(QDebug d,const AbstractMetaEnum * ae)1885 QDebug operator<<(QDebug d, const AbstractMetaEnum *ae)
1886 {
1887     QDebugStateSaver saver(d);
1888     d.noquote();
1889     d.nospace();
1890     d << "AbstractMetaEnum(";
1891     if (ae) {
1892         d << ae->fullName();
1893         if (!ae->isSigned())
1894             d << " (unsigned) ";
1895         d << '[';
1896         const AbstractMetaEnumValueList &values = ae->values();
1897         for (int i = 0, count = values.size(); i < count; ++i) {
1898             if (i)
1899                 d << ' ';
1900             formatMetaEnumValue(d, values.at(i));
1901         }
1902         d << ']';
1903     } else {
1904         d << '0';
1905     }
1906     d << ')';
1907     return d;
1908 }
1909 #endif // !QT_NO_DEBUG_STREAM
1910 
hasConstructors() const1911 bool AbstractMetaClass::hasConstructors() const
1912 {
1913     return AbstractMetaClass::queryFirstFunction(m_functions, Constructors) != nullptr;
1914 }
1915 
copyConstructor() const1916 const AbstractMetaFunction *AbstractMetaClass::copyConstructor() const
1917 {
1918     for (const AbstractMetaFunction *f : m_functions) {
1919         if (f->functionType() == AbstractMetaFunction::CopyConstructorFunction)
1920             return f;
1921     }
1922     return nullptr;
1923 }
1924 
hasPrivateCopyConstructor() const1925 bool AbstractMetaClass::hasPrivateCopyConstructor() const
1926 {
1927     const AbstractMetaFunction *copyCt = copyConstructor();
1928     return copyCt && copyCt->isPrivate();
1929 }
1930 
addDefaultConstructor()1931 void AbstractMetaClass::addDefaultConstructor()
1932 {
1933     auto *f = new AbstractMetaFunction;
1934     f->setType(AbstractMetaType::createVoid());
1935     f->setOriginalName(name());
1936     f->setName(name());
1937     f->setOwnerClass(this);
1938     f->setFunctionType(AbstractMetaFunction::ConstructorFunction);
1939     f->setArguments(AbstractMetaArgumentList());
1940     f->setDeclaringClass(this);
1941 
1942     f->setAttributes(Public | FinalInTargetLang | AddedMethod);
1943     f->setImplementingClass(this);
1944     f->setOriginalAttributes(f->attributes());
1945 
1946     addFunction(f);
1947     this->setHasNonPrivateConstructor(true);
1948 }
1949 
addDefaultCopyConstructor(bool isPrivate)1950 void AbstractMetaClass::addDefaultCopyConstructor(bool isPrivate)
1951 {
1952     auto f = new AbstractMetaFunction;
1953     f->setType(AbstractMetaType::createVoid());
1954     f->setOriginalName(name());
1955     f->setName(name());
1956     f->setOwnerClass(this);
1957     f->setFunctionType(AbstractMetaFunction::CopyConstructorFunction);
1958     f->setDeclaringClass(this);
1959 
1960     auto argType = new AbstractMetaType(typeEntry());
1961     argType->setReferenceType(LValueReference);
1962     argType->setConstant(true);
1963     argType->setTypeUsagePattern(AbstractMetaType::ValuePattern);
1964 
1965     auto arg = new AbstractMetaArgument;
1966     arg->setType(argType);
1967     arg->setName(name());
1968     f->addArgument(arg);
1969 
1970     AbstractMetaAttributes::Attributes attr = FinalInTargetLang | AddedMethod;
1971     if (isPrivate)
1972         attr |= AbstractMetaAttributes::Private;
1973     else
1974         attr |= AbstractMetaAttributes::Public;
1975     f->setAttributes(attr);
1976     f->setImplementingClass(this);
1977     f->setOriginalAttributes(f->attributes());
1978 
1979     addFunction(f);
1980 }
1981 
setHasVirtualDestructor(bool value)1982 void AbstractMetaClass::setHasVirtualDestructor(bool value)
1983 {
1984     m_hasVirtualDestructor = value;
1985     if (value)
1986         m_hasVirtuals = m_isPolymorphic = 1;
1987 }
1988 
hasFunction(const AbstractMetaFunction * f) const1989 bool AbstractMetaClass::hasFunction(const AbstractMetaFunction *f) const
1990 {
1991     return functions_contains(m_functions, f);
1992 }
1993 
generateExceptionHandling() const1994 bool AbstractMetaClass::generateExceptionHandling() const
1995 {
1996     return queryFirstFunction(m_functions, AbstractMetaClass::Visible
1997                               | AbstractMetaClass::GenerateExceptionHandling) != nullptr;
1998 }
1999 /* Goes through the list of functions and returns a list of all
2000    functions matching all of the criteria in \a query.
2001  */
2002 
queryFunction(const AbstractMetaFunction * f,FunctionQueryOptions query)2003 bool AbstractMetaClass::queryFunction(const AbstractMetaFunction *f, FunctionQueryOptions query)
2004 {
2005     if ((query & NotRemovedFromTargetLang)
2006         && f->isRemovedFrom(f->implementingClass(), TypeSystem::TargetLangCode)) {
2007         return false;
2008     }
2009 
2010     if ((query & NotRemovedFromTargetLang) && f->isVirtual()
2011         && f->isRemovedFrom(f->declaringClass(), TypeSystem::TargetLangCode)) {
2012         return false;
2013     }
2014 
2015     if ((query & Visible) && f->isPrivate())
2016         return false;
2017 
2018     if ((query & VirtualInTargetLangFunctions) && f->isFinalInTargetLang())
2019         return false;
2020 
2021     if ((query & Invisible) && !f->isPrivate())
2022         return false;
2023 
2024     if ((query & Empty) && !f->isEmptyFunction())
2025         return false;
2026 
2027     if ((query & WasPublic) && !f->wasPublic())
2028         return false;
2029 
2030     if ((query & ClassImplements) && f->ownerClass() != f->implementingClass())
2031         return false;
2032 
2033     if ((query & FinalInTargetLangFunctions) && !f->isFinalInTargetLang())
2034         return false;
2035 
2036     if ((query & VirtualInCppFunctions) && !f->isVirtual())
2037         return false;
2038 
2039     if ((query & Signals) && (!f->isSignal()))
2040         return false;
2041 
2042     if ((query & Constructors) && (!f->isConstructor() || f->ownerClass() != f->implementingClass()))
2043         return false;
2044 
2045     if (!(query & Constructors) && f->isConstructor())
2046         return false;
2047 
2048     // Destructors are never included in the functions of a class currently
2049     /*
2050            if ((query & Destructors) && (!f->isDestructor()
2051                                        || f->ownerClass() != f->implementingClass())
2052             || f->isDestructor() && (query & Destructors) == 0) {
2053             return false;
2054         }*/
2055 
2056     if ((query & StaticFunctions) && (!f->isStatic() || f->isSignal()))
2057         return false;
2058 
2059     if ((query & NonStaticFunctions) && (f->isStatic()))
2060         return false;
2061 
2062     if ((query & NormalFunctions) && (f->isSignal()))
2063         return false;
2064 
2065     if ((query & OperatorOverloads) && !f->isOperatorOverload())
2066         return false;
2067 
2068     if ((query & GenerateExceptionHandling) && !f->generateExceptionHandling())
2069         return false;
2070 
2071     if (query.testFlag(GetAttroFunction)
2072         && f->functionType() != AbstractMetaFunction::GetAttroFunction) {
2073         return false;
2074     }
2075 
2076     if (query.testFlag(SetAttroFunction)
2077         && f->functionType() != AbstractMetaFunction::SetAttroFunction) {
2078         return false;
2079     }
2080 
2081     return true;
2082 }
2083 
queryFunctionList(const AbstractMetaFunctionList & list,FunctionQueryOptions query)2084 AbstractMetaFunctionList AbstractMetaClass::queryFunctionList(const AbstractMetaFunctionList &list,
2085                                                               FunctionQueryOptions query)
2086 {
2087     AbstractMetaFunctionList result;
2088     for (AbstractMetaFunction *f : list) {
2089         if (queryFunction(f, query))
2090             result.append(f);
2091     }
2092     return result;
2093 }
2094 
queryFirstFunction(const AbstractMetaFunctionList & list,FunctionQueryOptions query)2095 const AbstractMetaFunction *AbstractMetaClass::queryFirstFunction(const AbstractMetaFunctionList &list,
2096                                                                FunctionQueryOptions query)
2097 {
2098     AbstractMetaFunctionList result;
2099     for (AbstractMetaFunction *f : list) {
2100         if (queryFunction(f, query))
2101             return f;
2102     }
2103     return nullptr;
2104 }
2105 
queryFunctions(FunctionQueryOptions query) const2106 AbstractMetaFunctionList AbstractMetaClass::queryFunctions(FunctionQueryOptions query) const
2107 {
2108     return AbstractMetaClass::queryFunctionList(m_functions, query);
2109 }
2110 
hasSignals() const2111 bool AbstractMetaClass::hasSignals() const
2112 {
2113     return queryFirstFunction(m_functions, Signals | Visible | NotRemovedFromTargetLang) != nullptr;
2114 }
2115 
cppSignalFunctions() const2116 AbstractMetaFunctionList AbstractMetaClass::cppSignalFunctions() const
2117 {
2118     return queryFunctions(Signals | Visible | NotRemovedFromTargetLang);
2119 }
2120 
findField(const QString & name) const2121 AbstractMetaField *AbstractMetaClass::findField(const QString &name) const
2122 {
2123     return AbstractMetaField::find(m_fields, name);
2124 }
2125 
findEnum(const QString & enumName)2126 AbstractMetaEnum *AbstractMetaClass::findEnum(const QString &enumName)
2127 {
2128     if (AbstractMetaEnum *e = findByName(m_enums, enumName))
2129         return e;
2130     return nullptr;
2131 }
2132 
2133 /*!  Recursively searches for the enum value named \a enumValueName in
2134   this class and its superclasses and interfaces.
2135 */
findEnumValue(const QString & enumValueName)2136 AbstractMetaEnumValue *AbstractMetaClass::findEnumValue(const QString &enumValueName)
2137 {
2138     for (AbstractMetaEnum *e : qAsConst(m_enums)) {
2139         if (AbstractMetaEnumValue *v = e->findEnumValue(enumValueName))
2140             return v;
2141     }
2142     if (baseClass())
2143         return baseClass()->findEnumValue(enumValueName);
2144 
2145     return nullptr;
2146 }
2147 
getEnumsToBeGenerated(AbstractMetaEnumList * enumList) const2148 void AbstractMetaClass::getEnumsToBeGenerated(AbstractMetaEnumList *enumList) const
2149 {
2150     for (AbstractMetaEnum *metaEnum : m_enums) {
2151         if (!metaEnum->isPrivate() && metaEnum->typeEntry()->generateCode())
2152             enumList->append(metaEnum);
2153     }
2154 }
2155 
getEnumsFromInvisibleNamespacesToBeGenerated(AbstractMetaEnumList * enumList) const2156 void AbstractMetaClass::getEnumsFromInvisibleNamespacesToBeGenerated(AbstractMetaEnumList *enumList) const
2157 {
2158     if (isNamespace()) {
2159         invisibleNamespaceRecursion([enumList](AbstractMetaClass *c) {
2160             c->getEnumsToBeGenerated(enumList);
2161         });
2162     }
2163 }
2164 
getFunctionsFromInvisibleNamespacesToBeGenerated(AbstractMetaFunctionList * funcList) const2165 void AbstractMetaClass::getFunctionsFromInvisibleNamespacesToBeGenerated(AbstractMetaFunctionList *funcList) const
2166 {
2167     if (isNamespace()) {
2168         invisibleNamespaceRecursion([funcList](AbstractMetaClass *c) {
2169             funcList->append(c->functions());
2170         });
2171     }
2172 }
2173 
addExtraIncludeForType(AbstractMetaClass * metaClass,const AbstractMetaType * type)2174 static void addExtraIncludeForType(AbstractMetaClass *metaClass, const AbstractMetaType *type)
2175 {
2176     if (!type)
2177         return;
2178 
2179     Q_ASSERT(metaClass);
2180     const TypeEntry *entry = (type ? type->typeEntry() : nullptr);
2181     if (entry && entry->isComplex()) {
2182         const auto *centry = static_cast<const ComplexTypeEntry *>(entry);
2183         ComplexTypeEntry *class_entry = metaClass->typeEntry();
2184         if (class_entry && centry->include().isValid())
2185             class_entry->addExtraInclude(centry->include());
2186     }
2187 
2188     if (type->hasInstantiations()) {
2189         for (const AbstractMetaType *instantiation : type->instantiations())
2190             addExtraIncludeForType(metaClass, instantiation);
2191     }
2192 }
2193 
addExtraIncludesForFunction(AbstractMetaClass * metaClass,const AbstractMetaFunction * meta_function)2194 static void addExtraIncludesForFunction(AbstractMetaClass *metaClass, const AbstractMetaFunction *meta_function)
2195 {
2196     Q_ASSERT(metaClass);
2197     Q_ASSERT(meta_function);
2198     addExtraIncludeForType(metaClass, meta_function->type());
2199 
2200     const AbstractMetaArgumentList &arguments = meta_function->arguments();
2201     for (AbstractMetaArgument *argument : arguments)
2202         addExtraIncludeForType(metaClass, argument->type());
2203 }
2204 
fixFunctions()2205 void AbstractMetaClass::fixFunctions()
2206 {
2207     if (m_functionsFixed)
2208         return;
2209 
2210     m_functionsFixed = true;
2211 
2212     AbstractMetaFunctionList funcs = functions();
2213 
2214     for (auto superClass : m_baseClasses) {
2215         superClass->fixFunctions();
2216         // Since we always traverse the complete hierarchy we are only
2217         // interrested in what each super class implements, not what
2218         // we may have propagated from their base classes again.
2219         AbstractMetaFunctionList superFuncs;
2220         // Super classes can never be final
2221         if (superClass->isFinalInTargetLang()) {
2222             qCWarning(lcShiboken).noquote().nospace()
2223                 << "Final class '" << superClass->name() << "' set to non-final, as it is extended by other classes";
2224             *superClass -= AbstractMetaAttributes::FinalInTargetLang;
2225         }
2226         superFuncs = superClass->queryFunctions(AbstractMetaClass::ClassImplements);
2227         AbstractMetaFunctionList virtuals = superClass->queryFunctions(AbstractMetaClass::VirtualInCppFunctions);
2228         superFuncs += virtuals;
2229 
2230         QSet<AbstractMetaFunction *> funcsToAdd;
2231         for (auto sf : qAsConst(superFuncs)) {
2232             if (sf->isRemovedFromAllLanguages(sf->implementingClass()))
2233                 continue;
2234 
2235             // skip functions added in base classes
2236             if (sf->isUserAdded() && sf->declaringClass() != this)
2237                 continue;
2238 
2239             // we generally don't care about private functions, but we have to get the ones that are
2240             // virtual in case they override abstract functions.
2241             bool add = (sf->isNormal() || sf->isSignal() || sf->isEmptyFunction());
2242             for (AbstractMetaFunction *f : funcs) {
2243                 if (f->isRemovedFromAllLanguages(f->implementingClass()))
2244                     continue;
2245 
2246 
2247                 const AbstractMetaFunction::CompareResult cmp = f->compareTo(sf);
2248 
2249                 if (cmp & AbstractMetaFunction::EqualModifiedName) {
2250                     add = false;
2251                     if (cmp & AbstractMetaFunction::EqualArguments) {
2252                         // Same function, propegate virtual...
2253                         if (!(cmp & AbstractMetaFunction::EqualAttributes)) {
2254                             if (!f->isEmptyFunction()) {
2255                                 if (!sf->isFinalInTargetLang() && f->isFinalInTargetLang()) {
2256                                     *f -= AbstractMetaAttributes::FinalInTargetLang;
2257                                 }
2258 #if 0
2259                                 if (!f->isFinalInTargetLang() && f->isPrivate()) {
2260                                     f->setFunctionType(AbstractMetaFunction::EmptyFunction);
2261                                     f->setVisibility(AbstractMetaAttributes::Protected);
2262                                     *f += AbstractMetaAttributes::FinalInTargetLang;
2263                                     qCWarning(lcShiboken).noquote().nospace()
2264                                         << QStringLiteral("private virtual function '%1' in '%2'")
2265                                                           .arg(f->signature(), f->implementingClass()->name());
2266                                 }
2267 #endif
2268                             }
2269                         }
2270 
2271                         if (f->visibility() != sf->visibility()) {
2272                             QString warn = QStringLiteral("visibility of function '%1' modified in class '%2'")
2273                                                           .arg(f->name(), name());
2274                             qCWarning(lcShiboken).noquote().nospace() << warn;
2275 #if 0
2276                             // If new visibility is private, we can't
2277                             // do anything. If it isn't, then we
2278                             // prefer the parent class's visibility
2279                             // setting for the function.
2280                             if (!f->isPrivate() && !sf->isPrivate())
2281                                 f->setVisibility(sf->visibility());
2282 #endif
2283                             // Private overrides of abstract functions have to go into the class or
2284                             // the subclasses will not compile as non-abstract classes.
2285                             // But they don't need to be implemented, since they can never be called.
2286                             if (f->isPrivate()) {
2287                                 f->setFunctionType(AbstractMetaFunction::EmptyFunction);
2288                                 *f += AbstractMetaAttributes::FinalInTargetLang;
2289                             }
2290                         }
2291 
2292                         // Set the class which first declares this function, afawk
2293                         f->setDeclaringClass(sf->declaringClass());
2294 
2295                         if (sf->isFinalInTargetLang() && !sf->isPrivate() && !f->isPrivate() && !sf->isStatic() && !f->isStatic()) {
2296                             // Shadowed funcion, need to make base class
2297                             // function non-virtual
2298                             if (f->implementingClass() != sf->implementingClass() && f->implementingClass()->inheritsFrom(sf->implementingClass())) {
2299 
2300                                 // Check whether the superclass method has been redefined to non-final
2301 
2302                                 bool hasNonFinalModifier = false;
2303                                 bool isBaseImplPrivate = false;
2304                                 const FunctionModificationList &mods = sf->modifications(sf->implementingClass());
2305                                 for (const FunctionModification &mod : mods) {
2306                                     if (mod.isNonFinal()) {
2307                                         hasNonFinalModifier = true;
2308                                         break;
2309                                     }
2310                                     if (mod.isPrivate()) {
2311                                         isBaseImplPrivate = true;
2312                                         break;
2313                                     }
2314                                 }
2315 
2316                                 if (!hasNonFinalModifier && !isBaseImplPrivate) {
2317                                     qCWarning(lcShiboken).noquote().nospace()
2318                                         << QStringLiteral("Shadowing: %1::%2 and %3::%4")
2319                                            .arg(sf->implementingClass()->name(), sf->signature(),
2320                                                 f->implementingClass()->name(), f->signature());
2321                                 }
2322                             }
2323                         }
2324 
2325                     }
2326 
2327                     if (cmp & AbstractMetaFunction::EqualDefaultValueOverload) {
2328                         AbstractMetaArgumentList arguments;
2329                         if (f->arguments().size() < sf->arguments().size())
2330                             arguments = sf->arguments();
2331                         else
2332                             arguments = f->arguments();
2333                         //TODO: fix this
2334                         //for (int i=0; i<arguments.size(); ++i)
2335                         //    arguments[i]->setDefaultValueExpression("<#>" + QString());
2336                     }
2337 
2338 
2339                     // Otherwise we have function shadowing and we can
2340                     // skip the thing...
2341                 } else if (cmp & AbstractMetaFunction::EqualName && !sf->isSignal()) {
2342                     // In the case of function shadowing where the function name has been altered to
2343                     // avoid conflict, we don't copy in the original.
2344                     add = false;
2345                 }
2346             }
2347 
2348             if (add)
2349                 funcsToAdd << sf;
2350         }
2351 
2352         for (AbstractMetaFunction *f : qAsConst(funcsToAdd)) {
2353             AbstractMetaFunction *copy = f->copy();
2354             (*copy) += AddedMethod;
2355             funcs.append(copy);
2356         }
2357     }
2358 
2359     bool hasPrivateConstructors = false;
2360     bool hasPublicConstructors = false;
2361     for (AbstractMetaFunction *func : qAsConst(funcs)) {
2362         const FunctionModificationList &mods = func->modifications(this);
2363         for (const FunctionModification &mod : mods) {
2364             if (mod.isRenameModifier()) {
2365                 func->setName(mod.renamedTo());
2366             }
2367         }
2368 
2369         // Make sure class is abstract if one of the functions is
2370         if (func->isAbstract()) {
2371             (*this) += AbstractMetaAttributes::Abstract;
2372             (*this) -= AbstractMetaAttributes::FinalInTargetLang;
2373         }
2374 
2375         if (func->isConstructor()) {
2376             if (func->isPrivate())
2377                 hasPrivateConstructors = true;
2378             else
2379                 hasPublicConstructors = true;
2380         }
2381 
2382 
2383 
2384         // Make sure that we include files for all classes that are in use
2385 
2386         if (!func->isRemovedFrom(this, TypeSystem::ShellCode))
2387             addExtraIncludesForFunction(this, func);
2388     }
2389 
2390     if (hasPrivateConstructors && !hasPublicConstructors) {
2391         (*this) += AbstractMetaAttributes::Abstract;
2392         (*this) -= AbstractMetaAttributes::FinalInTargetLang;
2393     }
2394 
2395     setFunctions(funcs);
2396 }
2397 
formatArraySize(int e)2398 static inline QString formatArraySize(int e)
2399 {
2400     QString result;
2401     result += QLatin1Char('[');
2402     if (e >= 0)
2403         result += QString::number(e);
2404     result += QLatin1Char(']');
2405     return result;
2406 }
2407 
formatSignature(bool minimal) const2408 QString AbstractMetaType::formatSignature(bool minimal) const
2409 {
2410     QString result;
2411     if (isConstant())
2412         result += QLatin1String("const ");
2413     if (isVolatile())
2414         result += QLatin1String("volatile ");
2415     if (isArray()) {
2416         // Build nested array dimensions a[2][3] in correct order
2417         result += m_arrayElementType->minimalSignature();
2418         const int arrayPos = result.indexOf(QLatin1Char('['));
2419         if (arrayPos != -1)
2420             result.insert(arrayPos, formatArraySize(m_arrayElementCount));
2421         else
2422             result.append(formatArraySize(m_arrayElementCount));
2423     } else {
2424         result += typeEntry()->qualifiedCppName();
2425     }
2426     if (!m_instantiations.isEmpty()) {
2427         result += QLatin1Char('<');
2428         if (minimal)
2429             result += QLatin1Char(' ');
2430         for (int i = 0, size = m_instantiations.size(); i < size; ++i) {
2431             if (i > 0)
2432                 result += QLatin1Char(',');
2433             result += m_instantiations.at(i)->minimalSignature();
2434         }
2435         result += QLatin1String(" >");
2436     }
2437 
2438     if (!minimal && (!m_indirections.isEmpty() || m_referenceType != NoReference))
2439         result += QLatin1Char(' ');
2440     for (Indirection i : m_indirections)
2441         result += TypeInfo::indirectionKeyword(i);
2442     switch (referenceType()) {
2443     case NoReference:
2444         break;
2445     case LValueReference:
2446         result += QLatin1Char('&');
2447         break;
2448     case RValueReference:
2449         result += QLatin1String("&&");
2450         break;
2451     }
2452     return result;
2453 }
2454 
formatPythonSignature() const2455 QString AbstractMetaType::formatPythonSignature() const
2456 {
2457     /*
2458      * This is a version of the above, more suitable for Python.
2459      * We avoid extra keywords that are not needed in Python.
2460      * We prepend the package name, unless it is a primitive type.
2461      *
2462      * Primitive types like 'int', 'char' etc.:
2463      * When we have a primitive with an indirection, we use that '*'
2464      * character for later postprocessing, since those indirections
2465      * need to be modified into a result tuple.
2466      * Smart pointer instantiations: Drop the package
2467      */
2468     QString result;
2469     if (m_pattern == AbstractMetaType::NativePointerAsArrayPattern)
2470         result += QLatin1String("array ");
2471     // We no longer use the "const" qualifier for heuristics. Instead,
2472     // NativePointerAsArrayPattern indicates when we have <array> in XML.
2473     // if (m_typeEntry->isPrimitive() && isConstant())
2474     //     result += QLatin1String("const ");
2475     if (!m_typeEntry->isPrimitive() && !m_typeEntry->isSmartPointer() && !package().isEmpty())
2476         result += package() + QLatin1Char('.');
2477     if (isArray()) {
2478         // Build nested array dimensions a[2][3] in correct order
2479         result += m_arrayElementType->formatPythonSignature();
2480         const int arrayPos = result.indexOf(QLatin1Char('['));
2481         if (arrayPos != -1)
2482             result.insert(arrayPos, formatArraySize(m_arrayElementCount));
2483         else
2484             result.append(formatArraySize(m_arrayElementCount));
2485     } else {
2486         result += typeEntry()->targetLangName();
2487     }
2488     if (!m_instantiations.isEmpty()) {
2489         result += QLatin1Char('[');
2490         for (int i = 0, size = m_instantiations.size(); i < size; ++i) {
2491             if (i > 0)
2492                 result += QLatin1String(", ");
2493             result += m_instantiations.at(i)->formatPythonSignature();
2494         }
2495         result += QLatin1Char(']');
2496     }
2497     if (m_typeEntry->isPrimitive())
2498         for (Indirection i : m_indirections)
2499             result += TypeInfo::indirectionKeyword(i);
2500     // If it is a flags type, we replace it with the full name:
2501     // "PySide2.QtCore.Qt.ItemFlags" instead of "PySide2.QtCore.QFlags<Qt.ItemFlag>"
2502     if (m_typeEntry->isFlags())
2503         result = fullName();
2504     result.replace(QLatin1String("::"), QLatin1String("."));
2505     return result;
2506 }
2507 
isCppPrimitive() const2508 bool AbstractMetaType::isCppPrimitive() const
2509 {
2510     return m_pattern == PrimitivePattern && m_typeEntry->isCppPrimitive();
2511 }
2512 
2513 /*******************************************************************************
2514  * Other stuff...
2515  */
2516 
2517 
findEnum(const AbstractMetaClassList & classes,const EnumTypeEntry * entry)2518 AbstractMetaEnum *AbstractMetaClass::findEnum(const AbstractMetaClassList &classes,
2519                                               const EnumTypeEntry *entry)
2520 {
2521     Q_ASSERT(entry->isEnum());
2522 
2523     QString qualifiedName = entry->qualifiedCppName();
2524     int pos = qualifiedName.lastIndexOf(QLatin1String("::"));
2525 
2526     QString enumName;
2527     QString className;
2528 
2529     if (pos > 0) {
2530         enumName = qualifiedName.mid(pos + 2);
2531         className = qualifiedName.mid(0, pos);
2532     } else {
2533         enumName = qualifiedName;
2534         className = TypeDatabase::globalNamespaceClassName(entry);
2535     }
2536 
2537     AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes, className);
2538     if (!metaClass) {
2539         qCWarning(lcShiboken).noquote().nospace()
2540             << QStringLiteral("AbstractMeta::findEnum(), unknown class '%1' in '%2'")
2541                               .arg(className, entry->qualifiedCppName());
2542         return nullptr;
2543     }
2544 
2545     return metaClass->findEnum(enumName);
2546 }
2547 
findEnumValue(const AbstractMetaClassList & classes,const QString & name)2548 AbstractMetaEnumValue *AbstractMetaClass::findEnumValue(const AbstractMetaClassList &classes,
2549                                                         const QString &name)
2550 {
2551     const QVector<QStringRef> lst = name.splitRef(QLatin1String("::"));
2552 
2553     if (lst.size() > 1) {
2554         const QStringRef &prefixName = lst.at(0);
2555         const QStringRef &enumName = lst.at(1);
2556         if (AbstractMetaClass *cl = findClass(classes, prefixName.toString()))
2557             return cl->findEnumValue(enumName.toString());
2558     }
2559 
2560     for (AbstractMetaClass *metaClass : classes) {
2561         if (AbstractMetaEnumValue *enumValue = metaClass->findEnumValue(name))
2562             return enumValue;
2563     }
2564 
2565     qCWarning(lcShiboken).noquote().nospace()
2566         << QStringLiteral("no matching enum '%1'").arg(name);
2567     return nullptr;
2568 }
2569 
2570 /*!
2571  * Searches the list after a class that mathces \a name; either as
2572  * C++, Target language base name or complete Target language package.class name.
2573  */
2574 
findClass(const AbstractMetaClassList & classes,const QString & name)2575 AbstractMetaClass *AbstractMetaClass::findClass(const AbstractMetaClassList &classes,
2576                                                 const QString &name)
2577 {
2578     if (name.isEmpty())
2579         return nullptr;
2580 
2581     for (AbstractMetaClass *c : classes) {
2582         if (c->qualifiedCppName() == name)
2583             return c;
2584     }
2585 
2586     for (AbstractMetaClass *c : classes) {
2587         if (c->fullName() == name)
2588             return c;
2589     }
2590 
2591     for (AbstractMetaClass *c : classes) {
2592         if (c->name() == name)
2593             return c;
2594     }
2595 
2596     return nullptr;
2597 }
2598 
findClass(const AbstractMetaClassList & classes,const TypeEntry * typeEntry)2599 AbstractMetaClass *AbstractMetaClass::findClass(const AbstractMetaClassList &classes,
2600                                                 const TypeEntry *typeEntry)
2601 {
2602     for (AbstractMetaClass *c : classes) {
2603         if (c->typeEntry() == typeEntry)
2604             return c;
2605     }
2606     return nullptr;
2607 }
2608 
2609 #ifndef QT_NO_DEBUG_STREAM
2610 
format(QDebug & d) const2611 void AbstractMetaClass::format(QDebug &d) const
2612 {
2613     if (d.verbosity() > 2)
2614         d << static_cast<const void *>(this) << ", ";
2615     d << '"' << qualifiedCppName();
2616     if (const int count = m_templateArgs.size()) {
2617         for (int i = 0; i < count; ++i)
2618             d << (i ? ',' : '<') << m_templateArgs.at(i)->qualifiedCppName();
2619         d << '>';
2620     }
2621     d << '"';
2622     if (isNamespace())
2623         d << " [namespace]";
2624     if (attributes() & AbstractMetaAttributes::FinalCppClass)
2625         d << " [final]";
2626     if (attributes().testFlag(AbstractMetaAttributes::Deprecated))
2627         d << " [deprecated]";
2628     if (!m_baseClasses.isEmpty()) {
2629         d << ", inherits ";
2630         for (auto b : m_baseClasses)
2631             d << " \"" << b->name() << '"';
2632     }
2633     if (auto templateBase = templateBaseClass()) {
2634         const auto &instantiatedTypes = templateBaseClassInstantiations();
2635         d << ", instantiates \"" << templateBase->name();
2636         for (int i = 0, count = instantiatedTypes.size(); i < count; ++i)
2637             d << (i ? ',' : '<') << instantiatedTypes.at(i)->name();
2638         d << ">\"";
2639     }
2640     if (const int count = m_propertySpecs.size()) {
2641         d << ", properties (" << count << "): [";
2642         for (int i = 0; i < count; ++i) {
2643             if (i)
2644                 d << ", ";
2645             m_propertySpecs.at(i)->formatDebug(d);
2646         }
2647         d << ']';
2648     }
2649 }
2650 
formatMembers(QDebug & d) const2651 void AbstractMetaClass::formatMembers(QDebug &d) const
2652 {
2653     if (!m_enums.isEmpty())
2654         d << ", enums[" << m_enums.size() << "]=" << m_enums;
2655     if (!m_functions.isEmpty()) {
2656         const int count = m_functions.size();
2657         d << ", functions=[" << count << "](";
2658         for (int i = 0; i < count; ++i) {
2659             if (i)
2660                 d << ", ";
2661             formatMetaFunctionBrief(d, m_functions.at(i));
2662         }
2663         d << ')';
2664     }
2665     if (const int count = m_fields.size()) {
2666         d << ", fields=[" << count << "](";
2667         for (int i = 0; i < count; ++i) {
2668             if (i)
2669                 d << ", ";
2670             formatMetaField(d, m_fields.at(i));
2671         }
2672         d << ')';
2673     }
2674 }
2675 
sourceLocation() const2676 SourceLocation AbstractMetaClass::sourceLocation() const
2677 {
2678     return m_sourceLocation;
2679 }
2680 
setSourceLocation(const SourceLocation & sourceLocation)2681 void AbstractMetaClass::setSourceLocation(const SourceLocation &sourceLocation)
2682 {
2683     m_sourceLocation = sourceLocation;
2684 }
2685 
operator <<(QDebug d,const AbstractMetaClass * ac)2686 QDebug operator<<(QDebug d, const AbstractMetaClass *ac)
2687 {
2688     QDebugStateSaver saver(d);
2689     d.noquote();
2690     d.nospace();
2691     d << "AbstractMetaClass(";
2692     if (ac) {
2693         ac->format(d);
2694         if (d.verbosity() > 2)
2695             ac->formatMembers(d);
2696     } else {
2697         d << '0';
2698     }
2699     d << ')';
2700     return d;
2701 }
2702 #endif // !QT_NO_DEBUG_STREAM
2703 
2704 /*******************************************************************************
2705 * AbstractMetaEnum
2706 */
2707 
AbstractMetaEnum()2708 AbstractMetaEnum::AbstractMetaEnum() :
2709     m_hasQenumsDeclaration(false), m_signed(true)
2710 {
2711 }
2712 
~AbstractMetaEnum()2713 AbstractMetaEnum::~AbstractMetaEnum()
2714 {
2715     qDeleteAll(m_enumValues);
2716 }
2717 
2718 template <class String>
findMatchingEnumValue(const AbstractMetaEnumValueList & list,const String & value)2719 AbstractMetaEnumValue *findMatchingEnumValue(const AbstractMetaEnumValueList &list, const String &value)
2720 {
2721     for (AbstractMetaEnumValue *enumValue : list) {
2722         if (enumValue->name() == value)
2723             return enumValue;
2724     }
2725     return nullptr;
2726 }
2727 
2728 // Find enum values for "enum Enum { e1 }" either for "e1" or "Enum::e1"
findEnumValue(const QString & value) const2729 AbstractMetaEnumValue *AbstractMetaEnum::findEnumValue(const QString &value) const
2730 {
2731     if (isAnonymous())
2732         return findMatchingEnumValue(m_enumValues, value);
2733     const int sepPos = value.indexOf(QLatin1String("::"));
2734     if (sepPos == -1)
2735         return findMatchingEnumValue(m_enumValues, value);
2736     return name() == value.leftRef(sepPos)
2737         ? findMatchingEnumValue(m_enumValues, value.rightRef(value.size() - sepPos - 2))
2738         : nullptr;
2739 }
2740 
name() const2741 QString AbstractMetaEnum::name() const
2742 {
2743     return m_typeEntry->targetLangEntryName();
2744 }
2745 
qualifier() const2746 QString AbstractMetaEnum::qualifier() const
2747 {
2748     return m_typeEntry->targetLangQualifier();
2749 }
2750 
package() const2751 QString AbstractMetaEnum::package() const
2752 {
2753     return m_typeEntry->targetLangPackage();
2754 }
2755 
2756