diff options
Diffstat (limited to 'sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp')
-rw-r--r-- | sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp | 2083 |
1 files changed, 1284 insertions, 799 deletions
diff --git a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp index 4ef6132e1..29566a272 100644 --- a/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken6/ApiExtractor/abstractmetabuilder.cpp @@ -1,43 +1,34 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "abstractmetabuilder_p.h" +#include "abstractmetaargument.h" #include "abstractmetaenum.h" #include "abstractmetafield.h" #include "abstractmetafunction.h" +#include "abstractmetatype.h" +#include "addedfunction.h" #include "graph.h" +#include "debughelpers_p.h" #include "exception.h" #include "messages.h" #include "propertyspec.h" #include "reporthandler.h" #include "sourcelocation.h" #include "typedatabase.h" -#include "typesystem.h" +#include "enumtypeentry.h" +#include "enumvaluetypeentry.h" +#include "arraytypeentry.h" +#include "constantvaluetypeentry.h" +#include "containertypeentry.h" +#include "flagstypeentry.h" +#include "functiontypeentry.h" +#include "namespacetypeentry.h" +#include "primitivetypeentry.h" +#include "smartpointertypeentry.h" +#include "templateargumententry.h" +#include "typedefentry.h" +#include "typesystemtypeentry.h" #include "usingmember.h" #include "parser/codemodel.h" @@ -46,10 +37,13 @@ #include <clangparser/clangutils.h> #include <clangparser/compilersupport.h> +#include "qtcompat.h" + #include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QFile> #include <QtCore/QFileInfo> +#include <QtCore/QMetaObject> #include <QtCore/QQueue> #include <QtCore/QRegularExpression> #include <QtCore/QTemporaryFile> @@ -59,11 +53,11 @@ #include <algorithm> #include <memory> -static inline QString colonColon() { return QStringLiteral("::"); } +using namespace Qt::StringLiterals; static QString stripTemplateArgs(const QString &name) { - int pos = name.indexOf(QLatin1Char('<')); + const auto pos = name.indexOf(u'<'); return pos < 0 ? name : name.left(pos); } @@ -73,18 +67,37 @@ static void fixArgumentIndexes(AbstractMetaArgumentList *list) (*list)[i].setArgumentIndex(i); } -bool AbstractMetaBuilderPrivate::m_useGlobalHeader = false; +bool operator<(const RejectEntry &re1, const RejectEntry &re2) +{ + return re1.reason != re2.reason + ? (re1.reason < re2.reason) : (re1.sortkey < re2.sortkey); +} -AbstractMetaBuilderPrivate::AbstractMetaBuilderPrivate() : - m_logDirectory(QLatin1String(".") + QDir::separator()) +QTextStream &operator<<(QTextStream &str, const RejectEntry &re) { + str << re.signature; + if (!re.message.isEmpty()) + str << ": " << re.message; + return str; } -AbstractMetaBuilderPrivate::~AbstractMetaBuilderPrivate() +static void applyCachedFunctionModifications(AbstractMetaFunction *metaFunction, + const FunctionModificationList &functionMods) +{ + for (const FunctionModification &mod : functionMods) { + if (mod.exceptionHandling() != TypeSystem::ExceptionHandling::Unspecified) + metaFunction->setExceptionHandlingModification(mod.exceptionHandling()); + if (mod.allowThread() != TypeSystem::AllowThread::Unspecified) + metaFunction->setAllowThreadModification(mod.allowThread()); + } +} + +bool AbstractMetaBuilderPrivate::m_useGlobalHeader = false; +bool AbstractMetaBuilderPrivate::m_codeModelTestMode = false; + +AbstractMetaBuilderPrivate::AbstractMetaBuilderPrivate() : + m_logDirectory(u"."_s + QDir::separator()) { - qDeleteAll(m_templates); - qDeleteAll(m_smartPointers); - qDeleteAll(m_metaClasses); } AbstractMetaBuilder::AbstractMetaBuilder() : d(new AbstractMetaBuilderPrivate) @@ -102,16 +115,37 @@ const AbstractMetaClassList &AbstractMetaBuilder::classes() const return d->m_metaClasses; } +AbstractMetaClassList AbstractMetaBuilder::takeClasses() +{ + AbstractMetaClassList result; + qSwap(result, d->m_metaClasses); + return result; +} + const AbstractMetaClassList &AbstractMetaBuilder::templates() const { return d->m_templates; } +AbstractMetaClassList AbstractMetaBuilder::takeTemplates() +{ + AbstractMetaClassList result; + qSwap(result, d->m_templates); + return result; +} + const AbstractMetaClassList &AbstractMetaBuilder::smartPointers() const { return d->m_smartPointers; } +AbstractMetaClassList AbstractMetaBuilder::takeSmartPointers() +{ + AbstractMetaClassList result; + qSwap(result, d->m_smartPointers); + return result; +} + const AbstractMetaFunctionCList &AbstractMetaBuilder::globalFunctions() const { return d->m_globalFunctions; @@ -122,36 +156,41 @@ const AbstractMetaEnumList &AbstractMetaBuilder::globalEnums() const return d->m_globalEnums; } -const QHash<const TypeEntry *, AbstractMetaEnum> &AbstractMetaBuilder::typeEntryToEnumsHash() const +const QHash<TypeEntryCPtr, AbstractMetaEnum> &AbstractMetaBuilder::typeEntryToEnumsHash() const { return d->m_enums; } -void AbstractMetaBuilderPrivate::checkFunctionModifications() +const QMultiHash<QString, QString> &AbstractMetaBuilder::typedefTargetToName() const +{ + return d->m_typedefTargetToName; +} + +void AbstractMetaBuilderPrivate::checkFunctionModifications() const { const auto &entries = TypeDatabase::instance()->entries(); for (auto it = entries.cbegin(), end = entries.cend(); it != end; ++it) { - const TypeEntry *entry = it.value(); + TypeEntryCPtr entry = it.value(); if (!entry) continue; if (!entry->isComplex() || !entry->generateCode()) continue; - auto centry = static_cast<const ComplexTypeEntry *>(entry); + auto centry = std::static_pointer_cast<const ComplexTypeEntry>(entry); if (!centry->generateCode()) continue; FunctionModificationList modifications = centry->functionModifications(); - for (const FunctionModification &modification : qAsConst(modifications)) { + for (const FunctionModification &modification : std::as_const(modifications)) { QString signature = modification.signature(); QString name = signature.trimmed(); - name.truncate(name.indexOf(QLatin1Char('('))); + name.truncate(name.indexOf(u'(')); - AbstractMetaClass *clazz = AbstractMetaClass::findClass(m_metaClasses, centry); + const auto clazz = AbstractMetaClass::findClass(m_metaClasses, centry); if (!clazz) continue; @@ -159,13 +198,14 @@ void AbstractMetaBuilderPrivate::checkFunctionModifications() QStringList possibleSignatures; for (const auto &function : clazz->functions()) { if (function->implementingClass() == clazz - && modification.matches(function->minimalSignature())) { + && modification.matches(function->modificationSignatures())) { found = true; break; } if (function->originalName() == name) { - possibleSignatures.append(function->minimalSignature() + QLatin1String(" in ") + const QString signatures = function->modificationSignatures().join(u'/'); + possibleSignatures.append(signatures + u" in "_s + function->implementingClass()->name()); } } @@ -180,14 +220,14 @@ void AbstractMetaBuilderPrivate::checkFunctionModifications() } } -AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(const ArgumentModelItem &argument, - const AbstractMetaClass *currentClass) +AbstractMetaClassPtr AbstractMetaBuilderPrivate::argumentToClass(const ArgumentModelItem &argument, + const AbstractMetaClassCPtr ¤tClass) { - AbstractMetaClass *returned = nullptr; + AbstractMetaClassPtr returned; auto type = translateType(argument->type(), currentClass); if (!type.has_value()) return returned; - const TypeEntry *entry = type->typeEntry(); + TypeEntryCPtr entry = type->typeEntry(); if (entry && entry->isComplex()) returned = AbstractMetaClass::findClass(m_metaClasses, entry); return returned; @@ -197,18 +237,20 @@ 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, - AbstractMetaClass *currentClass) + const AbstractMetaClassPtr ¤tClass) { + if (function_item->isDeleted()) + return; ArgumentList arguments = function_item->arguments(); - if (arguments.size() == 1) { - if (AbstractMetaClass *cls = argumentToClass(arguments.at(0), currentClass)) - cls->setHasHashFunction(true); + if (arguments.size() >= 1) { // (Class, Hash seed). + if (AbstractMetaClassPtr cls = argumentToClass(arguments.at(0), currentClass)) + cls->setHashFunction(function_item->name()); } } void AbstractMetaBuilderPrivate::registerToStringCapabilityIn(const NamespaceModelItem &nsItem) { - const FunctionList &streamOps = nsItem->findFunctions(QLatin1String("operator<<")); + const FunctionList &streamOps = nsItem->findFunctions("operator<<"); for (const FunctionModelItem &item : streamOps) registerToStringCapability(item, nullptr); for (const NamespaceModelItem &ni : nsItem->namespaces()) @@ -220,13 +262,13 @@ void AbstractMetaBuilderPrivate::registerToStringCapabilityIn(const NamespaceMod */ void AbstractMetaBuilderPrivate::registerToStringCapability(const FunctionModelItem &function_item, - AbstractMetaClass *currentClass) + const AbstractMetaClassPtr ¤tClass) { ArgumentList arguments = function_item->arguments(); if (arguments.size() == 2) { - if (arguments.at(0)->type().toString() == QLatin1String("QDebug")) { + if (arguments.at(0)->type().toString() == u"QDebug") { const ArgumentModelItem &arg = arguments.at(1); - if (AbstractMetaClass *cls = argumentToClass(arg, currentClass)) { + if (AbstractMetaClassPtr cls = argumentToClass(arg, currentClass)) { if (arg->type().indirections() < 2) cls->setToStringCapability(true, int(arg->type().indirections())); } @@ -235,27 +277,27 @@ void AbstractMetaBuilderPrivate::registerToStringCapability(const FunctionModelI } void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelItem &item, - AbstractMetaClass *currentClass) + const AbstractMetaClassPtr ¤tClass) { if (item->accessPolicy() != Access::Public) return; - ArgumentList arguments = item->arguments(); + const ArgumentList &itemArguments = item->arguments(); bool firstArgumentIsSelf = true; bool unaryOperator = false; - auto baseoperandClass = argumentToClass(arguments.at(0), currentClass); + auto baseoperandClass = argumentToClass(itemArguments.at(0), currentClass); - if (arguments.size() == 1) { + if (itemArguments.size() == 1) { unaryOperator = true; } else if (!baseoperandClass || !baseoperandClass->typeEntry()->generateCode()) { - baseoperandClass = argumentToClass(arguments.at(1), currentClass); + baseoperandClass = argumentToClass(itemArguments.at(1), currentClass); firstArgumentIsSelf = false; } else { auto type = translateType(item->type(), currentClass); - const TypeEntry *retType = type.has_value() ? type->typeEntry() : nullptr; - AbstractMetaClass *otherArgClass = argumentToClass(arguments.at(1), currentClass); + const auto retType = type.has_value() ? type->typeEntry() : TypeEntryCPtr{}; + const auto otherArgClass = argumentToClass(itemArguments.at(1), currentClass); if (otherArgClass && retType && (retType->isValue() || retType->isObject()) && retType != baseoperandClass->typeEntry() @@ -264,43 +306,60 @@ void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelIte firstArgumentIsSelf = false; } } + if (!baseoperandClass) { + rejectFunction(item, currentClass, AbstractMetaBuilder::UnmatchedOperator, + u"base operand class not found."_s); + return; + } - if (baseoperandClass) { - AbstractMetaFunction *metaFunction = traverseFunction(item, baseoperandClass); - if (metaFunction) { - // Strip away first argument, since that is the containing object - AbstractMetaArgumentList arguments = metaFunction->arguments(); - if (firstArgumentIsSelf || unaryOperator) { - AbstractMetaArgument first = arguments.takeFirst(); - fixArgumentIndexes(&arguments); - if (!unaryOperator && first.type().indirections()) - metaFunction->setPointerOperator(true); - metaFunction->setArguments(arguments); - } else { - // If the operator method is not unary and the first operator is - // not of the same type of its owning class we suppose that it - // must be an reverse operator (e.g. CLASS::operator(TYPE, CLASS)). - // All operator overloads that operate over a class are already - // being added as member functions of that class by the API Extractor. - AbstractMetaArgument last = arguments.takeLast(); - if (last.type().indirections()) - metaFunction->setPointerOperator(true); - - metaFunction->setArguments(arguments); - metaFunction->setReverseOperator(true); - } - metaFunction->setAccess(Access::Public); - setupFunctionDefaults(metaFunction, baseoperandClass); - baseoperandClass->addFunction(AbstractMetaFunctionCPtr(metaFunction)); - Q_ASSERT(!metaFunction->wasPrivate()); - } else { - delete metaFunction; - } + if (item->isSpaceshipOperator() && !item->isDeleted()) { + AbstractMetaClass::addSynthesizedComparisonOperators(baseoperandClass); + return; } + + AbstractMetaFunction *metaFunction = traverseFunction(item, baseoperandClass); + if (metaFunction == nullptr) + return; + + auto flags = metaFunction->flags(); + // Strip away first argument, since that is the containing object + AbstractMetaArgumentList arguments = metaFunction->arguments(); + if (firstArgumentIsSelf || unaryOperator) { + AbstractMetaArgument first = arguments.takeFirst(); + fixArgumentIndexes(&arguments); + if (!unaryOperator && first.type().indirections()) + metaFunction->setPointerOperator(true); + metaFunction->setArguments(arguments); + flags.setFlag(AbstractMetaFunction::Flag::OperatorLeadingClassArgumentRemoved); + if (first.type().passByValue()) + flags.setFlag(AbstractMetaFunction::Flag::OperatorClassArgumentByValue); + } else { + // If the operator method is not unary and the first operator is + // not of the same type of its owning class we suppose that it + // must be an reverse operator (e.g. CLASS::operator(TYPE, CLASS)). + // All operator overloads that operate over a class are already + // being added as member functions of that class by the API Extractor. + AbstractMetaArgument last = arguments.takeLast(); + if (last.type().indirections()) + metaFunction->setPointerOperator(true); + metaFunction->setArguments(arguments); + metaFunction->setReverseOperator(true); + flags.setFlag(AbstractMetaFunction::Flag::OperatorTrailingClassArgumentRemoved); + if (last.type().passByValue()) + flags.setFlag(AbstractMetaFunction::Flag::OperatorClassArgumentByValue); + } + metaFunction->setFlags(flags); + metaFunction->setAccess(Access::Public); + AbstractMetaClass::addFunction(baseoperandClass, AbstractMetaFunctionCPtr(metaFunction)); + if (!metaFunction->arguments().isEmpty()) { + const auto include = metaFunction->arguments().constFirst().type().typeEntry()->include(); + baseoperandClass->typeEntry()->addArgumentInclude(include); + } + Q_ASSERT(!metaFunction->wasPrivate()); } bool AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem &item, - AbstractMetaClass *currentClass) + const AbstractMetaClassPtr ¤tClass) { ArgumentList itemArguments = item->arguments(); if (itemArguments.size() != 2 || item->accessPolicy() != Access::Public) @@ -327,10 +386,9 @@ bool AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem streamFunction->setArguments(arguments); - *streamFunction += AbstractMetaFunction::FinalInTargetLang; streamFunction->setAccess(Access::Public); - AbstractMetaClass *funcClass; + AbstractMetaClassPtr funcClass; if (!streamClass->typeEntry()->generateCode()) { AbstractMetaArgumentList reverseArgs = streamFunction->arguments(); @@ -343,19 +401,19 @@ bool AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem funcClass = streamClass; } - setupFunctionDefaults(streamFunction, funcClass); - funcClass->addFunction(AbstractMetaFunctionCPtr(streamFunction)); + AbstractMetaClass::addFunction(funcClass, AbstractMetaFunctionCPtr(streamFunction)); + auto funcTe = funcClass->typeEntry(); if (funcClass == streamClass) - funcClass->typeEntry()->addExtraInclude(streamedClass->typeEntry()->include()); + funcTe->addArgumentInclude(streamedClass->typeEntry()->include()); else - funcClass->typeEntry()->addExtraInclude(streamClass->typeEntry()->include()); + funcTe->addArgumentInclude(streamClass->typeEntry()->include()); return true; } static bool metaEnumLessThan(const AbstractMetaEnum &e1, const AbstractMetaEnum &e2) { return e1.fullName() < e2.fullName(); } -static bool metaClassLessThan(const AbstractMetaClass *c1, const AbstractMetaClass *c2) +static bool metaClassLessThan(const AbstractMetaClassCPtr &c1, const AbstractMetaClassCPtr &c2) { return c1->fullName() < c2->fullName(); } static bool metaFunctionLessThan(const AbstractMetaFunctionCPtr &f1, const AbstractMetaFunctionCPtr &f2) @@ -368,8 +426,8 @@ void AbstractMetaBuilderPrivate::sortLists() // this is a temporary solution before new type revision implementation // We need move QMetaObject register before QObject. Dependencies additionalDependencies; - if (auto qObjectClass = AbstractMetaClass::findClass(m_metaClasses, QStringLiteral("QObject"))) { - if (auto qMetaObjectClass = AbstractMetaClass::findClass(m_metaClasses, QStringLiteral("QMetaObject"))) { + if (auto qObjectClass = AbstractMetaClass::findClass(m_metaClasses, "QObject")) { + if (auto qMetaObjectClass = AbstractMetaClass::findClass(m_metaClasses, "QMetaObject")) { Dependency dependency; dependency.parent = qMetaObjectClass; dependency.child = qObjectClass; @@ -378,7 +436,7 @@ void AbstractMetaBuilderPrivate::sortLists() } m_metaClasses = classesTopologicalSorted(m_metaClasses, additionalDependencies); - for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) + for (const auto &cls : std::as_const(m_metaClasses)) cls->sortFunctions(); // Ensure that indexes are in alphabetical order, roughly, except @@ -395,7 +453,7 @@ FileModelItem AbstractMetaBuilderPrivate::buildDom(QByteArrayList arguments, unsigned clangFlags) { clang::Builder builder; - builder.setSystemIncludes(TypeDatabase::instance()->systemIncludes()); + builder.setForceProcessSystemIncludes(TypeDatabase::instance()->forceProcessSystemIncludes()); if (addCompilerSupportArguments) { if (level == LanguageLevel::Default) level = clang::emulatedCompilerLanguageLevel(); @@ -406,18 +464,35 @@ FileModelItem AbstractMetaBuilderPrivate::buildDom(QByteArrayList arguments, clangFlags, builder) ? builder.dom() : FileModelItem(); const clang::BaseVisitor::Diagnostics &diagnostics = builder.diagnostics(); - if (const int diagnosticsCount = diagnostics.size()) { + if (const auto diagnosticsCount = diagnostics.size()) { QDebug d = qWarning(); d.nospace(); d.noquote(); d << "Clang: " << diagnosticsCount << " diagnostic messages:\n"; - for (int i = 0; i < diagnosticsCount; ++i) + for (qsizetype i = 0; i < diagnosticsCount; ++i) d << " " << diagnostics.at(i) << '\n'; } return result; } -void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) +// List of candidates for a mismatched added global function. +static QStringList functionCandidates(const AbstractMetaFunctionCList &list, + const QString &signature) +{ + QString name = signature; + const auto parenPos = name.indexOf(u'('); + if (parenPos > 0) + name.truncate(parenPos); + QStringList result; + for (const auto &func : list) { + if (name == func->name()) + result += func->minimalSignature(); + } + return result; +} + +void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom, + ApiExtractorFlags flags) { const TypeDatabase *types = TypeDatabase::instance(); @@ -426,18 +501,18 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) // Start the generation... const ClassList &typeValues = dom->classes(); - ReportHandler::startProgress("Generating class model (" - + QByteArray::number(typeValues.size()) + ")..."); + ReportHandler::startProgress("Generated class model (" + + QByteArray::number(typeValues.size()) + ")."); for (const ClassModelItem &item : typeValues) { - if (AbstractMetaClass *cls = traverseClass(dom, item, nullptr)) - addAbstractMetaClass(cls, item.data()); + if (const auto cls = traverseClass(dom, item, nullptr)) + addAbstractMetaClass(cls, item.get()); } // We need to know all global enums const EnumList &enums = dom->enums(); - ReportHandler::startProgress("Generating enum model (" - + QByteArray::number(enums.size()) + ")..."); + ReportHandler::startProgress("Generated enum model (" + + QByteArray::number(enums.size()) + ")."); for (const EnumModelItem &item : enums) { auto metaEnum = traverseEnum(item, nullptr, QSet<QString>()); if (metaEnum.has_value()) { @@ -447,19 +522,19 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) } const auto &namespaceTypeValues = dom->namespaces(); - ReportHandler::startProgress("Generating namespace model (" - + QByteArray::number(namespaceTypeValues.size()) + ")..."); + ReportHandler::startProgress("Generated namespace model (" + + QByteArray::number(namespaceTypeValues.size()) + ")."); for (const NamespaceModelItem &item : namespaceTypeValues) traverseNamespace(dom, item); // Go through all typedefs to see if we have defined any // specific typedefs to be used as classes. const TypeDefList typeDefs = dom->typeDefs(); - ReportHandler::startProgress("Resolving typedefs (" - + QByteArray::number(typeDefs.size()) + ")..."); + ReportHandler::startProgress("Resolved typedefs (" + + QByteArray::number(typeDefs.size()) + ")."); for (const TypeDefModelItem &typeDef : typeDefs) { - if (AbstractMetaClass *cls = traverseTypeDef(dom, typeDef, nullptr)) - addAbstractMetaClass(cls, typeDef.data()); + if (const auto cls = traverseTypeDef(dom, typeDef, nullptr)) + addAbstractMetaClass(cls, typeDef.get()); } traverseTypesystemTypedefs(); @@ -473,10 +548,10 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) // Global functions const FunctionList &functions = dom->functions(); for (const FunctionModelItem &func : functions) { - if (func->accessPolicy() != Access::Public || func->name().startsWith(QLatin1String("operator"))) + if (func->accessPolicy() != Access::Public || func->name().startsWith(u"operator")) continue; - FunctionTypeEntry *funcEntry = types->findFunctionType(func->name()); + FunctionTypeEntryPtr funcEntry = types->findFunctionType(func->name()); if (!funcEntry || !funcEntry->generateCode()) continue; @@ -490,14 +565,15 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) metaFunc->setTypeEntry(funcEntry); applyFunctionModifications(metaFunc); + metaFunc->applyTypeModifications(); setInclude(funcEntry, func->fileName()); m_globalFunctions << metaFuncPtr; } - ReportHandler::startProgress("Fixing class inheritance..."); - for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) { + ReportHandler::startProgress("Fixed class inheritance."); + for (const auto &cls : std::as_const(m_metaClasses)) { if (cls->needsInheritanceSetup()) { setupInheritance(cls); traverseUsingMembers(cls); @@ -509,26 +585,28 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) } } - ReportHandler::startProgress("Detecting inconsistencies in class model..."); - for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) { - cls->fixFunctions(); + ReportHandler::startProgress("Checked for inconsistencies in class model."); + for (const auto &cls : std::as_const(m_metaClasses)) { + AbstractMetaClass::fixFunctions(cls); if (cls->canAddDefaultConstructor()) - cls->addDefaultConstructor(); + AbstractMetaClass::addDefaultConstructor(cls); if (cls->canAddDefaultCopyConstructor()) - cls->addDefaultCopyConstructor(); + AbstractMetaClass::addDefaultCopyConstructor(cls); - const bool vco = AbstractMetaClass::determineValueTypeWithCopyConstructorOnly(cls); + const bool avoidProtectedHack = flags.testFlag(ApiExtractorFlag::AvoidProtectedHack); + const bool vco = + AbstractMetaClass::determineValueTypeWithCopyConstructorOnly(cls, avoidProtectedHack); cls->setValueTypeWithCopyConstructorOnly(vco); cls->typeEntry()->setValueTypeWithCopyConstructorOnly(vco); } const auto &allEntries = types->entries(); - ReportHandler::startProgress("Detecting inconsistencies in typesystem (" - + QByteArray::number(allEntries.size()) + ")..."); + ReportHandler::startProgress("Checked for inconsistencies in typesystem (" + + QByteArray::number(allEntries.size()) + ")."); for (auto it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) { - TypeEntry *entry = it.value(); + const TypeEntryPtr &entry = it.value(); if (!entry->isPrimitive()) { if ((entry->isValue() || entry->isObject()) && !types->shouldDropTypeEntry(entry->qualifiedCppName()) @@ -538,25 +616,27 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) && !AbstractMetaClass::findClass(m_metaClasses, entry)) { qCWarning(lcShiboken, "%s", qPrintable(msgTypeNotDefined(entry))); } else if (entry->generateCode() && entry->type() == TypeEntry::FunctionType) { - auto fte = static_cast<const FunctionTypeEntry *>(entry); + auto fte = std::static_pointer_cast<const FunctionTypeEntry>(entry); const QStringList &signatures = fte->signatures(); for (const QString &signature : signatures) { bool ok = false; - for (const auto &func : qAsConst(m_globalFunctions)) { + for (const auto &func : std::as_const(m_globalFunctions)) { if (signature == func->minimalSignature()) { ok = true; break; } } if (!ok) { + const QStringList candidates = functionCandidates(m_globalFunctions, + signatures.constFirst()); qCWarning(lcShiboken, "%s", - qPrintable(msgGlobalFunctionNotDefined(fte, signature))); + qPrintable(msgGlobalFunctionNotDefined(fte, signature, candidates))); } } } else if (entry->isEnum() && entry->generateCode()) { - auto enumEntry = static_cast<const EnumTypeEntry *>(entry); - AbstractMetaClass *cls = AbstractMetaClass::findClass(m_metaClasses, - enumEntry->parent()); + const auto enumEntry = std::static_pointer_cast<const EnumTypeEntry>(entry); + const auto cls = AbstractMetaClass::findClass(m_metaClasses, + enumEntry->parent()); const bool enumFound = cls ? cls->findEnum(entry->targetLangEntryName()).has_value() @@ -573,7 +653,7 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) } { - const FunctionList &hashFunctions = dom->findFunctions(QLatin1String("qHash")); + const FunctionList &hashFunctions = dom->findFunctions("qHash"); for (const FunctionModelItem &item : hashFunctions) registerHashFunction(item, nullptr); } @@ -596,16 +676,15 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) } } - ReportHandler::startProgress("Checking inconsistencies in function modifications..."); + ReportHandler::startProgress("Checked for inconsistencies in function modifications."); checkFunctionModifications(); - ReportHandler::startProgress("Writing log files..."); + ReportHandler::startProgress("Wrote log files."); - for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) { + for (const auto &cls : std::as_const(m_metaClasses)) { // setupEquals(cls); // setupComparable(cls); - setupClonable(cls); setupExternalConversion(cls); // sort all inner classes topologically @@ -615,6 +694,8 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) cls->setInnerClasses(classesTopologicalSorted(cls->innerClasses())); } + fixSmartPointers(); + dumpLog(); sortLists(); @@ -627,25 +708,29 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) throw Exception(errorMessage); } - m_itemToClass.clear(); - m_classToItem.clear(); - m_typeSystemTypeDefs.clear(); + if (!m_codeModelTestMode) { + m_itemToClass.clear(); + m_classToItem.clear(); + m_typeSystemTypeDefs.clear(); + m_scopes.clear(); + } ReportHandler::endProgress(); } bool AbstractMetaBuilder::build(const QByteArrayList &arguments, + ApiExtractorFlags apiExtractorFlags, bool addCompilerSupportArguments, LanguageLevel level, unsigned clangFlags) { const FileModelItem dom = d->buildDom(arguments, addCompilerSupportArguments, level, clangFlags); - if (dom.isNull()) + if (!dom) return false; if (ReportHandler::isDebug(ReportHandler::MediumDebug)) - qCDebug(lcShiboken) << dom.data(); - d->traverseDom(dom); + qCDebug(lcShiboken) << dom.get(); + d->traverseDom(dom, apiExtractorFlags); return true; } @@ -657,7 +742,7 @@ void AbstractMetaBuilder::setLogDirectory(const QString &logDir) d->m_logDirectory.append(QDir::separator()); } -void AbstractMetaBuilderPrivate::addAbstractMetaClass(AbstractMetaClass *cls, +void AbstractMetaBuilderPrivate::addAbstractMetaClass(const AbstractMetaClassPtr &cls, const _CodeModelItem *item) { m_itemToClass.insert(item, cls); @@ -671,23 +756,27 @@ void AbstractMetaBuilderPrivate::addAbstractMetaClass(AbstractMetaClass *cls, } } -AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModelItem &dom, - const NamespaceModelItem &namespaceItem) +AbstractMetaClassPtr + AbstractMetaBuilderPrivate::traverseNamespace(const FileModelItem &dom, + const NamespaceModelItem &namespaceItem) { - QString namespaceName = currentScope()->qualifiedName().join(colonColon()); + QString namespaceName = currentScope()->qualifiedName().join(u"::"_s); if (!namespaceName.isEmpty()) - namespaceName.append(colonColon()); + namespaceName.append(u"::"_s); namespaceName.append(namespaceItem->name()); if (TypeDatabase::instance()->isClassRejected(namespaceName)) { - m_rejectedClasses.insert(namespaceName, AbstractMetaBuilder::GenerationDisabled); - return nullptr; + m_rejectedClasses.insert({AbstractMetaBuilder::GenerationDisabled, + namespaceName, namespaceName, QString{}}); + return {}; } auto type = TypeDatabase::instance()->findNamespaceType(namespaceName, namespaceItem->fileName()); if (!type) { - qCWarning(lcShiboken, "%s", - qPrintable(msgNamespaceNoTypeEntry(namespaceItem, namespaceName))); + const QString rejectReason = msgNamespaceNoTypeEntry(namespaceItem, namespaceName); + qCWarning(lcShiboken, "%s", qPrintable(rejectReason)); + m_rejectedClasses.insert({AbstractMetaBuilder::GenerationDisabled, + namespaceName, namespaceName, rejectReason}); return nullptr; } @@ -697,22 +786,22 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModel } // Continue populating namespace? - AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_metaClasses, type); + AbstractMetaClassPtr metaClass = AbstractMetaClass::findClass(m_metaClasses, type); if (!metaClass) { - metaClass = new AbstractMetaClass; + metaClass.reset(new AbstractMetaClass); metaClass->setTypeEntry(type); - addAbstractMetaClass(metaClass, namespaceItem.data()); + addAbstractMetaClass(metaClass, namespaceItem.get()); if (auto extendsType = type->extends()) { - AbstractMetaClass *extended = AbstractMetaClass::findClass(m_metaClasses, extendsType); + const auto extended = AbstractMetaClass::findClass(m_metaClasses, extendsType); if (!extended) { qCWarning(lcShiboken, "%s", qPrintable(msgNamespaceToBeExtendedNotFound(extendsType->name(), extendsType->targetLangPackage()))); - return nullptr; + return {}; } metaClass->setExtendedNamespace(extended); } } else { - m_itemToClass.insert(namespaceItem.data(), metaClass); + m_itemToClass.insert(namespaceItem.get(), metaClass); } traverseEnums(namespaceItem, metaClass, namespaceItem->enumsDeclarations()); @@ -721,11 +810,11 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModel const ClassList &classes = namespaceItem->classes(); for (const ClassModelItem &cls : classes) { - AbstractMetaClass *mjc = traverseClass(dom, cls, metaClass); + const auto mjc = traverseClass(dom, cls, metaClass); if (mjc) { metaClass->addInnerClass(mjc); mjc->setEnclosingClass(metaClass); - addAbstractMetaClass(mjc, cls.data()); + addAbstractMetaClass(mjc, cls.get()); } } @@ -733,20 +822,22 @@ 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, metaClass); + const auto cls = traverseTypeDef(dom, typeDef, metaClass); if (cls) { metaClass->addInnerClass(cls); cls->setEnclosingClass(metaClass); - addAbstractMetaClass(cls, typeDef.data()); + addAbstractMetaClass(cls, typeDef.get()); } } // Traverse namespaces recursively for (const NamespaceModelItem &ni : namespaceItem->namespaces()) { - AbstractMetaClass *mjc = traverseNamespace(dom, ni); + const auto mjc = traverseNamespace(dom, ni); if (mjc) { metaClass->addInnerClass(mjc); mjc->setEnclosingClass(metaClass); + m_classToItem.insert(mjc, ni.get()); // Add for enum lookup. + m_itemToClass.insert(ni.get(), mjc); } } @@ -760,16 +851,16 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModel std::optional<AbstractMetaEnum> AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem &enumItem, - AbstractMetaClass *enclosing, + const AbstractMetaClassPtr &enclosing, const QSet<QString> &enumsDeclarations) { - QString qualifiedName = enumItem->qualifiedName().join(colonColon()); + QString qualifiedName = enumItem->qualifiedName().join(u"::"_s); - TypeEntry *typeEntry = nullptr; - const TypeEntry *enclosingTypeEntry = enclosing ? enclosing->typeEntry() : nullptr; + TypeEntryPtr typeEntry; + const auto enclosingTypeEntry = enclosing ? enclosing->typeEntry() : TypeEntryCPtr{}; if (enumItem->accessPolicy() == Access::Private) { - typeEntry = new EnumTypeEntry(enumItem->qualifiedName().constLast(), - QVersionNumber(0, 0), enclosingTypeEntry); + typeEntry.reset(new EnumTypeEntry(enumItem->qualifiedName().constLast(), + QVersionNumber(0, 0), enclosingTypeEntry)); TypeDatabase::instance()->addType(typeEntry); } else if (enumItem->enumKind() != AnonymousEnum) { typeEntry = TypeDatabase::instance()->findType(qualifiedName); @@ -779,7 +870,7 @@ std::optional<AbstractMetaEnum> for (const EnumeratorModelItem &enumValue : enums) { tmpQualifiedName.removeLast(); tmpQualifiedName << enumValue->name(); - qualifiedName = tmpQualifiedName.join(colonColon()); + qualifiedName = tmpQualifiedName.join(u"::"_s); typeEntry = TypeDatabase::instance()->findType(qualifiedName); if (typeEntry) break; @@ -796,65 +887,75 @@ std::optional<AbstractMetaEnum> if (TypeDatabase::instance()->isEnumRejected(className, enumName, &rejectReason)) { if (typeEntry) typeEntry->setCodeGeneration(TypeEntry::GenerateNothing); - m_rejectedEnums.insert(qualifiedName + rejectReason, AbstractMetaBuilder::GenerationDisabled); + m_rejectedEnums.insert({AbstractMetaBuilder::GenerationDisabled, qualifiedName, + qualifiedName, rejectReason}); return {}; } const bool rejectionWarning = !enclosing || enclosing->typeEntry()->generateCode(); if (!typeEntry) { + const QString rejectReason = msgNoEnumTypeEntry(enumItem, className); if (rejectionWarning) - qCWarning(lcShiboken, "%s", qPrintable(msgNoEnumTypeEntry(enumItem, className))); - m_rejectedEnums.insert(qualifiedName, AbstractMetaBuilder::NotInTypeSystem); + qCWarning(lcShiboken, "%s", qPrintable(rejectReason)); + m_rejectedEnums.insert({AbstractMetaBuilder::NotInTypeSystem, qualifiedName, + qualifiedName, rejectReason}); return {}; } if (!typeEntry->isEnum()) { - if (rejectionWarning) { - qCWarning(lcShiboken, "%s", - qPrintable(msgNoEnumTypeConflict(enumItem, className, typeEntry))); - } - m_rejectedEnums.insert(qualifiedName, AbstractMetaBuilder::NotInTypeSystem); + const QString rejectReason = msgNoEnumTypeConflict(enumItem, className, typeEntry); + if (rejectionWarning) + qCWarning(lcShiboken, "%s", qPrintable(rejectReason)); + m_rejectedEnums.insert({AbstractMetaBuilder::NotInTypeSystem, qualifiedName, + qualifiedName, rejectReason}); return {}; } AbstractMetaEnum metaEnum; metaEnum.setEnumKind(enumItem->enumKind()); + metaEnum.setDeprecated(enumItem->isDeprecated()); + metaEnum.setUnderlyingType(enumItem->underlyingType()); metaEnum.setSigned(enumItem->isSigned()); if (enumsDeclarations.contains(qualifiedName) || enumsDeclarations.contains(enumName)) { metaEnum.setHasQEnumsDeclaration(true); } - auto *enumTypeEntry = static_cast<EnumTypeEntry *>(typeEntry); + auto enumTypeEntry = std::static_pointer_cast<EnumTypeEntry>(typeEntry); metaEnum.setTypeEntry(enumTypeEntry); metaEnum.setAccess(enumItem->accessPolicy()); if (metaEnum.access() == Access::Private) typeEntry->setCodeGeneration(TypeEntry::GenerateNothing); - + // PYSIDE-2088, MSVC signedness issue in Qt + const bool castToUnsigned = enumItem->isSigned() + && enumTypeEntry->cppType().contains(u"unsigned"_s); const EnumeratorList &enums = enumItem->enumerators(); - for (const EnumeratorModelItem &value : enums) { + for (const EnumeratorModelItem &valueItem : enums) { AbstractMetaEnumValue metaEnumValue; - metaEnumValue.setName(value->name()); + metaEnumValue.setName(valueItem->name()); // Deciding the enum value... - metaEnumValue.setStringValue(value->stringValue()); - metaEnumValue.setValue(value->value()); + metaEnumValue.setStringValue(valueItem->stringValue()); + const auto value = valueItem->value(); + metaEnumValue.setValue(castToUnsigned ? value.toUnsigned() : value); + metaEnumValue.setDeprecated(valueItem->isDeprecated()); metaEnum.addEnumValue(metaEnumValue); } - if (!metaEnum.typeEntry()->include().isValid()) - setInclude(metaEnum.typeEntry(), enumItem->fileName()); + if (!metaEnum.typeEntry()->include().isValid()) { + auto te = std::const_pointer_cast<EnumTypeEntry>(metaEnum.typeEntry()); + setInclude(te, enumItem->fileName()); + } // Register all enum values on Type database const bool isScopedEnum = enumItem->enumKind() == EnumClass; const EnumeratorList &enumerators = enumItem->enumerators(); for (const EnumeratorModelItem &e : enumerators) { - auto enumValue = - new EnumValueTypeEntry(e->name(), e->stringValue(), - enumTypeEntry, isScopedEnum, - enumTypeEntry->version()); + auto enumValue = std::make_shared<EnumValueTypeEntry>(e->name(), e->stringValue(), + enumTypeEntry, isScopedEnum, + enumTypeEntry->version()); TypeDatabase::instance()->addType(enumValue); if (e->value().isNullValue()) enumTypeEntry->setNullValue(enumValue); @@ -866,9 +967,31 @@ std::optional<AbstractMetaEnum> return metaEnum; } -AbstractMetaClass *AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelItem &, - const TypeDefModelItem &typeDef, - AbstractMetaClass *currentClass) +AbstractMetaClassPtr + AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelItem &dom, + const TypeDefModelItem &typeDef, + const AbstractMetaClassPtr ¤tClass) +{ + auto result = traverseTypeDefHelper(dom, typeDef, currentClass); + if (!result && typeDef->type().isPlain()) { + const auto &type = typeDef->type(); + QString fullName; + if (currentClass) + fullName += currentClass->qualifiedCppName() + "::"_L1; + fullName += typeDef->name(); + QString targetName = typeDef->type().toString(); + m_typedefTargetToName.insert(targetName, fullName); + const QByteArray normalized = QMetaObject::normalizedType(targetName.toUtf8().constData()); + if (targetName != QLatin1StringView(normalized)) + m_typedefTargetToName.insert(QString::fromUtf8(normalized), fullName); + } + return result; +} + +AbstractMetaClassPtr + AbstractMetaBuilderPrivate::traverseTypeDefHelper(const FileModelItem &, + const TypeDefModelItem &typeDef, + const AbstractMetaClassPtr ¤tClass) { TypeDatabase *types = TypeDatabase::instance(); QString className = stripTemplateArgs(typeDef->name()); @@ -877,26 +1000,39 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelIt // we have an inner class if (currentClass) { fullClassName = stripTemplateArgs(currentClass->typeEntry()->qualifiedCppName()) - + colonColon() + fullClassName; + + u"::"_s + fullClassName; } // If this is the alias for a primitive type // we store the aliased type on the alias // TypeEntry - PrimitiveTypeEntry *ptype = types->findPrimitiveType(className); + const auto ptype = types->findPrimitiveType(className); + const auto &targetNames = typeDef->type().qualifiedName(); + const auto pTarget = targetNames.size() == 1 + ? types->findPrimitiveType(targetNames.constFirst()) : PrimitiveTypeEntryPtr{}; if (ptype) { - QString typeDefName = typeDef->type().qualifiedName()[0]; - ptype->setReferencedTypeEntry(types->findPrimitiveType(typeDefName)); + ptype->setReferencedTypeEntry(pTarget); return nullptr; } + // It is a (nested?) global typedef to a primitive type + // (like size_t = unsigned)? Add it to the type DB. + if (pTarget && isCppPrimitive(basicReferencedNonBuiltinTypeEntry(pTarget)) + && currentClass == nullptr) { + auto pte = std::make_shared<PrimitiveTypeEntry>(className, QVersionNumber{}, + TypeEntryCPtr{}); + pte->setReferencedTypeEntry(pTarget); + pte->setBuiltIn(true); + types->addType(pte); + return nullptr; + } // If we haven't specified anything for the typedef, then we don't care - ComplexTypeEntry *type = types->findComplexType(fullClassName); + auto type = types->findComplexType(fullClassName); if (!type) return nullptr; - auto *metaClass = new AbstractMetaClass; + auto metaClass = std::make_shared<AbstractMetaClass>(); metaClass->setTypeDef(true); metaClass->setTypeEntry(type); metaClass->setBaseClassNames(QStringList(typeDef->type().toString())); @@ -915,8 +1051,8 @@ void AbstractMetaBuilderPrivate::traverseTypesystemTypedefs() { const auto &entries = TypeDatabase::instance()->typedefEntries(); for (auto it = entries.begin(), end = entries.end(); it != end; ++it) { - TypedefEntry *te = it.value(); - auto *metaClass = new AbstractMetaClass; + const TypedefEntryPtr &te = it.value(); + auto metaClass = std::make_shared<AbstractMetaClass>(); metaClass->setTypeDef(true); metaClass->setTypeEntry(te->target()); metaClass->setBaseClassNames(QStringList(te->sourceType())); @@ -942,9 +1078,9 @@ void AbstractMetaBuilderPrivate::traverseTypesystemTypedefs() } } -AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem &dom, +AbstractMetaClassPtr AbstractMetaBuilderPrivate::traverseClass(const FileModelItem &dom, const ClassModelItem &classItem, - AbstractMetaClass *currentClass) + const AbstractMetaClassPtr ¤tClass) { QString className = stripTemplateArgs(classItem->name()); QString fullClassName = className; @@ -952,20 +1088,24 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem // we have inner an class if (currentClass) { fullClassName = stripTemplateArgs(currentClass->typeEntry()->qualifiedCppName()) - + colonColon() + fullClassName; + + u"::"_s + fullClassName; } - ComplexTypeEntry *type = TypeDatabase::instance()->findComplexType(fullClassName); + const auto type = TypeDatabase::instance()->findComplexType(fullClassName); AbstractMetaBuilder::RejectReason reason = AbstractMetaBuilder::NoReason; if (TypeDatabase::instance()->isClassRejected(fullClassName)) { reason = AbstractMetaBuilder::GenerationDisabled; } else if (!type) { - TypeEntry *te = TypeDatabase::instance()->findType(fullClassName); - if (te && !te->isComplex()) + TypeEntryPtr te = TypeDatabase::instance()->findType(fullClassName); + if (te && !te->isComplex()) { reason = AbstractMetaBuilder::RedefinedToNotClass; - else + // Set the default include file name + if (!te->include().isValid()) + setInclude(te, classItem->fileName()); + } else { reason = AbstractMetaBuilder::NotInTypeSystem; + } } else if (type->codeGeneration() == TypeEntry::GenerateNothing) { reason = AbstractMetaBuilder::GenerationDisabled; } @@ -974,11 +1114,11 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem QTextStream(&fullClassName) << "anonymous struct at " << classItem->fileName() << ':' << classItem->startLine(); } - m_rejectedClasses.insert(fullClassName, reason); + m_rejectedClasses.insert({reason, fullClassName, fullClassName, QString{}}); return nullptr; } - auto *metaClass = new AbstractMetaClass; + auto metaClass = std::make_shared<AbstractMetaClass>(); metaClass->setSourceLocation(classItem->sourceLocation()); metaClass->setTypeEntry(type); if ((type->typeFlags() & ComplexTypeEntry::ForceAbstract) != 0) @@ -987,6 +1127,9 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem if (classItem->isFinal()) *metaClass += AbstractMetaClass::FinalCppClass; + if (classItem->classType() == CodeModel::Struct) + *metaClass += AbstractMetaClass::Struct; + QStringList baseClassNames; const QList<_ClassModelItem::BaseClass> &baseClasses = classItem->baseClasses(); for (const _ClassModelItem::BaseClass &baseClass : baseClasses) { @@ -1000,21 +1143,22 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem if (ReportHandler::isDebug(ReportHandler::MediumDebug)) { const QString message = type->isContainer() - ? u"container: '"_qs + fullClassName + u'\'' - : u"class: '"_qs + metaClass->fullName() + u'\''; + ? u"container: '"_s + fullClassName + u'\'' + : u"class: '"_s + metaClass->fullName() + u'\''; qCInfo(lcShiboken, "%s", qPrintable(message)); } TemplateParameterList template_parameters = classItem->templateParameters(); - TypeEntries template_args; + TypeEntryCList template_args; template_args.clear(); - auto argumentParent = metaClass->typeEntry()->typeSystemTypeEntry(); - for (int i = 0; i < template_parameters.size(); ++i) { + auto argumentParent = typeSystemTypeEntry(metaClass->typeEntry()); + for (qsizetype i = 0; i < template_parameters.size(); ++i) { const TemplateParameterModelItem ¶m = template_parameters.at(i); - auto param_type = new TemplateArgumentEntry(param->name(), type->version(), + auto param_type = + std::make_shared<TemplateArgumentEntry>(param->name(), type->version(), argumentParent); param_type->setOrdinal(i); - template_args.append(param_type); + template_args.append(TypeEntryCPtr(param_type)); } metaClass->setTemplateArguments(template_args); @@ -1026,11 +1170,11 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem { const ClassList &innerClasses = classItem->classes(); for (const ClassModelItem &ci : innerClasses) { - AbstractMetaClass *cl = traverseClass(dom, ci, metaClass); + const auto cl = traverseClass(dom, ci, metaClass); if (cl) { cl->setEnclosingClass(metaClass); metaClass->addInnerClass(cl); - addAbstractMetaClass(cl, ci.data()); + addAbstractMetaClass(cl, ci.get()); } } @@ -1040,10 +1184,10 @@ 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, metaClass); + const auto cls = traverseTypeDef(dom, typeDef, metaClass); if (cls) { cls->setEnclosingClass(metaClass); - addAbstractMetaClass(cls, typeDef.data()); + addAbstractMetaClass(cls, typeDef.get()); } } @@ -1055,7 +1199,7 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem } void AbstractMetaBuilderPrivate::traverseScopeMembers(const ScopeModelItem &item, - AbstractMetaClass *metaClass) + const AbstractMetaClassPtr &metaClass) { // Classes/Namespace members traverseFields(item, metaClass); @@ -1069,28 +1213,25 @@ void AbstractMetaBuilderPrivate::traverseScopeMembers(const ScopeModelItem &item void AbstractMetaBuilderPrivate::traverseClassMembers(const ClassModelItem &item) { - AbstractMetaClass *metaClass = m_itemToClass.value(item.data()); - if (!metaClass) - return; - - // Class members - traverseScopeMembers(item, metaClass); + const auto metaClass = m_itemToClass.value(item.get()); + if (metaClass) // Class members + traverseScopeMembers(item, metaClass); } -void AbstractMetaBuilderPrivate::traverseUsingMembers(AbstractMetaClass *metaClass) +void AbstractMetaBuilderPrivate::traverseUsingMembers(const AbstractMetaClassPtr &metaClass) const { const _CodeModelItem *item = m_classToItem.value(metaClass); if (item == nullptr || item->kind() != _CodeModelItem::Kind_Class) return; - auto classItem = static_cast<const _ClassModelItem *>(item); + const auto *classItem = static_cast<const _ClassModelItem *>(item); for (const auto &um : classItem->usingMembers()) { QString className = um.className; - int pos = className.indexOf(u'<'); // strip "QList<value>" + auto pos = className.indexOf(u'<'); // strip "QList<value>" if (pos != -1) className.truncate(pos); - if (auto baseClass = metaClass->AbstractMetaClass::findBaseClass(className)) { + if (auto baseClass = findBaseClass(metaClass, className)) { QString name = um.memberName; - const int lastQualPos = name.lastIndexOf(colonColon()); + const auto lastQualPos = name.lastIndexOf(u"::"_s); if (lastQualPos != -1) name.remove(0, lastQualPos + 2); metaClass->addUsingMember({name, baseClass, um.access}); @@ -1104,7 +1245,7 @@ void AbstractMetaBuilderPrivate::traverseUsingMembers(AbstractMetaClass *metaCla void AbstractMetaBuilderPrivate::traverseNamespaceMembers(const NamespaceModelItem &item) { - AbstractMetaClass *metaClass = m_itemToClass.value(item.data()); + const auto metaClass = m_itemToClass.value(item.get()); if (!metaClass) return; @@ -1119,18 +1260,18 @@ void AbstractMetaBuilderPrivate::traverseNamespaceMembers(const NamespaceModelIt static inline QString fieldSignatureWithType(const VariableModelItem &field) { - return field->name() + QStringLiteral(" -> ") + field->type().toString(); + return field->name() + " -> "_L1 + field->type().toString(); } static inline QString qualifiedFieldSignatureWithType(const QString &className, const VariableModelItem &field) { - return className + colonColon() + fieldSignatureWithType(field); + return className + u"::"_s + fieldSignatureWithType(field); } std::optional<AbstractMetaField> AbstractMetaBuilderPrivate::traverseField(const VariableModelItem &field, - const AbstractMetaClass *cls) + const AbstractMetaClassCPtr &cls) { QString fieldName = field->name(); QString className = cls->typeEntry()->qualifiedCppName(); @@ -1144,8 +1285,9 @@ std::optional<AbstractMetaField> QString rejectReason; if (TypeDatabase::instance()->isFieldRejected(className, fieldName, &rejectReason)) { - m_rejectedFields.insert(qualifiedFieldSignatureWithType(className, field) + rejectReason, - AbstractMetaBuilder::GenerationDisabled); + const QString signature = qualifiedFieldSignatureWithType(className, field); + m_rejectedFields.insert({AbstractMetaBuilder::GenerationDisabled, + signature, signature, rejectReason}); return {}; } @@ -1158,7 +1300,7 @@ std::optional<AbstractMetaField> auto metaType = translateType(fieldType, cls); if (!metaType.has_value()) { - const QString type = TypeInfo::resolveType(fieldType, currentScope()).qualifiedName().join(colonColon()); + const QString type = TypeInfo::resolveType(fieldType, currentScope()).qualifiedName().join(u"::"_s); if (cls->typeEntry()->generateCode()) { qCWarning(lcShiboken, "%s", qPrintable(msgSkippingField(field, cls->name(), type))); @@ -1193,7 +1335,7 @@ static bool applyFieldModifications(AbstractMetaField *f) } void AbstractMetaBuilderPrivate::traverseFields(const ScopeModelItem &scope_item, - AbstractMetaClass *metaClass) + const AbstractMetaClassPtr &metaClass) { const VariableList &variables = scope_item->variables(); for (const VariableModelItem &field : variables) { @@ -1206,37 +1348,22 @@ void AbstractMetaBuilderPrivate::traverseFields(const ScopeModelItem &scope_item } } -void AbstractMetaBuilderPrivate::setupFunctionDefaults(AbstractMetaFunction *metaFunction, - AbstractMetaClass *metaClass) -{ - // Set the default value of the declaring class. This may be changed - // in fixFunctions later on - metaFunction->setDeclaringClass(metaClass); - - // Some of the queries below depend on the implementing class being set - // to function properly. Such as function modifications - metaFunction->setImplementingClass(metaClass); - - if (metaFunction->name() == QLatin1String("operator_equal")) - metaClass->setHasEqualsOperator(true); -} - void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaFunction *metaFunction) { if (!metaFunction->isConversionOperator()) return; TypeDatabase *types = TypeDatabase::instance(); - static const QRegularExpression operatorRegExp(QStringLiteral("^operator ")); + static const QRegularExpression operatorRegExp("^operator "_L1); Q_ASSERT(operatorRegExp.isValid()); QString castTo = metaFunction->name().remove(operatorRegExp).trimmed(); - if (castTo.endsWith(QLatin1Char('&'))) + if (castTo.endsWith(u'&')) castTo.chop(1); - if (castTo.startsWith(QLatin1String("const "))) + if (castTo.startsWith(u"const ")) castTo.remove(0, 6); - TypeEntry *retType = types->findType(castTo); + TypeEntryPtr retType = types->findType(castTo); if (!retType) return; @@ -1248,16 +1375,22 @@ void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaF AbstractMetaFunctionRawPtrList AbstractMetaBuilderPrivate::classFunctionList(const ScopeModelItem &scopeItem, AbstractMetaClass::Attributes *constructorAttributes, - AbstractMetaClass *currentClass) + const AbstractMetaClassPtr ¤tClass) { *constructorAttributes = {}; AbstractMetaFunctionRawPtrList result; const FunctionList &scopeFunctionList = scopeItem->functions(); result.reserve(scopeFunctionList.size()); + const bool isNamespace = currentClass->isNamespace(); for (const FunctionModelItem &function : scopeFunctionList) { - if (AbstractMetaFunction *metaFunction = traverseFunction(function, currentClass)) { + if (isNamespace && function->isOperator()) { + traverseOperatorFunction(function, currentClass); + } else if (function->isSpaceshipOperator() && !function->isDeleted()) { + if (currentClass) + AbstractMetaClass::addSynthesizedComparisonOperators(currentClass); + } else if (auto *metaFunction = traverseFunction(function, currentClass)) { result.append(metaFunction); - } else if (function->functionType() == CodeModel::Constructor) { + } else if (!function->isDeleted() && function->functionType() == CodeModel::Constructor) { auto arguments = function->arguments(); *constructorAttributes |= AbstractMetaClass::HasRejectedConstructor; if (arguments.isEmpty() || arguments.constFirst()->defaultValue()) @@ -1267,8 +1400,8 @@ AbstractMetaFunctionRawPtrList return result; } -void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, - AbstractMetaClass *metaClass) +void AbstractMetaBuilderPrivate::traverseFunctions(const ScopeModelItem& scopeItem, + const AbstractMetaClassPtr &metaClass) { AbstractMetaClass::Attributes constructorAttributes; const AbstractMetaFunctionRawPtrList functions = @@ -1277,7 +1410,7 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, for (AbstractMetaFunction *metaFunction : functions) { if (metaClass->isNamespace()) - *metaFunction += AbstractMetaFunction::Static; + metaFunction->setCppAttribute(FunctionAttribute::Static); const auto propertyFunction = metaClass->searchPropertyFunction(metaFunction->name()); if (propertyFunction.index >= 0) { @@ -1310,34 +1443,31 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, metaFunction->setPropertySpecIndex(propertyFunction.index); } break; + case AbstractMetaClass::PropertyFunction::Notify: + if (metaFunction->isSignal()) { + *metaFunction += AbstractMetaFunction::PropertyNotify; + metaFunction->setPropertySpecIndex(propertyFunction.index); + } } } - const bool isInvalidDestructor = metaFunction->isDestructor() && metaFunction->isPrivate(); - const bool isInvalidConstructor = metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction - && metaFunction->isPrivate(); - if (isInvalidConstructor) + if (metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction + && metaFunction->isPrivate()) { metaClass->setHasPrivateConstructor(true); - if ((isInvalidDestructor || isInvalidConstructor) - && !metaClass->hasNonPrivateConstructor()) { - *metaClass += AbstractMetaClass::FinalInTargetLang; - } else if (metaFunction->isConstructor() && !metaFunction->isPrivate()) { - *metaClass -= AbstractMetaClass::FinalInTargetLang; - metaClass->setHasNonPrivateConstructor(true); } + if (metaFunction->isConstructor() && !metaFunction->isPrivate()) // Including Copy CT + metaClass->setHasNonPrivateConstructor(true); if (!metaFunction->isDestructor() && !(metaFunction->isPrivate() && metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction)) { - setupFunctionDefaults(metaFunction, metaClass); - if (metaFunction->isSignal() && metaClass->hasSignal(metaFunction)) qCWarning(lcShiboken, "%s", qPrintable(msgSignalOverloaded(metaClass, metaFunction))); if (metaFunction->isConversionOperator()) fixReturnTypeOfConversionOperator(metaFunction); - metaClass->addFunction(AbstractMetaFunctionCPtr(metaFunction)); + AbstractMetaClass::addFunction(metaClass, AbstractMetaFunctionCPtr(metaFunction)); applyFunctionModifications(metaFunction); } else if (metaFunction->isDestructor()) { metaClass->setHasPrivateDestructor(metaFunction->isPrivate()); @@ -1353,7 +1483,7 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, fillAddedFunctions(metaClass); } -void AbstractMetaBuilderPrivate::fillAddedFunctions(AbstractMetaClass *metaClass) +void AbstractMetaBuilderPrivate::fillAddedFunctions(const AbstractMetaClassPtr &metaClass) { // Add the functions added by the typesystem QString errorMessage; @@ -1366,12 +1496,12 @@ void AbstractMetaBuilderPrivate::fillAddedFunctions(AbstractMetaClass *metaClass QString AbstractMetaBuilder::getSnakeCaseName(const QString &name) { - const int size = name.size(); + const auto size = name.size(); if (size < 3) return name; QString result; result.reserve(size + 4); - for (int i = 0; i < size; ++i) { + for (qsizetype i = 0; i < size; ++i) { const QChar c = name.at(i); if (c.isUpper()) { if (i > 0) { @@ -1417,26 +1547,17 @@ void AbstractMetaBuilderPrivate::applyFunctionModifications(AbstractMetaFunction func->setOriginalName(func->name()); func->setName(mod.renamedToName()); } else if (mod.isAccessModifier()) { - funcRef -= AbstractMetaFunction::Friendly; - if (mod.isPublic()) funcRef.modifyAccess(Access::Public); else if (mod.isProtected()) funcRef.modifyAccess(Access::Protected); else if (mod.isPrivate()) funcRef.modifyAccess(Access::Private); - else if (mod.isFriendly()) - funcRef += AbstractMetaFunction::Friendly; } - - if (mod.isFinal()) - funcRef += AbstractMetaFunction::FinalInTargetLang; - else if (mod.isNonFinal()) - funcRef -= AbstractMetaFunction::FinalInTargetLang; } } -bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass) +bool AbstractMetaBuilderPrivate::setupInheritance(const AbstractMetaClassPtr &metaClass) { if (metaClass->inheritanceDone()) return true; @@ -1446,13 +1567,15 @@ bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass) QStringList baseClasses = metaClass->baseClassNames(); // we only support our own containers and ONLY if there is only one baseclass - if (baseClasses.size() == 1 && baseClasses.constFirst().contains(QLatin1Char('<'))) { + if (baseClasses.size() == 1 && baseClasses.constFirst().contains(u'<')) { TypeInfo info; - ComplexTypeEntry* baseContainerType; - AbstractMetaClass* templ = findTemplateClass(baseClasses.constFirst(), metaClass, &info, &baseContainerType); + ComplexTypeEntryPtr baseContainerType; + const auto templ = findTemplateClass(baseClasses.constFirst(), metaClass, + &info, &baseContainerType); if (templ) { setupInheritance(templ); - inheritTemplate(metaClass, templ, info); + if (!inheritTemplate(metaClass, templ, info)) + return false; metaClass->typeEntry()->setBaseContainerType(templ->typeEntry()); return true; } @@ -1469,15 +1592,15 @@ bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass) return true; } - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("template baseclass '%1' of '%2' is not known") - .arg(baseClasses.constFirst(), metaClass->name()); + qCWarning(lcShiboken, "template baseclass '%s' of '%s' is not known", + qPrintable(baseClasses.constFirst()), + qPrintable(metaClass->name())); return false; } - TypeDatabase* types = TypeDatabase::instance(); + auto *types = TypeDatabase::instance(); - for (const auto &baseClassName : baseClasses) { + for (const auto &baseClassName : baseClasses) { if (!types->isClassRejected(baseClassName)) { auto typeEntry = types->findType(baseClassName); if (typeEntry == nullptr || !typeEntry->isComplex()) { @@ -1506,7 +1629,7 @@ bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass) } else { QString message; QTextStream(&message) << "Class \"" << defaultSuperclassName - << "\" specified as \"default-superclass\" of \"" << metaClass->name() + << R"(" specified as "default-superclass" of ")" << metaClass->name() << "\" could not be found in the code model."; qCWarning(lcShiboken, "%s", qPrintable(message)); } @@ -1516,7 +1639,7 @@ bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass) } void AbstractMetaBuilderPrivate::traverseEnums(const ScopeModelItem &scopeItem, - AbstractMetaClass *metaClass, + const AbstractMetaClassPtr &metaClass, const QStringList &enumsDeclarations) { const EnumList &enums = scopeItem->enums(); @@ -1564,7 +1687,7 @@ bool AbstractMetaBuilderPrivate::traverseAddedGlobalFunction(const AddedFunction AbstractMetaFunction * AbstractMetaBuilderPrivate::traverseAddedFunctionHelper(const AddedFunctionPtr &addedFunc, - AbstractMetaClass *metaClass /* = nullptr */, + const AbstractMetaClassPtr &metaClass /* = {} */, QString *errorMessage) { auto returnType = translateType(addedFunc->returnType(), metaClass, {}, errorMessage); @@ -1576,13 +1699,13 @@ AbstractMetaFunction * return nullptr; } - auto metaFunction = new AbstractMetaFunction(addedFunc); + auto *metaFunction = new AbstractMetaFunction(addedFunc); metaFunction->setType(returnType.value()); metaFunction->setFunctionType(functionTypeFromName(addedFunc->name())); const auto &args = addedFunc->arguments(); - qsizetype argCount = args.count(); + qsizetype argCount = args.size(); // Check "foo(void)" if (argCount == 1 && args.constFirst().typeInfo.isVoid()) argCount = 0; @@ -1633,7 +1756,8 @@ AbstractMetaFunction * // Find the correct default values const FunctionModificationList functionMods = metaFunction->modifications(metaClass); - for (int i = 0; i < metaArguments.size(); ++i) { + applyCachedFunctionModifications(metaFunction, functionMods); + for (qsizetype i = 0; i < metaArguments.size(); ++i) { AbstractMetaArgument &metaArg = metaArguments[i]; // use replace-default-expression for set default value @@ -1648,7 +1772,7 @@ AbstractMetaFunction * } bool AbstractMetaBuilderPrivate::traverseAddedMemberFunction(const AddedFunctionPtr &addedFunc, - AbstractMetaClass *metaClass, + const AbstractMetaClassPtr &metaClass, QString *errorMessage) { AbstractMetaFunction *metaFunction = @@ -1658,11 +1782,11 @@ bool AbstractMetaBuilderPrivate::traverseAddedMemberFunction(const AddedFunction const AbstractMetaArgumentList fargs = metaFunction->arguments(); if (metaClass->isNamespace()) - *metaFunction += AbstractMetaFunction::Static; + metaFunction->setCppAttribute(FunctionAttribute::Static); if (metaFunction->name() == metaClass->name()) { metaFunction->setFunctionType(AbstractMetaFunction::ConstructorFunction); if (fargs.size() == 1) { - const TypeEntry *te = fargs.constFirst().type().typeEntry(); + const auto te = fargs.constFirst().type().typeEntry(); if (te->isCustom()) metaFunction->setExplicit(true); if (te->name() == metaFunction->name()) @@ -1672,7 +1796,7 @@ bool AbstractMetaBuilderPrivate::traverseAddedMemberFunction(const AddedFunction metaFunction->setDeclaringClass(metaClass); metaFunction->setImplementingClass(metaClass); - metaClass->addFunction(AbstractMetaFunctionCPtr(metaFunction)); + AbstractMetaClass::addFunction(metaClass, AbstractMetaFunctionCPtr(metaFunction)); metaClass->setHasNonPrivateConstructor(true); return true; } @@ -1688,9 +1812,9 @@ void AbstractMetaBuilderPrivate::fixArgumentNames(AbstractMetaFunction *func, co } } - for (int i = 0, size = arguments.size(); i < size; ++i) { + for (qsizetype i = 0, size = arguments.size(); i < size; ++i) { if (arguments.at(i).name().isEmpty()) - arguments[i].setName(QLatin1String("arg__") + QString::number(i + 1), false); + arguments[i].setName(u"arg__"_s + QString::number(i + 1), false); } } @@ -1700,15 +1824,15 @@ static QString functionSignature(const FunctionModelItem &functionItem) const ArgumentList &arguments = functionItem->arguments(); for (const ArgumentModelItem &arg : arguments) args << arg->type().toString(); - return functionItem->name() + QLatin1Char('(') + args.join(QLatin1Char(',')) + QLatin1Char(')'); + return functionItem->name() + u'(' + args.join(u',') + u')'; } static inline QString qualifiedFunctionSignatureWithType(const FunctionModelItem &functionItem, const QString &className = QString()) { - QString result = functionItem->type().toString() + QLatin1Char(' '); + QString result = functionItem->type().toString() + u' '; if (!className.isEmpty()) - result += className + colonColon(); + result += className + u"::"_s; result += functionSignature(functionItem); return result; } @@ -1805,7 +1929,7 @@ static bool applyArrayArgumentModifications(const FunctionModificationList &func const int i = argMod.index() - 1; if (i < 0 || i >= func->arguments().size()) { *errorMessage = msgCannotSetArrayUsage(func->minimalSignature(), i, - QLatin1String("Index out of range.")); + u"Index out of range."_s); return false; } auto t = func->arguments().at(i).type(); @@ -1820,9 +1944,48 @@ static bool applyArrayArgumentModifications(const FunctionModificationList &func return true; } +// Create the meta type for a view (std::string_view -> std::string) +static AbstractMetaType createViewOnType(const AbstractMetaType &metaType, + const TypeEntryCPtr &viewOnTypeEntry) +{ + auto result = metaType; + result.setTypeEntry(viewOnTypeEntry); + if (!metaType.isContainer() || !viewOnTypeEntry->isContainer()) + return result; + // For containers, when sth with several template parameters + // (std::span<T, int N>) is mapped onto a std::vector<T>, + // remove the superfluous template parameters and strip 'const'. + const auto vcte = std::static_pointer_cast<const ContainerTypeEntry>(viewOnTypeEntry); + const auto &instantiations = metaType.instantiations(); + AbstractMetaTypeList viewInstantiations; + const auto size = std::min(vcte->templateParameterCount(), instantiations.size()); + for (qsizetype i = 0; i < size; ++i) { + auto ins = instantiations.at(i); + ins.setConstant(false); + viewInstantiations.append(ins); + } + result.setInstantiations(viewInstantiations); + return result; +} + +void AbstractMetaBuilderPrivate::rejectFunction(const FunctionModelItem &functionItem, + const AbstractMetaClassPtr ¤tClass, + AbstractMetaBuilder::RejectReason reason, + const QString &rejectReason) +{ + QString sortKey; + if (currentClass) + sortKey += currentClass->typeEntry()->qualifiedCppName() + u"::"_s; + sortKey += functionSignature(functionItem); // Sort without return type + const QString signatureWithType = functionItem->type().toString() + u' ' + sortKey; + m_rejectedFunctions.insert({reason, signatureWithType, sortKey, rejectReason}); +} + AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const FunctionModelItem &functionItem, - AbstractMetaClass *currentClass) + const AbstractMetaClassPtr ¤tClass) { + const auto *tdb = TypeDatabase::instance(); + if (!functionItem->templateParameters().isEmpty()) return nullptr; @@ -1840,34 +2003,40 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio } return nullptr; } - QString functionName = functionItem->name(); - QString className; - if (currentClass) { + const QString &functionName = functionItem->name(); + const QString className = currentClass != nullptr ? + currentClass->typeEntry()->qualifiedCppName() : QString{}; + + if (m_apiExtractorFlags.testFlag(ApiExtractorFlag::UsePySideExtensions)) { + // Skip enum helpers generated by Q_ENUM + if ((currentClass == nullptr || currentClass->isNamespace()) + && (functionName == u"qt_getEnumMetaObject" || functionName == u"qt_getEnumName")) { + return nullptr; + } + // 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; + if (currentClass != nullptr) { + if (functionName == u"qt_check_for_QGADGET_macro" + || functionName.startsWith(u"qt_meta")) { + return nullptr; + } + if (functionName == u"metaObject" && className != u"QObject") + return nullptr; } - className = currentClass->typeEntry()->qualifiedCppName(); - if (functionName == QLatin1String("metaObject") && className != QLatin1String("QObject")) - return nullptr; - } - - // Store original signature with unresolved typedefs for message/log purposes - const QString originalQualifiedSignatureWithReturn = - qualifiedFunctionSignatureWithType(functionItem, className); + } // PySide extensions QString rejectReason; - if (TypeDatabase::instance()->isFunctionRejected(className, functionName, &rejectReason)) { - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); + if (tdb->isFunctionRejected(className, functionName, &rejectReason)) { + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::GenerationDisabled, rejectReason); return nullptr; } - const QString &signature = functionSignature(functionItem); - const bool rejected = - TypeDatabase::instance()->isFunctionRejected(className, signature, &rejectReason); - if (rejected) { + const QString &signature = functionSignature(functionItem); + if (tdb->isFunctionRejected(className, signature, &rejectReason)) { + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::GenerationDisabled, rejectReason); if (ReportHandler::isDebug(ReportHandler::MediumDebug)) { qCInfo(lcShiboken, "%s::%s was rejected by the type database (%s).", qPrintable(className), qPrintable(signature), qPrintable(rejectReason)); @@ -1878,47 +2047,30 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio if (functionItem->isFriend()) return nullptr; - const bool deprecated = functionItem->isDeprecated(); + const auto cppAttributes = functionItem->attributes(); + const bool deprecated = cppAttributes.testFlag(FunctionAttribute::Deprecated); if (deprecated && m_skipDeprecated) { - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + QLatin1String(" is deprecated."), - AbstractMetaBuilder::GenerationDisabled); + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::GenerationDisabled, u" is deprecated."_s); return nullptr; } - auto *metaFunction = new AbstractMetaFunction; + AbstractMetaFunction::Flags flags; + auto *metaFunction = new AbstractMetaFunction(functionName); + metaFunction->setCppAttributes(cppAttributes); + const QByteArray cSignature = signature.toUtf8(); + const QString unresolvedSignature = + QString::fromUtf8(QMetaObject::normalizedSignature(cSignature.constData())); + metaFunction->setUnresolvedSignature(unresolvedSignature); + if (functionItem->isHiddenFriend()) + flags.setFlag(AbstractMetaFunction::Flag::HiddenFriend); metaFunction->setSourceLocation(functionItem->sourceLocation()); - if (deprecated) - *metaFunction += AbstractMetaFunction::Deprecated; // Additional check for assignment/move assignment down below metaFunction->setFunctionType(functionTypeFromCodeModel(functionItem->functionType())); metaFunction->setConstant(functionItem->isConstant()); metaFunction->setExceptionSpecification(functionItem->exceptionSpecification()); - metaFunction->setName(functionName); - metaFunction->setOriginalName(functionItem->name()); - - if (functionItem->isAbstract()) - *metaFunction += AbstractMetaFunction::Abstract; - - if (functionItem->isVirtual()) { - *metaFunction += AbstractMetaFunction::VirtualCppMethod; - if (functionItem->isOverride()) - *metaFunction += AbstractMetaFunction::OverriddenCppMethod; - if (functionItem->isFinal()) - *metaFunction += AbstractMetaFunction::FinalCppMethod; - } else { - *metaFunction += AbstractMetaFunction::FinalInTargetLang; - } - - if (functionItem->isInvokable()) - *metaFunction += AbstractMetaFunction::Invokable; - - if (functionItem->isStatic()) { - *metaFunction += AbstractMetaFunction::Static; - *metaFunction += AbstractMetaFunction::FinalInTargetLang; - } - // Access rights metaFunction->setAccess(functionItem->accessPolicy()); @@ -1928,25 +2080,30 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio metaFunction->setType(AbstractMetaType::createVoid()); break; case AbstractMetaFunction::ConstructorFunction: - metaFunction->setExplicit(functionItem->isExplicit()); metaFunction->setName(currentClass->name()); metaFunction->setType(AbstractMetaType::createVoid()); break; default: { TypeInfo returnType = functionItem->type(); - if (TypeDatabase::instance()->isReturnTypeRejected(className, returnType.toString(), &rejectReason)) { - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); + if (tdb->isReturnTypeRejected(className, returnType.toString(), &rejectReason)) { + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::GenerationDisabled, rejectReason); delete metaFunction; return nullptr; } - auto type = translateType(returnType, currentClass, {}, &errorMessage); + TranslateTypeFlags flags; + if (functionItem->scopeResolution()) + flags.setFlag(AbstractMetaBuilder::NoClassScopeLookup); + auto type = translateType(returnType, currentClass, flags, &errorMessage); if (!type.has_value()) { const QString reason = msgUnmatchedReturnType(functionItem, errorMessage); + const QString signature = qualifiedFunctionSignatureWithType(functionItem, className); qCWarning(lcShiboken, "%s", - qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason))); - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::UnmatchedReturnType); + qPrintable(msgSkippingFunction(functionItem, signature, reason))); + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::UnmatchedReturnType, reason); delete metaFunction; return nullptr; } @@ -1957,41 +2114,56 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio } ArgumentList arguments = functionItem->arguments(); + // Add private signals for documentation purposes + if (!arguments.isEmpty() + && m_apiExtractorFlags.testFlag(ApiExtractorFlag::UsePySideExtensions) + && functionItem->functionType() == CodeModel::Signal + && arguments.constLast()->type().qualifiedName().constLast() == u"QPrivateSignal") { + flags.setFlag(AbstractMetaFunction::Flag::PrivateSignal); + arguments.removeLast(); + } if (arguments.size() == 1) { ArgumentModelItem arg = arguments.at(0); TypeInfo type = arg->type(); - if (type.qualifiedName().constFirst() == QLatin1String("void") && type.indirections() == 0) + if (type.qualifiedName().constFirst() == u"void" && type.indirections() == 0) arguments.pop_front(); } - for (int i = 0; i < arguments.size(); ++i) { + for (qsizetype i = 0; i < arguments.size(); ++i) { const ArgumentModelItem &arg = arguments.at(i); - if (TypeDatabase::instance()->isArgumentTypeRejected(className, arg->type().toString(), &rejectReason)) { - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); + if (tdb->isArgumentTypeRejected(className, arg->type().toString(), &rejectReason)) { + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::GenerationDisabled, rejectReason); delete metaFunction; return nullptr; } - auto metaTypeO = translateType(arg->type(), currentClass, {}, &errorMessage); + TranslateTypeFlags flags; + if (arg->scopeResolution()) + flags.setFlag(AbstractMetaBuilder::NoClassScopeLookup); + auto metaTypeO = translateType(arg->type(), currentClass, flags, &errorMessage); if (!metaTypeO.has_value()) { // If an invalid argument has a default value, simply remove it // unless the function is virtual (since the override in the // wrapper can then not correctly be generated). - if (arg->defaultValue() && !functionItem->isVirtual()) { + if (arg->defaultValue() + && !functionItem->attributes().testFlag(FunctionAttribute::Virtual)) { if (!currentClass || currentClass->typeEntry()->generateCode()) { + const QString signature = qualifiedFunctionSignatureWithType(functionItem, className); qCWarning(lcShiboken, "%s", - qPrintable(msgStrippingArgument(functionItem, i, originalQualifiedSignatureWithReturn, arg))); + qPrintable(msgStrippingArgument(functionItem, i, signature, + arg, errorMessage))); } break; } const QString reason = msgUnmatchedParameterType(arg, i, errorMessage); + const QString signature = qualifiedFunctionSignatureWithType(functionItem, className); qCWarning(lcShiboken, "%s", - qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason))); - const QString rejectedFunctionSignature = originalQualifiedSignatureWithReturn - + QLatin1String(": ") + reason; - m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::UnmatchedArgumentType); + qPrintable(msgSkippingFunction(functionItem, signature, reason))); + rejectFunction(functionItem, currentClass, + AbstractMetaBuilder::UnmatchedArgumentType, reason); delete metaFunction; return nullptr; } @@ -2002,10 +2174,8 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio auto viewOnTypeEntry = metaType.typeEntry()->viewOn(); if (viewOnTypeEntry != nullptr && metaType.indirections() == 0 && metaType.arrayElementType() == nullptr - && !metaType.hasInstantiations()) { - auto viewOn = metaType; - viewOn.setTypeEntry(viewOnTypeEntry); - metaType.setViewOn(viewOn); + && (!metaType.hasInstantiations() || metaType.isContainer())) { + metaType.setViewOn(createViewOnType(metaType, viewOnTypeEntry)); } AbstractMetaArgument metaArgument; @@ -2021,20 +2191,15 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio ? AbstractMetaFunction::findClassModifications(metaFunction, currentClass) : AbstractMetaFunction::findGlobalModifications(metaFunction); - for (const FunctionModification &mod : functionMods) { - if (mod.exceptionHandling() != TypeSystem::ExceptionHandling::Unspecified) - metaFunction->setExceptionHandlingModification(mod.exceptionHandling()); - else if (mod.allowThread() != TypeSystem::AllowThread::Unspecified) - metaFunction->setAllowThreadModification(mod.allowThread()); - } + applyCachedFunctionModifications(metaFunction, functionMods); // Find the correct default values - for (int i = 0, size = metaArguments.size(); i < size; ++i) { + for (qsizetype i = 0, size = metaArguments.size(); i < size; ++i) { const ArgumentModelItem &arg = arguments.at(i); AbstractMetaArgument &metaArg = metaArguments[i]; const QString originalDefaultExpression = - fixDefaultValue(arg, metaArg.type(), currentClass, i); + fixDefaultValue(arg->defaultValueExpression(), metaArg.type(), currentClass); metaArg.setOriginalDefaultValueExpression(originalDefaultExpression); metaArg.setDefaultValueExpression(originalDefaultExpression); @@ -2067,7 +2232,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio if (currentClass && metaFunction->arguments().size() == 1) { const AbstractMetaType &argType = metaFunction->arguments().constFirst().type(); if (argType.typeEntry() == currentClass->typeEntry() && argType.indirections() == 0) { - if (metaFunction->name() == QLatin1String("operator=")) { + if (metaFunction->name() == u"operator=") { switch (argType.referenceType()) { case NoReference: metaFunction->setFunctionType(AbstractMetaFunction::AssignmentOperatorFunction); @@ -2083,35 +2248,39 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio } } } + metaFunction->setFlags(flags); return metaFunction; } -static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaClass, const QString& qualifiedName) +static TypeEntryCPtr findTypeEntryUsingContext(const AbstractMetaClassCPtr &metaClass, + const QString& qualifiedName) { - const TypeEntry* type = nullptr; - QStringList context = metaClass->qualifiedCppName().split(colonColon()); + TypeEntryCPtr type; + QStringList context = metaClass->qualifiedCppName().split(u"::"_s); while (!type && !context.isEmpty()) { - type = TypeDatabase::instance()->findType(context.join(colonColon()) + colonColon() + qualifiedName); + type = TypeDatabase::instance()->findType(context.join(u"::"_s) + u"::"_s + qualifiedName); context.removeLast(); } return type; } // Helper for findTypeEntries/translateTypeStatic() -TypeEntries AbstractMetaBuilderPrivate::findTypeEntriesHelper(const QString &qualifiedName, - const QString &name, - const AbstractMetaClass *currentClass, - AbstractMetaBuilderPrivate *d) +TypeEntryCList AbstractMetaBuilderPrivate::findTypeEntriesHelper(const QString &qualifiedName, + const QString &name, + TranslateTypeFlags flags, + const AbstractMetaClassCPtr ¤tClass, + AbstractMetaBuilderPrivate *d) { // 5.1 - Try first using the current scope - if (currentClass) { + if (currentClass != nullptr + && !flags.testFlag(AbstractMetaBuilder::NoClassScopeLookup)) { if (auto type = findTypeEntryUsingContext(currentClass, qualifiedName)) return {type}; // 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) { + const auto &baseClasses = d->getBaseClasses(currentClass); + for (const auto &cls : baseClasses) { if (auto type = findTypeEntryUsingContext(cls, qualifiedName)) return {type}; } @@ -2135,7 +2304,7 @@ TypeEntries AbstractMetaBuilderPrivate::findTypeEntriesHelper(const QString &qua // of the parameters. if (currentClass) { const auto &template_args = currentClass->templateArguments(); - for (const TypeEntry *te : template_args) { + for (const auto &te : template_args) { if (te->name() == qualifiedName) return {te}; } @@ -2145,25 +2314,37 @@ TypeEntries AbstractMetaBuilderPrivate::findTypeEntriesHelper(const QString &qua // Helper for translateTypeStatic() that calls findTypeEntriesHelper() // and does some error checking. -TypeEntries AbstractMetaBuilderPrivate::findTypeEntries(const QString &qualifiedName, - const QString &name, - const AbstractMetaClass *currentClass, - AbstractMetaBuilderPrivate *d, - QString *errorMessage) -{ - const TypeEntries types = findTypeEntriesHelper(qualifiedName, name, currentClass, d); +TypeEntryCList AbstractMetaBuilderPrivate::findTypeEntries(const QString &qualifiedName, + const QString &name, + TranslateTypeFlags flags, + const AbstractMetaClassCPtr ¤tClass, + AbstractMetaBuilderPrivate *d, + QString *errorMessage) +{ + TypeEntryCList types = findTypeEntriesHelper(qualifiedName, name, flags, + currentClass, d); if (types.isEmpty()) { if (errorMessage != nullptr) *errorMessage = msgCannotFindTypeEntry(qualifiedName); return {}; } + // Resolve entries added by metabuilder (for example, "GLenum") to match + // the signatures for modifications. + for (qsizetype i = 0, size = types.size(); i < size; ++i) { + const auto &e = types.at(i); + if (e->isPrimitive()) { + const auto pte = std::static_pointer_cast<const PrimitiveTypeEntry>(e); + types[i] = basicReferencedNonBuiltinTypeEntry(pte); + } + } + if (types.size() == 1) return types; const auto typeEntryType = types.constFirst()->type(); const bool sameType = std::all_of(types.cbegin() + 1, types.cend(), - [typeEntryType](const TypeEntry *e) { + [typeEntryType](const TypeEntryCPtr &e) { return e->type() == typeEntryType; }); @@ -2186,10 +2367,10 @@ TypeEntries AbstractMetaBuilderPrivate::findTypeEntries(const QString &qualified // 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 +AbstractMetaClassCPtr AbstractMetaBuilderPrivate::resolveTypeSystemTypeDef(const AbstractMetaType &t) const { if (t.hasInstantiations()) { - auto pred = [t](const TypeClassEntry &e) { return e.type.equals(t); }; + auto pred = [t](const TypeClassEntry &e) { return e.type == t; }; auto it = std::find_if(m_typeSystemTypeDefs.cbegin(), m_typeSystemTypeDefs.cend(), pred); if (it != m_typeSystemTypeDefs.cend()) return it->klass; @@ -2197,9 +2378,194 @@ const AbstractMetaClass *AbstractMetaBuilderPrivate::resolveTypeSystemTypeDef(co return nullptr; } +// The below helpers and AbstractMetaBuilderPrivate::fixSmartPointers() +// synthesize missing smart pointer functions and classes. For example for +// std::shared_ptr, the full class declaration or base classes from +// internal, compiler-dependent STL implementation headers might not be exposed +// to the parser unless those headers are specified as <system-include>. + +static void synthesizeWarning(const AbstractMetaFunctionCPtr &f) +{ + qCWarning(lcShiboken, "Synthesizing \"%s\"...", + qPrintable(f->classQualifiedSignature())); +} + +static AbstractMetaFunctionPtr + addMethod(const AbstractMetaClassPtr &s, const AbstractMetaType &returnType, + const QString &name, bool isConst = true) +{ + auto function = std::make_shared<AbstractMetaFunction>(name); + function->setType(returnType); + AbstractMetaClass::addFunction(s, function); + function->setConstant(isConst); + synthesizeWarning(function); + return function; +} + +static AbstractMetaFunctionPtr + addMethod(const AbstractMetaClassPtr &s, const QString &returnTypeName, + const QString &name, bool isConst = true) +{ + auto typeEntry = TypeDatabase::instance()->findPrimitiveType(returnTypeName); + Q_ASSERT(typeEntry); + AbstractMetaType returnType(typeEntry); + returnType.decideUsagePattern(); + return addMethod(s, returnType, name, isConst); +} + +// Create the instantiation type of a smart pointer +static AbstractMetaType instantiationType(const AbstractMetaClassCPtr &s, + const SmartPointerTypeEntryCPtr &ste) +{ + AbstractMetaType type(s->templateArguments().constFirst()); + if (ste->smartPointerType() != TypeSystem::SmartPointerType::ValueHandle) + type.addIndirection(); + type.decideUsagePattern(); + return type; +} + +// Create the pointee argument of a smart pointer constructor or reset() +static AbstractMetaArgument pointeeArgument(const AbstractMetaClassCPtr &s, + const SmartPointerTypeEntryCPtr &ste) +{ + AbstractMetaArgument pointee; + pointee.setType(instantiationType(s, ste)); + pointee.setName(u"pointee"_s); + return pointee; +} + +// Add the smart pointer constructors. For MSVC, (when not specifying +// <system-header>), clang only sees the default constructor. +static void fixSmartPointerConstructors(const AbstractMetaClassPtr &s, + const SmartPointerTypeEntryCPtr &ste) +{ + const auto ctors = s->queryFunctions(FunctionQueryOption::Constructors); + bool seenDefaultConstructor = false; + bool seenParameter = false; + for (const auto &ctor : ctors) { + if (ctor->arguments().isEmpty()) + seenDefaultConstructor = true; + else + seenParameter = true; + } + + if (!seenParameter) { + auto constructor = std::make_shared<AbstractMetaFunction>(s->name()); + constructor->setFunctionType(AbstractMetaFunction::ConstructorFunction); + constructor->addArgument(pointeeArgument(s, ste)); + AbstractMetaClass::addFunction(s, constructor); + synthesizeWarning(constructor); + } + + if (!seenDefaultConstructor) { + auto constructor = std::make_shared<AbstractMetaFunction>(s->name()); + constructor->setFunctionType(AbstractMetaFunction::ConstructorFunction); + AbstractMetaClass::addFunction(s, constructor); + synthesizeWarning(constructor); + } +} + +// Similarly, add the smart pointer reset() functions +static void fixSmartPointerReset(const AbstractMetaClassPtr &s, + const SmartPointerTypeEntryCPtr &ste) +{ + const QString resetMethodName = ste->resetMethod(); + const auto functions = s->findFunctions(resetMethodName); + bool seenParameterLess = false; + bool seenParameter = false; + for (const auto &function : functions) { + if (function->arguments().isEmpty()) + seenParameterLess = true; + else + seenParameter = true; + } + + if (!seenParameter) { + auto f = std::make_shared<AbstractMetaFunction>(resetMethodName); + f->addArgument(pointeeArgument(s, ste)); + AbstractMetaClass::addFunction(s, f); + synthesizeWarning(f); + } + + if (!seenParameterLess) { + auto f = std::make_shared<AbstractMetaFunction>(resetMethodName); + AbstractMetaClass::addFunction(s, f); + synthesizeWarning(f); + } +} + +// Add the relevant missing smart pointer functions. +static void fixSmartPointerClass(const AbstractMetaClassPtr &s, + const SmartPointerTypeEntryCPtr &ste) +{ + fixSmartPointerConstructors(s, ste); + + if (!ste->resetMethod().isEmpty()) + fixSmartPointerReset(s, ste); + + const QString getterName = ste->getter(); + if (!s->findFunction(getterName)) + addMethod(s, instantiationType(s, ste), getterName); + + const QString refCountName = ste->refCountMethodName(); + if (!refCountName.isEmpty() && !s->findFunction(refCountName)) + addMethod(s, u"int"_s, refCountName); + + const QString valueCheckMethod = ste->valueCheckMethod(); + if (!valueCheckMethod.isEmpty() && !s->findFunction(valueCheckMethod)) { + auto f = addMethod(s, u"bool"_s, valueCheckMethod); + if (valueCheckMethod == u"operator bool") + f->setFunctionType(AbstractMetaFunction::ConversionOperator); + } + + const QString nullCheckMethod = ste->nullCheckMethod(); + if (!nullCheckMethod.isEmpty() && !s->findFunction(nullCheckMethod)) + addMethod(s, u"bool"_s, nullCheckMethod); +} + +// Create a missing smart pointer class +static AbstractMetaClassPtr createSmartPointerClass(const SmartPointerTypeEntryCPtr &ste, + const AbstractMetaClassList &allClasses) +{ + auto result = std::make_shared<AbstractMetaClass>(); + result->setTypeEntry(std::const_pointer_cast<SmartPointerTypeEntry>(ste)); + auto templateArg = std::make_shared<TemplateArgumentEntry>(u"T"_s, ste->version(), + typeSystemTypeEntry(ste)); + result->setTemplateArguments({templateArg}); + fixSmartPointerClass(result, ste); + auto enclosingTe = ste->parent(); + if (!enclosingTe->isTypeSystem()) { + const auto enclosing = AbstractMetaClass::findClass(allClasses, enclosingTe); + if (!enclosing) + throw Exception(msgEnclosingClassNotFound(ste)); + result->setEnclosingClass(enclosing); + auto inner = enclosing->innerClasses(); + inner.append(std::const_pointer_cast<const AbstractMetaClass>(result)); + enclosing->setInnerClasses(inner); + } + return result; +} + +void AbstractMetaBuilderPrivate::fixSmartPointers() +{ + const auto smartPointerTypes = TypeDatabase::instance()->smartPointerTypes(); + for (const auto &ste : smartPointerTypes) { + const auto smartPointerClass = + AbstractMetaClass::findClass(m_smartPointers, ste); + if (smartPointerClass) { + fixSmartPointerClass(std::const_pointer_cast<AbstractMetaClass>(smartPointerClass), + ste); + } else { + qCWarning(lcShiboken, "Synthesizing smart pointer \"%s\"...", + qPrintable(ste->qualifiedCppName())); + m_smartPointers.append(createSmartPointerClass(ste, m_metaClasses)); + } + } +} + std::optional<AbstractMetaType> AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typei, - const AbstractMetaClass *currentClass, + const AbstractMetaClassCPtr ¤tClass, TranslateTypeFlags flags, QString *errorMessage) { @@ -2212,9 +2578,16 @@ static bool isNumber(const QString &s) [](QChar c) { return c.isDigit(); }); } +// A type entry relevant only for non type template "X<5>" +static bool isNonTypeTemplateArgument(const TypeEntryCPtr &te) +{ + const auto type = te->type(); + return type == TypeEntry::EnumValue || type == TypeEntry::ConstantValueType; +} + std::optional<AbstractMetaType> AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo &_typei, - const AbstractMetaClass *currentClass, + const AbstractMetaClassCPtr ¤tClass, AbstractMetaBuilderPrivate *d, TranslateTypeFlags flags, QString *errorMessageIn) @@ -2241,10 +2614,10 @@ std::optional<AbstractMetaType> // the global scope when they are referenced from inside a namespace. // This is a work around to fix this bug since fixing it in resolveType // seemed non-trivial - int i = d ? d->m_scopes.size() - 1 : -1; + qsizetype i = d ? d->m_scopes.size() - 1 : -1; while (i >= 0) { typeInfo = TypeInfo::resolveType(_typei, d->m_scopes.at(i--)); - if (typeInfo.qualifiedName().join(colonColon()) != _typei.qualifiedName().join(colonColon())) + if (typeInfo.qualifiedName().join(u"::"_s) != _typei.qualifiedName().join(u"::"_s)) break; } @@ -2252,7 +2625,7 @@ std::optional<AbstractMetaType> if (typeInfo.isFunctionPointer()) { if (errorMessageIn) - *errorMessageIn = msgUnableToTranslateType(_typei, QLatin1String("Unsupported function pointer.")); + *errorMessageIn = msgUnableToTranslateType(_typei, u"Unsupported function pointer."_s); return {}; } @@ -2268,7 +2641,7 @@ std::optional<AbstractMetaType> bool isConstCharStarCase = oneDimensionalArrayOfUnspecifiedSize && typeInfo.qualifiedName().size() == 1 - && typeInfo.qualifiedName().at(0) == QStringLiteral("char") + && typeInfo.qualifiedName().at(0) == "char"_L1 && typeInfo.indirections() == 0 && typeInfo.isConstant() && typeInfo.referenceType() == NoReference @@ -2292,13 +2665,13 @@ std::optional<AbstractMetaType> auto elementType = translateTypeStatic(newInfo, currentClass, d, flags, &errorMessage); if (!elementType.has_value()) { if (errorMessageIn) { - errorMessage.prepend(QLatin1String("Unable to translate array element: ")); + errorMessage.prepend(u"Unable to translate array element: "_s); *errorMessageIn = msgUnableToTranslateType(_typei, errorMessage); } return {}; } - for (int i = typeInfo.arrayElements().size() - 1; i >= 0; --i) { + for (auto i = typeInfo.arrayElements().size() - 1; i >= 0; --i) { AbstractMetaType arrayType; arrayType.setArrayElementType(elementType.value()); const QString &arrayElement = typeInfo.arrayElements().at(i); @@ -2311,8 +2684,9 @@ std::optional<AbstractMetaType> arrayType.setArrayElementCount(int(elems)); } auto elementTypeEntry = elementType->typeEntry(); - arrayType.setTypeEntry(new ArrayTypeEntry(elementTypeEntry, elementTypeEntry->version(), - elementTypeEntry->parent())); + auto at = std::make_shared<ArrayTypeEntry>(elementTypeEntry, elementTypeEntry->version(), + elementTypeEntry->parent()); + arrayType.setTypeEntry(at); arrayType.decideUsagePattern(); elementType = arrayType; @@ -2323,7 +2697,7 @@ std::optional<AbstractMetaType> QStringList qualifierList = typeInfo.qualifiedName(); if (qualifierList.isEmpty()) { - errorMessage = msgUnableToTranslateType(_typei, QLatin1String("horribly broken type")); + errorMessage = msgUnableToTranslateType(_typei, u"horribly broken type"_s); if (errorMessageIn) *errorMessageIn = errorMessage; else @@ -2331,23 +2705,32 @@ std::optional<AbstractMetaType> return {}; } - QString qualifiedName = qualifierList.join(colonColon()); + QString qualifiedName = qualifierList.join(u"::"_s); QString name = qualifierList.takeLast(); // 4. Special case QFlags (include instantiation in name) - if (qualifiedName == QLatin1String("QFlags")) { + if (qualifiedName == u"QFlags") { qualifiedName = typeInfo.toString(); typeInfo.clearInstantiations(); } - const TypeEntries types = findTypeEntries(qualifiedName, name, currentClass, d, errorMessageIn); + TypeEntryCList types = findTypeEntries(qualifiedName, name, flags, + currentClass, d, errorMessageIn); + if (!flags.testFlag(AbstractMetaBuilder::TemplateArgument)) { + // Avoid clashes between QByteArray and enum value QMetaType::QByteArray + // unless we are looking for template arguments. + auto end = std::remove_if(types.begin(), types.end(), + isNonTypeTemplateArgument); + types.erase(end, types.end()); + } + if (types.isEmpty()) { if (errorMessageIn != nullptr) *errorMessageIn = msgUnableToTranslateType(_typei, *errorMessageIn); return {}; } - const TypeEntry *type = types.constFirst(); + TypeEntryCPtr type = types.constFirst(); const TypeEntry::Type typeEntryType = type->type(); AbstractMetaType metaType; @@ -2358,15 +2741,18 @@ std::optional<AbstractMetaType> metaType.setOriginalTypeDescription(_typei.toString()); const auto &templateArguments = typeInfo.instantiations(); - for (int t = 0, size = templateArguments.size(); t < size; ++t) { + for (qsizetype t = 0, size = templateArguments.size(); t < size; ++t) { const TypeInfo &ti = templateArguments.at(t); - auto targType = translateTypeStatic(ti, currentClass, d, flags, &errorMessage); + auto targType = translateTypeStatic(ti, currentClass, d, + flags | AbstractMetaBuilder::TemplateArgument, + &errorMessage); // For non-type template parameters, create a dummy type entry on the fly // as is done for classes. if (!targType.has_value()) { - const QString value = ti.qualifiedName().join(colonColon()); + const QString value = ti.qualifiedName().join(u"::"_s); if (isNumber(value)) { - TypeDatabase::instance()->addConstantValueTypeEntry(value, type->typeSystemTypeEntry()); + auto module = typeSystemTypeEntry(type); + TypeDatabase::instance()->addConstantValueTypeEntry(value, module); targType = translateTypeStatic(ti, currentClass, d, flags, &errorMessage); } } @@ -2392,8 +2778,8 @@ std::optional<AbstractMetaType> type = instantiationType; } else { auto it = std::find_if(types.cbegin(), types.cend(), - [instantiationType](const TypeEntry *e) { - auto smartPtr = static_cast<const SmartPointerTypeEntry *>(e); + [instantiationType](const TypeEntryCPtr &e) { + auto smartPtr = std::static_pointer_cast<const SmartPointerTypeEntry>(e); return smartPtr->matchesInstantiation(instantiationType); }); if (it == types.cend()) { @@ -2427,7 +2813,7 @@ std::optional<AbstractMetaType> std::optional<AbstractMetaType> AbstractMetaBuilder::translateType(const TypeInfo &_typei, - AbstractMetaClass *currentClass, + const AbstractMetaClassPtr ¤tClass, TranslateTypeFlags flags, QString *errorMessage) { @@ -2438,7 +2824,7 @@ std::optional<AbstractMetaType> std::optional<AbstractMetaType> AbstractMetaBuilder::translateType(const QString &t, - AbstractMetaClass *currentClass, + const AbstractMetaClassPtr ¤tClass, TranslateTypeFlags flags, QString *errorMessageIn) { @@ -2461,14 +2847,14 @@ qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringV if (ok) return value; - if (stringValue == QLatin1String("true") || stringValue == QLatin1String("false")) { + if (stringValue == u"true" || stringValue == u"false") { ok = true; - return (stringValue == QLatin1String("true")); + return (stringValue == u"true"); } // This is a very lame way to handle expression evaluation, // but it is not critical and will do for the time being. - static const QRegularExpression variableNameRegExp(QStringLiteral("^[a-zA-Z_][a-zA-Z0-9_]*$")); + static const QRegularExpression variableNameRegExp("^[a-zA-Z_][a-zA-Z0-9_]*$"_L1); Q_ASSERT(variableNameRegExp.isValid()); if (!variableNameRegExp.match(stringValue).hasMatch()) { ok = true; @@ -2481,7 +2867,7 @@ qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringV return enumValue->value().value(); } - for (const AbstractMetaEnum &metaEnum : qAsConst(m_globalEnums)) { + for (const AbstractMetaEnum &metaEnum : std::as_const(m_globalEnums)) { auto ev = metaEnum.findEnumValue(stringValue); if (ev.has_value()) { ok = true; @@ -2493,115 +2879,163 @@ qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringV return 0; } -QString AbstractMetaBuilderPrivate::fixDefaultValue(const ArgumentModelItem &item, - const AbstractMetaType &type, - const AbstractMetaClass *implementingClass, - int /* argumentIndex */) +// Return whether candidate is some underqualified specification of qualifiedType +// ("B::C" should be qualified to "A::B::C") +static bool isUnderQualifiedSpec(QStringView qualifiedType, QStringView candidate) { - QString expr = item->defaultValueExpression(); - if (expr.isEmpty() || expr == u"{}") - return expr; + const auto candidateSize = candidate.size(); + const auto qualifiedTypeSize = qualifiedType.size(); + return candidateSize < qualifiedTypeSize + && qualifiedType.endsWith(candidate) + && qualifiedType.at(qualifiedTypeSize - candidateSize - 1) == u':'; +} + +QString AbstractMetaBuilder::fixEnumDefault(const AbstractMetaType &type, + const QString &expr, + const AbstractMetaClassCPtr &klass) const +{ + return d->fixEnumDefault(type, expr, klass); +} + +void AbstractMetaBuilder::setCodeModelTestMode(bool b) +{ + AbstractMetaBuilderPrivate::m_codeModelTestMode = b; +} + +// Helper to fix a simple default value (field or enum reference) in a +// class context. +QString AbstractMetaBuilderPrivate::fixSimpleDefaultValue(QStringView expr, + const AbstractMetaClassCPtr &klass) const +{ + const QString field = qualifyStaticField(klass, expr); + + if (!field.isEmpty()) + return field; + const auto cit = m_classToItem.constFind(klass); + if (cit == m_classToItem.cend()) + return {}; + auto *scope = dynamic_cast<const _ScopeModelItem *>(cit.value()); + if (!scope) + return {}; + if (auto enumValue = scope->findEnumByValue(expr)) + return enumValue.qualifiedName; + return {}; +} +// see TestResolveType::testFixDefaultArguments() +QString AbstractMetaBuilderPrivate::fixDefaultValue(QString expr, const AbstractMetaType &type, + const AbstractMetaClassCPtr &implementingClass) const +{ expr.replace(u'\n', u' '); // breaks signature parser - if (type.isPrimitive()) { - if (type.name() == QLatin1String("boolean")) { - if (expr != QLatin1String("false") && expr != QLatin1String("true")) { - bool ok = false; - int number = expr.toInt(&ok); - if (ok && number) - expr = QLatin1String("true"); - else - expr = QLatin1String("false"); - } - } else { - // This can be an enum or flag so I need to delay the - // translation until all namespaces are completely - // processed. This is done in figureOutEnumValues() - } - } else if (type.isFlags() || type.isEnum()) { - bool isNumber; - expr.toInt(&isNumber); - if (!isNumber && expr.indexOf(colonColon()) < 0) { - // Add the enum/flag scope to default value, making it usable - // from other contexts beside its owner class hierarchy - static const QRegularExpression typeRegEx(QStringLiteral("[^<]*[<]([^:]*::).*")); - Q_ASSERT(typeRegEx.isValid()); - const QRegularExpressionMatch match = typeRegEx.match(type.minimalSignature()); - if (match.hasMatch()) - expr.prepend(match.captured(1)); - } - } else if (type.isContainer() && expr.contains(QLatin1Char('<'))) { - static const QRegularExpression typeRegEx(QStringLiteral("[^<]*<(.*)>")); - Q_ASSERT(typeRegEx.isValid()); - const QRegularExpressionMatch typeMatch = typeRegEx.match(type.minimalSignature()); - static const QRegularExpression defaultRegEx(QLatin1String("([^<]*<).*(>[^>]*)")); - Q_ASSERT(defaultRegEx.isValid()); - const QRegularExpressionMatch defaultMatch = defaultRegEx.match(expr); - if (typeMatch.hasMatch() && defaultMatch.hasMatch()) - expr = defaultMatch.captured(1) + typeMatch.captured(1) + defaultMatch.captured(2); + if (AbstractMetaBuilder::dontFixDefaultValue(expr)) + return expr; + + if (type.isFlags() || type.isEnum()) { + expr = fixEnumDefault(type, expr, implementingClass); + } else if (type.isContainer() && expr.contains(u'<')) { + // Expand a container of a nested class, fex + // "QList<FormatRange>()" -> "QList<QTextLayout::FormatRange>()" + if (type.instantiations().size() != 1) + return expr; // Only simple types are handled, not QMap<int, int>. + auto innerTypeEntry = type.instantiations().constFirst().typeEntry(); + if (!innerTypeEntry->isComplex()) + return expr; + const QString &qualifiedInnerTypeName = innerTypeEntry->qualifiedCppName(); + if (!qualifiedInnerTypeName.contains(u"::")) // Nothing to qualify here + return expr; + const auto openPos = expr.indexOf(u'<'); + const auto closingPos = expr.lastIndexOf(u'>'); + if (openPos == -1 || closingPos == -1) + return expr; + const auto innerPos = openPos + 1; + const auto innerLen = closingPos - innerPos; + const auto innerType = QStringView{expr}.mid(innerPos, innerLen).trimmed(); + if (isUnderQualifiedSpec(qualifiedInnerTypeName, innerType)) + expr.replace(innerPos, innerLen, qualifiedInnerTypeName); } else { - // Here the default value is supposed to be a constructor, - // a class field, or a constructor receiving a class field - static const QRegularExpression defaultRegEx(QStringLiteral("([^\\(]*\\(|)([^\\)]*)(\\)|)")); - Q_ASSERT(defaultRegEx.isValid()); - const QRegularExpressionMatch defaultMatch = defaultRegEx.match(expr); - QString defaultValueCtorName = defaultMatch.hasMatch() ? defaultMatch.captured(1) : QString(); - if (defaultValueCtorName.endsWith(QLatin1Char('('))) - defaultValueCtorName.chop(1); - - // Fix the scope for constructor using the already resolved argument - // type as a reference. The following regular expression extracts any - // use of namespaces/scopes from the type string. - static const QRegularExpression - typeRegEx(QLatin1String(R"(^(?:const[\s]+|)([\w:]*::|)([A-Za-z_]\w*)\s*[&\*]?$)")); - Q_ASSERT(typeRegEx.isValid()); - const QRegularExpressionMatch typeMatch = typeRegEx.match(type.minimalSignature()); - - QString typeNamespace = typeMatch.hasMatch() ? typeMatch.captured(1) : QString(); - QString typeCtorName = typeMatch.hasMatch() ? typeMatch.captured(2) : QString(); - if (!typeNamespace.isEmpty() && defaultValueCtorName == typeCtorName) - expr.prepend(typeNamespace); - - // Fix scope if the parameter is a field of the current class - if (implementingClass) { - const AbstractMetaFieldList &fields = implementingClass->fields(); - for (const AbstractMetaField &field : fields) { - if (defaultMatch.hasMatch() && defaultMatch.captured(2) == field.name()) { - expr = defaultMatch.captured(1) + implementingClass->name() - + colonColon() + defaultMatch.captured(2) + defaultMatch.captured(3); - break; - } + // Here the default value is supposed to be a constructor, a class field, + // a constructor receiving a static class field or an enum. Consider + // class QSqlDatabase { ... + // static const char *defaultConnection; + // QSqlDatabase(const QString &connection = QLatin1String(defaultConnection)) + // -> = QLatin1String(QSqlDatabase::defaultConnection) + // static void foo(QSqlDatabase db = QSqlDatabase(defaultConnection)); + // -> = QSqlDatabase(QSqlDatabase::defaultConnection) + // + // Enum values from the class as defaults of int and others types (via + // implicit conversion) are handled here as well: + // class QStyleOption { ... + // enum StyleOptionType { Type = SO_Default }; + // QStyleOption(..., int type = SO_Default); + // -> = QStyleOption::StyleOptionType::SO_Default + + // Is this a single field or an enum? + if (isQualifiedCppIdentifier(expr)) { + const QString fixed = fixSimpleDefaultValue(expr, implementingClass); + return fixed.isEmpty() ? expr : fixed; + } + + // Is this sth like "QLatin1String(field)", "Class(Field)", "Class()"? + const auto parenPos = expr.indexOf(u'('); + if (parenPos == -1 || !expr.endsWith(u')')) + return expr; + // Is the term within parentheses a class field or enum? + const auto innerLength = expr.size() - parenPos - 2; + if (innerLength > 0) { // Not some function call "defaultFunc()" + const auto inner = QStringView{expr}.mid(parenPos + 1, innerLength); + if (isQualifiedCppIdentifier(inner) + && !AbstractMetaBuilder::dontFixDefaultValue(inner)) { + const QString replacement = fixSimpleDefaultValue(inner, implementingClass); + if (!replacement.isEmpty() && replacement != inner) + expr.replace(parenPos + 1, innerLength, replacement); } } + // Is this a class constructor "Class(Field)"? Expand it. + const auto te = type.typeEntry(); + if (!te->isComplex()) + return expr; + const QString &qualifiedTypeName = te->qualifiedCppName(); + if (!qualifiedTypeName.contains(u"::")) // Nothing to qualify here + return expr; + const auto className = QStringView{expr}.left(parenPos); + if (isUnderQualifiedSpec(qualifiedTypeName, className)) + expr.replace(0, className.size(), qualifiedTypeName); } return expr; } +QString AbstractMetaBuilder::fixDefaultValue(const QString &expr, const AbstractMetaType &type, + const AbstractMetaClassCPtr &c) const +{ + return d->fixDefaultValue(expr, type, c); +} + bool AbstractMetaBuilderPrivate::isEnum(const FileModelItem &dom, const QStringList& qualified_name) { CodeModelItem item = dom->model()->findItem(qualified_name, dom); return item && item->kind() == _EnumModelItem::__node_kind; } -AbstractMetaClass* AbstractMetaBuilderPrivate::findTemplateClass(const QString &name, - const AbstractMetaClass *context, - TypeInfo *info, - ComplexTypeEntry **baseContainerType) const +AbstractMetaClassPtr + AbstractMetaBuilderPrivate::findTemplateClass(const QString &name, + const AbstractMetaClassCPtr &context, + TypeInfo *info, + ComplexTypeEntryPtr *baseContainerType) const { if (baseContainerType) - *baseContainerType = nullptr; - TypeDatabase* types = TypeDatabase::instance(); + baseContainerType->reset(); + auto *types = TypeDatabase::instance(); - QStringList scope = context->typeEntry()->qualifiedCppName().split(colonColon()); + QStringList scope = context->typeEntry()->qualifiedCppName().split(u"::"_s); QString errorMessage; scope.removeLast(); - for (int i = scope.size(); i >= 0; --i) { - QString prefix = i > 0 ? QStringList(scope.mid(0, i)).join(colonColon()) + colonColon() : QString(); + for (auto i = scope.size(); i >= 0; --i) { + QString prefix = i > 0 ? QStringList(scope.mid(0, i)).join(u"::"_s) + u"::"_s : QString(); QString completeName = prefix + name; const TypeInfo parsed = TypeParser::parse(completeName, &errorMessage); - QString qualifiedName = parsed.qualifiedName().join(colonColon()); + QString qualifiedName = parsed.qualifiedName().join(u"::"_s); if (qualifiedName.isEmpty()) { qWarning().noquote().nospace() << "Unable to parse type \"" << completeName << "\" while looking for template \"" << name << "\": " << errorMessage; @@ -2610,8 +3044,8 @@ AbstractMetaClass* AbstractMetaBuilderPrivate::findTemplateClass(const QString & if (info) *info = parsed; - AbstractMetaClass *templ = nullptr; - for (AbstractMetaClass *c : qAsConst(m_templates)) { + AbstractMetaClassPtr templ; + for (const auto &c : std::as_const(m_templates)) { if (c->typeEntry()->name() == qualifiedName) { templ = c; break; @@ -2631,19 +3065,18 @@ AbstractMetaClass* AbstractMetaBuilderPrivate::findTemplateClass(const QString & return nullptr; } -AbstractMetaClassList AbstractMetaBuilderPrivate::getBaseClasses(const AbstractMetaClass *metaClass) const +AbstractMetaClassCList + AbstractMetaBuilderPrivate::getBaseClasses(const AbstractMetaClassCPtr &metaClass) const { // Shortcut if inheritance has already been set up if (metaClass->inheritanceDone() || !metaClass->needsInheritanceSetup()) return metaClass->baseClasses(); - AbstractMetaClassList baseClasses; + AbstractMetaClassCList baseClasses; const QStringList &baseClassNames = metaClass->baseClassNames(); for (const QString& parent : baseClassNames) { - AbstractMetaClass *cls = nullptr; - if (parent.contains(QLatin1Char('<'))) - cls = findTemplateClass(parent, metaClass); - else - cls = AbstractMetaClass::findClass(m_metaClasses, parent); + const auto cls = parent.contains(u'<') + ? findTemplateClass(parent, metaClass) + : AbstractMetaClass::findClass(m_metaClasses, parent); if (cls) baseClasses << cls; @@ -2663,7 +3096,7 @@ std::optional<AbstractMetaType> returned.setOriginalTemplateType(metaType); if (returned.typeEntry()->isTemplateArgument()) { - const auto *tae = static_cast<const TemplateArgumentEntry*>(returned.typeEntry()); + const auto tae = std::static_pointer_cast<const TemplateArgumentEntry>(returned.typeEntry()); // If the template is intantiated with void we special case this as rejecting the functions that use this // parameter from the instantiation. @@ -2681,7 +3114,7 @@ std::optional<AbstractMetaType> if (returned.hasInstantiations()) { AbstractMetaTypeList instantiations = returned.instantiations(); - for (int i = 0; i < instantiations.count(); ++i) { + for (qsizetype i = 0; i < instantiations.size(); ++i) { auto ins = inheritTemplateType(templateTypes, instantiations.at(i)); if (!ins.has_value()) return {}; @@ -2693,84 +3126,240 @@ std::optional<AbstractMetaType> return returned; } -bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, - const AbstractMetaClass *templateClass, +AbstractMetaClassPtr + AbstractMetaBuilder::inheritTemplateClass(const ComplexTypeEntryPtr &te, + const AbstractMetaClassCPtr &templateClass, + const AbstractMetaTypeList &templateTypes, + InheritTemplateFlags flags) +{ + auto result = std::make_shared<AbstractMetaClass>(); + result->setTypeDef(true); + + result->setTypeEntry(te); + if (!AbstractMetaBuilderPrivate::inheritTemplate(result, templateClass, + templateTypes, flags)) { + return {}; + } + AbstractMetaBuilderPrivate::inheritTemplateFunctions(result); + return result; +} + + +static std::optional<AbstractMetaType> + inheritTemplateParameter(const AbstractMetaClassPtr &subclass, + const AbstractMetaClassCPtr &templateClass, + const TypeInfo &info, QString *errorMessage) +{ + QString typeName = info.qualifiedName().join("::"_L1); + TypeDatabase *typeDb = TypeDatabase::instance(); + TypeEntryPtr t; + // Check for a non-type template integer parameter, that is, for a base + // "template <int R, int C> Matrix<R, C>" and subclass + // "typedef Matrix<2,3> Matrix2x3;". If so, create dummy entries of + // EnumValueTypeEntry for the integer values encountered on the fly. + if (isNumber(typeName)) { + t = typeDb->findType(typeName); + if (!t) { + auto parent = typeSystemTypeEntry(subclass->typeEntry()); + t = TypeDatabase::instance()->addConstantValueTypeEntry(typeName, parent); + } + } else { + QStringList possibleNames; + possibleNames << subclass->qualifiedCppName() + "::"_L1 + typeName; + possibleNames << templateClass->qualifiedCppName() + "::"_L1 + typeName; + if (subclass->enclosingClass()) + possibleNames << subclass->enclosingClass()->qualifiedCppName() + "::"_L1 + typeName; + possibleNames << typeName; + + for (const QString &possibleName : std::as_const(possibleNames)) { + t = typeDb->findType(possibleName); + if (t) + break; + } + } + + if (!t) { + *errorMessage = msgIgnoringTemplateParameter(typeName, + "The corresponding type was not found in the typesystem."); + return std::nullopt; + } + + if (t->isContainer()) { + *errorMessage = msgIgnoringTemplateParameter(typeName, + "Template inheritance from nested containers is not supported"); + return std::nullopt; + } + AbstractMetaType result(t); + result.setConstant(info.isConstant()); + result.setReferenceType(info.referenceType()); + result.setIndirectionsV(info.indirectionsV()); + result.decideUsagePattern(); + return result; +} + +bool AbstractMetaBuilderPrivate::inheritTemplate(const AbstractMetaClassPtr &subclass, + const AbstractMetaClassCPtr &templateClass, const TypeInfo &info) { AbstractMetaTypeList templateTypes; + QString errorMessage; for (const TypeInfo &i : info.instantiations()) { - QString typeName = i.qualifiedName().join(colonColon()); - TypeDatabase *typeDb = TypeDatabase::instance(); - TypeEntry *t = nullptr; - // Check for a non-type template integer parameter, that is, for a base - // "template <int R, int C> Matrix<R, C>" and subclass - // "typedef Matrix<2,3> Matrix2x3;". If so, create dummy entries of - // EnumValueTypeEntry for the integer values encountered on the fly. - if (isNumber(typeName)) { - t = typeDb->findType(typeName); - if (!t) { - auto parent = subclass->typeEntry()->typeSystemTypeEntry(); - t = TypeDatabase::instance()->addConstantValueTypeEntry(typeName, parent); - } + const auto typeO = inheritTemplateParameter(subclass, templateClass, i, &errorMessage); + if (typeO.has_value()) { + templateTypes.append(typeO.value()); } else { - QStringList possibleNames; - possibleNames << subclass->qualifiedCppName() + colonColon() + typeName; - possibleNames << templateClass->qualifiedCppName() + colonColon() + typeName; - if (subclass->enclosingClass()) - possibleNames << subclass->enclosingClass()->qualifiedCppName() + colonColon() + typeName; - possibleNames << typeName; - - for (const QString &possibleName : qAsConst(possibleNames)) { - t = typeDb->findType(possibleName); - if (t) - break; - } - } - - if (t) { - AbstractMetaType temporaryType(t); - temporaryType.setConstant(i.isConstant()); - temporaryType.setReferenceType(i.referenceType()); - temporaryType.setIndirectionsV(i.indirectionsV()); - temporaryType.decideUsagePattern(); - templateTypes << temporaryType; - } else { - qCWarning(lcShiboken).noquote().nospace() - << "Ignoring template parameter " << typeName << " from " - << info.toString() << ". The corresponding type was not found in the typesystem."; + errorMessage = msgInheritTemplateIssue(subclass, info, errorMessage); + qCWarning(lcShiboken, "%s", qPrintable(errorMessage)); } } + if (templateTypes.isEmpty()) { + errorMessage = msgInheritTemplateIssue(subclass, info, + "No template parameters could be inherited"_L1); + qCWarning(lcShiboken, "%s", qPrintable(errorMessage)); + return false; + } + return inheritTemplate(subclass, templateClass, templateTypes); +} +bool AbstractMetaBuilderPrivate::inheritTemplate(const AbstractMetaClassPtr &subclass, + const AbstractMetaClassCPtr &templateClass, + const AbstractMetaTypeList &templateTypes, + InheritTemplateFlags flags) +{ subclass->setTemplateBaseClass(templateClass); + if (flags.testFlag(InheritTemplateFlag::SetEnclosingClass)) + subclass->setEnclosingClass(templateClass->enclosingClass()); subclass->setTemplateBaseClassInstantiations(templateTypes); subclass->setBaseClass(templateClass->baseClass()); return true; } -static bool inheritTemplateFunction(const AbstractMetaFunctionCPtr &function, - const AbstractMetaFunctionCList &existingSubclassFuncs, - const AbstractMetaClass *subclass, - const AbstractMetaClass *templateBaseClass) +AbstractMetaFunctionPtr + AbstractMetaBuilderPrivate::inheritTemplateFunction(const AbstractMetaFunctionCPtr &function, + const AbstractMetaTypeList &templateTypes) +{ + AbstractMetaFunctionPtr f(function->copy()); + f->setArguments(AbstractMetaArgumentList()); + f->setFlags(f->flags() | AbstractMetaFunction::Flag::InheritedFromTemplate); + + if (!function->isVoid()) { + auto returnType = inheritTemplateType(templateTypes, function->type()); + if (!returnType.has_value()) + return {}; + f->setType(returnType.value()); + } + + const AbstractMetaArgumentList &arguments = function->arguments(); + for (const AbstractMetaArgument &argument : arguments) { + auto argType = inheritTemplateType(templateTypes, argument.type()); + if (!argType.has_value()) + return {}; + AbstractMetaArgument arg = argument; + arg.setType(argType.value()); + f->addArgument(arg); + } + + return f; +} + +AbstractMetaFunctionPtr + AbstractMetaBuilder::inheritTemplateFunction(const AbstractMetaFunctionCPtr &function, + const AbstractMetaTypeList &templateTypes) +{ + return AbstractMetaBuilderPrivate::inheritTemplateFunction(function, templateTypes); +} + +AbstractMetaFunctionPtr + AbstractMetaBuilderPrivate::inheritTemplateMember(const AbstractMetaFunctionCPtr &function, + const AbstractMetaTypeList &templateTypes, + const AbstractMetaClassCPtr &templateClass, + const AbstractMetaClassPtr &subclass) +{ + AbstractMetaFunctionPtr f = inheritTemplateFunction(function, templateTypes); + if (!f) + return {}; + + // There is no base class in the target language to inherit from here, so + // the template instantiation is the class that implements the function. + f->setImplementingClass(subclass); + + // We also set it as the declaring class, since the superclass is + // supposed to disappear. This allows us to make certain function modifications + // on the inherited functions. + f->setDeclaringClass(subclass); + + if (f->isConstructor()) { + f->setName(subclass->name()); + f->setOriginalName(subclass->name()); + } + + ComplexTypeEntryPtr te = subclass->typeEntry(); + const FunctionModificationList mods = function->modifications(templateClass); + + for (auto mod : mods) { + mod.setSignature(f->minimalSignature()); + +// If we ever need it... Below is the code to do +// substitution of the template instantation type inside +// injected code.. +#if 0 + if (mod.modifiers & Modification::CodeInjection) { + for (int j = 0; j < template_types.size(); ++j) { + CodeSnip &snip = mod.snips.last(); + QString code = snip.code(); + code.replace(QString::fromLatin1("$$QT_TEMPLATE_%1$$").arg(j), + template_types.at(j)->typeEntry()->qualifiedCppName()); + snip.codeList.clear(); + snip.addCode(code); + } + } +#endif + te->addFunctionModification(mod); + } + + QString errorMessage; + if (!applyArrayArgumentModifications(f->modifications(subclass), f.get(), + &errorMessage)) { + qCWarning(lcShiboken, "While specializing %s (%s): %s", + qPrintable(subclass->name()), qPrintable(templateClass->name()), + qPrintable(errorMessage)); + } + return f; +} + +AbstractMetaFunctionPtr + AbstractMetaBuilder::inheritTemplateMember(const AbstractMetaFunctionCPtr &function, + const AbstractMetaTypeList &templateTypes, + const AbstractMetaClassCPtr &templateClass, + const AbstractMetaClassPtr &subclass) +{ + return AbstractMetaBuilderPrivate::inheritTemplateMember(function, templateTypes, + templateClass, subclass); +} + +static bool doInheritTemplateFunction(const AbstractMetaFunctionCPtr &function, + const AbstractMetaFunctionCList &existingSubclassFuncs, + const AbstractMetaClassCPtr &templateBaseClass, + const AbstractMetaClassCPtr &subclass) { // If the function is modified or the instantiation has an equally named // function we are shadowing, so we need to skip it (unless the subclass // declares it via "using"). if (function->isModifiedRemoved()) return false; + if (function->isConstructor() && !subclass->isTypeDef()) + return false; return AbstractMetaFunction::find(existingSubclassFuncs, function->name()) == nullptr || subclass->isUsingMember(templateBaseClass, function->name(), Access::Protected); } -void AbstractMetaBuilderPrivate::inheritTemplateFunctions(AbstractMetaClass *subclass) +void AbstractMetaBuilderPrivate::inheritTemplateFunctions(const AbstractMetaClassPtr &subclass) { - QString errorMessage; auto templateClass = subclass->templateBaseClass(); if (subclass->isTypeDef()) { - subclass->setHasCloneOperator(templateClass->hasCloneOperator()); - subclass->setHasEqualsOperator(templateClass->hasEqualsOperator()); - subclass->setHasHashFunction(templateClass->hasHashFunction()); + subclass->setHashFunction(templateClass->hashFunction()); subclass->setHasNonPrivateConstructor(templateClass->hasNonPrivateConstructor()); subclass->setHasPrivateDestructor(templateClass->hasPrivateDestructor()); subclass->setHasProtectedDestructor(templateClass->hasProtectedDestructor()); @@ -2782,82 +3371,13 @@ void AbstractMetaBuilderPrivate::inheritTemplateFunctions(AbstractMetaClass *sub subclass->functions(); // Take copy const auto &templateClassFunctions = templateClass->functions(); for (const auto &function : templateClassFunctions) { - if (!inheritTemplateFunction(function, existingSubclassFuncs, - subclass, templateClass)) { - continue; - } - - std::unique_ptr<AbstractMetaFunction> f(function->copy()); - f->setArguments(AbstractMetaArgumentList()); - - if (!function->isVoid()) { - auto returnType = inheritTemplateType(templateTypes, function->type()); - if (!returnType.has_value()) - continue; - f->setType(returnType.value()); - } - - const AbstractMetaArgumentList &arguments = function->arguments(); - for (const AbstractMetaArgument &argument : arguments) { - auto argType = inheritTemplateType(templateTypes, argument.type()); - if (!argType.has_value()) - break; - AbstractMetaArgument arg = argument; - arg.setType(argType.value()); - f->addArgument(arg); - } - - if (f->arguments().size() < function->arguments().size()) - continue; - - // There is no base class in the target language to inherit from here, so - // the template instantiation is the class that implements the function. - f->setImplementingClass(subclass); - - // We also set it as the declaring class, since the superclass is - // supposed to disappear. This allows us to make certain function modifications - // on the inherited functions. - f->setDeclaringClass(subclass); - - if (f->isConstructor()) { - if (!subclass->isTypeDef()) - continue; - f->setName(subclass->name()); - f->setOriginalName(subclass->name()); + if (doInheritTemplateFunction(function, existingSubclassFuncs, + templateClass, subclass)) { + AbstractMetaFunctionCPtr f = inheritTemplateMember(function, templateTypes, + templateClass, subclass); + if (f) + AbstractMetaClass::addFunction(subclass, f); } - - ComplexTypeEntry* te = subclass->typeEntry(); - FunctionModificationList mods = function->modifications(templateClass); - for (int i = 0; i < mods.size(); ++i) { - FunctionModification mod = mods.at(i); - mod.setSignature(f->minimalSignature()); - - // If we ever need it... Below is the code to do - // substitution of the template instantation type inside - // injected code.. -#if 0 - if (mod.modifiers & Modification::CodeInjection) { - for (int j = 0; j < template_types.size(); ++j) { - CodeSnip &snip = mod.snips.last(); - QString code = snip.code(); - code.replace(QString::fromLatin1("$$QT_TEMPLATE_%1$$").arg(j), - template_types.at(j)->typeEntry()->qualifiedCppName()); - snip.codeList.clear(); - snip.addCode(code); - } - } -#endif - te->addFunctionModification(mod); - } - - - if (!applyArrayArgumentModifications(f->modifications(subclass), f.get(), - &errorMessage)) { - qCWarning(lcShiboken, "While specializing %s (%s): %s", - qPrintable(subclass->name()), qPrintable(templateClass->name()), - qPrintable(errorMessage)); - } - subclass->addFunction(AbstractMetaFunctionCPtr(f.release())); } // Take copy @@ -2866,8 +3386,7 @@ void AbstractMetaBuilderPrivate::inheritTemplateFunctions(AbstractMetaClass *sub for (const AbstractMetaField &field : templateClassFields) { // If the field is modified or the instantiation has a field named // the same as an existing field we have shadowing, so we need to skip it. - if (field.isModifiedRemoved(TypeSystem::All) - || field.isStatic() + if (field.isModifiedRemoved() || field.isStatic() || AbstractMetaField::find(existingSubclassFields, field.name()).has_value()) { continue; } @@ -2882,7 +3401,7 @@ void AbstractMetaBuilderPrivate::inheritTemplateFunctions(AbstractMetaClass *sub } } -void AbstractMetaBuilderPrivate::parseQ_Properties(AbstractMetaClass *metaClass, +void AbstractMetaBuilderPrivate::parseQ_Properties(const AbstractMetaClassPtr &metaClass, const QStringList &declarations) { const QStringList scopes = currentScope()->qualifiedName(); @@ -2893,7 +3412,7 @@ void AbstractMetaBuilderPrivate::parseQ_Properties(AbstractMetaClass *metaClass, if (spec.has_value()) { spec->setIndex(i); metaClass->addPropertySpec(spec.value()); - } else { + } else if (!errorMessage.isEmpty()) { QString message; QTextStream str(&message); str << metaClass->sourceLocation() << errorMessage; @@ -2922,63 +3441,35 @@ void AbstractMetaBuilderPrivate::parseQ_Properties(AbstractMetaClass *metaClass, } } -static AbstractMetaFunctionCPtr findCopyCtor(AbstractMetaClass* cls) -{ - for (const auto &f : cls->functions()) { - const AbstractMetaFunction::FunctionType t = f->functionType(); - if (t == AbstractMetaFunction::CopyConstructorFunction || t == AbstractMetaFunction::AssignmentOperatorFunction) - return f; - } - return {}; -} - -void AbstractMetaBuilderPrivate::setupClonable(AbstractMetaClass *cls) -{ - bool result = true; - - // find copy ctor for the current class - auto copyCtor = findCopyCtor(cls); - if (!copyCtor.isNull()) { // if exists a copy ctor in this class - result = copyCtor->isPublic(); - } else { // else... lets find one in the parent class - QQueue<AbstractMetaClass*> baseClasses; - if (cls->baseClass()) - baseClasses.enqueue(cls->baseClass()); - - while (!baseClasses.isEmpty()) { - AbstractMetaClass* currentClass = baseClasses.dequeue(); - if (currentClass->baseClass()) - baseClasses.enqueue(currentClass->baseClass()); - - copyCtor = findCopyCtor(currentClass); - if (copyCtor) { - result = copyCtor->isPublic(); - break; - } - } - } - cls->setHasCloneOperator(result); -} - -void AbstractMetaBuilderPrivate::setupExternalConversion(AbstractMetaClass *cls) +void AbstractMetaBuilderPrivate::setupExternalConversion(const AbstractMetaClassCPtr &cls) { const auto &convOps = cls->operatorOverloads(OperatorQueryOption::ConversionOp); for (const auto &func : convOps) { if (func->isModifiedRemoved()) continue; - AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_metaClasses, func->type().typeEntry()); + const auto metaClass = + AbstractMetaClass::findClass(m_metaClasses, func->type().typeEntry()); if (!metaClass) continue; metaClass->addExternalConversionOperator(func); } - const AbstractMetaClassList &innerClasses = cls->innerClasses(); - for (AbstractMetaClass *innerClass : innerClasses) + for (const auto &innerClass : cls->innerClasses()) setupExternalConversion(innerClass); } static void writeRejectLogFile(const QString &name, - const QMap<QString, AbstractMetaBuilder::RejectReason> &rejects) -{ + const AbstractMetaBuilderPrivate::RejectSet &rejects) +{ + static const QHash<AbstractMetaBuilder::RejectReason, QByteArray> descriptions ={ + {AbstractMetaBuilder::NotInTypeSystem, "Not in type system"_ba}, + {AbstractMetaBuilder::GenerationDisabled, "Generation disabled by type system"_ba}, + {AbstractMetaBuilder::RedefinedToNotClass, "Type redefined to not be a class"_ba}, + {AbstractMetaBuilder::UnmatchedReturnType, "Unmatched return type"_ba}, + {AbstractMetaBuilder::UnmatchedArgumentType, "Unmatched argument type"_ba}, + {AbstractMetaBuilder::UnmatchedOperator, "Unmatched operator"_ba}, + {AbstractMetaBuilder::Deprecated, "Deprecated"_ba} + }; + QFile f(name); if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { qCWarning(lcShiboken, "%s", qPrintable(msgCannotOpenForWriting(f))); @@ -2987,70 +3478,37 @@ static void writeRejectLogFile(const QString &name, QTextStream s(&f); - - for (int reason = 0; reason < AbstractMetaBuilder::NoReason; ++reason) { - s << QString(72, QLatin1Char('*')) << Qt::endl; - switch (reason) { - case AbstractMetaBuilder::NotInTypeSystem: - s << "Not in type system"; - break; - case AbstractMetaBuilder::GenerationDisabled: - s << "Generation disabled by type system"; - break; - case AbstractMetaBuilder::RedefinedToNotClass: - s << "Type redefined to not be a class"; - break; - - case AbstractMetaBuilder::UnmatchedReturnType: - s << "Unmatched return type"; - break; - - case AbstractMetaBuilder::UnmatchedArgumentType: - s << "Unmatched argument type"; - break; - - case AbstractMetaBuilder::ApiIncompatible: - s << "Incompatible API"; - break; - - case AbstractMetaBuilder::Deprecated: - s << "Deprecated"; - break; - - default: - s << "unknown reason"; - break; + int lastReason = -1; + for (const auto &e : rejects) { + if (e.reason != lastReason) { + const QByteArray description = descriptions.value(e.reason, "Unknown reason"_ba); + const QByteArray underline(description.size(), '*'); + if (lastReason != -1) + s << '\n'; + s << underline << '\n' << description << '\n' << underline << "\n\n"; + lastReason = e.reason; } - s << Qt::endl; - - for (QMap<QString, AbstractMetaBuilder::RejectReason>::const_iterator it = rejects.constBegin(); - it != rejects.constEnd(); ++it) { - if (it.value() != reason) - continue; - s << " - " << it.key() << Qt::endl; - } - - s << QString(72, QLatin1Char('*')) << Qt::endl << Qt::endl; + s << " - " << e << '\n'; } - } void AbstractMetaBuilderPrivate::dumpLog() const { - writeRejectLogFile(m_logDirectory + QLatin1String("mjb_rejected_classes.log"), m_rejectedClasses); - writeRejectLogFile(m_logDirectory + QLatin1String("mjb_rejected_enums.log"), m_rejectedEnums); - writeRejectLogFile(m_logDirectory + QLatin1String("mjb_rejected_functions.log"), m_rejectedFunctions); - writeRejectLogFile(m_logDirectory + QLatin1String("mjb_rejected_fields.log"), m_rejectedFields); + writeRejectLogFile(m_logDirectory + u"mjb_rejected_classes.log"_s, m_rejectedClasses); + writeRejectLogFile(m_logDirectory + u"mjb_rejected_enums.log"_s, m_rejectedEnums); + writeRejectLogFile(m_logDirectory + u"mjb_rejected_functions.log"_s, m_rejectedFunctions); + writeRejectLogFile(m_logDirectory + u"mjb_rejected_fields.log"_s, m_rejectedFields); } -using ClassGraph = Graph<AbstractMetaClass *>; - -// Add a dependency of the class associated with typeEntry on clazz -static bool addClassDependency(const AbstractMetaClassList &classList, - const TypeEntry *typeEntry, - AbstractMetaClass *clazz, - ClassGraph *graph) +// Topological sorting of classes. Templates for use with +// AbstractMetaClassList/AbstractMetaClassCList. +// Add a dependency of the class associated with typeEntry on clazz. +template <class MetaClass> +static bool addClassDependency(const QList<std::shared_ptr<MetaClass> > &classList, + const TypeEntryCPtr &typeEntry, + std::shared_ptr<MetaClass> clazz, + Graph<std::shared_ptr<MetaClass> > *graph) { if (!typeEntry->isComplex() || typeEntry == clazz->typeEntry()) return false; @@ -3060,10 +3518,12 @@ static bool addClassDependency(const AbstractMetaClassList &classList, return graph->addEdge(c, clazz); } -AbstractMetaClassList AbstractMetaBuilderPrivate::classesTopologicalSorted(const AbstractMetaClassList &classList, - const Dependencies &additionalDependencies) +template <class MetaClass> +static QList<std::shared_ptr<MetaClass> > + topologicalSortHelper(const QList<std::shared_ptr<MetaClass> > &classList, + const Dependencies &additionalDependencies) { - ClassGraph graph(classList.cbegin(), classList.cend()); + Graph<std::shared_ptr<MetaClass> > graph(classList.cbegin(), classList.cend()); for (const auto &dep : additionalDependencies) { if (!graph.addEdge(dep.parent, dep.child)) { @@ -3073,14 +3533,14 @@ AbstractMetaClassList AbstractMetaBuilderPrivate::classesTopologicalSorted(const } } - for (AbstractMetaClass *clazz : classList) { + for (const auto &clazz : classList) { if (auto enclosingC = clazz->enclosingClass()) { - auto enclosing = const_cast<AbstractMetaClass *>(enclosingC); + const auto enclosing = std::const_pointer_cast<MetaClass>(enclosingC); graph.addEdge(enclosing, clazz); } - for (auto baseClass : clazz->baseClasses()) - graph.addEdge(baseClass, clazz); + for (const auto &baseClass : clazz->baseClasses()) + graph.addEdge(std::const_pointer_cast<MetaClass>(baseClass), clazz); for (const auto &func : clazz->functions()) { const AbstractMetaArgumentList &arguments = func->arguments(); @@ -3106,24 +3566,44 @@ AbstractMetaClassList AbstractMetaBuilderPrivate::classesTopologicalSorted(const const auto result = graph.topologicalSort(); if (!result.isValid() && graph.nodeCount()) { - QTemporaryFile tempFile(QDir::tempPath() + QLatin1String("/cyclic_depXXXXXX.dot")); + QTemporaryFile tempFile(QDir::tempPath() + u"/cyclic_depXXXXXX.dot"_s); tempFile.setAutoRemove(false); - tempFile.open(); - graph.dumpDot(tempFile.fileName(), - [] (const AbstractMetaClass *c) { return c->name(); }); + const bool ok = tempFile.open(); + if (ok) { + graph.dumpDot(tempFile.fileName(), + [] (const AbstractMetaClassCPtr &c) { return c->name(); }); + } QString message; QTextStream str(&message); str << "Cyclic dependency of classes found:"; - for (auto c : result.cyclic) + for (const auto &c : result.cyclic) str << ' ' << c->name(); - str << ". Graph can be found at \"" << QDir::toNativeSeparators(tempFile.fileName()) << '"'; + str << '.'; + if (ok) { + str << " Graph can be found at \"" + << QDir::toNativeSeparators(tempFile.fileName()) << '"'; + } qCWarning(lcShiboken, "%s", qPrintable(message)); } return result.result; } +AbstractMetaClassList + AbstractMetaBuilderPrivate::classesTopologicalSorted(const AbstractMetaClassList &classList, + const Dependencies &additionalDependencies) +{ + return topologicalSortHelper(classList, additionalDependencies); +} + +AbstractMetaClassCList + AbstractMetaBuilderPrivate::classesTopologicalSorted(const AbstractMetaClassCList &classList, + const Dependencies &additionalDependencies) +{ + return topologicalSortHelper(classList, additionalDependencies); +} + void AbstractMetaBuilderPrivate::pushScope(const NamespaceModelItem &item) { // For purposes of type lookup, join all namespaces of the same name @@ -3137,8 +3617,8 @@ void AbstractMetaBuilderPrivate::pushScope(const NamespaceModelItem &item) } } if (candidates.size() > 1) { - NamespaceModelItem joined(new _NamespaceModelItem(m_scopes.constLast()->model(), - name, _CodeModelItem::Kind_Namespace)); + auto joined = std::make_shared<_NamespaceModelItem>(m_scopes.constLast()->model(), + name, _CodeModelItem::Kind_Namespace); joined->setScope(item->scope()); for (const auto &n : candidates) joined->appendNamespace(*n); @@ -3171,13 +3651,18 @@ void AbstractMetaBuilder::setSkipDeprecated(bool value) d->m_skipDeprecated = value; } +void AbstractMetaBuilder::setApiExtractorFlags(ApiExtractorFlags flags) +{ + d->m_apiExtractorFlags = flags; +} + // 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('\\'); + return c == u'/' || c == u'\\'; } static bool matchHeader(const QString &headerPath, const QString &fileName) @@ -3187,13 +3672,13 @@ static bool matchHeader(const QString &headerPath, const QString &fileName) #else static const Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive; #endif - const int pathSize = headerPath.size(); + const auto pathSize = headerPath.size(); return fileName.size() > pathSize && isFileSystemSlash(fileName.at(pathSize)) && fileName.startsWith(headerPath, caseSensitivity); } -void AbstractMetaBuilderPrivate::setInclude(TypeEntry *te, const QString &path) const +void AbstractMetaBuilderPrivate::setInclude(const TypeEntryPtr &te, const QString &path) const { auto it = m_resolveIncludeHash.find(path); if (it == m_resolveIncludeHash.end()) { @@ -3241,9 +3726,9 @@ void AbstractMetaBuilder::formatDebug(QDebug &debug) const 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()) { + if (const auto scopeCount = d->m_scopes.size()) { debug << "\n scopes[" << scopeCount << "]=("; - for (int i = 0; i < scopeCount; ++i) { + for (qsizetype i = 0; i < scopeCount; ++i) { if (i) debug << ", "; _CodeModelItem::formatKind(debug, d->m_scopes.at(i)->kind()); |