diff options
Diffstat (limited to 'sources/shiboken6/generator/generator.cpp')
-rw-r--r-- | sources/shiboken6/generator/generator.cpp | 649 |
1 files changed, 247 insertions, 402 deletions
diff --git a/sources/shiboken6/generator/generator.cpp b/sources/shiboken6/generator/generator.cpp index 6a0183403..b224858c5 100644 --- a/sources/shiboken6/generator/generator.cpp +++ b/sources/shiboken6/generator/generator.cpp @@ -1,171 +1,43 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "generator.h" +#include "defaultvalue.h" +#include "generatorcontext.h" #include "apiextractorresult.h" -#include "ctypenames.h" +#include "abstractmetaargument.h" #include "abstractmetaenum.h" -#include "abstractmetafield.h" #include "abstractmetafunction.h" #include "abstractmetalang.h" -#include "parser/codemodel.h" #include "messages.h" +#include <optionsparser.h> #include "reporthandler.h" #include "fileout.h" -#include "apiextractor.h" -#include "typesystem.h" +#include "arraytypeentry.h" +#include "enumtypeentry.h" +#include "enumvaluetypeentry.h" +#include "namespacetypeentry.h" +#include "primitivetypeentry.h" +#include "typesystemtypeentry.h" +#include <typedatabase.h> + +#include "qtcompat.h" #include <QtCore/QDir> #include <QtCore/QFile> #include <QtCore/QFileInfo> #include <QtCore/QRegularExpression> -#include <QDebug> -#include <typedatabase.h> - -/** - * DefaultValue is used for storing default values of types for which code is - * generated in different contexts: - * - * Context | Example: "Class *" | Example: "Class" with default Constructor - * --------------------+-------------------------------+------------------------------------------ - * Variable | var{nullptr}; | var; - * initializations | | - * --------------------+-------------------------------+------------------------------------------ - * Return values | return nullptr; | return {} - * --------------------+-------------------------------+------------------------------------------ - * constructor | static_cast<Class *>(nullptr) | Class() - * arguments lists | | - * (recursive, precise | | - * matching). | | - */ - -DefaultValue::DefaultValue(Type t, QString value) : - m_type(t), m_value(std::move(value)) -{ -} - -DefaultValue::DefaultValue(QString customValue) : - m_type(Custom), m_value(std::move(customValue)) -{ -} - -QString DefaultValue::returnValue() const -{ - switch (m_type) { - case DefaultValue::Boolean: - return QLatin1String("false"); - case DefaultValue::CppScalar: - return QLatin1String("0"); - case DefaultValue::Custom: - case DefaultValue::Enum: - return m_value; - case DefaultValue::Pointer: - return QLatin1String("nullptr"); - case DefaultValue::Void: - return QString(); - case DefaultValue::DefaultConstructorWithDefaultValues: - return m_value + QLatin1String("()"); - case DefaultValue::DefaultConstructor: - break; - } - return QLatin1String("{}"); -} - -QString DefaultValue::initialization() const -{ - switch (m_type) { - case DefaultValue::Boolean: - return QLatin1String("{false}"); - case DefaultValue::CppScalar: - return QLatin1String("{0}"); - case DefaultValue::Custom: - return QLatin1String(" = ") + m_value; - case DefaultValue::Enum: - return QLatin1Char('{') + m_value + QLatin1Char('}'); - case DefaultValue::Pointer: - return QLatin1String("{nullptr}"); - case DefaultValue::Void: - Q_ASSERT(false); - break; - case DefaultValue::DefaultConstructor: - case DefaultValue::DefaultConstructorWithDefaultValues: - break; - } - return QString(); -} -QString DefaultValue::constructorParameter() const -{ - switch (m_type) { - case DefaultValue::Boolean: - return QLatin1String("false"); - case DefaultValue::CppScalar: { - // PYSIDE-846: Use static_cast in case of "unsigned long" and similar - const QString cast = m_value.contains(QLatin1Char(' ')) - ? QLatin1String("static_cast<") + m_value + QLatin1Char('>') - : m_value; - return cast + QLatin1String("(0)"); - } - case DefaultValue::Custom: - case DefaultValue::Enum: - return m_value; - case DefaultValue::Pointer: - // Be precise here to be able to differentiate between constructors - // taking different pointer types, cf - // QTreeWidgetItemIterator(QTreeWidget *) and - // QTreeWidgetItemIterator(QTreeWidgetItemIterator *). - return QLatin1String("static_cast<") + m_value + QLatin1String("*>(nullptr)"); - case DefaultValue::Void: - Q_ASSERT(false); - break; - case DefaultValue::DefaultConstructor: - case DefaultValue::DefaultConstructorWithDefaultValues: - break; - } - return m_value + QLatin1String("()"); -} +using namespace Qt::StringLiterals; -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug debug, const DefaultValue &v) -{ - QDebugStateSaver saver(debug); - debug.noquote(); - debug.nospace(); - debug << "DefaultValue(" << v.type() << ", \"" << v.value() << "\")"; - return debug; -} -#endif // !QT_NO_DEBUG_STREAM +static constexpr auto ENABLE_PYSIDE_EXTENSIONS = "enable-pyside-extensions"_L1; +static constexpr auto AVOID_PROTECTED_HACK = "avoid-protected-hack"_L1; -QString GeneratorContext::smartPointerWrapperName() const +struct GeneratorOptions { - Q_ASSERT(m_type == SmartPointer); - return m_preciseClassType.cppSignature(); -} + bool usePySideExtensions = false; + bool avoidProtectedHack = false; +}; struct Generator::GeneratorPrivate { @@ -173,13 +45,16 @@ struct Generator::GeneratorPrivate QString outDir; // License comment QString licenseComment; - QStringList instantiatedContainersNames; - AbstractMetaTypeList instantiatedContainers; - AbstractMetaTypeList instantiatedSmartPointers; AbstractMetaClassCList m_invisibleTopNamespaces; bool m_hasPrivateClasses = false; + static GeneratorOptions m_options; }; +GeneratorOptions Generator::GeneratorPrivate::m_options; + +// Kept as a variable for a potential Qt-in-namespace support +QString Generator::m_gsp = "::"_L1; + Generator::Generator() : m_d(new GeneratorPrivate) { } @@ -193,17 +68,19 @@ bool Generator::setup(const ApiExtractorResult &api) { m_d->api = api; const auto moduleEntry = TypeDatabase::instance()->defaultTypeSystemType(); - if (!moduleEntry || !moduleEntry->generateCode()) { - qCWarning(lcShiboken) << "Couldn't find the package name!!"; + if (!moduleEntry) { + qCWarning(lcShiboken,"Couldn't find the package name!!"); + return false; + } + if (!moduleEntry->generateCode()) { + qCWarning(lcShiboken, "Code generation of root typesystem is disabled!!"); return false; } - collectInstantiatedContainersAndSmartPointers(); - - for (auto c : api.classes()) { + for (const auto &c : api.classes()) { if (c->enclosingClass() == nullptr && c->isInvisibleNamespace()) { m_d->m_invisibleTopNamespaces.append(c); - c->invisibleNamespaceRecursion([&](AbstractMetaClass *ic) { + c->invisibleNamespaceRecursion([&](const AbstractMetaClassCPtr &ic) { m_d->m_invisibleTopNamespaces.append(ic); }); } @@ -212,150 +89,65 @@ bool Generator::setup(const ApiExtractorResult &api) return doSetup(); } -QString Generator::getSimplifiedContainerTypeName(const AbstractMetaType &type) +QList<OptionDescription> Generator::options() { - const QString signature = type.cppSignature(); - if (!type.typeEntry()->isContainer() && !type.typeEntry()->isSmartPointer()) - return signature; - QString typeName = signature; - if (type.isConstant()) - typeName.remove(0, sizeof("const ") / sizeof(char) - 1); - switch (type.referenceType()) { - case NoReference: - break; - case LValueReference: - typeName.chop(1); - break; - case RValueReference: - typeName.chop(2); - break; - } - while (typeName.endsWith(QLatin1Char('*')) || typeName.endsWith(QLatin1Char(' '))) - typeName.chop(1); - return typeName; -} - -// Strip a "const QSharedPtr<const Foo> &" or similar to "QSharedPtr<Foo>" (PYSIDE-1016/454) -AbstractMetaType canonicalSmartPtrInstantiation(const AbstractMetaType &type) -{ - const AbstractMetaTypeList &instantiations = type.instantiations(); - Q_ASSERT(instantiations.size() == 1); - const bool needsFix = type.isConstant() || type.referenceType() != NoReference; - const bool pointeeNeedsFix = instantiations.constFirst().isConstant(); - if (!needsFix && !pointeeNeedsFix) - return type; - auto fixedType = type; - fixedType.setReferenceType(NoReference); - fixedType.setConstant(false); - if (pointeeNeedsFix) { - auto fixedPointeeType = instantiations.constFirst(); - fixedPointeeType.setConstant(false); - fixedType.setInstantiations(AbstractMetaTypeList(1, fixedPointeeType)); - } - return fixedType; -} - -static inline const TypeEntry *pointeeTypeEntry(const AbstractMetaType &smartPtrType) -{ - return smartPtrType.instantiations().constFirst().typeEntry(); + return { + {AVOID_PROTECTED_HACK, + u"Avoid the use of the '#define protected public' hack."_s}, + {ENABLE_PYSIDE_EXTENSIONS, + u"Enable PySide extensions, such as support for signal/slots,\n" + "use this if you are creating a binding for a Qt-based library."_s} + }; } -void Generator::addInstantiatedContainersAndSmartPointers(const AbstractMetaType &type, - const QString &context) +class GeneratorOptionsParser : public OptionsParser { - for (const auto &t : type.instantiations()) - addInstantiatedContainersAndSmartPointers(t, context); - const auto typeEntry = type.typeEntry(); - const bool isContainer = typeEntry->isContainer(); - if (!isContainer - && !(typeEntry->isSmartPointer() && typeEntry->generateCode())) { - return; - } - if (type.hasTemplateChildren()) { - QString piece = isContainer ? QStringLiteral("container") : QStringLiteral("smart pointer"); - QString warning = - QString::fromLatin1("Skipping instantiation of %1 '%2' because it has template" - " arguments.").arg(piece, type.originalTypeDescription()); - if (!context.isEmpty()) - warning.append(QStringLiteral(" Calling context: ") + context); - - qCWarning(lcShiboken).noquote().nospace() << warning; - return; - - } - if (isContainer) { - const QString typeName = getSimplifiedContainerTypeName(type); - if (!m_d->instantiatedContainersNames.contains(typeName)) { - m_d->instantiatedContainersNames.append(typeName); - auto simplifiedType = type; - simplifiedType.setIndirections(0); - simplifiedType.setConstant(false); - simplifiedType.setReferenceType(NoReference); - simplifiedType.decideUsagePattern(); - m_d->instantiatedContainers.append(simplifiedType); - } - return; - } - - // Is smart pointer. Check if the (const?) pointee is already known for the given - // smart pointer type entry. - auto pt = pointeeTypeEntry(type); - const bool present = - std::any_of(m_d->instantiatedSmartPointers.cbegin(), m_d->instantiatedSmartPointers.cend(), - [typeEntry, pt] (const AbstractMetaType &t) { - return t.typeEntry() == typeEntry && pointeeTypeEntry(t) == pt; - }); - if (!present) - m_d->instantiatedSmartPointers.append(canonicalSmartPtrInstantiation(type)); -} +public: + explicit GeneratorOptionsParser(GeneratorOptions *o) : m_options(o) {} -void Generator::collectInstantiatedContainersAndSmartPointers(const AbstractMetaFunctionCPtr &func) -{ - addInstantiatedContainersAndSmartPointers(func->type(), func->signature()); - const AbstractMetaArgumentList &arguments = func->arguments(); - for (const AbstractMetaArgument &arg : arguments) - addInstantiatedContainersAndSmartPointers(arg.type(), func->signature()); -} + bool handleBoolOption(const QString &key, OptionSource source) override; -void Generator::collectInstantiatedContainersAndSmartPointers(const AbstractMetaClass *metaClass) -{ - if (!metaClass->typeEntry()->generateCode()) - return; - for (const auto &func : metaClass->functions()) - collectInstantiatedContainersAndSmartPointers(func); - for (const AbstractMetaField &field : metaClass->fields()) - addInstantiatedContainersAndSmartPointers(field.type(), field.name()); - const AbstractMetaClassList &innerClasses = metaClass->innerClasses(); - for (AbstractMetaClass *innerClass : innerClasses) - collectInstantiatedContainersAndSmartPointers(innerClass); -} +private: + GeneratorOptions *m_options; +}; -void Generator::collectInstantiatedContainersAndSmartPointers() +bool GeneratorOptionsParser::handleBoolOption(const QString & key, OptionSource source) { - for (const auto &func : m_d->api.globalFunctions()) - collectInstantiatedContainersAndSmartPointers(func); - for (auto metaClass : m_d->api.classes()) - collectInstantiatedContainersAndSmartPointers(metaClass); + if (source == OptionSource::CommandLineSingleDash) + return false; + if (key == ENABLE_PYSIDE_EXTENSIONS) + return ( m_options->usePySideExtensions = true); + if (key == AVOID_PROTECTED_HACK) + return ( m_options->avoidProtectedHack = true); + return false; } -AbstractMetaTypeList Generator::instantiatedContainers() const +std::shared_ptr<OptionsParser> Generator::createOptionsParser() { - return m_d->instantiatedContainers; + return std::make_shared<GeneratorOptionsParser>(&GeneratorPrivate::m_options); } -AbstractMetaTypeList Generator::instantiatedSmartPointers() const -{ - return m_d->instantiatedSmartPointers; -} +QString Generator::fileNameForContextHelper(const GeneratorContext &context, + const QString &suffix, + FileNameFlags flags) -Generator::OptionDescriptions Generator::options() const { - return OptionDescriptions(); -} + if (!context.forSmartPointer()) { + const auto metaClass = context.metaClass(); + QString fileNameBase = flags.testFlag(FileNameFlag::UnqualifiedName) + ? metaClass->name() : metaClass->qualifiedCppName(); + if (!flags.testFlag(FileNameFlag::KeepCase)) + fileNameBase = fileNameBase.toLower(); + fileNameBase.replace(u"::"_s, u"_"_s); + return fileNameBase + suffix; + } -bool Generator::handleOption(const QString & /* key */, const QString & /* value */) -{ - return false; + // FIXME: PYSIDE7: Use the above code path for all types. Note the file + // names will then change to reflect the namespaces of the pointee + // (smart/integer2). + const AbstractMetaType &smartPointerType = context.preciseType(); + QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType); + return fileNameBase + suffix; } const AbstractMetaClassCList &Generator::invisibleTopNamespaces() const @@ -363,12 +155,12 @@ const AbstractMetaClassCList &Generator::invisibleTopNamespaces() const return m_d->m_invisibleTopNamespaces; } -PrimitiveTypeEntryList Generator::primitiveTypes() +PrimitiveTypeEntryCList Generator::primitiveTypes() { return TypeDatabase::instance()->primitiveTypes(); } -ContainerTypeEntryList Generator::containerTypes() +ContainerTypeEntryCList Generator::containerTypes() { return TypeDatabase::instance()->containerTypes(); } @@ -391,7 +183,7 @@ QString Generator::packageName() static QString getModuleName() { QString result = TypeDatabase::instance()->defaultPackageName(); - result.remove(0, result.lastIndexOf(QLatin1Char('.')) + 1); + result.remove(0, result.lastIndexOf(u'.') + 1); return result; } @@ -413,17 +205,19 @@ void Generator::setOutputDirectory(const QString &outDir) bool Generator::generateFileForContext(const GeneratorContext &context) { - const AbstractMetaClass *cls = context.metaClass(); + const auto cls = context.metaClass(); + auto typeEntry = cls->typeEntry(); - if (!shouldGenerate(cls)) + if (!shouldGenerate(typeEntry)) return true; const QString fileName = fileNameForContext(context); if (fileName.isEmpty()) return true; - QString filePath = outputDirectory() + QLatin1Char('/') + subDirectoryForClass(cls) - + QLatin1Char('/') + fileName; + QString filePath = outputDirectory() + u'/' + + subDirectoryForPackage(typeEntry->targetLangPackage()) + + u'/' + fileName; FileOut fileOut(filePath); generateClass(fileOut.stream, context); @@ -432,68 +226,64 @@ bool Generator::generateFileForContext(const GeneratorContext &context) return true; } -QString Generator::getFileNameBaseForSmartPointer(const AbstractMetaType &smartPointerType, - const AbstractMetaClass *smartPointerClass) +QString Generator::getFileNameBaseForSmartPointer(const AbstractMetaType &smartPointerType) { const AbstractMetaType innerType = smartPointerType.getSmartPointerInnerType(); - QString fileName = smartPointerClass->qualifiedCppName().toLower(); - fileName.replace(QLatin1String("::"), QLatin1String("_")); - fileName.append(QLatin1String("_")); + smartPointerType.typeEntry()->qualifiedCppName(); + QString fileName = smartPointerType.typeEntry()->qualifiedCppName().toLower(); + fileName.replace(u"::"_s, u"_"_s); + fileName.append(u"_"_s); fileName.append(innerType.name().toLower()); return fileName; } -GeneratorContext Generator::contextForClass(const AbstractMetaClass *c) const +GeneratorContext Generator::contextForClass(const AbstractMetaClassCPtr &c) const { GeneratorContext result; result.m_metaClass = c; return result; } -GeneratorContext Generator::contextForSmartPointer(const AbstractMetaClass *c, - const AbstractMetaType &t) +GeneratorContext + Generator::contextForSmartPointer(const AbstractMetaClassCPtr &c, + const AbstractMetaType &t, + const AbstractMetaClassCPtr &pointeeClass) { GeneratorContext result; result.m_metaClass = c; result.m_preciseClassType = t; result.m_type = GeneratorContext::SmartPointer; + result.m_pointeeClass = pointeeClass; return result; } bool Generator::generate() { - for (auto cls : m_d->api.classes()) { + for (const auto &cls : m_d->api.classes()) { if (!generateFileForContext(contextForClass(cls))) return false; - if (shouldGenerate(cls) && cls->typeEntry()->isPrivate()) + auto te = cls->typeEntry(); + if (shouldGenerate(te) && te->isPrivate()) m_d->m_hasPrivateClasses = true; } - const auto smartPointers = m_d->api.smartPointers(); - for (const AbstractMetaType &type : qAsConst(m_d->instantiatedSmartPointers)) { - const AbstractMetaClass *smartPointerClass = - AbstractMetaClass::findClass(smartPointers, type.typeEntry()); - if (!smartPointerClass) { - qCWarning(lcShiboken, "%s", - qPrintable(msgCannotFindSmartPointer(type.cppSignature(), - smartPointers))); + for (const auto &smp: m_d->api.instantiatedSmartPointers()) { + AbstractMetaClassCPtr pointeeClass; + const auto instantiatedType = smp.type.instantiations().constFirst().typeEntry(); + if (instantiatedType->isComplex()) // not a C++ primitive + pointeeClass = AbstractMetaClass::findClass(m_d->api.classes(), instantiatedType); + if (!generateFileForContext(contextForSmartPointer(smp.specialized, smp.type, + pointeeClass))) { return false; } - if (!generateFileForContext(contextForSmartPointer(smartPointerClass, type))) - return false; } return finishGeneration(); } -bool Generator::shouldGenerateTypeEntry(const TypeEntry *type) -{ - return type->generateCode() && NamespaceTypeEntry::isVisibleScope(type); -} - -bool Generator::shouldGenerate(const AbstractMetaClass *metaClass) const +bool Generator::shouldGenerate(const TypeEntryCPtr &typeEntry) const { - return shouldGenerateTypeEntry(metaClass->typeEntry()); + return typeEntry->shouldGenerate(); } const ApiExtractorResult &Generator::api() const @@ -506,24 +296,32 @@ bool Generator::hasPrivateClasses() const return m_d->m_hasPrivateClasses; } -QString Generator::getFullTypeName(const TypeEntry *type) +bool Generator::usePySideExtensions() +{ + return GeneratorPrivate::m_options.usePySideExtensions; +} + +bool Generator::avoidProtectedHack() +{ + return GeneratorPrivate::m_options.avoidProtectedHack; +} + +QString Generator::getFullTypeName(TypeEntryCPtr type) { QString result = type->qualifiedCppName(); if (type->isArray()) - type = static_cast<const ArrayTypeEntry *>(type)->nestedTypeEntry(); - if (!type->isCppPrimitive()) - result.prepend(QLatin1String("::")); - return result; + type = std::static_pointer_cast<const ArrayTypeEntry>(type)->nestedTypeEntry(); + return isCppPrimitive(type) ? result : addGlobalScopePrefix(result); } QString Generator::getFullTypeName(const AbstractMetaType &type) { if (type.isCString()) - return QLatin1String("const char*"); + return u"const char*"_s; if (type.isVoidPointer()) - return QLatin1String("void*"); + return u"void*"_s; if (type.typeEntry()->isContainer()) - return QLatin1String("::") + type.cppSignature(); + return addGlobalScopePrefix(type.cppSignature()); QString typeName; if (type.typeEntry()->isComplex() && type.hasInstantiations()) typeName = getFullTypeNameWithoutModifiers(type); @@ -532,17 +330,19 @@ QString Generator::getFullTypeName(const AbstractMetaType &type) return typeName + QString::fromLatin1("*").repeated(type.indirections()); } -QString Generator::getFullTypeName(const AbstractMetaClass *metaClass) +QString Generator::getFullTypeName(const AbstractMetaClassCPtr &metaClass) { - return QLatin1String("::") + metaClass->qualifiedCppName(); + const QString &qualName = metaClass->qualifiedCppName(); + // Typedefs are generated into the global namespace + return metaClass->isTypeDef() ? qualName : addGlobalScopePrefix(qualName); } QString Generator::getFullTypeNameWithoutModifiers(const AbstractMetaType &type) { if (type.isCString()) - return QLatin1String("const char*"); + return u"const char*"_s; if (type.isVoidPointer()) - return QLatin1String("void*"); + return u"void*"_s; if (!type.hasInstantiations()) return getFullTypeName(type.typeEntry()); QString typeName = type.cppSignature(); @@ -558,9 +358,9 @@ QString Generator::getFullTypeNameWithoutModifiers(const AbstractMetaType &type) typeName.chop(2); break; } - while (typeName.endsWith(QLatin1Char('*')) || typeName.endsWith(QLatin1Char(' '))) + while (typeName.endsWith(u'*') || typeName.endsWith(u' ')) typeName.chop(1); - return QLatin1String("::") + typeName; + return addGlobalScopePrefix(typeName); } std::optional<DefaultValue> @@ -573,29 +373,29 @@ std::optional<DefaultValue> if (type.isContainer()) { QString ctor = type.cppSignature(); - if (ctor.endsWith(QLatin1Char('*'))) { + if (ctor.endsWith(u'*')) { ctor.chop(1); return DefaultValue(DefaultValue::Pointer, ctor.trimmed()); } - if (ctor.startsWith(QLatin1String("const "))) + if (ctor.startsWith(u"const ")) ctor.remove(0, sizeof("const ") / sizeof(char) - 1); - if (ctor.endsWith(QLatin1Char('&'))) { + if (ctor.endsWith(u'&')) { ctor.chop(1); ctor = ctor.trimmed(); } - return DefaultValue(DefaultValue::DefaultConstructor, QLatin1String("::") + ctor); + return DefaultValue(DefaultValue::DefaultConstructor, u"::"_s + ctor); } if (type.isNativePointer()) return DefaultValue(DefaultValue::Pointer, type.typeEntry()->qualifiedCppName()); if (type.isPointer()) - return DefaultValue(DefaultValue::Pointer, QLatin1String("::") + type.typeEntry()->qualifiedCppName()); + return DefaultValue(DefaultValue::Pointer, getFullTypeName(type.typeEntry())); if (type.typeEntry()->isSmartPointer()) return minimalConstructor(api, type.typeEntry()); if (type.typeEntry()->isComplex()) { - auto cType = static_cast<const ComplexTypeEntry *>(type.typeEntry()); + auto cType = std::static_pointer_cast<const ComplexTypeEntry>(type.typeEntry()); if (cType->hasDefaultConstructor()) return DefaultValue(DefaultValue::Custom, cType->defaultConstructor()); auto klass = AbstractMetaClass::findClass(api.classes(), cType); @@ -620,41 +420,40 @@ std::optional<DefaultValue> std::optional<DefaultValue> Generator::minimalConstructor(const ApiExtractorResult &api, - const TypeEntry *type, + const TypeEntryCPtr &type, QString *errorString) { if (!type) return {}; - if (type->isCppPrimitive()) { + if (isCppPrimitive(type)) { const QString &name = type->qualifiedCppName(); - return name == QLatin1String("bool") + return name == u"bool" ? DefaultValue(DefaultValue::Boolean) : DefaultValue(DefaultValue::CppScalar, name); } if (type->isEnum()) { - const auto enumEntry = static_cast<const EnumTypeEntry *>(type); - if (const auto *nullValue = enumEntry->nullValue()) + const auto enumEntry = std::static_pointer_cast<const EnumTypeEntry>(type); + if (const auto nullValue = enumEntry->nullValue()) return DefaultValue(DefaultValue::Enum, nullValue->name()); return DefaultValue(DefaultValue::Custom, - QLatin1String("static_cast< ::") + type->qualifiedCppName() - + QLatin1String(">(0)")); + "static_cast< "_L1 + getFullTypeName(type) + ">(0)"_L1); } if (type->isFlags()) { return DefaultValue(DefaultValue::Custom, - type->qualifiedCppName() + QLatin1String("(0)")); + type->qualifiedCppName() + u"(0)"_s); } if (type->isPrimitive()) { - QString ctor = static_cast<const PrimitiveTypeEntry *>(type)->defaultConstructor(); + QString ctor = std::static_pointer_cast<const PrimitiveTypeEntry>(type)->defaultConstructor(); // If a non-C++ (i.e. defined by the user) primitive type does not have // a default constructor defined by the user, the empty constructor is // heuristically returned. If this is wrong the build of the generated // bindings will tell. return ctor.isEmpty() - ? DefaultValue(DefaultValue::DefaultConstructorWithDefaultValues, QLatin1String("::") + ? DefaultValue(DefaultValue::DefaultConstructorWithDefaultValues, u"::"_s + type->qualifiedCppName()) : DefaultValue(DefaultValue::Custom, ctor); } @@ -673,25 +472,25 @@ std::optional<DefaultValue> } if (errorString != nullptr) - *errorString = QLatin1String("No default value could be determined."); + *errorString = u"No default value could be determined."_s; return {}; } static QString constructorCall(const QString &qualifiedCppName, const QStringList &args) { - return QLatin1String("::") + qualifiedCppName + QLatin1Char('(') - + args.join(QLatin1String(", ")) + QLatin1Char(')'); + return u"::"_s + qualifiedCppName + u'(' + + args.join(u", "_s) + u')'; } std::optional<DefaultValue> Generator::minimalConstructor(const ApiExtractorResult &api, - const AbstractMetaClass *metaClass, + const AbstractMetaClassCPtr &metaClass, QString *errorString) { if (!metaClass) return {}; - auto cType = static_cast<const ComplexTypeEntry *>(metaClass->typeEntry()); + auto cType = std::static_pointer_cast<const ComplexTypeEntry>(metaClass->typeEntry()); if (cType->hasDefaultConstructor()) return DefaultValue(DefaultValue::Custom, cType->defaultConstructor()); @@ -701,27 +500,27 @@ std::optional<DefaultValue> const auto &constructors = metaClass->queryFunctions(FunctionQueryOption::Constructors); for (const auto &ctor : constructors) { if (!ctor->isUserAdded() && !ctor->isPrivate() - && ctor->functionType() == AbstractMetaFunction::ConstructorFunction) { + && (ctor->isPublic() || !api.flags().testFlag(ApiExtractorFlag::AvoidProtectedHack))) { // No arguments: Default constructible const auto &arguments = ctor->arguments(); if (arguments.isEmpty()) { return DefaultValue(DefaultValue::DefaultConstructor, - QLatin1String("::") + qualifiedCppName); + u"::"_s + qualifiedCppName); } // First argument has unmodified default: Default constructible with values if (arguments.constFirst().hasUnmodifiedDefaultValueExpression()) { return DefaultValue(DefaultValue::DefaultConstructorWithDefaultValues, - QLatin1String("::") + qualifiedCppName); + u"::"_s + qualifiedCppName); } // Examine arguments, exclude functions taking a self parameter bool simple = true; bool suitable = true; - for (int i = 0, size = arguments.size(); + for (qsizetype i = 0, size = arguments.size(); suitable && i < size && !arguments.at(i).hasOriginalDefaultValueExpression(); ++i) { const AbstractMetaArgument &arg = arguments.at(i); - const TypeEntry *aType = arg.type().typeEntry(); + TypeEntryCPtr aType = arg.type().typeEntry(); suitable &= aType != cType; - simple &= aType->isCppPrimitive() || aType->isEnum() || arg.type().isPointer(); + simple &= isCppPrimitive(aType) || aType->isEnum() || arg.type().isPointer(); } if (suitable) candidates.insert(arguments.size() + (simple ? 0 : 100), ctor); @@ -731,8 +530,7 @@ std::optional<DefaultValue> for (auto it = candidates.cbegin(), end = candidates.cend(); it != end; ++it) { const AbstractMetaArgumentList &arguments = it.value()->arguments(); QStringList args; - for (int i = 0, size = arguments.size(); i < size; ++i) { - const AbstractMetaArgument &arg = arguments.at(i); + for (const auto &arg : arguments) { if (arg.hasModifiedDefaultValueExpression()) { args << arg.defaultValueExpression(); // Spell out modified values break; @@ -751,7 +549,7 @@ std::optional<DefaultValue> } QString Generator::translateType(AbstractMetaType cType, - const AbstractMetaClass *context, + const AbstractMetaClassCPtr &context, Options options) const { QString s; @@ -763,94 +561,141 @@ QString Generator::translateType(AbstractMetaType cType, } if (cType.isVoid()) { - s = QLatin1String("void"); + s = u"void"_s; } else if (cType.isArray()) { - s = translateType(*cType.arrayElementType(), context, options) + QLatin1String("[]"); + s = translateType(*cType.arrayElementType(), context, options) + u"[]"_s; } else { + AbstractMetaType copyType = cType; if (options & Generator::ExcludeConst || options & Generator::ExcludeReference) { - AbstractMetaType copyType = cType; - if (options & Generator::ExcludeConst) copyType.setConstant(false); - if (options & Generator::ExcludeReference) copyType.setReferenceType(NoReference); + } - s = copyType.cppSignature(); - if (!copyType.typeEntry()->isVoid() && !copyType.typeEntry()->isCppPrimitive()) - s.prepend(QLatin1String("::")); - } else { - s = cType.cppSignature(); + s = copyType.cppSignature(); + const auto te = copyType.typeEntry(); + if (!te->isVoid() && !isCppPrimitive(te)) { // Add scope resolution + const auto pos = s.indexOf(te->qualifiedCppName()); // Skip const/volatile + Q_ASSERT(pos >= 0); + s.insert(pos, u"::"_s); } } return s; } +static const QHash<QString, QString> &pythonOperators() +{ + static const QHash<QString, QString> result = { + // call operator + {u"operator()"_s, u"__call__"_s}, + // Arithmetic operators + {u"operator+"_s, u"__add__"_s}, + {u"operator-"_s, u"__sub__"_s}, + {u"operator*"_s, u"__mul__"_s}, + {u"operator/"_s, u"__div__"_s}, + {u"operator%"_s, u"__mod__"_s}, + // Inplace arithmetic operators + {u"operator+="_s, u"__iadd__"_s}, + {u"operator-="_s, u"__isub__"_s}, + {u"operator++"_s, u"__iadd__"_s}, + {u"operator--"_s, u"__isub__"_s}, + {u"operator*="_s, u"__imul__"_s}, + {u"operator%="_s, u"__imod__"_s}, + // Bitwise operators + {u"operator&"_s, u"__and__"_s}, + {u"operator^"_s, u"__xor__"_s}, + {u"operator|"_s, u"__or__"_s}, + {u"operator<<"_s, u"__lshift__"_s}, + {u"operator>>"_s, u"__rshift__"_s}, + {u"operator~"_s, u"__invert__"_s}, + // Inplace bitwise operators + {u"operator&="_s, u"__iand__"_s}, + {u"operator^="_s, u"__ixor__"_s}, + {u"operator|="_s, u"__ior__"_s}, + {u"operator<<="_s, u"__ilshift__"_s}, + {u"operator>>="_s, u"__irshift__"_s}, + // Comparison operators + {u"operator=="_s, u"__eq__"_s}, + {u"operator!="_s, u"__ne__"_s}, + {u"operator<"_s, u"__lt__"_s}, + {u"operator>"_s, u"__gt__"_s}, + {u"operator<="_s, u"__le__"_s}, + {u"operator>="_s, u"__ge__"_s}, + // Conversion (note bool has special handling with heuristics) + {u"operator int"_s, u"__int__"_s}, + {u"operator double"_s, u"__float__"_s} + }; + return result; +} + +QString Generator::pythonOperatorFunctionName(const QString &cppOpFuncName) +{ + return pythonOperators().value(cppOpFuncName); +} -QString Generator::subDirectoryForClass(const AbstractMetaClass *clazz) const +bool Generator::isPythonOperatorFunctionName(const QString &cppOpFuncName) { - return subDirectoryForPackage(clazz->package()); + return pythonOperators().contains(cppOpFuncName); } QString Generator::subDirectoryForPackage(QString packageNameIn) const { if (packageNameIn.isEmpty()) packageNameIn = packageName(); - packageNameIn.replace(QLatin1Char('.'), QDir::separator()); + packageNameIn.replace(u'.', QDir::separator()); return packageNameIn; } +QString Generator::addGlobalScopePrefix(const QString &t) +{ + return t.startsWith("std::"_L1) ? t : m_gsp + t; +} + +QString Generator::globalScopePrefix(const GeneratorContext &classContext) +{ + return classContext.useWrapper() ? QString{} : m_gsp; +} + template<typename T> -static QString getClassTargetFullName_(const T *t, bool includePackageName) +static QString getClassTargetFullName_(T t, bool includePackageName) { QString name = t->name(); - const AbstractMetaClass *context = t->enclosingClass(); + AbstractMetaClassCPtr context = t->enclosingClass(); while (context) { // If the type was marked as 'visible=false' we should not use it in // the type name if (NamespaceTypeEntry::isVisibleScope(context->typeEntry())) { - name.prepend(QLatin1Char('.')); + name.prepend(u'.'); name.prepend(context->name()); } context = context->enclosingClass(); } if (includePackageName) { - name.prepend(QLatin1Char('.')); + name.prepend(u'.'); name.prepend(t->package()); } return name; } -QString getClassTargetFullName(const AbstractMetaClass *metaClass, bool includePackageName) +QString getClassTargetFullName(const AbstractMetaClassCPtr &metaClass, + bool includePackageName) { return getClassTargetFullName_(metaClass, includePackageName); } -QString getClassTargetFullName(const AbstractMetaEnum &metaEnum, bool includePackageName) +QString getClassTargetFullName(const AbstractMetaEnum &metaEnum, + bool includePackageName) { return getClassTargetFullName_(&metaEnum, includePackageName); } -QString getClassTargetFullName(const AbstractMetaType &metaType, bool includePackageName) -{ - QString name = metaType.cppSignature(); - name.replace(QLatin1String("::"), QLatin1String("_")); - name.replace(QLatin1Char('<'), QLatin1Char('_')); - name.remove(QLatin1Char('>')); - name.remove(QLatin1Char(' ')); - if (includePackageName) { - name.prepend(QLatin1Char('.')); - name.prepend(metaType.package()); - } - return name; -} - QString getFilteredCppSignatureString(QString signature) { - signature.replace(QLatin1String("::"), QLatin1String("_")); - signature.replace(QLatin1Char('<'), QLatin1Char('_')); - signature.replace(QLatin1Char('>'), QLatin1Char('_')); - signature.replace(QLatin1Char(' '), QLatin1Char('_')); + signature.replace(u"::"_s, u"_"_s); + signature.replace(u'<', u'_'); + signature.replace(u'>', u'_'); + signature.replace(u' ', u'_'); return signature; } |