aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/generator/generator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6/generator/generator.cpp')
-rw-r--r--sources/shiboken6/generator/generator.cpp649
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;
}