aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/generator/generator.cpp
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-05-22 17:50:30 +0200
committerOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-05-22 18:20:59 +0200
commit9c333ade1a1b694fc6ce22e483f5de3e952c17ad (patch)
treed3a2e41de3501f91ebfdc8ec81a80156597c2585 /sources/shiboken2/generator/generator.cpp
parent8f3761d8eac7780393382ab54dbdb487eb4df027 (diff)
move everying into sources/shiboken2 (5.9 edition)
in preparation for a subtree merge. this should not be necessary to do in a separate commit, but git is a tad stupid about following history correctly without it.
Diffstat (limited to 'sources/shiboken2/generator/generator.cpp')
-rw-r--r--sources/shiboken2/generator/generator.cpp864
1 files changed, 864 insertions, 0 deletions
diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp
new file mode 100644
index 000000000..76d104c12
--- /dev/null
+++ b/sources/shiboken2/generator/generator.cpp
@@ -0,0 +1,864 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $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 "generator.h"
+#include "abstractmetalang.h"
+#include "reporthandler.h"
+#include "fileout.h"
+#include "apiextractor.h"
+#include "typesystem.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QRegularExpression>
+#include <QDebug>
+#include <typedatabase.h>
+
+struct Generator::GeneratorPrivate {
+ const ApiExtractor* apiextractor;
+ QString outDir;
+ // License comment
+ QString licenseComment;
+ QString packageName;
+ int numGenerated;
+ QStringList instantiatedContainersNames;
+ QStringList instantiatedSmartPointerNames;
+ QVector<const AbstractMetaType *> instantiatedContainers;
+ QVector<const AbstractMetaType *> instantiatedSmartPointers;
+
+};
+
+Generator::Generator() : m_d(new GeneratorPrivate)
+{
+ m_d->numGenerated = 0;
+}
+
+Generator::~Generator()
+{
+ delete m_d;
+}
+
+bool Generator::setup(const ApiExtractor& extractor, const QMap< QString, QString > args)
+{
+ m_d->apiextractor = &extractor;
+ TypeEntryHash allEntries = TypeDatabase::instance()->allEntries();
+ 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)
+ break;
+ }
+ if (entryFound)
+ m_d->packageName = entryFound->name();
+ else
+ qCWarning(lcShiboken) << "Couldn't find the package name!!";
+
+ collectInstantiatedContainersAndSmartPointers();
+
+ return doSetup(args);
+}
+
+QString Generator::getSimplifiedContainerTypeName(const AbstractMetaType* type)
+{
+ 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;
+}
+
+void Generator::addInstantiatedContainersAndSmartPointers(const AbstractMetaType *type,
+ const QString &context)
+{
+ if (!type)
+ return;
+ const AbstractMetaTypeList &instantiations = type->instantiations();
+ for (const AbstractMetaType* t : instantiations)
+ addInstantiatedContainersAndSmartPointers(t, context);
+ if (!type->typeEntry()->isContainer() && !type->typeEntry()->isSmartPointer())
+ return;
+ bool isContainer = type->typeEntry()->isContainer();
+ 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).arg(type->originalTypeDescription());
+ if (!context.isEmpty())
+ warning.append(QStringLiteral(" Calling context: %1").arg(context));
+
+ qCWarning(lcShiboken).noquote().nospace() << warning;
+ return;
+
+ }
+ QString typeName = getSimplifiedContainerTypeName(type);
+ if (isContainer) {
+ if (!m_d->instantiatedContainersNames.contains(typeName)) {
+ m_d->instantiatedContainersNames.append(typeName);
+ m_d->instantiatedContainers.append(type);
+ }
+ } else {
+ // Is smart pointer.
+ if (!m_d->instantiatedSmartPointerNames.contains(typeName)) {
+ m_d->instantiatedSmartPointerNames.append(typeName);
+ m_d->instantiatedSmartPointers.append(type);
+ }
+ }
+
+}
+
+void Generator::collectInstantiatedContainersAndSmartPointers(const AbstractMetaFunction *func)
+{
+ addInstantiatedContainersAndSmartPointers(func->type(), func->signature());
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument *arg : arguments)
+ addInstantiatedContainersAndSmartPointers(arg->type(), func->signature());
+}
+
+void Generator::collectInstantiatedContainersAndSmartPointers(const AbstractMetaClass *metaClass)
+{
+ if (!metaClass->typeEntry()->generateCode())
+ return;
+ const AbstractMetaFunctionList &funcs = metaClass->functions();
+ for (const AbstractMetaFunction *func : funcs)
+ collectInstantiatedContainersAndSmartPointers(func);
+ const AbstractMetaFieldList &fields = metaClass->fields();
+ for (const AbstractMetaField *field : fields)
+ addInstantiatedContainersAndSmartPointers(field->type(), field->name());
+ const AbstractMetaClassList &innerClasses = metaClass->innerClasses();
+ for (AbstractMetaClass *innerClass : innerClasses)
+ collectInstantiatedContainersAndSmartPointers(innerClass);
+}
+
+void Generator::collectInstantiatedContainersAndSmartPointers()
+{
+ const AbstractMetaFunctionList &funcs = globalFunctions();
+ for (const AbstractMetaFunction *func : funcs)
+ collectInstantiatedContainersAndSmartPointers(func);
+ const AbstractMetaClassList &classList = classes();
+ for (const AbstractMetaClass *metaClass : classList)
+ collectInstantiatedContainersAndSmartPointers(metaClass);
+}
+
+QVector<const AbstractMetaType *> Generator::instantiatedContainers() const
+{
+ return m_d->instantiatedContainers;
+}
+
+QVector<const AbstractMetaType*> Generator::instantiatedSmartPointers() const
+{
+ return m_d->instantiatedSmartPointers;
+}
+
+QMap< QString, QString > Generator::options() const
+{
+ return QMap<QString, QString>();
+}
+
+AbstractMetaClassList Generator::classes() const
+{
+ return m_d->apiextractor->classes();
+}
+
+AbstractMetaClassList Generator::classesTopologicalSorted(const Dependencies &additionalDependencies) const
+{
+ return m_d->apiextractor->classesTopologicalSorted(additionalDependencies);
+}
+
+AbstractMetaFunctionList Generator::globalFunctions() const
+{
+ return m_d->apiextractor->globalFunctions();
+}
+
+AbstractMetaEnumList Generator::globalEnums() const
+{
+ return m_d->apiextractor->globalEnums();
+}
+
+PrimitiveTypeEntryList Generator::primitiveTypes() const
+{
+ return m_d->apiextractor->primitiveTypes();
+}
+
+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);
+}
+
+QSet< QString > Generator::qtMetaTypeDeclaredTypeNames() const
+{
+ return m_d->apiextractor->qtMetaTypeDeclaredTypeNames();
+}
+
+QString Generator::licenseComment() const
+{
+ return m_d->licenseComment;
+}
+
+void Generator::setLicenseComment(const QString& licenseComment)
+{
+ m_d->licenseComment = licenseComment;
+}
+
+QString Generator::packageName() const
+{
+ return m_d->packageName;
+}
+
+QString Generator::moduleName() const
+{
+ QString& pkgName = m_d->packageName;
+ return QString(pkgName).remove(0, pkgName.lastIndexOf(QLatin1Char('.')) + 1);
+}
+
+QString Generator::outputDirectory() const
+{
+ return m_d->outDir;
+}
+
+void Generator::setOutputDirectory(const QString &outDir)
+{
+ m_d->outDir = outDir;
+}
+
+int Generator::numGenerated() const
+{
+ return m_d->numGenerated;
+}
+
+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();
+
+ if (!shouldGenerate(cls))
+ return true;
+
+ const QString fileName = fileNameForContext(context);
+ if (fileName.isEmpty())
+ return true;
+ if (ReportHandler::isDebug(ReportHandler::SparseDebug))
+ qCDebug(lcShiboken) << "generating: " << fileName;
+
+ QString filePath = outputDirectory() + QLatin1Char('/') + subDirectoryForClass(cls)
+ + QLatin1Char('/') + fileName;
+ FileOut fileOut(filePath);
+
+ 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;
+ }
+
+ ++m_d->numGenerated;
+ return true;
+}
+
+QString Generator::getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType,
+ const AbstractMetaClass *smartPointerClass) const
+{
+ const AbstractMetaType *innerType = smartPointerType->getSmartPointerInnerType();
+ QString fileName = smartPointerClass->qualifiedCppName().toLower();
+ fileName.replace(QLatin1String("::"), QLatin1String("_"));
+ fileName.append(QLatin1String("_"));
+ fileName.append(innerType->name().toLower());
+
+ return fileName;
+}
+
+bool Generator::generate()
+{
+ const AbstractMetaClassList &classList = m_d->apiextractor->classes();
+ for (AbstractMetaClass *cls : classList) {
+ GeneratorContext context(cls);
+ if (!generateFileForContext(context))
+ return false;
+ }
+
+ for (const AbstractMetaType *type : qAsConst(m_d->instantiatedSmartPointers)) {
+ AbstractMetaClass *smartPointerClass =
+ AbstractMetaClass::findClass(m_d->apiextractor->smartPointers(), type->name());
+ GeneratorContext context(smartPointerClass, type, true);
+ if (!generateFileForContext(context))
+ return false;
+ }
+ return finishGeneration();
+}
+
+bool Generator::shouldGenerateTypeEntry(const TypeEntry* type) const
+{
+ return type->codeGeneration() & TypeEntry::GenerateTargetLang;
+}
+
+bool Generator::shouldGenerate(const AbstractMetaClass* metaClass) const
+{
+ return shouldGenerateTypeEntry(metaClass->typeEntry());
+}
+
+void verifyDirectoryFor(const QFile &file)
+{
+ QDir dir = QFileInfo(file).dir();
+ if (!dir.exists()) {
+ if (!dir.mkpath(dir.absolutePath())) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("unable to create directory '%1'").arg(dir.absolutePath());
+ }
+ }
+}
+
+void Generator::replaceTemplateVariables(QString &code, const AbstractMetaFunction *func)
+{
+ const AbstractMetaClass *cpp_class = func->ownerClass();
+ if (cpp_class)
+ code.replace(QLatin1String("%TYPE"), cpp_class->name());
+
+ const AbstractMetaArgumentList &argument = func->arguments();
+ for (AbstractMetaArgument *arg : argument)
+ code.replace(QLatin1Char('%') + QString::number(arg->argumentIndex() + 1), arg->name());
+
+ //template values
+ code.replace(QLatin1String("%RETURN_TYPE"), translateType(func->type(), cpp_class));
+ code.replace(QLatin1String("%FUNCTION_NAME"), func->originalName());
+
+ if (code.contains(QLatin1String("%ARGUMENT_NAMES"))) {
+ QString str;
+ QTextStream aux_stream(&str);
+ writeArgumentNames(aux_stream, func, Generator::SkipRemovedArguments);
+ code.replace(QLatin1String("%ARGUMENT_NAMES"), str);
+ }
+
+ if (code.contains(QLatin1String("%ARGUMENTS"))) {
+ QString str;
+ QTextStream aux_stream(&str);
+ writeFunctionArguments(aux_stream, func, Options(SkipDefaultValues) | SkipRemovedArguments);
+ code.replace(QLatin1String("%ARGUMENTS"), str);
+ }
+}
+
+QTextStream& formatCode(QTextStream &s, const QString& code, Indentor &indentor)
+{
+ // detect number of spaces before the first character
+ const QStringList lst(code.split(QLatin1Char('\n')));
+ static const QRegularExpression nonSpaceRegex(QStringLiteral("[^\\s]"));
+ Q_ASSERT(nonSpaceRegex.isValid());
+ int spacesToRemove = 0;
+ for (const QString &line : lst) {
+ if (!line.trimmed().isEmpty()) {
+ spacesToRemove = line.indexOf(nonSpaceRegex);
+ if (spacesToRemove == -1)
+ spacesToRemove = 0;
+ break;
+ }
+ }
+
+ static const QRegularExpression emptyLine(QStringLiteral("^\\s*[\\r]?[\\n]?\\s*$"));
+ Q_ASSERT(emptyLine.isValid());
+
+ for (QString line : lst) {
+ if (!line.isEmpty() && !emptyLine.match(line).hasMatch()) {
+ while (line.end()->isSpace())
+ line.chop(1);
+ int limit = 0;
+ for(int i = 0; i < spacesToRemove; ++i) {
+ if (!line[i].isSpace())
+ break;
+ limit++;
+ }
+
+ s << indentor << line.remove(0, limit);
+ }
+ s << endl;
+ }
+ return s;
+}
+
+AbstractMetaFunctionList Generator::implicitConversions(const TypeEntry* type) const
+{
+ if (type->isValue()) {
+ if (const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes(), type))
+ return metaClass->implicitConversions();
+ }
+ return AbstractMetaFunctionList();
+}
+
+AbstractMetaFunctionList Generator::implicitConversions(const AbstractMetaType* metaType) const
+{
+ return implicitConversions(metaType->typeEntry());
+}
+
+bool Generator::isObjectType(const TypeEntry* type)
+{
+ if (type->isComplex())
+ return Generator::isObjectType((const ComplexTypeEntry*)type);
+ return type->isObject();
+}
+bool Generator::isObjectType(const ComplexTypeEntry* type)
+{
+ return type->isObject() || type->isQObject();
+}
+bool Generator::isObjectType(const AbstractMetaClass* metaClass)
+{
+ return Generator::isObjectType(metaClass->typeEntry());
+}
+bool Generator::isObjectType(const AbstractMetaType* metaType)
+{
+ return isObjectType(metaType->typeEntry());
+}
+
+bool Generator::isPointer(const AbstractMetaType* type)
+{
+ return type->indirections() > 0
+ || type->isNativePointer()
+ || type->isValuePointer();
+}
+
+bool Generator::isCString(const AbstractMetaType* type)
+{
+ return type->isNativePointer()
+ && type->indirections() == 1
+ && type->name() == QLatin1String("char");
+}
+
+bool Generator::isVoidPointer(const AbstractMetaType* type)
+{
+ return type->isNativePointer()
+ && type->indirections() == 1
+ && type->name() == QLatin1String("void");
+}
+
+QString Generator::getFullTypeName(const TypeEntry* type) const
+{
+ return type->isCppPrimitive()
+ ? type->qualifiedCppName()
+ : (QLatin1String("::") + type->qualifiedCppName());
+}
+
+QString Generator::getFullTypeName(const AbstractMetaType* type) const
+{
+ if (isCString(type))
+ return QLatin1String("const char*");
+ if (isVoidPointer(type))
+ return QLatin1String("void*");
+ if (type->typeEntry()->isContainer())
+ return QLatin1String("::") + type->cppSignature();
+ QString typeName;
+ if (type->typeEntry()->isComplex() && type->hasInstantiations())
+ typeName = getFullTypeNameWithoutModifiers(type);
+ else
+ typeName = getFullTypeName(type->typeEntry());
+ return typeName + QString::fromLatin1("*").repeated(type->indirections());
+}
+
+QString Generator::getFullTypeName(const AbstractMetaClass* metaClass) const
+{
+ return QLatin1String("::") + metaClass->qualifiedCppName();
+}
+
+QString Generator::getFullTypeNameWithoutModifiers(const AbstractMetaType* type) const
+{
+ if (isCString(type))
+ return QLatin1String("const char*");
+ if (isVoidPointer(type))
+ return QLatin1String("void*");
+ if (!type->hasInstantiations())
+ return getFullTypeName(type->typeEntry());
+ QString typeName = type->cppSignature();
+ 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 QLatin1String("::") + typeName;
+}
+
+QString Generator::minimalConstructor(const AbstractMetaType* type) const
+{
+ if (!type || (type->referenceType() == LValueReference && Generator::isObjectType(type)))
+ return QString();
+
+ if (type->isContainer()) {
+ QString ctor = type->cppSignature();
+ if (ctor.endsWith(QLatin1Char('*')))
+ return QLatin1String("0");
+ 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("()");
+ }
+
+ if (type->isNativePointer())
+ return QLatin1String("static_cast<") + type->typeEntry()->qualifiedCppName() + QLatin1String(" *>(0)");
+ if (Generator::isPointer(type))
+ return QLatin1String("static_cast< ::") + type->typeEntry()->qualifiedCppName() + QLatin1String(" *>(0)");
+
+ 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));
+ return ctor;
+ }
+
+ return minimalConstructor(type->typeEntry());
+}
+
+QString Generator::minimalConstructor(const TypeEntry* type) const
+{
+ if (!type)
+ return QString();
+
+ if (type->isCppPrimitive()) {
+ const QString &name = type->qualifiedCppName();
+ return name == QLatin1String("bool")
+ ? QLatin1String("false") : name + QLatin1String("(0)");
+ }
+
+ if (type->isEnum())
+ return QLatin1String("static_cast< ::") + type->qualifiedCppName() + QLatin1String(">(0)");
+
+ if (type->isFlags())
+ return type->qualifiedCppName() + QLatin1String("(0)");
+
+ if (type->isPrimitive()) {
+ QString ctor = reinterpret_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;
+ }
+
+ if (type->isComplex())
+ return minimalConstructor(AbstractMetaClass::findClass(classes(), type));
+
+ return QString();
+}
+
+QString Generator::minimalConstructor(const AbstractMetaClass* metaClass) const
+{
+ if (!metaClass)
+ return QString();
+
+ const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(metaClass->typeEntry());
+ if (cType->hasDefaultConstructor())
+ return cType->defaultConstructor();
+
+ 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 (!args.isEmpty())
+ return QString::fromLatin1("::%1(%2)").arg(qualifiedCppName, args.join(QLatin1String(", ")));
+
+ candidates << 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)) {
+ 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();
+ break;
+ }
+ args << argValue;
+ }
+ if (!args.isEmpty()) {
+ return QString::fromLatin1("::%1(%2)").arg(qualifiedCppName, args.join(QLatin1String(", ")));
+ }
+ }
+
+ return QString();
+}
+
+QString Generator::translateType(const AbstractMetaType *cType,
+ const AbstractMetaClass *context,
+ Options options) const
+{
+ QString s;
+ static int constLen = strlen("const");
+
+ if (context && cType &&
+ context->typeEntry()->isGenericClass() &&
+ cType->originalTemplateType()) {
+ cType = cType->originalTemplateType();
+ }
+
+ if (!cType) {
+ s = QLatin1String("void");
+ } else if (cType->isArray()) {
+ s = translateType(cType->arrayElementType(), context, options) + QLatin1String("[]");
+ } else if (options & Generator::EnumAsInts && (cType->isEnum() || cType->isFlags())) {
+ s = QLatin1String("int");
+ } else {
+ if (options & Generator::OriginalName) {
+ s = cType->originalTypeDescription().trimmed();
+ if ((options & Generator::ExcludeReference) && s.endsWith(QLatin1Char('&')))
+ s.chop(1);
+
+ // remove only the last const (avoid remove template const)
+ if (options & Generator::ExcludeConst) {
+ int index = s.lastIndexOf(QLatin1String("const"));
+
+ if (index >= (s.size() - (constLen + 1))) // (VarType const) or (VarType const[*|&])
+ s = s.remove(index, constLen);
+ }
+ } else if (options & Generator::ExcludeConst || options & Generator::ExcludeReference) {
+ AbstractMetaType* copyType = cType->copy();
+
+ 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("::"));
+ delete copyType;
+ } else {
+ s = cType->cppSignature();
+ }
+ }
+
+ return s;
+}
+
+
+QString Generator::subDirectoryForClass(const AbstractMetaClass* clazz) const
+{
+ return subDirectoryForPackage(clazz->package());
+}
+
+QString Generator::subDirectoryForPackage(QString packageName) const
+{
+ if (packageName.isEmpty())
+ packageName = m_d->packageName;
+ return QString(packageName).replace(QLatin1Char('.'), QDir::separator());
+}
+
+template<typename T>
+static QString getClassTargetFullName_(const T* t, bool includePackageName)
+{
+ QString name = t->name();
+ const AbstractMetaClass* context = t->enclosingClass();
+ while (context) {
+ name.prepend(QLatin1Char('.'));
+ name.prepend(context->name());
+ context = context->enclosingClass();
+ }
+ if (includePackageName) {
+ name.prepend(QLatin1Char('.'));
+ name.prepend(t->package());
+ }
+ return name;
+}
+
+QString getClassTargetFullName(const AbstractMetaClass* metaClass, bool includePackageName)
+{
+ return getClassTargetFullName_(metaClass, 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('_'));
+ return signature;
+}