diff options
Diffstat (limited to 'sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp')
-rw-r--r-- | sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp | 706 |
1 files changed, 379 insertions, 327 deletions
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index 84c116708..f6724e61d 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -27,6 +27,7 @@ ****************************************************************************/ #include "abstractmetabuilder_p.h" +#include "messages.h" #include "reporthandler.h" #include "typedatabase.h" @@ -159,38 +160,18 @@ AbstractMetaEnumList AbstractMetaBuilder::globalEnums() const return d->m_globalEnums; } -static QString msgNoFunctionForModification(const QString &signature, - const QString &originalSignature, - const QString &className, - const QStringList &possibleSignatures, - const AbstractMetaFunctionList &allFunctions) -{ - QString result; - QTextStream str(&result); - str << "signature '" << signature << '\''; - if (!originalSignature.isEmpty() && originalSignature != signature) - str << " (specified as '" << originalSignature << "')"; - str << " for function modification in '" - << className << "' not found."; - if (possibleSignatures.isEmpty()) { - str << " No candidates were found. Member functions: "; - for (int f = 0, size = allFunctions.size(); f < size; ++f) { - if (f) - str << ", "; - str << allFunctions.at(f)->minimalSignature(); - } - } else { - str << " Possible candidates: " << possibleSignatures.join(QLatin1String(", ")); - } - return result; +AbstractMetaEnum *AbstractMetaBuilder::findEnum(const TypeEntry *typeEntry) const +{ + if (typeEntry && typeEntry->isFlags()) + typeEntry = static_cast<const FlagsTypeEntry*>(typeEntry)->originator(); + return d->m_enums.value(typeEntry); } void AbstractMetaBuilderPrivate::checkFunctionModifications() { - TypeDatabase *types = TypeDatabase::instance(); - const SingleTypeEntryHash entryHash = types->entries(); + const auto &entries = TypeDatabase::instance()->entries(); - for (SingleTypeEntryHash::const_iterator it = entryHash.cbegin(), end = entryHash.cend(); it != end; ++it) { + for (auto it = entries.cbegin(), end = entries.cend(); it != end; ++it) { const TypeEntry *entry = it.value(); if (!entry) continue; @@ -241,7 +222,7 @@ void AbstractMetaBuilderPrivate::checkFunctionModifications() } } -AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(ArgumentModelItem argument) +AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(const ArgumentModelItem &argument) { AbstractMetaClass* returned = 0; AbstractMetaType *type = translateType(argument->type()); @@ -256,7 +237,7 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(ArgumentModelItem /** * Checks the argument of a hash function and flags the type if it is a complex type */ -void AbstractMetaBuilderPrivate::registerHashFunction(FunctionModelItem function_item) +void AbstractMetaBuilderPrivate::registerHashFunction(const FunctionModelItem &function_item) { ArgumentList arguments = function_item->arguments(); if (arguments.size() == 1) { @@ -269,12 +250,12 @@ void AbstractMetaBuilderPrivate::registerHashFunction(FunctionModelItem function * Check if a class has a debug stream operator that can be used as toString */ -void AbstractMetaBuilderPrivate::registerToStringCapability(FunctionModelItem function_item) +void AbstractMetaBuilderPrivate::registerToStringCapability(const FunctionModelItem &function_item) { ArgumentList arguments = function_item->arguments(); if (arguments.size() == 2) { if (arguments.at(0)->type().toString() == QLatin1String("QDebug")) { - ArgumentModelItem arg = arguments.at(1); + const ArgumentModelItem &arg = arguments.at(1); if (AbstractMetaClass *cls = argumentToClass(arg)) { if (arg->type().indirections() < 2) cls->setToStringCapability(true); @@ -283,7 +264,7 @@ void AbstractMetaBuilderPrivate::registerToStringCapability(FunctionModelItem fu } } -void AbstractMetaBuilderPrivate::traverseOperatorFunction(FunctionModelItem item) +void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelItem &item) { if (item->accessPolicy() != CodeModel::Public) return; @@ -348,7 +329,7 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(FunctionModelItem item setupFunctionDefaults(metaFunction, baseoperandClass); baseoperandClass->addFunction(metaFunction); Q_ASSERT(!metaFunction->wasPrivate()); - } else if (metaFunction) { + } else { delete metaFunction; } @@ -356,7 +337,7 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(FunctionModelItem item } } -void AbstractMetaBuilderPrivate::traverseStreamOperator(FunctionModelItem item) +void AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem &item) { ArgumentList arguments = item->arguments(); if (arguments.size() == 2 && item->accessPolicy() == CodeModel::Public) { @@ -404,7 +385,7 @@ void AbstractMetaBuilderPrivate::traverseStreamOperator(FunctionModelItem item) funcClass->typeEntry()->addExtraInclude(streamClass->typeEntry()->include()); m_currentClass = oldCurrentClass; - } else if (streamFunction) { + } else { delete streamFunction; } @@ -422,7 +403,7 @@ void AbstractMetaBuilderPrivate::fixQObjectForScope(const FileModelItem &dom, TypeEntry* entry = types->findType(qualifiedName); if (entry) { if (isQObject(dom, qualifiedName) && entry->isComplex()) - ((ComplexTypeEntry*) entry)->setQObject(true); + static_cast<ComplexTypeEntry *>(entry)->setQObject(true); } } @@ -475,19 +456,18 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) const ClassList &typeValues = dom->classes(); ReportHandler::setProgressReference(typeValues); for (const ClassModelItem &item : typeValues) { - ReportHandler::progress(QLatin1String("Generating class model...")); - AbstractMetaClass *cls = traverseClass(dom, item); - if (!cls) - continue; - - addAbstractMetaClass(cls); + ReportHandler::progress(QStringLiteral("Generating class model (%1)...") + .arg(typeValues.size())); + if (AbstractMetaClass *cls = traverseClass(dom, item)) + addAbstractMetaClass(cls); } // We need to know all global enums const EnumList &enums = dom->enums(); ReportHandler::setProgressReference(enums); for (const EnumModelItem &item : enums) { - ReportHandler::progress(QLatin1String("Generating enum model...")); + ReportHandler::progress(QStringLiteral("Generating enum model (%1)...") + .arg(enums.size())); AbstractMetaEnum *metaEnum = traverseEnum(item, 0, QSet<QString>()); if (metaEnum) { if (metaEnum->typeEntry()->generateCode()) @@ -495,10 +475,11 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) } } - const QSet<NamespaceModelItem> &namespaceTypeValues = dom->uniqueNamespaces(); + const auto &namespaceTypeValues = dom->namespaces(); ReportHandler::setProgressReference(namespaceTypeValues); for (const NamespaceModelItem &item : namespaceTypeValues) { - ReportHandler::progress(QLatin1String("Generating namespace model...")); + ReportHandler::progress(QStringLiteral("Generating namespace model (%1)...") + .arg(namespaceTypeValues.size())); AbstractMetaClass *metaClass = traverseNamespace(dom, item); if (metaClass) m_metaClasses << metaClass; @@ -509,11 +490,14 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) const TypeDefList typeDefs = dom->typeDefs(); ReportHandler::setProgressReference(typeDefs); for (const TypeDefModelItem &typeDef : typeDefs) { - ReportHandler::progress(QLatin1String("Resolving typedefs...")); - AbstractMetaClass* cls = traverseTypeDef(dom, typeDef); - addAbstractMetaClass(cls); + ReportHandler::progress(QStringLiteral("Resolving typedefs (%1)...") + .arg(typeDefs.size())); + if (AbstractMetaClass *cls = traverseTypeDef(dom, typeDef)) + addAbstractMetaClass(cls); } + traverseTypesystemTypedefs(); + for (const ClassModelItem &item : typeValues) traverseClassMembers(item); @@ -580,13 +564,12 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) if (cls->isAbstract() && !cls->isInterface()) cls->typeEntry()->setLookupName(cls->typeEntry()->targetLangName() + QLatin1String("$ConcreteWrapper")); } - const TypeEntryHash allEntries = types->allEntries(); - ReportHandler::progress(QLatin1String("Detecting inconsistencies in typesystem...")); - for (TypeEntryHash::const_iterator it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) { - for (TypeEntry *entry : it.value()) { - if (entry->isPrimitive()) - continue; - + const auto &allEntries = types->entries(); + ReportHandler::progress(QStringLiteral("Detecting inconsistencies in typesystem (%1)...") + .arg(allEntries.size())); + for (auto it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) { + TypeEntry *entry = it.value(); + if (!entry->isPrimitive()) { if ((entry->isValue() || entry->isObject()) && !entry->isString() && !entry->isChar() @@ -616,20 +599,13 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) } } } else if (entry->isEnum() && (entry->generateCode() & TypeEntry::GenerateTargetLang)) { - const QString name = ((EnumTypeEntry*) entry)->targetLangQualifier(); + const QString name = static_cast<const EnumTypeEntry *>(entry)->targetLangQualifier(); AbstractMetaClass *cls = AbstractMetaClass::findClass(m_metaClasses, name); - bool enumFound = false; - if (cls) { - enumFound = cls->findEnum(entry->targetLangName()); - } else { // Global enum - for (AbstractMetaEnum *metaEnum : qAsConst(m_enums)) { - if (metaEnum->typeEntry() == entry) { - enumFound = true; - break; - } - } - } + const bool enumFound = cls + ? cls->findEnum(entry->targetLangName()) != nullptr + : m_enums.contains(entry); + if (!enumFound) { entry->setCodeGeneration(TypeEntry::GenerateNothing); qCWarning(lcShiboken).noquote().nospace() @@ -727,6 +703,15 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) std::puts(""); } +static bool metaEnumLessThan(const AbstractMetaEnum *e1, const AbstractMetaEnum *e2) +{ return e1->fullName() < e2->fullName(); } + +static bool metaClassLessThan(const AbstractMetaClass *c1, const AbstractMetaClass *c2) +{ return c1->fullName() < c2->fullName(); } + +static bool metaFunctionLessThan(const AbstractMetaFunction *f1, const AbstractMetaFunction *f2) +{ return f1->name() < f2->name(); } + bool AbstractMetaBuilder::build(const QByteArrayList &arguments, LanguageLevel level, unsigned clangFlags) @@ -737,6 +722,14 @@ bool AbstractMetaBuilder::build(const QByteArrayList &arguments, if (ReportHandler::isDebug(ReportHandler::MediumDebug)) qCDebug(lcShiboken) << dom.data(); d->traverseDom(dom); + + // Ensure that indexes are in alphabetical order, roughly + std::sort(d->m_globalEnums.begin(), d->m_globalEnums.end(), metaEnumLessThan); + std::sort(d->m_metaClasses.begin(), d->m_metaClasses.end(), metaClassLessThan); + std::sort(d->m_templates.begin(), d->m_templates.end(), metaClassLessThan); + std::sort(d->m_smartPointers.begin(), d->m_smartPointers.end(), metaClassLessThan); + std::sort(d->m_globalFunctions.begin(), d->m_globalFunctions.end(), metaFunctionLessThan); + return true; } @@ -749,9 +742,6 @@ void AbstractMetaBuilder::setLogDirectory(const QString& logDir) void AbstractMetaBuilderPrivate::addAbstractMetaClass(AbstractMetaClass *cls) { - if (!cls) - return; - cls->setOriginalAttributes(cls->attributes()); if (cls->typeEntry()->isContainer()) { m_templates << cls; @@ -827,8 +817,7 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModel } // Traverse namespaces recursively - const QSet<NamespaceModelItem> &innerNamespaces = namespaceItem->uniqueNamespaces(); - for (const NamespaceModelItem &ni : innerNamespaces) { + for (const NamespaceModelItem &ni : namespaceItem->namespaces()) { AbstractMetaClass* mjc = traverseNamespace(dom, ni); if (mjc) { metaClass->addInnerClass(mjc); @@ -848,7 +837,7 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModel return metaClass; } -AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumItem, +AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem &enumItem, AbstractMetaClass *enclosing, const QSet<QString> &enumsDeclarations) { @@ -857,7 +846,7 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumIte TypeEntry* typeEntry = 0; if (enumItem->accessPolicy() == CodeModel::Private) { QStringList names = enumItem->qualifiedName(); - QString enumName = names.constLast(); + const QString &enumName = names.constLast(); QString nspace; if (names.size() > 1) nspace = QStringList(names.mid(0, names.size() - 1)).join(colonColon()); @@ -892,15 +881,23 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumIte return 0; } - if ((!typeEntry || !typeEntry->isEnum())) { - if (!m_currentClass || - (m_currentClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang)) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("enum '%1' does not have a type entry or is not an enum") - .arg(qualifiedName); + const bool rejectionWarning = !m_currentClass + || (m_currentClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang); + + if (!typeEntry) { + if (rejectionWarning) + qCWarning(lcShiboken, "%s", qPrintable(msgNoEnumTypeEntry(enumItem, className))); + m_rejectedEnums.insert(qualifiedName, AbstractMetaBuilder::NotInTypeSystem); + return nullptr; + } + + if (!typeEntry->isEnum()) { + if (rejectionWarning) { + qCWarning(lcShiboken, "%s", + qPrintable(msgNoEnumTypeConflict(enumItem, className, typeEntry))); } m_rejectedEnums.insert(qualifiedName, AbstractMetaBuilder::NotInTypeSystem); - return 0; + return nullptr; } AbstractMetaEnum *metaEnum = new AbstractMetaEnum; @@ -946,15 +943,9 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumIte qCDebug(lcShiboken) << " - " << metaEnumValue->name() << " = " << metaEnumValue->value() << " = " << metaEnumValue->value(); } - - // Add into global register... - if (enclosing) - m_enumValues[enclosing->name() + colonColon() + metaEnumValue->name()] = metaEnumValue; - else - m_enumValues[metaEnumValue->name()] = metaEnumValue; } - m_enums << metaEnum; + m_enums.insert(typeEntry, metaEnum); if (!metaEnum->typeEntry()->include().isValid()) setInclude(metaEnum->typeEntry(), enumItem->fileName()); @@ -962,6 +953,15 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumIte metaEnum->setOriginalAttributes(metaEnum->attributes()); // Register all enum values on Type database + QString prefix; + if (enclosing) { + prefix += enclosing->typeEntry()->qualifiedCppName(); + prefix += colonColon(); + } + if (enumItem->enumKind() == EnumClass) { + prefix += enumItem->name(); + prefix += colonColon(); + } const EnumeratorList &enumerators = enumItem->enumerators(); for (const EnumeratorModelItem &e : enumerators) { QString name; @@ -969,11 +969,12 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumIte name += enclosing->name(); name += colonColon(); } - name += e->name(); EnumValueTypeEntry *enumValue = - new EnumValueTypeEntry(name, e->stringValue(), + new EnumValueTypeEntry(prefix + e->name(), e->stringValue(), enumTypeEntry, enumTypeEntry->version()); TypeDatabase::instance()->addType(enumValue); + if (e->value().isNullValue()) + enumTypeEntry->setNullValue(enumValue); } return metaEnum; @@ -1014,7 +1015,7 @@ AbstractMetaClass* AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelIt AbstractMetaClass *metaClass = new AbstractMetaClass; metaClass->setTypeDef(true); metaClass->setTypeEntry(type); - metaClass->setBaseClassNames(QStringList() << typeDef->type().qualifiedName().join(colonColon())); + metaClass->setBaseClassNames(QStringList(typeDef->type().toString())); *metaClass += AbstractMetaAttributes::Public; // Set the default include file name @@ -1026,6 +1027,22 @@ AbstractMetaClass* AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelIt return metaClass; } +// Add the typedef'ed classes +void AbstractMetaBuilderPrivate::traverseTypesystemTypedefs() +{ + const auto &entries = TypeDatabase::instance()->typedefEntries(); + for (auto it = entries.begin(), end = entries.end(); it != end; ++it) { + TypedefEntry *te = it.value(); + AbstractMetaClass *metaClass = new AbstractMetaClass; + metaClass->setTypeDef(true); + metaClass->setTypeEntry(te->target()); + metaClass->setBaseClassNames(QStringList(te->sourceType())); + *metaClass += AbstractMetaAttributes::Public; + fillAddedFunctions(metaClass); + addAbstractMetaClass(metaClass); + } +} + AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem &dom, const ClassModelItem &classItem) { @@ -1197,25 +1214,24 @@ void AbstractMetaBuilderPrivate::traverseNamespaceMembers(NamespaceModelItem ite traverseScopeMembers(item, metaClass); // Inner namespaces - const QSet<NamespaceModelItem> &innerNamespaces = item->uniqueNamespaces(); - for (const NamespaceModelItem &ni : innerNamespaces) + for (const NamespaceModelItem &ni : item->namespaces()) traverseNamespaceMembers(ni); m_currentClass = oldCurrentClass; } -static inline QString fieldSignatureWithType(VariableModelItem field) +static inline QString fieldSignatureWithType(const VariableModelItem &field) { return field->name() + QStringLiteral(" -> ") + field->type().toString(); } static inline QString qualifiedFieldSignatureWithType(const QString &className, - VariableModelItem field) + const VariableModelItem &field) { return className + colonColon() + fieldSignatureWithType(field); } -AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(VariableModelItem field, +AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(const VariableModelItem &field, const AbstractMetaClass *cls) { QString fieldName = field->name(); @@ -1272,7 +1288,7 @@ AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(VariableModelItem f return metaField; } -void AbstractMetaBuilderPrivate::traverseFields(ScopeModelItem scope_item, +void AbstractMetaBuilderPrivate::traverseFields(const ScopeModelItem &scope_item, AbstractMetaClass *metaClass) { const VariableList &variables = scope_item->variables(); @@ -1327,14 +1343,8 @@ void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaF static bool _compareAbstractMetaTypes(const AbstractMetaType* type, const AbstractMetaType* other) { - if (!type && !other) - return true; - if (!type || !other) - return false; - return type->typeEntry() == other->typeEntry() - && type->isConstant() == other->isConstant() - && type->referenceType() == other->referenceType() - && type->indirections() == other->indirections(); + return (type != nullptr) == (other != nullptr) + && (type == nullptr || *type == *other); } static bool _compareAbstractMetaFunctions(const AbstractMetaFunction* func, const AbstractMetaFunction* other) @@ -1426,7 +1436,7 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, } } else if (QPropertySpec* reset = metaClass->propertySpecForReset(metaFunction->name())) { // Property resetter must be in the form "void name()" - if ((!metaFunction->type()) && (metaFunction->arguments().size() == 0)) { + if ((!metaFunction->type()) && metaFunction->arguments().isEmpty()) { *metaFunction += AbstractMetaAttributes::PropertyResetter; metaFunction->setPropertySpec(reset); } @@ -1635,7 +1645,7 @@ bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass) return true; } -void AbstractMetaBuilderPrivate::traverseEnums(ScopeModelItem scopeItem, +void AbstractMetaBuilderPrivate::traverseEnums(const ScopeModelItem &scopeItem, AbstractMetaClass *metaClass, const QStringList &enumsDeclarations) { @@ -1724,13 +1734,9 @@ AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFu replacedExpression = metaFunction->replacedDefaultExpression(m_currentClass, i + 1); if (!replacedExpression.isEmpty()) { - QString expr = replacedExpression; if (!metaFunction->removedDefaultExpression(m_currentClass, i + 1)) { - metaArg->setDefaultValueExpression(expr); - metaArg->setOriginalDefaultValueExpression(expr); - - if (metaArg->type()->isEnum() || metaArg->type()->isFlags()) - m_enumDefaultArguments << QPair<AbstractMetaArgument*, AbstractMetaFunction*>(metaArg, metaFunction); + metaArg->setDefaultValueExpression(replacedExpression); + metaArg->setOriginalDefaultValueExpression(replacedExpression); } } } @@ -1784,7 +1790,7 @@ void AbstractMetaBuilderPrivate::fixArgumentNames(AbstractMetaFunction *func, co } } -static QString functionSignature(FunctionModelItem functionItem) +static QString functionSignature(const FunctionModelItem &functionItem) { QStringList args; const ArgumentList &arguments = functionItem->arguments(); @@ -1802,50 +1808,6 @@ static inline QString qualifiedFunctionSignatureWithType(const FunctionModelItem result += functionSignature(functionItem); return result; } - -static inline QString msgUnmatchedParameterType(const ArgumentModelItem &arg, int n) -{ - QString result; - QTextStream str(&result); - str << "unmatched type '" << arg->type().toString() << "' in parameter #" - << (n + 1); - if (!arg->name().isEmpty()) - str << " \"" << arg->name() << '"'; - return result; -} - -static inline QString msgUnmatchedReturnType(const FunctionModelItem &functionItem) -{ - return QLatin1String("unmatched return type '") - + functionItem->type().toString() + QLatin1Char('\''); -} - -static inline QString msgVoidParameterType(const ArgumentModelItem &arg, int n) -{ - QString result; - QTextStream str(&result); - str << "'void' encountered at parameter #" << (n + 1); - if (!arg->name().isEmpty()) - str << " \"" << arg->name() << '"'; - return result; -} - -static QString msgSkippingFunction(const FunctionModelItem &functionItem, - const QString &signature, const QString &why) -{ - QString result; - QTextStream str(&result); - str << "skipping "; - if (functionItem->isAbstract()) - str << "abstract "; - str << "function '" << signature << "', " << why; - if (functionItem->isAbstract()) { - str << "\nThis will lead to compilation errors due to not " - "being able to instantiate the wrapper."; - } - return result; -} - static inline AbstractMetaFunction::FunctionType functionTypeFromCodeModel(CodeModel::FunctionType ft) { AbstractMetaFunction::FunctionType result = AbstractMetaFunction::NormalFunction; @@ -1874,12 +1836,6 @@ static inline AbstractMetaFunction::FunctionType functionTypeFromCodeModel(CodeM return result; } -static inline QString msgCannotSetArrayUsage(const QString &function, int i, const QString &reason) -{ - return function + QLatin1String(": Cannot use parameter ") + QString::number(i + 1) - + QLatin1String(" as an array: ") + reason; -} - bool AbstractMetaBuilderPrivate::setArrayArgumentType(AbstractMetaFunction *func, const FunctionModelItem &functionItem, int i) @@ -1911,12 +1867,40 @@ bool AbstractMetaBuilderPrivate::setArrayArgumentType(AbstractMetaFunction *func return true; } -AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModelItem functionItem) +static bool generateExceptionHandling(const AbstractMetaFunction *func, + ExceptionSpecification spec, + TypeSystem::ExceptionHandling handling) +{ + switch (func->functionType()) { + case AbstractMetaFunction::CopyConstructorFunction: + case AbstractMetaFunction::MoveConstructorFunction: + case AbstractMetaFunction::AssignmentOperatorFunction: + case AbstractMetaFunction::MoveAssignmentOperatorFunction: + case AbstractMetaFunction::DestructorFunction: + return false; + default: + break; + } + switch (handling) { + case TypeSystem::ExceptionHandling::On: + return true; + case TypeSystem::ExceptionHandling::AutoDefaultToOn: + return spec != ExceptionSpecification::NoExcept; + case TypeSystem::ExceptionHandling::AutoDefaultToOff: + return spec == ExceptionSpecification::Throws; + default: + break; + } + return false; +} + +AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const FunctionModelItem &functionItem) { if (functionItem->isDeleted() || !functionItem->templateParameters().isEmpty()) return nullptr; QString functionName = functionItem->name(); QString className; + TypeSystem::ExceptionHandling exceptionHandling = TypeSystem::ExceptionHandling::Unspecified; if (m_currentClass) { // Clang: Skip qt_metacast(), qt_metacall(), expanded from Q_OBJECT // and overridden metaObject(), QGADGET helpers @@ -1925,6 +1909,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel return nullptr; } className = m_currentClass->typeEntry()->qualifiedCppName(); + exceptionHandling = m_currentClass->typeEntry()->exceptionHandling(); if (functionName == QLatin1String("metaObject") && className != QLatin1String("QObject")) return nullptr; } @@ -1936,13 +1921,16 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel QString rejectReason; if (TypeDatabase::instance()->isFunctionRejected(className, functionName, &rejectReason)) { m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); - return 0; - } - else if (TypeDatabase::instance()->isFunctionRejected(className, - functionSignature(functionItem), &rejectReason)) { - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); - return 0; + return nullptr; } + const QString &signature = functionSignature(functionItem); + const bool rejected = + TypeDatabase::instance()->isFunctionRejected(className, signature, &rejectReason); + qCDebug(lcShiboken).nospace().noquote() << __FUNCTION__ + << ": Checking rejection for signature \"" << signature << "\" for " << className + << ": " << rejected; + if (rejected) + return nullptr; if (functionItem->isFriend()) return 0; @@ -1951,6 +1939,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel // Additional check for assignment/move assignment down below metaFunction->setFunctionType(functionTypeFromCodeModel(functionItem->functionType())); metaFunction->setConstant(functionItem->isConstant()); + metaFunction->setExceptionSpecification(functionItem->exceptionSpecification()); if (ReportHandler::isDebug(ReportHandler::MediumDebug)) qCDebug(lcShiboken).noquote().nospace() << " - " << functionName << "()"; @@ -1987,6 +1976,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel else *metaFunction += AbstractMetaAttributes::Protected; + QString errorMessage; switch (metaFunction->functionType()) { case AbstractMetaFunction::DestructorFunction: break; @@ -2005,9 +1995,9 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel AbstractMetaType *type = nullptr; if (!returnType.isVoid()) { - type = translateType(returnType); + type = translateType(returnType, true, &errorMessage); if (!type) { - const QString reason = msgUnmatchedReturnType(functionItem); + const QString reason = msgUnmatchedReturnType(functionItem, errorMessage); qCWarning(lcShiboken, "%s", qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason))); m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::UnmatchedReturnType); @@ -2033,7 +2023,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel AbstractMetaArgumentList metaArguments; for (int i = 0; i < arguments.size(); ++i) { - ArgumentModelItem arg = arguments.at(i); + const ArgumentModelItem &arg = arguments.at(i); if (TypeDatabase::instance()->isArgumentTypeRejected(className, arg->type().toString(), &rejectReason)) { m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); @@ -2041,7 +2031,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel return nullptr; } - AbstractMetaType *metaType = translateType(arg->type()); + AbstractMetaType *metaType = translateType(arg->type(), true, &errorMessage); if (!metaType) { // If an invalid argument has a default value, simply remove it if (arg->defaultValue()) { @@ -2058,18 +2048,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel break; } Q_ASSERT(metaType == 0); - const QString reason = msgUnmatchedParameterType(arg, i); - qCWarning(lcShiboken, "%s", - qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason))); - const QString rejectedFunctionSignature = originalQualifiedSignatureWithReturn - + QLatin1String(": ") + reason; - m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::UnmatchedArgumentType); - delete metaFunction; - return nullptr; - } - - if (metaType == Q_NULLPTR) { - const QString reason = msgVoidParameterType(arg, i); + const QString reason = msgUnmatchedParameterType(arg, i, errorMessage); qCWarning(lcShiboken, "%s", qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason))); const QString rejectedFunctionSignature = originalQualifiedSignatureWithReturn @@ -2089,9 +2068,22 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel metaFunction->setArguments(metaArguments); + const FunctionModificationList functionMods = metaFunction->modifications(m_currentClass); + + for (const FunctionModification &mod : functionMods) { + if (mod.exceptionHandling() != TypeSystem::ExceptionHandling::Unspecified) { + exceptionHandling = mod.exceptionHandling(); + break; + } + } + + metaFunction->setGenerateExceptionHandling(generateExceptionHandling(metaFunction, + functionItem->exceptionSpecification(), + exceptionHandling)); + // Find the correct default values for (int i = 0, size = metaArguments.size(); i < size; ++i) { - ArgumentModelItem arg = arguments.at(i); + const ArgumentModelItem &arg = arguments.at(i); AbstractMetaArgument* metaArg = metaArguments.at(i); //use relace-default-expression for set default value @@ -2099,9 +2091,8 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel if (m_currentClass) { replacedExpression = metaFunction->replacedDefaultExpression(m_currentClass, i + 1); } else { - FunctionModificationList mods = TypeDatabase::instance()->functionModifications(metaFunction->minimalSignature()); - if (!mods.isEmpty()) { - QVector<ArgumentModification> argMods = mods.constFirst().argument_mods; + if (!functionMods.isEmpty()) { + QVector<ArgumentModification> argMods = functionMods.constFirst().argument_mods; if (!argMods.isEmpty()) replacedExpression = argMods.constFirst().replacedDefaultExpression; } @@ -2119,10 +2110,6 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel expr = replacedExpression; } metaArg->setDefaultValueExpression(expr); - - if (metaArg->type()->isEnum() || metaArg->type()->isFlags()) - m_enumDefaultArguments << QPair<AbstractMetaArgument *, AbstractMetaFunction *>(metaArg, metaFunction); - hasDefaultValue = !expr.isEmpty(); } @@ -2140,9 +2127,8 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModel } if (!metaArguments.isEmpty()) { - const FunctionModificationList &mods = metaFunction->modifications(m_currentClass); - fixArgumentNames(metaFunction, mods); - for (const FunctionModification &mod : mods) { + fixArgumentNames(metaFunction, functionMods); + for (const FunctionModification &mod : functionMods) { for (const ArgumentModification &argMod : mod.argument_mods) { if (argMod.array) setArrayArgumentType(metaFunction, functionItem, argMod.index - 1); @@ -2202,8 +2188,8 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const AddedFunction: if (!type) { QStringList candidates; - SingleTypeEntryHash entries = typeDb->entries(); - for (SingleTypeEntryHash::const_iterator it = entries.cbegin(), end = entries.cend(); it != end; ++it) { + const auto &entries = typeDb->entries(); + for (auto it = entries.cbegin(), end = entries.cend(); it != end; ++it) { // Let's try to find the type in different scopes. if (it.key().endsWith(colonColon() + typeName)) candidates.append(it.key()); @@ -2211,15 +2197,17 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const AddedFunction: QString msg = QStringLiteral("Type '%1' wasn't found in the type database.\n").arg(typeName); - if (candidates.isEmpty()) - qFatal(qPrintable(QString(msg + QLatin1String("Declare it in the type system using the proper <*-type> tag."))), NULL); + if (candidates.isEmpty()) { + qFatal("%sDeclare it in the type system using the proper <*-type> tag.", + qPrintable(msg)); + } msg += QLatin1String("Remember to inform the full qualified name for the type you want to use.\nCandidates are:\n"); candidates.sort(); for (const QString& candidate : qAsConst(candidates)) { msg += QLatin1String(" ") + candidate + QLatin1Char('\n'); } - qFatal(qPrintable(msg), NULL); + qFatal("%s", qPrintable(msg)); } AbstractMetaType *metaType = new AbstractMetaType; @@ -2243,7 +2231,7 @@ static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaC { const TypeEntry* type = 0; QStringList context = metaClass->qualifiedCppName().split(colonColon()); - while(!type && (context.size() > 0) ) { + while (!type && !context.isEmpty()) { type = TypeDatabase::instance()->findType(context.join(colonColon()) + colonColon() + qualifiedName); context.removeLast(); } @@ -2251,43 +2239,48 @@ static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaC } AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typei, - bool resolveType) + bool resolveType, + QString *errorMessage) +{ + return translateTypeStatic(_typei, m_currentClass, this, resolveType, errorMessage); +} + +AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo &_typei, + AbstractMetaClass *currentClass, + AbstractMetaBuilderPrivate *d, + bool resolveType, + QString *errorMessageIn) { // 1. Test the type info without resolving typedefs in case this is present in the // type system - TypeInfo typei; if (resolveType) { - if (AbstractMetaType *resolved = translateType(_typei, false)) + if (AbstractMetaType *resolved = translateTypeStatic(_typei, currentClass, d, false, errorMessageIn)) return resolved; } - if (!resolveType) { - typei = _typei; - } else { + TypeInfo typeInfo = _typei; + if (resolveType) { // Go through all parts of the current scope (including global namespace) // to resolve typedefs. The parser does not properly resolve typedefs in // the global scope when they are referenced from inside a namespace. // This is a work around to fix this bug since fixing it in resolveType // seemed non-trivial - int i = m_scopes.size() - 1; + int i = d ? d->m_scopes.size() - 1 : -1; while (i >= 0) { - typei = TypeInfo::resolveType(_typei, m_scopes.at(i--)); - if (typei.qualifiedName().join(colonColon()) != _typei.qualifiedName().join(colonColon())) + typeInfo = TypeInfo::resolveType(_typei, d->m_scopes.at(i--)); + if (typeInfo.qualifiedName().join(colonColon()) != _typei.qualifiedName().join(colonColon())) break; } } - if (typei.isFunctionPointer()) + if (typeInfo.isFunctionPointer()) { + if (errorMessageIn) + *errorMessageIn = msgUnableToTranslateType(_typei, QLatin1String("Unsupported function pointer.")); return nullptr; + } QString errorMessage; - TypeInfo typeInfo = TypeParser::parse(typei.toString(), &errorMessage); - if (typeInfo.qualifiedName().isEmpty()) { - qWarning().noquote().nospace() << "Unable to translate type \"" << _typei.toString() - << "\": " << errorMessage; - return 0; - } // 2. Handle arrays. // 2.1 Handle char arrays with unspecified size (aka "const char[]") as "const char*" with @@ -2312,16 +2305,22 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ if (!typeInfo.arrayElements().isEmpty() && !isConstCharStarCase) { TypeInfo newInfo; //newInfo.setArguments(typeInfo.arguments()); - newInfo.setIndirections(typeInfo.indirections()); + newInfo.setIndirectionsV(typeInfo.indirectionsV()); newInfo.setConstant(typeInfo.isConstant()); + newInfo.setVolatile(typeInfo.isVolatile()); newInfo.setFunctionPointer(typeInfo.isFunctionPointer()); newInfo.setQualifiedName(typeInfo.qualifiedName()); newInfo.setReferenceType(typeInfo.referenceType()); newInfo.setVolatile(typeInfo.isVolatile()); - AbstractMetaType *elementType = translateType(newInfo); - if (!elementType) + AbstractMetaType *elementType = translateTypeStatic(newInfo, currentClass, d, true, &errorMessage); + if (!elementType) { + if (errorMessageIn) { + errorMessage.prepend(QLatin1String("Unable to translate array element: ")); + *errorMessageIn = msgUnableToTranslateType(_typei, errorMessage); + } return nullptr; + } for (int i = typeInfo.arrayElements().size() - 1; i >= 0; --i) { AbstractMetaType *arrayType = new AbstractMetaType; @@ -2329,7 +2328,9 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ const QString &arrayElement = typeInfo.arrayElements().at(i); if (!arrayElement.isEmpty()) { bool _ok; - const qint64 elems = findOutValueFromString(arrayElement, _ok); + const qint64 elems = d + ? d->findOutValueFromString(arrayElement, _ok) + : arrayElement.toLongLong(&_ok, 0); if (_ok) arrayType->setArrayElementCount(int(elems)); } @@ -2344,8 +2345,11 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ QStringList qualifierList = typeInfo.qualifiedName(); if (qualifierList.isEmpty()) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("horribly broken type '%1'").arg(_typei.toString()); + errorMessage = msgUnableToTranslateType(_typei, QLatin1String("horribly broken type")); + if (errorMessageIn) + *errorMessageIn = errorMessage; + else + qCWarning(lcShiboken,"%s", qPrintable(errorMessage)); return nullptr; } @@ -2353,19 +2357,21 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ QString name = qualifierList.takeLast(); // 4. Special case QFlags (include instantiation in name) - if (qualifiedName == QLatin1String("QFlags")) + if (qualifiedName == QLatin1String("QFlags")) { qualifiedName = typeInfo.toString(); + typeInfo.clearInstantiations(); + } const TypeEntry *type = 0; // 5. Try to find the type // 5.1 - Try first using the current scope - if (m_currentClass) { - type = findTypeEntryUsingContext(m_currentClass, qualifiedName); + if (currentClass) { + type = findTypeEntryUsingContext(currentClass, qualifiedName); // 5.1.1 - Try using the class parents' scopes - if (!type && !m_currentClass->baseClassNames().isEmpty()) { - const AbstractMetaClassList &baseClasses = getBaseClasses(m_currentClass); + if (!type && d && !currentClass->baseClassNames().isEmpty()) { + const AbstractMetaClassList &baseClasses = d->getBaseClasses(currentClass); for (const AbstractMetaClass *cls : baseClasses) { type = findTypeEntryUsingContext(cls, qualifiedName); if (type) @@ -2388,36 +2394,40 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ // 8. No? Check if the current class is a template and this type is one // of the parameters. - if (!type && m_currentClass) { - const QVector<TypeEntry *> &template_args = m_currentClass->templateArguments(); + if (!type && currentClass) { + const QVector<TypeEntry *> &template_args = currentClass->templateArguments(); for (TypeEntry *te : template_args) { if (te->name() == qualifiedName) type = te; } } - if (!type) + if (!type) { + if (errorMessageIn) { + *errorMessageIn = + msgUnableToTranslateType(_typei, msgCannotFindTypeEntry(qualifiedName)); + } return nullptr; - - // Used to for diagnostics later... - m_usedTypes << type; + } // These are only implicit and should not appear in code... Q_ASSERT(!type->isInterface()); AbstractMetaType *metaType = new AbstractMetaType; metaType->setTypeEntry(type); - metaType->setIndirections(typeInfo.indirections()); + metaType->setIndirectionsV(typeInfo.indirectionsV()); metaType->setReferenceType(typeInfo.referenceType()); metaType->setConstant(typeInfo.isConstant()); + metaType->setVolatile(typeInfo.isVolatile()); metaType->setOriginalTypeDescription(_typei.toString()); - const auto &templateArguments = typeInfo.arguments(); + const auto &templateArguments = typeInfo.instantiations(); for (int t = 0, size = templateArguments.size(); t < size; ++t) { - TypeInfo ti = templateArguments.at(t); - ti.setQualifiedName(ti.instantiationName()); - AbstractMetaType *targType = translateType(ti); + const TypeInfo &ti = templateArguments.at(t); + AbstractMetaType *targType = translateTypeStatic(ti, currentClass, d, true, &errorMessage); if (!targType) { + if (errorMessageIn) + *errorMessageIn = msgCannotTranslateTemplateArgument(t, ti, errorMessage); delete metaType; return nullptr; } @@ -2434,6 +2444,33 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ return metaType; } +AbstractMetaType *AbstractMetaBuilder::translateType(const TypeInfo &_typei, + AbstractMetaClass *currentClass, + bool resolveType, + QString *errorMessage) +{ + return AbstractMetaBuilderPrivate::translateTypeStatic(_typei, currentClass, + nullptr, resolveType, + errorMessage); +} + +AbstractMetaType *AbstractMetaBuilder::translateType(const QString &t, + AbstractMetaClass *currentClass, + bool resolveType, + QString *errorMessageIn) +{ + QString errorMessage; + TypeInfo typeInfo = TypeParser::parse(t, &errorMessage); + if (typeInfo.qualifiedName().isEmpty()) { + errorMessage = msgUnableToTranslateType(t, errorMessage); + if (errorMessageIn) + *errorMessageIn = errorMessage; + else + qCWarning(lcShiboken, "%s", qPrintable(errorMessage)); + return nullptr; + } + return translateType(typeInfo, currentClass, resolveType, errorMessageIn); +} qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringValue, bool &ok) { @@ -2472,7 +2509,7 @@ qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringV return 0; } -QString AbstractMetaBuilderPrivate::fixDefaultValue(ArgumentModelItem item, +QString AbstractMetaBuilderPrivate::fixDefaultValue(const ArgumentModelItem &item, AbstractMetaType *type, AbstractMetaFunction *fnc, AbstractMetaClass *implementingClass, @@ -2676,59 +2713,55 @@ bool AbstractMetaBuilderPrivate::ancestorHasPrivateCopyConstructor(const Abstrac return false; } -AbstractMetaType* AbstractMetaBuilderPrivate::inheritTemplateType(const QVector<AbstractMetaType *> &templateTypes, - const AbstractMetaType *metaType, - bool *ok) +AbstractMetaType * + AbstractMetaBuilderPrivate::inheritTemplateType(const AbstractMetaTypeList &templateTypes, + const AbstractMetaType *metaType) { - if (ok) - *ok = true; - if (!metaType || (!metaType->typeEntry()->isTemplateArgument() && !metaType->hasInstantiations())) - return metaType ? metaType->copy() : 0; + Q_ASSERT(metaType); + + QScopedPointer<AbstractMetaType> returned(metaType->copy()); - AbstractMetaType *returned = metaType->copy(); - returned->setOriginalTemplateType(metaType->copy()); + if (!metaType->typeEntry()->isTemplateArgument() && !metaType->hasInstantiations()) + return returned.take(); + + returned->setOriginalTemplateType(metaType); if (returned->typeEntry()->isTemplateArgument()) { const TemplateArgumentEntry* tae = static_cast<const TemplateArgumentEntry*>(returned->typeEntry()); // If the template is intantiated with void we special case this as rejecting the functions that use this // parameter from the instantiation. - if (templateTypes.size() <= tae->ordinal() || templateTypes.at(tae->ordinal())->typeEntry()->name() == QLatin1String("void")) { - if (ok) - *ok = false; - return 0; - } + const AbstractMetaType *templateType = templateTypes.value(tae->ordinal()); + if (!templateType || templateType->typeEntry()->isVoid()) + return nullptr; AbstractMetaType* t = returned->copy(); - t->setTypeEntry(templateTypes.at(tae->ordinal())->typeEntry()); - t->setIndirections(templateTypes.at(tae->ordinal())->indirections() + t->indirections() ? 1 : 0); + t->setTypeEntry(templateType->typeEntry()); + t->setIndirections(templateType->indirections() + t->indirections() ? 1 : 0); t->decideUsagePattern(); - delete returned; - returned = inheritTemplateType(templateTypes, t, ok); - if (ok && !(*ok)) - return 0; + return inheritTemplateType(templateTypes, t); } if (returned->hasInstantiations()) { AbstractMetaTypeList instantiations = returned->instantiations(); for (int i = 0; i < instantiations.count(); ++i) { - AbstractMetaType *type = instantiations[i]; - instantiations[i] = inheritTemplateType(templateTypes, type, ok); - if (ok && !(*ok)) - return 0; + instantiations[i] = + inheritTemplateType(templateTypes, instantiations.at(i)); + if (!instantiations.at(i)) + return nullptr; } returned->setInstantiations(instantiations, true); } - return returned; + return returned.take(); } bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, const AbstractMetaClass *templateClass, const TypeInfo &info) { - QVector<TypeInfo> targs = info.arguments(); + QVector<TypeInfo> targs = info.instantiations(); QVector<AbstractMetaType *> templateTypes; if (subclass->isTypeDef()) { @@ -2743,20 +2776,35 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, for (const TypeInfo &i : qAsConst(targs)) { QString typeName = i.qualifiedName().join(colonColon()); - QStringList possibleNames; - possibleNames << subclass->qualifiedCppName() + colonColon() + typeName; - possibleNames << templateClass->qualifiedCppName() + colonColon() + typeName; - if (subclass->enclosingClass()) - possibleNames << subclass->enclosingClass()->qualifiedCppName() + colonColon() + typeName; - possibleNames << typeName; - - TypeDatabase* typeDb = TypeDatabase::instance(); - TypeEntry* t = 0; - QString templateParamName; - for (const QString &possibleName : qAsConst(possibleNames)) { - t = typeDb->findType(possibleName); - if (t) - break; + TypeDatabase *typeDb = TypeDatabase::instance(); + TypeEntry *t = nullptr; + // 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. + const bool isNumber = std::all_of(typeName.cbegin(), typeName.cend(), + [](QChar c) { return c.isDigit(); }); + if (isNumber) { + t = typeDb->findType(typeName); + if (!t) { + t = new EnumValueTypeEntry(typeName, typeName, nullptr, + QVersionNumber(0, 0)); + t->setCodeGeneration(0); + typeDb->addType(t); + } + } else { + QStringList possibleNames; + possibleNames << subclass->qualifiedCppName() + colonColon() + typeName; + possibleNames << templateClass->qualifiedCppName() + colonColon() + typeName; + if (subclass->enclosingClass()) + possibleNames << subclass->enclosingClass()->qualifiedCppName() + colonColon() + typeName; + possibleNames << typeName; + + for (const QString &possibleName : qAsConst(possibleNames)) { + t = typeDb->findType(possibleName); + if (t) + break; + } } if (t) { @@ -2764,48 +2812,48 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, temporaryType->setTypeEntry(t); temporaryType->setConstant(i.isConstant()); temporaryType->setReferenceType(i.referenceType()); - temporaryType->setIndirections(i.indirections()); + temporaryType->setIndirectionsV(i.indirectionsV()); temporaryType->decideUsagePattern(); templateTypes << temporaryType; } else { qCWarning(lcShiboken).noquote().nospace() - << "Ignoring template parameter " << templateParamName << " from " - << info.instantiationName() << ", because I don't know what it is."; + << "Ignoring template parameter " << typeName << " from " + << info.toString() << ". The corresponding type was not found in the typesystem."; } } - AbstractMetaFunctionList funcs = subclass->functions(); + const AbstractMetaFunctionList &subclassFuncs = subclass->functions(); const AbstractMetaFunctionList &templateClassFunctions = templateClass->functions(); for (const AbstractMetaFunction *function : templateClassFunctions) { - if (function->isModifiedRemoved(TypeSystem::All)) + // If the function is modified or the instantiation has an equally named + // function we have shadowing, so we need to skip it. + if (function->isModifiedRemoved(TypeSystem::All) + || AbstractMetaFunction::find(subclassFuncs, function->name()) != nullptr) { continue; + } - AbstractMetaFunction *f = function->copy(); + QScopedPointer<AbstractMetaFunction> f(function->copy()); f->setArguments(AbstractMetaArgumentList()); - bool ok = true; - AbstractMetaType *ftype = function->type(); - f->replaceType(inheritTemplateType(templateTypes, ftype, &ok)); - if (!ok) { - delete f; - continue; + if (function->type()) { // Non-void + AbstractMetaType *returnType = inheritTemplateType(templateTypes, function->type()); + if (!returnType) + continue; + f->replaceType(returnType); } const AbstractMetaArgumentList &arguments = function->arguments(); for (AbstractMetaArgument *argument : arguments) { - AbstractMetaType* atype = argument->type(); - - AbstractMetaArgument *arg = argument->copy(); - arg->replaceType(inheritTemplateType(templateTypes, atype, &ok)); - if (!ok) + AbstractMetaType *argType = inheritTemplateType(templateTypes, argument->type()); + if (!argType) break; + AbstractMetaArgument *arg = argument->copy(); + arg->replaceType(argType); f->addArgument(arg); } - if (!ok) { - delete f; + if (f->arguments().size() < function->arguments().size()) continue; - } // There is no base class in the target language to inherit from here, so // the template instantiation is the class that implements the function. @@ -2816,27 +2864,11 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, // on the inherited functions. f->setDeclaringClass(subclass); - - if (f->isConstructor() && subclass->isTypeDef()) { + if (f->isConstructor()) { + if (!subclass->isTypeDef()) + continue; f->setName(subclass->name()); f->setOriginalName(subclass->name()); - } else if (f->isConstructor()) { - delete f; - continue; - } - - // if the instantiation has a function named the same as an existing - // function we have shadowing so we need to skip it. - bool found = false; - for (int i = 0; i < funcs.size(); ++i) { - if (funcs.at(i)->name() == f->name()) { - found = true; - continue; - } - } - if (found) { - delete f; - continue; } ComplexTypeEntry* te = subclass->typeEntry(); @@ -2863,7 +2895,27 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, te->addFunctionModification(mod); } - subclass->addFunction(f); + subclass->addFunction(f.take()); + } + + const AbstractMetaFieldList &subClassFields = subclass->fields(); + const AbstractMetaFieldList &templateClassFields = templateClass->fields(); + for (const AbstractMetaField *field : templateClassFields) { + // If the field is modified or the instantiation has a field named + // the same as an existing field we have shadowing, so we need to skip it. + if (field->isModifiedRemoved(TypeSystem::All) + || field->attributes().testFlag(AbstractMetaAttributes::Static) + || AbstractMetaField::find(subClassFields, field->name()) != nullptr) { + continue; + } + + QScopedPointer<AbstractMetaField> f(field->copy()); + f->setEnclosingClass(subclass); + AbstractMetaType *fieldType = inheritTemplateType(templateTypes, field->type()); + if (!fieldType) + continue; + f->replaceType(fieldType); + subclass->addField(f.take()); } subclass->setTemplateBaseClass(templateClass); @@ -2878,9 +2930,9 @@ void AbstractMetaBuilderPrivate::parseQ_Property(AbstractMetaClass *metaClass, const QStringList &declarations) { for (int i = 0; i < declarations.size(); ++i) { - QString p = declarations.at(i); + const QString &p = declarations.at(i); - QStringList l = p.split(QLatin1String(" ")); + QStringList l = p.split(QLatin1Char(' ')); QStringList qualifiedScopeName = currentScope()->qualifiedName(); @@ -2925,8 +2977,8 @@ void AbstractMetaBuilderPrivate::parseQ_Property(AbstractMetaClass *metaClass, static AbstractMetaFunction* findCopyCtor(AbstractMetaClass* cls) { - AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::Invisible); - functions << cls->queryFunctions(AbstractMetaClass::Visible); + + const auto &functions = cls->functions(); for (AbstractMetaFunction *f : qAsConst(functions)) { const AbstractMetaFunction::FunctionType t = f->functionType(); |