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