diff options
Diffstat (limited to 'sources/shiboken2/ApiExtractor')
19 files changed, 455 insertions, 444 deletions
diff --git a/sources/shiboken2/ApiExtractor/CMakeLists.txt b/sources/shiboken2/ApiExtractor/CMakeLists.txt index 4c0ac7b30..147fda377 100644 --- a/sources/shiboken2/ApiExtractor/CMakeLists.txt +++ b/sources/shiboken2/ApiExtractor/CMakeLists.txt @@ -2,30 +2,8 @@ project(apiextractor) cmake_minimum_required(VERSION 3.1) cmake_policy(VERSION 3.1) -find_package(LibXml2 2.6.32) -find_package(LibXslt 1.1.19) -option(DISABLE_DOCSTRINGS "Disable documentation extraction." FALSE) - -set (USE_LIBXSLT 0) -if (NOT DISABLE_DOCSTRINGS) - if (LIBXSLT_FOUND AND LIBXML2_FOUND) - add_definitions(-DHAVE_LIBXSLT) - set (USE_LIBXSLT 1) - else() - message(WARNING "libxslt and/or libxml not found, falling back to QtXmlPatterns (QTBUG-66925)") - endif() -endif() - -if(BUILD_TESTS) - set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/tests) -endif () - -set(QT_USE_QTCORE 1) -set(QT_USE_QTXML 1) -add_definitions(-DQT_PLUGIN) -add_definitions(-DQT_SHARED) -add_definitions(-DRXX_ALLOCATOR_INIT_0) +set(CMAKE_AUTOMOC ON) set(apiextractor_SRC apiextractor.cpp @@ -50,45 +28,37 @@ parser/codemodel.cpp parser/enumvalue.cpp ) -set(APIEXTRACTOR_EXTRA_INCLUDES ${CLANG_EXTRA_INCLUDES}) -set(APIEXTRACTOR_EXTRA_LIBRARIES ${CLANG_EXTRA_LIBRARIES}) +add_library(apiextractor STATIC ${apiextractor_SRC}) +target_include_directories(apiextractor PRIVATE ${CLANG_EXTRA_INCLUDES} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/parser + ${CMAKE_CURRENT_SOURCE_DIR}/parser/rpp) +target_link_libraries(apiextractor PUBLIC Qt5::Core) +target_link_libraries(apiextractor PRIVATE ${CLANG_EXTRA_LIBRARIES}) if (NOT DISABLE_DOCSTRINGS) - set(apiextractor_SRC - ${apiextractor_SRC} - docparser.cpp - doxygenparser.cpp - qtdocparser.cpp - ) - set(APIEXTRACTOR_EXTRA_INCLUDES ${APIEXTRACTOR_EXTRA_INCLUDES}) - set(APIEXTRACTOR_EXTRA_LIBRARIES ${APIEXTRACTOR_EXTRA_LIBRARIES}) - if (USE_LIBXSLT) - list(APPEND APIEXTRACTOR_EXTRA_INCLUDES ${LIBXSLT_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR}) - list(APPEND APIEXTRACTOR_EXTRA_LIBRARIES ${LIBXSLT_LIBRARIES} ${LIBXML2_LIBRARIES}) + target_sources(apiextractor PRIVATE docparser.cpp + doxygenparser.cpp + qtdocparser.cpp) + target_link_libraries(apiextractor PUBLIC Qt5::Xml Qt5::XmlPatterns) + + if (LIBXSLT_FOUND AND LIBXML2_FOUND) + target_compile_definitions(apiextractor PUBLIC HAVE_LIBXSLT) + target_include_directories(apiextractor + PRIVATE ${LIBXSLT_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR}) + target_link_libraries(apiextractor + PRIVATE ${LIBXSLT_LIBRARIES} ${LIBXML2_LIBRARIES}) + else() + message(WARNING + "libxslt and/or libxml not found, falling back to QtXmlPatterns (QTBUG-66925)") endif() endif() set(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})" FORCE) -set(CMAKE_AUTOMOC ON) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/parser - ${CMAKE_CURRENT_SOURCE_DIR}/parser/rpp - ${APIEXTRACTOR_EXTRA_INCLUDES} - ${Qt5Core_INCLUDE_DIRS} - ${Qt5Xml_INCLUDE_DIRS} - ) - -add_library(apiextractor STATIC ${apiextractor_SRC} ${apiextractor_RCCS_SRC}) -target_link_libraries(apiextractor - ${Qt5Xml_LIBRARIES} - ${Qt5XmlPatterns_LIBRARIES} - ${APIEXTRACTOR_EXTRA_LIBRARIES} - ) - if (BUILD_TESTS) + set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/tests) enable_testing() add_subdirectory(tests) endif() diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index e62a2a78a..6e95e79e7 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -111,7 +111,7 @@ static QStringList parseTemplateType(const QString& name) { return result; } -AbstractMetaBuilderPrivate::AbstractMetaBuilderPrivate() : m_currentClass(0), +AbstractMetaBuilderPrivate::AbstractMetaBuilderPrivate() : m_logDirectory(QLatin1String(".") + QDir::separator()), m_skipDeprecated(false) { @@ -192,7 +192,7 @@ void AbstractMetaBuilderPrivate::checkFunctionModifications() QString name = signature.trimmed(); name.truncate(name.indexOf(QLatin1Char('('))); - AbstractMetaClass *clazz = AbstractMetaClass::findClass(m_metaClasses, centry->qualifiedCppName()); + AbstractMetaClass *clazz = AbstractMetaClass::findClass(m_metaClasses, centry); if (!clazz) continue; @@ -223,13 +223,14 @@ void AbstractMetaBuilderPrivate::checkFunctionModifications() } } -AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(const ArgumentModelItem &argument) +AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(const ArgumentModelItem &argument, + AbstractMetaClass *currentClass) { AbstractMetaClass* returned = 0; - AbstractMetaType *type = translateType(argument->type()); + AbstractMetaType *type = translateType(argument->type(), currentClass); if (type && type->typeEntry() && type->typeEntry()->isComplex()) { const TypeEntry *entry = type->typeEntry(); - returned = AbstractMetaClass::findClass(m_metaClasses, entry->name()); + returned = AbstractMetaClass::findClass(m_metaClasses, entry); } delete type; return returned; @@ -238,11 +239,12 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(const ArgumentMod /** * Checks the argument of a hash function and flags the type if it is a complex type */ -void AbstractMetaBuilderPrivate::registerHashFunction(const FunctionModelItem &function_item) +void AbstractMetaBuilderPrivate::registerHashFunction(const FunctionModelItem &function_item, + AbstractMetaClass *currentClass) { ArgumentList arguments = function_item->arguments(); if (arguments.size() == 1) { - if (AbstractMetaClass *cls = argumentToClass(arguments.at(0))) + if (AbstractMetaClass *cls = argumentToClass(arguments.at(0), currentClass)) cls->setHasHashFunction(true); } } @@ -251,13 +253,14 @@ void AbstractMetaBuilderPrivate::registerHashFunction(const FunctionModelItem &f * Check if a class has a debug stream operator that can be used as toString */ -void AbstractMetaBuilderPrivate::registerToStringCapability(const FunctionModelItem &function_item) +void AbstractMetaBuilderPrivate::registerToStringCapability(const FunctionModelItem &function_item, + AbstractMetaClass *currentClass) { ArgumentList arguments = function_item->arguments(); if (arguments.size() == 2) { if (arguments.at(0)->type().toString() == QLatin1String("QDebug")) { const ArgumentModelItem &arg = arguments.at(1); - if (AbstractMetaClass *cls = argumentToClass(arg)) { + if (AbstractMetaClass *cls = argumentToClass(arg, currentClass)) { if (arg->type().indirections() < 2) cls->setToStringCapability(true); } @@ -265,28 +268,28 @@ void AbstractMetaBuilderPrivate::registerToStringCapability(const FunctionModelI } } -void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelItem &item) +void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelItem &item, + AbstractMetaClass *currentClass) { if (item->accessPolicy() != CodeModel::Public) return; ArgumentList arguments = item->arguments(); - AbstractMetaClass* baseoperandClass; bool firstArgumentIsSelf = true; bool unaryOperator = false; - baseoperandClass = argumentToClass(arguments.at(0)); + auto baseoperandClass = argumentToClass(arguments.at(0), currentClass); if (arguments.size() == 1) { unaryOperator = true; } else if (!baseoperandClass || !(baseoperandClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang)) { - baseoperandClass = argumentToClass(arguments.at(1)); + baseoperandClass = argumentToClass(arguments.at(1), currentClass); firstArgumentIsSelf = false; } else { - AbstractMetaType *type = translateType(item->type()); + AbstractMetaType *type = translateType(item->type(), currentClass); const TypeEntry *retType = type ? type->typeEntry() : nullptr; - AbstractMetaClass* otherArgClass = argumentToClass(arguments.at(1)); + AbstractMetaClass *otherArgClass = argumentToClass(arguments.at(1), currentClass); if (otherArgClass && retType && (retType->isValue() || retType->isObject()) && retType != baseoperandClass->typeEntry() @@ -298,9 +301,7 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelIte } if (baseoperandClass) { - AbstractMetaClass* oldCurrentClass = m_currentClass; - m_currentClass = baseoperandClass; - AbstractMetaFunction *metaFunction = traverseFunction(item); + AbstractMetaFunction *metaFunction = traverseFunction(item, baseoperandClass); if (metaFunction) { // Strip away first argument, since that is the containing object AbstractMetaArgumentList arguments = metaFunction->arguments(); @@ -333,22 +334,19 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelIte } else { delete metaFunction; } - - m_currentClass = oldCurrentClass; } } -void AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem &item) +void AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem &item, + AbstractMetaClass *currentClass) { ArgumentList arguments = item->arguments(); if (arguments.size() == 2 && item->accessPolicy() == CodeModel::Public) { - AbstractMetaClass* streamClass = argumentToClass(arguments.at(0)); - AbstractMetaClass* streamedClass = argumentToClass(arguments.at(1)); + AbstractMetaClass *streamClass = argumentToClass(arguments.at(0), currentClass); + AbstractMetaClass *streamedClass = argumentToClass(arguments.at(1), currentClass); if (streamClass && streamedClass && (streamClass->isStream())) { - AbstractMetaClass *oldCurrentClass = m_currentClass; - m_currentClass = streamedClass; - AbstractMetaFunction *streamFunction = traverseFunction(item); + AbstractMetaFunction *streamFunction = traverseFunction(item, streamedClass); if (streamFunction) { streamFunction->setFunctionType(AbstractMetaFunction::GlobalScopeFunction); @@ -385,7 +383,6 @@ void AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem else funcClass->typeEntry()->addExtraInclude(streamClass->typeEntry()->include()); - m_currentClass = oldCurrentClass; } else { delete streamFunction; } @@ -394,27 +391,6 @@ void AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem } } -void AbstractMetaBuilderPrivate::fixQObjectForScope(const FileModelItem &dom, - const TypeDatabase *types, - const NamespaceModelItem &scope) -{ - const ClassList &scopeClasses = scope->classes(); - for (const ClassModelItem &item : scopeClasses) { - QString qualifiedName = item->qualifiedName().join(colonColon()); - TypeEntry* entry = types->findType(qualifiedName); - if (entry) { - if (isQObject(dom, qualifiedName) && entry->isComplex()) - static_cast<ComplexTypeEntry *>(entry)->setQObject(true); - } - } - - const NamespaceList &namespaces = scope->namespaces(); - for (const NamespaceModelItem &n : namespaces) { - if (scope != n) - fixQObjectForScope(dom, types, n); - } -} - void AbstractMetaBuilderPrivate::sortLists() { for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) @@ -450,17 +426,14 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) pushScope(dom); - // fix up QObject's in the type system.. - fixQObjectForScope(dom, types, dom); - // Start the generation... const ClassList &typeValues = dom->classes(); ReportHandler::setProgressReference(typeValues); for (const ClassModelItem &item : typeValues) { ReportHandler::progress(QStringLiteral("Generating class model (%1)...") .arg(typeValues.size())); - if (AbstractMetaClass *cls = traverseClass(dom, item)) - addAbstractMetaClass(cls); + if (AbstractMetaClass *cls = traverseClass(dom, item, nullptr)) + addAbstractMetaClass(cls, item.data()); } // We need to know all global enums @@ -481,9 +454,8 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) for (const NamespaceModelItem &item : namespaceTypeValues) { ReportHandler::progress(QStringLiteral("Generating namespace model (%1)...") .arg(namespaceTypeValues.size())); - AbstractMetaClass *metaClass = traverseNamespace(dom, item); - if (metaClass) - m_metaClasses << metaClass; + if (AbstractMetaClass *metaClass = traverseNamespace(dom, item)) + addAbstractMetaClass(metaClass, item.data()); } // Go through all typedefs to see if we have defined any @@ -493,8 +465,8 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) for (const TypeDefModelItem &typeDef : typeDefs) { ReportHandler::progress(QStringLiteral("Resolving typedefs (%1)...") .arg(typeDefs.size())); - if (AbstractMetaClass *cls = traverseTypeDef(dom, typeDef)) - addAbstractMetaClass(cls); + if (AbstractMetaClass *cls = traverseTypeDef(dom, typeDef, nullptr)) + addAbstractMetaClass(cls, typeDef.data()); } traverseTypesystemTypedefs(); @@ -515,7 +487,7 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) if (!funcEntry || !funcEntry->generateCode()) continue; - AbstractMetaFunction* metaFunc = traverseFunction(func); + AbstractMetaFunction* metaFunc = traverseFunction(func, nullptr); if (!metaFunc) continue; @@ -579,7 +551,7 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) && !entry->isCustom() && !entry->isVariant() && (entry->generateCode() & TypeEntry::GenerateTargetLang) - && !AbstractMetaClass::findClass(m_metaClasses, entry->qualifiedCppName())) { + && !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()); @@ -622,13 +594,13 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) { const FunctionList &hashFunctions = dom->findFunctions(QLatin1String("qHash")); for (const FunctionModelItem &item : hashFunctions) - registerHashFunction(item); + registerHashFunction(item, nullptr); } { const FunctionList &streamOps = dom->findFunctions(QLatin1String("operator<<")); for (const FunctionModelItem &item : streamOps) - registerToStringCapability(item); + registerToStringCapability(item, nullptr); } { @@ -656,14 +628,14 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) binaryOperators.append(dom->findFunctions(QStringLiteral("operator>"))); for (const FunctionModelItem &item : qAsConst(binaryOperators)) - traverseOperatorFunction(item); + traverseOperatorFunction(item, nullptr); } { const FunctionList streamOperators = dom->findFunctions(QLatin1String("operator<<")) + dom->findFunctions(QLatin1String("operator>>")); for (const FunctionModelItem &item : streamOperators) - traverseStreamOperator(item); + traverseStreamOperator(item, nullptr); } checkFunctionModifications(); @@ -688,21 +660,19 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) sortLists(); - m_currentClass = 0; - // Functions added to the module on the type system. const AddedFunctionList &globalUserFunctions = types->globalUserFunctions(); - for (const AddedFunction &addedFunc : globalUserFunctions) { + for (const AddedFunctionPtr &addedFunc : globalUserFunctions) { AbstractMetaFunction* metaFunc = traverseFunction(addedFunc); if (Q_UNLIKELY(!metaFunc)) { qFatal("Unable to traverse added global function \"%s\".", - qPrintable(addedFunc.name())); + qPrintable(addedFunc->name())); } metaFunc->setFunctionType(AbstractMetaFunction::NormalFunction); m_globalFunctions << metaFunc; } - std::puts(""); + m_itemToClass.clear(); } static bool metaEnumLessThan(const AbstractMetaEnum *e1, const AbstractMetaEnum *e2) @@ -742,9 +712,11 @@ void AbstractMetaBuilder::setLogDirectory(const QString& logDir) d->m_logDirectory.append(QDir::separator()); } -void AbstractMetaBuilderPrivate::addAbstractMetaClass(AbstractMetaClass *cls) +void AbstractMetaBuilderPrivate::addAbstractMetaClass(AbstractMetaClass *cls, + const _CodeModelItem *item) { cls->setOriginalAttributes(cls->attributes()); + m_itemToClass.insert(item, cls); if (cls->typeEntry()->isContainer()) { m_templates << cls; } else if (cls->typeEntry()->isSmartPointer()) { @@ -763,9 +735,10 @@ void AbstractMetaBuilderPrivate::addAbstractMetaClass(AbstractMetaClass *cls) AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModelItem &dom, const NamespaceModelItem &namespaceItem) { - QString namespaceName = - (!m_namespacePrefix.isEmpty() ? m_namespacePrefix + colonColon() : QString()) - + namespaceItem->name(); + QString namespaceName = currentScope()->qualifiedName().join(colonColon()); + if (!namespaceName.isEmpty()) + namespaceName.append(colonColon()); + namespaceName.append(namespaceItem->name()); NamespaceTypeEntry *type = TypeDatabase::instance()->findNamespaceType(namespaceName); if (TypeDatabase::instance()->isClassRejected(namespaceName)) { @@ -784,8 +757,6 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModel *metaClass += AbstractMetaAttributes::Public; - m_currentClass = metaClass; - if (ReportHandler::isDebug(ReportHandler::SparseDebug)) { qCDebug(lcShiboken) << QStringLiteral("namespace '%1.%2'").arg(metaClass->package(), namespaceItem->name()); @@ -794,15 +765,14 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModel traverseEnums(namespaceItem, metaClass, namespaceItem->enumsDeclarations()); pushScope(namespaceItem); - m_namespacePrefix = currentScope()->qualifiedName().join(colonColon()); const ClassList &classes = namespaceItem->classes(); for (const ClassModelItem &cls : classes) { - AbstractMetaClass* mjc = traverseClass(dom, cls); + AbstractMetaClass* mjc = traverseClass(dom, cls, metaClass); if (mjc) { metaClass->addInnerClass(mjc); mjc->setEnclosingClass(metaClass); - addAbstractMetaClass(mjc); + addAbstractMetaClass(mjc, cls.data()); } } @@ -810,11 +780,11 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModel // specific typedefs to be used as classes. const TypeDefList typeDefs = namespaceItem->typeDefs(); for (const TypeDefModelItem &typeDef : typeDefs) { - AbstractMetaClass *cls = traverseTypeDef(dom, typeDef); + AbstractMetaClass *cls = traverseTypeDef(dom, typeDef, metaClass); if (cls) { metaClass->addInnerClass(cls); cls->setEnclosingClass(metaClass); - addAbstractMetaClass(cls); + addAbstractMetaClass(cls, typeDef.data()); } } @@ -824,14 +794,11 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModel if (mjc) { metaClass->addInnerClass(mjc); mjc->setEnclosingClass(metaClass); - addAbstractMetaClass(mjc); + addAbstractMetaClass(mjc, ni.data()); } } - m_currentClass = 0; - popScope(); - m_namespacePrefix = currentScope()->qualifiedName().join(colonColon()); if (!type->include().isValid()) setInclude(type, namespaceItem->fileName()); @@ -872,8 +839,8 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem & QString enumName = enumItem->name(); QString className; - if (m_currentClass) - className = m_currentClass->typeEntry()->qualifiedCppName(); + if (enclosing) + className = enclosing->typeEntry()->qualifiedCppName(); QString rejectReason; if (TypeDatabase::instance()->isEnumRejected(className, enumName, &rejectReason)) { @@ -883,8 +850,8 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem & return 0; } - const bool rejectionWarning = !m_currentClass - || (m_currentClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang); + const bool rejectionWarning = !enclosing + || (enclosing->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang); if (!typeEntry) { if (rejectionWarning) @@ -983,15 +950,16 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem & } AbstractMetaClass* AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelItem &dom, - const TypeDefModelItem &typeDef) + const TypeDefModelItem &typeDef, + AbstractMetaClass *currentClass) { TypeDatabase* types = TypeDatabase::instance(); QString className = stripTemplateArgs(typeDef->name()); QString fullClassName = className; // we have an inner class - if (m_currentClass) { - fullClassName = stripTemplateArgs(m_currentClass->typeEntry()->qualifiedCppName()) + if (currentClass) { + fullClassName = stripTemplateArgs(currentClass->typeEntry()->qualifiedCppName()) + colonColon() + fullClassName; } @@ -1011,9 +979,6 @@ AbstractMetaClass* AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelIt if (!type) return 0; - if (type->isObject()) - static_cast<ObjectTypeEntry *>(type)->setQObject(isQObject(dom, stripTemplateArgs(typeDef->type().qualifiedName().join(colonColon())))); - AbstractMetaClass *metaClass = new AbstractMetaClass; metaClass->setTypeDef(true); metaClass->setTypeEntry(type); @@ -1041,19 +1006,20 @@ void AbstractMetaBuilderPrivate::traverseTypesystemTypedefs() metaClass->setBaseClassNames(QStringList(te->sourceType())); *metaClass += AbstractMetaAttributes::Public; fillAddedFunctions(metaClass); - addAbstractMetaClass(metaClass); + addAbstractMetaClass(metaClass, nullptr); } } AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem &dom, - const ClassModelItem &classItem) + const ClassModelItem &classItem, + AbstractMetaClass *currentClass) { QString className = stripTemplateArgs(classItem->name()); QString fullClassName = className; // we have inner an class - if (m_currentClass) { - fullClassName = stripTemplateArgs(m_currentClass->typeEntry()->qualifiedCppName()) + if (currentClass) { + fullClassName = stripTemplateArgs(currentClass->typeEntry()->qualifiedCppName()) + colonColon() + fullClassName; } @@ -1076,9 +1042,6 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem return 0; } - if (type->isObject()) - ((ObjectTypeEntry*)type)->setQObject(isQObject(dom, fullClassName)); - AbstractMetaClass *metaClass = new AbstractMetaClass; metaClass->setTypeEntry(type); @@ -1097,9 +1060,6 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem if (type->stream()) metaClass->setStream(true); - AbstractMetaClass* oldCurrentClass = m_currentClass; - m_currentClass = metaClass; - if (ReportHandler::isDebug(ReportHandler::SparseDebug)) { const QString message = type->isContainer() ? QStringLiteral("container: '%1'").arg(fullClassName) @@ -1126,11 +1086,11 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem { const ClassList &innerClasses = classItem->classes(); for (const ClassModelItem &ci : innerClasses) { - AbstractMetaClass *cl = traverseClass(dom, ci); + AbstractMetaClass *cl = traverseClass(dom, ci, metaClass); if (cl) { cl->setEnclosingClass(metaClass); metaClass->addInnerClass(cl); - m_metaClasses << cl; + addAbstractMetaClass(cl, ci.data()); } } @@ -1140,16 +1100,13 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem // specific typedefs to be used as classes. const TypeDefList typeDefs = classItem->typeDefs(); for (const TypeDefModelItem &typeDef : typeDefs) { - AbstractMetaClass *cls = traverseTypeDef(dom, typeDef); + AbstractMetaClass *cls = traverseTypeDef(dom, typeDef, metaClass); if (cls) { cls->setEnclosingClass(metaClass); - addAbstractMetaClass(cls); + addAbstractMetaClass(cls, typeDef.data()); } } - - m_currentClass = oldCurrentClass; - // Set the default include file name if (!type->include().isValid()) setInclude(type, classItem->fileName()); @@ -1170,48 +1127,22 @@ void AbstractMetaBuilderPrivate::traverseScopeMembers(ScopeModelItem item, traverseClassMembers(ci); } -AbstractMetaClass* AbstractMetaBuilderPrivate::currentTraversedClass(ScopeModelItem item) -{ - QString className = stripTemplateArgs(item->name()); - QString fullClassName = className; - - // This is an inner class - if (m_currentClass) - fullClassName = stripTemplateArgs(m_currentClass->typeEntry()->qualifiedCppName()) + colonColon() + fullClassName; - - AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_metaClasses, fullClassName); - if (!metaClass) - metaClass = AbstractMetaClass::findClass(m_templates, fullClassName); - - if (!metaClass) - metaClass = AbstractMetaClass::findClass(m_smartPointers, fullClassName); - return metaClass; -} - void AbstractMetaBuilderPrivate::traverseClassMembers(ClassModelItem item) { - AbstractMetaClass* metaClass = currentTraversedClass(item); + AbstractMetaClass* metaClass = m_itemToClass.value(item.data()); if (!metaClass) return; - AbstractMetaClass* oldCurrentClass = m_currentClass; - m_currentClass = metaClass; - // Class members traverseScopeMembers(item, metaClass); - - m_currentClass = oldCurrentClass; } void AbstractMetaBuilderPrivate::traverseNamespaceMembers(NamespaceModelItem item) { - AbstractMetaClass* metaClass = currentTraversedClass(item); + AbstractMetaClass* metaClass = m_itemToClass.value(item.data()); if (!metaClass) return; - AbstractMetaClass* oldCurrentClass = m_currentClass; - m_currentClass = metaClass; - // Namespace members traverseScopeMembers(item, metaClass); @@ -1219,7 +1150,6 @@ void AbstractMetaBuilderPrivate::traverseNamespaceMembers(NamespaceModelItem ite for (const NamespaceModelItem &ni : item->namespaces()) traverseNamespaceMembers(ni); - m_currentClass = oldCurrentClass; } static inline QString fieldSignatureWithType(const VariableModelItem &field) @@ -1234,10 +1164,10 @@ static inline QString qualifiedFieldSignatureWithType(const QString &className, } AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(const VariableModelItem &field, - const AbstractMetaClass *cls) + AbstractMetaClass *cls) { QString fieldName = field->name(); - QString className = m_currentClass->typeEntry()->qualifiedCppName(); + QString className = cls->typeEntry()->qualifiedCppName(); // Ignore friend decl. if (field->isFriend()) @@ -1259,14 +1189,14 @@ AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(const VariableModel metaField->setEnclosingClass(cls); TypeInfo fieldType = field->type(); - AbstractMetaType *metaType = translateType(fieldType); + AbstractMetaType *metaType = translateType(fieldType, cls); if (!metaType) { const QString type = TypeInfo::resolveType(fieldType, currentScope()).qualifiedName().join(colonColon()); - if (m_currentClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang) { + if (cls->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang) { qCWarning(lcShiboken).noquote().nospace() << QStringLiteral("skipping field '%1::%2' with unmatched type '%3'") - .arg(m_currentClass->name(), fieldName, type); + .arg(cls->name(), fieldName, type); } delete metaField; return 0; @@ -1369,14 +1299,15 @@ static bool _compareAbstractMetaFunctions(const AbstractMetaFunction* func, cons } AbstractMetaFunctionList AbstractMetaBuilderPrivate::classFunctionList(const ScopeModelItem &scopeItem, - AbstractMetaClass::Attributes *constructorAttributes) + AbstractMetaClass::Attributes *constructorAttributes, + AbstractMetaClass *currentClass) { *constructorAttributes = 0; AbstractMetaFunctionList result; const FunctionList &scopeFunctionList = scopeItem->functions(); result.reserve(scopeFunctionList.size()); for (const FunctionModelItem &function : scopeFunctionList) { - if (AbstractMetaFunction *metaFunction = traverseFunction(function)) { + if (AbstractMetaFunction *metaFunction = traverseFunction(function, currentClass)) { result.append(metaFunction); } else if (function->functionType() == CodeModel::Constructor) { auto arguments = function->arguments(); @@ -1416,7 +1347,7 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, { AbstractMetaAttributes::Attributes constructorAttributes; const AbstractMetaFunctionList functions = - classFunctionList(scopeItem, &constructorAttributes); + classFunctionList(scopeItem, &constructorAttributes, metaClass); metaClass->setAttributes(metaClass->attributes() | constructorAttributes); for (AbstractMetaFunction *metaFunction : functions){ @@ -1477,12 +1408,6 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, .arg(metaFunction->name(), metaClass->name()); } - if (metaFunction->isSignal() && !metaClass->isQObject()) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("signal '%1' in non-QObject class '%2'") - .arg(metaFunction->name(), metaClass->name()); - } - if (metaFunction->isConversionOperator()) fixReturnTypeOfConversionOperator(metaFunction); @@ -1506,10 +1431,10 @@ void AbstractMetaBuilderPrivate::fillAddedFunctions(AbstractMetaClass *metaClass { // Add the functions added by the typesystem const AddedFunctionList &addedFunctions = metaClass->typeEntry()->addedFunctions(); - for (const AddedFunction &addedFunc : addedFunctions) { + for (const AddedFunctionPtr &addedFunc : addedFunctions) { if (!traverseFunction(addedFunc, metaClass)) { qFatal("Unable to traverse function \"%s\" added to \"%s\".", - qPrintable(addedFunc.name()), qPrintable(metaClass->name())); + qPrintable(addedFunc->name()), qPrintable(metaClass->name())); } } } @@ -1663,29 +1588,19 @@ void AbstractMetaBuilderPrivate::traverseEnums(const ScopeModelItem &scopeItem, } } -AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFunction& addedFunc) +AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFunctionPtr &addedFunc) { return traverseFunction(addedFunc, 0); } -AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFunction& addedFunc, +AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFunctionPtr &addedFunc, AbstractMetaClass *metaClass) { - AbstractMetaFunction *metaFunction = new AbstractMetaFunction; - metaFunction->setConstant(addedFunc.isConstant()); - metaFunction->setName(addedFunc.name()); - metaFunction->setOriginalName(addedFunc.name()); - AbstractMetaClass::Attributes visibility = - addedFunc.access() == AddedFunction::Public - ? AbstractMetaAttributes::Public : AbstractMetaAttributes::Protected; - metaFunction->setVisibility(visibility); - metaFunction->setUserAdded(true); - AbstractMetaAttributes::Attribute isStatic = addedFunc.isStatic() ? AbstractMetaFunction::Static : AbstractMetaFunction::None; - metaFunction->setAttributes(metaFunction->attributes() | AbstractMetaAttributes::FinalInTargetLang | isStatic); - metaFunction->setType(translateType(addedFunc.returnType())); - - - QVector<AddedFunction::TypeInfo> args = addedFunc.arguments(); + AbstractMetaFunction *metaFunction = new AbstractMetaFunction(addedFunc); + metaFunction->setType(translateType(addedFunc->returnType())); + + + QVector<AddedFunction::TypeInfo> args = addedFunc->arguments(); AbstractMetaArgumentList metaArguments; for (int i = 0; i < args.count(); ++i) { @@ -1695,7 +1610,7 @@ AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFu 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())); + qPrintable(typeInfo.name), i + 1, qPrintable(addedFunc->name())); delete metaFunction; return nullptr; } @@ -1734,11 +1649,11 @@ AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFu //use relace-default-expression for set default value QString replacedExpression; - if (m_currentClass) - replacedExpression = metaFunction->replacedDefaultExpression(m_currentClass, i + 1); + if (metaClass) + replacedExpression = metaFunction->replacedDefaultExpression(metaClass, i + 1); if (!replacedExpression.isEmpty()) { - if (!metaFunction->removedDefaultExpression(m_currentClass, i + 1)) { + if (!metaFunction->removedDefaultExpression(metaClass, i + 1)) { metaArg->setDefaultValueExpression(replacedExpression); metaArg->setOriginalDefaultValueExpression(replacedExpression); } @@ -1747,7 +1662,7 @@ AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFu metaFunction->setOriginalAttributes(metaFunction->attributes()); if (!metaArguments.isEmpty()) - fixArgumentNames(metaFunction, metaFunction->modifications(m_currentClass)); + fixArgumentNames(metaFunction, metaFunction->modifications(metaClass)); if (metaClass) { const AbstractMetaArgumentList fargs = metaFunction->arguments(); @@ -1864,20 +1779,21 @@ static bool applyArrayArgumentModifications(const FunctionModificationList &func return true; } -AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const FunctionModelItem &functionItem) +AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const FunctionModelItem &functionItem, + AbstractMetaClass *currentClass) { if (functionItem->isDeleted() || !functionItem->templateParameters().isEmpty()) return nullptr; QString functionName = functionItem->name(); QString className; - if (m_currentClass) { + if (currentClass) { // Clang: Skip qt_metacast(), qt_metacall(), expanded from Q_OBJECT // and overridden metaObject(), QGADGET helpers if (functionName == QLatin1String("qt_check_for_QGADGET_macro") || functionName.startsWith(QLatin1String("qt_meta"))) { return nullptr; } - className = m_currentClass->typeEntry()->qualifiedCppName(); + className = currentClass->typeEntry()->qualifiedCppName(); if (functionName == QLatin1String("metaObject") && className != QLatin1String("QObject")) return nullptr; } @@ -1960,7 +1876,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio break; case AbstractMetaFunction::ConstructorFunction: metaFunction->setExplicit(functionItem->isExplicit()); - metaFunction->setName(m_currentClass->name()); + metaFunction->setName(currentClass->name()); break; default: { TypeInfo returnType = functionItem->type(); @@ -1973,7 +1889,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio AbstractMetaType *type = nullptr; if (!returnType.isVoid()) { - type = translateType(returnType, true, &errorMessage); + type = translateType(returnType, currentClass, true, &errorMessage); if (!type) { const QString reason = msgUnmatchedReturnType(functionItem, errorMessage); qCWarning(lcShiboken, "%s", @@ -2009,12 +1925,12 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio return nullptr; } - AbstractMetaType *metaType = translateType(arg->type(), true, &errorMessage); + AbstractMetaType *metaType = translateType(arg->type(), currentClass, true, &errorMessage); if (!metaType) { // If an invalid argument has a default value, simply remove it if (arg->defaultValue()) { - if (!m_currentClass - || (m_currentClass->typeEntry()->codeGeneration() + if (!currentClass + || (currentClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang)) { qCWarning(lcShiboken).noquote().nospace() << "Stripping argument #" << (i + 1) << " of " @@ -2046,7 +1962,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio metaFunction->setArguments(metaArguments); - const FunctionModificationList functionMods = metaFunction->modifications(m_currentClass); + const FunctionModificationList functionMods = metaFunction->modifications(currentClass); for (const FunctionModification &mod : functionMods) { if (mod.exceptionHandling() != TypeSystem::ExceptionHandling::Unspecified) @@ -2062,8 +1978,8 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio //use relace-default-expression for set default value QString replacedExpression; - if (m_currentClass) { - replacedExpression = metaFunction->replacedDefaultExpression(m_currentClass, i + 1); + if (currentClass) { + replacedExpression = metaFunction->replacedDefaultExpression(currentClass, i + 1); } else { if (!functionMods.isEmpty()) { QVector<ArgumentModification> argMods = functionMods.constFirst().argument_mods; @@ -2075,10 +1991,10 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio bool hasDefaultValue = false; if (arg->defaultValue() || !replacedExpression.isEmpty()) { QString expr = arg->defaultValueExpression(); - expr = fixDefaultValue(arg, metaArg->type(), metaFunction, m_currentClass, i); + expr = fixDefaultValue(arg, metaArg->type(), metaFunction, currentClass, i); metaArg->setOriginalDefaultValueExpression(expr); - if (metaFunction->removedDefaultExpression(m_currentClass, i + 1)) { + if (metaFunction->removedDefaultExpression(currentClass, i + 1)) { expr.clear(); } else if (!replacedExpression.isEmpty()) { expr = replacedExpression; @@ -2092,7 +2008,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio && !metaArg->hasName() && !metaFunction->isOperatorOverload() && !metaFunction->isSignal() - && metaFunction->argumentName(i+1, false, m_currentClass).isEmpty()) { + && metaFunction->argumentName(i + 1, false, currentClass).isEmpty()) { qCWarning(lcShiboken).noquote().nospace() << QStringLiteral("Argument %1 on function '%2::%3' has default expression but does not have name.") .arg(i+1).arg(className, metaFunction->minimalSignature()); @@ -2110,9 +2026,9 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio } // Determine class special functions - if (m_currentClass && metaFunction->arguments().size() == 1) { + if (currentClass && metaFunction->arguments().size() == 1) { const AbstractMetaType *argType = metaFunction->arguments().constFirst()->type(); - if (argType->typeEntry() == m_currentClass->typeEntry() && argType->indirections() == 0) { + if (argType->typeEntry() == currentClass->typeEntry() && argType->indirections() == 0) { if (metaFunction->name() == QLatin1String("operator=")) { switch (argType->referenceType()) { case NoReference: @@ -2212,10 +2128,11 @@ static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaC } AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typei, + AbstractMetaClass *currentClass, bool resolveType, QString *errorMessage) { - return translateTypeStatic(_typei, m_currentClass, this, resolveType, errorMessage); + return translateTypeStatic(_typei, currentClass, this, resolveType, errorMessage); } AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo &_typei, @@ -2575,38 +2492,6 @@ QString AbstractMetaBuilderPrivate::fixDefaultValue(const ArgumentModelItem &ite return expr; } -bool AbstractMetaBuilderPrivate::isQObject(const FileModelItem &dom, const QString &qualifiedName) -{ - if (qualifiedName == QLatin1String("QObject")) - return true; - - ClassModelItem classItem = dom->findClass(qualifiedName); - - if (!classItem) { - QStringList names = qualifiedName.split(colonColon()); - NamespaceModelItem ns = dom; - for (int i = 0; i < names.size() - 1 && ns; ++i) - ns = ns->findNamespace(names.at(i)); - if (ns && names.size() >= 2) - classItem = ns->findClass(names.at(names.size() - 1)); - } - - if (!classItem) - return false; - - if (classItem->extendsClass(QLatin1String("QObject"))) - return true; - - const QVector<_ClassModelItem::BaseClass> &baseClasses = classItem->baseClasses(); - for (const _ClassModelItem::BaseClass &baseClass : baseClasses) { - if (isQObject(dom, baseClass.name)) - return true; - } - - return false; -} - - bool AbstractMetaBuilderPrivate::isEnum(const FileModelItem &dom, const QStringList& qualified_name) { CodeModelItem item = dom->model()->findItem(qualified_name, dom); @@ -2910,21 +2795,19 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, void AbstractMetaBuilderPrivate::parseQ_Property(AbstractMetaClass *metaClass, const QStringList &declarations) { - for (int i = 0; i < declarations.size(); ++i) { - const QString &p = declarations.at(i); - - QStringList l = p.split(QLatin1Char(' ')); + const QStringList scopes = currentScope()->qualifiedName(); + for (int i = 0; i < declarations.size(); ++i) { + const auto propertyTokens = declarations.at(i).splitRef(QLatin1Char(' ')); - QStringList qualifiedScopeName = currentScope()->qualifiedName(); - AbstractMetaType* type = 0; - QString scope; - for (int j = qualifiedScopeName.size(); j >= 0; --j) { - scope = j > 0 ? QStringList(qualifiedScopeName.mid(0, j)).join(colonColon()) + colonColon() : QString(); + 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((scope + l.at(0)).split(colonColon())); + info.setQualifiedName(qualifiedName); - type = translateType(info); + type = translateType(info, metaClass); if (type) break; } @@ -2932,23 +2815,23 @@ void AbstractMetaBuilderPrivate::parseQ_Property(AbstractMetaClass *metaClass, if (!type) { qCWarning(lcShiboken).noquote().nospace() << QStringLiteral("Unable to decide type of property: '%1' in class '%2'") - .arg(l.at(0), metaClass->name()); + .arg(propertyTokens.at(0).toString(), metaClass->name()); continue; } QPropertySpec* spec = new QPropertySpec(type->typeEntry()); - spec->setName(l.at(1)); + spec->setName(propertyTokens.at(1).toString()); spec->setIndex(i); - for (int pos = 2; pos + 1 < l.size(); pos += 2) { - if (l.at(pos) == QLatin1String("READ")) - spec->setRead(l.at(pos + 1)); - else if (l.at(pos) == QLatin1String("WRITE")) - spec->setWrite(l.at(pos + 1)); - else if (l.at(pos) == QLatin1String("DESIGNABLE")) - spec->setDesignable(l.at(pos + 1)); - else if (l.at(pos) == QLatin1String("RESET")) - spec->setReset(l.at(pos + 1)); + 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()); } metaClass->addPropertySpec(spec); @@ -3214,16 +3097,60 @@ void AbstractMetaBuilder::setGlobalHeader(const QString& globalHeader) d->m_globalHeader = QFileInfo(globalHeader); } +void AbstractMetaBuilder::setHeaderPaths(const HeaderPaths &hp) +{ + for (const auto & h: hp) { + if (h.type != HeaderType::Framework && h.type != HeaderType::FrameworkSystem) + d->m_headerPaths.append(QFile::decodeName(h.path)); + } +} + void AbstractMetaBuilder::setSkipDeprecated(bool value) { d->m_skipDeprecated = value; } +// PYSIDE-975: When receiving an absolute path name from the code model, try +// to resolve it against the include paths set on shiboken in order to recreate +// relative paths like #include <foo/bar.h>. + +static inline bool isFileSystemSlash(QChar c) +{ + return c == QLatin1Char('/') || c == QLatin1Char('\\'); +} + +static bool matchHeader(const QString &headerPath, const QString &fileName) +{ +#if defined(Q_OS_WIN) || defined(Q_OS_DARWIN) + static const Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive; +#else + static const Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive; +#endif + const int pathSize = headerPath.size(); + return fileName.size() > pathSize + && isFileSystemSlash(fileName.at(pathSize)) + && fileName.startsWith(headerPath, caseSensitivity); +} + void AbstractMetaBuilderPrivate::setInclude(TypeEntry *te, const QString &fileName) const { - QFileInfo info(fileName); - if (m_globalHeader.fileName() != info.fileName()) - te->setInclude(Include(Include::IncludePath, info.fileName())); + auto it = m_resolveIncludeHash.find(fileName); + if (it == m_resolveIncludeHash.end()) { + QFileInfo info(fileName); + if (m_globalHeader.fileName() == info.fileName()) + return; + + int bestMatchLength = 0; + for (const auto &headerPath : m_headerPaths) { + if (headerPath.size() > bestMatchLength && matchHeader(headerPath, fileName)) + bestMatchLength = headerPath.size(); + } + const QString include = bestMatchLength > 0 + ? fileName.right(fileName.size() - bestMatchLength - 1) + : info.fileName(); + it = m_resolveIncludeHash.insert(fileName, {Include::IncludePath, include}); + } + te->setInclude(it.value()); } #ifndef QT_NO_DEBUG_STREAM diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h index ed89060ac..1789ca2aa 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h @@ -30,6 +30,7 @@ #define ABSTRACTMETABUILDER_H #include "abstractmetalang_typedefs.h" +#include "header_paths.h" #include "dependency.h" #include "clangparser/compilersupport.h" @@ -85,6 +86,7 @@ public: * filled. */ void setGlobalHeader(const QString& globalHeader); + void setHeaderPaths(const HeaderPaths &h); void setSkipDeprecated(bool value); diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h index d8203a586..3c0039f0e 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h @@ -60,15 +60,17 @@ public: ScopeModelItem currentScope() const { return m_scopes.constLast(); } - AbstractMetaClass *argumentToClass(const ArgumentModelItem &); + AbstractMetaClass *argumentToClass(const ArgumentModelItem &, + AbstractMetaClass *currentClass); - void addAbstractMetaClass(AbstractMetaClass *cls); + void addAbstractMetaClass(AbstractMetaClass *cls, const _CodeModelItem *item); AbstractMetaClass *traverseTypeDef(const FileModelItem &dom, - const TypeDefModelItem &typeDef); + const TypeDefModelItem &typeDef, + AbstractMetaClass *currentClass); void traverseTypesystemTypedefs(); AbstractMetaClass *traverseClass(const FileModelItem &dom, - const ClassModelItem &item); - AbstractMetaClass *currentTraversedClass(ScopeModelItem item); + const ClassModelItem &item, + AbstractMetaClass *currentClass); void traverseScopeMembers(ScopeModelItem item, AbstractMetaClass *metaClass); void traverseClassMembers(ClassModelItem scopeItem); void traverseNamespaceMembers(NamespaceModelItem scopeItem); @@ -80,24 +82,30 @@ public: void traverseEnums(const ScopeModelItem &item, AbstractMetaClass *parent, const QStringList &enumsDeclarations); AbstractMetaFunctionList classFunctionList(const ScopeModelItem &scopeItem, - AbstractMetaClass::Attributes *constructorAttributes); + AbstractMetaClass::Attributes *constructorAttributes, + AbstractMetaClass *currentClass); AbstractMetaFunctionList templateClassFunctionList(const ScopeModelItem &scopeItem, AbstractMetaClass *metaClass, bool *constructorRejected); void traverseFunctions(ScopeModelItem item, AbstractMetaClass *parent); void applyFunctionModifications(AbstractMetaFunction* func); void traverseFields(const ScopeModelItem &item, AbstractMetaClass *parent); - void traverseStreamOperator(const FunctionModelItem &functionItem); - void traverseOperatorFunction(const FunctionModelItem &item); - AbstractMetaFunction* traverseFunction(const AddedFunction &addedFunc); - AbstractMetaFunction* traverseFunction(const AddedFunction &addedFunc, + void traverseStreamOperator(const FunctionModelItem &functionItem, + AbstractMetaClass *currentClass); + void traverseOperatorFunction(const FunctionModelItem &item, + AbstractMetaClass *currentClass); + AbstractMetaFunction* traverseFunction(const AddedFunctionPtr &addedFunc); + AbstractMetaFunction* traverseFunction(const AddedFunctionPtr &addedFunc, AbstractMetaClass *metaClass); - AbstractMetaFunction *traverseFunction(const FunctionModelItem &function); + AbstractMetaFunction *traverseFunction(const FunctionModelItem &function, + AbstractMetaClass *currentClass); AbstractMetaField *traverseField(const VariableModelItem &field, - const AbstractMetaClass *cls); + AbstractMetaClass *cls); void checkFunctionModifications(); - void registerHashFunction(const FunctionModelItem &functionItem); - void registerToStringCapability(const FunctionModelItem &functionItem); + void registerHashFunction(const FunctionModelItem &functionItem, + AbstractMetaClass *currentClass); + void registerToStringCapability(const FunctionModelItem &functionItem, + AbstractMetaClass *currentClass); /** * A conversion operator function should not have its owner class as @@ -124,6 +132,7 @@ public: int argumentIndex); AbstractMetaType *translateType(const AddedFunction::TypeInfo &typeInfo); AbstractMetaType *translateType(const TypeInfo &type, + AbstractMetaClass *currentClass, bool resolveType = true, QString *errorMessage = nullptr); static AbstractMetaType *translateTypeStatic(const TypeInfo &type, @@ -149,9 +158,6 @@ public: bool isQObject(const FileModelItem &dom, const QString &qualifiedName); bool isEnum(const FileModelItem &dom, const QStringList &qualifiedName); - void fixQObjectForScope(const FileModelItem &dom, const TypeDatabase *types, - const NamespaceModelItem &item); - void sortLists(); AbstractMetaArgumentList reverseList(const AbstractMetaArgumentList &list); void setInclude(TypeEntry *te, const QString &fileName) const; @@ -163,6 +169,7 @@ public: AbstractMetaClassList m_metaClasses; AbstractMetaClassList m_templates; AbstractMetaClassList m_smartPointers; + QHash<const _CodeModelItem *, AbstractMetaClass *> m_itemToClass; AbstractMetaFunctionList m_globalFunctions; AbstractMetaEnumList m_globalEnums; @@ -175,14 +182,14 @@ public: QHash<const TypeEntry *, AbstractMetaEnum *> m_enums; - AbstractMetaClass *m_currentClass; QList<ScopeModelItem> m_scopes; - QString m_namespacePrefix; QSet<AbstractMetaClass *> m_setupInheritanceDone; QString m_logDirectory; QFileInfo m_globalHeader; + QStringList m_headerPaths; + mutable QHash<QString, Include> m_resolveIncludeHash; bool m_skipDeprecated; }; diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp index 95f8048cd..512efef58 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp @@ -288,8 +288,7 @@ AbstractMetaType::TypeUsagePattern AbstractMetaType::determineUsagePattern() con if (m_typeEntry->isObject()) { if (indirections() == 0 && m_referenceType == NoReference) return ValuePattern; - return static_cast<const ComplexTypeEntry *>(m_typeEntry)->isQObject() - ? QObjectPattern : ObjectPattern; + return ObjectPattern; } if (m_typeEntry->isContainer() && indirections() == 0) @@ -322,8 +321,7 @@ void AbstractMetaType::decideUsagePattern() // const-references to pointers can be passed as pointers setReferenceType(NoReference); setConstant(false); - pattern = static_cast<const ComplexTypeEntry *>(m_typeEntry)->isQObject() - ? QObjectPattern : ObjectPattern; + pattern = ObjectPattern; } setTypeUsagePattern(pattern); } @@ -454,10 +452,32 @@ QDebug operator<<(QDebug d, const AbstractMetaArgument *aa) * AbstractMetaFunction */ +AbstractMetaFunction::AbstractMetaFunction(const AddedFunctionPtr &addedFunc) : + AbstractMetaFunction() +{ + m_addedFunction = addedFunc; + setConstant(addedFunc->isConstant()); + setName(addedFunc->name()); + setOriginalName(addedFunc->name()); + auto atts = attributes() | AbstractMetaAttributes::FinalInTargetLang; + switch (addedFunc->access()) { + case AddedFunction::InvalidAccess: + break; + case AddedFunction::Protected: + atts |= AbstractMetaAttributes::Protected; + break; + case AddedFunction::Public: + atts |= AbstractMetaAttributes::Public; + break; + } + if (addedFunc->isStatic()) + atts |= AbstractMetaFunction::Static; + setAttributes(atts); +} + AbstractMetaFunction::AbstractMetaFunction() : m_constant(false), m_reverse(false), - m_userAdded(false), m_explicit(false), m_pointerOperator(false), m_isCallOperator(false) @@ -581,6 +601,7 @@ AbstractMetaFunction *AbstractMetaFunction::copy() const cpy->setExceptionSpecification(m_exceptionSpecification); cpy->setAllowThreadModification(m_allowThreadModification); cpy->setExceptionHandlingModification(m_exceptionHandlingModification); + cpy->m_addedFunction = m_addedFunction; for (AbstractMetaArgument *arg : m_arguments) cpy->addArgument(arg->copy()); @@ -944,6 +965,8 @@ QString AbstractMetaFunction::debugSignature() const FunctionModificationList AbstractMetaFunction::modifications(const AbstractMetaClass* implementor) const { + if (!m_addedFunction.isNull()) + return m_addedFunction->modifications; if (!implementor) implementor = ownerClass(); @@ -1281,7 +1304,7 @@ void AbstractMetaFunction::formatDebugVerbose(QDebug &d) const d << " [const]"; if (m_reverse) d << " [reverse]"; - if (m_userAdded) + if (isUserAdded()) d << " [userAdded]"; if (m_explicit) d << " [explicit]"; @@ -1636,9 +1659,14 @@ bool AbstractMetaClass::isNamespace() const return m_typeEntry->isNamespace(); } +static bool qObjectPredicate(const AbstractMetaClass *c) +{ + return c->qualifiedCppName() == QLatin1String("QObject"); +} + bool AbstractMetaClass::isQObject() const { - return m_typeEntry->isQObject(); + return qObjectPredicate(this) || recurseClassHierarchy(this, qObjectPredicate) != nullptr; } QString AbstractMetaClass::qualifiedCppName() const diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h index 0c652a39a..ef4cef2b4 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.h +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h @@ -301,7 +301,6 @@ public: EnumPattern, ValuePattern, ObjectPattern, - QObjectPattern, ValuePointerPattern, NativePointerPattern, NativePointerAsArrayPattern, // "int*" as "int[]" @@ -376,12 +375,6 @@ public: return m_pattern == EnumPattern; } - // returns true if the type is used as a QObject * - bool isQObject() const - { - return m_pattern == QObjectPattern; - } - // returns true if the type is used as an object, e.g. Xxx * bool isObject() const { @@ -790,6 +783,7 @@ public: Q_FLAG(CompareResultFlag) AbstractMetaFunction(); + explicit AbstractMetaFunction(const AddedFunctionPtr &addedFunc); ~AbstractMetaFunction(); QString name() const @@ -1010,14 +1004,7 @@ public: } /// Returns true if the AbstractMetaFunction was added by the user via the type system description. - bool isUserAdded() const - { - return m_userAdded; - } - void setUserAdded(bool userAdded) - { - m_userAdded = userAdded; - } + bool isUserAdded() const { return !m_addedFunction.isNull(); } QString toString() const { @@ -1125,9 +1112,9 @@ private: const AbstractMetaClass *m_declaringClass = nullptr; QPropertySpec *m_propertySpec = nullptr; AbstractMetaArgumentList m_arguments; + AddedFunctionPtr m_addedFunction; uint m_constant : 1; uint m_reverse : 1; - uint m_userAdded : 1; uint m_explicit : 1; uint m_pointerOperator : 1; uint m_isCallOperator : 1; diff --git a/sources/shiboken2/ApiExtractor/apiextractor.cpp b/sources/shiboken2/ApiExtractor/apiextractor.cpp index e301d891f..fbe7664e9 100644 --- a/sources/shiboken2/ApiExtractor/apiextractor.cpp +++ b/sources/shiboken2/ApiExtractor/apiextractor.cpp @@ -224,6 +224,7 @@ bool ApiExtractor::run() m_builder->setLogDirectory(m_logDirectory); m_builder->setGlobalHeader(m_cppFileName); m_builder->setSkipDeprecated(m_skipDeprecated); + m_builder->setHeaderPaths(m_includePaths); QByteArrayList arguments; arguments.reserve(m_includePaths.size() + 1); for (const HeaderPath &headerPath : qAsConst(m_includePaths)) diff --git a/sources/shiboken2/ApiExtractor/messages.cpp b/sources/shiboken2/ApiExtractor/messages.cpp index fa4c75743..fdae2359b 100644 --- a/sources/shiboken2/ApiExtractor/messages.cpp +++ b/sources/shiboken2/ApiExtractor/messages.cpp @@ -167,6 +167,12 @@ QString msgSkippingFunction(const FunctionModelItem &functionItem, return result; } +QString msgCannotResolveEntity(const QString &name, const QString &reason) +{ + return QLatin1String("Cannot resolve entity \"") + name + + QLatin1String("\": ") + reason; +} + QString msgCannotSetArrayUsage(const QString &function, int i, const QString &reason) { return function + QLatin1String(": Cannot use parameter ") diff --git a/sources/shiboken2/ApiExtractor/messages.h b/sources/shiboken2/ApiExtractor/messages.h index 539332aef..30b13fbf8 100644 --- a/sources/shiboken2/ApiExtractor/messages.h +++ b/sources/shiboken2/ApiExtractor/messages.h @@ -68,6 +68,8 @@ QString msgUnmatchedReturnType(const FunctionModelItem &functionItem, QString msgSkippingFunction(const FunctionModelItem &functionItem, const QString &signature, const QString &why); +QString msgCannotResolveEntity(const QString &name, const QString &reason); + QString msgCannotSetArrayUsage(const QString &function, int i, const QString &reason); QString msgUnableToTranslateType(const QString &t, const QString &why); diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.cpp b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp index 8bc9b24ac..9a845b04a 100644 --- a/sources/shiboken2/ApiExtractor/parser/codemodel.cpp +++ b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp @@ -83,37 +83,35 @@ FileModelItem CodeModel::findFile(const QString &name) const return findModelItem(m_files, name); } -CodeModelItem CodeModel::findItem(const QStringList &qualifiedName, CodeModelItem scope) const -{ - for (int i = 0; i < qualifiedName.size(); ++i) { - // ### Extend to look for members etc too. - const QString &name = qualifiedName.at(i); - - if (NamespaceModelItem ns = qSharedPointerDynamicCast<_NamespaceModelItem>(scope)) { - if (NamespaceModelItem tmp_ns = ns->findNamespace(name)) { - scope = tmp_ns; - continue; - } - } - - if (ScopeModelItem ss = qSharedPointerDynamicCast<_ScopeModelItem>(scope)) { - if (ClassModelItem cs = ss->findClass(name)) { - scope = cs; - } else if (EnumModelItem es = ss->findEnum(name)) { - if (i == qualifiedName.size() - 1) - return es; - } else if (TypeDefModelItem tp = ss->findTypeDef(name)) { - if (i == qualifiedName.size() - 1) - return tp; - } else { - // If we don't find the name in the scope chain we - // need to return an empty item to indicate failure... - return CodeModelItem(); +static CodeModelItem findRecursion(const ScopeModelItem &scope, + const QStringList &qualifiedName, int segment = 0) +{ + const QString &nameSegment = qualifiedName.at(segment); + if (segment == qualifiedName.size() - 1) { // Leaf item + if (ClassModelItem cs = scope->findClass(nameSegment)) + return cs; + if (EnumModelItem es = scope->findEnum(nameSegment)) + return es; + if (TypeDefModelItem tp = scope->findTypeDef(nameSegment)) + return tp; + return CodeModelItem(); + } + if (auto nestedClass = scope->findClass(nameSegment)) + return findRecursion(nestedClass, qualifiedName, segment + 1); + if (auto namespaceItem = qSharedPointerDynamicCast<_NamespaceModelItem>(scope)) { + for (const auto &nestedNamespace : namespaceItem->namespaces()) { + if (nestedNamespace->name() == nameSegment) { + if (auto item = findRecursion(nestedNamespace, qualifiedName, segment + 1)) + return item; } } } + return CodeModelItem(); +} - return scope; +CodeModelItem CodeModel::findItem(const QStringList &qualifiedName, const ScopeModelItem &scope) const +{ + return findRecursion(scope, qualifiedName); } #ifndef QT_NO_DEBUG_STREAM @@ -160,7 +158,7 @@ bool TypeInfo::isVoid() const && m_qualifiedName.constFirst() == QLatin1String("void"); } -TypeInfo TypeInfo::resolveType(TypeInfo const &__type, CodeModelItem __scope) +TypeInfo TypeInfo::resolveType(TypeInfo const &__type, const ScopeModelItem &__scope) { CodeModel *__model = __scope->model(); Q_ASSERT(__model != 0); @@ -168,7 +166,7 @@ TypeInfo TypeInfo::resolveType(TypeInfo const &__type, CodeModelItem __scope) return TypeInfo::resolveType(__model->findItem(__type.qualifiedName(), __scope), __type, __scope); } -TypeInfo TypeInfo::resolveType(CodeModelItem __item, TypeInfo const &__type, CodeModelItem __scope) +TypeInfo TypeInfo::resolveType(CodeModelItem __item, TypeInfo const &__type, const ScopeModelItem &__scope) { // Copy the type and replace with the proper qualified name. This // only makes sence to do if we're actually getting a resolved diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.h b/sources/shiboken2/ApiExtractor/parser/codemodel.h index 0296a8cb2..64415e07b 100644 --- a/sources/shiboken2/ApiExtractor/parser/codemodel.h +++ b/sources/shiboken2/ApiExtractor/parser/codemodel.h @@ -82,7 +82,7 @@ public: void addFile(FileModelItem item); FileModelItem findFile(const QString &name) const; - CodeModelItem findItem(const QStringList &qualifiedName, CodeModelItem scope) const; + CodeModelItem findItem(const QStringList &qualifiedName, const ScopeModelItem &scope) const; private: FileList m_files; @@ -202,7 +202,7 @@ public: QString toString() const; static TypeInfo combine(const TypeInfo &__lhs, const TypeInfo &__rhs); - static TypeInfo resolveType(TypeInfo const &__type, CodeModelItem __scope); + static TypeInfo resolveType(TypeInfo const &__type, const ScopeModelItem &__scope); #ifndef QT_NO_DEBUG_STREAM void formatDebug(QDebug &d) const; @@ -219,7 +219,7 @@ public: private: friend class TypeInfoTemplateArgumentHandler; - static TypeInfo resolveType(CodeModelItem item, TypeInfo const &__type, CodeModelItem __scope); + static TypeInfo resolveType(CodeModelItem item, TypeInfo const &__type, const ScopeModelItem &__scope); QStringList m_qualifiedName; QStringList m_arrayElements; diff --git a/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt b/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt index e100ef493..a36cc17de 100644 --- a/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt +++ b/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt @@ -1,9 +1,3 @@ -find_package(Qt5Core) -find_package(Qt5Gui) -find_package(Qt5Test) -find_package(Qt5Xml) -find_package(Qt5XmlPatterns) - set(CMAKE_AUTORCC ON) macro(declare_test testname) @@ -15,19 +9,13 @@ macro(declare_test testname) if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${testname}.qrc") list(APPEND SOURCES "${testname}.qrc") endif () + add_executable(${testname} ${SOURCES}) - include_directories(${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ${apiextractor_SOURCE_DIR} - ${Qt5Test_INCLUDE_DIRS} - ) - link_directories(${APIEXTRACTOR_EXTRA_LINK_DIRECTORIES}) - target_link_libraries(${testname} - ${Qt5XmlPatterns_LIBRARIES} - ${Qt5Test_LIBRARIES} - ${Qt5Core_LIBRARIES} - ${Qt5Gui_LIBRARIES} - apiextractor) + target_include_directories(${testname} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${apiextractor_SOURCE_DIR} + ) + target_link_libraries(${testname} PRIVATE apiextractor Qt5::Test) add_test(${testname} ${testname}) if (INSTALL_TESTS) install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${testname} diff --git a/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp index fc67ebba5..63434b3a5 100644 --- a/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp +++ b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp @@ -85,7 +85,6 @@ void TestAbstractMetaType::testConstCharPtrType() QVERIFY(!rtype->isObject()); QVERIFY(!rtype->isPrimitive()); // const char* differs from char, so it's not considered a primitive type by apiextractor QVERIFY(rtype->isNativePointer()); - QVERIFY(!rtype->isQObject()); QCOMPARE(rtype->referenceType(), NoReference); QVERIFY(!rtype->isValue()); QVERIFY(!rtype->isValuePointer()); @@ -159,7 +158,6 @@ void TestAbstractMetaType::testCharType() QVERIFY(!rtype->isObject()); QVERIFY(rtype->isPrimitive()); QVERIFY(!rtype->isNativePointer()); - QVERIFY(!rtype->isQObject()); QCOMPARE(rtype->referenceType(), NoReference); QVERIFY(!rtype->isValue()); QVERIFY(!rtype->isValuePointer()); diff --git a/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp b/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp index db49942c9..8c443527e 100644 --- a/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp +++ b/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp @@ -71,26 +71,32 @@ void TestAddFunction::testParsingFuncNameAndConstness() void TestAddFunction::testAddFunction() { - const char cppCode[] = "struct B {}; struct A { void a(int); };\n"; - const char xmlCode[] = "\ - <typesystem package='Foo'>\n\ - <primitive-type name='int'/>\n\ - <primitive-type name='float'/>\n\ - <value-type name='B'/>\n\ - <value-type name='A'>\n\ - <add-function signature='b(int, float = 4.6, const B&)' return-type='int' access='protected'>\n\ - </add-function>\n\ - </value-type>\n\ - </typesystem>\n"; + const char cppCode[] = R"CPP( +struct B {}; +struct A { + void a(int); +};)CPP"; + const char xmlCode[] = R"XML( +<typesystem package='Foo'> + <primitive-type name='int'/> + <primitive-type name='float'/> + <value-type name='B'/> + <value-type name='A'> + <add-function signature='b(int, float = 4.6, const B&)' return-type='int' access='protected'/> + <add-function signature='operator()(int)' return-type='int' access='public'/> + </value-type> +</typesystem>)XML"; + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); QVERIFY(!builder.isNull()); TypeDatabase* typeDb = TypeDatabase::instance(); AbstractMetaClassList classes = builder->classes(); const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A")); QVERIFY(classA); - QCOMPARE(classA->functions().count(), 4); // default ctor, default copy ctor, func a() and the added function + QCOMPARE(classA->functions().count(), 5); // default ctor, default copy ctor, func a() and the added functions - AbstractMetaFunction* addedFunc = classA->functions().last(); + auto addedFunc = classA->findFunction(QLatin1String("b")); + QVERIFY(addedFunc); QCOMPARE(addedFunc->visibility(), AbstractMetaFunction::Protected); QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction); QVERIFY(addedFunc->isUserAdded()); @@ -109,6 +115,9 @@ void TestAddFunction::testAddFunction() QCOMPARE(args[0]->type()->typeEntry(), returnType->typeEntry()); QCOMPARE(args[1]->defaultValueExpression(), QLatin1String("4.6")); QCOMPARE(args[2]->type()->typeEntry(), typeDb->findType(QLatin1String("B"))); + + auto addedCallOperator = classA->findFunction(QLatin1String("operator()")); + QVERIFY(addedCallOperator); } void TestAddFunction::testAddFunctionConstructor() @@ -265,7 +274,7 @@ void TestAddFunction::testAddFunctionAtModuleLevel() QCOMPARE(addedFuncs.size(), 1); - FunctionModificationList mods = typeDb->functionModifications(QLatin1String("func(int,int)")); + const FunctionModificationList mods = addedFuncs.constFirst()->modifications; QCOMPARE(mods.size(), 1); QVERIFY(mods.first().isCodeInjection()); diff --git a/sources/shiboken2/ApiExtractor/typedatabase.cpp b/sources/shiboken2/ApiExtractor/typedatabase.cpp index 4ce2790f5..a8c69d376 100644 --- a/sources/shiboken2/ApiExtractor/typedatabase.cpp +++ b/sources/shiboken2/ApiExtractor/typedatabase.cpp @@ -430,8 +430,8 @@ void TypeDatabase::addGlobalUserFunctions(const AddedFunctionList &functions) AddedFunctionList TypeDatabase::findGlobalUserFunctions(const QString& name) const { AddedFunctionList addedFunctions; - for (const AddedFunction &func : m_globalUserFunctions) { - if (func.name() == name) + for (const AddedFunctionPtr &func : m_globalUserFunctions) { + if (func->name() == name) addedFunctions.append(func); } return addedFunctions; @@ -802,7 +802,6 @@ void ComplexTypeEntry::formatDebug(QDebug &d) const { TypeEntry::formatDebug(d); FORMAT_NONEMPTY_STRING("targetLangName", m_targetLangName) - FORMAT_BOOL("QObject", m_qobject) FORMAT_BOOL("polymorphicBase", m_polymorphicBase) FORMAT_BOOL("genericClass", m_genericClass) FORMAT_BOOL("deleteInMainThread", m_deleteInMainThread) diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp index ad97e40ee..318a52e2e 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.cpp +++ b/sources/shiboken2/ApiExtractor/typesystem.cpp @@ -40,6 +40,7 @@ #include <QtCore/QStringAlgorithms> #include <QtCore/QXmlStreamAttributes> #include <QtCore/QXmlStreamReader> +#include <QtCore/QXmlStreamEntityResolver> #include <algorithm> @@ -105,6 +106,8 @@ static inline QString yesAttributeValue() { return QStringLiteral("yes"); } static inline QString trueAttributeValue() { return QStringLiteral("true"); } static inline QString falseAttributeValue() { return QStringLiteral("false"); } +static inline QString callOperator() { return QStringLiteral("operator()"); } + static QVector<CustomConversion *> customConversionsForReview; // Set a regular expression for rejection from text. By legacy, those are fixed @@ -437,12 +440,75 @@ static QString msgUnusedAttributes(const QStringRef &tag, const QXmlStreamAttrib return result; } +// QXmlStreamEntityResolver::resolveEntity(publicId, systemId) is not +// implemented; resolve via undeclared entities instead. +class TypeSystemEntityResolver : public QXmlStreamEntityResolver +{ +public: + explicit TypeSystemEntityResolver(const QString ¤tPath) : + m_currentPath(currentPath) {} + + QString resolveUndeclaredEntity(const QString &name) override; + +private: + QString readFile(const QString &entityName, QString *errorMessage) const; + + const QString m_currentPath; + QHash<QString, QString> m_cache; +}; + +QString TypeSystemEntityResolver::readFile(const QString &entityName, QString *errorMessage) const +{ + QString fileName = entityName; + if (!fileName.contains(QLatin1Char('.'))) + fileName += QLatin1String(".xml"); + QString path = TypeDatabase::instance()->modifiedTypesystemFilepath(fileName, m_currentPath); + if (!QFileInfo::exists(path)) // PySide2-specific hack + fileName.prepend(QLatin1String("typesystem_")); + path = TypeDatabase::instance()->modifiedTypesystemFilepath(fileName, m_currentPath); + if (!QFileInfo::exists(path)) { + *errorMessage = QLatin1String("Unable to resolve: ") + entityName; + return QString(); + } + QFile file(path); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + *errorMessage = msgCannotOpenForReading(file); + return QString(); + } + QString result = QString::fromUtf8(file.readAll()).trimmed(); + // Remove license header comments on which QXmlStreamReader chokes + if (result.startsWith(QLatin1String("<!--"))) { + const int commentEnd = result.indexOf(QLatin1String("-->")); + if (commentEnd != -1) { + result.remove(0, commentEnd + 3); + result = result.trimmed(); + } + } + return result; +} + +QString TypeSystemEntityResolver::resolveUndeclaredEntity(const QString &name) +{ + auto it = m_cache.find(name); + if (it == m_cache.end()) { + QString errorMessage; + it = m_cache.insert(name, readFile(name, &errorMessage)); + if (it.value().isEmpty()) { // The parser will fail and display the line number. + qCWarning(lcShiboken, "%s", + qPrintable(msgCannotResolveEntity(name, errorMessage))); + } + } + return it.value(); +} + Handler::Handler(TypeDatabase *database, bool generate) : m_database(database), m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass) { } +Handler::~Handler() = default; + static QString readerFileName(const QXmlStreamReader &reader) { const QFile *file = qobject_cast<const QFile *>(reader.device()); @@ -582,6 +648,8 @@ bool Handler::parse(QXmlStreamReader &reader) const QString fileName = readerFileName(reader); if (!fileName.isEmpty()) m_currentPath = QFileInfo(fileName).absolutePath(); + m_entityResolver.reset(new TypeSystemEntityResolver(m_currentPath)); + reader.setEntityResolver(m_entityResolver.data()); while (!reader.atEnd()) { switch (reader.readNext()) { @@ -674,6 +742,17 @@ bool Handler::endElement(const QStringRef &localName) } } break; + case StackElement::AddFunction: { + // Leaving add-function: Assign all modifications to the added function + StackElementContext *top = m_contextStack.top(); + const int modIndex = top->addedFunctionModificationIndex; + top->addedFunctionModificationIndex = -1; + Q_ASSERT(modIndex >= 0); + Q_ASSERT(!top->addedFunctions.isEmpty()); + while (modIndex < top->functionMods.size()) + top->addedFunctions.last()->modifications.append(top->functionMods.takeAt(modIndex)); + } + break; case StackElement::NativeToTarget: case StackElement::AddConversion: { CustomConversion* customConversion = static_cast<TypeEntry*>(m_current->entry)->customConversion(); @@ -2009,8 +2088,8 @@ bool Handler::parseAddFunction(const QXmlStreamReader &, return false; } - AddedFunction func(signature, returnType); - func.setStatic(staticFunction); + AddedFunctionPtr func(new AddedFunction(signature, returnType)); + func->setStatic(staticFunction); if (!signature.contains(QLatin1Char('('))) signature += QLatin1String("()"); m_currentSignature = signature; @@ -2021,10 +2100,12 @@ bool Handler::parseAddFunction(const QXmlStreamReader &, m_error = QString::fromLatin1("Bad access type '%1'").arg(access); return false; } - func.setAccess(a); + func->setAccess(a); } m_contextStack.top()->addedFunctions << func; + m_contextStack.top()->addedFunctionModificationIndex = + m_contextStack.top()->functionMods.size(); FunctionModification mod; if (!mod.setSignature(m_currentSignature, &m_error)) @@ -3231,7 +3312,10 @@ AddedFunction::AddedFunction(QString signature, const QString &returnType) : Q_ASSERT(!returnType.isEmpty()); m_returnType = parseType(returnType); signature = signature.trimmed(); - int endPos = signature.indexOf(QLatin1Char('(')); + // Skip past "operator()(...)" + const int parenStartPos = signature.startsWith(callOperator()) + ? callOperator().size() : 0; + int endPos = signature.indexOf(QLatin1Char('('), parenStartPos); if (endPos < 0) { m_isConst = false; m_name = signature; @@ -3413,7 +3497,6 @@ ComplexTypeEntry::ComplexTypeEntry(const QString &name, TypeEntry::Type t, const QVersionNumber &vr) : TypeEntry(name, t, vr), m_qualifiedCppName(name), - m_qobject(false), m_polymorphicBase(false), m_genericClass(false), m_deleteInMainThread(false) @@ -3483,6 +3566,20 @@ static const QSet<QString> &primitiveCppTypes() return result; } +void TypeEntry::setInclude(const Include &inc) +{ + // This is a workaround for preventing double inclusion of the QSharedPointer implementation + // header, which does not use header guards. In the previous parser this was not a problem + // because the Q_QDOC define was set, and the implementation header was never included. + if (inc.name().endsWith(QLatin1String("qsharedpointer_impl.h"))) { + QString path = inc.name(); + path.remove(QLatin1String("_impl")); + m_include = Include(inc.type(), path); + } else { + m_include = inc; + } +} + bool TypeEntry::isCppPrimitive() const { if (!isPrimitive()) diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h index 96d0bb5fd..f089bb6e0 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.h +++ b/sources/shiboken2/ApiExtractor/typesystem.h @@ -476,6 +476,8 @@ struct AddedFunction return m_isStatic; } + FunctionModificationList modifications; + private: QString m_name; QVector<TypeInfo> m_arguments; @@ -835,16 +837,7 @@ public: { return m_include; } - void setInclude(const Include &inc) - { - // This is a workaround for preventing double inclusion of the QSharedPointer implementation - // header, which does not use header guards. In the previous parser this was not a problem - // because the Q_QDOC define was set, and the implementation header was never included. - if (inc.name() == QLatin1String("qsharedpointer_impl.h")) - m_include = Include(inc.type(), QLatin1String("qsharedpointer.h")); - else - m_include = inc; - } + void setInclude(const Include &inc); // Replace conversionRule arg to CodeSnip in future version /// Set the type convertion rule @@ -1278,7 +1271,7 @@ public: { m_addedFunctions = addedFunctions; } - void addNewFunction(const AddedFunction &addedFunction) + void addNewFunction(const AddedFunctionPtr &addedFunction) { m_addedFunctions << addedFunction; } @@ -1293,15 +1286,6 @@ public: return m_fieldMods; } - bool isQObject() const - { - return m_qobject; - } - void setQObject(bool qobject) - { - m_qobject = qobject; - } - QString defaultSuperclass() const { return m_defaultSuperclass; @@ -1419,7 +1403,6 @@ private: QString m_qualifiedCppName; QString m_targetLangName; - uint m_qobject : 1; uint m_polymorphicBase : 1; uint m_genericClass : 1; uint m_deleteInMainThread : 1; diff --git a/sources/shiboken2/ApiExtractor/typesystem_p.h b/sources/shiboken2/ApiExtractor/typesystem_p.h index a119b2a97..f6b0717f4 100644 --- a/sources/shiboken2/ApiExtractor/typesystem_p.h +++ b/sources/shiboken2/ApiExtractor/typesystem_p.h @@ -29,11 +29,13 @@ #define TYPESYSTEM_P_H #include <QStack> +#include <QtCore/QScopedPointer> #include "typesystem.h" QT_FORWARD_DECLARE_CLASS(QXmlStreamAttributes) QT_FORWARD_DECLARE_CLASS(QXmlStreamReader) +class TypeSystemEntityResolver; class TypeDatabase; class StackElement { @@ -132,12 +134,16 @@ struct StackElementContext FunctionModificationList functionMods; FieldModificationList fieldMods; DocModificationList docModifications; + int addedFunctionModificationIndex = -1; }; class Handler { public: + Q_DISABLE_COPY(Handler) + Handler(TypeDatabase* database, bool generate); + ~Handler(); bool parse(QXmlStreamReader &reader); @@ -255,6 +261,7 @@ private: QString m_currentSignature; QString m_currentPath; + QScopedPointer<TypeSystemEntityResolver> m_entityResolver; }; #endif diff --git a/sources/shiboken2/ApiExtractor/typesystem_typedefs.h b/sources/shiboken2/ApiExtractor/typesystem_typedefs.h index dc6e5cbcc..5cea587ed 100644 --- a/sources/shiboken2/ApiExtractor/typesystem_typedefs.h +++ b/sources/shiboken2/ApiExtractor/typesystem_typedefs.h @@ -31,6 +31,7 @@ #include <QtCore/QHash> #include <QtCore/QList> +#include <QtCore/QSharedPointer> #include <QtCore/QVector> class CodeSnip; @@ -40,7 +41,8 @@ struct AddedFunction; struct FieldModification; struct FunctionModification; -typedef QVector<AddedFunction> AddedFunctionList; +using AddedFunctionPtr = QSharedPointer<AddedFunction>; +using AddedFunctionList = QVector<AddedFunctionPtr>; typedef QVector<CodeSnip> CodeSnipList; typedef QVector<DocModification> DocModificationList; typedef QVector<FieldModification> FieldModificationList; |