aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/generator/generator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2/generator/generator.cpp')
-rw-r--r--sources/shiboken2/generator/generator.cpp413
1 files changed, 241 insertions, 172 deletions
diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp
index 1e2f03932..ec227bd83 100644
--- a/sources/shiboken2/generator/generator.cpp
+++ b/sources/shiboken2/generator/generator.cpp
@@ -28,6 +28,7 @@
#include "generator.h"
#include "abstractmetalang.h"
+#include "messages.h"
#include "reporthandler.h"
#include "fileout.h"
#include "apiextractor.h"
@@ -40,8 +41,118 @@
#include <QDebug>
#include <typedatabase.h>
-struct Generator::GeneratorPrivate {
- const ApiExtractor* apiextractor;
+/**
+ * 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::Error:
+ return QLatin1String("#error");
+ 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::Error:
+ return QLatin1String("#error");
+ 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::Error:
+ return QLatin1String("#error");
+ 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("()");
+}
+
+struct Generator::GeneratorPrivate
+{
+ const ApiExtractor* apiextractor = nullptr;
QString outDir;
// License comment
QString licenseComment;
@@ -62,20 +173,17 @@ Generator::~Generator()
delete m_d;
}
-bool Generator::setup(const ApiExtractor& extractor, const QMap< QString, QString > args)
+bool Generator::setup(const ApiExtractor& extractor)
{
m_d->apiextractor = &extractor;
- TypeEntryHash allEntries = TypeDatabase::instance()->allEntries();
+ const auto &allEntries = TypeDatabase::instance()->entries();
TypeEntry* entryFound = 0;
- for (TypeEntryHash::const_iterator it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) {
- for (TypeEntry *entry : it.value()) {
- if (entry->type() == TypeEntry::TypeSystemType && entry->generateCode()) {
- entryFound = entry;
- break;
- }
- }
- if (entryFound)
+ for (auto it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) {
+ TypeEntry *entry = it.value();
+ if (entry->type() == TypeEntry::TypeSystemType && entry->generateCode()) {
+ entryFound = entry;
break;
+ }
}
if (entryFound)
m_d->packageName = entryFound->name();
@@ -84,7 +192,7 @@ bool Generator::setup(const ApiExtractor& extractor, const QMap< QString, QStrin
collectInstantiatedContainersAndSmartPointers();
- return doSetup(args);
+ return doSetup();
}
QString Generator::getSimplifiedContainerTypeName(const AbstractMetaType* type)
@@ -197,6 +305,11 @@ Generator::OptionDescriptions Generator::options() const
return OptionDescriptions();
}
+bool Generator::handleOption(const QString & /* key */, const QString & /* value */)
+{
+ return false;
+}
+
AbstractMetaClassList Generator::classes() const
{
return m_d->apiextractor->classes();
@@ -227,24 +340,14 @@ ContainerTypeEntryList Generator::containerTypes() const
return m_d->apiextractor->containerTypes();
}
-const AbstractMetaEnum* Generator::findAbstractMetaEnum(const EnumTypeEntry* typeEntry) const
-{
- return m_d->apiextractor->findAbstractMetaEnum(typeEntry);
-}
-
const AbstractMetaEnum* Generator::findAbstractMetaEnum(const TypeEntry* typeEntry) const
{
return m_d->apiextractor->findAbstractMetaEnum(typeEntry);
}
-const AbstractMetaEnum* Generator::findAbstractMetaEnum(const FlagsTypeEntry* typeEntry) const
-{
- return m_d->apiextractor->findAbstractMetaEnum(typeEntry);
-}
-
const AbstractMetaEnum* Generator::findAbstractMetaEnum(const AbstractMetaType* metaType) const
{
- return m_d->apiextractor->findAbstractMetaEnum(metaType);
+ return m_d->apiextractor->findAbstractMetaEnum(metaType->typeEntry());
}
QString Generator::licenseComment() const
@@ -278,21 +381,6 @@ void Generator::setOutputDirectory(const QString &outDir)
m_d->outDir = outDir;
}
-inline void touchFile(const QString &filePath)
-{
- QFile toucher(filePath);
- qint64 size = toucher.size();
- if (!toucher.open(QIODevice::ReadWrite)) {
- qCWarning(lcShiboken).noquote().nospace()
- << QStringLiteral("Failed to touch file '%1'")
- .arg(QDir::toNativeSeparators(filePath));
- return;
- }
- toucher.resize(size+1);
- toucher.resize(size);
- toucher.close();
-}
-
bool Generator::generateFileForContext(GeneratorContext &context)
{
AbstractMetaClass *cls = context.metaClass();
@@ -312,20 +400,7 @@ bool Generator::generateFileForContext(GeneratorContext &context)
generateClass(fileOut.stream, context);
- FileOut::State state = fileOut.done();
- switch (state) {
- case FileOut::Failure:
- return false;
- case FileOut::Unchanged:
- // Even if contents is unchanged, the last file modification time should be updated,
- // so that the build system can rely on the fact the generated file is up-to-date.
- touchFile(filePath);
- break;
- case FileOut::Success:
- break;
- }
-
- return true;
+ return fileOut.done() != FileOut::Failure;
}
QString Generator::getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType,
@@ -369,9 +444,9 @@ bool Generator::shouldGenerate(const AbstractMetaClass* metaClass) const
return shouldGenerateTypeEntry(metaClass->typeEntry());
}
-void verifyDirectoryFor(const QFile &file)
+void verifyDirectoryFor(const QString &file)
{
- QDir dir = QFileInfo(file).dir();
+ QDir dir = QFileInfo(file).absoluteDir();
if (!dir.exists()) {
if (!dir.mkpath(dir.absolutePath())) {
qCWarning(lcShiboken).noquote().nospace()
@@ -463,7 +538,7 @@ AbstractMetaFunctionList Generator::implicitConversions(const AbstractMetaType*
bool Generator::isObjectType(const TypeEntry* type)
{
if (type->isComplex())
- return Generator::isObjectType((const ComplexTypeEntry*)type);
+ return Generator::isObjectType(static_cast<const ComplexTypeEntry *>(type));
return type->isObject();
}
bool Generator::isObjectType(const ComplexTypeEntry* type)
@@ -557,184 +632,178 @@ QString Generator::getFullTypeNameWithoutModifiers(const AbstractMetaType* type)
return QLatin1String("::") + typeName;
}
-QString Generator::minimalConstructor(const AbstractMetaType* type) const
+DefaultValue Generator::minimalConstructor(const AbstractMetaType* type) const
{
if (!type || (type->referenceType() == LValueReference && Generator::isObjectType(type)))
- return QString();
+ return DefaultValue(DefaultValue::Error);
if (type->isContainer()) {
QString ctor = type->cppSignature();
- if (ctor.endsWith(QLatin1Char('*')))
- return QLatin1String("0");
+ if (ctor.endsWith(QLatin1Char('*'))) {
+ ctor.chop(1);
+ return DefaultValue(DefaultValue::Pointer, ctor.trimmed());
+ }
if (ctor.startsWith(QLatin1String("const ")))
ctor.remove(0, sizeof("const ") / sizeof(char) - 1);
if (ctor.endsWith(QLatin1Char('&'))) {
ctor.chop(1);
ctor = ctor.trimmed();
}
- return QLatin1String("::") + ctor + QLatin1String("()");
+ return DefaultValue(DefaultValue::DefaultConstructor, QLatin1String("::") + ctor);
}
if (type->isNativePointer())
- return QLatin1String("static_cast<") + type->typeEntry()->qualifiedCppName() + QLatin1String(" *>(0)");
+ return DefaultValue(DefaultValue::Pointer, type->typeEntry()->qualifiedCppName());
if (Generator::isPointer(type))
- return QLatin1String("static_cast< ::") + type->typeEntry()->qualifiedCppName() + QLatin1String(" *>(0)");
+ return DefaultValue(DefaultValue::Pointer, QLatin1String("::") + type->typeEntry()->qualifiedCppName());
if (type->typeEntry()->isComplex()) {
- const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(type->typeEntry());
- QString ctor = cType->defaultConstructor();
- if (!ctor.isEmpty())
- return ctor;
- ctor = minimalConstructor(AbstractMetaClass::findClass(classes(), cType));
- if (type->hasInstantiations())
- ctor = ctor.replace(getFullTypeName(cType), getFullTypeNameWithoutModifiers(type));
+ const ComplexTypeEntry* cType = static_cast<const ComplexTypeEntry*>(type->typeEntry());
+ if (cType->hasDefaultConstructor())
+ return DefaultValue(DefaultValue::Custom, cType->defaultConstructor());
+ auto ctor = minimalConstructor(AbstractMetaClass::findClass(classes(), cType));
+ if (ctor.isValid() && type->hasInstantiations()) {
+ QString v = ctor.value();
+ v.replace(getFullTypeName(cType), getFullTypeNameWithoutModifiers(type));
+ ctor.setValue(v);
+ }
return ctor;
}
return minimalConstructor(type->typeEntry());
}
-QString Generator::minimalConstructor(const TypeEntry* type) const
+DefaultValue Generator::minimalConstructor(const TypeEntry* type) const
{
if (!type)
- return QString();
+ return DefaultValue(DefaultValue::Error);
if (type->isCppPrimitive()) {
const QString &name = type->qualifiedCppName();
return name == QLatin1String("bool")
- ? QLatin1String("false") : name + QLatin1String("(0)");
+ ? DefaultValue(DefaultValue::Boolean)
+ : DefaultValue(DefaultValue::CppScalar, name);
}
- if (type->isEnum())
- return QLatin1String("static_cast< ::") + type->qualifiedCppName() + QLatin1String(">(0)");
+ if (type->isEnum()) {
+ const auto enumEntry = static_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)"));
+ }
- if (type->isFlags())
- return type->qualifiedCppName() + QLatin1String("(0)");
+ if (type->isFlags()) {
+ return DefaultValue(DefaultValue::Custom,
+ type->qualifiedCppName() + QLatin1String("(0)"));
+ }
if (type->isPrimitive()) {
- QString ctor = reinterpret_cast<const PrimitiveTypeEntry*>(type)->defaultConstructor();
+ QString ctor = static_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()
- ? (QLatin1String("::") + type->qualifiedCppName() + QLatin1String("()"))
- : ctor;
+ ? DefaultValue(DefaultValue::DefaultConstructorWithDefaultValues, QLatin1String("::")
+ + type->qualifiedCppName())
+ : DefaultValue(DefaultValue::Custom, ctor);
}
if (type->isComplex())
return minimalConstructor(AbstractMetaClass::findClass(classes(), type));
- return QString();
+ return DefaultValue(DefaultValue::Error);
}
-QString Generator::minimalConstructor(const AbstractMetaClass* metaClass) const
+static QString constructorCall(const QString &qualifiedCppName, const QStringList &args)
+{
+ return QLatin1String("::") + qualifiedCppName + QLatin1Char('(')
+ + args.join(QLatin1String(", ")) + QLatin1Char(')');
+}
+
+DefaultValue Generator::minimalConstructor(const AbstractMetaClass* metaClass) const
{
if (!metaClass)
- return QString();
+ return DefaultValue(DefaultValue::Error);
- const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(metaClass->typeEntry());
+ const ComplexTypeEntry* cType = static_cast<const ComplexTypeEntry*>(metaClass->typeEntry());
if (cType->hasDefaultConstructor())
- return cType->defaultConstructor();
+ return DefaultValue(DefaultValue::Custom, cType->defaultConstructor());
+ const QString qualifiedCppName = cType->qualifiedCppName();
+ // Obtain a list of constructors sorted by complexity and number of arguments
+ QMultiMap<int, const AbstractMetaFunction *> candidates;
const AbstractMetaFunctionList &constructors = metaClass->queryFunctions(AbstractMetaClass::Constructors);
- int maxArgs = 0;
for (const AbstractMetaFunction *ctor : constructors) {
- if (ctor->isUserAdded() || ctor->isPrivate() || ctor->functionType() != AbstractMetaFunction::ConstructorFunction)
- continue;
-
- int numArgs = ctor->arguments().size();
- if (numArgs == 0) {
- maxArgs = 0;
- break;
- }
- if (numArgs > maxArgs)
- maxArgs = numArgs;
- }
-
- QString qualifiedCppName = metaClass->typeEntry()->qualifiedCppName();
- QStringList templateTypes;
- const QVector<TypeEntry *> &templateArguments = metaClass->templateArguments();
- for (TypeEntry *templateType : templateArguments)
- templateTypes << templateType->qualifiedCppName();
-
- // Empty constructor.
- if (maxArgs == 0)
- return QLatin1String("::") + qualifiedCppName + QLatin1String("()");
-
- QVector<const AbstractMetaFunction *> candidates;
-
- // Constructors with C++ primitive types, enums or pointers only.
- // Start with the ones with fewer arguments.
- for (int i = 1; i <= maxArgs; ++i) {
- for (const AbstractMetaFunction *ctor : constructors) {
- if (ctor->isUserAdded() || ctor->isPrivate() || ctor->functionType() != AbstractMetaFunction::ConstructorFunction)
- continue;
-
- const AbstractMetaArgumentList &arguments = ctor->arguments();
- if (arguments.size() != i)
- continue;
-
- QStringList args;
- for (const AbstractMetaArgument *arg : arguments) {
- const TypeEntry* type = arg->type()->typeEntry();
- if (type == metaClass->typeEntry()) {
- args.clear();
- break;
- }
-
- if (!arg->originalDefaultValueExpression().isEmpty()) {
- if (!arg->defaultValueExpression().isEmpty()
- && arg->defaultValueExpression() != arg->originalDefaultValueExpression()) {
- args << arg->defaultValueExpression();
- }
- break;
- }
-
- if (type->isCppPrimitive() || type->isEnum() || isPointer(arg->type())) {
- QString argValue = minimalConstructor(arg->type());
- if (argValue.isEmpty()) {
- args.clear();
- break;
- }
- args << argValue;
- } else {
- args.clear();
- break;
- }
+ if (!ctor->isUserAdded() && !ctor->isPrivate()
+ && ctor->functionType() == AbstractMetaFunction::ConstructorFunction) {
+ // No arguments: Default constructible
+ const auto &arguments = ctor->arguments();
+ if (arguments.isEmpty()) {
+ return DefaultValue(DefaultValue::DefaultConstructor,
+ QLatin1String("::") + qualifiedCppName);
}
-
- if (!args.isEmpty())
- return QString::fromLatin1("::%1(%2)").arg(qualifiedCppName, args.join(QLatin1String(", ")));
-
- candidates << ctor;
+ // First argument has unmodified default: Default constructible with values
+ if (arguments.constFirst()->hasUnmodifiedDefaultValueExpression()) {
+ return DefaultValue(DefaultValue::DefaultConstructorWithDefaultValues,
+ QLatin1String("::") + qualifiedCppName);
+ }
+ // Examine arguments, exclude functions taking a self parameter
+ bool simple = true;
+ bool suitable = true;
+ for (int i = 0, size = arguments.size();
+ suitable && i < size && !arguments.at(i)->hasDefaultValueExpression(); ++i) {
+ const AbstractMetaArgument *arg = arguments.at(i);
+ const TypeEntry *aType = arg->type()->typeEntry();
+ suitable &= aType != cType;
+ simple &= aType->isCppPrimitive() || aType->isEnum() || isPointer(arg->type());
+ }
+ if (suitable)
+ candidates.insert(arguments.size() + (simple ? 0 : 100), ctor);
}
}
- // Constructors with C++ primitive types, enums, pointers, value types,
- // and user defined primitive types.
- // Builds the minimal constructor recursively.
- for (const AbstractMetaFunction *ctor : qAsConst(candidates)) {
+ for (auto it = candidates.cbegin(), end = candidates.cend(); it != end; ++it) {
+ const AbstractMetaArgumentList &arguments = it.value()->arguments();
QStringList args;
- const AbstractMetaArgumentList &arguments = ctor->arguments();
- for (const AbstractMetaArgument *arg : arguments) {
- if (arg->type()->typeEntry() == metaClass->typeEntry()) {
- args.clear();
- break;
- }
- QString argValue = minimalConstructor(arg->type());
- if (argValue.isEmpty()) {
- args.clear();
+ bool ok = true;
+ for (int i =0, size = arguments.size(); ok && i < size; ++i) {
+ const AbstractMetaArgument *arg = arguments.at(i);
+ if (arg->hasDefaultValueExpression()) {
+ if (arg->hasModifiedDefaultValueExpression())
+ args << arg->defaultValueExpression(); // Spell out modified values
break;
}
- args << argValue;
- }
- if (!args.isEmpty()) {
- return QString::fromLatin1("::%1(%2)").arg(qualifiedCppName, args.join(QLatin1String(", ")));
+ auto argValue = minimalConstructor(arg->type());
+ ok &= argValue.isValid();
+ args << argValue.constructorParameter();
}
+ if (ok)
+ return DefaultValue(DefaultValue::Custom, constructorCall(qualifiedCppName, args));
}
- return QString();
+ return DefaultValue(DefaultValue::Error);
+}
+
+// Should int be used for a (protected) enum when generating the public wrapper?
+bool Generator::useEnumAsIntForProtectedHack(const AbstractMetaType *metaType) const
+{
+ if (metaType->isFlags())
+ return true;
+ if (!metaType->isEnum())
+ return false;
+ const AbstractMetaEnum *metaEnum = findAbstractMetaEnum(metaType);
+ if (!metaEnum)
+ return true;
+ if (metaEnum->attributes() & AbstractMetaAttributes::Public) // No reason, type is public
+ return false;
+ // Only ordinary C-enums can be used as int, scoped enums fail when used
+ // as function arguments.
+ if (metaEnum->enumKind() == EnumKind::EnumClass)
+ qWarning(lcShiboken, "%s", qPrintable(msgCannotUseEnumAsInt(metaEnum->name())));
+ return true;
}
QString Generator::translateType(const AbstractMetaType *cType,
@@ -754,7 +823,7 @@ QString Generator::translateType(const AbstractMetaType *cType,
s = QLatin1String("void");
} else if (cType->isArray()) {
s = translateType(cType->arrayElementType(), context, options) + QLatin1String("[]");
- } else if (options & Generator::EnumAsInts && (cType->isEnum() || cType->isFlags())) {
+ } else if ((options & Generator::EnumAsInts) && useEnumAsIntForProtectedHack(cType)) {
s = QLatin1String("int");
} else {
if (options & Generator::OriginalName) {