diff options
Diffstat (limited to 'sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp')
-rw-r--r-- | sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp | 3253 |
1 files changed, 0 insertions, 3253 deletions
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp deleted file mode 100644 index 9c930dcdc..000000000 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ /dev/null @@ -1,3253 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#include "abstractmetabuilder_p.h" -#include "messages.h" -#include "reporthandler.h" -#include "typedatabase.h" - -#include <clangparser/clangbuilder.h> -#include <clangparser/clangutils.h> -#include <clangparser/compilersupport.h> - -#include "parser/codemodel.h" - -#include <QDebug> -#include <QDir> -#include <QFile> -#include <QFileInfo> -#include <QRegularExpression> -#include <QTextCodec> -#include <QTextStream> -#include <QVariant> -#include <QTime> -#include <QQueue> -#include <QDir> - -#include <cstdio> -#include <algorithm> -#include "graph.h" -#include <QTemporaryFile> - -static inline QString colonColon() { return QStringLiteral("::"); } - -static QString stripTemplateArgs(const QString &name) -{ - int pos = name.indexOf(QLatin1Char('<')); - return pos < 0 ? name : name.left(pos); -} - -static QStringList parseTemplateType(const QString &name) { - int n = name.indexOf(QLatin1Char('<')); - if (n <= 0) { - // If name starts with '<' or contains an unmatched (i.e. any) '>', we - // reject it - if (n == 0 || name.count(QLatin1Char('>'))) - return QStringList(); - // Doesn't look like a template instantiation; just return the name - return QStringList() << name; - } - - // Split the type name into the template name and template arguments; the - // part before the opening '<' is the template name - // - // Example: - // "foo<A, bar<B, C>, D>" -> ( "foo", "A", "bar<B, C>", "D" ) - QStringList result; - result << name.left(n).trimmed(); - - // Extract template arguments - int i, depth = 1; - const int l = name.length(); - for (i = n + 1; i < l; ++i) { - // Consume balanced '<'/'>' within a single argument so that we won't - // split on ',' as part of a single argument which is itself a - // multi-argument template type - if (name[i] == QLatin1Char('<')) { - ++depth; - } else if (name[i] == QLatin1Char('>')) { - if (--depth == 0) - break; - } else if (name[i] == QLatin1Char(',') && depth == 1) { - // Encountered ',' in template argument list that is not within - // another template name; add current argument to result and start - // working on the next argument - result << name.mid(n + 1, i - n - 1).trimmed(); - n = i; - } - } - if (i >= l) // arg list not closed - return QStringList(); - if (i + 1 < l) // arg list closed before end of name - return QStringList(); - - // Add final argument and return result - result << name.mid(n + 1, i - n - 1).trimmed(); - return result; -} - -AbstractMetaBuilderPrivate::AbstractMetaBuilderPrivate() : - m_logDirectory(QLatin1String(".") + QDir::separator()) -{ -} - -AbstractMetaBuilderPrivate::~AbstractMetaBuilderPrivate() -{ - qDeleteAll(m_globalEnums); - qDeleteAll(m_globalFunctions); - qDeleteAll(m_templates); - qDeleteAll(m_smartPointers); - qDeleteAll(m_metaClasses); -} - -AbstractMetaBuilder::AbstractMetaBuilder() : d(new AbstractMetaBuilderPrivate) -{ - d->q = this; -} - -AbstractMetaBuilder::~AbstractMetaBuilder() -{ - delete d; -} - -AbstractMetaClassList AbstractMetaBuilder::classes() const -{ - return d->m_metaClasses; -} - -AbstractMetaClassList AbstractMetaBuilder::templates() const -{ - return d->m_templates; -} - -AbstractMetaClassList AbstractMetaBuilder::smartPointers() const -{ - return d->m_smartPointers; -} - -AbstractMetaFunctionList AbstractMetaBuilder::globalFunctions() const -{ - return d->m_globalFunctions; -} - -AbstractMetaEnumList AbstractMetaBuilder::globalEnums() const -{ - return d->m_globalEnums; -} - -AbstractMetaEnum *AbstractMetaBuilder::findEnum(const TypeEntry *typeEntry) const -{ - if (typeEntry && typeEntry->isFlags()) - typeEntry = static_cast<const FlagsTypeEntry *>(typeEntry)->originator(); - return d->m_enums.value(typeEntry); -} - -void AbstractMetaBuilderPrivate::checkFunctionModifications() -{ - const auto &entries = TypeDatabase::instance()->entries(); - - for (auto it = entries.cbegin(), end = entries.cend(); it != end; ++it) { - const TypeEntry *entry = it.value(); - if (!entry) - continue; - if (!entry->isComplex() || entry->codeGeneration() == TypeEntry::GenerateNothing) - continue; - - auto centry = static_cast<const ComplexTypeEntry *>(entry); - - if (!(centry->codeGeneration() & TypeEntry::GenerateTargetLang)) - continue; - - FunctionModificationList modifications = centry->functionModifications(); - - for (const FunctionModification &modification : qAsConst(modifications)) { - QString signature = modification.signature(); - - QString name = signature.trimmed(); - name.truncate(name.indexOf(QLatin1Char('('))); - - AbstractMetaClass *clazz = AbstractMetaClass::findClass(m_metaClasses, centry); - if (!clazz) - continue; - - const AbstractMetaFunctionList functions = clazz->functions(); - bool found = false; - QStringList possibleSignatures; - for (AbstractMetaFunction *function : functions) { - if (function->implementingClass() == clazz - && modification.matches(function->minimalSignature())) { - found = true; - break; - } - - if (function->originalName() == name) { - possibleSignatures.append(function->minimalSignature() + QLatin1String(" in ") - + function->implementingClass()->name()); - } - } - - if (!found) { - qCWarning(lcShiboken).noquote().nospace() - << msgNoFunctionForModification(signature, - modification.originalSignature(), - clazz->qualifiedCppName(), - possibleSignatures, functions); - } - } - } -} - -AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(const ArgumentModelItem &argument, - AbstractMetaClass *currentClass) -{ - AbstractMetaClass *returned = nullptr; - AbstractMetaType *type = translateType(argument->type(), currentClass); - if (type && type->typeEntry() && type->typeEntry()->isComplex()) { - const TypeEntry *entry = type->typeEntry(); - returned = AbstractMetaClass::findClass(m_metaClasses, entry); - } - delete type; - return returned; -} - -/** - * 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) -{ - ArgumentList arguments = function_item->arguments(); - if (arguments.size() == 1) { - if (AbstractMetaClass *cls = argumentToClass(arguments.at(0), currentClass)) - cls->setHasHashFunction(true); - } -} - -/** - * Check if a class has a debug stream operator that can be used as toString - */ - -void AbstractMetaBuilderPrivate::registerToStringCapability(const FunctionModelItem &function_item, - AbstractMetaClass *currentClass) -{ - ArgumentList arguments = function_item->arguments(); - if (arguments.size() == 2) { - if (arguments.at(0)->type().toString() == QLatin1String("QDebug")) { - const ArgumentModelItem &arg = arguments.at(1); - if (AbstractMetaClass *cls = argumentToClass(arg, currentClass)) { - if (arg->type().indirections() < 2) - cls->setToStringCapability(true); - } - } - } -} - -void AbstractMetaBuilderPrivate::traverseOperatorFunction(const FunctionModelItem &item, - AbstractMetaClass *currentClass) -{ - if (item->accessPolicy() != CodeModel::Public) - return; - - ArgumentList arguments = item->arguments(); - bool firstArgumentIsSelf = true; - bool unaryOperator = false; - - auto baseoperandClass = argumentToClass(arguments.at(0), currentClass); - - if (arguments.size() == 1) { - unaryOperator = true; - } else if (!baseoperandClass - || !(baseoperandClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang)) { - baseoperandClass = argumentToClass(arguments.at(1), currentClass); - firstArgumentIsSelf = false; - } else { - AbstractMetaType *type = translateType(item->type(), currentClass); - const TypeEntry *retType = type ? type->typeEntry() : nullptr; - AbstractMetaClass *otherArgClass = argumentToClass(arguments.at(1), currentClass); - if (otherArgClass && retType - && (retType->isValue() || retType->isObject()) - && retType != baseoperandClass->typeEntry() - && retType == otherArgClass->typeEntry()) { - baseoperandClass = AbstractMetaClass::findClass(m_metaClasses, retType); - firstArgumentIsSelf = false; - } - delete type; - } - - 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(); - if (!unaryOperator && first->type()->indirections()) - metaFunction->setPointerOperator(true); - delete first; - 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); - delete last; - - metaFunction->setArguments(arguments); - metaFunction->setReverseOperator(true); - } - metaFunction->setFunctionType(AbstractMetaFunction::NormalFunction); - metaFunction->setVisibility(AbstractMetaFunction::Public); - metaFunction->setOriginalAttributes(metaFunction->attributes()); - setupFunctionDefaults(metaFunction, baseoperandClass); - baseoperandClass->addFunction(metaFunction); - Q_ASSERT(!metaFunction->wasPrivate()); - } else { - delete metaFunction; - } - } -} - -void AbstractMetaBuilderPrivate::traverseStreamOperator(const FunctionModelItem &item, - AbstractMetaClass *currentClass) -{ - ArgumentList arguments = item->arguments(); - if (arguments.size() == 2 && item->accessPolicy() == CodeModel::Public) { - AbstractMetaClass *streamClass = argumentToClass(arguments.at(0), currentClass); - AbstractMetaClass *streamedClass = argumentToClass(arguments.at(1), currentClass); - - if (streamClass && streamedClass && (streamClass->isStream())) { - AbstractMetaFunction *streamFunction = traverseFunction(item, streamedClass); - - if (streamFunction) { - streamFunction->setFunctionType(AbstractMetaFunction::GlobalScopeFunction); - // Strip first argument, since that is the containing object - AbstractMetaArgumentList arguments = streamFunction->arguments(); - if (!streamClass->typeEntry()->generateCode()) - delete arguments.takeLast(); - else - delete arguments.takeFirst(); - - streamFunction->setArguments(arguments); - - *streamFunction += AbstractMetaAttributes::FinalInTargetLang; - *streamFunction += AbstractMetaAttributes::Public; - streamFunction->setOriginalAttributes(streamFunction->attributes()); - -// streamFunction->setType(0); - - AbstractMetaClass *funcClass; - - if (!streamClass->typeEntry()->generateCode()) { - AbstractMetaArgumentList reverseArgs = reverseList(streamFunction->arguments()); - streamFunction->setArguments(reverseArgs); - streamFunction->setReverseOperator(true); - funcClass = streamedClass; - } else { - funcClass = streamClass; - } - - setupFunctionDefaults(streamFunction, funcClass); - funcClass->addFunction(streamFunction); - if (funcClass == streamClass) - funcClass->typeEntry()->addExtraInclude(streamedClass->typeEntry()->include()); - else - funcClass->typeEntry()->addExtraInclude(streamClass->typeEntry()->include()); - - } else { - delete streamFunction; - } - - } - } -} - -void AbstractMetaBuilderPrivate::sortLists() -{ - for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) - cls->sortFunctions(); -} - -FileModelItem AbstractMetaBuilderPrivate::buildDom(QByteArrayList arguments, - LanguageLevel level, - unsigned clangFlags) -{ - clang::Builder builder; - if (level == LanguageLevel::Default) - level = clang::emulatedCompilerLanguageLevel(); - arguments.prepend(QByteArrayLiteral("-std=") - + clang::languageLevelOption(level)); - FileModelItem result = clang::parse(arguments, clangFlags, builder) - ? builder.dom() : FileModelItem(); - const clang::BaseVisitor::Diagnostics &diagnostics = builder.diagnostics(); - if (const int diagnosticsCount = diagnostics.size()) { - QDebug d = qWarning(); - d.nospace(); - d.noquote(); - d << "Clang: " << diagnosticsCount << " diagnostic messages:\n"; - for (int i = 0; i < diagnosticsCount; ++i) - d << " " << diagnostics.at(i) << '\n'; - } - return result; -} - -void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) -{ - const TypeDatabase *types = TypeDatabase::instance(); - - pushScope(dom); - - // Start the generation... - const ClassList &typeValues = dom->classes(); - - ReportHandler::startProgress("Generating class model (" - + QByteArray::number(typeValues.size()) + ")..."); - for (const ClassModelItem &item : typeValues) { - if (AbstractMetaClass *cls = traverseClass(dom, item, nullptr)) - addAbstractMetaClass(cls, item.data()); - } - - // We need to know all global enums - const EnumList &enums = dom->enums(); - - ReportHandler::startProgress("Generating enum model (" - + QByteArray::number(enums.size()) + ")..."); - for (const EnumModelItem &item : enums) { - AbstractMetaEnum *metaEnum = traverseEnum(item, nullptr, QSet<QString>()); - if (metaEnum) { - if (metaEnum->typeEntry()->generateCode()) - m_globalEnums << metaEnum; - } - } - - const auto &namespaceTypeValues = dom->namespaces(); - ReportHandler::startProgress("Generating 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()) + ")..."); - for (const TypeDefModelItem &typeDef : typeDefs) { - if (AbstractMetaClass *cls = traverseTypeDef(dom, typeDef, nullptr)) - addAbstractMetaClass(cls, typeDef.data()); - } - - traverseTypesystemTypedefs(); - - for (const ClassModelItem &item : typeValues) - traverseClassMembers(item); - - for (const NamespaceModelItem &item : namespaceTypeValues) - traverseNamespaceMembers(item); - - // Global functions - const FunctionList &functions = dom->functions(); - for (const FunctionModelItem &func : functions) { - if (func->accessPolicy() != CodeModel::Public || func->name().startsWith(QLatin1String("operator"))) - continue; - - FunctionTypeEntry *funcEntry = types->findFunctionType(func->name()); - if (!funcEntry || !funcEntry->generateCode()) - continue; - - AbstractMetaFunction *metaFunc = traverseFunction(func, nullptr); - if (!metaFunc) - continue; - - if (!funcEntry->hasSignature(metaFunc->minimalSignature())) { - delete metaFunc; - continue; - } - - applyFunctionModifications(metaFunc); - - setInclude(funcEntry, func->fileName()); - if (metaFunc->typeEntry()) - delete metaFunc->typeEntry(); - - metaFunc->setTypeEntry(funcEntry); - m_globalFunctions << metaFunc; - } - - ReportHandler::startProgress("Fixing class inheritance..."); - for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) { - if (!cls->isInterface() && !cls->isNamespace()) - setupInheritance(cls); - } - - ReportHandler::startProgress("Detecting inconsistencies in class model..."); - for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) { - cls->fixFunctions(); - - if (!cls->typeEntry()) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("class '%1' does not have an entry in the type system") - .arg(cls->name()); - } else { - const bool couldAddDefaultCtors = cls->isConstructible() - && !cls->isInterface() && !cls->isNamespace() - && (cls->attributes() & AbstractMetaAttributes::HasRejectedConstructor) == 0; - if (couldAddDefaultCtors) { - if (!cls->hasConstructors()) - cls->addDefaultConstructor(); - if (cls->typeEntry()->isValue() && !cls->isAbstract() && !cls->hasCopyConstructor()) - cls->addDefaultCopyConstructor(ancestorHasPrivateCopyConstructor(cls)); - } - } - - if (cls->isAbstract() && !cls->isInterface()) - cls->typeEntry()->setLookupName(cls->typeEntry()->targetLangName() + QLatin1String("$ConcreteWrapper")); - } - const auto &allEntries = types->entries(); - - ReportHandler::startProgress("Detecting inconsistencies in typesystem (" - + QByteArray::number(allEntries.size()) + ")..."); - for (auto it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) { - TypeEntry *entry = it.value(); - if (!entry->isPrimitive()) { - if ((entry->isValue() || entry->isObject()) - && !types->shouldDropTypeEntry(entry->qualifiedCppName()) - && !entry->isString() - && !entry->isChar() - && !entry->isContainer() - && !entry->isCustom() - && !entry->isVariant() - && (entry->generateCode() & TypeEntry::GenerateTargetLang) - && !AbstractMetaClass::findClass(m_metaClasses, entry)) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("type '%1' is specified in typesystem, but not defined. This could potentially lead to compilation errors.") - .arg(entry->qualifiedCppName()); - } else if (entry->generateCode() && entry->type() == TypeEntry::FunctionType) { - auto fte = static_cast<const FunctionTypeEntry *>(entry); - const QStringList &signatures = fte->signatures(); - for (const QString &signature : signatures) { - bool ok = false; - for (AbstractMetaFunction *func : qAsConst(m_globalFunctions)) { - if (signature == func->minimalSignature()) { - ok = true; - break; - } - } - if (!ok) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("Global function '%1' is specified in typesystem, but not defined. This could potentially lead to compilation errors.") - .arg(signature); - } - } - } else if (entry->isEnum() && (entry->generateCode() & TypeEntry::GenerateTargetLang)) { - const QString name = static_cast<const EnumTypeEntry *>(entry)->targetLangQualifier(); - AbstractMetaClass *cls = AbstractMetaClass::findClass(m_metaClasses, name); - - const bool enumFound = cls - ? cls->findEnum(entry->targetLangName()) != nullptr - : m_enums.contains(entry); - - if (!enumFound) { - entry->setCodeGeneration(TypeEntry::GenerateNothing); - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("enum '%1' is specified in typesystem, but not declared") - .arg(entry->qualifiedCppName()); - } - - } - } - } - - { - const FunctionList &hashFunctions = dom->findFunctions(QLatin1String("qHash")); - for (const FunctionModelItem &item : hashFunctions) - registerHashFunction(item, nullptr); - } - - { - const FunctionList &streamOps = dom->findFunctions(QLatin1String("operator<<")); - for (const FunctionModelItem &item : streamOps) - registerToStringCapability(item, nullptr); - } - - { - FunctionList binaryOperators = dom->findFunctions(QStringLiteral("operator==")); - binaryOperators.append(dom->findFunctions(QStringLiteral("operator!="))); - binaryOperators.append(dom->findFunctions(QStringLiteral("operator<="))); - binaryOperators.append(dom->findFunctions(QStringLiteral("operator>="))); - binaryOperators.append(dom->findFunctions(QStringLiteral("operator<"))); - binaryOperators.append(dom->findFunctions(QStringLiteral("operator+"))); - binaryOperators.append(dom->findFunctions(QStringLiteral("operator/"))); - // Filter binary operators, skipping for example - // class Iterator { ... Value *operator*() ... }; - const FunctionList potentiallyBinaryOperators = - dom->findFunctions(QStringLiteral("operator*")) - + dom->findFunctions(QStringLiteral("operator&")); - for (const FunctionModelItem &item : potentiallyBinaryOperators) { - if (!item->arguments().isEmpty()) - binaryOperators.append(item); - } - binaryOperators.append(dom->findFunctions(QStringLiteral("operator-"))); - binaryOperators.append(dom->findFunctions(QStringLiteral("operator&"))); - binaryOperators.append(dom->findFunctions(QStringLiteral("operator|"))); - binaryOperators.append(dom->findFunctions(QStringLiteral("operator^"))); - binaryOperators.append(dom->findFunctions(QStringLiteral("operator~"))); - binaryOperators.append(dom->findFunctions(QStringLiteral("operator>"))); - - for (const FunctionModelItem &item : qAsConst(binaryOperators)) - traverseOperatorFunction(item, nullptr); - } - - { - const FunctionList streamOperators = dom->findFunctions(QLatin1String("operator<<")) - + dom->findFunctions(QLatin1String("operator>>")); - for (const FunctionModelItem &item : streamOperators) - traverseStreamOperator(item, nullptr); - } - - ReportHandler::startProgress("Checking inconsistencies in function modifications..."); - - checkFunctionModifications(); - - ReportHandler::startProgress("Writing log files..."); - - // sort all classes topologically - m_metaClasses = classesTopologicalSorted(m_metaClasses); - - for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) { -// setupEquals(cls); -// setupComparable(cls); - setupClonable(cls); - setupExternalConversion(cls); - - // sort all inner classes topologically - if (!cls->typeEntry()->codeGeneration() || cls->innerClasses().size() < 2) - continue; - - cls->setInnerClasses(classesTopologicalSorted(cls->innerClasses())); - } - - dumpLog(); - - sortLists(); - - // Functions added to the module on the type system. - const AddedFunctionList &globalUserFunctions = types->globalUserFunctions(); - for (const AddedFunctionPtr &addedFunc : globalUserFunctions) { - AbstractMetaFunction *metaFunc = traverseFunction(addedFunc); - if (Q_UNLIKELY(!metaFunc)) { - qFatal("Unable to traverse added global function \"%s\".", - qPrintable(addedFunc->name())); - } - metaFunc->setFunctionType(AbstractMetaFunction::NormalFunction); - m_globalFunctions << metaFunc; - } - - m_itemToClass.clear(); - - ReportHandler::endProgress(); -} - -static bool metaEnumLessThan(const AbstractMetaEnum *e1, const AbstractMetaEnum *e2) -{ return e1->fullName() < e2->fullName(); } - -static bool metaClassLessThan(const AbstractMetaClass *c1, const AbstractMetaClass *c2) -{ return c1->fullName() < c2->fullName(); } - -static bool metaFunctionLessThan(const AbstractMetaFunction *f1, const AbstractMetaFunction *f2) -{ return f1->name() < f2->name(); } - -bool AbstractMetaBuilder::build(const QByteArrayList &arguments, - LanguageLevel level, - unsigned clangFlags) -{ - const FileModelItem dom = d->buildDom(arguments, level, clangFlags); - if (dom.isNull()) - return false; - if (ReportHandler::isDebug(ReportHandler::MediumDebug)) - qCDebug(lcShiboken) << dom.data(); - d->traverseDom(dom); - - // Ensure that indexes are in alphabetical order, roughly - std::sort(d->m_globalEnums.begin(), d->m_globalEnums.end(), metaEnumLessThan); - std::sort(d->m_metaClasses.begin(), d->m_metaClasses.end(), metaClassLessThan); - std::sort(d->m_templates.begin(), d->m_templates.end(), metaClassLessThan); - std::sort(d->m_smartPointers.begin(), d->m_smartPointers.end(), metaClassLessThan); - std::sort(d->m_globalFunctions.begin(), d->m_globalFunctions.end(), metaFunctionLessThan); - - return true; -} - -void AbstractMetaBuilder::setLogDirectory(const QString &logDir) -{ - d->m_logDirectory = logDir; - if (!d->m_logDirectory.endsWith(QDir::separator())) - d->m_logDirectory.append(QDir::separator()); -} - -void AbstractMetaBuilderPrivate::addAbstractMetaClass(AbstractMetaClass *cls, - const _CodeModelItem *item) -{ - cls->setOriginalAttributes(cls->attributes()); - m_itemToClass.insert(item, cls); - if (cls->typeEntry()->isContainer()) { - m_templates << cls; - } else if (cls->typeEntry()->isSmartPointer()) { - m_smartPointers << cls; - } else { - m_metaClasses << cls; - if (cls->typeEntry()->designatedInterface()) { - AbstractMetaClass *interface = cls->extractInterface(); - m_metaClasses << interface; - if (ReportHandler::isDebug(ReportHandler::SparseDebug)) - qCDebug(lcShiboken) << QStringLiteral(" -> interface '%1'").arg(interface->name()); - } - } -} - -AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModelItem &dom, - const NamespaceModelItem &namespaceItem) -{ - QString namespaceName = currentScope()->qualifiedName().join(colonColon()); - if (!namespaceName.isEmpty()) - namespaceName.append(colonColon()); - namespaceName.append(namespaceItem->name()); - - if (TypeDatabase::instance()->isClassRejected(namespaceName)) { - m_rejectedClasses.insert(namespaceName, AbstractMetaBuilder::GenerationDisabled); - return nullptr; - } - - auto type = TypeDatabase::instance()->findNamespaceType(namespaceName, namespaceItem->fileName()); - if (!type) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("namespace '%1' does not have a type entry").arg(namespaceName); - return nullptr; - } - - // Continue populating namespace? - AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_metaClasses, type); - if (!metaClass) { - metaClass = new AbstractMetaClass; - metaClass->setTypeEntry(type); - *metaClass += AbstractMetaAttributes::Public; - addAbstractMetaClass(metaClass, namespaceItem.data()); - if (auto extendsType = type->extends()) { - AbstractMetaClass *extended = AbstractMetaClass::findClass(m_metaClasses, extendsType); - if (!extended) { - qCWarning(lcShiboken, "%s", - qPrintable(msgNamespaceToBeExtendedNotFound(extendsType->name(), extendsType->targetLangPackage()))); - return nullptr; - } - metaClass->setExtendedNamespace(extended); - } - } else { - m_itemToClass.insert(namespaceItem.data(), metaClass); - } - - if (ReportHandler::isDebug(ReportHandler::SparseDebug)) { - qCDebug(lcShiboken) - << QStringLiteral("namespace '%1.%2'").arg(metaClass->package(), namespaceItem->name()); - } - - traverseEnums(namespaceItem, metaClass, namespaceItem->enumsDeclarations()); - - pushScope(namespaceItem); - - const ClassList &classes = namespaceItem->classes(); - for (const ClassModelItem &cls : classes) { - AbstractMetaClass *mjc = traverseClass(dom, cls, metaClass); - if (mjc) { - metaClass->addInnerClass(mjc); - mjc->setEnclosingClass(metaClass); - addAbstractMetaClass(mjc, cls.data()); - } - } - - // Go through all typedefs to see if we have defined any - // specific typedefs to be used as classes. - const TypeDefList typeDefs = namespaceItem->typeDefs(); - for (const TypeDefModelItem &typeDef : typeDefs) { - AbstractMetaClass *cls = traverseTypeDef(dom, typeDef, metaClass); - if (cls) { - metaClass->addInnerClass(cls); - cls->setEnclosingClass(metaClass); - addAbstractMetaClass(cls, typeDef.data()); - } - } - - // Traverse namespaces recursively - for (const NamespaceModelItem &ni : namespaceItem->namespaces()) { - AbstractMetaClass *mjc = traverseNamespace(dom, ni); - if (mjc) { - metaClass->addInnerClass(mjc); - mjc->setEnclosingClass(metaClass); - } - } - - popScope(); - - if (!type->include().isValid()) - setInclude(type, namespaceItem->fileName()); - - return metaClass; -} - -AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem &enumItem, - AbstractMetaClass *enclosing, - const QSet<QString> &enumsDeclarations) -{ - QString qualifiedName = enumItem->qualifiedName().join(colonColon()); - - TypeEntry *typeEntry = nullptr; - if (enumItem->accessPolicy() == CodeModel::Private) { - QStringList names = enumItem->qualifiedName(); - const QString &enumName = names.constLast(); - QString nspace; - if (names.size() > 1) - nspace = QStringList(names.mid(0, names.size() - 1)).join(colonColon()); - typeEntry = new EnumTypeEntry(nspace, enumName, QVersionNumber(0, 0)); - TypeDatabase::instance()->addType(typeEntry); - } else if (enumItem->enumKind() != AnonymousEnum) { - typeEntry = TypeDatabase::instance()->findType(qualifiedName); - } else { - QStringList tmpQualifiedName = enumItem->qualifiedName(); - const EnumeratorList &enums = enumItem->enumerators(); - for (const EnumeratorModelItem &enumValue : enums) { - tmpQualifiedName.removeLast(); - tmpQualifiedName << enumValue->name(); - qualifiedName = tmpQualifiedName.join(colonColon()); - typeEntry = TypeDatabase::instance()->findType(qualifiedName); - if (typeEntry) - break; - } - } - - QString enumName = enumItem->name(); - - QString className; - if (enclosing) - className = enclosing->typeEntry()->qualifiedCppName(); - - QString rejectReason; - if (TypeDatabase::instance()->isEnumRejected(className, enumName, &rejectReason)) { - if (typeEntry) - typeEntry->setCodeGeneration(TypeEntry::GenerateNothing); - m_rejectedEnums.insert(qualifiedName + rejectReason, AbstractMetaBuilder::GenerationDisabled); - return nullptr; - } - - const bool rejectionWarning = !enclosing - || (enclosing->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang); - - if (!typeEntry) { - if (rejectionWarning) - qCWarning(lcShiboken, "%s", qPrintable(msgNoEnumTypeEntry(enumItem, className))); - m_rejectedEnums.insert(qualifiedName, AbstractMetaBuilder::NotInTypeSystem); - return nullptr; - } - - if (!typeEntry->isEnum()) { - if (rejectionWarning) { - qCWarning(lcShiboken, "%s", - qPrintable(msgNoEnumTypeConflict(enumItem, className, typeEntry))); - } - m_rejectedEnums.insert(qualifiedName, AbstractMetaBuilder::NotInTypeSystem); - return nullptr; - } - - auto *metaEnum = new AbstractMetaEnum; - metaEnum->setEnumKind(enumItem->enumKind()); - metaEnum->setSigned(enumItem->isSigned()); - if (enumsDeclarations.contains(qualifiedName) - || enumsDeclarations.contains(enumName)) { - metaEnum->setHasQEnumsDeclaration(true); - } - - auto *enumTypeEntry = static_cast<EnumTypeEntry *>(typeEntry); - metaEnum->setTypeEntry(enumTypeEntry); - switch (enumItem->accessPolicy()) { - case CodeModel::Public: - *metaEnum += AbstractMetaAttributes::Public; - break; - case CodeModel::Protected: - *metaEnum += AbstractMetaAttributes::Protected; - break; - case CodeModel::Private: - *metaEnum += AbstractMetaAttributes::Private; - typeEntry->setCodeGeneration(TypeEntry::GenerateNothing); - break; - default: - break; - } - - if (ReportHandler::isDebug(ReportHandler::MediumDebug)) - qCDebug(lcShiboken) << " - traversing enum " << metaEnum->fullName(); - - const EnumeratorList &enums = enumItem->enumerators(); - for (const EnumeratorModelItem &value : enums) { - - auto *metaEnumValue = new AbstractMetaEnumValue; - metaEnumValue->setName(value->name()); - // Deciding the enum value... - - metaEnumValue->setStringValue(value->stringValue()); - metaEnumValue->setValue(value->value()); - metaEnum->addEnumValue(metaEnumValue); - - if (ReportHandler::isDebug(ReportHandler::FullDebug)) { - qCDebug(lcShiboken) << " - " << metaEnumValue->name() << " = " - << metaEnumValue->value() << " = " << metaEnumValue->value(); - } - } - - m_enums.insert(typeEntry, metaEnum); - - if (!metaEnum->typeEntry()->include().isValid()) - setInclude(metaEnum->typeEntry(), enumItem->fileName()); - - metaEnum->setOriginalAttributes(metaEnum->attributes()); - - // Register all enum values on Type database - QString prefix; - if (enclosing) { - prefix += enclosing->typeEntry()->qualifiedCppName(); - prefix += colonColon(); - } - if (enumItem->enumKind() == EnumClass) { - prefix += enumItem->name(); - prefix += colonColon(); - } - const EnumeratorList &enumerators = enumItem->enumerators(); - for (const EnumeratorModelItem &e : enumerators) { - QString name; - if (enclosing) { - name += enclosing->name(); - name += colonColon(); - } - EnumValueTypeEntry *enumValue = - new EnumValueTypeEntry(prefix + e->name(), e->stringValue(), - enumTypeEntry, enumTypeEntry->version()); - TypeDatabase::instance()->addType(enumValue); - if (e->value().isNullValue()) - enumTypeEntry->setNullValue(enumValue); - } - - return metaEnum; -} - -AbstractMetaClass *AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelItem &, - const TypeDefModelItem &typeDef, - AbstractMetaClass *currentClass) -{ - TypeDatabase *types = TypeDatabase::instance(); - QString className = stripTemplateArgs(typeDef->name()); - - QString fullClassName = className; - // we have an inner class - if (currentClass) { - fullClassName = stripTemplateArgs(currentClass->typeEntry()->qualifiedCppName()) - + colonColon() + fullClassName; - } - - // If this is the alias for a primitive type - // we store the aliased type on the alias - // TypeEntry - PrimitiveTypeEntry *ptype = types->findPrimitiveType(className); - if (ptype) { - QString typeDefName = typeDef->type().qualifiedName()[0]; - ptype->setReferencedTypeEntry(types->findPrimitiveType(typeDefName)); - return nullptr; - } - - - // If we haven't specified anything for the typedef, then we don't care - ComplexTypeEntry *type = types->findComplexType(fullClassName); - if (!type) - return nullptr; - - auto *metaClass = new AbstractMetaClass; - metaClass->setTypeDef(true); - metaClass->setTypeEntry(type); - metaClass->setBaseClassNames(QStringList(typeDef->type().toString())); - *metaClass += AbstractMetaAttributes::Public; - - // Set the default include file name - if (!type->include().isValid()) - setInclude(type, typeDef->fileName()); - - fillAddedFunctions(metaClass); - - return metaClass; -} - -// Add the typedef'ed classes -void AbstractMetaBuilderPrivate::traverseTypesystemTypedefs() -{ - const auto &entries = TypeDatabase::instance()->typedefEntries(); - for (auto it = entries.begin(), end = entries.end(); it != end; ++it) { - TypedefEntry *te = it.value(); - auto *metaClass = new AbstractMetaClass; - metaClass->setTypeDef(true); - metaClass->setTypeEntry(te->target()); - metaClass->setBaseClassNames(QStringList(te->sourceType())); - *metaClass += AbstractMetaAttributes::Public; - fillAddedFunctions(metaClass); - addAbstractMetaClass(metaClass, nullptr); - } -} - -AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem &dom, - const ClassModelItem &classItem, - AbstractMetaClass *currentClass) -{ - QString className = stripTemplateArgs(classItem->name()); - QString fullClassName = className; - - // we have inner an class - if (currentClass) { - fullClassName = stripTemplateArgs(currentClass->typeEntry()->qualifiedCppName()) - + colonColon() + fullClassName; - } - - ComplexTypeEntry *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()) - reason = AbstractMetaBuilder::RedefinedToNotClass; - else - reason = AbstractMetaBuilder::NotInTypeSystem; - } else if (type->codeGeneration() == TypeEntry::GenerateNothing) { - reason = AbstractMetaBuilder::GenerationDisabled; - } - if (reason != AbstractMetaBuilder::NoReason) { - if (fullClassName.isEmpty()) { - QTextStream(&fullClassName) << "anonymous struct at " << classItem->fileName() - << ':' << classItem->startLine(); - } - m_rejectedClasses.insert(fullClassName, reason); - return nullptr; - } - - auto *metaClass = new AbstractMetaClass; - metaClass->setTypeEntry(type); - - if (classItem->isFinal()) - *metaClass += AbstractMetaAttributes::FinalCppClass; - - QStringList baseClassNames; - const QVector<_ClassModelItem::BaseClass> &baseClasses = classItem->baseClasses(); - for (const _ClassModelItem::BaseClass &baseClass : baseClasses) { - if (baseClass.accessPolicy == CodeModel::Public) - baseClassNames.append(baseClass.name); - } - - metaClass->setBaseClassNames(baseClassNames); - *metaClass += AbstractMetaAttributes::Public; - if (type->stream()) - metaClass->setStream(true); - - if (ReportHandler::isDebug(ReportHandler::SparseDebug)) { - const QString message = type->isContainer() - ? QStringLiteral("container: '%1'").arg(fullClassName) - : QStringLiteral("class: '%1'").arg(metaClass->fullName()); - qCDebug(lcShiboken) << message; - } - - TemplateParameterList template_parameters = classItem->templateParameters(); - QVector<TypeEntry *> template_args; - template_args.clear(); - for (int i = 0; i < template_parameters.size(); ++i) { - const TemplateParameterModelItem ¶m = template_parameters.at(i); - TemplateArgumentEntry *param_type = new TemplateArgumentEntry(param->name(), type->version()); - param_type->setOrdinal(i); - template_args.append(param_type); - } - metaClass->setTemplateArguments(template_args); - - parseQ_Property(metaClass, classItem->propertyDeclarations()); - - traverseEnums(classItem, metaClass, classItem->enumsDeclarations()); - - // Inner classes - { - const ClassList &innerClasses = classItem->classes(); - for (const ClassModelItem &ci : innerClasses) { - AbstractMetaClass *cl = traverseClass(dom, ci, metaClass); - if (cl) { - cl->setEnclosingClass(metaClass); - metaClass->addInnerClass(cl); - addAbstractMetaClass(cl, ci.data()); - } - } - - } - - // Go through all typedefs to see if we have defined any - // specific typedefs to be used as classes. - const TypeDefList typeDefs = classItem->typeDefs(); - for (const TypeDefModelItem &typeDef : typeDefs) { - AbstractMetaClass *cls = traverseTypeDef(dom, typeDef, metaClass); - if (cls) { - cls->setEnclosingClass(metaClass); - addAbstractMetaClass(cls, typeDef.data()); - } - } - - // Set the default include file name - if (!type->include().isValid()) - setInclude(type, classItem->fileName()); - - return metaClass; -} - -void AbstractMetaBuilderPrivate::traverseScopeMembers(const ScopeModelItem &item, - AbstractMetaClass *metaClass) -{ - // Classes/Namespace members - traverseFields(item, metaClass); - traverseFunctions(item, metaClass); - - // Inner classes - const ClassList &innerClasses = item->classes(); - for (const ClassModelItem &ci : innerClasses) - traverseClassMembers(ci); -} - -void AbstractMetaBuilderPrivate::traverseClassMembers(const ClassModelItem &item) -{ - AbstractMetaClass *metaClass = m_itemToClass.value(item.data()); - if (!metaClass) - return; - - // Class members - traverseScopeMembers(item, metaClass); -} - -void AbstractMetaBuilderPrivate::traverseNamespaceMembers(const NamespaceModelItem &item) -{ - AbstractMetaClass *metaClass = m_itemToClass.value(item.data()); - if (!metaClass) - return; - - // Namespace members - traverseScopeMembers(item, metaClass); - - // Inner namespaces - for (const NamespaceModelItem &ni : item->namespaces()) - traverseNamespaceMembers(ni); - -} - -static inline QString fieldSignatureWithType(const VariableModelItem &field) -{ - return field->name() + QStringLiteral(" -> ") + field->type().toString(); -} - -static inline QString qualifiedFieldSignatureWithType(const QString &className, - const VariableModelItem &field) -{ - return className + colonColon() + fieldSignatureWithType(field); -} - -AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(const VariableModelItem &field, - AbstractMetaClass *cls) -{ - QString fieldName = field->name(); - QString className = cls->typeEntry()->qualifiedCppName(); - - // Ignore friend decl. - if (field->isFriend()) - return nullptr; - - if (field->accessPolicy() == CodeModel::Private) - return nullptr; - - QString rejectReason; - if (TypeDatabase::instance()->isFieldRejected(className, fieldName, &rejectReason)) { - m_rejectedFields.insert(qualifiedFieldSignatureWithType(className, field) + rejectReason, - AbstractMetaBuilder::GenerationDisabled); - return nullptr; - } - - - auto *metaField = new AbstractMetaField; - metaField->setName(fieldName); - metaField->setEnclosingClass(cls); - - TypeInfo fieldType = field->type(); - AbstractMetaType *metaType = translateType(fieldType, cls); - - if (!metaType) { - const QString type = TypeInfo::resolveType(fieldType, currentScope()).qualifiedName().join(colonColon()); - if (cls->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("skipping field '%1::%2' with unmatched type '%3'") - .arg(cls->name(), fieldName, type); - } - delete metaField; - return nullptr; - } - - metaField->setType(metaType); - - AbstractMetaAttributes::Attributes attr = nullptr; - if (field->isStatic()) - attr |= AbstractMetaAttributes::Static; - - CodeModel::AccessPolicy policy = field->accessPolicy(); - if (policy == CodeModel::Public) - attr |= AbstractMetaAttributes::Public; - else if (policy == CodeModel::Protected) - attr |= AbstractMetaAttributes::Protected; - else - attr |= AbstractMetaAttributes::Private; - metaField->setAttributes(attr); - - return metaField; -} - -void AbstractMetaBuilderPrivate::traverseFields(const ScopeModelItem &scope_item, - AbstractMetaClass *metaClass) -{ - const VariableList &variables = scope_item->variables(); - for (const VariableModelItem &field : variables) { - AbstractMetaField *metaField = traverseField(field, metaClass); - - if (metaField && !metaField->isModifiedRemoved()) { - metaField->setOriginalAttributes(metaField->attributes()); - metaClass->addField(metaField); - } - } -} - -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 ")); - Q_ASSERT(operatorRegExp.isValid()); - QString castTo = metaFunction->name().remove(operatorRegExp).trimmed(); - - if (castTo.endsWith(QLatin1Char('&'))) - castTo.chop(1); - if (castTo.startsWith(QLatin1String("const "))) - castTo.remove(0, 6); - - TypeEntry *retType = types->findType(castTo); - if (!retType) - return; - - auto *metaType = new AbstractMetaType; - metaType->setTypeEntry(retType); - metaFunction->replaceType(metaType); -} - -static bool _compareAbstractMetaTypes(const AbstractMetaType *type, const AbstractMetaType *other) -{ - return (type != nullptr) == (other != nullptr) - && (type == nullptr || *type == *other); -} - -static bool _compareAbstractMetaFunctions(const AbstractMetaFunction *func, const AbstractMetaFunction *other) -{ - if (!func && !other) - return true; - if (!func || !other) - return false; - if (func->arguments().count() != other->arguments().count() - || func->isConstant() != other->isConstant() - || func->isStatic() != other->isStatic() - || !_compareAbstractMetaTypes(func->type(), other->type())) { - return false; - } - for (int i = 0; i < func->arguments().count(); ++i) { - if (!_compareAbstractMetaTypes(func->arguments().at(i)->type(), other->arguments().at(i)->type())) - return false; - } - return true; -} - -AbstractMetaFunctionList AbstractMetaBuilderPrivate::classFunctionList(const ScopeModelItem &scopeItem, - AbstractMetaClass::Attributes *constructorAttributes, - AbstractMetaClass *currentClass) -{ - *constructorAttributes = nullptr; - AbstractMetaFunctionList result; - const FunctionList &scopeFunctionList = scopeItem->functions(); - result.reserve(scopeFunctionList.size()); - for (const FunctionModelItem &function : scopeFunctionList) { - if (AbstractMetaFunction *metaFunction = traverseFunction(function, currentClass)) { - result.append(metaFunction); - } else if (function->functionType() == CodeModel::Constructor) { - auto arguments = function->arguments(); - *constructorAttributes |= AbstractMetaAttributes::HasRejectedConstructor; - if (arguments.isEmpty() || arguments.constFirst()->defaultValue()) - *constructorAttributes |= AbstractMetaAttributes::HasRejectedDefaultConstructor; - } - } - return result; -} - -// For template classes, entries with more specific types may exist from out-of- -// line definitions. If there is a declaration which matches it after fixing -// the parameters, remove it as duplicate. For example: -// template class<T> Vector { public: -// Vector(const Vector &rhs); -// }; -// template class<T> -// Vector<T>::Vector(const Vector<T>&) {} // More specific, remove declaration. - -class DuplicatingFunctionPredicate : public std::unary_function<bool, const AbstractMetaFunction *> { -public: - explicit DuplicatingFunctionPredicate(const AbstractMetaFunction *f) : m_function(f) {} - - bool operator()(const AbstractMetaFunction *rhs) const - { - return rhs != m_function && rhs->name() == m_function->name() - && _compareAbstractMetaFunctions(m_function, rhs); - } - -private: - const AbstractMetaFunction *m_function; -}; - -void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, - AbstractMetaClass *metaClass) -{ - AbstractMetaAttributes::Attributes constructorAttributes; - const AbstractMetaFunctionList functions = - classFunctionList(scopeItem, &constructorAttributes, metaClass); - metaClass->setAttributes(metaClass->attributes() | constructorAttributes); - - for (AbstractMetaFunction *metaFunction : functions){ - metaFunction->setOriginalAttributes(metaFunction->attributes()); - if (metaClass->isNamespace()) - *metaFunction += AbstractMetaAttributes::Static; - - QPropertySpec *read = nullptr; - if (!metaFunction->isSignal() && (read = metaClass->propertySpecForRead(metaFunction->name()))) { - // Property reader must be in the form "<type> name()" - if (metaFunction->type() && (read->type() == metaFunction->type()->typeEntry()) - && metaFunction->arguments().isEmpty()) { - *metaFunction += AbstractMetaAttributes::PropertyReader; - metaFunction->setPropertySpec(read); - } - } else if (QPropertySpec *write = metaClass->propertySpecForWrite(metaFunction->name())) { - // Property setter must be in the form "void name(<type>)" - // make sure the function was created with all aguments, some argument can be missing during the pareser because of errors on typesystem - if ((!metaFunction->type()) && (metaFunction->arguments().size() == 1) && (write->type() == metaFunction->arguments().at(0)->type()->typeEntry())) { - *metaFunction += AbstractMetaAttributes::PropertyWriter; - metaFunction->setPropertySpec(write); - } - } else if (QPropertySpec *reset = metaClass->propertySpecForReset(metaFunction->name())) { - // Property resetter must be in the form "void name()" - if ((!metaFunction->type()) && metaFunction->arguments().isEmpty()) { - *metaFunction += AbstractMetaAttributes::PropertyResetter; - metaFunction->setPropertySpec(reset); - } - } - - const bool isInvalidDestructor = metaFunction->isDestructor() && metaFunction->isPrivate(); - const bool isInvalidConstructor = metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction - && metaFunction->isPrivate(); - if (isInvalidConstructor) - metaClass->setHasPrivateConstructor(true); - if ((isInvalidDestructor || isInvalidConstructor) - && !metaClass->hasNonPrivateConstructor()) { - *metaClass += AbstractMetaAttributes::FinalInTargetLang; - } else if (metaFunction->isConstructor() && !metaFunction->isPrivate()) { - *metaClass -= AbstractMetaAttributes::FinalInTargetLang; - metaClass->setHasNonPrivateConstructor(true); - } - - // Classes with virtual destructors should always have a shell class - // (since we aren't registering the destructors, we need this extra check) - if (metaFunction->isDestructor() && metaFunction->isVirtual() - && metaFunction->visibility() != AbstractMetaAttributes::Private) { - metaClass->setForceShellClass(true); - } - - if (!metaFunction->isDestructor() - && !(metaFunction->isPrivate() && metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction)) { - - setupFunctionDefaults(metaFunction, metaClass); - - if (metaFunction->isSignal() && metaClass->hasSignal(metaFunction)) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("signal '%1' in class '%2' is overloaded.") - .arg(metaFunction->name(), metaClass->name()); - } - - if (metaFunction->isConversionOperator()) - fixReturnTypeOfConversionOperator(metaFunction); - - metaClass->addFunction(metaFunction); - applyFunctionModifications(metaFunction); - } else if (metaFunction->isDestructor()) { - metaClass->setHasPrivateDestructor(metaFunction->isPrivate()); - metaClass->setHasProtectedDestructor(metaFunction->isProtected()); - metaClass->setHasVirtualDestructor(metaFunction->isVirtual()); - } - if (!metaFunction->ownerClass()) { - delete metaFunction; - metaFunction = nullptr; - } - } - - fillAddedFunctions(metaClass); -} - -void AbstractMetaBuilderPrivate::fillAddedFunctions(AbstractMetaClass *metaClass) -{ - // Add the functions added by the typesystem - const AddedFunctionList &addedFunctions = metaClass->typeEntry()->addedFunctions(); - for (const AddedFunctionPtr &addedFunc : addedFunctions) { - if (!traverseFunction(addedFunc, metaClass)) { - qFatal("Unable to traverse function \"%s\" added to \"%s\".", - qPrintable(addedFunc->name()), qPrintable(metaClass->name())); - } - } -} - -void AbstractMetaBuilderPrivate::applyFunctionModifications(AbstractMetaFunction *func) -{ - const FunctionModificationList &mods = func->modifications(func->implementingClass()); - AbstractMetaFunction& funcRef = *func; - for (const FunctionModification &mod : mods) { - if (mod.isRenameModifier()) { - func->setOriginalName(func->name()); - func->setName(mod.renamedTo()); - } else if (mod.isAccessModifier()) { - funcRef -= AbstractMetaAttributes::Public; - funcRef -= AbstractMetaAttributes::Protected; - funcRef -= AbstractMetaAttributes::Private; - funcRef -= AbstractMetaAttributes::Friendly; - - if (mod.isPublic()) - funcRef += AbstractMetaAttributes::Public; - else if (mod.isProtected()) - funcRef += AbstractMetaAttributes::Protected; - else if (mod.isPrivate()) - funcRef += AbstractMetaAttributes::Private; - else if (mod.isFriendly()) - funcRef += AbstractMetaAttributes::Friendly; - } - - if (mod.isFinal()) - funcRef += AbstractMetaAttributes::FinalInTargetLang; - else if (mod.isNonFinal()) - funcRef -= AbstractMetaAttributes::FinalInTargetLang; - } -} - -bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass) -{ - Q_ASSERT(!metaClass->isInterface()); - - if (m_setupInheritanceDone.contains(metaClass)) - return true; - - m_setupInheritanceDone.insert(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('<'))) { - TypeInfo info; - ComplexTypeEntry* baseContainerType; - AbstractMetaClass* templ = findTemplateClass(baseClasses.constFirst(), metaClass, &info, &baseContainerType); - if (templ) { - setupInheritance(templ); - inheritTemplate(metaClass, templ, info); - metaClass->typeEntry()->setBaseContainerType(templ->typeEntry()); - return true; - } - - if (baseContainerType) { - // Container types are not necessarily wrapped as 'real' classes, - // but there may still be classes derived from them. In such case, - // we still need to set the base container type in order to - // generate correct code for type conversion checking. - // - // Additionally, we consider this case as successfully setting up - // inheritance. - metaClass->typeEntry()->setBaseContainerType(baseContainerType); - return true; - } - - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("template baseclass '%1' of '%2' is not known") - .arg(baseClasses.constFirst(), metaClass->name()); - return false; - } - - TypeDatabase* types = TypeDatabase::instance(); - - int primary = -1; - int primaries = 0; - for (int i = 0; i < baseClasses.size(); ++i) { - - if (types->isClassRejected(baseClasses.at(i))) - continue; - - TypeEntry* baseClassEntry = types->findType(baseClasses.at(i)); - if (!baseClassEntry) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("class '%1' inherits from unknown base class '%2'") - .arg(metaClass->name(), baseClasses.at(i)); - } else if (!baseClassEntry->designatedInterface()) { // true for primary base class - primaries++; - primary = i; - } - } - - if (primary >= 0) { - AbstractMetaClass *baseClass = AbstractMetaClass::findClass(m_metaClasses, baseClasses.at(primary)); - if (!baseClass) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("unknown baseclass for '%1': '%2'") - .arg(metaClass->name(), baseClasses.at(primary)); - return false; - } - metaClass->setBaseClass(baseClass); - } - - for (int i = 0; i < baseClasses.size(); ++i) { - if (types->isClassRejected(baseClasses.at(i))) - continue; - - if (i != primary) { - AbstractMetaClass *baseClass = AbstractMetaClass::findClass(m_metaClasses, baseClasses.at(i)); - if (!baseClass) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("class not found for setup inheritance '%1'").arg(baseClasses.at(i)); - return false; - } - - setupInheritance(baseClass); - - QString interfaceName = baseClass->isInterface() ? InterfaceTypeEntry::interfaceName(baseClass->name()) : baseClass->name(); - AbstractMetaClass *iface = AbstractMetaClass::findClass(m_metaClasses, interfaceName); - if (!iface) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("unknown interface for '%1': '%2'").arg(metaClass->name(), interfaceName); - return false; - } - metaClass->addInterface(iface); - - const AbstractMetaClassList &interfaces = iface->interfaces(); - for (AbstractMetaClass* iface : interfaces) - metaClass->addInterface(iface); - } - } - - return true; -} - -void AbstractMetaBuilderPrivate::traverseEnums(const ScopeModelItem &scopeItem, - AbstractMetaClass *metaClass, - const QStringList &enumsDeclarations) -{ - const EnumList &enums = scopeItem->enums(); -#if QT_VERSION >= 0x050E00 - const QSet<QString> enumsDeclarationSet(enumsDeclarations.cbegin(), enumsDeclarations.cend()); -#else - const QSet<QString> enumsDeclarationSet = QSet<QString>::fromList(enumsDeclarations); -#endif - for (const EnumModelItem &enumItem : enums) { - AbstractMetaEnum* metaEnum = traverseEnum(enumItem, metaClass, enumsDeclarationSet); - if (metaEnum) { - metaClass->addEnum(metaEnum); - metaEnum->setEnclosingClass(metaClass); - } - } -} - -AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFunctionPtr &addedFunc) -{ - return traverseFunction(addedFunc, nullptr); -} - -AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFunctionPtr &addedFunc, - AbstractMetaClass *metaClass) -{ - auto *metaFunction = new AbstractMetaFunction(addedFunc); - metaFunction->setType(translateType(addedFunc->returnType())); - - - const auto &args = addedFunc->arguments(); - AbstractMetaArgumentList metaArguments; - - for (int i = 0; i < args.count(); ++i) { - const AddedFunction::TypeInfo& typeInfo = args.at(i).typeInfo; - auto *metaArg = new AbstractMetaArgument; - AbstractMetaType *type = translateType(typeInfo); - if (Q_UNLIKELY(!type)) { - qCWarning(lcShiboken, - "Unable to translate type \"%s\" of argument %d of added function \"%s\".", - qPrintable(typeInfo.name), i + 1, qPrintable(addedFunc->name())); - delete metaFunction; - return nullptr; - } - type->decideUsagePattern(); - if (!args.at(i).name.isEmpty()) - metaArg->setName(args.at(i).name); - metaArg->setType(type); - metaArg->setArgumentIndex(i); - metaArg->setDefaultValueExpression(typeInfo.defaultValue); - metaArg->setOriginalDefaultValueExpression(typeInfo.defaultValue); - metaArguments.append(metaArg); - } - - metaFunction->setArguments(metaArguments); - if (metaFunction->isOperatorOverload() && !metaFunction->isCallOperator()) { - if (metaArguments.size() > 2) { - qCWarning(lcShiboken) << "An operator overload need to have 0, 1 or 2 arguments if it's reverse."; - } else if (metaArguments.size() == 2) { - // Check if it's a reverse operator - if (metaArguments[1]->type()->typeEntry() == metaClass->typeEntry()) { - metaFunction->setReverseOperator(true); - // we need to call these two function to cache the old signature (with two args) - // we do this buggy behaviour to comply with the original apiextractor buggy behaviour. - metaFunction->signature(); - metaFunction->minimalSignature(); - metaArguments.removeLast(); - metaFunction->setArguments(metaArguments); - } else { - qCWarning(lcShiboken) << "Operator overload can have two arguments only if it's a reverse operator!"; - } - } - } - - - // Find the correct default values - for (int i = 0; i < metaArguments.size(); ++i) { - AbstractMetaArgument* metaArg = metaArguments.at(i); - - //use relace-default-expression for set default value - QString replacedExpression; - if (metaClass) - replacedExpression = metaFunction->replacedDefaultExpression(metaClass, i + 1); - - if (!replacedExpression.isEmpty()) { - if (!metaFunction->removedDefaultExpression(metaClass, i + 1)) { - metaArg->setDefaultValueExpression(replacedExpression); - metaArg->setOriginalDefaultValueExpression(replacedExpression); - } - } - } - - metaFunction->setOriginalAttributes(metaFunction->attributes()); - if (!metaArguments.isEmpty()) - fixArgumentNames(metaFunction, metaFunction->modifications(metaClass)); - - if (metaClass) { - const AbstractMetaArgumentList fargs = metaFunction->arguments(); - if (metaClass->isNamespace()) - *metaFunction += AbstractMetaFunction::Static; - if (metaFunction->name() == metaClass->name()) { - metaFunction->setFunctionType(AbstractMetaFunction::ConstructorFunction); - if (fargs.size() == 1) { - const TypeEntry *te = fargs.constFirst()->type()->typeEntry(); - if (te->isCustom()) - metaFunction->setExplicit(true); - if (te->name() == metaFunction->name()) - metaFunction->setFunctionType(AbstractMetaFunction::CopyConstructorFunction); - } - } else { - metaFunction->setFunctionType(AbstractMetaFunction::NormalFunction); - } - - metaFunction->setDeclaringClass(metaClass); - metaFunction->setImplementingClass(metaClass); - metaClass->addFunction(metaFunction); - metaClass->setHasNonPrivateConstructor(true); - } - - return metaFunction; -} - -void AbstractMetaBuilderPrivate::fixArgumentNames(AbstractMetaFunction *func, const FunctionModificationList &mods) -{ - for (const FunctionModification &mod : mods) { - for (const ArgumentModification &argMod : mod.argument_mods) { - if (!argMod.renamed_to.isEmpty()) { - AbstractMetaArgument* arg = func->arguments().at(argMod.index - 1); - arg->setOriginalName(arg->name()); - arg->setName(argMod.renamed_to, false); - } - } - } - - AbstractMetaArgumentList arguments = func->arguments(); - for (int i = 0, size = arguments.size(); i < size; ++i) { - if (arguments.at(i)->name().isEmpty()) - arguments[i]->setName(QLatin1String("arg__") + QString::number(i + 1), false); - } -} - -static QString functionSignature(const FunctionModelItem &functionItem) -{ - QStringList args; - const ArgumentList &arguments = functionItem->arguments(); - for (const ArgumentModelItem &arg : arguments) - args << arg->type().toString(); - return functionItem->name() + QLatin1Char('(') + args.join(QLatin1Char(',')) + QLatin1Char(')'); -} - -static inline QString qualifiedFunctionSignatureWithType(const FunctionModelItem &functionItem, - const QString &className = QString()) -{ - QString result = functionItem->type().toString() + QLatin1Char(' '); - if (!className.isEmpty()) - result += className + colonColon(); - result += functionSignature(functionItem); - return result; -} -static inline AbstractMetaFunction::FunctionType functionTypeFromCodeModel(CodeModel::FunctionType ft) -{ - AbstractMetaFunction::FunctionType result = AbstractMetaFunction::NormalFunction; - switch (ft) { - case CodeModel::Constructor: - result = AbstractMetaFunction::ConstructorFunction; - break; - case CodeModel::CopyConstructor: - result = AbstractMetaFunction::CopyConstructorFunction; - break; - case CodeModel::MoveConstructor: - result = AbstractMetaFunction::MoveConstructorFunction; - break; - case CodeModel::Destructor: - result = AbstractMetaFunction::DestructorFunction; - break; - case CodeModel::Normal: - break; - case CodeModel::Signal: - result = AbstractMetaFunction::SignalFunction; - break; - case CodeModel::Slot: - result = AbstractMetaFunction::SlotFunction; - break; - } - return result; -} - -// Apply the <array> modifications of the arguments -static bool applyArrayArgumentModifications(const FunctionModificationList &functionMods, - AbstractMetaFunction *func, - QString *errorMessage) -{ - for (const FunctionModification &mod : functionMods) { - for (const ArgumentModification &argMod : mod.argument_mods) { - if (argMod.array) { - const int i = argMod.index - 1; - if (i < 0 || i >= func->arguments().size()) { - *errorMessage = msgCannotSetArrayUsage(func->minimalSignature(), i, - QLatin1String("Index out of range.")); - return false; - } - if (!func->arguments().at(i)->type()->applyArrayModification(errorMessage)) { - *errorMessage = msgCannotSetArrayUsage(func->minimalSignature(), i, *errorMessage); - return false; - } - } - } - } - return true; -} - -AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const FunctionModelItem &functionItem, - AbstractMetaClass *currentClass) -{ - if (functionItem->isDeleted() || !functionItem->templateParameters().isEmpty()) - return nullptr; - QString functionName = functionItem->name(); - QString className; - if (currentClass) { - // Clang: Skip qt_metacast(), qt_metacall(), expanded from Q_OBJECT - // and overridden metaObject(), QGADGET helpers - if (functionName == QLatin1String("qt_check_for_QGADGET_macro") - || functionName.startsWith(QLatin1String("qt_meta"))) { - return nullptr; - } - className = 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); - - QString rejectReason; - if (TypeDatabase::instance()->isFunctionRejected(className, functionName, &rejectReason)) { - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); - return nullptr; - } - const QString &signature = functionSignature(functionItem); - const bool rejected = - TypeDatabase::instance()->isFunctionRejected(className, signature, &rejectReason); - qCDebug(lcShiboken).nospace().noquote() << __FUNCTION__ - << ": Checking rejection for signature \"" << signature << "\" for " << className - << ": " << rejected; - if (rejected) - return nullptr; - - if (functionItem->isFriend()) - return nullptr; - - const bool deprecated = functionItem->isDeprecated(); - if (deprecated && m_skipDeprecated) { - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + QLatin1String(" is deprecated."), - AbstractMetaBuilder::GenerationDisabled); - return nullptr; - } - - auto *metaFunction = new AbstractMetaFunction; - if (deprecated) - *metaFunction += AbstractMetaAttributes::Deprecated; - - // Additional check for assignment/move assignment down below - metaFunction->setFunctionType(functionTypeFromCodeModel(functionItem->functionType())); - metaFunction->setConstant(functionItem->isConstant()); - metaFunction->setExceptionSpecification(functionItem->exceptionSpecification()); - - if (ReportHandler::isDebug(ReportHandler::MediumDebug)) - qCDebug(lcShiboken).noquote().nospace() << " - " << functionName << "()"; - - metaFunction->setName(functionName); - metaFunction->setOriginalName(functionItem->name()); - - if (functionItem->isAbstract()) - *metaFunction += AbstractMetaAttributes::Abstract; - - if (functionItem->isVirtual()) { - *metaFunction += AbstractMetaAttributes::VirtualCppMethod; - if (functionItem->isOverride()) - *metaFunction += AbstractMetaAttributes::OverriddenCppMethod; - if (functionItem->isFinal()) - *metaFunction += AbstractMetaAttributes::FinalCppMethod; - } else { - *metaFunction += AbstractMetaAttributes::FinalInTargetLang; - } - - if (functionItem->isInvokable()) - *metaFunction += AbstractMetaAttributes::Invokable; - - if (functionItem->isStatic()) { - *metaFunction += AbstractMetaAttributes::Static; - *metaFunction += AbstractMetaAttributes::FinalInTargetLang; - } - - // Access rights - if (functionItem->accessPolicy() == CodeModel::Public) - *metaFunction += AbstractMetaAttributes::Public; - else if (functionItem->accessPolicy() == CodeModel::Private) - *metaFunction += AbstractMetaAttributes::Private; - else - *metaFunction += AbstractMetaAttributes::Protected; - - QString errorMessage; - switch (metaFunction->functionType()) { - case AbstractMetaFunction::DestructorFunction: - break; - case AbstractMetaFunction::ConstructorFunction: - metaFunction->setExplicit(functionItem->isExplicit()); - metaFunction->setName(currentClass->name()); - break; - default: { - TypeInfo returnType = functionItem->type(); - - if (TypeDatabase::instance()->isReturnTypeRejected(className, returnType.toString(), &rejectReason)) { - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); - delete metaFunction; - return nullptr; - } - - AbstractMetaType *type = nullptr; - if (!returnType.isVoid()) { - type = translateType(returnType, currentClass, true, &errorMessage); - if (!type) { - const QString reason = msgUnmatchedReturnType(functionItem, errorMessage); - qCWarning(lcShiboken, "%s", - qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason))); - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::UnmatchedReturnType); - delete metaFunction; - return nullptr; - } - } - - metaFunction->setType(type); - } - break; - } - - ArgumentList arguments = functionItem->arguments(); - - if (arguments.size() == 1) { - ArgumentModelItem arg = arguments.at(0); - TypeInfo type = arg->type(); - if (type.qualifiedName().constFirst() == QLatin1String("void") && type.indirections() == 0) - arguments.pop_front(); - } - - AbstractMetaArgumentList metaArguments; - - for (int i = 0; i < arguments.size(); ++i) { - const ArgumentModelItem &arg = arguments.at(i); - - if (TypeDatabase::instance()->isArgumentTypeRejected(className, arg->type().toString(), &rejectReason)) { - m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled); - delete metaFunction; - return nullptr; - } - - AbstractMetaType *metaType = translateType(arg->type(), currentClass, true, &errorMessage); - if (!metaType) { - // If an invalid argument has a default value, simply remove it - if (arg->defaultValue()) { - if (!currentClass - || (currentClass->typeEntry()->codeGeneration() - & TypeEntry::GenerateTargetLang)) { - qCWarning(lcShiboken).noquote().nospace() - << "Stripping argument #" << (i + 1) << " of " - << originalQualifiedSignatureWithReturn - << " due to unmatched type \"" << arg->type().toString() - << "\" with default expression \"" - << arg->defaultValueExpression() << "\"."; - } - break; - } - Q_ASSERT(metaType == nullptr); - const QString reason = msgUnmatchedParameterType(arg, i, errorMessage); - qCWarning(lcShiboken, "%s", - qPrintable(msgSkippingFunction(functionItem, originalQualifiedSignatureWithReturn, reason))); - const QString rejectedFunctionSignature = originalQualifiedSignatureWithReturn - + QLatin1String(": ") + reason; - m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::UnmatchedArgumentType); - delete metaFunction; - return nullptr; - } - - auto *metaArgument = new AbstractMetaArgument; - - metaArgument->setType(metaType); - metaArgument->setName(arg->name()); - metaArgument->setArgumentIndex(i); - metaArguments << metaArgument; - } - - metaFunction->setArguments(metaArguments); - - const FunctionModificationList functionMods = metaFunction->modifications(currentClass); - - 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()); - } - - // Find the correct default values - for (int i = 0, size = metaArguments.size(); i < size; ++i) { - const ArgumentModelItem &arg = arguments.at(i); - AbstractMetaArgument* metaArg = metaArguments.at(i); - - //use relace-default-expression for set default value - QString replacedExpression; - if (currentClass) { - replacedExpression = metaFunction->replacedDefaultExpression(currentClass, i + 1); - } else { - if (!functionMods.isEmpty()) { - QVector<ArgumentModification> argMods = functionMods.constFirst().argument_mods; - if (!argMods.isEmpty()) - replacedExpression = argMods.constFirst().replacedDefaultExpression; - } - } - - bool hasDefaultValue = false; - if (arg->defaultValue() || !replacedExpression.isEmpty()) { - QString expr = arg->defaultValueExpression(); - expr = fixDefaultValue(arg, metaArg->type(), metaFunction, currentClass, i); - metaArg->setOriginalDefaultValueExpression(expr); - - if (metaFunction->removedDefaultExpression(currentClass, i + 1)) { - expr.clear(); - } else if (!replacedExpression.isEmpty()) { - expr = replacedExpression; - } - metaArg->setDefaultValueExpression(expr); - hasDefaultValue = !expr.isEmpty(); - } - - //Check for missing argument name - if (hasDefaultValue - && !metaArg->hasName() - && !metaFunction->isOperatorOverload() - && !metaFunction->isSignal() - && metaFunction->argumentName(i + 1, false, currentClass).isEmpty()) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("Argument %1 on function '%2::%3' has default expression but does not have name.") - .arg(i+1).arg(className, metaFunction->minimalSignature()); - } - - } - - if (!metaArguments.isEmpty()) { - fixArgumentNames(metaFunction, functionMods); - QString errorMessage; - if (!applyArrayArgumentModifications(functionMods, metaFunction, &errorMessage)) { - qCWarning(lcShiboken, "While traversing %s: %s", - qPrintable(className), qPrintable(errorMessage)); - } - } - - // Determine class special functions - 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=")) { - switch (argType->referenceType()) { - case NoReference: - metaFunction->setFunctionType(AbstractMetaFunction::AssignmentOperatorFunction); - break; - case LValueReference: - if (argType->isConstant()) - metaFunction->setFunctionType(AbstractMetaFunction::AssignmentOperatorFunction); - break; - case RValueReference: - metaFunction->setFunctionType(AbstractMetaFunction::MoveAssignmentOperatorFunction); - break; - } - } - } - } - return metaFunction; -} - -AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const AddedFunction::TypeInfo &typeInfo) -{ - Q_ASSERT(!typeInfo.name.isEmpty()); - TypeDatabase* typeDb = TypeDatabase::instance(); - TypeEntry* type; - - QString typeName = typeInfo.name; - - if (typeName == QLatin1String("void")) - return nullptr; - - type = typeDb->findType(typeName); - - // test if the type is a template, like a container - bool isTemplate = false; - QStringList templateArgs; - if (!type && typeInfo.name.contains(QLatin1Char('<'))) { - const QStringList& parsedType = parseTemplateType(typeInfo.name); - if (parsedType.isEmpty()) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("Template type parsing failed for '%1'").arg(typeInfo.name); - } else { - templateArgs = parsedType.mid(1); - isTemplate = (type = typeDb->findContainerType(parsedType[0])); - } - } - - if (!type) { - QStringList candidates; - const auto &entries = typeDb->entries(); - for (auto it = entries.cbegin(), end = entries.cend(); it != end; ++it) { - // Let's try to find the type in different scopes. - if (it.key().endsWith(colonColon() + typeName)) - candidates.append(it.key()); - } - - QString msg = QStringLiteral("Type '%1' wasn't found in the type database.\n").arg(typeName); - - if (candidates.isEmpty()) { - qFatal("%sDeclare it in the type system using the proper <*-type> tag.", - qPrintable(msg)); - } - - msg += QLatin1String("Remember to inform the full qualified name for the type you want to use.\nCandidates are:\n"); - candidates.sort(); - for (const QString& candidate : qAsConst(candidates)) { - msg += QLatin1String(" ") + candidate + QLatin1Char('\n'); - } - qFatal("%s", qPrintable(msg)); - } - - auto *metaType = new AbstractMetaType; - metaType->setTypeEntry(type); - metaType->setIndirections(typeInfo.indirections); - if (typeInfo.isReference) - metaType->setReferenceType(LValueReference); - metaType->setConstant(typeInfo.isConstant); - if (isTemplate) { - for (const QString& templateArg : qAsConst(templateArgs)) { - AbstractMetaType *metaArgType = translateType(AddedFunction::TypeInfo::fromSignature(templateArg)); - metaType->addInstantiation(metaArgType); - } - metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern); - } - - return metaType; -} - -static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaClass, const QString& qualifiedName) -{ - const TypeEntry* type = nullptr; - QStringList context = metaClass->qualifiedCppName().split(colonColon()); - while (!type && !context.isEmpty()) { - type = TypeDatabase::instance()->findType(context.join(colonColon()) + colonColon() + qualifiedName); - context.removeLast(); - } - return type; -} - -AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typei, - AbstractMetaClass *currentClass, - bool resolveType, - QString *errorMessage) -{ - return translateTypeStatic(_typei, currentClass, this, resolveType, errorMessage); -} - -AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo &_typei, - AbstractMetaClass *currentClass, - AbstractMetaBuilderPrivate *d, - bool resolveType, - QString *errorMessageIn) -{ - // 1. Test the type info without resolving typedefs in case this is present in the - // type system - if (resolveType) { - if (AbstractMetaType *resolved = translateTypeStatic(_typei, currentClass, d, false, errorMessageIn)) - return resolved; - } - - TypeInfo typeInfo = _typei; - if (resolveType) { - // Go through all parts of the current scope (including global namespace) - // to resolve typedefs. The parser does not properly resolve typedefs in - // the global scope when they are referenced from inside a namespace. - // This is a work around to fix this bug since fixing it in resolveType - // seemed non-trivial - int i = 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())) - break; - } - - } - - if (typeInfo.isFunctionPointer()) { - if (errorMessageIn) - *errorMessageIn = msgUnableToTranslateType(_typei, QLatin1String("Unsupported function pointer.")); - return nullptr; - } - - QString errorMessage; - - // 2. Handle arrays. - // 2.1 Handle char arrays with unspecified size (aka "const char[]") as "const char*" with - // NativePointerPattern usage. - bool oneDimensionalArrayOfUnspecifiedSize = - typeInfo.arrayElements().size() == 1 - && typeInfo.arrayElements().at(0).isEmpty(); - - bool isConstCharStarCase = - oneDimensionalArrayOfUnspecifiedSize - && typeInfo.qualifiedName().size() == 1 - && typeInfo.qualifiedName().at(0) == QStringLiteral("char") - && typeInfo.indirections() == 0 - && typeInfo.isConstant() - && typeInfo.referenceType() == NoReference - && typeInfo.arguments().isEmpty(); - - if (isConstCharStarCase) - typeInfo.setIndirections(typeInfo.indirections() + typeInfo.arrayElements().size()); - - // 2.2 Handle regular arrays. - if (!typeInfo.arrayElements().isEmpty() && !isConstCharStarCase) { - TypeInfo newInfo; - //newInfo.setArguments(typeInfo.arguments()); - newInfo.setIndirectionsV(typeInfo.indirectionsV()); - newInfo.setConstant(typeInfo.isConstant()); - newInfo.setVolatile(typeInfo.isVolatile()); - newInfo.setFunctionPointer(typeInfo.isFunctionPointer()); - newInfo.setQualifiedName(typeInfo.qualifiedName()); - newInfo.setReferenceType(typeInfo.referenceType()); - newInfo.setVolatile(typeInfo.isVolatile()); - - AbstractMetaType *elementType = translateTypeStatic(newInfo, currentClass, d, true, &errorMessage); - if (!elementType) { - if (errorMessageIn) { - errorMessage.prepend(QLatin1String("Unable to translate array element: ")); - *errorMessageIn = msgUnableToTranslateType(_typei, errorMessage); - } - return nullptr; - } - - for (int i = typeInfo.arrayElements().size() - 1; i >= 0; --i) { - auto *arrayType = new AbstractMetaType; - arrayType->setArrayElementType(elementType); - const QString &arrayElement = typeInfo.arrayElements().at(i); - if (!arrayElement.isEmpty()) { - bool _ok; - const qint64 elems = d - ? d->findOutValueFromString(arrayElement, _ok) - : arrayElement.toLongLong(&_ok, 0); - if (_ok) - arrayType->setArrayElementCount(int(elems)); - } - arrayType->setTypeEntry(new ArrayTypeEntry(elementType->typeEntry() , elementType->typeEntry()->version())); - arrayType->decideUsagePattern(); - - elementType = arrayType; - } - - return elementType; - } - - QStringList qualifierList = typeInfo.qualifiedName(); - if (qualifierList.isEmpty()) { - errorMessage = msgUnableToTranslateType(_typei, QLatin1String("horribly broken type")); - if (errorMessageIn) - *errorMessageIn = errorMessage; - else - qCWarning(lcShiboken,"%s", qPrintable(errorMessage)); - return nullptr; - } - - QString qualifiedName = qualifierList.join(colonColon()); - QString name = qualifierList.takeLast(); - - // 4. Special case QFlags (include instantiation in name) - if (qualifiedName == QLatin1String("QFlags")) { - qualifiedName = typeInfo.toString(); - typeInfo.clearInstantiations(); - } - - const TypeEntry *type = nullptr; - // 5. Try to find the type - - // 5.1 - Try first using the current scope - if (currentClass) { - type = findTypeEntryUsingContext(currentClass, qualifiedName); - - // 5.1.1 - Try using the class parents' scopes - if (!type && d && !currentClass->baseClassNames().isEmpty()) { - const AbstractMetaClassList &baseClasses = d->getBaseClasses(currentClass); - for (const AbstractMetaClass *cls : baseClasses) { - type = findTypeEntryUsingContext(cls, qualifiedName); - if (type) - break; - } - } - } - - // 5.2 - Try without scope - if (!type) - type = TypeDatabase::instance()->findType(qualifiedName); - - // 6. No? Try looking it up as a flags type - if (!type) - type = TypeDatabase::instance()->findFlagsType(qualifiedName); - - // 7. No? Try looking it up as a container type - if (!type) - type = TypeDatabase::instance()->findContainerType(name); - - // 8. No? Check if the current class is a template and this type is one - // of the parameters. - if (!type && currentClass) { - const QVector<TypeEntry *> &template_args = currentClass->templateArguments(); - for (TypeEntry *te : template_args) { - if (te->name() == qualifiedName) - type = te; - } - } - - if (!type) { - if (errorMessageIn) { - *errorMessageIn = - msgUnableToTranslateType(_typei, msgCannotFindTypeEntry(qualifiedName)); - } - return nullptr; - } - - // These are only implicit and should not appear in code... - Q_ASSERT(!type->isInterface()); - - auto *metaType = new AbstractMetaType; - metaType->setTypeEntry(type); - metaType->setIndirectionsV(typeInfo.indirectionsV()); - metaType->setReferenceType(typeInfo.referenceType()); - metaType->setConstant(typeInfo.isConstant()); - metaType->setVolatile(typeInfo.isVolatile()); - metaType->setOriginalTypeDescription(_typei.toString()); - - const auto &templateArguments = typeInfo.instantiations(); - for (int t = 0, size = templateArguments.size(); t < size; ++t) { - const TypeInfo &ti = templateArguments.at(t); - AbstractMetaType *targType = translateTypeStatic(ti, currentClass, d, true, &errorMessage); - if (!targType) { - if (errorMessageIn) - *errorMessageIn = msgCannotTranslateTemplateArgument(t, ti, errorMessage); - delete metaType; - return nullptr; - } - - metaType->addInstantiation(targType, true); - } - - // The usage pattern *must* be decided *after* the possible template - // instantiations have been determined, or else the absence of - // such instantiations will break the caching scheme of - // AbstractMetaType::cppSignature(). - metaType->decideUsagePattern(); - - return metaType; -} - -AbstractMetaType *AbstractMetaBuilder::translateType(const TypeInfo &_typei, - AbstractMetaClass *currentClass, - bool resolveType, - QString *errorMessage) -{ - return AbstractMetaBuilderPrivate::translateTypeStatic(_typei, currentClass, - nullptr, resolveType, - errorMessage); -} - -AbstractMetaType *AbstractMetaBuilder::translateType(const QString &t, - AbstractMetaClass *currentClass, - bool resolveType, - QString *errorMessageIn) -{ - QString errorMessage; - TypeInfo typeInfo = TypeParser::parse(t, &errorMessage); - if (typeInfo.qualifiedName().isEmpty()) { - errorMessage = msgUnableToTranslateType(t, errorMessage); - if (errorMessageIn) - *errorMessageIn = errorMessage; - else - qCWarning(lcShiboken, "%s", qPrintable(errorMessage)); - return nullptr; - } - return translateType(typeInfo, currentClass, resolveType, errorMessageIn); -} - -qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringValue, bool &ok) -{ - qint64 value = stringValue.toLongLong(&ok); - if (ok) - return value; - - if (stringValue == QLatin1String("true") || stringValue == QLatin1String("false")) { - ok = true; - return (stringValue == QLatin1String("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_]*$")); - Q_ASSERT(variableNameRegExp.isValid()); - if (!variableNameRegExp.match(stringValue).hasMatch()) { - ok = true; - return 0; - } - - AbstractMetaEnumValue *enumValue = AbstractMetaClass::findEnumValue(m_metaClasses, stringValue); - if (enumValue) { - ok = true; - return enumValue->value().value(); - } - - for (AbstractMetaEnum *metaEnum : qAsConst(m_globalEnums)) { - if (const AbstractMetaEnumValue *ev = metaEnum->findEnumValue(stringValue)) { - ok = true; - return ev->value().value(); - } - } - - ok = false; - return 0; -} - -QString AbstractMetaBuilderPrivate::fixDefaultValue(const ArgumentModelItem &item, - AbstractMetaType *type, - AbstractMetaFunction *fnc, - AbstractMetaClass *implementingClass, - int /* argumentIndex */) -{ - QString functionName = fnc->name(); - QString className = implementingClass ? implementingClass->qualifiedCppName() : QString(); - - QString expr = item->defaultValueExpression(); - if (type) { - 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 untill all namespaces are completly - // 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); - } 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("^(?: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; - } - } - } - } - } else { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("undefined type for default value '%3' of argument in function '%1', class '%2'") - .arg(functionName, className, item->defaultValueExpression()); - - expr = QString(); - } - - return expr; -} - -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 -{ - TypeDatabase* types = TypeDatabase::instance(); - - QStringList scope = context->typeEntry()->qualifiedCppName().split(colonColon()); - 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(); - QString completeName = prefix + name; - const TypeInfo parsed = TypeParser::parse(completeName, &errorMessage); - QString qualifiedName = parsed.qualifiedName().join(colonColon()); - if (qualifiedName.isEmpty()) { - qWarning().noquote().nospace() << "Unable to parse type \"" << completeName - << "\" while looking for template \"" << name << "\": " << errorMessage; - continue; - } - if (info) - *info = parsed; - - AbstractMetaClass *templ = nullptr; - for (AbstractMetaClass *c : qAsConst(m_templates)) { - if (c->typeEntry()->name() == qualifiedName) { - templ = c; - break; - } - } - - if (!templ) - templ = AbstractMetaClass::findClass(m_metaClasses, qualifiedName); - - if (templ) - return templ; - - if (baseContainerType) - *baseContainerType = types->findContainerType(qualifiedName); - } - - return nullptr; -} - -AbstractMetaClassList AbstractMetaBuilderPrivate::getBaseClasses(const AbstractMetaClass *metaClass) const -{ - AbstractMetaClassList 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); - - if (cls) - baseClasses << cls; - } - return baseClasses; -} - -bool AbstractMetaBuilderPrivate::ancestorHasPrivateCopyConstructor(const AbstractMetaClass *metaClass) const -{ - if (metaClass->hasPrivateCopyConstructor()) - return true; - const AbstractMetaClassList &baseClasses = getBaseClasses(metaClass); - for (const AbstractMetaClass *cls : baseClasses) { - if (ancestorHasPrivateCopyConstructor(cls)) - return true; - } - return false; -} - -AbstractMetaType * - AbstractMetaBuilderPrivate::inheritTemplateType(const AbstractMetaTypeList &templateTypes, - const AbstractMetaType *metaType) -{ - Q_ASSERT(metaType); - - QScopedPointer<AbstractMetaType> returned(metaType->copy()); - - if (!metaType->typeEntry()->isTemplateArgument() && !metaType->hasInstantiations()) - return returned.take(); - - returned->setOriginalTemplateType(metaType); - - if (returned->typeEntry()->isTemplateArgument()) { - const auto *tae = static_cast<const TemplateArgumentEntry*>(returned->typeEntry()); - - // If the template is intantiated with void we special case this as rejecting the functions that use this - // parameter from the instantiation. - const AbstractMetaType *templateType = templateTypes.value(tae->ordinal()); - if (!templateType || templateType->typeEntry()->isVoid()) - return nullptr; - - AbstractMetaType* t = returned->copy(); - t->setTypeEntry(templateType->typeEntry()); - t->setIndirections(templateType->indirections() + t->indirections() ? 1 : 0); - t->decideUsagePattern(); - - return inheritTemplateType(templateTypes, t); - } - - if (returned->hasInstantiations()) { - AbstractMetaTypeList instantiations = returned->instantiations(); - for (int i = 0; i < instantiations.count(); ++i) { - instantiations[i] = - inheritTemplateType(templateTypes, instantiations.at(i)); - if (!instantiations.at(i)) - return nullptr; - } - returned->setInstantiations(instantiations, true); - } - - return returned.take(); -} - -bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, - const AbstractMetaClass *templateClass, - const TypeInfo &info) -{ - QVector<TypeInfo> targs = info.instantiations(); - QVector<AbstractMetaType *> templateTypes; - QString errorMessage; - - if (subclass->isTypeDef()) { - subclass->setHasCloneOperator(templateClass->hasCloneOperator()); - subclass->setHasEqualsOperator(templateClass->hasEqualsOperator()); - subclass->setHasHashFunction(templateClass->hasHashFunction()); - subclass->setHasNonPrivateConstructor(templateClass->hasNonPrivateConstructor()); - subclass->setHasPrivateDestructor(templateClass->hasPrivateDestructor()); - subclass->setHasProtectedDestructor(templateClass->hasProtectedDestructor()); - subclass->setHasVirtualDestructor(templateClass->hasVirtualDestructor()); - } - - for (const TypeInfo &i : qAsConst(targs)) { - 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. - const bool isNumber = std::all_of(typeName.cbegin(), typeName.cend(), - [](QChar c) { return c.isDigit(); }); - if (isNumber) { - t = typeDb->findType(typeName); - if (!t) { - t = new EnumValueTypeEntry(typeName, typeName, nullptr, - QVersionNumber(0, 0)); - t->setCodeGeneration(0); - typeDb->addType(t); - } - } else { - QStringList possibleNames; - possibleNames << subclass->qualifiedCppName() + colonColon() + typeName; - possibleNames << templateClass->qualifiedCppName() + colonColon() + typeName; - if (subclass->enclosingClass()) - possibleNames << subclass->enclosingClass()->qualifiedCppName() + colonColon() + typeName; - possibleNames << typeName; - - for (const QString &possibleName : qAsConst(possibleNames)) { - t = typeDb->findType(possibleName); - if (t) - break; - } - } - - if (t) { - auto *temporaryType = new AbstractMetaType; - temporaryType->setTypeEntry(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."; - } - } - - const AbstractMetaFunctionList &subclassFuncs = subclass->functions(); - const AbstractMetaFunctionList &templateClassFunctions = templateClass->functions(); - for (const AbstractMetaFunction *function : templateClassFunctions) { - // If the function is modified or the instantiation has an equally named - // function we have shadowing, so we need to skip it. - if (function->isModifiedRemoved(TypeSystem::All) - || AbstractMetaFunction::find(subclassFuncs, function->name()) != nullptr) { - continue; - } - - QScopedPointer<AbstractMetaFunction> f(function->copy()); - f->setArguments(AbstractMetaArgumentList()); - - if (function->type()) { // Non-void - AbstractMetaType *returnType = inheritTemplateType(templateTypes, function->type()); - if (!returnType) - continue; - f->replaceType(returnType); - } - - const AbstractMetaArgumentList &arguments = function->arguments(); - for (AbstractMetaArgument *argument : arguments) { - AbstractMetaType *argType = inheritTemplateType(templateTypes, argument->type()); - if (!argType) - break; - AbstractMetaArgument *arg = argument->copy(); - arg->replaceType(argType); - 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()); - } - - 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.data(), - &errorMessage)) { - qCWarning(lcShiboken, "While specializing %s (%s): %s", - qPrintable(subclass->name()), qPrintable(templateClass->name()), - qPrintable(errorMessage)); - } - subclass->addFunction(f.take()); - } - - const AbstractMetaFieldList &subClassFields = subclass->fields(); - const AbstractMetaFieldList &templateClassFields = templateClass->fields(); - for (const AbstractMetaField *field : templateClassFields) { - // If the field is modified or the instantiation has a field named - // the same as an existing field we have shadowing, so we need to skip it. - if (field->isModifiedRemoved(TypeSystem::All) - || field->attributes().testFlag(AbstractMetaAttributes::Static) - || AbstractMetaField::find(subClassFields, field->name()) != nullptr) { - continue; - } - - QScopedPointer<AbstractMetaField> f(field->copy()); - f->setEnclosingClass(subclass); - AbstractMetaType *fieldType = inheritTemplateType(templateTypes, field->type()); - if (!fieldType) - continue; - f->replaceType(fieldType); - subclass->addField(f.take()); - } - - subclass->setTemplateBaseClass(templateClass); - subclass->setTemplateBaseClassInstantiations(templateTypes); - subclass->setInterfaces(templateClass->interfaces()); - subclass->setBaseClass(templateClass->baseClass()); - - return true; -} - -void AbstractMetaBuilderPrivate::parseQ_Property(AbstractMetaClass *metaClass, - const QStringList &declarations) -{ - const QStringList scopes = currentScope()->qualifiedName(); - - for (int i = 0; i < declarations.size(); ++i) { - const auto propertyTokens = declarations.at(i).splitRef(QLatin1Char(' ')); - - AbstractMetaType *type = nullptr; - for (int j = scopes.size(); j >= 0; --j) { - QStringList qualifiedName = scopes.mid(0, j); - qualifiedName.append(propertyTokens.at(0).toString()); - TypeInfo info; - info.setQualifiedName(qualifiedName); - - type = translateType(info, metaClass); - if (type) - break; - } - - if (!type) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("Unable to decide type of property: '%1' in class '%2'") - .arg(propertyTokens.at(0).toString(), metaClass->name()); - continue; - } - - auto *spec = new QPropertySpec(type->typeEntry()); - spec->setName(propertyTokens.at(1).toString()); - spec->setIndex(i); - - for (int pos = 2; pos + 1 < propertyTokens.size(); pos += 2) { - if (propertyTokens.at(pos) == QLatin1String("READ")) - spec->setRead(propertyTokens.at(pos + 1).toString()); - else if (propertyTokens.at(pos) == QLatin1String("WRITE")) - spec->setWrite(propertyTokens.at(pos + 1).toString()); - else if (propertyTokens.at(pos) == QLatin1String("DESIGNABLE")) - spec->setDesignable(propertyTokens.at(pos + 1).toString()); - else if (propertyTokens.at(pos) == QLatin1String("RESET")) - spec->setReset(propertyTokens.at(pos + 1).toString()); - } - - metaClass->addPropertySpec(spec); - delete type; - } -} - -static AbstractMetaFunction* findCopyCtor(AbstractMetaClass* cls) -{ - - const auto &functions = cls->functions(); - - for (AbstractMetaFunction *f : qAsConst(functions)) { - const AbstractMetaFunction::FunctionType t = f->functionType(); - if (t == AbstractMetaFunction::CopyConstructorFunction || t == AbstractMetaFunction::AssignmentOperatorFunction) - return f; - } - return nullptr; -} - -void AbstractMetaBuilderPrivate::setupClonable(AbstractMetaClass *cls) -{ - bool result = true; - - // find copy ctor for the current class - AbstractMetaFunction* copyCtor = findCopyCtor(cls); - if (copyCtor) { // 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()); - baseClasses << cls->interfaces().toList(); - - while (!baseClasses.isEmpty()) { - AbstractMetaClass* currentClass = baseClasses.dequeue(); - baseClasses << currentClass->interfaces().toList(); - if (currentClass->baseClass()) - baseClasses.enqueue(currentClass->baseClass()); - - copyCtor = findCopyCtor(currentClass); - if (copyCtor) { - result = copyCtor->isPublic(); - break; - } - } - } - cls->setHasCloneOperator(result); -} - -void AbstractMetaBuilderPrivate::setupExternalConversion(AbstractMetaClass *cls) -{ - const AbstractMetaFunctionList &convOps = cls->operatorOverloads(AbstractMetaClass::ConversionOp); - for (AbstractMetaFunction *func : convOps) { - if (func->isModifiedRemoved()) - continue; - AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_metaClasses, func->type()->typeEntry()); - if (!metaClass) - continue; - metaClass->addExternalConversionOperator(func); - } - const AbstractMetaClassList &innerClasses = cls->innerClasses(); - for (AbstractMetaClass *innerClass : innerClasses) - setupExternalConversion(innerClass); -} - -static void writeRejectLogFile(const QString &name, - const QMap<QString, AbstractMetaBuilder::RejectReason> &rejects) -{ - QFile f(name); - if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { - qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("failed to write log file: '%1'") - .arg(QDir::toNativeSeparators(f.fileName())); - return; - } - - QTextStream s(&f); - - - for (int reason = 0; reason < AbstractMetaBuilder::NoReason; ++reason) { - s << QString(72, QLatin1Char('*')) << 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; - } - - s << endl; - - for (QMap<QString, AbstractMetaBuilder::RejectReason>::const_iterator it = rejects.constBegin(); - it != rejects.constEnd(); ++it) { - if (it.value() != reason) - continue; - s << " - " << it.key() << endl; - } - - s << QString(72, QLatin1Char('*')) << endl << endl; - } - -} - -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); -} - -using ClassIndexHash = QHash<AbstractMetaClass *, int>; - -static ClassIndexHash::ConstIterator findByTypeEntry(const ClassIndexHash &map, - const TypeEntry *typeEntry) -{ - auto it = map.cbegin(); - for (auto end = map.cend(); it != end; ++it) { - if (it.key()->typeEntry() == typeEntry) - break; - } - return it; -} - -AbstractMetaClassList AbstractMetaBuilderPrivate::classesTopologicalSorted(const AbstractMetaClassList &classList, - const Dependencies &additionalDependencies) const -{ - ClassIndexHash map; - QHash<int, AbstractMetaClass *> reverseMap; - - int i = 0; - for (AbstractMetaClass *clazz : classList) { - if (map.contains(clazz)) - continue; - map.insert(clazz, i); - reverseMap.insert(i, clazz); - i++; - } - - Graph graph(map.count()); - - for (const auto &dep : additionalDependencies) { - const int parentIndex = map.value(dep.parent, -1); - const int childIndex = map.value(dep.child, -1); - if (parentIndex >= 0 && childIndex >= 0) { - graph.addEdge(parentIndex, childIndex); - } else { - qCWarning(lcShiboken).noquote().nospace() - << "AbstractMetaBuilder::classesTopologicalSorted(): Invalid additional dependency: " - << dep.child->name() << " -> " << dep.parent->name() << '.'; - } - } - - for (AbstractMetaClass *clazz : classList) { - const int classIndex = map.value(clazz); - if (auto enclosing = clazz->enclosingClass()) { - const auto enclosingIt = map.constFind(const_cast< AbstractMetaClass *>(enclosing)); - if (enclosingIt!= map.cend()) - graph.addEdge(enclosingIt.value(), classIndex); - } - - const AbstractMetaClassList &bases = getBaseClasses(clazz); - for (AbstractMetaClass *baseClass : bases) { - // Fix polymorphic expression - if (clazz->baseClass() == baseClass) - clazz->setBaseClass(baseClass); - - const auto baseIt = map.constFind(baseClass); - if (baseIt!= map.cend()) - graph.addEdge(baseIt.value(), classIndex); - } - - const AbstractMetaFunctionList &functions = clazz->functions(); - for (AbstractMetaFunction *func : functions) { - const AbstractMetaArgumentList &arguments = func->arguments(); - for (AbstractMetaArgument *arg : arguments) { - // Check methods with default args: If a class is instantiated by value, - // ("QString s = QString()"), add a dependency. - if (!arg->originalDefaultValueExpression().isEmpty() - && arg->type()->isValue()) { - auto typeEntry = arg->type()->typeEntry(); - if (typeEntry->isComplex() && typeEntry != clazz->typeEntry()) { - auto ait = findByTypeEntry(map, typeEntry); - if (ait != map.cend() && ait.key()->enclosingClass() != clazz) - graph.addEdge(ait.value(), classIndex); - } - } - } - } - } - - AbstractMetaClassList result; - const auto unmappedResult = graph.topologicalSort(); - if (unmappedResult.isEmpty() && graph.nodeCount()) { - QTemporaryFile tempFile(QDir::tempPath() + QLatin1String("/cyclic_depXXXXXX.dot")); - tempFile.setAutoRemove(false); - tempFile.open(); - QHash<int, QString> hash; - for (auto it = map.cbegin(), end = map.cend(); it != end; ++it) - hash.insert(it.value(), it.key()->qualifiedCppName()); - graph.dumpDot(hash, tempFile.fileName()); - qCWarning(lcShiboken).noquote().nospace() - << "Cyclic dependency found! Graph can be found at " - << QDir::toNativeSeparators(tempFile.fileName()); - } else { - for (int i : qAsConst(unmappedResult)) { - Q_ASSERT(reverseMap.contains(i)); - if (!reverseMap[i]->isInterface()) - result << reverseMap[i]; - } - } - - return result; -} - -void AbstractMetaBuilderPrivate::pushScope(const NamespaceModelItem &item) -{ - // For purposes of type lookup, join all namespaces of the same name - // within the parent item. - QVector<NamespaceModelItem> candidates; - const QString name = item->name(); - if (!m_scopes.isEmpty()) { - for (const auto &n : m_scopes.constLast()->namespaces()) { - if (n->name() == name) - candidates.append(n); - } - } - if (candidates.size() > 1) { - NamespaceModelItem joined(new _NamespaceModelItem(m_scopes.constLast()->model(), - name, _CodeModelItem::Kind_Namespace)); - joined->setScope(item->scope()); - for (const auto &n : candidates) - joined->appendNamespace(*n); - m_scopes << joined; - } else { - m_scopes << item; - } -} - -AbstractMetaClassList AbstractMetaBuilder::classesTopologicalSorted(const AbstractMetaClassList &classList, - const Dependencies &additionalDependencies) const -{ - return d->classesTopologicalSorted(classList, additionalDependencies); -} - -AbstractMetaArgumentList AbstractMetaBuilderPrivate::reverseList(const AbstractMetaArgumentList &list) -{ - AbstractMetaArgumentList ret; - - int index = list.size(); - for (AbstractMetaArgument *arg : list) { - arg->setArgumentIndex(index); - ret.prepend(arg); - index--; - } - - return ret; -} - -void AbstractMetaBuilder::setGlobalHeader(const QString& globalHeader) -{ - d->m_globalHeader = QFileInfo(globalHeader); -} - -void AbstractMetaBuilder::setHeaderPaths(const HeaderPaths &hp) -{ - for (const auto & h: hp) { - if (h.type != HeaderType::Framework && h.type != HeaderType::FrameworkSystem) - d->m_headerPaths.append(QFile::decodeName(h.path)); - } -} - -void AbstractMetaBuilder::setSkipDeprecated(bool value) -{ - d->m_skipDeprecated = value; -} - -// PYSIDE-975: When receiving an absolute path name from the code model, try -// to resolve it against the include paths set on shiboken in order to recreate -// relative paths like #include <foo/bar.h>. - -static inline bool isFileSystemSlash(QChar c) -{ - return c == QLatin1Char('/') || c == QLatin1Char('\\'); -} - -static bool matchHeader(const QString &headerPath, const QString &fileName) -{ -#if defined(Q_OS_WIN) || defined(Q_OS_DARWIN) - static const Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive; -#else - static const Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive; -#endif - const int pathSize = headerPath.size(); - return fileName.size() > pathSize - && isFileSystemSlash(fileName.at(pathSize)) - && fileName.startsWith(headerPath, caseSensitivity); -} - -void AbstractMetaBuilderPrivate::setInclude(TypeEntry *te, const QString &fileName) const -{ - auto it = m_resolveIncludeHash.find(fileName); - if (it == m_resolveIncludeHash.end()) { - QFileInfo info(fileName); - if (m_globalHeader.fileName() == info.fileName()) - return; - - int bestMatchLength = 0; - for (const auto &headerPath : m_headerPaths) { - if (headerPath.size() > bestMatchLength && matchHeader(headerPath, fileName)) - bestMatchLength = headerPath.size(); - } - const QString include = bestMatchLength > 0 - ? fileName.right(fileName.size() - bestMatchLength - 1) - : info.fileName(); - it = m_resolveIncludeHash.insert(fileName, {Include::IncludePath, include}); - } - te->setInclude(it.value()); -} - -#ifndef QT_NO_DEBUG_STREAM -template <class Container> -static void debugFormatSequence(QDebug &d, const char *key, const Container& c, - const char *separator = ", ") -{ - if (c.isEmpty()) - return; - const auto begin = c.begin(); - const auto end = c.end(); - d << "\n " << key << '[' << c.size() << "]=("; - for (auto it = begin; it != end; ++it) { - if (it != begin) - d << separator; - d << *it; - } - d << ')'; -} - -void AbstractMetaBuilder::formatDebug(QDebug &debug) const -{ - debug << "m_globalHeader=" << d->m_globalHeader.absoluteFilePath(); - debugFormatSequence(debug, "globalEnums", d->m_globalEnums, "\n"); - debugFormatSequence(debug, "globalFunctions", d->m_globalFunctions, "\n"); - if (const int scopeCount = d->m_scopes.size()) { - debug << "\n scopes[" << scopeCount << "]=("; - for (int i = 0; i < scopeCount; ++i) { - if (i) - debug << ", "; - _CodeModelItem::formatKind(debug, d->m_scopes.at(i)->kind()); - debug << " \"" << d->m_scopes.at(i)->name() << '"'; - } - debug << ')'; - } - debugFormatSequence(debug, "classes", d->m_metaClasses, "\n"); - debugFormatSequence(debug, "templates", d->m_templates, "\n"); -} - -QDebug operator<<(QDebug d, const AbstractMetaBuilder &ab) -{ - QDebugStateSaver saver(d); - d.noquote(); - d.nospace(); - d << "AbstractMetaBuilder("; - ab.formatDebug(d); - d << ')'; - return d; -} -#endif // !QT_NO_DEBUG_STREAM |