diff options
Diffstat (limited to 'sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp')
-rw-r--r-- | sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp | 697 |
1 files changed, 384 insertions, 313 deletions
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp index dd71b4fa7..f07fb96c6 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp @@ -57,7 +57,7 @@ using namespace Qt::StringLiterals; static QString stripTemplateArgs(const QString &name) { - int pos = name.indexOf(u'<'); + const auto pos = name.indexOf(u'<'); return pos < 0 ? name : name.left(pos); } @@ -67,6 +67,31 @@ static void fixArgumentIndexes(AbstractMetaArgumentList *list) (*list)[i].setArgumentIndex(i); } +bool operator<(const RejectEntry &re1, const RejectEntry &re2) +{ + return re1.reason != re2.reason + ? (re1.reason < re2.reason) : (re1.sortkey < re2.sortkey); +} + +QTextStream &operator<<(QTextStream &str, const RejectEntry &re) +{ + str << re.signature; + if (!re.message.isEmpty()) + str << ": " << re.message; + return str; +} + +static void applyCachedFunctionModifications(const AbstractMetaFunctionPtr &metaFunction, + const FunctionModificationList &functionMods) +{ + for (const FunctionModification &mod : functionMods) { + if (mod.exceptionHandling() != TypeSystem::ExceptionHandling::Unspecified) + metaFunction->setExceptionHandlingModification(mod.exceptionHandling()); + if (mod.allowThread() != TypeSystem::AllowThread::Unspecified) + metaFunction->setAllowThreadModification(mod.allowThread()); + } +} + bool AbstractMetaBuilderPrivate::m_useGlobalHeader = false; bool AbstractMetaBuilderPrivate::m_codeModelTestMode = false; @@ -136,7 +161,12 @@ const QHash<TypeEntryCPtr, AbstractMetaEnum> &AbstractMetaBuilder::typeEntryToEn return d->m_enums; } -void AbstractMetaBuilderPrivate::checkFunctionModifications() +const QMultiHash<QString, QString> &AbstractMetaBuilder::typedefTargetToName() const +{ + return d->m_typedefTargetToName; +} + +void AbstractMetaBuilderPrivate::checkFunctionModifications() const { const auto &entries = TypeDatabase::instance()->entries(); @@ -220,7 +250,7 @@ void AbstractMetaBuilderPrivate::registerHashFunction(const FunctionModelItem &f void AbstractMetaBuilderPrivate::registerToStringCapabilityIn(const NamespaceModelItem &nsItem) { - const FunctionList &streamOps = nsItem->findFunctions(u"operator<<"_s); + const FunctionList &streamOps = nsItem->findFunctions("operator<<"); for (const FunctionModelItem &item : streamOps) registerToStringCapability(item, nullptr); for (const NamespaceModelItem &ni : nsItem->namespaces()) @@ -276,15 +306,18 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelIte firstArgumentIsSelf = false; } } - if (!baseoperandClass) + if (!baseoperandClass) { + rejectFunction(item, currentClass, AbstractMetaBuilder::UnmatchedOperator, + u"base operand class not found."_s); return; + } if (item->isSpaceshipOperator() && !item->isDeleted()) { AbstractMetaClass::addSynthesizedComparisonOperators(baseoperandClass); return; } - AbstractMetaFunction *metaFunction = traverseFunction(item, baseoperandClass); + auto metaFunction = traverseFunction(item, baseoperandClass); if (metaFunction == nullptr) return; @@ -317,7 +350,7 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelIte } metaFunction->setFlags(flags); metaFunction->setAccess(Access::Public); - AbstractMetaClass::addFunction(baseoperandClass, AbstractMetaFunctionCPtr(metaFunction)); + AbstractMetaClass::addFunction(baseoperandClass, metaFunction); if (!metaFunction->arguments().isEmpty()) { const auto include = metaFunction->arguments().constFirst().type().typeEntry()->include(); baseoperandClass->typeEntry()->addArgumentInclude(include); @@ -338,7 +371,7 @@ bool AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem if (streamedClass == nullptr) return false; - AbstractMetaFunction *streamFunction = traverseFunction(item, streamedClass); + auto streamFunction = traverseFunction(item, streamedClass); if (!streamFunction) return false; @@ -353,7 +386,6 @@ bool AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem streamFunction->setArguments(arguments); - *streamFunction += AbstractMetaFunction::FinalInTargetLang; streamFunction->setAccess(Access::Public); AbstractMetaClassPtr funcClass; @@ -369,7 +401,7 @@ bool AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem funcClass = streamClass; } - AbstractMetaClass::addFunction(funcClass, AbstractMetaFunctionCPtr(streamFunction)); + AbstractMetaClass::addFunction(funcClass, streamFunction); auto funcTe = funcClass->typeEntry(); if (funcClass == streamClass) funcTe->addArgumentInclude(streamedClass->typeEntry()->include()); @@ -394,8 +426,8 @@ void AbstractMetaBuilderPrivate::sortLists() // this is a temporary solution before new type revision implementation // We need move QMetaObject register before QObject. Dependencies additionalDependencies; - if (auto qObjectClass = AbstractMetaClass::findClass(m_metaClasses, u"QObject")) { - if (auto qMetaObjectClass = AbstractMetaClass::findClass(m_metaClasses, u"QMetaObject")) { + if (auto qObjectClass = AbstractMetaClass::findClass(m_metaClasses, "QObject")) { + if (auto qMetaObjectClass = AbstractMetaClass::findClass(m_metaClasses, "QMetaObject")) { Dependency dependency; dependency.parent = qMetaObjectClass; dependency.child = qObjectClass; @@ -421,7 +453,7 @@ FileModelItem AbstractMetaBuilderPrivate::buildDom(QByteArrayList arguments, unsigned clangFlags) { clang::Builder builder; - builder.setSystemIncludes(TypeDatabase::instance()->systemIncludes()); + builder.setForceProcessSystemIncludes(TypeDatabase::instance()->forceProcessSystemIncludes()); if (addCompilerSupportArguments) { if (level == LanguageLevel::Default) level = clang::emulatedCompilerLanguageLevel(); @@ -429,7 +461,7 @@ FileModelItem AbstractMetaBuilderPrivate::buildDom(QByteArrayList arguments, + clang::languageLevelOption(level)); } FileModelItem result = clang::parse(arguments, addCompilerSupportArguments, - clangFlags, builder) + level, clangFlags, builder) ? builder.dom() : FileModelItem(); const clang::BaseVisitor::Diagnostics &diagnostics = builder.diagnostics(); if (const auto diagnosticsCount = diagnostics.size()) { @@ -448,7 +480,7 @@ static QStringList functionCandidates(const AbstractMetaFunctionCList &list, const QString &signature) { QString name = signature; - const int parenPos = name.indexOf(u'('); + const auto parenPos = name.indexOf(u'('); if (parenPos > 0) name.truncate(parenPos); QStringList result; @@ -469,8 +501,8 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom, // Start the generation... const ClassList &typeValues = dom->classes(); - ReportHandler::startProgress("Generating class model (" - + QByteArray::number(typeValues.size()) + ")..."); + ReportHandler::startProgress("Generated class model (" + + QByteArray::number(typeValues.size()) + ")."); for (const ClassModelItem &item : typeValues) { if (const auto cls = traverseClass(dom, item, nullptr)) addAbstractMetaClass(cls, item.get()); @@ -479,8 +511,8 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom, // We need to know all global enums const EnumList &enums = dom->enums(); - ReportHandler::startProgress("Generating enum model (" - + QByteArray::number(enums.size()) + ")..."); + ReportHandler::startProgress("Generated enum model (" + + QByteArray::number(enums.size()) + ")."); for (const EnumModelItem &item : enums) { auto metaEnum = traverseEnum(item, nullptr, QSet<QString>()); if (metaEnum.has_value()) { @@ -490,16 +522,16 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom, } const auto &namespaceTypeValues = dom->namespaces(); - ReportHandler::startProgress("Generating namespace model (" - + QByteArray::number(namespaceTypeValues.size()) + ")..."); + ReportHandler::startProgress("Generated namespace model (" + + QByteArray::number(namespaceTypeValues.size()) + ")."); for (const NamespaceModelItem &item : namespaceTypeValues) traverseNamespace(dom, item); // Go through all typedefs to see if we have defined any // specific typedefs to be used as classes. const TypeDefList typeDefs = dom->typeDefs(); - ReportHandler::startProgress("Resolving typedefs (" - + QByteArray::number(typeDefs.size()) + ")..."); + ReportHandler::startProgress("Resolved typedefs (" + + QByteArray::number(typeDefs.size()) + ")."); for (const TypeDefModelItem &typeDef : typeDefs) { if (const auto cls = traverseTypeDef(dom, typeDef, nullptr)) addAbstractMetaClass(cls, typeDef.get()); @@ -523,24 +555,23 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom, if (!funcEntry || !funcEntry->generateCode()) continue; - AbstractMetaFunction *metaFunc = traverseFunction(func, nullptr); - if (!metaFunc) + auto metaFuncPtr = traverseFunction(func, nullptr); + if (!metaFuncPtr) continue; - AbstractMetaFunctionCPtr metaFuncPtr(metaFunc); - if (!funcEntry->hasSignature(metaFunc->minimalSignature())) + if (!funcEntry->hasSignature(metaFuncPtr->minimalSignature())) continue; - metaFunc->setTypeEntry(funcEntry); - applyFunctionModifications(metaFunc); - metaFunc->applyTypeModifications(); + metaFuncPtr->setTypeEntry(funcEntry); + applyFunctionModifications(metaFuncPtr); + metaFuncPtr->applyTypeModifications(); setInclude(funcEntry, func->fileName()); m_globalFunctions << metaFuncPtr; } - ReportHandler::startProgress("Fixing class inheritance..."); + ReportHandler::startProgress("Fixed class inheritance."); for (const auto &cls : std::as_const(m_metaClasses)) { if (cls->needsInheritanceSetup()) { setupInheritance(cls); @@ -553,7 +584,7 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom, } } - ReportHandler::startProgress("Detecting inconsistencies in class model..."); + ReportHandler::startProgress("Checked for inconsistencies in class model."); for (const auto &cls : std::as_const(m_metaClasses)) { AbstractMetaClass::fixFunctions(cls); @@ -571,10 +602,10 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom, const auto &allEntries = types->entries(); - ReportHandler::startProgress("Detecting inconsistencies in typesystem (" - + QByteArray::number(allEntries.size()) + ")..."); + ReportHandler::startProgress("Checked for inconsistencies in typesystem (" + + QByteArray::number(allEntries.size()) + ")."); for (auto it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) { - TypeEntryPtr entry = it.value(); + const TypeEntryPtr &entry = it.value(); if (!entry->isPrimitive()) { if ((entry->isValue() || entry->isObject()) && !types->shouldDropTypeEntry(entry->qualifiedCppName()) @@ -621,7 +652,7 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom, } { - const FunctionList &hashFunctions = dom->findFunctions(u"qHash"_s); + const FunctionList &hashFunctions = dom->findFunctions("qHash"); for (const FunctionModelItem &item : hashFunctions) registerHashFunction(item, nullptr); } @@ -644,11 +675,11 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom, } } - ReportHandler::startProgress("Checking inconsistencies in function modifications..."); + ReportHandler::startProgress("Checked for inconsistencies in function modifications."); checkFunctionModifications(); - ReportHandler::startProgress("Writing log files..."); + ReportHandler::startProgress("Wrote log files."); for (const auto &cls : std::as_const(m_metaClasses)) { // setupEquals(cls); @@ -734,14 +765,17 @@ AbstractMetaClassPtr namespaceName.append(namespaceItem->name()); if (TypeDatabase::instance()->isClassRejected(namespaceName)) { - m_rejectedClasses.insert(namespaceName, AbstractMetaBuilder::GenerationDisabled); - return nullptr; + m_rejectedClasses.insert({AbstractMetaBuilder::GenerationDisabled, + namespaceName, namespaceName, QString{}}); + return {}; } auto type = TypeDatabase::instance()->findNamespaceType(namespaceName, namespaceItem->fileName()); if (!type) { - qCWarning(lcShiboken, "%s", - qPrintable(msgNamespaceNoTypeEntry(namespaceItem, namespaceName))); + const QString rejectReason = msgNamespaceNoTypeEntry(namespaceItem, namespaceName); + qCWarning(lcShiboken, "%s", qPrintable(rejectReason)); + m_rejectedClasses.insert({AbstractMetaBuilder::GenerationDisabled, + namespaceName, namespaceName, rejectReason}); return nullptr; } @@ -852,31 +886,35 @@ std::optional<AbstractMetaEnum> if (TypeDatabase::instance()->isEnumRejected(className, enumName, &rejectReason)) { if (typeEntry) typeEntry->setCodeGeneration(TypeEntry::GenerateNothing); - m_rejectedEnums.insert(qualifiedName + rejectReason, AbstractMetaBuilder::GenerationDisabled); + m_rejectedEnums.insert({AbstractMetaBuilder::GenerationDisabled, qualifiedName, + qualifiedName, rejectReason}); return {}; } const bool rejectionWarning = !enclosing || enclosing->typeEntry()->generateCode(); if (!typeEntry) { + const QString rejectReason = msgNoEnumTypeEntry(enumItem, className); if (rejectionWarning) - qCWarning(lcShiboken, "%s", qPrintable(msgNoEnumTypeEntry(enumItem, className))); - m_rejectedEnums.insert(qualifiedName, AbstractMetaBuilder::NotInTypeSystem); + qCWarning(lcShiboken, "%s", qPrintable(rejectReason)); + m_rejectedEnums.insert({AbstractMetaBuilder::NotInTypeSystem, qualifiedName, + qualifiedName, rejectReason}); return {}; } if (!typeEntry->isEnum()) { - if (rejectionWarning) { - qCWarning(lcShiboken, "%s", - qPrintable(msgNoEnumTypeConflict(enumItem, className, typeEntry))); - } - m_rejectedEnums.insert(qualifiedName, AbstractMetaBuilder::NotInTypeSystem); + const QString rejectReason = msgNoEnumTypeConflict(enumItem, className, typeEntry); + if (rejectionWarning) + qCWarning(lcShiboken, "%s", qPrintable(rejectReason)); + m_rejectedEnums.insert({AbstractMetaBuilder::NotInTypeSystem, qualifiedName, + qualifiedName, rejectReason}); return {}; } AbstractMetaEnum metaEnum; metaEnum.setEnumKind(enumItem->enumKind()); metaEnum.setDeprecated(enumItem->isDeprecated()); + metaEnum.setUnderlyingType(enumItem->underlyingType()); metaEnum.setSigned(enumItem->isSigned()); if (enumsDeclarations.contains(qualifiedName) || enumsDeclarations.contains(enumName)) { @@ -888,22 +926,27 @@ std::optional<AbstractMetaEnum> metaEnum.setAccess(enumItem->accessPolicy()); if (metaEnum.access() == Access::Private) typeEntry->setCodeGeneration(TypeEntry::GenerateNothing); - + // PYSIDE-2088, MSVC signedness issue in Qt + const bool castToUnsigned = enumItem->isSigned() + && enumTypeEntry->cppType().contains(u"unsigned"_s); const EnumeratorList &enums = enumItem->enumerators(); - for (const EnumeratorModelItem &value : enums) { + for (const EnumeratorModelItem &valueItem : enums) { AbstractMetaEnumValue metaEnumValue; - metaEnumValue.setName(value->name()); + metaEnumValue.setName(valueItem->name()); // Deciding the enum value... - metaEnumValue.setStringValue(value->stringValue()); - metaEnumValue.setValue(value->value()); - metaEnumValue.setDeprecated(value->isDeprecated()); + metaEnumValue.setStringValue(valueItem->stringValue()); + const auto value = valueItem->value(); + metaEnumValue.setValue(castToUnsigned ? value.toUnsigned() : value); + metaEnumValue.setDeprecated(valueItem->isDeprecated()); metaEnum.addEnumValue(metaEnumValue); } - if (!metaEnum.typeEntry()->include().isValid()) - setInclude(metaEnum.typeEntry(), enumItem->fileName()); + if (!metaEnum.typeEntry()->include().isValid()) { + auto te = std::const_pointer_cast<EnumTypeEntry>(metaEnum.typeEntry()); + setInclude(te, enumItem->fileName()); + } // Register all enum values on Type database const bool isScopedEnum = enumItem->enumKind() == EnumClass; @@ -923,9 +966,31 @@ std::optional<AbstractMetaEnum> return metaEnum; } -AbstractMetaClassPtr AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelItem &, - const TypeDefModelItem &typeDef, - const AbstractMetaClassPtr ¤tClass) +AbstractMetaClassPtr + AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelItem &dom, + const TypeDefModelItem &typeDef, + const AbstractMetaClassPtr ¤tClass) +{ + auto result = traverseTypeDefHelper(dom, typeDef, currentClass); + if (!result && typeDef->type().isPlain()) { + const auto &type = typeDef->type(); + QString fullName; + if (currentClass) + fullName += currentClass->qualifiedCppName() + "::"_L1; + fullName += typeDef->name(); + QString targetName = typeDef->type().toString(); + m_typedefTargetToName.insert(targetName, fullName); + const QByteArray normalized = QMetaObject::normalizedType(targetName.toUtf8().constData()); + if (targetName != QLatin1StringView(normalized)) + m_typedefTargetToName.insert(QString::fromUtf8(normalized), fullName); + } + return result; +} + +AbstractMetaClassPtr + AbstractMetaBuilderPrivate::traverseTypeDefHelper(const FileModelItem &, + const TypeDefModelItem &typeDef, + const AbstractMetaClassPtr ¤tClass) { TypeDatabase *types = TypeDatabase::instance(); QString className = stripTemplateArgs(typeDef->name()); @@ -985,7 +1050,7 @@ void AbstractMetaBuilderPrivate::traverseTypesystemTypedefs() { const auto &entries = TypeDatabase::instance()->typedefEntries(); for (auto it = entries.begin(), end = entries.end(); it != end; ++it) { - TypedefEntryPtr te = it.value(); + const TypedefEntryPtr &te = it.value(); auto metaClass = std::make_shared<AbstractMetaClass>(); metaClass->setTypeDef(true); metaClass->setTypeEntry(te->target()); @@ -1048,7 +1113,7 @@ AbstractMetaClassPtr AbstractMetaBuilderPrivate::traverseClass(const FileModelIt QTextStream(&fullClassName) << "anonymous struct at " << classItem->fileName() << ':' << classItem->startLine(); } - m_rejectedClasses.insert(fullClassName, reason); + m_rejectedClasses.insert({reason, fullClassName, fullClassName, QString{}}); return nullptr; } @@ -1152,20 +1217,20 @@ void AbstractMetaBuilderPrivate::traverseClassMembers(const ClassModelItem &item traverseScopeMembers(item, metaClass); } -void AbstractMetaBuilderPrivate::traverseUsingMembers(const AbstractMetaClassPtr &metaClass) +void AbstractMetaBuilderPrivate::traverseUsingMembers(const AbstractMetaClassPtr &metaClass) const { const _CodeModelItem *item = m_classToItem.value(metaClass); if (item == nullptr || item->kind() != _CodeModelItem::Kind_Class) return; - auto classItem = static_cast<const _ClassModelItem *>(item); + const auto *classItem = static_cast<const _ClassModelItem *>(item); for (const auto &um : classItem->usingMembers()) { QString className = um.className; - int pos = className.indexOf(u'<'); // strip "QList<value>" + auto pos = className.indexOf(u'<'); // strip "QList<value>" if (pos != -1) className.truncate(pos); if (auto baseClass = findBaseClass(metaClass, className)) { QString name = um.memberName; - const int lastQualPos = name.lastIndexOf(u"::"_s); + const auto lastQualPos = name.lastIndexOf(u"::"_s); if (lastQualPos != -1) name.remove(0, lastQualPos + 2); metaClass->addUsingMember({name, baseClass, um.access}); @@ -1194,7 +1259,7 @@ void AbstractMetaBuilderPrivate::traverseNamespaceMembers(const NamespaceModelIt static inline QString fieldSignatureWithType(const VariableModelItem &field) { - return field->name() + QStringLiteral(" -> ") + field->type().toString(); + return field->name() + " -> "_L1 + field->type().toString(); } static inline QString qualifiedFieldSignatureWithType(const QString &className, @@ -1219,8 +1284,9 @@ std::optional<AbstractMetaField> QString rejectReason; if (TypeDatabase::instance()->isFieldRejected(className, fieldName, &rejectReason)) { - m_rejectedFields.insert(qualifiedFieldSignatureWithType(className, field) + rejectReason, - AbstractMetaBuilder::GenerationDisabled); + const QString signature = qualifiedFieldSignatureWithType(className, field); + m_rejectedFields.insert({AbstractMetaBuilder::GenerationDisabled, + signature, signature, rejectReason}); return {}; } @@ -1281,13 +1347,13 @@ void AbstractMetaBuilderPrivate::traverseFields(const ScopeModelItem &scope_item } } -void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaFunction *metaFunction) +void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(const AbstractMetaFunctionPtr &metaFunction) { if (!metaFunction->isConversionOperator()) return; TypeDatabase *types = TypeDatabase::instance(); - static const QRegularExpression operatorRegExp(QStringLiteral("^operator ")); + static const QRegularExpression operatorRegExp("^operator "_L1); Q_ASSERT(operatorRegExp.isValid()); QString castTo = metaFunction->name().remove(operatorRegExp).trimmed(); @@ -1305,13 +1371,13 @@ void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaF metaFunction->setType(metaType); } -AbstractMetaFunctionRawPtrList +AbstractMetaFunctionList AbstractMetaBuilderPrivate::classFunctionList(const ScopeModelItem &scopeItem, AbstractMetaClass::Attributes *constructorAttributes, const AbstractMetaClassPtr ¤tClass) { *constructorAttributes = {}; - AbstractMetaFunctionRawPtrList result; + AbstractMetaFunctionList result; const FunctionList &scopeFunctionList = scopeItem->functions(); result.reserve(scopeFunctionList.size()); const bool isNamespace = currentClass->isNamespace(); @@ -1321,7 +1387,7 @@ AbstractMetaFunctionRawPtrList } else if (function->isSpaceshipOperator() && !function->isDeleted()) { if (currentClass) AbstractMetaClass::addSynthesizedComparisonOperators(currentClass); - } else if (auto *metaFunction = traverseFunction(function, currentClass)) { + } else if (auto metaFunction = traverseFunction(function, currentClass)) { result.append(metaFunction); } else if (!function->isDeleted() && function->functionType() == CodeModel::Constructor) { auto arguments = function->arguments(); @@ -1333,17 +1399,17 @@ AbstractMetaFunctionRawPtrList return result; } -void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, +void AbstractMetaBuilderPrivate::traverseFunctions(const ScopeModelItem& scopeItem, const AbstractMetaClassPtr &metaClass) { AbstractMetaClass::Attributes constructorAttributes; - const AbstractMetaFunctionRawPtrList functions = + const AbstractMetaFunctionList functions = classFunctionList(scopeItem, &constructorAttributes, metaClass); metaClass->setAttributes(metaClass->attributes() | constructorAttributes); - for (AbstractMetaFunction *metaFunction : functions) { + for (const auto &metaFunction : functions) { if (metaClass->isNamespace()) - *metaFunction += AbstractMetaFunction::Static; + metaFunction->setCppAttribute(FunctionAttribute::Static); const auto propertyFunction = metaClass->searchPropertyFunction(metaFunction->name()); if (propertyFunction.index >= 0) { @@ -1384,39 +1450,30 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, } } - const bool isInvalidDestructor = metaFunction->isDestructor() && metaFunction->isPrivate(); - const bool isInvalidConstructor = metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction - && metaFunction->isPrivate(); - if (isInvalidConstructor) + if (metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction + && metaFunction->isPrivate()) { metaClass->setHasPrivateConstructor(true); - if ((isInvalidDestructor || isInvalidConstructor) - && !metaClass->hasNonPrivateConstructor()) { - *metaClass += AbstractMetaClass::FinalInTargetLang; - } else if (metaFunction->isConstructor() && !metaFunction->isPrivate()) { - *metaClass -= AbstractMetaClass::FinalInTargetLang; - metaClass->setHasNonPrivateConstructor(true); } + if (metaFunction->isConstructor() && !metaFunction->isPrivate()) // Including Copy CT + metaClass->setHasNonPrivateConstructor(true); if (!metaFunction->isDestructor() && !(metaFunction->isPrivate() && metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction)) { - if (metaFunction->isSignal() && metaClass->hasSignal(metaFunction)) - qCWarning(lcShiboken, "%s", qPrintable(msgSignalOverloaded(metaClass, metaFunction))); + if (metaFunction->isSignal() && metaClass->hasSignal(metaFunction.get())) + qCWarning(lcShiboken, "%s", qPrintable(msgSignalOverloaded(metaClass, + metaFunction.get()))); if (metaFunction->isConversionOperator()) fixReturnTypeOfConversionOperator(metaFunction); - AbstractMetaClass::addFunction(metaClass, AbstractMetaFunctionCPtr(metaFunction)); + AbstractMetaClass::addFunction(metaClass, metaFunction); applyFunctionModifications(metaFunction); } else if (metaFunction->isDestructor()) { metaClass->setHasPrivateDestructor(metaFunction->isPrivate()); metaClass->setHasProtectedDestructor(metaFunction->isProtected()); metaClass->setHasVirtualDestructor(metaFunction->isVirtual()); } - if (!metaFunction->ownerClass()) { - delete metaFunction; - metaFunction = nullptr; - } } fillAddedFunctions(metaClass); @@ -1478,7 +1535,7 @@ QStringList AbstractMetaBuilder::definitionNames(const QString &name, return result; } -void AbstractMetaBuilderPrivate::applyFunctionModifications(AbstractMetaFunction *func) +void AbstractMetaBuilderPrivate::applyFunctionModifications(const AbstractMetaFunctionPtr &func) { AbstractMetaFunction& funcRef = *func; for (const FunctionModification &mod : func->modifications(func->implementingClass())) { @@ -1486,22 +1543,13 @@ void AbstractMetaBuilderPrivate::applyFunctionModifications(AbstractMetaFunction func->setOriginalName(func->name()); func->setName(mod.renamedToName()); } else if (mod.isAccessModifier()) { - funcRef -= AbstractMetaFunction::Friendly; - if (mod.isPublic()) funcRef.modifyAccess(Access::Public); else if (mod.isProtected()) funcRef.modifyAccess(Access::Protected); else if (mod.isPrivate()) funcRef.modifyAccess(Access::Private); - else if (mod.isFriendly()) - funcRef += AbstractMetaFunction::Friendly; } - - if (mod.isFinal()) - funcRef += AbstractMetaFunction::FinalInTargetLang; - else if (mod.isNonFinal()) - funcRef -= AbstractMetaFunction::FinalInTargetLang; } } @@ -1522,7 +1570,8 @@ bool AbstractMetaBuilderPrivate::setupInheritance(const AbstractMetaClassPtr &me &info, &baseContainerType); if (templ) { setupInheritance(templ); - inheritTemplate(metaClass, templ, info); + if (!inheritTemplate(metaClass, templ, info)) + return false; metaClass->typeEntry()->setBaseContainerType(templ->typeEntry()); return true; } @@ -1539,9 +1588,9 @@ bool AbstractMetaBuilderPrivate::setupInheritance(const AbstractMetaClassPtr &me return true; } - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("template baseclass '%1' of '%2' is not known") - .arg(baseClasses.constFirst(), metaClass->name()); + qCWarning(lcShiboken, "template baseclass '%s' of '%s' is not known", + qPrintable(baseClasses.constFirst()), + qPrintable(metaClass->name())); return false; } @@ -1576,7 +1625,7 @@ bool AbstractMetaBuilderPrivate::setupInheritance(const AbstractMetaClassPtr &me } else { QString message; QTextStream(&message) << "Class \"" << defaultSuperclassName - << "\" specified as \"default-superclass\" of \"" << metaClass->name() + << R"(" specified as "default-superclass" of ")" << metaClass->name() << "\" could not be found in the code model."; qCWarning(lcShiboken, "%s", qPrintable(message)); } @@ -1624,15 +1673,14 @@ static AbstractMetaFunction::FunctionType functionTypeFromName(const QString &); bool AbstractMetaBuilderPrivate::traverseAddedGlobalFunction(const AddedFunctionPtr &addedFunc, QString *errorMessage) { - AbstractMetaFunction *metaFunction = - traverseAddedFunctionHelper(addedFunc, nullptr, errorMessage); + auto metaFunction = traverseAddedFunctionHelper(addedFunc, nullptr, errorMessage); if (metaFunction == nullptr) return false; - m_globalFunctions << AbstractMetaFunctionCPtr(metaFunction); + m_globalFunctions << metaFunction; return true; } -AbstractMetaFunction * +AbstractMetaFunctionPtr AbstractMetaBuilderPrivate::traverseAddedFunctionHelper(const AddedFunctionPtr &addedFunc, const AbstractMetaClassPtr &metaClass /* = {} */, QString *errorMessage) @@ -1643,10 +1691,10 @@ AbstractMetaFunction * msgAddedFunctionInvalidReturnType(addedFunc->name(), addedFunc->returnType().qualifiedName(), *errorMessage, metaClass); - return nullptr; + return {}; } - auto *metaFunction = new AbstractMetaFunction(addedFunc); + auto metaFunction = std::make_shared<AbstractMetaFunction>(addedFunc); metaFunction->setType(returnType.value()); metaFunction->setFunctionType(functionTypeFromName(addedFunc->name())); @@ -1664,8 +1712,7 @@ AbstractMetaFunction * msgAddedFunctionInvalidArgType(addedFunc->name(), arg.typeInfo.qualifiedName(), i + 1, *errorMessage, metaClass); - delete metaFunction; - return nullptr; + return {}; } type->decideUsagePattern(); @@ -1703,6 +1750,7 @@ AbstractMetaFunction * // Find the correct default values const FunctionModificationList functionMods = metaFunction->modifications(metaClass); + applyCachedFunctionModifications(metaFunction, functionMods); for (qsizetype i = 0; i < metaArguments.size(); ++i) { AbstractMetaArgument &metaArg = metaArguments[i]; @@ -1721,14 +1769,13 @@ bool AbstractMetaBuilderPrivate::traverseAddedMemberFunction(const AddedFunction const AbstractMetaClassPtr &metaClass, QString *errorMessage) { - AbstractMetaFunction *metaFunction = - traverseAddedFunctionHelper(addedFunc, metaClass, errorMessage); + auto metaFunction = traverseAddedFunctionHelper(addedFunc, metaClass, errorMessage); if (metaFunction == nullptr) return false; const AbstractMetaArgumentList fargs = metaFunction->arguments(); if (metaClass->isNamespace()) - *metaFunction += AbstractMetaFunction::Static; + metaFunction->setCppAttribute(FunctionAttribute::Static); if (metaFunction->name() == metaClass->name()) { metaFunction->setFunctionType(AbstractMetaFunction::ConstructorFunction); if (fargs.size() == 1) { @@ -1742,12 +1789,13 @@ bool AbstractMetaBuilderPrivate::traverseAddedMemberFunction(const AddedFunction metaFunction->setDeclaringClass(metaClass); metaFunction->setImplementingClass(metaClass); - AbstractMetaClass::addFunction(metaClass, AbstractMetaFunctionCPtr(metaFunction)); + AbstractMetaClass::addFunction(metaClass, metaFunction); metaClass->setHasNonPrivateConstructor(true); return true; } -void AbstractMetaBuilderPrivate::fixArgumentNames(AbstractMetaFunction *func, const FunctionModificationList &mods) +void AbstractMetaBuilderPrivate::fixArgumentNames(const AbstractMetaFunctionPtr &func, + const FunctionModificationList &mods) { AbstractMetaArgumentList &arguments = func->arguments(); @@ -1866,7 +1914,7 @@ static AbstractMetaFunction::FunctionType functionTypeFromName(const QString &na // Apply the <array> modifications of the arguments static bool applyArrayArgumentModifications(const FunctionModificationList &functionMods, - AbstractMetaFunction *func, + const AbstractMetaFunctionPtr &func, QString *errorMessage) { for (const FunctionModification &mod : functionMods) { @@ -1902,7 +1950,7 @@ static AbstractMetaType createViewOnType(const AbstractMetaType &metaType, // (std::span<T, int N>) is mapped onto a std::vector<T>, // remove the superfluous template parameters and strip 'const'. const auto vcte = std::static_pointer_cast<const ContainerTypeEntry>(viewOnTypeEntry); - const auto instantiations = metaType.instantiations(); + const auto &instantiations = metaType.instantiations(); AbstractMetaTypeList viewInstantiations; const auto size = std::min(vcte->templateParameterCount(), instantiations.size()); for (qsizetype i = 0; i < size; ++i) { @@ -1914,11 +1962,27 @@ static AbstractMetaType createViewOnType(const AbstractMetaType &metaType, return result; } -AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const FunctionModelItem &functionItem, - const AbstractMetaClassPtr ¤tClass) +void AbstractMetaBuilderPrivate::rejectFunction(const FunctionModelItem &functionItem, + const AbstractMetaClassPtr ¤tClass, + AbstractMetaBuilder::RejectReason reason, + const QString &rejectReason) +{ + QString sortKey; + if (currentClass) + sortKey += currentClass->typeEntry()->qualifiedCppName() + u"::"_s; + sortKey += functionSignature(functionItem); // Sort without return type + const QString signatureWithType = functionItem->type().toString() + u' ' + sortKey; + m_rejectedFunctions.insert({reason, signatureWithType, sortKey, rejectReason}); +} + +AbstractMetaFunctionPtr + AbstractMetaBuilderPrivate::traverseFunction(const FunctionModelItem &functionItem, + const AbstractMetaClassPtr ¤tClass) { + const auto *tdb = TypeDatabase::instance(); + if (!functionItem->templateParameters().isEmpty()) - return nullptr; + return {}; if (functionItem->isDeleted()) { switch (functionItem->functionType()) { @@ -1932,7 +1996,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio default: break; } - return nullptr; + return {}; } const QString &functionName = functionItem->name(); const QString className = currentClass != nullptr ? @@ -1942,7 +2006,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio // Skip enum helpers generated by Q_ENUM if ((currentClass == nullptr || currentClass->isNamespace()) && (functionName == u"qt_getEnumMetaObject" || functionName == u"qt_getEnumName")) { - return nullptr; + return {}; } // Clang: Skip qt_metacast(), qt_metacall(), expanded from Q_OBJECT @@ -1950,46 +2014,45 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio if (currentClass != nullptr) { if (functionName == u"qt_check_for_QGADGET_macro" || functionName.startsWith(u"qt_meta")) { - return nullptr; + return {}; } if (functionName == u"metaObject" && className != u"QObject") - return nullptr; + return {}; } } // PySide extensions - // Store original signature with unresolved typedefs for message/log purposes - const QString originalQualifiedSignatureWithReturn = - qualifiedFunctionSignatureWithType(functionItem, className); - QString rejectReason; - if (TypeDatabase::instance()->isFunctionRejected(className, functionName, &rejectReason)) { - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); - return nullptr; + if (tdb->isFunctionRejected(className, functionName, &rejectReason)) { + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::GenerationDisabled, rejectReason); + return {}; } - const QString &signature = functionSignature(functionItem); - const bool rejected = - TypeDatabase::instance()->isFunctionRejected(className, signature, &rejectReason); - if (rejected) { + const QString &signature = functionSignature(functionItem); + if (tdb->isFunctionRejected(className, signature, &rejectReason)) { + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::GenerationDisabled, rejectReason); if (ReportHandler::isDebug(ReportHandler::MediumDebug)) { qCInfo(lcShiboken, "%s::%s was rejected by the type database (%s).", qPrintable(className), qPrintable(signature), qPrintable(rejectReason)); } - return nullptr; + return {}; } if (functionItem->isFriend()) - return nullptr; + return {}; - const bool deprecated = functionItem->isDeprecated(); + const auto cppAttributes = functionItem->attributes(); + const bool deprecated = cppAttributes.testFlag(FunctionAttribute::Deprecated); if (deprecated && m_skipDeprecated) { - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + u" is deprecated."_s, - AbstractMetaBuilder::GenerationDisabled); - return nullptr; + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::GenerationDisabled, u" is deprecated."_s); + return {}; } AbstractMetaFunction::Flags flags; - auto *metaFunction = new AbstractMetaFunction(functionName); + auto metaFunction = std::make_shared<AbstractMetaFunction>(functionName); + metaFunction->setCppAttributes(cppAttributes); const QByteArray cSignature = signature.toUtf8(); const QString unresolvedSignature = QString::fromUtf8(QMetaObject::normalizedSignature(cSignature.constData())); @@ -1997,35 +2060,12 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio if (functionItem->isHiddenFriend()) flags.setFlag(AbstractMetaFunction::Flag::HiddenFriend); metaFunction->setSourceLocation(functionItem->sourceLocation()); - if (deprecated) - *metaFunction += AbstractMetaFunction::Deprecated; // Additional check for assignment/move assignment down below metaFunction->setFunctionType(functionTypeFromCodeModel(functionItem->functionType())); metaFunction->setConstant(functionItem->isConstant()); metaFunction->setExceptionSpecification(functionItem->exceptionSpecification()); - if (functionItem->isAbstract()) - *metaFunction += AbstractMetaFunction::Abstract; - - if (functionItem->isVirtual()) { - *metaFunction += AbstractMetaFunction::VirtualCppMethod; - if (functionItem->isOverride()) - *metaFunction += AbstractMetaFunction::OverriddenCppMethod; - if (functionItem->isFinal()) - *metaFunction += AbstractMetaFunction::FinalCppMethod; - } else { - *metaFunction += AbstractMetaFunction::FinalInTargetLang; - } - - if (functionItem->isInvokable()) - *metaFunction += AbstractMetaFunction::Invokable; - - if (functionItem->isStatic()) { - *metaFunction += AbstractMetaFunction::Static; - *metaFunction += AbstractMetaFunction::FinalInTargetLang; - } - // Access rights metaFunction->setAccess(functionItem->accessPolicy()); @@ -2035,27 +2075,30 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio metaFunction->setType(AbstractMetaType::createVoid()); break; case AbstractMetaFunction::ConstructorFunction: - metaFunction->setExplicit(functionItem->isExplicit()); metaFunction->setName(currentClass->name()); metaFunction->setType(AbstractMetaType::createVoid()); break; default: { TypeInfo returnType = functionItem->type(); - if (TypeDatabase::instance()->isReturnTypeRejected(className, returnType.toString(), &rejectReason)) { - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); - delete metaFunction; - return nullptr; + if (tdb->isReturnTypeRejected(className, returnType.toString(), &rejectReason)) { + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::GenerationDisabled, rejectReason); + return {}; } - auto type = translateType(returnType, currentClass, {}, &errorMessage); + TranslateTypeFlags flags; + if (functionItem->scopeResolution()) + flags.setFlag(AbstractMetaBuilder::NoClassScopeLookup); + auto type = translateType(returnType, currentClass, flags, &errorMessage); if (!type.has_value()) { const QString reason = msgUnmatchedReturnType(functionItem, errorMessage); + const QString signature = qualifiedFunctionSignatureWithType(functionItem, className); qCWarning(lcShiboken, "%s", - qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason))); - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::UnmatchedReturnType); - delete metaFunction; - return nullptr; + qPrintable(msgSkippingFunction(functionItem, signature, reason))); + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::UnmatchedReturnType, reason); + return {}; } metaFunction->setType(type.value()); @@ -2083,32 +2126,37 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio for (qsizetype i = 0; i < arguments.size(); ++i) { const ArgumentModelItem &arg = arguments.at(i); - if (TypeDatabase::instance()->isArgumentTypeRejected(className, arg->type().toString(), &rejectReason)) { - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); - delete metaFunction; - return nullptr; + if (tdb->isArgumentTypeRejected(className, arg->type().toString(), &rejectReason)) { + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::GenerationDisabled, rejectReason); + return {}; } - auto metaTypeO = translateType(arg->type(), currentClass, {}, &errorMessage); + TranslateTypeFlags flags; + if (arg->scopeResolution()) + flags.setFlag(AbstractMetaBuilder::NoClassScopeLookup); + auto metaTypeO = translateType(arg->type(), currentClass, flags, &errorMessage); if (!metaTypeO.has_value()) { // If an invalid argument has a default value, simply remove it // unless the function is virtual (since the override in the // wrapper can then not correctly be generated). - if (arg->defaultValue() && !functionItem->isVirtual()) { + if (arg->defaultValue() + && !functionItem->attributes().testFlag(FunctionAttribute::Virtual)) { if (!currentClass || currentClass->typeEntry()->generateCode()) { + const QString signature = qualifiedFunctionSignatureWithType(functionItem, className); qCWarning(lcShiboken, "%s", - qPrintable(msgStrippingArgument(functionItem, i, originalQualifiedSignatureWithReturn, arg))); + qPrintable(msgStrippingArgument(functionItem, i, signature, + arg, errorMessage))); } break; } const QString reason = msgUnmatchedParameterType(arg, i, errorMessage); + const QString signature = qualifiedFunctionSignatureWithType(functionItem, className); qCWarning(lcShiboken, "%s", - qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason))); - const QString rejectedFunctionSignature = originalQualifiedSignatureWithReturn - + u": "_s + reason; - m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::UnmatchedArgumentType); - delete metaFunction; - return nullptr; + qPrintable(msgSkippingFunction(functionItem, signature, reason))); + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::UnmatchedArgumentType, reason); + return {}; } auto metaType = metaTypeO.value(); @@ -2131,15 +2179,10 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio AbstractMetaArgumentList &metaArguments = metaFunction->arguments(); const FunctionModificationList functionMods = currentClass - ? AbstractMetaFunction::findClassModifications(metaFunction, currentClass) - : AbstractMetaFunction::findGlobalModifications(metaFunction); + ? AbstractMetaFunction::findClassModifications(metaFunction.get(), currentClass) + : AbstractMetaFunction::findGlobalModifications(metaFunction.get()); - for (const FunctionModification &mod : functionMods) { - if (mod.exceptionHandling() != TypeSystem::ExceptionHandling::Unspecified) - metaFunction->setExceptionHandlingModification(mod.exceptionHandling()); - if (mod.allowThread() != TypeSystem::AllowThread::Unspecified) - metaFunction->setAllowThreadModification(mod.allowThread()); - } + applyCachedFunctionModifications(metaFunction, functionMods); // Find the correct default values for (qsizetype i = 0, size = metaArguments.size(); i < size; ++i) { @@ -2162,7 +2205,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio && metaFunction->argumentName(i + 1, false, currentClass).isEmpty()) { qCWarning(lcShiboken, "%s", qPrintable(msgUnnamedArgumentDefaultExpression(currentClass, i + 1, - className, metaFunction))); + className, metaFunction.get()))); } } @@ -2215,11 +2258,13 @@ static TypeEntryCPtr findTypeEntryUsingContext(const AbstractMetaClassCPtr &meta // Helper for findTypeEntries/translateTypeStatic() TypeEntryCList AbstractMetaBuilderPrivate::findTypeEntriesHelper(const QString &qualifiedName, const QString &name, + TranslateTypeFlags flags, const AbstractMetaClassCPtr ¤tClass, AbstractMetaBuilderPrivate *d) { // 5.1 - Try first using the current scope - if (currentClass) { + if (currentClass != nullptr + && !flags.testFlag(AbstractMetaBuilder::NoClassScopeLookup)) { if (auto type = findTypeEntryUsingContext(currentClass, qualifiedName)) return {type}; @@ -2262,11 +2307,13 @@ TypeEntryCList AbstractMetaBuilderPrivate::findTypeEntriesHelper(const QString & // and does some error checking. TypeEntryCList AbstractMetaBuilderPrivate::findTypeEntries(const QString &qualifiedName, const QString &name, + TranslateTypeFlags flags, const AbstractMetaClassCPtr ¤tClass, AbstractMetaBuilderPrivate *d, QString *errorMessage) { - TypeEntryCList types = findTypeEntriesHelper(qualifiedName, name, currentClass, d); + TypeEntryCList types = findTypeEntriesHelper(qualifiedName, name, flags, + currentClass, d); if (types.isEmpty()) { if (errorMessage != nullptr) *errorMessage = msgCannotFindTypeEntry(qualifiedName); @@ -2314,7 +2361,7 @@ TypeEntryCList AbstractMetaBuilderPrivate::findTypeEntries(const QString &qualif AbstractMetaClassCPtr AbstractMetaBuilderPrivate::resolveTypeSystemTypeDef(const AbstractMetaType &t) const { if (t.hasInstantiations()) { - auto pred = [t](const TypeClassEntry &e) { return e.type.equals(t); }; + auto pred = [t](const TypeClassEntry &e) { return e.type == t; }; auto it = std::find_if(m_typeSystemTypeDefs.cbegin(), m_typeSystemTypeDefs.cend(), pred); if (it != m_typeSystemTypeDefs.cend()) return it->klass; @@ -2522,6 +2569,13 @@ static bool isNumber(const QString &s) [](QChar c) { return c.isDigit(); }); } +// A type entry relevant only for non type template "X<5>" +static bool isNonTypeTemplateArgument(const TypeEntryCPtr &te) +{ + const auto type = te->type(); + return type == TypeEntry::EnumValue || type == TypeEntry::ConstantValueType; +} + std::optional<AbstractMetaType> AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo &_typei, const AbstractMetaClassCPtr ¤tClass, @@ -2578,7 +2632,7 @@ std::optional<AbstractMetaType> bool isConstCharStarCase = oneDimensionalArrayOfUnspecifiedSize && typeInfo.qualifiedName().size() == 1 - && typeInfo.qualifiedName().at(0) == QStringLiteral("char") + && typeInfo.qualifiedName().at(0) == "char"_L1 && typeInfo.indirections() == 0 && typeInfo.isConstant() && typeInfo.referenceType() == NoReference @@ -2651,7 +2705,16 @@ std::optional<AbstractMetaType> typeInfo.clearInstantiations(); } - const TypeEntryCList types = findTypeEntries(qualifiedName, name, currentClass, d, errorMessageIn); + TypeEntryCList types = findTypeEntries(qualifiedName, name, flags, + currentClass, d, errorMessageIn); + if (!flags.testFlag(AbstractMetaBuilder::TemplateArgument)) { + // Avoid clashes between QByteArray and enum value QMetaType::QByteArray + // unless we are looking for template arguments. + auto end = std::remove_if(types.begin(), types.end(), + isNonTypeTemplateArgument); + types.erase(end, types.end()); + } + if (types.isEmpty()) { if (errorMessageIn != nullptr) *errorMessageIn = msgUnableToTranslateType(_typei, *errorMessageIn); @@ -2671,7 +2734,9 @@ std::optional<AbstractMetaType> const auto &templateArguments = typeInfo.instantiations(); for (qsizetype t = 0, size = templateArguments.size(); t < size; ++t) { const TypeInfo &ti = templateArguments.at(t); - auto targType = translateTypeStatic(ti, currentClass, d, flags, &errorMessage); + auto targType = translateTypeStatic(ti, currentClass, d, + flags | AbstractMetaBuilder::TemplateArgument, + &errorMessage); // For non-type template parameters, create a dummy type entry on the fly // as is done for classes. if (!targType.has_value()) { @@ -2780,7 +2845,7 @@ qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringV // This is a very lame way to handle expression evaluation, // but it is not critical and will do for the time being. - static const QRegularExpression variableNameRegExp(QStringLiteral("^[a-zA-Z_][a-zA-Z0-9_]*$")); + static const QRegularExpression variableNameRegExp("^[a-zA-Z_][a-zA-Z0-9_]*$"_L1); Q_ASSERT(variableNameRegExp.isValid()); if (!variableNameRegExp.match(stringValue).hasMatch()) { ok = true; @@ -2817,9 +2882,10 @@ static bool isUnderQualifiedSpec(QStringView qualifiedType, QStringView candidat } QString AbstractMetaBuilder::fixEnumDefault(const AbstractMetaType &type, - const QString &expr) const + const QString &expr, + const AbstractMetaClassCPtr &klass) const { - return d->fixEnumDefault(type, expr); + return d->fixEnumDefault(type, expr, klass); } void AbstractMetaBuilder::setCodeModelTestMode(bool b) @@ -2857,7 +2923,7 @@ QString AbstractMetaBuilderPrivate::fixDefaultValue(QString expr, const Abstract return expr; if (type.isFlags() || type.isEnum()) { - expr = fixEnumDefault(type, expr); + expr = fixEnumDefault(type, expr, implementingClass); } else if (type.isContainer() && expr.contains(u'<')) { // Expand a container of a nested class, fex // "QList<FormatRange>()" -> "QList<QTextLayout::FormatRange>()" @@ -3054,80 +3120,103 @@ std::optional<AbstractMetaType> AbstractMetaClassPtr AbstractMetaBuilder::inheritTemplateClass(const ComplexTypeEntryPtr &te, const AbstractMetaClassCPtr &templateClass, - const AbstractMetaTypeList &templateTypes, - InheritTemplateFlags flags) + const AbstractMetaTypeList &templateTypes) { auto result = std::make_shared<AbstractMetaClass>(); result->setTypeDef(true); result->setTypeEntry(te); if (!AbstractMetaBuilderPrivate::inheritTemplate(result, templateClass, - templateTypes, flags)) { + templateTypes)) { return {}; } AbstractMetaBuilderPrivate::inheritTemplateFunctions(result); return result; } + +static std::optional<AbstractMetaType> + inheritTemplateParameter(const AbstractMetaClassPtr &subclass, + const AbstractMetaClassCPtr &templateClass, + const TypeInfo &info, QString *errorMessage) +{ + QString typeName = info.qualifiedName().join("::"_L1); + TypeDatabase *typeDb = TypeDatabase::instance(); + TypeEntryPtr t; + // Check for a non-type template integer parameter, that is, for a base + // "template <int R, int C> Matrix<R, C>" and subclass + // "typedef Matrix<2,3> Matrix2x3;". If so, create dummy entries of + // EnumValueTypeEntry for the integer values encountered on the fly. + if (isNumber(typeName)) { + t = typeDb->findType(typeName); + if (!t) { + auto parent = typeSystemTypeEntry(subclass->typeEntry()); + t = TypeDatabase::instance()->addConstantValueTypeEntry(typeName, parent); + } + } else { + QStringList possibleNames; + possibleNames << subclass->qualifiedCppName() + "::"_L1 + typeName; + possibleNames << templateClass->qualifiedCppName() + "::"_L1 + typeName; + if (subclass->enclosingClass()) + possibleNames << subclass->enclosingClass()->qualifiedCppName() + "::"_L1 + typeName; + possibleNames << typeName; + + for (const QString &possibleName : std::as_const(possibleNames)) { + t = typeDb->findType(possibleName); + if (t) + break; + } + } + + if (!t) { + *errorMessage = msgIgnoringTemplateParameter(typeName, + "The corresponding type was not found in the typesystem."); + return std::nullopt; + } + + if (t->isContainer()) { + *errorMessage = msgIgnoringTemplateParameter(typeName, + "Template inheritance from nested containers is not supported"); + return std::nullopt; + } + AbstractMetaType result(t); + result.setConstant(info.isConstant()); + result.setReferenceType(info.referenceType()); + result.setIndirectionsV(info.indirectionsV()); + result.decideUsagePattern(); + return result; +} + bool AbstractMetaBuilderPrivate::inheritTemplate(const AbstractMetaClassPtr &subclass, const AbstractMetaClassCPtr &templateClass, const TypeInfo &info) { AbstractMetaTypeList templateTypes; + QString errorMessage; for (const TypeInfo &i : info.instantiations()) { - QString typeName = i.qualifiedName().join(u"::"_s); - TypeDatabase *typeDb = TypeDatabase::instance(); - TypeEntryPtr t; - // Check for a non-type template integer parameter, that is, for a base - // "template <int R, int C> Matrix<R, C>" and subclass - // "typedef Matrix<2,3> Matrix2x3;". If so, create dummy entries of - // EnumValueTypeEntry for the integer values encountered on the fly. - if (isNumber(typeName)) { - t = typeDb->findType(typeName); - if (!t) { - auto parent = typeSystemTypeEntry(subclass->typeEntry()); - t = TypeDatabase::instance()->addConstantValueTypeEntry(typeName, parent); - } + const auto typeO = inheritTemplateParameter(subclass, templateClass, i, &errorMessage); + if (typeO.has_value()) { + templateTypes.append(typeO.value()); } else { - QStringList possibleNames; - possibleNames << subclass->qualifiedCppName() + u"::"_s + typeName; - possibleNames << templateClass->qualifiedCppName() + u"::"_s + typeName; - if (subclass->enclosingClass()) - possibleNames << subclass->enclosingClass()->qualifiedCppName() + u"::"_s + typeName; - possibleNames << typeName; - - for (const QString &possibleName : std::as_const(possibleNames)) { - t = typeDb->findType(possibleName); - if (t) - break; - } - } - - if (t) { - AbstractMetaType temporaryType(t); - temporaryType.setConstant(i.isConstant()); - temporaryType.setReferenceType(i.referenceType()); - temporaryType.setIndirectionsV(i.indirectionsV()); - temporaryType.decideUsagePattern(); - templateTypes << temporaryType; - } else { - qCWarning(lcShiboken).noquote().nospace() - << "Ignoring template parameter " << typeName << " from " - << info.toString() << ". The corresponding type was not found in the typesystem."; + errorMessage = msgInheritTemplateIssue(subclass, info, errorMessage); + qCWarning(lcShiboken, "%s", qPrintable(errorMessage)); } } + if (templateTypes.isEmpty()) { + errorMessage = msgInheritTemplateIssue(subclass, info, + "No template parameters could be inherited"_L1); + qCWarning(lcShiboken, "%s", qPrintable(errorMessage)); + return false; + } return inheritTemplate(subclass, templateClass, templateTypes); } bool AbstractMetaBuilderPrivate::inheritTemplate(const AbstractMetaClassPtr &subclass, const AbstractMetaClassCPtr &templateClass, - const AbstractMetaTypeList &templateTypes, - InheritTemplateFlags flags) + const AbstractMetaTypeList &templateTypes) { subclass->setTemplateBaseClass(templateClass); - if (flags.testFlag(InheritTemplateFlag::SetEnclosingClass)) - subclass->setEnclosingClass(templateClass->enclosingClass()); subclass->setTemplateBaseClassInstantiations(templateTypes); subclass->setBaseClass(templateClass->baseClass()); return true; @@ -3217,7 +3306,7 @@ AbstractMetaFunctionPtr } QString errorMessage; - if (!applyArrayArgumentModifications(f->modifications(subclass), f.get(), + if (!applyArrayArgumentModifications(f->modifications(subclass), f, &errorMessage)) { qCWarning(lcShiboken, "While specializing %s (%s): %s", qPrintable(subclass->name()), qPrintable(templateClass->name()), @@ -3310,7 +3399,7 @@ void AbstractMetaBuilderPrivate::parseQ_Properties(const AbstractMetaClassPtr &m if (spec.has_value()) { spec->setIndex(i); metaClass->addPropertySpec(spec.value()); - } else { + } else if (!errorMessage.isEmpty()) { QString message; QTextStream str(&message); str << metaClass->sourceLocation() << errorMessage; @@ -3356,8 +3445,18 @@ void AbstractMetaBuilderPrivate::setupExternalConversion(const AbstractMetaClass } static void writeRejectLogFile(const QString &name, - const QMap<QString, AbstractMetaBuilder::RejectReason> &rejects) -{ + const AbstractMetaBuilderPrivate::RejectSet &rejects) +{ + static const QHash<AbstractMetaBuilder::RejectReason, QByteArray> descriptions ={ + {AbstractMetaBuilder::NotInTypeSystem, "Not in type system"_ba}, + {AbstractMetaBuilder::GenerationDisabled, "Generation disabled by type system"_ba}, + {AbstractMetaBuilder::RedefinedToNotClass, "Type redefined to not be a class"_ba}, + {AbstractMetaBuilder::UnmatchedReturnType, "Unmatched return type"_ba}, + {AbstractMetaBuilder::UnmatchedArgumentType, "Unmatched argument type"_ba}, + {AbstractMetaBuilder::UnmatchedOperator, "Unmatched operator"_ba}, + {AbstractMetaBuilder::Deprecated, "Deprecated"_ba} + }; + QFile f(name); if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { qCWarning(lcShiboken, "%s", qPrintable(msgCannotOpenForWriting(f))); @@ -3366,53 +3465,19 @@ static void writeRejectLogFile(const QString &name, QTextStream s(&f); - - for (int reason = 0; reason < AbstractMetaBuilder::NoReason; ++reason) { - s << QByteArray(72, '*') << '\n'; - switch (reason) { - case AbstractMetaBuilder::NotInTypeSystem: - s << "Not in type system"; - break; - case AbstractMetaBuilder::GenerationDisabled: - s << "Generation disabled by type system"; - break; - case AbstractMetaBuilder::RedefinedToNotClass: - s << "Type redefined to not be a class"; - break; - - case AbstractMetaBuilder::UnmatchedReturnType: - s << "Unmatched return type"; - break; - - case AbstractMetaBuilder::UnmatchedArgumentType: - s << "Unmatched argument type"; - break; - - case AbstractMetaBuilder::ApiIncompatible: - s << "Incompatible API"; - break; - - case AbstractMetaBuilder::Deprecated: - s << "Deprecated"; - break; - - default: - s << "unknown reason"; - break; - } - - s << Qt::endl; - - for (QMap<QString, AbstractMetaBuilder::RejectReason>::const_iterator it = rejects.constBegin(); - it != rejects.constEnd(); ++it) { - if (it.value() != reason) - continue; - s << " - " << it.key() << Qt::endl; + int lastReason = -1; + for (const auto &e : rejects) { + if (e.reason != lastReason) { + const QByteArray description = descriptions.value(e.reason, "Unknown reason"_ba); + const QByteArray underline(description.size(), '*'); + if (lastReason != -1) + s << '\n'; + s << underline << '\n' << description << '\n' << underline << "\n\n"; + lastReason = e.reason; } - s << QByteArray(72, '*') << "\n\n"; + s << " - " << e << '\n'; } - } void AbstractMetaBuilderPrivate::dumpLog() const @@ -3490,16 +3555,22 @@ static QList<std::shared_ptr<MetaClass> > if (!result.isValid() && graph.nodeCount()) { QTemporaryFile tempFile(QDir::tempPath() + u"/cyclic_depXXXXXX.dot"_s); tempFile.setAutoRemove(false); - tempFile.open(); - graph.dumpDot(tempFile.fileName(), - [] (const AbstractMetaClassCPtr &c) { return c->name(); }); + const bool ok = tempFile.open(); + if (ok) { + graph.dumpDot(tempFile.fileName(), + [] (const AbstractMetaClassCPtr &c) { return c->name(); }); + } QString message; QTextStream str(&message); str << "Cyclic dependency of classes found:"; - for (auto c : result.cyclic) + for (const auto &c : result.cyclic) str << ' ' << c->name(); - str << ". Graph can be found at \"" << QDir::toNativeSeparators(tempFile.fileName()) << '"'; + str << '.'; + if (ok) { + str << " Graph can be found at \"" + << QDir::toNativeSeparators(tempFile.fileName()) << '"'; + } qCWarning(lcShiboken, "%s", qPrintable(message)); } |