diff options
Diffstat (limited to 'sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp')
-rw-r--r-- | sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp | 832 |
1 files changed, 422 insertions, 410 deletions
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index ae3cdd86b..5ab6c1976 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -28,6 +28,7 @@ #include "abstractmetabuilder_p.h" #include "messages.h" +#include "propertyspec.h" #include "reporthandler.h" #include "typedatabase.h" @@ -42,7 +43,6 @@ #include <QFile> #include <QFileInfo> #include <QRegularExpression> -#include <QTextCodec> #include <QTextStream> #include <QVariant> #include <QTime> @@ -135,27 +135,27 @@ AbstractMetaBuilder::~AbstractMetaBuilder() delete d; } -AbstractMetaClassList AbstractMetaBuilder::classes() const +const AbstractMetaClassList &AbstractMetaBuilder::classes() const { return d->m_metaClasses; } -AbstractMetaClassList AbstractMetaBuilder::templates() const +const AbstractMetaClassList &AbstractMetaBuilder::templates() const { return d->m_templates; } -AbstractMetaClassList AbstractMetaBuilder::smartPointers() const +const AbstractMetaClassList &AbstractMetaBuilder::smartPointers() const { return d->m_smartPointers; } -AbstractMetaFunctionList AbstractMetaBuilder::globalFunctions() const +const AbstractMetaFunctionList &AbstractMetaBuilder::globalFunctions() const { return d->m_globalFunctions; } -AbstractMetaEnumList AbstractMetaBuilder::globalEnums() const +const AbstractMetaEnumList &AbstractMetaBuilder::globalEnums() const { return d->m_globalEnums; } @@ -175,12 +175,12 @@ void AbstractMetaBuilderPrivate::checkFunctionModifications() const TypeEntry *entry = it.value(); if (!entry) continue; - if (!entry->isComplex() || entry->codeGeneration() == TypeEntry::GenerateNothing) + if (!entry->isComplex() || !entry->generateCode()) continue; auto centry = static_cast<const ComplexTypeEntry *>(entry); - if (!(centry->codeGeneration() & TypeEntry::GenerateTargetLang)) + if (!centry->generateCode()) continue; FunctionModificationList modifications = centry->functionModifications(); @@ -213,9 +213,8 @@ void AbstractMetaBuilderPrivate::checkFunctionModifications() if (!found) { qCWarning(lcShiboken).noquote().nospace() - << msgNoFunctionForModification(signature, + << msgNoFunctionForModification(clazz, signature, modification.originalSignature(), - clazz->qualifiedCppName(), possibleSignatures, functions); } } @@ -270,7 +269,7 @@ void AbstractMetaBuilderPrivate::registerToStringCapability(const FunctionModelI const ArgumentModelItem &arg = arguments.at(1); if (AbstractMetaClass *cls = argumentToClass(arg, currentClass)) { if (arg->type().indirections() < 2) - cls->setToStringCapability(true, arg->type().indirections()); + cls->setToStringCapability(true, int(arg->type().indirections())); } } } @@ -291,7 +290,7 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelIte if (arguments.size() == 1) { unaryOperator = true; } else if (!baseoperandClass - || !(baseoperandClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang)) { + || !baseoperandClass->typeEntry()->generateCode()) { baseoperandClass = argumentToClass(arguments.at(1), currentClass); firstArgumentIsSelf = false; } else { @@ -410,6 +409,7 @@ FileModelItem AbstractMetaBuilderPrivate::buildDom(QByteArrayList arguments, unsigned clangFlags) { clang::Builder builder; + builder.setSystemIncludes(TypeDatabase::instance()->systemIncludes()); if (level == LanguageLevel::Default) level = clang::emulatedCompilerLanguageLevel(); arguments.prepend(QByteArrayLiteral("-std=") @@ -512,8 +512,10 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) ReportHandler::startProgress("Fixing class inheritance..."); for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) { - if (!cls->isInterface() && !cls->isNamespace()) { + if (!cls->isNamespace()) { setupInheritance(cls); + if (cls->templateBaseClass()) + inheritTemplateFunctions(cls); if (!cls->hasVirtualDestructor() && cls->baseClass() && cls->baseClass()->hasVirtualDestructor()) cls->setHasVirtualDestructor(true); @@ -530,7 +532,7 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) .arg(cls->name()); } else { const bool couldAddDefaultCtors = cls->isConstructible() - && !cls->isInterface() && !cls->isNamespace() + && !cls->isNamespace() && (cls->attributes() & AbstractMetaAttributes::HasRejectedConstructor) == 0; if (couldAddDefaultCtors) { if (!cls->hasConstructors()) @@ -539,9 +541,6 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) cls->addDefaultCopyConstructor(ancestorHasPrivateCopyConstructor(cls)); } } - - if (cls->isAbstract() && !cls->isInterface()) - cls->typeEntry()->setLookupName(cls->typeEntry()->targetLangName() + QLatin1String("$ConcreteWrapper")); } const auto &allEntries = types->entries(); @@ -552,16 +551,11 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) if (!entry->isPrimitive()) { if ((entry->isValue() || entry->isObject()) && !types->shouldDropTypeEntry(entry->qualifiedCppName()) - && !entry->isString() - && !entry->isChar() && !entry->isContainer() && !entry->isCustom() - && !entry->isVariant() - && (entry->generateCode() & TypeEntry::GenerateTargetLang) + && entry->generateCode() && !AbstractMetaClass::findClass(m_metaClasses, entry)) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("type '%1' is specified in typesystem, but not defined. This could potentially lead to compilation errors.") - .arg(entry->qualifiedCppName()); + qCWarning(lcShiboken, "%s", qPrintable(msgTypeNotDefined(entry))); } else if (entry->generateCode() && entry->type() == TypeEntry::FunctionType) { auto fte = static_cast<const FunctionTypeEntry *>(entry); const QStringList &signatures = fte->signatures(); @@ -574,24 +568,24 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) } } if (!ok) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("Global function '%1' is specified in typesystem, but not defined. This could potentially lead to compilation errors.") - .arg(signature); + qCWarning(lcShiboken, "%s", + qPrintable(msgGlobalFunctionNotDefined(fte, signature))); } } - } else if (entry->isEnum() && (entry->generateCode() & TypeEntry::GenerateTargetLang)) { - const QString name = static_cast<const EnumTypeEntry *>(entry)->targetLangQualifier(); - AbstractMetaClass *cls = AbstractMetaClass::findClass(m_metaClasses, name); + } else if (entry->isEnum() && entry->generateCode()) { + auto enumEntry = static_cast<const EnumTypeEntry *>(entry); + const QString name = enumEntry->targetLangQualifier(); + AbstractMetaClass *cls = AbstractMetaClass::findClass(m_metaClasses, + enumEntry->parent()); const bool enumFound = cls - ? cls->findEnum(entry->targetLangName()) != nullptr + ? cls->findEnum(entry->targetLangEntryName()) != nullptr : m_enums.contains(entry); if (!enumFound) { entry->setCodeGeneration(TypeEntry::GenerateNothing); - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("enum '%1' is specified in typesystem, but not declared") - .arg(entry->qualifiedCppName()); + qCWarning(lcShiboken, "%s", + qPrintable(msgEnumNotDefined(enumEntry))); } } @@ -680,6 +674,7 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) } m_itemToClass.clear(); + m_typeSystemTypeDefs.clear(); ReportHandler::endProgress(); } @@ -732,12 +727,6 @@ void AbstractMetaBuilderPrivate::addAbstractMetaClass(AbstractMetaClass *cls, m_smartPointers << cls; } else { m_metaClasses << cls; - if (cls->typeEntry()->designatedInterface()) { - AbstractMetaClass *interface = cls->extractInterface(); - m_metaClasses << interface; - if (ReportHandler::isDebug(ReportHandler::SparseDebug)) - qCDebug(lcShiboken) << QStringLiteral(" -> interface '%1'").arg(interface->name()); - } } } @@ -756,11 +745,16 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModel auto type = TypeDatabase::instance()->findNamespaceType(namespaceName, namespaceItem->fileName()); if (!type) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("namespace '%1' does not have a type entry").arg(namespaceName); + qCWarning(lcShiboken, "%s", + qPrintable(msgNamespaceNoTypeEntry(namespaceItem, namespaceName))); return nullptr; } + if (namespaceItem->type() == NamespaceType::Inline) { + type->setInlineNamespace(true); + TypeDatabase::instance()->addInlineNamespaceLookups(type); + } + // Continue populating namespace? AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_metaClasses, type); if (!metaClass) { @@ -781,11 +775,6 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModel m_itemToClass.insert(namespaceItem.data(), metaClass); } - if (ReportHandler::isDebug(ReportHandler::SparseDebug)) { - qCDebug(lcShiboken) - << QStringLiteral("namespace '%1.%2'").arg(metaClass->package(), namespaceItem->name()); - } - traverseEnums(namespaceItem, metaClass, namespaceItem->enumsDeclarations()); pushScope(namespaceItem); @@ -836,13 +825,10 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem & QString qualifiedName = enumItem->qualifiedName().join(colonColon()); TypeEntry *typeEntry = nullptr; + const TypeEntry *enclosingTypeEntry = enclosing ? enclosing->typeEntry() : nullptr; if (enumItem->accessPolicy() == CodeModel::Private) { - QStringList names = enumItem->qualifiedName(); - const QString &enumName = names.constLast(); - QString nspace; - if (names.size() > 1) - nspace = QStringList(names.mid(0, names.size() - 1)).join(colonColon()); - typeEntry = new EnumTypeEntry(nspace, enumName, QVersionNumber(0, 0)); + typeEntry = new EnumTypeEntry(enumItem->qualifiedName().constLast(), + QVersionNumber(0, 0), enclosingTypeEntry); TypeDatabase::instance()->addType(typeEntry); } else if (enumItem->enumKind() != AnonymousEnum) { typeEntry = TypeDatabase::instance()->findType(qualifiedName); @@ -862,8 +848,8 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem & QString enumName = enumItem->name(); QString className; - if (enclosing) - className = enclosing->typeEntry()->qualifiedCppName(); + if (enclosingTypeEntry) + className = enclosingTypeEntry->qualifiedCppName(); QString rejectReason; if (TypeDatabase::instance()->isEnumRejected(className, enumName, &rejectReason)) { @@ -873,8 +859,7 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem & return nullptr; } - const bool rejectionWarning = !enclosing - || (enclosing->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang); + const bool rejectionWarning = !enclosing || enclosing->typeEntry()->generateCode(); if (!typeEntry) { if (rejectionWarning) @@ -917,9 +902,6 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem & break; } - if (ReportHandler::isDebug(ReportHandler::MediumDebug)) - qCDebug(lcShiboken) << " - traversing enum " << metaEnum->fullName(); - const EnumeratorList &enums = enumItem->enumerators(); for (const EnumeratorModelItem &value : enums) { @@ -930,11 +912,6 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem & metaEnumValue->setStringValue(value->stringValue()); metaEnumValue->setValue(value->value()); metaEnum->addEnumValue(metaEnumValue); - - if (ReportHandler::isDebug(ReportHandler::FullDebug)) { - qCDebug(lcShiboken) << " - " << metaEnumValue->name() << " = " - << metaEnumValue->value() << " = " << metaEnumValue->value(); - } } m_enums.insert(typeEntry, metaEnum); @@ -945,25 +922,13 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem & 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 bool isScopedEnum = enumItem->enumKind() == EnumClass; const EnumeratorList &enumerators = enumItem->enumerators(); for (const EnumeratorModelItem &e : enumerators) { - QString name; - if (enclosing) { - name += enclosing->name(); - name += colonColon(); - } - EnumValueTypeEntry *enumValue = - new EnumValueTypeEntry(prefix + e->name(), e->stringValue(), - enumTypeEntry, enumTypeEntry->version()); + auto enumValue = + new EnumValueTypeEntry(e->name(), e->stringValue(), + enumTypeEntry, isScopedEnum, + enumTypeEntry->version()); TypeDatabase::instance()->addType(enumValue); if (e->value().isNullValue()) enumTypeEntry->setNullValue(enumValue); @@ -1030,6 +995,23 @@ void AbstractMetaBuilderPrivate::traverseTypesystemTypedefs() *metaClass += AbstractMetaAttributes::Public; fillAddedFunctions(metaClass); addAbstractMetaClass(metaClass, nullptr); + // Ensure base classes are set up when traversing functions for the + // type to be resolved. + if (setupInheritance(metaClass)) { + // Create an entry to look up up types obtained from parsing + // functions in reverse. As opposed to container specializations, + // which are generated into every instantiating module (indicated + // by ContainerTypeEntry::targetLangPackage() being empty), the + // correct index array of the module needs to be found by reverse + // mapping the instantiations to the typedef entry. + // Synthesize a AbstractMetaType which would be found by an + // instantiation. + auto sourceType = new AbstractMetaType; + sourceType->setTypeEntry(metaClass->templateBaseClass()->typeEntry()); + sourceType->setInstantiations(metaClass->templateBaseClassInstantiations()); + sourceType->decideUsagePattern(); + m_typeSystemTypeDefs.append({AbstractMetaTypeCPtr(sourceType), metaClass}); + } } } @@ -1070,6 +1052,7 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem } auto *metaClass = new AbstractMetaClass; + metaClass->setSourceLocation(classItem->sourceLocation()); metaClass->setTypeEntry(type); if (classItem->isFinal()) @@ -1087,25 +1070,27 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem if (type->stream()) metaClass->setStream(true); - if (ReportHandler::isDebug(ReportHandler::SparseDebug)) { + if (ReportHandler::isDebug(ReportHandler::MediumDebug)) { const QString message = type->isContainer() ? QStringLiteral("container: '%1'").arg(fullClassName) : QStringLiteral("class: '%1'").arg(metaClass->fullName()); - qCDebug(lcShiboken) << message; + qCInfo(lcShiboken, "%s", qPrintable(message)); } TemplateParameterList template_parameters = classItem->templateParameters(); QVector<TypeEntry *> template_args; template_args.clear(); + auto argumentParent = metaClass->typeEntry()->typeSystemTypeEntry(); for (int i = 0; i < template_parameters.size(); ++i) { const TemplateParameterModelItem ¶m = template_parameters.at(i); - TemplateArgumentEntry *param_type = new TemplateArgumentEntry(param->name(), type->version()); + auto param_type = new TemplateArgumentEntry(param->name(), type->version(), + argumentParent); param_type->setOrdinal(i); template_args.append(param_type); } metaClass->setTemplateArguments(template_args); - parseQ_Property(metaClass, classItem->propertyDeclarations()); + parseQ_Properties(metaClass, classItem->propertyDeclarations()); traverseEnums(classItem, metaClass, classItem->enumsDeclarations()); @@ -1220,10 +1205,9 @@ AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(const VariableModel if (!metaType) { const QString type = TypeInfo::resolveType(fieldType, currentScope()).qualifiedName().join(colonColon()); - if (cls->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("skipping field '%1::%2' with unmatched type '%3'") - .arg(cls->name(), fieldName, type); + if (cls->typeEntry()->generateCode()) { + qCWarning(lcShiboken, "%s", + qPrintable(msgSkippingField(field, cls->name(), type))); } delete metaField; return nullptr; @@ -1231,7 +1215,7 @@ AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(const VariableModel metaField->setType(metaType); - AbstractMetaAttributes::Attributes attr = nullptr; + AbstractMetaAttributes::Attributes attr; if (field->isStatic()) attr |= AbstractMetaAttributes::Static; @@ -1295,41 +1279,16 @@ void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaF if (!retType) return; - auto *metaType = new AbstractMetaType; - metaType->setTypeEntry(retType); + auto metaType = new AbstractMetaType(retType); + metaType->decideUsagePattern(); metaFunction->replaceType(metaType); } -static bool _compareAbstractMetaTypes(const AbstractMetaType *type, const AbstractMetaType *other) -{ - return (type != nullptr) == (other != nullptr) - && (type == nullptr || *type == *other); -} - -static bool _compareAbstractMetaFunctions(const AbstractMetaFunction *func, const AbstractMetaFunction *other) -{ - if (!func && !other) - return true; - if (!func || !other) - return false; - if (func->arguments().count() != other->arguments().count() - || func->isConstant() != other->isConstant() - || func->isStatic() != other->isStatic() - || !_compareAbstractMetaTypes(func->type(), other->type())) { - return false; - } - for (int i = 0; i < func->arguments().count(); ++i) { - if (!_compareAbstractMetaTypes(func->arguments().at(i)->type(), other->arguments().at(i)->type())) - return false; - } - return true; -} - AbstractMetaFunctionList AbstractMetaBuilderPrivate::classFunctionList(const ScopeModelItem &scopeItem, AbstractMetaClass::Attributes *constructorAttributes, AbstractMetaClass *currentClass) { - *constructorAttributes = nullptr; + *constructorAttributes = {}; AbstractMetaFunctionList result; const FunctionList &scopeFunctionList = scopeItem->functions(); result.reserve(scopeFunctionList.size()); @@ -1346,29 +1305,6 @@ AbstractMetaFunctionList AbstractMetaBuilderPrivate::classFunctionList(const Sco return result; } -// For template classes, entries with more specific types may exist from out-of- -// line definitions. If there is a declaration which matches it after fixing -// the parameters, remove it as duplicate. For example: -// template class<T> Vector { public: -// Vector(const Vector &rhs); -// }; -// template class<T> -// Vector<T>::Vector(const Vector<T>&) {} // More specific, remove declaration. - -class DuplicatingFunctionPredicate : public std::unary_function<bool, const AbstractMetaFunction *> { -public: - explicit DuplicatingFunctionPredicate(const AbstractMetaFunction *f) : m_function(f) {} - - bool operator()(const AbstractMetaFunction *rhs) const - { - return rhs != m_function && rhs->name() == m_function->name() - && _compareAbstractMetaFunctions(m_function, rhs); - } - -private: - const AbstractMetaFunction *m_function; -}; - void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, AbstractMetaClass *metaClass) { @@ -1377,7 +1313,7 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, classFunctionList(scopeItem, &constructorAttributes, metaClass); metaClass->setAttributes(metaClass->attributes() | constructorAttributes); - for (AbstractMetaFunction *metaFunction : functions){ + for (AbstractMetaFunction *metaFunction : functions) { metaFunction->setOriginalAttributes(metaFunction->attributes()); if (metaClass->isNamespace()) *metaFunction += AbstractMetaAttributes::Static; @@ -1385,21 +1321,23 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, QPropertySpec *read = nullptr; if (!metaFunction->isSignal() && (read = metaClass->propertySpecForRead(metaFunction->name()))) { // Property reader must be in the form "<type> name()" - if (metaFunction->type() && (read->type() == metaFunction->type()->typeEntry()) + if (read->typeEntry() == metaFunction->type()->typeEntry() && metaFunction->arguments().isEmpty()) { *metaFunction += AbstractMetaAttributes::PropertyReader; metaFunction->setPropertySpec(read); } } else if (QPropertySpec *write = metaClass->propertySpecForWrite(metaFunction->name())) { // Property setter must be in the form "void name(<type>)" - // make sure the function was created with all aguments, some argument can be missing during the pareser because of errors on typesystem - if ((!metaFunction->type()) && (metaFunction->arguments().size() == 1) && (write->type() == metaFunction->arguments().at(0)->type()->typeEntry())) { + // Make sure the function was created with all arguments; some argument can be + // missing during the parsing because of errors in the typesystem. + if (metaFunction->isVoid() && metaFunction->arguments().size() == 1 + && (write->typeEntry() == metaFunction->arguments().at(0)->type()->typeEntry())) { *metaFunction += AbstractMetaAttributes::PropertyWriter; metaFunction->setPropertySpec(write); } } else if (QPropertySpec *reset = metaClass->propertySpecForReset(metaFunction->name())) { // Property resetter must be in the form "void name()" - if ((!metaFunction->type()) && metaFunction->arguments().isEmpty()) { + if (metaFunction->isVoid() && metaFunction->arguments().isEmpty()) { *metaFunction += AbstractMetaAttributes::PropertyResetter; metaFunction->setPropertySpec(reset); } @@ -1418,13 +1356,6 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, metaClass->setHasNonPrivateConstructor(true); } - // Classes with virtual destructors should always have a shell class - // (since we aren't registering the destructors, we need this extra check) - if (metaFunction->isDestructor() && metaFunction->isVirtual() - && metaFunction->visibility() != AbstractMetaAttributes::Private) { - metaClass->setForceShellClass(true); - } - if (!metaFunction->isDestructor() && !(metaFunction->isPrivate() && metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction)) { @@ -1500,8 +1431,6 @@ void AbstractMetaBuilderPrivate::applyFunctionModifications(AbstractMetaFunction bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass) { - Q_ASSERT(!metaClass->isInterface()); - if (m_setupInheritanceDone.contains(metaClass)) return true; @@ -1541,61 +1470,23 @@ bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass) TypeDatabase* types = TypeDatabase::instance(); - int primary = -1; - int primaries = 0; - for (int i = 0; i < baseClasses.size(); ++i) { - - if (types->isClassRejected(baseClasses.at(i))) - continue; - - TypeEntry* baseClassEntry = types->findType(baseClasses.at(i)); - if (!baseClassEntry) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("class '%1' inherits from unknown base class '%2'") - .arg(metaClass->name(), baseClasses.at(i)); - } else if (!baseClassEntry->designatedInterface()) { // true for primary base class - primaries++; - primary = i; - } - } - - if (primary >= 0) { - AbstractMetaClass *baseClass = AbstractMetaClass::findClass(m_metaClasses, baseClasses.at(primary)); - if (!baseClass) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("unknown baseclass for '%1': '%2'") - .arg(metaClass->name(), baseClasses.at(primary)); - return false; - } - metaClass->setBaseClass(baseClass); - } - - for (int i = 0; i < baseClasses.size(); ++i) { - if (types->isClassRejected(baseClasses.at(i))) - continue; - - if (i != primary) { - AbstractMetaClass *baseClass = AbstractMetaClass::findClass(m_metaClasses, baseClasses.at(i)); - if (!baseClass) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("class not found for setup inheritance '%1'").arg(baseClasses.at(i)); + for (const auto &baseClassName : baseClasses) { + if (!types->isClassRejected(baseClassName)) { + auto typeEntry = types->findType(baseClassName); + if (typeEntry == nullptr || !typeEntry->isComplex()) { + qCWarning(lcShiboken, "%s", + qPrintable(msgUnknownBase(metaClass, baseClassName))); return false; } - - setupInheritance(baseClass); - - QString interfaceName = baseClass->isInterface() ? InterfaceTypeEntry::interfaceName(baseClass->name()) : baseClass->name(); - AbstractMetaClass *iface = AbstractMetaClass::findClass(m_metaClasses, interfaceName); - if (!iface) { + auto baseClass = AbstractMetaClass::findClass(m_metaClasses, typeEntry); + if (!baseClass) { qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("unknown interface for '%1': '%2'").arg(metaClass->name(), interfaceName); + << QStringLiteral("class not found for setup inheritance '%1'").arg(baseClassName); return false; } - metaClass->addInterface(iface); + metaClass->addBaseClass(baseClass); - const AbstractMetaClassList &interfaces = iface->interfaces(); - for (AbstractMetaClass* iface : interfaces) - metaClass->addInterface(iface); + setupInheritance(baseClass); } } @@ -1649,9 +1540,19 @@ AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFu AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFunctionPtr &addedFunc, AbstractMetaClass *metaClass) { - auto *metaFunction = new AbstractMetaFunction(addedFunc); - metaFunction->setType(translateType(addedFunc->returnType())); + QString errorMessage; + + AbstractMetaType *returnType = translateType(addedFunc->returnType(), &errorMessage); + if (!returnType) { + qCWarning(lcShiboken, "%s", + qPrintable(msgAddedFunctionInvalidReturnType(addedFunc->name(), + addedFunc->returnType().name, + errorMessage))); + return nullptr; + } + auto metaFunction = new AbstractMetaFunction(addedFunc); + metaFunction->setType(returnType); const auto &args = addedFunc->arguments(); AbstractMetaArgumentList metaArguments; @@ -1659,11 +1560,12 @@ AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFu for (int i = 0; i < args.count(); ++i) { const AddedFunction::TypeInfo& typeInfo = args.at(i).typeInfo; auto *metaArg = new AbstractMetaArgument; - AbstractMetaType *type = translateType(typeInfo); + AbstractMetaType *type = translateType(typeInfo, &errorMessage); if (Q_UNLIKELY(!type)) { - qCWarning(lcShiboken, - "Unable to translate type \"%s\" of argument %d of added function \"%s\".", - qPrintable(typeInfo.name), i + 1, qPrintable(addedFunc->name())); + qCWarning(lcShiboken, "%s", + qPrintable(msgAddedFunctionInvalidArgType(addedFunc->name(), + typeInfo.name, i + 1, + errorMessage))); delete metaFunction; return nullptr; } @@ -1726,7 +1628,12 @@ AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFu metaFunction->setFunctionType(AbstractMetaFunction::CopyConstructorFunction); } } else { - metaFunction->setFunctionType(AbstractMetaFunction::NormalFunction); + auto type = AbstractMetaFunction::NormalFunction; + if (metaFunction->name() == QLatin1String("__getattro__")) + type = AbstractMetaFunction::GetAttroFunction; + else if (metaFunction->name() == QLatin1String("__setattro__")) + type = AbstractMetaFunction::SetAttroFunction; + metaFunction->setFunctionType(type); } metaFunction->setDeclaringClass(metaClass); @@ -1858,11 +1765,14 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio 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) + + if (rejected) { + if (ReportHandler::isDebug(ReportHandler::MediumDebug)) { + qCInfo(lcShiboken, "%s::%s was rejected by the type database (%s).", + qPrintable(className), qPrintable(signature), qPrintable(rejectReason)); + } return nullptr; + } if (functionItem->isFriend()) return nullptr; @@ -1875,6 +1785,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio } auto *metaFunction = new AbstractMetaFunction; + metaFunction->setSourceLocation(functionItem->sourceLocation()); if (deprecated) *metaFunction += AbstractMetaAttributes::Deprecated; @@ -1883,9 +1794,6 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio metaFunction->setConstant(functionItem->isConstant()); metaFunction->setExceptionSpecification(functionItem->exceptionSpecification()); - if (ReportHandler::isDebug(ReportHandler::MediumDebug)) - qCDebug(lcShiboken).noquote().nospace() << " - " << functionName << "()"; - metaFunction->setName(functionName); metaFunction->setOriginalName(functionItem->name()); @@ -1921,10 +1829,12 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio QString errorMessage; switch (metaFunction->functionType()) { case AbstractMetaFunction::DestructorFunction: + 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(); @@ -1935,17 +1845,14 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio return nullptr; } - AbstractMetaType *type = nullptr; - if (!returnType.isVoid()) { - type = translateType(returnType, currentClass, {}, &errorMessage); - if (!type) { - const QString reason = msgUnmatchedReturnType(functionItem, errorMessage); - qCWarning(lcShiboken, "%s", - qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason))); - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::UnmatchedReturnType); - delete metaFunction; - return nullptr; - } + AbstractMetaType *type = translateType(returnType, currentClass, {}, &errorMessage); + if (!type) { + const QString reason = msgUnmatchedReturnType(functionItem, errorMessage); + qCWarning(lcShiboken, "%s", + qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason))); + m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::UnmatchedReturnType); + delete metaFunction; + return nullptr; } metaFunction->setType(type); @@ -1976,16 +1883,12 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio AbstractMetaType *metaType = translateType(arg->type(), currentClass, {}, &errorMessage); if (!metaType) { // If an invalid argument has a default value, simply remove it - if (arg->defaultValue()) { - if (!currentClass - || (currentClass->typeEntry()->codeGeneration() - & TypeEntry::GenerateTargetLang)) { - qCWarning(lcShiboken).noquote().nospace() - << "Stripping argument #" << (i + 1) << " of " - << originalQualifiedSignatureWithReturn - << " due to unmatched type \"" << arg->type().toString() - << "\" with default expression \"" - << arg->defaultValueExpression() << "\"."; + // unless the function is virtual (since the override in the + // wrapper can then not correctly be generated). + if (arg->defaultValue() && !functionItem->isVirtual()) { + if (!currentClass || currentClass->typeEntry()->generateCode()) { + qCWarning(lcShiboken, "%s", + qPrintable(msgStrippingArgument(functionItem, i, originalQualifiedSignatureWithReturn, arg))); } break; } @@ -2049,8 +1952,8 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio fixArgumentNames(metaFunction, functionMods); QString errorMessage; if (!applyArrayArgumentModifications(functionMods, metaFunction, &errorMessage)) { - qCWarning(lcShiboken, "While traversing %s: %s", - qPrintable(className), qPrintable(errorMessage)); + qCWarning(lcShiboken, "%s", + qPrintable(msgArrayModificationFailed(functionItem, className, errorMessage))); } } @@ -2077,31 +1980,40 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio return metaFunction; } -AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const AddedFunction::TypeInfo &typeInfo) +AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const AddedFunction::TypeInfo &typeInfo, + QString *errorMessage) { Q_ASSERT(!typeInfo.name.isEmpty()); TypeDatabase* typeDb = TypeDatabase::instance(); - TypeEntry* type; QString typeName = typeInfo.name; if (typeName == QLatin1String("void")) - return nullptr; + return AbstractMetaType::createVoid(); - type = typeDb->findType(typeName); + TypeEntry *type = typeDb->findType(typeName); + if (!type) + type = typeDb->findFlagsType(typeName); // test if the type is a template, like a container bool isTemplate = false; QStringList templateArgs; if (!type && typeInfo.name.contains(QLatin1Char('<'))) { - const QStringList& parsedType = parseTemplateType(typeInfo.name); + QStringList parsedType = parseTemplateType(typeInfo.name); if (parsedType.isEmpty()) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("Template type parsing failed for '%1'").arg(typeInfo.name); - } else { - templateArgs = parsedType.mid(1); - isTemplate = (type = typeDb->findContainerType(parsedType[0])); + *errorMessage = QStringLiteral("Template type parsing failed for '%1'").arg(typeInfo.name); + return nullptr; + } + const QString name = parsedType.takeFirst(); + templateArgs = parsedType; + type = typeDb->findContainerType(name); + if (!type) { // A template typedef? + if (auto candidate = typeDb->findType(name)) { + if (candidate->type() == TypeEntry::ObjectType || candidate->type() == TypeEntry::BasicValueType) + type = candidate; + } } + isTemplate = type != nullptr; } if (!type) { @@ -2112,34 +2024,36 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const AddedFunction: if (it.key().endsWith(colonColon() + typeName)) candidates.append(it.key()); } - - QString msg = QStringLiteral("Type '%1' wasn't found in the type database.\n").arg(typeName); + QTextStream str(errorMessage); + str << "Type '" << typeName << "' wasn't found in the type database.\n"; 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'); + str << "Declare it in the type system using the proper <*-type> tag."; + } else { + str << "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)) + str << " " << candidate << '\n'; } - qFatal("%s", qPrintable(msg)); + return nullptr; } - auto *metaType = new AbstractMetaType; - metaType->setTypeEntry(type); + // These are only implicit and should not appear in code... + auto *metaType = new AbstractMetaType(type); metaType->setIndirections(typeInfo.indirections); if (typeInfo.isReference) metaType->setReferenceType(LValueReference); metaType->setConstant(typeInfo.isConstant); if (isTemplate) { for (const QString& templateArg : qAsConst(templateArgs)) { - AbstractMetaType *metaArgType = translateType(AddedFunction::TypeInfo::fromSignature(templateArg)); + AbstractMetaType *metaArgType = translateType(AddedFunction::TypeInfo::fromSignature(templateArg), errorMessage); + if (!metaArgType) + return nullptr; metaType->addInstantiation(metaArgType); } metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern); + } else { + metaType->decideUsagePattern(); } return metaType; @@ -2156,6 +2070,66 @@ static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaC return type; } +// Helper for translateTypeStatic() +TypeEntries AbstractMetaBuilderPrivate::findTypeEntries(const QString &qualifiedName, + const QString &name, + AbstractMetaClass *currentClass, + AbstractMetaBuilderPrivate *d) +{ + // 5.1 - Try first using the current scope + if (currentClass) { + if (auto type = findTypeEntryUsingContext(currentClass, qualifiedName)) + return {type}; + + // 5.1.1 - Try using the class parents' scopes + if (d && !currentClass->baseClassNames().isEmpty()) { + const AbstractMetaClassList &baseClasses = d->getBaseClasses(currentClass); + for (const AbstractMetaClass *cls : baseClasses) { + if (auto type = findTypeEntryUsingContext(cls, qualifiedName)) + return {type}; + } + } + } + + // 5.2 - Try without scope + auto types = TypeDatabase::instance()->findCppTypes(qualifiedName); + if (!types.isEmpty()) + return types; + + // 6. No? Try looking it up as a flags type + if (auto type = TypeDatabase::instance()->findFlagsType(qualifiedName)) + return {type}; + + // 7. No? Try looking it up as a container type + if (auto type = TypeDatabase::instance()->findContainerType(name)) + return {type}; + + // 8. No? Check if the current class is a template and this type is one + // of the parameters. + if (currentClass) { + const QVector<TypeEntry *> &template_args = currentClass->templateArguments(); + for (TypeEntry *te : template_args) { + if (te->name() == qualifiedName) + return {te}; + } + } + return {}; +} + +// Reverse lookup of AbstractMetaType representing a template specialization +// found during traversing function arguments to its type system typedef'ed +// class. +const AbstractMetaClass *AbstractMetaBuilderPrivate::resolveTypeSystemTypeDef(const AbstractMetaType *t) const +{ + if (t->hasInstantiations()) { + auto pred = [t](const TypeClassEntry &e) { return e.type->compare(*t); }; + auto it = std::find_if(m_typeSystemTypeDefs.cbegin(), m_typeSystemTypeDefs.cend(), pred); + if (it != m_typeSystemTypeDefs.cend()) + return it->klass; + } + return nullptr; +} + AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typei, AbstractMetaClass *currentClass, TranslateTypeFlags flags, @@ -2164,12 +2138,21 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typ return translateTypeStatic(_typei, currentClass, this, flags, errorMessage); } +static bool isNumber(const QString &s) +{ + return std::all_of(s.cbegin(), s.cend(), + [](QChar c) { return c.isDigit(); }); +} + AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo &_typei, AbstractMetaClass *currentClass, AbstractMetaBuilderPrivate *d, TranslateTypeFlags flags, QString *errorMessageIn) { + if (_typei.isVoid()) + return AbstractMetaType::createVoid(); + // 1. Test the type info without resolving typedefs in case this is present in the // type system const bool resolveType = !flags.testFlag(AbstractMetaBuilder::DontResolveType); @@ -2258,7 +2241,9 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo if (_ok) arrayType->setArrayElementCount(int(elems)); } - arrayType->setTypeEntry(new ArrayTypeEntry(elementType->typeEntry() , elementType->typeEntry()->version())); + auto elementTypeEntry = elementType->typeEntry(); + arrayType->setTypeEntry(new ArrayTypeEntry(elementTypeEntry, elementTypeEntry->version(), + elementTypeEntry->parent())); arrayType->decideUsagePattern(); elementType = arrayType; @@ -2286,47 +2271,8 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo typeInfo.clearInstantiations(); } - const TypeEntry *type = nullptr; - // 5. Try to find the type - - // 5.1 - Try first using the current scope - if (currentClass) { - type = findTypeEntryUsingContext(currentClass, qualifiedName); - - // 5.1.1 - Try using the class parents' scopes - if (!type && d && !currentClass->baseClassNames().isEmpty()) { - const AbstractMetaClassList &baseClasses = d->getBaseClasses(currentClass); - for (const AbstractMetaClass *cls : baseClasses) { - type = findTypeEntryUsingContext(cls, qualifiedName); - if (type) - break; - } - } - } - - // 5.2 - Try without scope - if (!type) - type = TypeDatabase::instance()->findType(qualifiedName); - - // 6. No? Try looking it up as a flags type - if (!type) - type = TypeDatabase::instance()->findFlagsType(qualifiedName); - - // 7. No? Try looking it up as a container type - if (!type) - type = TypeDatabase::instance()->findContainerType(name); - - // 8. No? Check if the current class is a template and this type is one - // of the parameters. - if (!type && currentClass) { - const QVector<TypeEntry *> &template_args = currentClass->templateArguments(); - for (TypeEntry *te : template_args) { - if (te->name() == qualifiedName) - type = te; - } - } - - if (!type) { + const TypeEntries types = findTypeEntries(qualifiedName, name, currentClass, d); + if (types.isEmpty()) { if (errorMessageIn) { *errorMessageIn = msgUnableToTranslateType(_typei, msgCannotFindTypeEntry(qualifiedName)); @@ -2334,11 +2280,10 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo return nullptr; } - // These are only implicit and should not appear in code... - Q_ASSERT(!type->isInterface()); + const TypeEntry *type = types.constFirst(); + const TypeEntry::Type typeEntryType = type->type(); - auto *metaType = new AbstractMetaType; - metaType->setTypeEntry(type); + QScopedPointer<AbstractMetaType> metaType(new AbstractMetaType); metaType->setIndirectionsV(typeInfo.indirectionsV()); metaType->setReferenceType(typeInfo.referenceType()); metaType->setConstant(typeInfo.isConstant()); @@ -2349,23 +2294,88 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo for (int t = 0, size = templateArguments.size(); t < size; ++t) { const TypeInfo &ti = templateArguments.at(t); AbstractMetaType *targType = translateTypeStatic(ti, currentClass, d, flags, &errorMessage); + // For non-type template parameters, create a dummy type entry on the fly + // as is done for classes. + if (!targType) { + const QString value = ti.qualifiedName().join(colonColon()); + if (isNumber(value)) { + TypeDatabase::instance()->addConstantValueTypeEntry(value, type->typeSystemTypeEntry()); + targType = translateTypeStatic(ti, currentClass, d, flags, &errorMessage); + } + } if (!targType) { if (errorMessageIn) *errorMessageIn = msgCannotTranslateTemplateArgument(t, ti, errorMessage); - delete metaType; return nullptr; } metaType->addInstantiation(targType, true); } + if (types.size() > 1) { + const bool sameType = std::all_of(types.cbegin() + 1, types.cend(), + [typeEntryType](const TypeEntry *e) { + return e->type() == typeEntryType; }); + if (!sameType) { + if (errorMessageIn) + *errorMessageIn = msgAmbiguousVaryingTypesFound(qualifiedName, types); + return nullptr; + } + // Ambiguous primitive/smart pointer types are possible (when + // including type systems). + if (typeEntryType != TypeEntry::PrimitiveType + && typeEntryType != TypeEntry::SmartPointerType) { + if (errorMessageIn) + *errorMessageIn = msgAmbiguousTypesFound(qualifiedName, types); + return nullptr; + } + } + + if (typeEntryType == TypeEntry::SmartPointerType) { + // Find a matching instantiation + if (metaType->instantiations().size() != 1) { + if (errorMessageIn) + *errorMessageIn = msgInvalidSmartPointerType(_typei); + return nullptr; + } + auto instantiationType = metaType->instantiations().constFirst()->typeEntry(); + if (instantiationType->type() == TypeEntry::TemplateArgumentType) { + // Member functions of the template itself, SharedPtr(const SharedPtr &) + type = instantiationType; + } else { + auto it = std::find_if(types.cbegin(), types.cend(), + [instantiationType](const TypeEntry *e) { + auto smartPtr = static_cast<const SmartPointerTypeEntry *>(e); + return smartPtr->matchesInstantiation(instantiationType); + }); + if (it == types.cend()) { + if (errorMessageIn) + *errorMessageIn = msgCannotFindSmartPointerInstantion(_typei); + return nullptr; + } + type =*it; + } + } + + metaType->setTypeEntry(type); + // The usage pattern *must* be decided *after* the possible template // instantiations have been determined, or else the absence of // such instantiations will break the caching scheme of // AbstractMetaType::cppSignature(). metaType->decideUsagePattern(); - return metaType; + if (d) { + // Reverse lookup of type system typedefs. Replace by class. + if (auto klass = d->resolveTypeSystemTypeDef(metaType.data())) { + metaType.reset(new AbstractMetaType); + metaType->setTypeEntry(klass->typeEntry()); + metaType->decideUsagePattern(); + } + } + + Q_ASSERT(metaType->typeUsagePattern() != AbstractMetaType::InvalidPattern); + return metaType.take(); } AbstractMetaType *AbstractMetaBuilder::translateType(const TypeInfo &_typei, @@ -2655,18 +2665,7 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, const TypeInfo &info) { QVector<TypeInfo> targs = info.instantiations(); - QVector<AbstractMetaType *> templateTypes; - QString errorMessage; - - if (subclass->isTypeDef()) { - subclass->setHasCloneOperator(templateClass->hasCloneOperator()); - subclass->setHasEqualsOperator(templateClass->hasEqualsOperator()); - subclass->setHasHashFunction(templateClass->hasHashFunction()); - subclass->setHasNonPrivateConstructor(templateClass->hasNonPrivateConstructor()); - subclass->setHasPrivateDestructor(templateClass->hasPrivateDestructor()); - subclass->setHasProtectedDestructor(templateClass->hasProtectedDestructor()); - subclass->setHasVirtualDestructor(templateClass->hasVirtualDestructor()); - } + AbstractMetaTypeList templateTypes; for (const TypeInfo &i : qAsConst(targs)) { QString typeName = i.qualifiedName().join(colonColon()); @@ -2676,15 +2675,11 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, // "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) { + if (isNumber(typeName)) { t = typeDb->findType(typeName); if (!t) { - t = new EnumValueTypeEntry(typeName, typeName, nullptr, - QVersionNumber(0, 0)); - t->setCodeGeneration(0); - typeDb->addType(t); + auto parent = subclass->typeEntry()->typeSystemTypeEntry(); + t = TypeDatabase::instance()->addConstantValueTypeEntry(typeName, parent); } } else { QStringList possibleNames; @@ -2702,8 +2697,7 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, } if (t) { - auto *temporaryType = new AbstractMetaType; - temporaryType->setTypeEntry(t); + auto *temporaryType = new AbstractMetaType(t); temporaryType->setConstant(i.isConstant()); temporaryType->setReferenceType(i.referenceType()); temporaryType->setIndirectionsV(i.indirectionsV()); @@ -2716,6 +2710,28 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, } } + subclass->setTemplateBaseClass(templateClass); + subclass->setTemplateBaseClassInstantiations(templateTypes); + subclass->setBaseClass(templateClass->baseClass()); + return true; +} + +void AbstractMetaBuilderPrivate::inheritTemplateFunctions(AbstractMetaClass *subclass) +{ + QString errorMessage; + auto templateClass = subclass->templateBaseClass(); + + if (subclass->isTypeDef()) { + subclass->setHasCloneOperator(templateClass->hasCloneOperator()); + subclass->setHasEqualsOperator(templateClass->hasEqualsOperator()); + subclass->setHasHashFunction(templateClass->hasHashFunction()); + subclass->setHasNonPrivateConstructor(templateClass->hasNonPrivateConstructor()); + subclass->setHasPrivateDestructor(templateClass->hasPrivateDestructor()); + subclass->setHasProtectedDestructor(templateClass->hasProtectedDestructor()); + subclass->setHasVirtualDestructor(templateClass->hasVirtualDestructor()); + } + + const auto &templateTypes = subclass->templateBaseClassInstantiations(); const AbstractMetaFunctionList &subclassFuncs = subclass->functions(); const AbstractMetaFunctionList &templateClassFunctions = templateClass->functions(); for (const AbstractMetaFunction *function : templateClassFunctions) { @@ -2729,7 +2745,7 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, QScopedPointer<AbstractMetaFunction> f(function->copy()); f->setArguments(AbstractMetaArgumentList()); - if (function->type()) { // Non-void + if (!function->isVoid()) { AbstractMetaType *returnType = inheritTemplateType(templateTypes, function->type()); if (!returnType) continue; @@ -2818,59 +2834,44 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, f->replaceType(fieldType); subclass->addField(f.take()); } - - subclass->setTemplateBaseClass(templateClass); - subclass->setTemplateBaseClassInstantiations(templateTypes); - subclass->setInterfaces(templateClass->interfaces()); - subclass->setBaseClass(templateClass->baseClass()); - - return true; } -void AbstractMetaBuilderPrivate::parseQ_Property(AbstractMetaClass *metaClass, - const QStringList &declarations) +void AbstractMetaBuilderPrivate::parseQ_Properties(AbstractMetaClass *metaClass, + const QStringList &declarations) { const QStringList scopes = currentScope()->qualifiedName(); - - for (int i = 0; i < declarations.size(); ++i) { - const auto propertyTokens = declarations.at(i).splitRef(QLatin1Char(' ')); - - AbstractMetaType *type = nullptr; - for (int j = scopes.size(); j >= 0; --j) { - QStringList qualifiedName = scopes.mid(0, j); - qualifiedName.append(propertyTokens.at(0).toString()); - TypeInfo info; - info.setQualifiedName(qualifiedName); - - type = translateType(info, metaClass); - if (type) - break; - } - - if (!type) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("Unable to decide type of property: '%1' in class '%2'") - .arg(propertyTokens.at(0).toString(), metaClass->name()); - continue; + QString errorMessage; + int i = 0; + for (; i < declarations.size(); ++i) { + if (auto spec = QPropertySpec::parseQ_Property(this, metaClass, declarations.at(i), scopes, &errorMessage)) { + spec->setIndex(i); + metaClass->addPropertySpec(spec); + } else { + QString message; + QTextStream str(&message); + str << metaClass->sourceLocation() << errorMessage; + qCWarning(lcShiboken, "%s", qPrintable(message)); } + } - auto *spec = new QPropertySpec(type->typeEntry()); - spec->setName(propertyTokens.at(1).toString()); - spec->setIndex(i); + // User-added properties + auto typeEntry = metaClass->typeEntry(); + for (const TypeSystemProperty &tp : typeEntry->properties()) { + QPropertySpec *spec = nullptr; + if (metaClass->propertySpecByName(tp.name)) + errorMessage = msgPropertyExists(metaClass->name(), tp.name); + else + spec = QPropertySpec::fromTypeSystemProperty(this, metaClass, tp, scopes, &errorMessage); - for (int pos = 2; pos + 1 < propertyTokens.size(); pos += 2) { - if (propertyTokens.at(pos) == QLatin1String("READ")) - spec->setRead(propertyTokens.at(pos + 1).toString()); - else if (propertyTokens.at(pos) == QLatin1String("WRITE")) - spec->setWrite(propertyTokens.at(pos + 1).toString()); - else if (propertyTokens.at(pos) == QLatin1String("DESIGNABLE")) - spec->setDesignable(propertyTokens.at(pos + 1).toString()); - else if (propertyTokens.at(pos) == QLatin1String("RESET")) - spec->setReset(propertyTokens.at(pos + 1).toString()); + if (spec) { + spec->setIndex(i++); + metaClass->addPropertySpec(spec); + } else { + QString message; + QTextStream str(&message); + str << typeEntry->sourceLocation() << errorMessage; + qCWarning(lcShiboken, "%s", qPrintable(message)); } - - metaClass->addPropertySpec(spec); - delete type; } } @@ -2899,11 +2900,9 @@ void AbstractMetaBuilderPrivate::setupClonable(AbstractMetaClass *cls) QQueue<AbstractMetaClass*> baseClasses; if (cls->baseClass()) baseClasses.enqueue(cls->baseClass()); - baseClasses << cls->interfaces().toList(); while (!baseClasses.isEmpty()) { AbstractMetaClass* currentClass = baseClasses.dequeue(); - baseClasses << currentClass->interfaces().toList(); if (currentClass->baseClass()) baseClasses.enqueue(currentClass->baseClass()); @@ -2948,7 +2947,7 @@ static void writeRejectLogFile(const QString &name, for (int reason = 0; reason < AbstractMetaBuilder::NoReason; ++reason) { - s << QString(72, QLatin1Char('*')) << endl; + s << QString(72, QLatin1Char('*')) << Qt::endl; switch (reason) { case AbstractMetaBuilder::NotInTypeSystem: s << "Not in type system"; @@ -2981,16 +2980,16 @@ static void writeRejectLogFile(const QString &name, break; } - s << endl; + 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() << endl; + s << " - " << it.key() << Qt::endl; } - s << QString(72, QLatin1Char('*')) << endl << endl; + s << QString(72, QLatin1Char('*')) << Qt::endl << Qt::endl; } } @@ -3016,6 +3015,19 @@ static ClassIndexHash::ConstIterator findByTypeEntry(const ClassIndexHash &map, return it; } +// Add a dependency of the class associated with typeEntry on clazz +static void addClassDependency(const TypeEntry *typeEntry, + const AbstractMetaClass *clazz, + int classIndex, const ClassIndexHash &map, + Graph *graph) +{ + if (typeEntry->isComplex() && typeEntry != clazz->typeEntry()) { + const auto it = findByTypeEntry(map, typeEntry); + if (it != map.cend() && it.key()->enclosingClass() != clazz) + graph->addEdge(it.value(), classIndex); + } +} + AbstractMetaClassList AbstractMetaBuilderPrivate::classesTopologicalSorted(const AbstractMetaClassList &classList, const Dependencies &additionalDependencies) const { @@ -3055,10 +3067,6 @@ AbstractMetaClassList AbstractMetaBuilderPrivate::classesTopologicalSorted(const const AbstractMetaClassList &bases = getBaseClasses(clazz); for (AbstractMetaClass *baseClass : bases) { - // Fix polymorphic expression - if (clazz->baseClass() == baseClass) - clazz->setBaseClass(baseClass); - const auto baseIt = map.constFind(baseClass); if (baseIt!= map.cend()) graph.addEdge(baseIt.value(), classIndex); @@ -3072,15 +3080,17 @@ AbstractMetaClassList AbstractMetaBuilderPrivate::classesTopologicalSorted(const // ("QString s = QString()"), add a dependency. if (!arg->originalDefaultValueExpression().isEmpty() && arg->type()->isValue()) { - auto typeEntry = arg->type()->typeEntry(); - if (typeEntry->isComplex() && typeEntry != clazz->typeEntry()) { - auto ait = findByTypeEntry(map, typeEntry); - if (ait != map.cend() && ait.key()->enclosingClass() != clazz) - graph.addEdge(ait.value(), classIndex); - } + addClassDependency(arg->type()->typeEntry(), clazz, classIndex, + map, &graph); } } } + // Member fields need to be initialized + const AbstractMetaFieldList &fields = clazz->fields(); + for (AbstractMetaField *field : fields) { + addClassDependency(field->type()->typeEntry(), clazz, classIndex, + map, &graph); + } } AbstractMetaClassList result; @@ -3099,8 +3109,7 @@ AbstractMetaClassList AbstractMetaBuilderPrivate::classesTopologicalSorted(const } else { for (int i : qAsConst(unmappedResult)) { Q_ASSERT(reverseMap.contains(i)); - if (!reverseMap[i]->isInterface()) - result << reverseMap[i]; + result << reverseMap[i]; } } @@ -3151,9 +3160,9 @@ AbstractMetaArgumentList AbstractMetaBuilderPrivate::reverseList(const AbstractM return ret; } -void AbstractMetaBuilder::setGlobalHeader(const QString& globalHeader) +void AbstractMetaBuilder::setGlobalHeaders(const QFileInfoList &globalHeaders) { - d->m_globalHeader = QFileInfo(globalHeader); + d->m_globalHeaders = globalHeaders; } void AbstractMetaBuilder::setHeaderPaths(const HeaderPaths &hp) @@ -3191,23 +3200,26 @@ static bool matchHeader(const QString &headerPath, const QString &fileName) && fileName.startsWith(headerPath, caseSensitivity); } -void AbstractMetaBuilderPrivate::setInclude(TypeEntry *te, const QString &fileName) const +void AbstractMetaBuilderPrivate::setInclude(TypeEntry *te, const QString &path) const { - auto it = m_resolveIncludeHash.find(fileName); + auto it = m_resolveIncludeHash.find(path); if (it == m_resolveIncludeHash.end()) { - QFileInfo info(fileName); - if (m_globalHeader.fileName() == info.fileName()) + QFileInfo info(path); + const QString fileName = info.fileName(); + if (std::any_of(m_globalHeaders.cbegin(), m_globalHeaders.cend(), + [fileName] (const QFileInfo &fi) { + return fi.fileName() == fileName; })) { return; + } int bestMatchLength = 0; for (const auto &headerPath : m_headerPaths) { - if (headerPath.size() > bestMatchLength && matchHeader(headerPath, fileName)) + if (headerPath.size() > bestMatchLength && matchHeader(headerPath, path)) bestMatchLength = headerPath.size(); } const QString include = bestMatchLength > 0 - ? fileName.right(fileName.size() - bestMatchLength - 1) - : info.fileName(); - it = m_resolveIncludeHash.insert(fileName, {Include::IncludePath, include}); + ? path.right(path.size() - bestMatchLength - 1) : fileName; + it = m_resolveIncludeHash.insert(path, {Include::IncludePath, include}); } te->setInclude(it.value()); } @@ -3232,7 +3244,7 @@ static void debugFormatSequence(QDebug &d, const char *key, const Container& c, void AbstractMetaBuilder::formatDebug(QDebug &debug) const { - debug << "m_globalHeader=" << d->m_globalHeader.absoluteFilePath(); + debug << "m_globalHeader=" << d->m_globalHeaders; debugFormatSequence(debug, "globalEnums", d->m_globalEnums, "\n"); debugFormatSequence(debug, "globalFunctions", d->m_globalFunctions, "\n"); if (const int scopeCount = d->m_scopes.size()) { |