aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/generator
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2/generator')
-rw-r--r--sources/shiboken2/generator/CMakeLists.txt40
-rw-r--r--sources/shiboken2/generator/generator.cpp854
-rw-r--r--sources/shiboken2/generator/generator.h447
-rw-r--r--sources/shiboken2/generator/main.cpp529
-rw-r--r--sources/shiboken2/generator/qtdoc/CMakeLists.txt21
-rw-r--r--sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp1704
-rw-r--r--sources/shiboken2/generator/qtdoc/qtdocgenerator.h235
-rw-r--r--sources/shiboken2/generator/shiboken2/CMakeLists.txt28
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp5689
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.h370
-rw-r--r--sources/shiboken2/generator/shiboken2/headergenerator.cpp558
-rw-r--r--sources/shiboken2/generator/shiboken2/headergenerator.h67
-rw-r--r--sources/shiboken2/generator/shiboken2/overloaddata.cpp1079
-rw-r--r--sources/shiboken2/generator/shiboken2/overloaddata.h161
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.cpp2674
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.h554
-rw-r--r--sources/shiboken2/generator/shibokenconfig.h.in6
17 files changed, 15016 insertions, 0 deletions
diff --git a/sources/shiboken2/generator/CMakeLists.txt b/sources/shiboken2/generator/CMakeLists.txt
new file mode 100644
index 000000000..032118666
--- /dev/null
+++ b/sources/shiboken2/generator/CMakeLists.txt
@@ -0,0 +1,40 @@
+project(shibokengenerator)
+
+find_package(Qt5Xml)
+find_package(Qt5XmlPatterns)
+
+set(shiboken2_SRC
+generator.cpp
+shiboken2/cppgenerator.cpp
+shiboken2/headergenerator.cpp
+shiboken2/overloaddata.cpp
+shiboken2/shibokengenerator.cpp
+main.cpp
+)
+
+if (NOT DISABLE_DOCSTRINGS)
+ set(shiboken2_SRC ${shiboken2_SRC} qtdoc/qtdocgenerator.cpp)
+ add_definitions(-DDOCSTRINGS_ENABLED)
+endif()
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/shiboken2
+ ${CMAKE_CURRENT_SOURCE_DIR}/qtdoc
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${apiextractor_SOURCE_DIR}
+ ${Qt5Core_INCLUDE_DIRS}
+ ${Qt5XmlPatterns_INCLUDE_DIRS}
+ )
+
+add_executable(shiboken2 ${shiboken2_SRC})
+add_dependencies(shiboken2 apiextractor)
+set_target_properties(shiboken2 PROPERTIES OUTPUT_NAME shiboken2${shiboken2_SUFFIX})
+target_link_libraries(shiboken2
+ apiextractor
+ ${Qt5Core_LIBRARIES}
+ ${Qt5XmlPatterns_LIBRARIES}
+ )
+
+configure_file(shibokenconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/shibokenconfig.h" @ONLY)
+
+install(TARGETS shiboken2 DESTINATION bin)
diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp
new file mode 100644
index 000000000..d7f98a90f
--- /dev/null
+++ b/sources/shiboken2/generator/generator.cpp
@@ -0,0 +1,854 @@
+/****************************************************************************
+**
+** 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 <QDebug>
+#include <typedatabase.h>
+
+struct Generator::GeneratorPrivate {
+ const ApiExtractor* apiextractor;
+ QString outDir;
+ // License comment
+ QString licenseComment;
+ QString packageName;
+ int numGenerated;
+ QStringList instantiatedContainersNames;
+ QStringList instantiatedSmartPointerNames;
+ QList<const AbstractMetaType *> instantiatedContainers;
+ QList<const AbstractMetaType *> instantiatedSmartPointers;
+
+};
+
+Generator::Generator() : m_d(new GeneratorPrivate)
+{
+ m_d->numGenerated = 0;
+ m_d->instantiatedContainers = QList<const AbstractMetaType *>();
+ m_d->instantiatedSmartPointers = QList<const AbstractMetaType *>();
+ m_d->instantiatedContainersNames = QStringList();
+ m_d->instantiatedSmartPointerNames = QStringList();
+}
+
+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) {
+ foreach (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;
+ foreach (const AbstractMetaType* t, type->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());
+ foreach (const AbstractMetaArgument* arg, func->arguments())
+ addInstantiatedContainersAndSmartPointers(arg->type(), func->signature());
+}
+
+void Generator::collectInstantiatedContainersAndSmartPointers(const AbstractMetaClass *metaClass)
+{
+ if (!metaClass->typeEntry()->generateCode())
+ return;
+ foreach (const AbstractMetaFunction* func, metaClass->functions())
+ collectInstantiatedContainersAndSmartPointers(func);
+ foreach (const AbstractMetaField* field, metaClass->fields())
+ addInstantiatedContainersAndSmartPointers(field->type(), field->name());
+ foreach (AbstractMetaClass* innerClass, metaClass->innerClasses())
+ collectInstantiatedContainersAndSmartPointers(innerClass);
+}
+
+void Generator::collectInstantiatedContainersAndSmartPointers()
+{
+ foreach (const AbstractMetaFunction* func, globalFunctions())
+ collectInstantiatedContainersAndSmartPointers(func);
+ foreach (const AbstractMetaClass* metaClass, classes())
+ collectInstantiatedContainersAndSmartPointers(metaClass);
+}
+
+QList<const AbstractMetaType*> Generator::instantiatedContainers() const
+{
+ return m_d->instantiatedContainers;
+}
+
+QList<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();
+}
+
+QList<const PrimitiveTypeEntry*> Generator::primitiveTypes() const
+{
+ return m_d->apiextractor->primitiveTypes();
+}
+
+QList<const ContainerTypeEntry*> 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()
+{
+ foreach (AbstractMetaClass *cls, m_d->apiextractor->classes()) {
+ GeneratorContext context(cls);
+ if (!generateFileForContext(context))
+ return false;
+ }
+
+ foreach (const AbstractMetaType *type, 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());
+
+ foreach (AbstractMetaArgument *arg, func->arguments())
+ 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
+ QStringList lst(code.split(QLatin1Char('\n')));
+ QRegExp nonSpaceRegex(QLatin1String("[^\\s]"));
+ int spacesToRemove = 0;
+ foreach(QString line, lst) {
+ if (!line.trimmed().isEmpty()) {
+ spacesToRemove = line.indexOf(nonSpaceRegex);
+ if (spacesToRemove == -1)
+ spacesToRemove = 0;
+ break;
+ }
+ }
+
+ static QRegExp emptyLine(QLatin1String("\\s*[\\r]?[\\n]?\\s*"));
+
+ foreach(QString line, lst) {
+ if (!line.isEmpty() && !emptyLine.exactMatch(line)) {
+ 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();
+
+ AbstractMetaFunctionList constructors = metaClass->queryFunctions(AbstractMetaClass::Constructors);
+ int maxArgs = 0;
+ foreach (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;
+ foreach (TypeEntry* templateType, metaClass->templateArguments())
+ templateTypes << templateType->qualifiedCppName();
+
+ // Empty constructor.
+ if (maxArgs == 0)
+ return QLatin1String("::") + qualifiedCppName + QLatin1String("()");
+
+ QList<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) {
+ foreach (const AbstractMetaFunction* ctor, constructors) {
+ if (ctor->isUserAdded() || ctor->isPrivate() || ctor->functionType() != AbstractMetaFunction::ConstructorFunction)
+ continue;
+
+ AbstractMetaArgumentList arguments = ctor->arguments();
+ if (arguments.size() != i)
+ continue;
+
+ QStringList args;
+ foreach (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.
+ foreach (const AbstractMetaFunction* ctor, candidates) {
+ QStringList args;
+ foreach (const AbstractMetaArgument* arg, ctor->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;
+}
diff --git a/sources/shiboken2/generator/generator.h b/sources/shiboken2/generator/generator.h
new file mode 100644
index 000000000..f734ff9d7
--- /dev/null
+++ b/sources/shiboken2/generator/generator.h
@@ -0,0 +1,447 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef GENERATOR_H
+#define GENERATOR_H
+
+#include <abstractmetalang_typedefs.h>
+#include <dependency.h>
+#include <QtCore/QObject>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QTextStream>
+#include <QtCore/QVector>
+
+class ApiExtractor;
+class AbstractMetaBuilder;
+class AbstractMetaFunction;
+class AbstractMetaClass;
+class AbstractMetaEnum;
+class TypeEntry;
+class ComplexTypeEntry;
+class AbstractMetaType;
+class EnumTypeEntry;
+class FlagsTypeEntry;
+
+QT_BEGIN_NAMESPACE
+class QFile;
+QT_END_NAMESPACE
+
+class PrimitiveTypeEntry;
+class ContainerTypeEntry;
+class Indentor;
+
+QTextStream& formatCode(QTextStream &s, const QString& code, Indentor &indentor);
+void verifyDirectoryFor(const QFile &file);
+
+QString getClassTargetFullName(const AbstractMetaClass* metaClass, bool includePackageName = true);
+QString getClassTargetFullName(const AbstractMetaEnum* metaEnum, bool includePackageName = true);
+QString getClassTargetFullName(const AbstractMetaType *metaType, bool includePackageName = true);
+QString getFilteredCppSignatureString(QString signature);
+
+/**
+ * PYSIDE-504: Handling the "protected hack"
+ *
+ * The problem: Creating wrappers when the class has private destructors.
+ * You can see an example on Windows in qclipboard_wrapper.h and others.
+ * Simply search for the text "// C++11: need to declare (unimplemented) destructor".
+ *
+ * The protected hack is the definition "#define protected public".
+ * For most compilers, this "hack" is enabled, because the problem of private
+ * destructors simply vanishes.
+ *
+ * If one does not want to use this hack, then a new problem arises:
+ * C++11 requires that a destructor is declared in a wrapper class when it is
+ * private in the base class. There is no implementation allowed!
+ *
+ * Unfortunately, MSVC in recent versions supports C++11, and due to restrictive
+ * rules, it is impossible to use the hack with this compiler.
+ * More unfortunate: Clang, when C++11 is enabled, also enforces a declaration
+ * of a private destructor, but it falsely then creates a linker error!
+ *
+ * Originally, we wanted to remove the protected hack. But due to the Clang
+ * problem, we gave up on removal of the protected hack and use it always
+ * when we can. This might change again when the Clang problem is solved.
+ */
+
+#ifdef Q_CC_MSVC
+const int alwaysGenerateDestructor = 1;
+#else
+const int alwaysGenerateDestructor = 0;
+#endif
+
+/**
+ * A GeneratorContext object contains a pointer to an AbstractMetaClass and/or a specialized
+ * AbstractMetaType, for which code is currently being generated.
+ *
+ * The main case is when the context contains only an AbstractMetaClass pointer, which is used
+ * by different methods to generate appropriate expressions, functions, type names, etc.
+ *
+ * The second case is for generation of code for smart pointers. In this case the m_metaClass member
+ * contains the generic template class of the smart pointer, and the m_preciseClassType member
+ * contains the instantiated template type, e.g. a concrete shared_ptr<int>. To
+ * distinguish this case, the member m_forSmartPointer is set to true.
+ *
+ * In the future the second case might be generalized for all template type instantiations.
+ */
+class GeneratorContext {
+public:
+ GeneratorContext() : m_metaClass(0), m_preciseClassType(0), m_forSmartPointer(false) {}
+ GeneratorContext(AbstractMetaClass *metaClass,
+ const AbstractMetaType *preciseType = 0,
+ bool forSmartPointer = false)
+ : m_metaClass(metaClass),
+ m_preciseClassType(preciseType),
+ m_forSmartPointer(forSmartPointer) {}
+
+
+ AbstractMetaClass *metaClass() const { return m_metaClass; }
+ bool forSmartPointer() const { return m_forSmartPointer; }
+ const AbstractMetaType *preciseType() const { return m_preciseClassType; }
+
+private:
+ AbstractMetaClass *m_metaClass;
+ const AbstractMetaType *m_preciseClassType;
+ bool m_forSmartPointer;
+};
+
+/**
+ * Base class for all generators. The default implementations does nothing,
+ * you must subclass this to create your own generators.
+ */
+class Generator
+{
+public:
+ /// Optiosn used around the generator code
+ enum Option {
+ NoOption = 0x00000000,
+ BoxedPrimitive = 0x00000001,
+ ExcludeConst = 0x00000002,
+ ExcludeReference = 0x00000004,
+ UseNativeIds = 0x00000008,
+
+ EnumAsInts = 0x00000010,
+ SkipName = 0x00000020,
+ NoCasts = 0x00000040,
+ SkipReturnType = 0x00000080,
+ OriginalName = 0x00000100,
+ ShowStatic = 0x00000200,
+ UnderscoreSpaces = 0x00000400,
+ ForceEnumCast = 0x00000800,
+ ArrayAsPointer = 0x00001000,
+ VirtualCall = 0x00002000,
+ SkipTemplateParameters = 0x00004000,
+ SkipAttributes = 0x00008000,
+ OriginalTypeDescription = 0x00010000,
+ SkipRemovedArguments = 0x00020000,
+ IncludeDefaultExpression = 0x00040000,
+ NoReturnStatement = 0x00080000,
+ NoBlockedSlot = 0x00100000,
+
+ SuperCall = 0x00200000,
+
+ GlobalRefJObject = 0x00100000,
+
+ SkipDefaultValues = 0x00400000,
+
+ WriteSelf = 0x00800000,
+ ExcludeMethodConst = 0x01000000,
+
+ ForceValueType = ExcludeReference | ExcludeConst
+ };
+ Q_DECLARE_FLAGS(Options, Option)
+
+ Generator();
+ virtual ~Generator();
+
+ bool setup(const ApiExtractor& extractor, const QMap<QString, QString> args);
+
+ virtual QMap<QString, QString> options() const;
+
+ /// Returns the classes used to generate the binding code.
+ AbstractMetaClassList classes() const;
+
+ /// Returns the classes, topologically ordered, used to generate the binding code.
+ ///
+ /// The classes are ordered such that derived classes appear later in the list than
+ /// their parent classes.
+ AbstractMetaClassList classesTopologicalSorted(const Dependencies &additionalDependencies = Dependencies()) const;
+
+ /// Returns all global functions found by APIExtractor
+ AbstractMetaFunctionList globalFunctions() const;
+
+ /// Returns all global enums found by APIExtractor
+ AbstractMetaEnumList globalEnums() const;
+
+ /// Returns all primitive types found by APIExtractor
+ QList<const PrimitiveTypeEntry*> primitiveTypes() const;
+
+ /// Returns all container types found by APIExtractor
+ QList<const ContainerTypeEntry*> containerTypes() const;
+
+ /// Returns an AbstractMetaEnum for a given EnumTypeEntry, or NULL if not found.
+ const AbstractMetaEnum* findAbstractMetaEnum(const EnumTypeEntry* typeEntry) const;
+
+ /// Returns an AbstractMetaEnum for a given TypeEntry that is an EnumTypeEntry, or NULL if not found.
+ const AbstractMetaEnum* findAbstractMetaEnum(const TypeEntry* typeEntry) const;
+
+ /// Returns an AbstractMetaEnum for the enum related to a given FlagsTypeEntry, or NULL if not found.
+ const AbstractMetaEnum* findAbstractMetaEnum(const FlagsTypeEntry* typeEntry) const;
+
+ /// Returns an AbstractMetaEnum for a given AbstractMetaType that holds an EnumTypeEntry, or NULL if not found.
+ const AbstractMetaEnum* findAbstractMetaEnum(const AbstractMetaType* metaType) const;
+
+ /// Returns the output directory
+ QString outputDirectory() const;
+
+ /// Set the output directory
+ void setOutputDirectory(const QString &outDir);
+
+ /**
+ * Start the code generation, be sure to call setClasses before callign this method.
+ * For each class it creates a QTextStream, call the write method with the current
+ * class and the associated text stream, then write the text stream contents if needed.
+ * \see #write
+ */
+ bool generate();
+
+
+ /// Generates a file for given AbstractMetaClass or AbstractMetaType (smart pointer case).
+ bool generateFileForContext(GeneratorContext &context);
+
+ /// Returns the file base name for a smart pointer.
+ QString getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType,
+ const AbstractMetaClass *smartPointerClass) const;
+
+ /// Returns the number of generated items
+ int numGenerated() const;
+
+ /// Returns the generator's name. Used for cosmetic purposes.
+ virtual const char* name() const = 0;
+
+ /// Returns true if the generator should generate any code for the TypeEntry.
+ bool shouldGenerateTypeEntry(const TypeEntry*) const;
+
+ /// Returns true if the generator should generate any code for the AbstractMetaClass.
+ virtual bool shouldGenerate(const AbstractMetaClass *) const;
+
+ /// Returns the subdirectory used to write the binding code of an AbstractMetaClass.
+ virtual QString subDirectoryForClass(const AbstractMetaClass* clazz) const;
+
+ /**
+ * Translate metatypes to binding source format.
+ * \param metatype a pointer to metatype
+ * \param context the current meta class
+ * \param option some extra options
+ * \return the metatype translated to binding source format
+ */
+ QString translateType(const AbstractMetaType *metatype,
+ const AbstractMetaClass *context,
+ Options options = NoOption) const;
+
+ /**
+ * Function used to write the fucntion arguments on the class buffer.
+ * \param s the class output buffer
+ * \param metafunction the pointer to metafunction information
+ * \param count the number of function arguments
+ * \param options some extra options used during the parser
+ */
+ virtual void writeFunctionArguments(QTextStream &s,
+ const AbstractMetaFunction *metafunction,
+ Options options = NoOption) const = 0;
+
+ virtual void writeArgumentNames(QTextStream &s,
+ const AbstractMetaFunction *metafunction,
+ Options options = NoOption) const = 0;
+
+ void replaceTemplateVariables(QString &code, const AbstractMetaFunction *func);
+
+ // QtScript
+ QSet<QString> qtMetaTypeDeclaredTypeNames() const;
+
+ /**
+ * Returns the license comment to be prepended to each source file generated.
+ */
+ QString licenseComment() const;
+
+ /**
+ * Sets the license comment to be prepended to each source file generated.
+ */
+ void setLicenseComment(const QString &licenseComment);
+
+ /**
+ * Returns the package name.
+ */
+ QString packageName() const;
+
+ /**
+ * Retrieves the name of the currently processed module.
+ * While package name is a complete package idetification, e.g. 'PySide.QtCore',
+ * a module name represents the last part of the package, e.g. 'QtCore'.
+ * If the target language separates the modules with characters other than
+ * dots ('.') the generator subclass must overload this method.
+ * \return a string representing the last part of a package name
+ */
+ virtual QString moduleName() const;
+
+ /**
+ * Retrieves a list of constructors used in implicit conversions
+ * available on the given type. The TypeEntry must be a value-type
+ * or else it will return an empty list.
+ * \param type a TypeEntry that is expected to be a value-type
+ * \return a list of constructors that could be used as implicit converters
+ */
+ AbstractMetaFunctionList implicitConversions(const TypeEntry* type) const;
+
+ /// Convenience function for implicitConversions(const TypeEntry* type).
+ AbstractMetaFunctionList implicitConversions(const AbstractMetaType* metaType) const;
+
+ /// Check if type is a pointer.
+ static bool isPointer(const AbstractMetaType* type);
+
+ /// Tells if the type or class is an Object (or QObject) Type.
+ static bool isObjectType(const TypeEntry* type);
+ static bool isObjectType(const ComplexTypeEntry* type);
+ static bool isObjectType(const AbstractMetaType* metaType);
+ static bool isObjectType(const AbstractMetaClass* metaClass);
+
+ /// Returns true if the type is a C string (const char*).
+ static bool isCString(const AbstractMetaType* type);
+ /// Returns true if the type is a void pointer.
+ static bool isVoidPointer(const AbstractMetaType* type);
+
+ // Returns the full name of the type.
+ QString getFullTypeName(const TypeEntry* type) const;
+ QString getFullTypeName(const AbstractMetaType* type) const;
+ QString getFullTypeName(const AbstractMetaClass* metaClass) const;
+
+ /**
+ * Returns the full qualified C++ name for an AbstractMetaType, but removing modifiers
+ * as 'const', '&', and '*' (except if the class is not derived from a template).
+ * This is useful for instantiated templates.
+ */
+ QString getFullTypeNameWithoutModifiers(const AbstractMetaType* type) const;
+
+ /**
+ * Tries to build a minimal constructor for the type.
+ * It will check first for a user defined default constructor.
+ * Returns a null string if it fails.
+ */
+ QString minimalConstructor(const TypeEntry* type) const;
+ QString minimalConstructor(const AbstractMetaType* type) const;
+ QString minimalConstructor(const AbstractMetaClass* metaClass) const;
+
+protected:
+ /**
+ * Returns the file name used to write the binding code of an AbstractMetaClass/Type.
+ * \param context the GeneratorContext which contains an AbstractMetaClass or AbstractMetaType
+ * for which the file name must be returned
+ * \return the file name used to write the binding code for the class
+ */
+ virtual QString fileNamePrefix() const = 0;
+ virtual QString fileNameForContext(GeneratorContext &context) const = 0;
+
+
+ virtual bool doSetup(const QMap<QString, QString>& args) = 0;
+
+ /**
+ * Write the bindding code for an AbstractMetaClass.
+ * This is called by generate method.
+ * \param s text stream to write the generated output
+ * \param metaClass the class that should be generated
+ */
+ virtual void generateClass(QTextStream& s, GeneratorContext &classContext) = 0;
+ virtual bool finishGeneration() = 0;
+
+ /**
+ * Returns the subdirectory path for a given package
+ * (aka module, aka library) name.
+ * If the target language separates the package modules with characters other
+ * than dots ('.') the generator subclass must overload this method.
+ * /param packageName complete package name for which to return the subdirectory path
+ * or nothing the use the name of the currently processed package
+ * /return a string representing the subdirectory path for the given package
+ */
+ virtual QString subDirectoryForPackage(QString packageName = QString()) const;
+
+ QList<const AbstractMetaType*> instantiatedContainers() const;
+ QList<const AbstractMetaType*> instantiatedSmartPointers() const;
+
+ static QString getSimplifiedContainerTypeName(const AbstractMetaType *type);
+ void addInstantiatedContainersAndSmartPointers(const AbstractMetaType *type,
+ const QString &context);
+
+private:
+ struct GeneratorPrivate;
+ GeneratorPrivate* m_d;
+ void collectInstantiatedContainersAndSmartPointers(const AbstractMetaFunction* func);
+ void collectInstantiatedContainersAndSmartPointers(const AbstractMetaClass *metaClass);
+ void collectInstantiatedContainersAndSmartPointers();
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(Generator::Options)
+typedef QSharedPointer<Generator> GeneratorPtr;
+typedef QVector<GeneratorPtr> Generators;
+
+/**
+* Utility class to store the identation level, use it in a QTextStream.
+*/
+class Indentor
+{
+public:
+ Indentor() : indent(0) {}
+ int indent;
+};
+
+/**
+* Class that use the RAII idiom to set and unset the identation level.
+*/
+class Indentation
+{
+public:
+ Indentation(Indentor &indentor) : indentor(indentor)
+ {
+ indentor.indent++;
+ }
+ ~Indentation()
+ {
+ indentor.indent--;
+ }
+
+private:
+ Indentor &indentor;
+};
+
+inline QTextStream &operator <<(QTextStream &s, const Indentor &indentor)
+{
+ for (int i = 0; i < indentor.indent; ++i)
+ s << " ";
+ return s;
+}
+
+#endif // GENERATOR_H
+
diff --git a/sources/shiboken2/generator/main.cpp b/sources/shiboken2/generator/main.cpp
new file mode 100644
index 000000000..874540e54
--- /dev/null
+++ b/sources/shiboken2/generator/main.cpp
@@ -0,0 +1,529 @@
+/****************************************************************************
+**
+** 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 <QCoreApplication>
+#include <QElapsedTimer>
+#include <QLinkedList>
+#include <QLibrary>
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+#include <iostream>
+#include <apiextractor.h>
+#include "generator.h"
+#include "shibokenconfig.h"
+#include "cppgenerator.h"
+#include "headergenerator.h"
+#include "qtdocgenerator.h"
+
+#ifdef _WINDOWS
+ #define PATH_SPLITTER ";"
+#else
+ #define PATH_SPLITTER ":"
+#endif
+
+namespace {
+
+class ArgsHandler
+{
+public:
+ explicit ArgsHandler(const QMap<QString, QString>& other);
+ virtual ~ArgsHandler();
+
+ inline QMap<QString, QString>& args() const
+ {
+ return *m_args;
+ }
+
+ inline bool argExists(const QString& s) const
+ {
+ return m_args->contains(s);
+ }
+
+ QString removeArg(const QString& s);
+ bool argExistsRemove(const QString& s);
+
+ inline QString argValue(const QString& s) const
+ {
+ return m_args->value(s);
+ }
+
+ inline bool noArgs() const
+ {
+ return m_args->isEmpty();
+ }
+
+ QString errorMessage() const;
+
+private:
+ QMap<QString, QString>* m_args;
+};
+
+ArgsHandler::ArgsHandler(const QMap<QString, QString>& other)
+ : m_args(new QMap<QString, QString>(other))
+{
+}
+
+ArgsHandler::~ArgsHandler()
+{
+ delete m_args;
+}
+
+QString ArgsHandler::removeArg(const QString& s)
+{
+ QString retval;
+
+ if (argExists(s)) {
+ retval = argValue(s);
+ m_args->remove(s);
+ }
+
+ return retval;
+}
+
+bool ArgsHandler::argExistsRemove(const QString& s)
+{
+ bool retval = false;
+
+ if (argExists(s)) {
+ retval = true;
+ m_args->remove(s);
+ }
+
+ return retval;
+}
+
+QString ArgsHandler::errorMessage() const
+{
+ typedef QMap<QString, QString>::ConstIterator StringMapConstIt;
+
+ QString message;
+ QTextStream str(&message);
+ str << "shiboken: Called with wrong arguments:";
+ for (StringMapConstIt it = m_args->cbegin(), end = m_args->cend(); it != end; ++it) {
+ str << ' ' << it.key();
+ if (!it.value().isEmpty())
+ str << ' ' << it.value();
+ }
+ str << "\nCommand line: " << QCoreApplication::arguments().join(QLatin1Char(' '));
+ return message;
+}
+}
+
+static void printOptions(QTextStream& s, const QMap<QString, QString>& options)
+{
+ QMap<QString, QString>::const_iterator it = options.constBegin();
+ s.setFieldAlignment(QTextStream::AlignLeft);
+ for (; it != options.constEnd(); ++it) {
+ s << " --";
+ s.setFieldWidth(38);
+ s << it.key() << it.value();
+ s.setFieldWidth(0);
+ s << endl;
+ }
+}
+
+typedef void (*getGeneratorsFunc)(QLinkedList<Generator*>*);
+
+static bool processProjectFile(QFile& projectFile, QMap<QString, QString>& args)
+{
+ QByteArray line = projectFile.readLine().trimmed();
+ if (line.isEmpty() || line != "[generator-project]")
+ return false;
+
+ QStringList includePaths;
+ QStringList typesystemPaths;
+ QStringList apiVersions;
+
+ while (!projectFile.atEnd()) {
+ line = projectFile.readLine().trimmed();
+ if (line.isEmpty())
+ continue;
+
+ int split = line.indexOf('=');
+ QByteArray key;
+ QString value;
+ if (split > 0) {
+ key = line.left(split - 1).trimmed();
+ value = QString::fromUtf8(line.mid(split + 1).trimmed());
+ } else {
+ key = line;
+ }
+
+ if (key == "include-path")
+ includePaths << QDir::toNativeSeparators(value);
+ else if (key == "typesystem-path")
+ typesystemPaths << QDir::toNativeSeparators(value);
+ else if (key == "api-version")
+ apiVersions << value;
+ else if (key == "header-file")
+ args.insert(QLatin1String("arg-1"), value);
+ else if (key == "typesystem-file")
+ args.insert(QLatin1String("arg-2"), value);
+ else
+ args.insert(QString::fromUtf8(key), value);
+ }
+
+ if (!includePaths.isEmpty())
+ args.insert(QLatin1String("include-paths"), includePaths.join(QLatin1String(PATH_SPLITTER)));
+
+ if (!typesystemPaths.isEmpty())
+ args.insert(QLatin1String("typesystem-paths"), typesystemPaths.join(QLatin1String(PATH_SPLITTER)));
+ if (!apiVersions.isEmpty())
+ args.insert(QLatin1String("api-version"), apiVersions.join(QLatin1Char('|')));
+ return true;
+}
+
+static QMap<QString, QString> getInitializedArguments()
+{
+ QMap<QString, QString> args;
+ QStringList arguments = QCoreApplication::arguments();
+ QString appName = arguments.first();
+ arguments.removeFirst();
+
+ QString projectFileName;
+ foreach (const QString& arg, arguments) {
+ if (arg.startsWith(QLatin1String("--project-file"))) {
+ int split = arg.indexOf(QLatin1Char('='));
+ if (split > 0)
+ projectFileName = arg.mid(split + 1).trimmed();
+ break;
+ }
+ }
+
+ if (projectFileName.isNull())
+ return args;
+
+ if (!QFile::exists(projectFileName)) {
+ std::cerr << qPrintable(appName) << ": Project file \"";
+ std::cerr << qPrintable(projectFileName) << "\" not found.";
+ std::cerr << std::endl;
+ return args;
+ }
+
+ QFile projectFile(projectFileName);
+ if (!projectFile.open(QIODevice::ReadOnly))
+ return args;
+
+ if (!processProjectFile(projectFile, args)) {
+ std::cerr << qPrintable(appName) << ": first line of project file \"";
+ std::cerr << qPrintable(projectFileName) << "\" must be the string \"[generator-project]\"";
+ std::cerr << std::endl;
+ return args;
+ }
+
+ return args;
+}
+
+static QMap<QString, QString> getCommandLineArgs()
+{
+ QMap<QString, QString> args = getInitializedArguments();
+ QStringList arguments = QCoreApplication::arguments();
+ arguments.removeFirst();
+
+ int argNum = 0;
+ foreach (const QString &carg, arguments) {
+ const QString &arg = carg.trimmed();
+ if (arg.startsWith(QLatin1String("--"))) {
+ int split = arg.indexOf(QLatin1Char('='));
+ if (split > 0)
+ args[arg.mid(2).left(split-2)] = arg.mid(split + 1).trimmed();
+ else
+ args[arg.mid(2)] = QString();
+ } else if (arg.startsWith(QLatin1Char('-'))) {
+ args[arg.mid(1)] = QString();
+ } else {
+ argNum++;
+ args[QString::fromLatin1("arg-%1").arg(argNum)] = arg;
+ }
+ }
+ return args;
+}
+
+static inline Generators docGenerators()
+{
+ Generators result;
+#ifdef DOCSTRINGS_ENABLED
+ result.append(GeneratorPtr(new QtDocGenerator));
+#endif
+ return result;
+}
+
+static inline Generators shibokenGenerators()
+{
+ Generators result;
+ result << GeneratorPtr(new CppGenerator) << GeneratorPtr(new HeaderGenerator);
+ return result;
+}
+
+void printUsage()
+{
+ QTextStream s(stdout);
+ s << "Usage:\n "
+ << "shiboken [options] header-file typesystem-file\n\n"
+ << "General options:\n";
+ QMap<QString, QString> generalOptions;
+ generalOptions.insert(QLatin1String("project-file=<file>"),
+ QLatin1String("text file containing a description of the binding project. Replaces and overrides command line arguments"));
+ generalOptions.insert(QLatin1String("debug-level=[sparse|medium|full]"),
+ QLatin1String("Set the debug level"));
+ generalOptions.insert(QLatin1String("silent"),
+ QLatin1String("Avoid printing any message"));
+ generalOptions.insert(QLatin1String("help"),
+ QLatin1String("Display this help and exit"));
+ generalOptions.insert(QLatin1String("no-suppress-warnings"),
+ QLatin1String("Show all warnings"));
+ generalOptions.insert(QLatin1String("output-directory=<path>"),
+ QLatin1String("The directory where the generated files will be written"));
+ generalOptions.insert(QLatin1String("include-paths=<path>[" PATH_SPLITTER "<path>" PATH_SPLITTER "...]"),
+ QLatin1String("Include paths used by the C++ parser"));
+ generalOptions.insert(QLatin1String("typesystem-paths=<path>[" PATH_SPLITTER "<path>" PATH_SPLITTER "...]"),
+ QLatin1String("Paths used when searching for typesystems"));
+ generalOptions.insert(QLatin1String("documentation-only"),
+ QLatin1String("Do not generates any code, just the documentation"));
+ generalOptions.insert(QLatin1String("license-file=<license-file>"),
+ QLatin1String("File used for copyright headers of generated files"));
+ generalOptions.insert(QLatin1String("version"),
+ QLatin1String("Output version information and exit"));
+ generalOptions.insert(QLatin1String("generator-set=<\"generator module\">"),
+ QLatin1String("generator-set to be used. e.g. qtdoc"));
+ generalOptions.insert(QLatin1String("api-version=<\"package mask\">,<\"version\">"),
+ QLatin1String("Specify the supported api version used to generate the bindings"));
+ generalOptions.insert(QLatin1String("drop-type-entries=\"<TypeEntry0>[;TypeEntry1;...]\""),
+ QLatin1String("Semicolon separated list of type system entries (classes, namespaces, global functions and enums) to be dropped from generation."));
+ printOptions(s, generalOptions);
+
+ const Generators generators = shibokenGenerators() + docGenerators();
+ foreach (const GeneratorPtr &generator, generators) {
+ QMap<QString, QString> options = generator->options();
+ if (!options.isEmpty()) {
+ s << endl << generator->name() << " options:\n";
+ printOptions(s, generator->options());
+ }
+ }
+}
+
+static inline void printVerAndBanner()
+{
+ std::cout << "shiboken v" SHIBOKEN_VERSION << std::endl;
+ std::cout << "Copyright (C) 2016 The Qt Company Ltd." << std::endl;
+}
+
+static inline void errorPrint(const QString& s)
+{
+ QStringList arguments = QCoreApplication::arguments();
+ arguments.pop_front();
+ std::cerr << "shiboken: " << qPrintable(s)
+ << "\nCommand line: " << qPrintable(arguments.join(QLatin1Char(' '))) << '\n';
+}
+
+static QString msgInvalidVersion(const QString &package, const QString &version)
+{
+ return QLatin1String("Invalid version \"") + version
+ + QLatin1String("\" specified for package ") + package + QLatin1Char('.');
+}
+
+int main(int argc, char *argv[])
+{
+ QElapsedTimer timer;
+ timer.start();
+ // needed by qxmlpatterns
+ QCoreApplication app(argc, argv);
+ ReportHandler::install();
+ qCDebug(lcShiboken()).noquote().nospace() << QCoreApplication::arguments().join(QLatin1Char(' '));
+
+ // Store command arguments in a map
+ QMap<QString, QString> args = getCommandLineArgs();
+ ArgsHandler argsHandler(args);
+ Generators generators;
+
+ if (argsHandler.argExistsRemove(QLatin1String("version"))) {
+ printVerAndBanner();
+ return EXIT_SUCCESS;
+ }
+
+ QString generatorSet = argsHandler.removeArg(QLatin1String("generator-set"));
+ // Also check QLatin1String("generatorSet") command line argument for backward compatibility.
+ if (generatorSet.isEmpty())
+ generatorSet = argsHandler.removeArg(QLatin1String("generatorSet"));
+
+ // Pre-defined generator sets.
+ if (generatorSet == QLatin1String("qtdoc")) {
+ generators = docGenerators();
+ if (generators.isEmpty()) {
+ errorPrint(QLatin1String("Doc strings extractions was not enabled in this shiboken build."));
+ return EXIT_FAILURE;
+ }
+ } else if (generatorSet.isEmpty() || generatorSet == QLatin1String("shiboken")) {
+ generators = shibokenGenerators();
+ } else {
+ errorPrint(QLatin1String("Unknown generator set, try \"shiboken\" or \"qtdoc\"."));
+ return EXIT_FAILURE;
+ }
+
+ if (argsHandler.argExistsRemove(QLatin1String("help"))) {
+ printUsage();
+ return EXIT_SUCCESS;
+ }
+
+ QString licenseComment;
+ QString licenseFileName = argsHandler.removeArg(QLatin1String("license-file"));
+ if (!licenseFileName.isEmpty()) {
+ if (QFile::exists(licenseFileName)) {
+ QFile licenseFile(licenseFileName);
+ if (licenseFile.open(QIODevice::ReadOnly))
+ licenseComment = QString::fromUtf8(licenseFile.readAll());
+ } else {
+ errorPrint(QStringLiteral("Couldn't find the file containing the license heading: %1").
+ arg(licenseFileName));
+ return EXIT_FAILURE;
+ }
+ }
+
+ QString outputDirectory = argsHandler.removeArg(QLatin1String("output-directory"));
+ if (outputDirectory.isEmpty())
+ outputDirectory = QLatin1String("out");
+
+ if (!QDir(outputDirectory).exists()) {
+ if (!QDir().mkpath(outputDirectory)) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Can't create output directory: " << QDir::toNativeSeparators(outputDirectory);
+ return EXIT_FAILURE;
+ }
+ }
+
+ // Create and set-up API Extractor
+ ApiExtractor extractor;
+ extractor.setLogDirectory(outputDirectory);
+
+ if (argsHandler.argExistsRemove(QLatin1String("silent"))) {
+ extractor.setSilent(true);
+ } else {
+ QString level = argsHandler.removeArg(QLatin1String("debug-level"));
+ if (!level.isEmpty()) {
+ if (level == QLatin1String("sparse"))
+ extractor.setDebugLevel(ReportHandler::SparseDebug);
+ else if (level == QLatin1String("medium"))
+ extractor.setDebugLevel(ReportHandler::MediumDebug);
+ else if (level == QLatin1String("full"))
+ extractor.setDebugLevel(ReportHandler::FullDebug);
+ }
+ }
+ if (argsHandler.argExistsRemove(QLatin1String("no-suppress-warnings")))
+ extractor.setSuppressWarnings(false);
+
+ if (argsHandler.argExists(QLatin1String("api-version"))) {
+ QStringList versions = argsHandler.removeArg(QLatin1String("api-version")).split(QLatin1Char('|'));
+ foreach (const QString &fullVersion, versions) {
+ QStringList parts = fullVersion.split(QLatin1Char(','));
+ QString package;
+ QString version;
+ // avoid constFirst to stay Qt 5.5 compatible
+ package = parts.count() == 1 ? QLatin1String("*") : parts.first();
+ version = parts.last();
+ if (!extractor.setApiVersion(package, version)) {
+ errorPrint(msgInvalidVersion(package, version));
+ return EXIT_FAILURE;
+ }
+ }
+ }
+
+ if (argsHandler.argExists(QLatin1String("drop-type-entries")))
+ extractor.setDropTypeEntries(argsHandler.removeArg(QLatin1String("drop-type-entries")));
+
+ QString path = argsHandler.removeArg(QLatin1String("typesystem-paths"));
+ if (!path.isEmpty())
+ extractor.addTypesystemSearchPath(path.split(QLatin1String(PATH_SPLITTER)));
+
+ path = argsHandler.removeArg(QLatin1String("include-paths"));
+ if (!path.isEmpty())
+ extractor.addIncludePath(path.split(QLatin1String(PATH_SPLITTER)));
+
+ QString cppFileName = argsHandler.removeArg(QLatin1String("arg-1"));
+ QString typeSystemFileName = argsHandler.removeArg(QLatin1String("arg-2"));
+
+ /* Make sure to remove the project file's arguments (if any) and
+ * --project-file, also the arguments of each generator before
+ * checking if there isn't any existing arguments in argsHandler.
+ */
+ argsHandler.removeArg(QLatin1String("project-file"));
+ QMap<QString, QString> projectFileArgs = getInitializedArguments();
+ if (!projectFileArgs.isEmpty()) {
+ QMap<QString, QString>::const_iterator it =
+ projectFileArgs.constBegin();
+ for ( ; it != projectFileArgs.constEnd(); ++it)
+ argsHandler.removeArg(it.key());
+ }
+ foreach (const GeneratorPtr &generator, generators) {
+ QMap<QString, QString> options = generator->options();
+ if (!options.isEmpty()) {
+ QMap<QString, QString>::const_iterator it = options.constBegin();
+ for ( ; it != options.constEnd(); ++it)
+ argsHandler.removeArg(it.key());
+ }
+ }
+
+ if (!argsHandler.noArgs()) {
+ errorPrint(argsHandler.errorMessage());
+ std::cout << "Note: use --help option for more information." << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ extractor.setCppFileName(cppFileName);
+ extractor.setTypeSystem(typeSystemFileName);
+ if (!extractor.run()) {
+ errorPrint(QLatin1String("Error running ApiExtractor."));
+ return EXIT_FAILURE;
+ }
+
+ if (!extractor.classCount())
+ qCWarning(lcShiboken) << "No C++ classes found!";
+
+ qCDebug(lcShiboken) << extractor;
+
+ foreach (const GeneratorPtr &g, generators) {
+ g->setOutputDirectory(outputDirectory);
+ g->setLicenseComment(licenseComment);
+ if (g->setup(extractor, args)) {
+ if (!g->generate()) {
+ errorPrint(QLatin1String("Error running generator: ")
+ + QLatin1String(g->name()) + QLatin1Char('.'));
+ return EXIT_FAILURE;
+ }
+ }
+ }
+
+ QByteArray doneMessage = "Done, " + QByteArray::number(timer.elapsed()) + "ms";
+ if (const int w = ReportHandler::warningCount())
+ doneMessage += ", " + QByteArray::number(w) + " warnings";
+ if (const int sw = ReportHandler::suppressedCount())
+ doneMessage += " (" + QByteArray::number(sw) + " known issues)";
+ qCDebug(lcShiboken()).noquote().nospace() << doneMessage;
+ std::cout << doneMessage.constData() << std::endl;
+
+ return EXIT_SUCCESS;
+}
diff --git a/sources/shiboken2/generator/qtdoc/CMakeLists.txt b/sources/shiboken2/generator/qtdoc/CMakeLists.txt
new file mode 100644
index 000000000..1361ba8f1
--- /dev/null
+++ b/sources/shiboken2/generator/qtdoc/CMakeLists.txt
@@ -0,0 +1,21 @@
+project(qtdoc_generator)
+
+set(qtdoc_generator_SRC
+qtdocgenerator.cpp
+)
+
+include_directories(${generators_SOURCE_DIR}
+ ${Qt5Core_INCLUDE_DIRS}
+ ${APIEXTRACTOR_INCLUDE_DIR})
+add_executable(docgenerator main.cpp)
+set_target_properties(docgenerator PROPERTIES OUTPUT_NAME docgenerator${generator_SUFFIX})
+
+target_link_libraries(docgenerator ${Qt5Core_LIBRARES})
+
+add_library(qtdoc_generator SHARED ${qtdoc_generator_SRC})
+target_link_libraries(qtdoc_generator ${APIEXTRACTOR_LIBRARY} ${Qt5Core_LIBRARES} genrunner)
+set_property(TARGET qtdoc_generator PROPERTY PREFIX "")
+
+install(TARGETS qtdoc_generator DESTINATION ${generator_plugin_DIR})
+install(TARGETS docgenerator DESTINATION bin)
+
diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
new file mode 100644
index 000000000..a7a176907
--- /dev/null
+++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
@@ -0,0 +1,1704 @@
+/****************************************************************************
+**
+** 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 "qtdocgenerator.h"
+#include <abstractmetalang.h>
+#include <reporthandler.h>
+#include <typesystem.h>
+#include <qtdocparser.h>
+#include <doxygenparser.h>
+#include <typedatabase.h>
+#include <algorithm>
+#include <QtCore/QStack>
+#include <QtCore/QTextStream>
+#include <QtCore/QXmlStreamReader>
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+#include <fileout.h>
+#include <limits>
+
+static Indentor INDENT;
+
+static bool shouldSkip(const AbstractMetaFunction* func)
+{
+ bool skipable = func->isConstructor()
+ || func->isModifiedRemoved()
+ || func->declaringClass() != func->ownerClass()
+ || func->isCastOperator()
+ || func->name() == QLatin1String("operator=");
+
+ // Search a const clone
+ if (!skipable && !func->isConstant()) {
+ const AbstractMetaArgumentList funcArgs = func->arguments();
+ foreach (AbstractMetaFunction* f, func->ownerClass()->functions()) {
+ if (f != func
+ && f->isConstant()
+ && f->name() == func->name()
+ && f->arguments().count() == funcArgs.count()) {
+ // Compare each argument
+ bool cloneFound = true;
+
+ const AbstractMetaArgumentList fargs = f->arguments();
+ for (int i = 0, max = funcArgs.count(); i < max; ++i) {
+ if (funcArgs.at(i)->type()->typeEntry() != fargs.at(i)->type()->typeEntry()) {
+ cloneFound = false;
+ break;
+ }
+ }
+ if (cloneFound)
+ return true;
+ }
+ }
+ }
+ return skipable;
+}
+
+static bool functionSort(const AbstractMetaFunction* func1, const AbstractMetaFunction* func2)
+{
+ return func1->name() < func2->name();
+}
+
+static QString createRepeatedChar(int i, char c)
+{
+ QString out;
+ for (int j = 0; j < i; ++j)
+ out += QLatin1Char(c);
+
+ return out;
+}
+
+static QString escape(QString str)
+{
+ str.replace(QLatin1Char('*'), QLatin1String("\\*"));
+ str.replace(QLatin1Char('_'), QLatin1String("\\_"));
+ return str;
+}
+
+static QString escape(const QStringRef& strref)
+{
+ QString str = strref.toString();
+ return escape(str);
+}
+
+
+QtXmlToSphinx::QtXmlToSphinx(QtDocGenerator* generator, const QString& doc, const QString& context)
+ : m_context(context), m_generator(generator), m_insideBold(false), m_insideItalic(false)
+{
+ m_handlerMap.insert(QLatin1String("heading"), &QtXmlToSphinx::handleHeadingTag);
+ m_handlerMap.insert(QLatin1String("brief"), &QtXmlToSphinx::handleParaTag);
+ m_handlerMap.insert(QLatin1String("para"), &QtXmlToSphinx::handleParaTag);
+ m_handlerMap.insert(QLatin1String("italic"), &QtXmlToSphinx::handleItalicTag);
+ m_handlerMap.insert(QLatin1String("bold"), &QtXmlToSphinx::handleBoldTag);
+ m_handlerMap.insert(QLatin1String("see-also"), &QtXmlToSphinx::handleSeeAlsoTag);
+ m_handlerMap.insert(QLatin1String("snippet"), &QtXmlToSphinx::handleSnippetTag);
+ m_handlerMap.insert(QLatin1String("dots"), &QtXmlToSphinx::handleDotsTag);
+ m_handlerMap.insert(QLatin1String("codeline"), &QtXmlToSphinx::handleDotsTag);
+ m_handlerMap.insert(QLatin1String("table"), &QtXmlToSphinx::handleTableTag);
+ m_handlerMap.insert(QLatin1String("header"), &QtXmlToSphinx::handleRowTag);
+ m_handlerMap.insert(QLatin1String("row"), &QtXmlToSphinx::handleRowTag);
+ m_handlerMap.insert(QLatin1String("item"), &QtXmlToSphinx::handleItemTag);
+ m_handlerMap.insert(QLatin1String("argument"), &QtXmlToSphinx::handleArgumentTag);
+ m_handlerMap.insert(QLatin1String("teletype"), &QtXmlToSphinx::handleArgumentTag);
+ m_handlerMap.insert(QLatin1String("link"), &QtXmlToSphinx::handleLinkTag);
+ m_handlerMap.insert(QLatin1String("inlineimage"), &QtXmlToSphinx::handleImageTag);
+ m_handlerMap.insert(QLatin1String("image"), &QtXmlToSphinx::handleImageTag);
+ m_handlerMap.insert(QLatin1String("list"), &QtXmlToSphinx::handleListTag);
+ m_handlerMap.insert(QLatin1String("term"), &QtXmlToSphinx::handleTermTag);
+ m_handlerMap.insert(QLatin1String("raw"), &QtXmlToSphinx::handleRawTag);
+ m_handlerMap.insert(QLatin1String("underline"), &QtXmlToSphinx::handleItalicTag);
+ m_handlerMap.insert(QLatin1String("superscript"), &QtXmlToSphinx::handleSuperScriptTag);
+ m_handlerMap.insert(QLatin1String("code"), &QtXmlToSphinx::handleCodeTag);
+ m_handlerMap.insert(QLatin1String("badcode"), &QtXmlToSphinx::handleCodeTag);
+ m_handlerMap.insert(QLatin1String("legalese"), &QtXmlToSphinx::handleCodeTag);
+ m_handlerMap.insert(QLatin1String("section"), &QtXmlToSphinx::handleAnchorTag);
+ m_handlerMap.insert(QLatin1String("quotefile"), &QtXmlToSphinx::handleQuoteFileTag);
+
+ // ignored tags
+ m_handlerMap.insert(QLatin1String("generatedlist"), &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert(QLatin1String("tableofcontents"), &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert(QLatin1String("quotefromfile"), &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert(QLatin1String("skipto"), &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert(QLatin1String("target"), &QtXmlToSphinx::handleIgnoredTag);
+
+ // useless tags
+ m_handlerMap.insert(QLatin1String("description"), &QtXmlToSphinx::handleUselessTag);
+ m_handlerMap.insert(QLatin1String("definition"), &QtXmlToSphinx::handleUselessTag);
+ m_handlerMap.insert(QLatin1String("printuntil"), &QtXmlToSphinx::handleUselessTag);
+ m_handlerMap.insert(QLatin1String("relation"), &QtXmlToSphinx::handleUselessTag);
+
+ // Doxygen tags
+ m_handlerMap.insert(QLatin1String("title"), &QtXmlToSphinx::handleHeadingTag);
+ m_handlerMap.insert(QLatin1String("ref"), &QtXmlToSphinx::handleParaTag);
+ m_handlerMap.insert(QLatin1String("computeroutput"), &QtXmlToSphinx::handleParaTag);
+ m_handlerMap.insert(QLatin1String("detaileddescription"), &QtXmlToSphinx::handleParaTag);
+ m_handlerMap.insert(QLatin1String("name"), &QtXmlToSphinx::handleParaTag);
+ m_handlerMap.insert(QLatin1String("listitem"), &QtXmlToSphinx::handleItemTag);
+ m_handlerMap.insert(QLatin1String("parametername"), &QtXmlToSphinx::handleItemTag);
+ m_handlerMap.insert(QLatin1String("parameteritem"), &QtXmlToSphinx::handleItemTag);
+ m_handlerMap.insert(QLatin1String("ulink"), &QtXmlToSphinx::handleLinkTag);
+ m_handlerMap.insert(QLatin1String("itemizedlist"), &QtXmlToSphinx::handleListTag);
+ m_handlerMap.insert(QLatin1String("parameternamelist"), &QtXmlToSphinx::handleListTag);
+ m_handlerMap.insert(QLatin1String("parameterlist"), &QtXmlToSphinx::handleListTag);
+
+ // Doxygen ignored tags
+ m_handlerMap.insert(QLatin1String("highlight"), &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert(QLatin1String("linebreak"), &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert(QLatin1String("programlisting"), &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert(QLatin1String("xreftitle"), &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert(QLatin1String("sp"), &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert(QLatin1String("entry"), &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert(QLatin1String("simplesect"), &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert(QLatin1String("verbatim"), &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert(QLatin1String("xrefsect"), &QtXmlToSphinx::handleIgnoredTag);
+ m_handlerMap.insert(QLatin1String("xrefdescription"), &QtXmlToSphinx::handleIgnoredTag);
+
+ m_result = transform(doc);
+}
+
+void QtXmlToSphinx::pushOutputBuffer()
+{
+ QString* buffer = new QString();
+ m_buffers << buffer;
+ m_output.setString(buffer);
+}
+
+QString QtXmlToSphinx::popOutputBuffer()
+{
+ Q_ASSERT(!m_buffers.isEmpty());
+ QString* str = m_buffers.pop();
+ QString strcpy(*str);
+ delete str;
+ m_output.setString(m_buffers.isEmpty() ? 0 : m_buffers.top());
+ return strcpy;
+}
+
+QString QtXmlToSphinx::expandFunction(const QString& function)
+{
+ QStringList functionSpec = function.split(QLatin1Char('.'));
+ QString className = functionSpec.first();
+ const AbstractMetaClass* metaClass = 0;
+ foreach (const AbstractMetaClass* cls, m_generator->classes()) {
+ if (cls->name() == className) {
+ metaClass = cls;
+ break;
+ }
+ }
+
+ if (metaClass) {
+ functionSpec.removeFirst();
+ return metaClass->typeEntry()->qualifiedTargetLangName()
+ + QLatin1Char('.') + functionSpec.join(QLatin1Char('.'));
+ } else {
+ return function;
+ }
+}
+
+QString QtXmlToSphinx::resolveContextForMethod(const QString& methodName)
+{
+ // avoid constLast to stay Qt 5.5 compatible
+ QString currentClass = m_context.split(QLatin1Char('.')).last();
+
+ const AbstractMetaClass* metaClass = 0;
+ foreach (const AbstractMetaClass* cls, m_generator->classes()) {
+ if (cls->name() == currentClass) {
+ metaClass = cls;
+ break;
+ }
+ }
+
+ if (metaClass) {
+ QList<const AbstractMetaFunction*> funcList;
+ foreach (const AbstractMetaFunction* func, metaClass->queryFunctionsByName(methodName)) {
+ if (methodName == func->name())
+ funcList.append(func);
+ }
+
+ const AbstractMetaClass* implementingClass = 0;
+ foreach (const AbstractMetaFunction* func, funcList) {
+ implementingClass = func->implementingClass();
+ if (implementingClass->name() == currentClass)
+ break;
+ }
+
+ if (implementingClass)
+ return implementingClass->typeEntry()->qualifiedTargetLangName();
+ }
+
+ return QLatin1Char('~') + m_context;
+}
+
+QString QtXmlToSphinx::transform(const QString& doc)
+{
+ Q_ASSERT(m_buffers.isEmpty());
+ Indentation indentation(INDENT);
+ if (doc.trimmed().isEmpty())
+ return doc;
+
+ pushOutputBuffer();
+
+ QXmlStreamReader reader(doc);
+
+ while (!reader.atEnd()) {
+ QXmlStreamReader::TokenType token = reader.readNext();
+ if (reader.hasError()) {
+ const QString message = QLatin1String("XML Error: ") + reader.errorString()
+ + QLatin1Char('\n') + doc;
+ m_output << INDENT << message;
+ qCWarning(lcShiboken).noquote().nospace() << message;
+ break;
+ }
+
+ if (token == QXmlStreamReader::StartElement) {
+ QStringRef tagName = reader.name();
+ TagHandler handler = m_handlerMap.value(tagName.toString(), &QtXmlToSphinx::handleUnknownTag);
+ if (!m_handlers.isEmpty() && ( (m_handlers.top() == &QtXmlToSphinx::handleIgnoredTag) ||
+ (m_handlers.top() == &QtXmlToSphinx::handleRawTag)) )
+ handler = &QtXmlToSphinx::handleIgnoredTag;
+
+ m_handlers.push(handler);
+ }
+ if (!m_handlers.isEmpty())
+ (this->*(m_handlers.top()))(reader);
+
+ if (token == QXmlStreamReader::EndElement) {
+ m_handlers.pop();
+ m_lastTagName = reader.name().toString();
+ }
+ }
+ m_output.flush();
+ QString retval = popOutputBuffer();
+ Q_ASSERT(m_buffers.isEmpty());
+ return retval;
+}
+
+QString QtXmlToSphinx::readFromLocations(const QStringList& locations, const QString& path, const QString& identifier)
+{
+ QString result;
+ bool ok;
+ foreach (QString location, locations) {
+ location.append(QLatin1Char('/'));
+ location.append(path);
+ result = readFromLocation(location, identifier, &ok);
+ if (ok)
+ break;
+ }
+ if (!ok) {
+ qCDebug(lcShiboken).noquote().nospace() << "Couldn't read code snippet file: {"
+ << locations.join(QLatin1Char('|')) << '}' << path;
+ }
+ return result;
+
+}
+
+QString QtXmlToSphinx::readFromLocation(const QString& location, const QString& identifier, bool* ok)
+{
+ QFile inputFile;
+ inputFile.setFileName(location);
+ if (!inputFile.open(QIODevice::ReadOnly)) {
+ if (!ok) {
+ qCDebug(lcShiboken).noquote().nospace() << "Couldn't read code snippet file: "
+ << QDir::toNativeSeparators(inputFile.fileName());
+ } else {
+ *ok = false;
+ }
+ return QString();
+ }
+
+ QRegExp searchString(QLatin1String("//!\\s*\\[") + identifier + QLatin1String("\\]"));
+ QRegExp codeSnippetCode(QLatin1String("//!\\s*\\[[\\w\\d\\s]+\\]"));
+ QString code;
+
+ bool identifierIsEmpty = identifier.isEmpty();
+ bool getCode = false;
+
+ while (!inputFile.atEnd()) {
+ QString line = QString::fromUtf8(inputFile.readLine());
+ if (identifierIsEmpty) {
+ code += line;
+ } else if (getCode && !line.contains(searchString)) {
+ line.remove(codeSnippetCode);
+ code += line;
+ } else if (line.contains(searchString)) {
+ if (getCode)
+ break;
+ else
+ getCode = true;
+ }
+ }
+
+ if (!identifierIsEmpty && !getCode) {
+ qCDebug(lcShiboken).noquote().nospace() << "Code snippet file found ("
+ << location << "), but snippet " << identifier << " not found.";
+ }
+
+ if (ok)
+ *ok = true;
+ return code;
+}
+
+void QtXmlToSphinx::handleHeadingTag(QXmlStreamReader& reader)
+{
+ static QString heading;
+ static char type;
+ static char types[] = { '-', '^' };
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ uint typeIdx = reader.attributes().value(QLatin1String("level")).toString().toInt();
+ if (typeIdx >= sizeof(types))
+ type = types[sizeof(types)-1];
+ else
+ type = types[typeIdx];
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_output << createRepeatedChar(heading.length(), type) << endl << endl;
+ } else if (token == QXmlStreamReader::Characters) {
+ heading = escape(reader.text()).trimmed();
+ m_output << endl << endl << heading << endl;
+ }
+}
+
+void QtXmlToSphinx::handleParaTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ pushOutputBuffer();
+ } else if (token == QXmlStreamReader::EndElement) {
+ QString result = popOutputBuffer().simplified();
+ if (result.startsWith(QLatin1String("**Warning:**")))
+ result.replace(0, 12, QLatin1String(".. warning:: "));
+ else if (result.startsWith(QLatin1String("**Note:**")))
+ result.replace(0, 9, QLatin1String(".. note:: "));
+
+ m_output << INDENT << result << endl << endl;
+ } else if (token == QXmlStreamReader::Characters) {
+ QString text = escape(reader.text());
+ if (!m_output.string()->isEmpty()) {
+ QChar start = text[0];
+ QChar end = m_output.string()->at(m_output.string()->length() - 1);
+ if ((end == QLatin1Char('*') || end == QLatin1Char('`')) && start != QLatin1Char(' ') && !start.isPunct())
+ m_output << '\\';
+ }
+ m_output << INDENT << text;
+ }
+}
+
+void QtXmlToSphinx::handleItalicTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement || token == QXmlStreamReader::EndElement) {
+ m_insideItalic = !m_insideItalic;
+ m_output << '*';
+ } else if (token == QXmlStreamReader::Characters) {
+ m_output << escape(reader.text()).trimmed();
+ }
+}
+
+void QtXmlToSphinx::handleBoldTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement || token == QXmlStreamReader::EndElement) {
+ m_insideBold = !m_insideBold;
+ m_output << "**";
+ } else if (token == QXmlStreamReader::Characters) {
+ m_output << escape(reader.text()).trimmed();
+ }
+}
+
+void QtXmlToSphinx::handleArgumentTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement || token == QXmlStreamReader::EndElement)
+ m_output << "``";
+ else if (token == QXmlStreamReader::Characters)
+ m_output << reader.text().toString().trimmed();
+}
+
+void QtXmlToSphinx::handleSeeAlsoTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement)
+ m_output << INDENT << ".. seealso:: ";
+ else if (token == QXmlStreamReader::EndElement)
+ m_output << endl;
+}
+
+void QtXmlToSphinx::handleSnippetTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ const bool consecutiveSnippet = m_lastTagName == QLatin1String("snippet")
+ || m_lastTagName == QLatin1String("dots") || m_lastTagName == QLatin1String("codeline");
+ if (consecutiveSnippet) {
+ m_output.flush();
+ m_output.string()->chop(2);
+ }
+ QString location = reader.attributes().value(QLatin1String("location")).toString();
+ QString identifier = reader.attributes().value(QLatin1String("identifier")).toString();
+ QString code = readFromLocations(m_generator->codeSnippetDirs(), location, identifier);
+ if (!consecutiveSnippet)
+ m_output << INDENT << "::\n\n";
+
+ Indentation indentation(INDENT);
+ if (code.isEmpty()) {
+ m_output << INDENT << "<Code snippet \"" << location << ':' << identifier << "\" not found>" << endl;
+ } else {
+ foreach (const QString &line, code.split(QLatin1Char('\n'))) {
+ if (!QString(line).trimmed().isEmpty())
+ m_output << INDENT << line;
+
+ m_output << endl;
+ }
+ }
+ m_output << endl;
+ }
+}
+void QtXmlToSphinx::handleDotsTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ const bool consecutiveSnippet = m_lastTagName == QLatin1String("snippet")
+ || m_lastTagName == QLatin1String("dots") || m_lastTagName == QLatin1String("codeline");
+ if (consecutiveSnippet) {
+ m_output.flush();
+ m_output.string()->chop(2);
+ }
+ Indentation indentation(INDENT);
+ pushOutputBuffer();
+ m_output << INDENT;
+ int indent = reader.attributes().value(QLatin1String("indent")).toString().toInt();
+ for (int i = 0; i < indent; ++i)
+ m_output << ' ';
+ } else if (token == QXmlStreamReader::Characters) {
+ m_output << reader.text().toString();
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_output << popOutputBuffer() << "\n\n\n";
+ }
+}
+
+void QtXmlToSphinx::handleTableTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ m_currentTable.clear();
+ m_tableHasHeader = false;
+ } else if (token == QXmlStreamReader::EndElement) {
+ // write the table on m_output
+ m_currentTable.enableHeader(m_tableHasHeader);
+ m_currentTable.normalize();
+ m_output << m_currentTable;
+ m_currentTable.clear();
+ }
+}
+
+void QtXmlToSphinx::handleTermTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ pushOutputBuffer();
+ } else if (token == QXmlStreamReader::Characters) {
+ m_output << reader.text().toString().replace(QLatin1String("::"), QLatin1String("."));
+ } else if (token == QXmlStreamReader::EndElement) {
+ TableCell cell;
+ cell.data = popOutputBuffer().trimmed();
+ m_currentTable << (TableRow() << cell);
+ }
+}
+
+
+void QtXmlToSphinx::handleItemTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ if (m_currentTable.isEmpty())
+ m_currentTable << TableRow();
+ TableRow& row = m_currentTable.last();
+ TableCell cell;
+ cell.colSpan = reader.attributes().value(QLatin1String("colspan")).toString().toShort();
+ cell.rowSpan = reader.attributes().value(QLatin1String("rowspan")).toString().toShort();
+ row << cell;
+ pushOutputBuffer();
+ } else if (token == QXmlStreamReader::EndElement) {
+ QString data = popOutputBuffer().trimmed();
+ if (!m_currentTable.isEmpty()) {
+ TableRow& row = m_currentTable.last();
+ if (!row.isEmpty())
+ row.last().data = data;
+ }
+ }
+}
+
+void QtXmlToSphinx::handleRowTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ m_tableHasHeader = reader.name() == QLatin1String("header");
+ m_currentTable << TableRow();
+ }
+}
+
+void QtXmlToSphinx::handleListTag(QXmlStreamReader& reader)
+{
+ // BUG We do not support a list inside a table cell
+ static QString listType;
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ listType = reader.attributes().value(QLatin1String("type")).toString();
+ if (listType == QLatin1String("enum")) {
+ m_currentTable << (TableRow() << "Constant" << "Description");
+ m_tableHasHeader = true;
+ }
+ INDENT.indent--;
+ } else if (token == QXmlStreamReader::EndElement) {
+ INDENT.indent++;
+ if (!m_currentTable.isEmpty()) {
+ if (listType == QLatin1String("bullet")) {
+ m_output << endl;
+ foreach (TableCell cell, m_currentTable.first()) {
+ QStringList itemLines = cell.data.split(QLatin1Char('\n'));
+ m_output << INDENT << "* " << itemLines.first() << endl;
+ for (int i = 1, max = itemLines.count(); i < max; ++i)
+ m_output << INDENT << " " << itemLines[i] << endl;
+ }
+ m_output << endl;
+ } else if (listType == QLatin1String("enum")) {
+ m_currentTable.enableHeader(m_tableHasHeader);
+ m_currentTable.normalize();
+ m_output << m_currentTable;
+ }
+ }
+ m_currentTable.clear();
+ }
+}
+
+void QtXmlToSphinx::handleLinkTag(QXmlStreamReader& reader)
+{
+ static QString l_linktag;
+ static QString l_linkref;
+ static QString l_linktext;
+ static QString l_linktagending;
+ static QString l_type;
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ l_linktagending = QLatin1String("` ");
+ if (m_insideBold) {
+ l_linktag.prepend(QLatin1String("**"));
+ l_linktagending.append(QLatin1String("**"));
+ } else if (m_insideItalic) {
+ l_linktag.prepend(QLatin1Char('*'));
+ l_linktagending.append(QLatin1Char('*'));
+ }
+ l_type = reader.attributes().value(QLatin1String("type")).toString();
+
+ // TODO: create a flag PROPERTY-AS-FUNCTION to ask if the properties
+ // are recognized as such or not in the binding
+ if (l_type == QLatin1String("property"))
+ l_type = QLatin1String("function");
+
+ if (l_type == QLatin1String("typedef"))
+ l_type = QLatin1String("class");
+
+ QString linkSource;
+ if (l_type == QLatin1String("function") || l_type == QLatin1String("class")) {
+ linkSource = QLatin1String("raw");
+ } else if (l_type == QLatin1String("enum")) {
+ linkSource = QLatin1String("enum");
+ } else if (l_type == QLatin1String("page")) {
+ linkSource = QLatin1String("page");
+ } else {
+ linkSource = QLatin1String("href");
+ }
+
+ l_linkref = reader.attributes().value(linkSource).toString();
+ l_linkref.replace(QLatin1String("::"), QLatin1String("."));
+ l_linkref.remove(QLatin1String("()"));
+
+ if (l_type == QLatin1String("function") && !m_context.isEmpty()) {
+ l_linktag = QLatin1String(" :meth:`");
+ QStringList rawlinklist = l_linkref.split(QLatin1Char('.'));
+ if (rawlinklist.size() == 1 || rawlinklist.first() == m_context) {
+ QString context = resolveContextForMethod(rawlinklist.last());
+ if (!l_linkref.startsWith(context))
+ l_linkref.prepend(context + QLatin1Char('.'));
+ } else {
+ l_linkref = expandFunction(l_linkref);
+ }
+ } else if (l_type == QLatin1String("function") && m_context.isEmpty()) {
+ l_linktag = QLatin1String(" :func:`");
+ } else if (l_type == QLatin1String("class")) {
+ l_linktag = QLatin1String(" :class:`");
+ TypeEntry* type = TypeDatabase::instance()->findType(l_linkref);
+ if (type) {
+ l_linkref = type->qualifiedTargetLangName();
+ } else { // fall back to the old heuristic if the type wasn't found.
+ QStringList rawlinklist = l_linkref.split(QLatin1Char('.'));
+ QStringList splittedContext = m_context.split(QLatin1Char('.'));
+ if (rawlinklist.size() == 1 || rawlinklist.first() == splittedContext.last()) {
+ splittedContext.removeLast();
+ l_linkref.prepend(QLatin1Char('~') + splittedContext.join(QLatin1Char('.'))
+ + QLatin1Char('.'));
+ }
+ }
+ } else if (l_type == QLatin1String("enum")) {
+ l_linktag = QLatin1String(" :attr:`");
+ } else if (l_type == QLatin1String("page") && l_linkref == m_generator->moduleName()) {
+ l_linktag = QLatin1String(" :mod:`");
+ } else {
+ l_linktag = QLatin1String(" :ref:`");
+ }
+
+ } else if (token == QXmlStreamReader::Characters) {
+ QString linktext = reader.text().toString();
+ linktext.replace(QLatin1String("::"), QLatin1String("."));
+ // avoid constLast to stay Qt 5.5 compatible
+ QString item = l_linkref.split(QLatin1Char('.')).last();
+ if (l_linkref == linktext
+ || (l_linkref + QLatin1String("()")) == linktext
+ || item == linktext
+ || (item + QLatin1String("()")) == linktext)
+ l_linktext.clear();
+ else
+ l_linktext = linktext + QLatin1Char('<');
+ } else if (token == QXmlStreamReader::EndElement) {
+ if (!l_linktext.isEmpty())
+ l_linktagending.prepend(QLatin1Char('>'));
+ m_output << l_linktag << l_linktext << escape(l_linkref) << l_linktagending;
+ }
+}
+
+void QtXmlToSphinx::handleImageTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ QString href = reader.attributes().value(QLatin1String("href")).toString();
+ QString packageName = m_generator->packageName();
+ packageName.replace(QLatin1Char('.'), QLatin1Char('/'));
+ QDir dir(m_generator->outputDirectory() + QLatin1Char('/') + packageName);
+ QString imgPath = dir.relativeFilePath(m_generator->libSourceDir() + QLatin1String("/doc/src/"))
+ + QLatin1Char('/') + href;
+
+ if (reader.name() == QLatin1String("image"))
+ m_output << INDENT << ".. image:: " << imgPath << endl << endl;
+ else
+ m_output << ".. image:: " << imgPath << ' ';
+ }
+}
+
+void QtXmlToSphinx::handleRawTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ QString format = reader.attributes().value(QLatin1String("format")).toString();
+ m_output << INDENT << ".. raw:: " << format.toLower() << endl << endl;
+ } else if (token == QXmlStreamReader::Characters) {
+ QStringList lst(reader.text().toString().split(QLatin1Char('\n')));
+ foreach(QString row, lst)
+ m_output << INDENT << INDENT << row << endl;
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_output << endl << endl;
+ }
+}
+
+void QtXmlToSphinx::handleCodeTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ QString format = reader.attributes().value(QLatin1String("format")).toString();
+ m_output << INDENT << "::" << endl << endl;
+ INDENT.indent++;
+ } else if (token == QXmlStreamReader::Characters) {
+ QStringList lst(reader.text().toString().split(QLatin1Char('\n')));
+ foreach(QString row, lst)
+ m_output << INDENT << INDENT << row << endl;
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_output << endl << endl;
+ INDENT.indent--;
+ }
+}
+
+void QtXmlToSphinx::handleUnknownTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement)
+ qCDebug(lcShiboken).noquote().nospace() << "Unknown QtDoc tag: \"" << reader.name().toString() << "\".";
+}
+
+void QtXmlToSphinx::handleSuperScriptTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ m_output << " :sup:`";
+ pushOutputBuffer();
+ } else if (token == QXmlStreamReader::Characters) {
+ m_output << reader.text().toString();
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_output << popOutputBuffer();
+ m_output << '`';
+ }
+}
+
+void QtXmlToSphinx::handleIgnoredTag(QXmlStreamReader&)
+{
+}
+
+void QtXmlToSphinx::handleUselessTag(QXmlStreamReader&)
+{
+ // Tag "description" just marks the init of "Detailed description" title.
+ // Tag "definition" just marks enums. We have a different way to process them.
+}
+
+void QtXmlToSphinx::handleAnchorTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::StartElement) {
+ QString anchor;
+ if (reader.attributes().hasAttribute(QLatin1String("id")))
+ anchor = reader.attributes().value(QLatin1String("id")).toString();
+ else if (reader.attributes().hasAttribute(QLatin1String("name")))
+ anchor = reader.attributes().value(QLatin1String("name")).toString();
+ if (!anchor.isEmpty() && m_opened_anchor != anchor) {
+ m_opened_anchor = anchor;
+ m_output << INDENT << ".. _" << m_context << "_" << anchor.toLower() << ":" << endl << endl;
+ }
+ } else if (token == QXmlStreamReader::EndElement) {
+ m_opened_anchor.clear();
+ }
+}
+
+void QtXmlToSphinx::handleQuoteFileTag(QXmlStreamReader& reader)
+{
+ QXmlStreamReader::TokenType token = reader.tokenType();
+ if (token == QXmlStreamReader::Characters) {
+ QString location = reader.text().toString();
+ QString identifier;
+ location.prepend(m_generator->libSourceDir() + QLatin1Char('/'));
+ QString code = readFromLocation(location, identifier);
+
+ m_output << INDENT << "::\n\n";
+ Indentation indentation(INDENT);
+ if (code.isEmpty()) {
+ m_output << INDENT << "<Code snippet \"" << location << "\" not found>" << endl;
+ } else {
+ foreach (QString line, code.split(QLatin1Char('\n'))) {
+ if (!QString(line).trimmed().isEmpty())
+ m_output << INDENT << line;
+
+ m_output << endl;
+ }
+ }
+ m_output << endl;
+ }
+}
+
+void QtXmlToSphinx::Table::normalize()
+{
+ if (m_normalized || isEmpty())
+ return;
+
+ int row;
+ int col;
+ QtXmlToSphinx::Table& self = *this;
+
+ //QDoc3 generates tables with wrong number of columns. We have to
+ //check and if necessary, merge the last columns.
+ int maxCols = self.at(0).count();
+ // add col spans
+ for (row = 0; row < count(); ++row) {
+ for (col = 0; col < at(row).count(); ++col) {
+ QtXmlToSphinx::TableCell& cell = self[row][col];
+ bool mergeCols = (col >= maxCols);
+ if (cell.colSpan > 0) {
+ QtXmlToSphinx::TableCell newCell;
+ newCell.colSpan = -1;
+ for (int i = 0, max = cell.colSpan-1; i < max; ++i) {
+ self[row].insert(col+1, newCell);
+ }
+ cell.colSpan = 0;
+ col++;
+ } else if (mergeCols) {
+ self[row][maxCols - 1].data += QLatin1Char(' ') + cell.data;
+ }
+ }
+ }
+
+ // row spans
+ const int numCols = first().count();
+ for (col = 0; col < numCols; ++col) {
+ for (row = 0; row < count(); ++row) {
+ if (col < self[row].count()) {
+ QtXmlToSphinx::TableCell& cell = self[row][col];
+ if (cell.rowSpan > 0) {
+ QtXmlToSphinx::TableCell newCell;
+ newCell.rowSpan = -1;
+ int max = std::min(cell.rowSpan - 1, count());
+ cell.rowSpan = 0;
+ for (int i = 0; i < max; ++i) {
+ self[row+i+1].insert(col, newCell);
+ }
+ row++;
+ }
+ }
+ }
+ }
+ m_normalized = true;
+}
+
+QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table)
+{
+ if (table.isEmpty())
+ return s;
+
+ if (!table.isNormalized()) {
+ qCDebug(lcShiboken) << "Attempt to print an unnormalized table!";
+ return s;
+ }
+
+ // calc width and height of each column and row
+ QVector<int> colWidths(table.first().count());
+ QVector<int> rowHeights(table.count());
+ for (int i = 0, maxI = table.count(); i < maxI; ++i) {
+ const QtXmlToSphinx::TableRow& row = table[i];
+ for (int j = 0, maxJ = std::min(row.count(), colWidths.size()); j < maxJ; ++j) {
+ QStringList rowLines = row[j].data.split(QLatin1Char('\n')); // cache this would be a good idea
+ foreach (QString str, rowLines)
+ colWidths[j] = std::max(colWidths[j], str.count());
+ rowHeights[i] = std::max(rowHeights[i], row[j].data.count(QLatin1Char('\n')) + 1);
+ }
+ }
+
+ if (!*std::max_element(colWidths.begin(), colWidths.end()))
+ return s; // empty table (table with empty cells)
+
+ // create a horizontal line to be used later.
+ QString horizontalLine = QLatin1String("+");
+ for (int i = 0, max = colWidths.count(); i < max; ++i) {
+ horizontalLine += createRepeatedChar(colWidths[i], '-');
+ horizontalLine += QLatin1Char('+');
+ }
+
+ // write table rows
+ for (int i = 0, maxI = table.count(); i < maxI; ++i) { // for each row
+ const QtXmlToSphinx::TableRow& row = table[i];
+
+ // print line
+ s << INDENT << '+';
+ for (int col = 0, max = colWidths.count(); col < max; ++col) {
+ char c;
+ if (col >= row.length() || row[col].rowSpan == -1)
+ c = ' ';
+ else if (i == 1 && table.hasHeader())
+ c = '=';
+ else
+ c = '-';
+ s << createRepeatedChar(colWidths[col], c) << '+';
+ }
+ s << endl;
+
+
+ // Print the table cells
+ for (int rowLine = 0; rowLine < rowHeights[i]; ++rowLine) { // for each line in a row
+ for (int j = 0, maxJ = std::min(row.count(), colWidths.size()); j < maxJ; ++j) { // for each column
+ const QtXmlToSphinx::TableCell& cell = row[j];
+ QStringList rowLines = cell.data.split(QLatin1Char('\n')); // FIXME: Cache this!!!
+ if (!j) // First column, so we need print the identation
+ s << INDENT;
+
+ if (!j || !cell.colSpan)
+ s << '|';
+ else
+ s << ' ';
+ s << qSetFieldWidth(colWidths[j]) << left;
+ s << (rowLine < rowLines.count() ? rowLines[rowLine] : QString());
+ s << qSetFieldWidth(0);
+ }
+ s << '|' << endl;
+ }
+ }
+ s << INDENT << horizontalLine << endl;
+ s << endl;
+ return s;
+}
+
+static QString getFuncName(const AbstractMetaFunction* cppFunc) {
+ static bool hashInitialized = false;
+ static QHash<QString, QString> operatorsHash;
+ if (!hashInitialized) {
+ operatorsHash.insert(QLatin1String("operator+"), QLatin1String("__add__"));
+ operatorsHash.insert(QLatin1String("operator+="), QLatin1String("__iadd__"));
+ operatorsHash.insert(QLatin1String("operator-"), QLatin1String("__sub__"));
+ operatorsHash.insert(QLatin1String("operator-="), QLatin1String("__isub__"));
+ operatorsHash.insert(QLatin1String("operator*"), QLatin1String("__mul__"));
+ operatorsHash.insert(QLatin1String("operator*="), QLatin1String("__imul__"));
+ operatorsHash.insert(QLatin1String("operator/"), QLatin1String("__div__"));
+ operatorsHash.insert(QLatin1String("operator/="), QLatin1String("__idiv__"));
+ operatorsHash.insert(QLatin1String("operator%"), QLatin1String("__mod__"));
+ operatorsHash.insert(QLatin1String("operator%="), QLatin1String("__imod__"));
+ operatorsHash.insert(QLatin1String("operator<<"), QLatin1String("__lshift__"));
+ operatorsHash.insert(QLatin1String("operator<<="), QLatin1String("__ilshift__"));
+ operatorsHash.insert(QLatin1String("operator>>"), QLatin1String("__rshift__"));
+ operatorsHash.insert(QLatin1String("operator>>="), QLatin1String("__irshift__"));
+ operatorsHash.insert(QLatin1String("operator&"), QLatin1String("__and__"));
+ operatorsHash.insert(QLatin1String("operator&="), QLatin1String("__iand__"));
+ operatorsHash.insert(QLatin1String("operator|"), QLatin1String("__or__"));
+ operatorsHash.insert(QLatin1String("operator|="), QLatin1String("__ior__"));
+ operatorsHash.insert(QLatin1String("operator^"), QLatin1String("__xor__"));
+ operatorsHash.insert(QLatin1String("operator^="), QLatin1String("__ixor__"));
+ operatorsHash.insert(QLatin1String("operator=="), QLatin1String("__eq__"));
+ operatorsHash.insert(QLatin1String("operator!="), QLatin1String("__ne__"));
+ operatorsHash.insert(QLatin1String("operator<"), QLatin1String("__lt__"));
+ operatorsHash.insert(QLatin1String("operator<="), QLatin1String("__le__"));
+ operatorsHash.insert(QLatin1String("operator>"), QLatin1String("__gt__"));
+ operatorsHash.insert(QLatin1String("operator>="), QLatin1String("__ge__"));
+ hashInitialized = true;
+ }
+
+ QHash<QString, QString>::const_iterator it = operatorsHash.find(cppFunc->name());
+ QString result = it != operatorsHash.end() ? it.value() : cppFunc->name();
+ result.replace(QLatin1String("::"), QLatin1String("."));
+ return result;
+}
+
+QtDocGenerator::QtDocGenerator() : m_docParser(0)
+{
+}
+
+QtDocGenerator::~QtDocGenerator()
+{
+ delete m_docParser;
+}
+
+QString QtDocGenerator::fileNamePrefix() const
+{
+ return QLatin1String(".rst");
+}
+
+QString QtDocGenerator::fileNameForContext(GeneratorContext &context) const
+{
+ const AbstractMetaClass *metaClass = context.metaClass();
+ if (!context.forSmartPointer()) {
+ return getClassTargetFullName(metaClass, false) + fileNamePrefix();
+ } else {
+ const AbstractMetaType *smartPointerType = context.preciseType();
+ QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass);
+ return fileNameBase + fileNamePrefix();
+ }
+}
+
+void QtDocGenerator::writeFormatedText(QTextStream& s, const Documentation& doc, const AbstractMetaClass* metaClass)
+{
+ QString metaClassName;
+
+ if (metaClass)
+ metaClassName = getClassTargetFullName(metaClass);
+
+ if (doc.format() == Documentation::Native) {
+ QtXmlToSphinx x(this, doc.value(), metaClassName);
+ s << x;
+ } else {
+ QStringList lines = doc.value().split(QLatin1Char('\n'));
+ QRegExp regex(QLatin1String("\\S")); // non-space character
+ int typesystemIndentation = std::numeric_limits<int>().max();
+ // check how many spaces must be removed from the begining of each line
+ foreach (QString line, lines) {
+ int idx = line.indexOf(regex);
+ if (idx >= 0)
+ typesystemIndentation = qMin(typesystemIndentation, idx);
+ }
+ foreach (QString line, lines)
+ s << INDENT << line.remove(0, typesystemIndentation) << endl;
+ }
+
+ s << endl;
+}
+
+static void writeInheritedByList(QTextStream& s, const AbstractMetaClass* metaClass, const AbstractMetaClassList& allClasses)
+{
+ AbstractMetaClassList res;
+ foreach (AbstractMetaClass* c, allClasses) {
+ if (c != metaClass && c->inheritsFrom(metaClass))
+ res << c;
+ }
+
+ if (res.isEmpty())
+ return;
+
+ s << "**Inherited by:** ";
+ QStringList classes;
+ foreach (AbstractMetaClass* c, res)
+ classes << QLatin1String(":ref:`") + getClassTargetFullName(c, false) + QLatin1Char('`');
+ s << classes.join(QLatin1String(", ")) << endl << endl;
+}
+
+void QtDocGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
+{
+ AbstractMetaClass *metaClass = classContext.metaClass();
+ qCDebug(lcShiboken).noquote().nospace() << "Generating Documentation for " << metaClass->fullName();
+
+ m_packages[metaClass->package()] << fileNameForContext(classContext);
+
+ m_docParser->setPackageName(metaClass->package());
+ m_docParser->fillDocumentation(const_cast<AbstractMetaClass*>(metaClass));
+
+ s << ".. module:: " << metaClass->package() << endl;
+ QString className = getClassTargetFullName(metaClass, false);
+ s << ".. _" << className << ":" << endl << endl;
+
+ s << className << endl;
+ s << createRepeatedChar(className.count(), '*') << endl << endl;
+
+ s << ".. inheritance-diagram:: " << className << endl
+ << " :parts: 2" << endl << endl; // TODO: This would be a parameter in the future...
+
+
+ writeInheritedByList(s, metaClass, classes());
+
+ if (metaClass->typeEntry() && (metaClass->typeEntry()->version() != 0))
+ s << ".. note:: This class was introduced in Qt " << metaClass->typeEntry()->version() << endl;
+
+ writeFunctionList(s, metaClass);
+
+ //Function list
+ AbstractMetaFunctionList functionList = metaClass->functions();
+ qSort(functionList.begin(), functionList.end(), functionSort);
+
+ s << "Detailed Description\n"
+ "--------------------\n\n";
+
+ writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, metaClass, 0);
+ if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, metaClass, 0))
+ writeFormatedText(s, metaClass->documentation(), metaClass);
+
+ if (!metaClass->isNamespace())
+ writeConstructors(s, metaClass);
+ writeEnums(s, metaClass);
+ if (!metaClass->isNamespace())
+ writeFields(s, metaClass);
+
+
+ foreach (AbstractMetaFunction* func, functionList) {
+ if (shouldSkip(func))
+ continue;
+
+ if (func->isStatic())
+ s << ".. staticmethod:: ";
+ else
+ s << ".. method:: ";
+
+ writeFunction(s, true, metaClass, func);
+ }
+
+ writeInjectDocumentation(s, TypeSystem::DocModificationAppend, metaClass, 0);
+}
+
+void QtDocGenerator::writeFunctionList(QTextStream& s, const AbstractMetaClass* cppClass)
+{
+ QStringList functionList;
+ QStringList virtualList;
+ QStringList signalList;
+ QStringList slotList;
+ QStringList staticFunctionList;
+
+ foreach (AbstractMetaFunction* func, cppClass->functions()) {
+ if (shouldSkip(func))
+ continue;
+
+ QString className;
+ if (!func->isConstructor())
+ className = getClassTargetFullName(cppClass) + QLatin1Char('.');
+ else if (func->implementingClass() && func->implementingClass()->enclosingClass())
+ className = getClassTargetFullName(func->implementingClass()->enclosingClass()) + QLatin1Char('.');
+ QString funcName = getFuncName(func);
+
+ QString str = QLatin1String("def :meth:`");
+
+ str += funcName;
+ str += QLatin1Char('<');
+ if (!funcName.startsWith(className))
+ str += className;
+ str += funcName;
+ str += QLatin1String(">` (");
+ str += parseArgDocStyle(cppClass, func);
+ str += QLatin1Char(')');
+
+ if (func->isStatic())
+ staticFunctionList << str;
+ else if (func->isVirtual())
+ virtualList << str;
+ else if (func->isSignal())
+ signalList << str;
+ else if (func->isSlot())
+ slotList << str;
+ else
+ functionList << str;
+ }
+
+ if ((functionList.size() > 0) || (staticFunctionList.size() > 0)) {
+ QtXmlToSphinx::Table functionTable;
+ QtXmlToSphinx::TableRow row;
+
+ s << "Synopsis" << endl
+ << "--------" << endl << endl;
+
+ writeFunctionBlock(s, QLatin1String("Functions"), functionList);
+ writeFunctionBlock(s, QLatin1String("Virtual functions"), virtualList);
+ writeFunctionBlock(s, QLatin1String("Slots"), slotList);
+ writeFunctionBlock(s, QLatin1String("Signals"), signalList);
+ writeFunctionBlock(s, QLatin1String("Static functions"), staticFunctionList);
+ }
+}
+
+void QtDocGenerator::writeFunctionBlock(QTextStream& s, const QString& title, QStringList& functions)
+{
+ if (functions.size() > 0) {
+ s << title << endl
+ << QString(title.size(), QLatin1Char('^')) << endl;
+
+ qSort(functions);
+
+ s << ".. container:: function_list" << endl << endl;
+ Indentation indentation(INDENT);
+ foreach (QString func, functions)
+ s << '*' << INDENT << func << endl;
+
+ s << endl << endl;
+ }
+}
+
+void QtDocGenerator::writeEnums(QTextStream& s, const AbstractMetaClass* cppClass)
+{
+ static const QString section_title = QLatin1String(".. attribute:: ");
+
+ foreach (AbstractMetaEnum* en, cppClass->enums()) {
+ s << section_title << getClassTargetFullName(cppClass) << '.' << en->name() << endl << endl;
+ writeFormatedText(s, en->documentation(), cppClass);
+
+ if (en->typeEntry() && (en->typeEntry()->version() != 0))
+ s << ".. note:: This enum was introduced or modified in Qt " << en->typeEntry()->version() << endl;
+ }
+
+}
+
+void QtDocGenerator::writeFields(QTextStream& s, const AbstractMetaClass* cppClass)
+{
+ static const QString section_title = QLatin1String(".. attribute:: ");
+
+ foreach (AbstractMetaField* field, cppClass->fields()) {
+ s << section_title << getClassTargetFullName(cppClass) << "." << field->name() << endl << endl;
+ //TODO: request for member ‘documentation’ is ambiguous
+ writeFormatedText(s, field->AbstractMetaAttributes::documentation(), cppClass);
+ }
+}
+
+void QtDocGenerator::writeConstructors(QTextStream& s, const AbstractMetaClass* cppClass)
+{
+ static const QString sectionTitle = QLatin1String(".. class:: ");
+ static const QString sectionTitleSpace = QString(sectionTitle.size(), QLatin1Char(' '));
+
+ AbstractMetaFunctionList lst = cppClass->queryFunctions(AbstractMetaClass::Constructors | AbstractMetaClass::Visible);
+
+ bool first = true;
+ QHash<QString, AbstractMetaArgument*> arg_map;
+
+ foreach(AbstractMetaFunction* func, lst) {
+ if (func->isModifiedRemoved())
+ continue;
+
+ if (first) {
+ first = false;
+ s << sectionTitle;
+ } else {
+ s << sectionTitleSpace;
+ }
+ writeFunction(s, false, cppClass, func);
+ foreach(AbstractMetaArgument* arg, func->arguments())
+ {
+ if (!arg_map.contains(arg->name())) {
+ arg_map.insert(arg->name(), arg);
+ }
+ }
+ }
+
+ s << endl;
+
+ foreach (AbstractMetaArgument* arg, arg_map.values()) {
+ Indentation indentation(INDENT);
+ writeParamerteType(s, cppClass, arg);
+ }
+
+ s << endl;
+
+ foreach (AbstractMetaFunction* func, lst) {
+ writeFormatedText(s, func->documentation(), cppClass);
+ }
+}
+
+QString QtDocGenerator::parseArgDocStyle(const AbstractMetaClass* cppClass, const AbstractMetaFunction* func)
+{
+ QString ret;
+ int optArgs = 0;
+
+ foreach (AbstractMetaArgument* arg, func->arguments()) {
+
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+
+ bool thisIsoptional = !arg->defaultValueExpression().isEmpty();
+ if (optArgs || thisIsoptional) {
+ ret += QLatin1Char('[');
+ optArgs++;
+ }
+
+ if (arg->argumentIndex() > 0)
+ ret += QLatin1String(", ");
+
+ ret += arg->name();
+
+ if (thisIsoptional) {
+ QString defValue = arg->defaultValueExpression();
+ if (defValue == QLatin1String("QString()")) {
+ defValue = QLatin1String("\"\"");
+ } else if (defValue == QLatin1String("QStringList()")
+ || defValue.startsWith(QLatin1String("QVector"))
+ || defValue.startsWith(QLatin1String("QList"))) {
+ defValue = QLatin1String("list()");
+ } else if (defValue == QLatin1String("QVariant()")) {
+ defValue = QLatin1String("None");
+ } else {
+ defValue.replace(QLatin1String("::"), QLatin1String("."));
+ if (defValue == QLatin1String("0") && (arg->type()->isQObject() || arg->type()->isObject()))
+ defValue = QLatin1String("None");
+ }
+ ret += QLatin1Char('=') + defValue;
+ }
+ }
+
+ ret += QString(optArgs, QLatin1Char(']'));
+ return ret;
+}
+
+void QtDocGenerator::writeDocSnips(QTextStream &s,
+ const CodeSnipList &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language)
+{
+ Indentation indentation(INDENT);
+ QStringList invalidStrings;
+ const static QString startMarkup = QLatin1String("[sphinx-begin]");
+ const static QString endMarkup = QLatin1String("[sphinx-end]");
+
+ invalidStrings << QLatin1String("*") << QLatin1String("//") << QLatin1String("/*") << QLatin1String("*/");
+
+ foreach (CodeSnip snip, codeSnips) {
+ if ((snip.position != position) ||
+ !(snip.language & language))
+ continue;
+
+ QString code = snip.code();
+ while (code.contains(startMarkup) && code.contains(endMarkup)) {
+ int startBlock = code.indexOf(startMarkup) + startMarkup.size();
+ int endBlock = code.indexOf(endMarkup);
+
+ if ((startBlock == -1) || (endBlock == -1))
+ break;
+
+ QString codeBlock = code.mid(startBlock, endBlock - startBlock);
+ QStringList rows = codeBlock.split(QLatin1Char('\n'));
+ int currenRow = 0;
+ int offset = 0;
+
+ foreach(QString row, rows) {
+ foreach(QString invalidString, invalidStrings) {
+ row = row.remove(invalidString);
+ }
+
+ if (row.trimmed().size() == 0) {
+ if (currenRow == 0)
+ continue;
+ else
+ s << endl;
+ }
+
+ if (currenRow == 0) {
+ //find offset
+ for (int i=0, i_max = row.size(); i < i_max; i++) {
+ if (row[i] == QLatin1Char(' '))
+ offset++;
+ else if (row[i] == QLatin1Char('\n'))
+ offset = 0;
+ else
+ break;
+ }
+ }
+ row = row.mid(offset);
+ s << row << endl;
+ currenRow++;
+ }
+
+ code = code.mid(endBlock+endMarkup.size());
+ }
+ }
+}
+
+bool QtDocGenerator::writeInjectDocumentation(QTextStream& s,
+ TypeSystem::DocModificationMode mode,
+ const AbstractMetaClass* cppClass,
+ const AbstractMetaFunction* func)
+{
+ Indentation indentation(INDENT);
+ bool didSomething = false;
+
+ foreach (DocModification mod, cppClass->typeEntry()->docModifications()) {
+ if (mod.mode() == mode) {
+ bool modOk = func ? mod.signature() == func->minimalSignature() : mod.signature().isEmpty();
+
+ if (modOk) {
+ Documentation doc;
+ Documentation::Format fmt;
+
+ if (mod.format == TypeSystem::NativeCode)
+ fmt = Documentation::Native;
+ else if (mod.format == TypeSystem::TargetLangCode)
+ fmt = Documentation::Target;
+ else
+ continue;
+
+ doc.setValue(mod.code() , fmt);
+ writeFormatedText(s, doc, cppClass);
+ didSomething = true;
+ }
+ }
+ }
+
+ s << endl;
+
+ // TODO: Deprecate the use of doc string on glue code.
+ // This is pre "add-function" and "inject-documentation" tags.
+ const TypeSystem::CodeSnipPosition pos = mode == TypeSystem::DocModificationPrepend
+ ? TypeSystem::CodeSnipPositionBeginning : TypeSystem::CodeSnipPositionEnd;
+ if (func)
+ writeDocSnips(s, func->injectedCodeSnips(), pos, TypeSystem::TargetLangCode);
+ else
+ writeDocSnips(s, cppClass->typeEntry()->codeSnips(), pos, TypeSystem::TargetLangCode);
+ return didSomething;
+}
+
+void QtDocGenerator::writeFunctionSignature(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func)
+{
+ QString className;
+ if (!func->isConstructor())
+ className = getClassTargetFullName(cppClass) + QLatin1Char('.');
+ else if (func->implementingClass() && func->implementingClass()->enclosingClass())
+ className = getClassTargetFullName(func->implementingClass()->enclosingClass()) + QLatin1Char('.');
+
+ QString funcName = getFuncName(func);
+ if (!funcName.startsWith(className))
+ funcName = className + funcName;
+
+ s << funcName << "(" << parseArgDocStyle(cppClass, func) << ")";
+}
+
+QString QtDocGenerator::translateToPythonType(const AbstractMetaType* type, const AbstractMetaClass* cppClass)
+{
+ QString strType;
+ if (type->name() == QLatin1String("QString")) {
+ strType = QLatin1String("unicode");
+ } else if (type->name() == QLatin1String("QVariant")) {
+ strType = QLatin1String("object");
+ } else if (type->name() == QLatin1String("QStringList")) {
+ strType = QLatin1String("list of strings");
+ } else if (type->isConstant() && type->name() == QLatin1String("char") && type->indirections() == 1) {
+ strType = QLatin1String("str");
+ } else if (type->name().startsWith(QLatin1String("unsigned short"))) {
+ strType = QLatin1String("int");
+ } else if (type->name().startsWith(QLatin1String("unsigned "))) { // uint and ulong
+ strType = QLatin1String("long");
+ } else if (type->isContainer()) {
+ QString strType = translateType(type, cppClass, Options(ExcludeConst) | ExcludeReference);
+ strType.remove(QLatin1Char('*'));
+ strType.remove(QLatin1Char('>'));
+ strType.remove(QLatin1Char('<'));
+ strType.replace(QLatin1String("::"), QLatin1String("."));
+ if (strType.contains(QLatin1String("QList")) || strType.contains(QLatin1String("QVector"))) {
+ strType.replace(QLatin1String("QList"), QLatin1String("list of "));
+ strType.replace(QLatin1String("QVector"), QLatin1String("list of "));
+ } else if (strType.contains(QLatin1String("QHash")) || strType.contains(QLatin1String("QMap"))) {
+ strType.remove(QLatin1String("QHash"));
+ strType.remove(QLatin1String("QMap"));
+ QStringList types = strType.split(QLatin1Char(','));
+ strType = QString::fromLatin1("Dictionary with keys of type %1 and values of type %2.")
+ .arg(types[0], types[1]);
+ }
+ } else {
+ QString refTag;
+ if (type->isEnum())
+ refTag = QLatin1String("attr");
+ else
+ refTag = QLatin1String("class");
+ strType = QLatin1Char(':') + refTag + QLatin1String(":`") + type->fullName() + QLatin1Char('`');
+ }
+ return strType;
+}
+
+void QtDocGenerator::writeParamerteType(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaArgument* arg)
+{
+ s << INDENT << ":param " << arg->name() << ": "
+ << translateToPythonType(arg->type(), cppClass) << endl;
+}
+
+void QtDocGenerator::writeFunctionParametersType(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func)
+{
+ Indentation indentation(INDENT);
+
+ s << endl;
+ foreach (AbstractMetaArgument* arg, func->arguments()) {
+
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+
+ writeParamerteType(s, cppClass, arg);
+ }
+
+ if (!func->isConstructor() && func->type()) {
+
+ QString retType;
+ // check if the return type was modified
+ foreach (FunctionModification mod, func->modifications()) {
+ foreach (ArgumentModification argMod, mod.argument_mods) {
+ if (argMod.index == 0) {
+ retType = argMod.modified_type;
+ break;
+ }
+ }
+ }
+
+ if (retType.isEmpty())
+ retType = translateToPythonType(func->type(), cppClass);
+ s << INDENT << ":rtype: " << retType << endl;
+ }
+ s << endl;
+}
+
+void QtDocGenerator::writeFunction(QTextStream& s, bool writeDoc, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func)
+{
+ writeFunctionSignature(s, cppClass, func);
+ s << endl;
+
+ if (func->typeEntry() && (func->typeEntry()->version() != 0))
+ s << ".. note:: This method was introduced in Qt " << func->typeEntry()->version() << endl;
+
+ if (writeDoc) {
+ s << endl;
+ writeFunctionParametersType(s, cppClass, func);
+ s << endl;
+ writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, cppClass, func);
+ if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, cppClass, func))
+ writeFormatedText(s, func->documentation(), cppClass);
+ writeInjectDocumentation(s, TypeSystem::DocModificationAppend, cppClass, func);
+ }
+}
+
+static void writeFancyToc(QTextStream& s, const QStringList& items, int cols = 4)
+{
+ typedef QMap<QChar, QStringList> TocMap;
+ TocMap tocMap;
+ QChar Q = QLatin1Char('Q');
+ QChar idx;
+ foreach (QString item, items) {
+ if (item.isEmpty())
+ continue;
+ if (item.startsWith(Q) && item.length() > 1)
+ idx = item[1];
+ item.chop(4); // Remove the .rst extension
+ tocMap[idx] << item;
+ }
+ QtXmlToSphinx::Table table;
+ QtXmlToSphinx::TableRow row;
+
+ int itemsPerCol = (items.size() + tocMap.size()*2) / cols;
+ QString currentColData;
+ int i = 0;
+ QTextStream ss(&currentColData);
+ QMutableMapIterator<QChar, QStringList> it(tocMap);
+ while (it.hasNext()) {
+ it.next();
+ qSort(it.value());
+
+ if (i)
+ ss << endl;
+
+ ss << "**" << it.key() << "**" << endl << endl;
+ i += 2; // a letter title is equivalent to two entries in space
+ foreach (QString item, it.value()) {
+ ss << "* :doc:`" << item << "`" << endl;
+ ++i;
+
+ // end of column detected!
+ if (i > itemsPerCol) {
+ ss.flush();
+ QtXmlToSphinx::TableCell cell(currentColData);
+ row << cell;
+ currentColData.clear();
+ i = 0;
+ }
+ }
+ }
+ if (i) {
+ ss.flush();
+ QtXmlToSphinx::TableCell cell(currentColData);
+ row << cell;
+ currentColData.clear();
+ i = 0;
+ }
+ table << row;
+ table.normalize();
+ s << ".. container:: pysidetoc" << endl << endl;
+ s << table;
+}
+
+bool QtDocGenerator::finishGeneration()
+{
+ if (classes().isEmpty())
+ return true;
+
+ QMap<QString, QStringList>::iterator it = m_packages.begin();
+ for (; it != m_packages.end(); ++it) {
+ QString key = it.key();
+ key.replace(QLatin1Char('.'), QLatin1Char('/'));
+ QString outputDir = outputDirectory() + QLatin1Char('/') + key;
+ FileOut output(outputDir + QLatin1String("/index.rst"));
+ QTextStream& s = output.stream;
+
+ s << ".. module:: " << it.key() << endl << endl;
+
+ QString title = it.key();
+ s << title << endl;
+ s << createRepeatedChar(title.length(), '*') << endl << endl;
+
+ /* Avoid showing "Detailed Description for *every* class in toc tree */
+ Indentation indentation(INDENT);
+
+ // Search for extra-sections
+ if (!m_extraSectionDir.isEmpty()) {
+ QDir extraSectionDir(m_extraSectionDir);
+ QStringList fileList = extraSectionDir.entryList(QStringList() << (it.key() + QLatin1String("?*.rst")), QDir::Files);
+ QStringList::iterator it2 = fileList.begin();
+ for (; it2 != fileList.end(); ++it2) {
+ QString origFileName(*it2);
+ it2->remove(0, it.key().count() + 1);
+ QString newFilePath = outputDir + QLatin1Char('/') + *it2;
+ if (QFile::exists(newFilePath))
+ QFile::remove(newFilePath);
+ if (!QFile::copy(m_extraSectionDir + QLatin1Char('/') + origFileName, newFilePath)) {
+ qCDebug(lcShiboken).noquote().nospace() << "Error copying extra doc "
+ << QDir::toNativeSeparators(m_extraSectionDir + QLatin1Char('/') + origFileName)
+ << " to " << QDir::toNativeSeparators(newFilePath);
+ }
+ }
+ it.value().append(fileList);
+ }
+
+ writeFancyToc(s, it.value());
+
+ s << INDENT << ".. container:: hide" << endl << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << ".. toctree::" << endl;
+ Indentation deeperIndentation(INDENT);
+ s << INDENT << ":maxdepth: 1" << endl << endl;
+ foreach (QString className, it.value())
+ s << INDENT << className << endl;
+ s << endl << endl;
+ }
+
+ s << "Detailed Description" << endl;
+ s << "--------------------" << endl << endl;
+
+ // module doc is always wrong and C++istic, so go straight to the extra directory!
+ QFile moduleDoc(m_extraSectionDir + QLatin1Char('/') + it.key() + QLatin1String(".rst"));
+ if (moduleDoc.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ s << moduleDoc.readAll();
+ moduleDoc.close();
+ } else {
+ // try the normal way
+ Documentation moduleDoc = m_docParser->retrieveModuleDocumentation(it.key());
+ if (moduleDoc.format() == Documentation::Native) {
+ QString context = it.key();
+ context.remove(0, context.lastIndexOf(QLatin1Char('.')) + 1);
+ QtXmlToSphinx x(this, moduleDoc.value(), context);
+ s << x;
+ } else {
+ s << moduleDoc.value();
+ }
+ }
+ }
+ return true;
+}
+
+bool QtDocGenerator::doSetup(const QMap<QString, QString>& args)
+{
+ m_libSourceDir = args.value(QLatin1String("library-source-dir"));
+ m_docDataDir = args.value(QLatin1String("documentation-data-dir"));
+#ifdef __WIN32__
+# define PATH_SEP ';'
+#else
+# define PATH_SEP ':'
+#endif
+ m_codeSnippetDirs = args.value(QLatin1String("documentation-code-snippets-dir"), m_libSourceDir).split(QLatin1Char(PATH_SEP));
+ m_extraSectionDir = args.value(QLatin1String("documentation-extra-sections-dir"));
+
+ m_docParser = args.value(QLatin1String("doc-parser")) == QLatin1String("doxygen")
+ ? static_cast<DocParser*>(new DoxygenParser)
+ : static_cast<DocParser*>(new QtDocParser);
+ qCDebug(lcShiboken).noquote().nospace() << "doc-parser: " << args.value(QLatin1String("doc-parser"));
+
+ if (m_libSourceDir.isEmpty() || m_docDataDir.isEmpty()) {
+ qCWarning(lcShiboken) << "Documentation data dir and/or Qt source dir not informed, "
+ "documentation will not be extracted from Qt sources.";
+ return false;
+ } else {
+ m_docParser->setDocumentationDataDirectory(m_docDataDir);
+ m_docParser->setLibrarySourceDirectory(m_libSourceDir);
+ }
+ return true;
+}
+
+
+QMap<QString, QString> QtDocGenerator::options() const
+{
+ QMap<QString, QString> options;
+ options.insert(QLatin1String("doc-parser"),
+ QLatin1String("The documentation parser used to interpret the documentation input files (qdoc3|doxygen)"));
+ options.insert(QLatin1String("library-source-dir"),
+ QLatin1String("Directory where library source code is located"));
+ options.insert(QLatin1String("documentation-data-dir"),
+ QLatin1String("Directory with XML files generated by documentation tool (qdoc3 or Doxygen)"));
+ options.insert(QLatin1String("documentation-code-snippets-dir"),
+ QLatin1String("Directory used to search code snippets used by the documentation"));
+ options.insert(QLatin1String("documentation-extra-sections-dir"),
+ QLatin1String("Directory used to search for extra documentation sections"));
+ return options;
+}
+
diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.h b/sources/shiboken2/generator/qtdoc/qtdocgenerator.h
new file mode 100644
index 000000000..fa8524b21
--- /dev/null
+++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.h
@@ -0,0 +1,235 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#ifndef DOCGENERATOR_H
+#define DOCGENERATOR_H
+
+#include <QtCore/QStack>
+#include <QtCore/QHash>
+#include <QtCore/QTextStream>
+#include <QXmlStreamReader>
+#include "generator.h"
+#include "docparser.h"
+#include "typesystem_enums.h"
+#include "typesystem_typedefs.h"
+
+class QtDocParser;
+class AbstractMetaFunction;
+class AbstractMetaClass;
+QT_BEGIN_NAMESPACE
+class QXmlStreamReader;
+QT_END_NAMESPACE
+class QtDocGenerator;
+
+class QtXmlToSphinx
+{
+public:
+ struct TableCell
+ {
+ short rowSpan;
+ short colSpan;
+ QString data;
+
+ TableCell(const QString& text = QString()) : rowSpan(0), colSpan(0), data(text) {}
+ TableCell(const char* text) : rowSpan(0), colSpan(0), data(QLatin1String(text)) {}
+ };
+
+ typedef QList<TableCell> TableRow;
+ class Table : public QList<TableRow>
+ {
+ public:
+ Table() : m_hasHeader(false), m_normalized(false)
+ {
+ }
+
+ void enableHeader(bool enable)
+ {
+ m_hasHeader = enable;
+ }
+
+ bool hasHeader() const
+ {
+ return m_hasHeader;
+ }
+
+ void normalize();
+
+ bool isNormalized() const
+ {
+ return m_normalized;
+ }
+
+ void clear() {
+ m_normalized = false;
+ QList<TableRow>::clear();
+ }
+
+ private:
+ bool m_hasHeader;
+ bool m_normalized;
+ };
+
+ QtXmlToSphinx(QtDocGenerator* generator, const QString& doc, const QString& context = QString());
+
+ QString result() const
+ {
+ return m_result;
+ }
+
+private:
+ QString resolveContextForMethod(const QString& methodName);
+ QString expandFunction(const QString& function);
+ QString transform(const QString& doc);
+
+ void handleHeadingTag(QXmlStreamReader& reader);
+ void handleParaTag(QXmlStreamReader& reader);
+ void handleItalicTag(QXmlStreamReader& reader);
+ void handleBoldTag(QXmlStreamReader& reader);
+ void handleArgumentTag(QXmlStreamReader& reader);
+ void handleSeeAlsoTag(QXmlStreamReader& reader);
+ void handleSnippetTag(QXmlStreamReader& reader);
+ void handleDotsTag(QXmlStreamReader& reader);
+ void handleLinkTag(QXmlStreamReader& reader);
+ void handleImageTag(QXmlStreamReader& reader);
+ void handleListTag(QXmlStreamReader& reader);
+ void handleTermTag(QXmlStreamReader& reader);
+ void handleSuperScriptTag(QXmlStreamReader& reader);
+ void handleQuoteFileTag(QXmlStreamReader& reader);
+
+ // table tagsvoid QtXmlToSphinx::handleValueTag(QXmlStreamReader& reader)
+
+ void handleTableTag(QXmlStreamReader& reader);
+ void handleRowTag(QXmlStreamReader& reader);
+ void handleItemTag(QXmlStreamReader& reader);
+ void handleRawTag(QXmlStreamReader& reader);
+ void handleCodeTag(QXmlStreamReader& reader);
+
+ void handleIgnoredTag(QXmlStreamReader& reader);
+ void handleUnknownTag(QXmlStreamReader& reader);
+ void handleUselessTag(QXmlStreamReader& reader);
+ void handleAnchorTag(QXmlStreamReader& reader);
+
+ typedef void (QtXmlToSphinx::*TagHandler)(QXmlStreamReader&);
+ QHash<QString, TagHandler> m_handlerMap;
+ QStack<TagHandler> m_handlers;
+ QTextStream m_output;
+ QString m_result;
+
+ QStack<QString*> m_buffers;
+
+
+ Table m_currentTable;
+ bool m_tableHasHeader;
+ QString m_context;
+ QtDocGenerator* m_generator;
+ bool m_insideBold;
+ bool m_insideItalic;
+ QString m_lastTagName;
+ QString m_opened_anchor;
+
+ QString readFromLocations(const QStringList& locations, const QString& path, const QString& identifier);
+ QString readFromLocation(const QString& location, const QString& identifier, bool* ok = 0);
+ void pushOutputBuffer();
+ QString popOutputBuffer();
+ void writeTable(Table& table);
+};
+
+inline QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx& xmlToSphinx)
+{
+ return s << xmlToSphinx.result();
+}
+
+QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table);
+
+/**
+* The DocGenerator generates documentation from library being binded.
+*/
+class QtDocGenerator : public Generator
+{
+public:
+ QtDocGenerator();
+ ~QtDocGenerator();
+
+ QString libSourceDir() const
+ {
+ return m_libSourceDir;
+ }
+
+ bool doSetup(const QMap<QString, QString>& args);
+
+ const char* name() const
+ {
+ return "QtDocGenerator";
+ }
+
+ QMap<QString, QString> options() const;
+
+ QStringList codeSnippetDirs() const
+ {
+ return m_codeSnippetDirs;
+ }
+
+protected:
+ QString fileNamePrefix() const;
+ QString fileNameForContext(GeneratorContext &context) const;
+ void generateClass(QTextStream &s, GeneratorContext &classContext);
+ bool finishGeneration();
+
+ void writeFunctionArguments(QTextStream&, const AbstractMetaFunction*, Options) const {}
+ void writeArgumentNames(QTextStream&, const AbstractMetaFunction*, Options) const {}
+
+private:
+ void writeEnums(QTextStream& s, const AbstractMetaClass* cppClass);
+
+ void writeFields(QTextStream &s, const AbstractMetaClass *cppClass);
+ void writeArguments(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaFunction *func);
+ void writeFunctionSignature(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func);
+ void writeFunction(QTextStream& s, bool writeDoc, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func);
+ void writeFunctionParametersType(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaFunction* func);
+ void writeFunctionList(QTextStream& s, const AbstractMetaClass* cppClass);
+ void writeFunctionBlock(QTextStream& s, const QString& title, QStringList& functions);
+ void writeParamerteType(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaArgument *arg);
+
+ void writeConstructors(QTextStream &s, const AbstractMetaClass *cppClass);
+ void writeFormatedText(QTextStream& s, const Documentation& doc, const AbstractMetaClass* metaclass = 0);
+ bool writeInjectDocumentation(QTextStream& s, TypeSystem::DocModificationMode mode, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func);
+ void writeDocSnips(QTextStream &s, const CodeSnipList &codeSnips, TypeSystem::CodeSnipPosition position, TypeSystem::Language language);
+
+
+ QString parseArgDocStyle(const AbstractMetaClass *cppClass, const AbstractMetaFunction *func);
+ QString translateToPythonType(const AbstractMetaType *type, const AbstractMetaClass *cppClass);
+
+ QString m_docDataDir;
+ QString m_libSourceDir;
+ QStringList m_codeSnippetDirs;
+ QString m_extraSectionDir;
+ QStringList m_functionList;
+ QMap<QString, QStringList> m_packages;
+ DocParser* m_docParser;
+};
+
+#endif // DOCGENERATOR_H
diff --git a/sources/shiboken2/generator/shiboken2/CMakeLists.txt b/sources/shiboken2/generator/shiboken2/CMakeLists.txt
new file mode 100644
index 000000000..5c1b612dd
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/CMakeLists.txt
@@ -0,0 +1,28 @@
+project(shibokengenerator)
+
+set(shiboken_SRC
+../generator.cpp
+cppgenerator.cpp
+headergenerator.cpp
+overloaddata.cpp
+shibokengenerator.cpp
+main.cpp
+)
+
+include_directories(${generators_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${APIEXTRACTOR_INCLUDE_DIR}
+ ${Qt5Core_INCLUDE_DIRS}
+ )
+
+add_executable(shiboken2 ${shiboken_SRC})
+set_target_properties(shiboken2 PROPERTIES OUTPUT_NAME shiboken2${shiboken_SUFFIX})
+target_link_libraries(shiboken2
+ ${APIEXTRACTOR_LIBRARY}
+ ${Qt5Core_LIBRARIES}
+ )
+
+configure_file(shibokenconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/shibokenconfig.h" @ONLY)
+
+install(TARGETS shiboken2 DESTINATION bin)
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
new file mode 100644
index 000000000..68b62477e
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -0,0 +1,5689 @@
+/****************************************************************************
+**
+** 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 <memory>
+
+#include "cppgenerator.h"
+#include "overloaddata.h"
+#include <abstractmetalang.h>
+#include <reporthandler.h>
+#include <typedatabase.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QMetaObject>
+#include <QtCore/QTextStream>
+#include <QtCore/QDebug>
+#include <QMetaType>
+
+QHash<QString, QString> CppGenerator::m_nbFuncs = QHash<QString, QString>();
+QHash<QString, QString> CppGenerator::m_sqFuncs = QHash<QString, QString>();
+QHash<QString, QString> CppGenerator::m_mpFuncs = QHash<QString, QString>();
+QString CppGenerator::m_currentErrorCode(QLatin1String("0"));
+
+// utility functions
+inline AbstractMetaType* getTypeWithoutContainer(AbstractMetaType* arg)
+{
+ if (arg && arg->typeEntry()->isContainer()) {
+ AbstractMetaTypeList lst = arg->instantiations();
+ // only support containers with 1 type
+ if (lst.size() == 1)
+ return lst[0];
+ }
+ return arg;
+}
+
+CppGenerator::CppGenerator()
+{
+ // Number protocol structure members names
+ m_nbFuncs.insert(QLatin1String("__add__"), QLatin1String("nb_add"));
+ m_nbFuncs.insert(QLatin1String("__sub__"), QLatin1String("nb_subtract"));
+ m_nbFuncs.insert(QLatin1String("__mul__"), QLatin1String("nb_multiply"));
+ m_nbFuncs.insert(QLatin1String("__div__"), QLatin1String("nb_divide"));
+ m_nbFuncs.insert(QLatin1String("__mod__"), QLatin1String("nb_remainder"));
+ m_nbFuncs.insert(QLatin1String("__neg__"), QLatin1String("nb_negative"));
+ m_nbFuncs.insert(QLatin1String("__pos__"), QLatin1String("nb_positive"));
+ m_nbFuncs.insert(QLatin1String("__invert__"), QLatin1String("nb_invert"));
+ m_nbFuncs.insert(QLatin1String("__lshift__"), QLatin1String("nb_lshift"));
+ m_nbFuncs.insert(QLatin1String("__rshift__"), QLatin1String("nb_rshift"));
+ m_nbFuncs.insert(QLatin1String("__and__"), QLatin1String("nb_and"));
+ m_nbFuncs.insert(QLatin1String("__xor__"), QLatin1String("nb_xor"));
+ m_nbFuncs.insert(QLatin1String("__or__"), QLatin1String("nb_or"));
+ m_nbFuncs.insert(QLatin1String("__iadd__"), QLatin1String("nb_inplace_add"));
+ m_nbFuncs.insert(QLatin1String("__isub__"), QLatin1String("nb_inplace_subtract"));
+ m_nbFuncs.insert(QLatin1String("__imul__"), QLatin1String("nb_inplace_multiply"));
+ m_nbFuncs.insert(QLatin1String("__idiv__"), QLatin1String("nb_inplace_divide"));
+ m_nbFuncs.insert(QLatin1String("__imod__"), QLatin1String("nb_inplace_remainder"));
+ m_nbFuncs.insert(QLatin1String("__ilshift__"), QLatin1String("nb_inplace_lshift"));
+ m_nbFuncs.insert(QLatin1String("__irshift__"), QLatin1String("nb_inplace_rshift"));
+ m_nbFuncs.insert(QLatin1String("__iand__"), QLatin1String("nb_inplace_and"));
+ m_nbFuncs.insert(QLatin1String("__ixor__"), QLatin1String("nb_inplace_xor"));
+ m_nbFuncs.insert(QLatin1String("__ior__"), QLatin1String("nb_inplace_or"));
+ m_nbFuncs.insert(QLatin1String("bool"), QLatin1String("nb_nonzero"));
+
+ // sequence protocol functions
+ typedef QPair<QString, QString> StrPair;
+ m_sequenceProtocol.insert(QLatin1String("__len__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR), QLatin1String("Py_ssize_t")));
+ m_sequenceProtocol.insert(QLatin1String("__getitem__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i"),
+ QLatin1String("PyObject*")));
+ m_sequenceProtocol.insert(QLatin1String("__setitem__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i, PyObject* _value"),
+ QLatin1String("int")));
+ m_sequenceProtocol.insert(QLatin1String("__getslice__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i1, Py_ssize_t _i2"),
+ QLatin1String("PyObject*")));
+ m_sequenceProtocol.insert(QLatin1String("__setslice__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i1, Py_ssize_t _i2, PyObject* _value"),
+ QLatin1String("int")));
+ m_sequenceProtocol.insert(QLatin1String("__contains__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _value"),
+ QLatin1String("int")));
+ m_sequenceProtocol.insert(QLatin1String("__concat__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _other"),
+ QLatin1String("PyObject*")));
+
+ // Sequence protocol structure members names
+ m_sqFuncs.insert(QLatin1String("__concat__"), QLatin1String("sq_concat"));
+ m_sqFuncs.insert(QLatin1String("__contains__"), QLatin1String("sq_contains"));
+ m_sqFuncs.insert(QLatin1String("__getitem__"), QLatin1String("sq_item"));
+ m_sqFuncs.insert(QLatin1String("__getslice__"), QLatin1String("sq_slice"));
+ m_sqFuncs.insert(QLatin1String("__len__"), QLatin1String("sq_length"));
+ m_sqFuncs.insert(QLatin1String("__setitem__"), QLatin1String("sq_ass_item"));
+ m_sqFuncs.insert(QLatin1String("__setslice__"), QLatin1String("sq_ass_slice"));
+
+ // mapping protocol function
+ m_mappingProtocol.insert(QLatin1String("__mlen__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR),
+ QLatin1String("Py_ssize_t")));
+ m_mappingProtocol.insert(QLatin1String("__mgetitem__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _key"),
+ QLatin1String("PyObject*")));
+ m_mappingProtocol.insert(QLatin1String("__msetitem__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _key, PyObject* _value"),
+ QLatin1String("int")));
+
+ // Sequence protocol structure members names
+ m_mpFuncs.insert(QLatin1String("__mlen__"), QLatin1String("mp_length"));
+ m_mpFuncs.insert(QLatin1String("__mgetitem__"), QLatin1String("mp_subscript"));
+ m_mpFuncs.insert(QLatin1String("__msetitem__"), QLatin1String("mp_ass_subscript"));
+}
+
+QString CppGenerator::fileNamePrefix() const
+{
+ return QLatin1String("_wrapper.cpp");
+}
+
+QString CppGenerator::fileNameForContext(GeneratorContext &context) const
+{
+ const AbstractMetaClass *metaClass = context.metaClass();
+ if (!context.forSmartPointer()) {
+ QString fileNameBase = metaClass->qualifiedCppName().toLower();
+ fileNameBase.replace(QLatin1String("::"), QLatin1String("_"));
+ return fileNameBase + fileNamePrefix();
+ } else {
+ const AbstractMetaType *smartPointerType = context.preciseType();
+ QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass);
+ return fileNameBase + fileNamePrefix();
+ }
+}
+
+QList<AbstractMetaFunctionList> CppGenerator::filterGroupedOperatorFunctions(const AbstractMetaClass* metaClass,
+ uint queryIn)
+{
+ // ( func_name, num_args ) => func_list
+ QMap<QPair<QString, int >, AbstractMetaFunctionList> results;
+ const AbstractMetaClass::OperatorQueryOptions query(queryIn);
+ foreach (AbstractMetaFunction* func, metaClass->operatorOverloads(query)) {
+ if (func->isModifiedRemoved()
+ || func->usesRValueReferences()
+ || func->name() == QLatin1String("operator[]")
+ || func->name() == QLatin1String("operator->")
+ || func->name() == QLatin1String("operator!")) {
+ continue;
+ }
+ int args;
+ if (func->isComparisonOperator()) {
+ args = -1;
+ } else {
+ args = func->arguments().size();
+ }
+ QPair<QString, int > op(func->name(), args);
+ results[op].append(func);
+ }
+ return results.values();
+}
+
+bool CppGenerator::hasBoolCast(const AbstractMetaClass* metaClass) const
+{
+ if (!useIsNullAsNbNonZero())
+ return false;
+ // TODO: This could be configurable someday
+ const AbstractMetaFunction* func = metaClass->findFunction(QLatin1String("isNull"));
+ if (!func || !func->type() || !func->type()->typeEntry()->isPrimitive() || !func->isPublic())
+ return false;
+ const PrimitiveTypeEntry* pte = static_cast<const PrimitiveTypeEntry*>(func->type()->typeEntry());
+ while (pte->referencedTypeEntry())
+ pte = pte->referencedTypeEntry();
+ return func && func->isConstant() && pte->name() == QLatin1String("bool") && func->arguments().isEmpty();
+}
+
+typedef QMap<QString, AbstractMetaFunctionList> FunctionGroupMap;
+typedef FunctionGroupMap::const_iterator FunctionGroupMapIt;
+
+// Prevent ELF symbol qt_version_tag from being generated into the source
+static const char includeQDebug[] =
+"#ifndef QT_NO_VERSION_TAGGING\n"
+"# define QT_NO_VERSION_TAGGING\n"
+"#endif\n"
+"#include <QDebug>\n";
+
+/*!
+ Function used to write the class generated binding code on the buffer
+ \param s the output buffer
+ \param metaClass the pointer to metaclass information
+*/
+void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
+{
+ AbstractMetaClass *metaClass = classContext.metaClass();
+ if (ReportHandler::isDebug(ReportHandler::SparseDebug))
+ qCDebug(lcShiboken) << "Generating wrapper implementation for " << metaClass->fullName();
+
+ // write license comment
+ s << licenseComment() << endl;
+
+ if (!avoidProtectedHack() && !metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) {
+ s << "//workaround to access protected functions" << endl;
+ s << "#define protected public" << endl << endl;
+ }
+
+ // headers
+ s << "// default includes" << endl;
+ s << "#include <shiboken.h>" << endl;
+ if (usePySideExtensions()) {
+ s << includeQDebug;
+ s << "#include <pysidesignal.h>" << endl;
+ s << "#include <pysideproperty.h>" << endl;
+ s << "#include <pyside.h>" << endl;
+ s << "#include <destroylistener.h>" << endl;
+ }
+
+ s << "#include <typeresolver.h>" << endl;
+ s << "#include <typeinfo>" << endl;
+ if (usePySideExtensions() && metaClass->isQObject()) {
+ s << "#include <signalmanager.h>" << endl;
+ s << "#include <pysidemetafunction.h>" << endl;
+ }
+
+ // The multiple inheritance initialization function
+ // needs the 'set' class from C++ STL.
+ if (hasMultipleInheritanceInAncestry(metaClass))
+ s << "#include <set>" << endl;
+
+ s << endl << "// module include" << endl << "#include \"" << getModuleHeaderFileName() << '"' << endl;
+
+ QString headerfile = fileNameForContext(classContext);
+ headerfile.replace(QLatin1String(".cpp"), QLatin1String(".h"));
+ s << endl << "// main header" << endl << "#include \"" << headerfile << '"' << endl;
+
+ // PYSIDE-500: Use also includes for inherited wrapper classes, because
+ // without the protected hack, we sometimes need to cast inherited wrappers.
+ s << endl << "// inherited wrapper classes" << endl;
+ AbstractMetaClass *basis = metaClass->baseClass();
+ for (; basis; basis = basis->baseClass()) {
+ GeneratorContext basisContext(basis);
+ QString headerfile = fileNameForContext(basisContext);
+ headerfile.replace(QLatin1String(".cpp"), QLatin1String(".h"));
+ s << "#include \"" << headerfile << '"' << endl;
+ }
+
+ s << endl << "// inner classes" << endl;
+ foreach (AbstractMetaClass* innerClass, metaClass->innerClasses()) {
+ GeneratorContext innerClassContext(innerClass);
+ if (shouldGenerate(innerClass)) {
+ QString headerfile = fileNameForContext(innerClassContext);
+ headerfile.replace(QLatin1String(".cpp"), QLatin1String(".h"));
+ s << "#include \"" << headerfile << '"' << endl;
+ }
+ }
+
+ AbstractMetaEnumList classEnums = metaClass->enums();
+ foreach (AbstractMetaClass* innerClass, metaClass->innerClasses())
+ lookForEnumsInClassesNotToBeGenerated(classEnums, innerClass);
+
+ //Extra includes
+ s << endl << "// Extra includes" << endl;
+ QList<Include> includes = metaClass->typeEntry()->extraIncludes();
+ foreach (AbstractMetaEnum* cppEnum, classEnums)
+ includes.append(cppEnum->typeEntry()->extraIncludes());
+ qSort(includes.begin(), includes.end());
+ foreach (const Include &inc, includes)
+ s << inc.toString() << endl;
+ s << endl;
+
+ if (metaClass->typeEntry()->typeFlags() & ComplexTypeEntry::Deprecated)
+ s << "#Deprecated" << endl;
+
+ // Use class base namespace
+ {
+ const AbstractMetaClass *context = metaClass->enclosingClass();
+ while (context) {
+ if (context->isNamespace() && !context->enclosingClass()) {
+ s << "using namespace " << context->qualifiedCppName() << ";" << endl;
+ break;
+ }
+ context = context->enclosingClass();
+ }
+ }
+
+ s << endl;
+
+ // Create string literal for smart pointer getter method.
+ if (classContext.forSmartPointer()) {
+ const SmartPointerTypeEntry *typeEntry =
+ static_cast<const SmartPointerTypeEntry *>(classContext.preciseType()
+ ->typeEntry());
+ QString rawGetter = typeEntry->getter();
+ s << "static const char * " SMART_POINTER_GETTER " = \"" << rawGetter << "\";";
+ }
+
+ // class inject-code native/beginning
+ if (!metaClass->typeEntry()->codeSnips().isEmpty()) {
+ writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode, metaClass);
+ s << endl;
+ }
+
+ // python conversion rules
+ if (metaClass->typeEntry()->hasTargetConversionRule()) {
+ s << "// Python Conversion" << endl;
+ s << metaClass->typeEntry()->conversionRule() << endl;
+ }
+
+ if (shouldGenerateCppWrapper(metaClass)) {
+ s << "// Native ---------------------------------------------------------" << endl;
+ s << endl;
+
+ if (avoidProtectedHack() && usePySideExtensions()) {
+ s << "void " << wrapperName(metaClass) << "::pysideInitQtMetaTypes()\n{\n";
+ Indentation indent(INDENT);
+ writeInitQtMetaTypeFunctionBody(s, classContext);
+ s << "}\n\n";
+ }
+
+ foreach (const AbstractMetaFunction* func, filterFunctions(metaClass)) {
+ if ((func->isPrivate() && !visibilityModifiedToPrivate(func))
+ || (func->isModifiedRemoved() && !func->isAbstract()))
+ continue;
+ if (func->functionType() == AbstractMetaFunction::ConstructorFunction && !func->isUserAdded())
+ writeConstructorNative(s, func);
+ else if ((!avoidProtectedHack() || !metaClass->hasPrivateDestructor())
+ && (func->isVirtual() || func->isAbstract()))
+ writeVirtualMethodNative(s, func);
+ }
+
+ if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor()) {
+ if (usePySideExtensions() && metaClass->isQObject())
+ writeMetaObjectMethod(s, metaClass);
+ writeDestructorNative(s, metaClass);
+ }
+ }
+
+ Indentation indentation(INDENT);
+
+ QString methodsDefinitions;
+ QTextStream md(&methodsDefinitions);
+ QString singleMethodDefinitions;
+ QTextStream smd(&singleMethodDefinitions);
+
+ s << endl << "// Target ---------------------------------------------------------" << endl << endl;
+ s << "extern \"C\" {" << endl;
+ const FunctionGroupMap &functionGroups = getFunctionGroups(metaClass);
+ for (FunctionGroupMapIt it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
+ AbstractMetaFunctionList overloads;
+ QSet<QString> seenSignatures;
+ foreach (AbstractMetaFunction* func, it.value()) {
+ if (!func->isAssignmentOperator()
+ && !func->usesRValueReferences()
+ && !func->isCastOperator()
+ && !func->isModifiedRemoved()
+ && (!func->isPrivate() || func->functionType() == AbstractMetaFunction::EmptyFunction)
+ && func->ownerClass() == func->implementingClass()
+ && (func->name() != QLatin1String("qt_metacall"))) {
+ // PYSIDE-331: Inheritance works correctly when there are disjoint functions.
+ // But when a function is both in a class and inherited in a subclass,
+ // then we need to search through all subclasses and collect the new signatures.
+ overloads << getFunctionAndInheritedOverloads(func, &seenSignatures);
+ }
+ }
+
+ if (overloads.isEmpty())
+ continue;
+
+ const AbstractMetaFunction* rfunc = overloads.first();
+ if (m_sequenceProtocol.contains(rfunc->name()) || m_mappingProtocol.contains(rfunc->name()))
+ continue;
+
+ if (rfunc->isConstructor()) {
+ // @TODO: Implement constructor support for smart pointers, so that they can be
+ // instantiated in python code.
+ if (classContext.forSmartPointer())
+ continue;
+ writeConstructorWrapper(s, overloads, classContext);
+ }
+ // call operators
+ else if (rfunc->name() == QLatin1String("operator()"))
+ writeMethodWrapper(s, overloads, classContext);
+ else if (!rfunc->isOperatorOverload()) {
+
+ if (classContext.forSmartPointer()) {
+ const SmartPointerTypeEntry *smartPointerTypeEntry =
+ static_cast<const SmartPointerTypeEntry *>(
+ classContext.preciseType()->typeEntry());
+
+ if (smartPointerTypeEntry->getter() == rfunc->name()) {
+ // Replace the return type of the raw pointer getter method with the actual
+ // return type.
+ QString innerTypeName =
+ classContext.preciseType()->getSmartPointerInnerType()->name();
+ QString pointerToInnerTypeName = innerTypeName + QLatin1Char('*');
+ // @TODO: This possibly leaks, but there are a bunch of other places where this
+ // is done, so this will be fixed in bulk with all the other cases, because the
+ // ownership of the pointers is not clear at the moment.
+ AbstractMetaType *pointerToInnerType =
+ buildAbstractMetaTypeFromString(pointerToInnerTypeName);
+
+ AbstractMetaFunction *mutableRfunc = overloads.first();
+ mutableRfunc->replaceType(pointerToInnerType);
+ } else if (smartPointerTypeEntry->refCountMethodName().isEmpty()
+ || smartPointerTypeEntry->refCountMethodName() != rfunc->name()) {
+ // Skip all public methods of the smart pointer except for the raw getter and
+ // the ref count method.
+ continue;
+ }
+ }
+
+ writeMethodWrapper(s, overloads, classContext);
+ if (OverloadData::hasStaticAndInstanceFunctions(overloads)) {
+ QString methDefName = cpythonMethodDefinitionName(rfunc);
+ smd << "static PyMethodDef " << methDefName << " = {" << endl;
+ smd << INDENT;
+ writeMethodDefinitionEntry(smd, overloads);
+ smd << endl << "};" << endl << endl;
+ }
+ writeMethodDefinition(md, overloads);
+ }
+ }
+
+ QString className = cpythonTypeName(metaClass);
+ className.remove(QRegExp(QLatin1String("_Type$")));
+
+ if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer())
+ writeCopyFunction(s, classContext);
+
+ // Write single method definitions
+ s << singleMethodDefinitions;
+
+ // Write methods definition
+ s << "static PyMethodDef " << className << "_methods[] = {" << endl;
+ s << methodsDefinitions << endl;
+ if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer())
+ s << INDENT << "{\"__copy__\", (PyCFunction)" << className << "___copy__" << ", METH_NOARGS}," << endl;
+ s << INDENT << "{0} // Sentinel" << endl;
+ s << "};" << endl << endl;
+
+ // Write tp_getattro function
+ if ((usePySideExtensions() && metaClass->qualifiedCppName() == QLatin1String("QObject"))) {
+ writeGetattroFunction(s, classContext);
+ s << endl;
+ writeSetattroFunction(s, classContext);
+ s << endl;
+ } else {
+ if (classNeedsGetattroFunction(metaClass)) {
+ writeGetattroFunction(s, classContext);
+ s << endl;
+ }
+ if (classNeedsSetattroFunction(metaClass)) {
+ writeSetattroFunction(s, classContext);
+ s << endl;
+ }
+ }
+
+ if (hasBoolCast(metaClass)) {
+ ErrorCode errorCode(-1);
+ s << "static int " << cpythonBaseName(metaClass) << "___nb_bool(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << '{' << endl;
+ writeCppSelfDefinition(s, classContext);
+ s << INDENT << "int result;" << endl;
+ s << INDENT << BEGIN_ALLOW_THREADS << endl;
+ s << INDENT << "result = !" CPP_SELF_VAR "->isNull();" << endl;
+ s << INDENT << END_ALLOW_THREADS << endl;
+ s << INDENT << "return result;" << endl;
+ s << '}' << endl << endl;
+ }
+
+ if (supportsNumberProtocol(metaClass) && !metaClass->typeEntry()->isSmartPointer()) {
+ QList<AbstractMetaFunctionList> opOverloads = filterGroupedOperatorFunctions(
+ metaClass,
+ AbstractMetaClass::ArithmeticOp
+ | AbstractMetaClass::LogicalOp
+ | AbstractMetaClass::BitwiseOp);
+
+ foreach (const AbstractMetaFunctionList &allOverloads, opOverloads) {
+ AbstractMetaFunctionList overloads;
+ foreach (AbstractMetaFunction* func, allOverloads) {
+ if (!func->isModifiedRemoved()
+ && !func->isPrivate()
+ && (func->ownerClass() == func->implementingClass() || func->isAbstract()))
+ overloads.append(func);
+ }
+
+ if (overloads.isEmpty())
+ continue;
+
+ writeMethodWrapper(s, overloads, classContext);
+ }
+ }
+
+ if (supportsSequenceProtocol(metaClass)) {
+ writeSequenceMethods(s, metaClass, classContext);
+ }
+
+ if (supportsMappingProtocol(metaClass)) {
+ writeMappingMethods(s, metaClass, classContext);
+ }
+
+ if (metaClass->hasComparisonOperatorOverload()) {
+ s << "// Rich comparison" << endl;
+ writeRichCompareFunction(s, classContext);
+ }
+
+ if (shouldGenerateGetSetList(metaClass) && !classContext.forSmartPointer()) {
+ foreach (const AbstractMetaField* metaField, metaClass->fields()) {
+ if (metaField->isStatic())
+ continue;
+ writeGetterFunction(s, metaField, classContext);
+ if (!metaField->type()->isConstant())
+ writeSetterFunction(s, metaField, classContext);
+ s << endl;
+ }
+
+ s << "// Getters and Setters for " << metaClass->name() << endl;
+ s << "static PyGetSetDef " << cpythonGettersSettersDefinitionName(metaClass) << "[] = {" << endl;
+ foreach (const AbstractMetaField* metaField, metaClass->fields()) {
+ if (metaField->isStatic())
+ continue;
+
+ bool hasSetter = !metaField->type()->isConstant();
+ s << INDENT << "{const_cast<char*>(\"" << metaField->name() << "\"), ";
+ s << cpythonGetterFunctionName(metaField);
+ s << ", " << (hasSetter ? cpythonSetterFunctionName(metaField) : QLatin1String("0"));
+ s << "}," << endl;
+ }
+ s << INDENT << "{0} // Sentinel" << endl;
+ s << "};" << endl << endl;
+ }
+
+ s << "} // extern \"C\"" << endl << endl;
+
+ if (!metaClass->typeEntry()->hashFunction().isEmpty())
+ writeHashFunction(s, classContext);
+
+ // Write tp_traverse and tp_clear functions.
+ writeTpTraverseFunction(s, metaClass);
+ writeTpClearFunction(s, metaClass);
+
+ writeClassDefinition(s, metaClass, classContext);
+ s << endl;
+
+ if (metaClass->isPolymorphic() && metaClass->baseClass())
+ writeTypeDiscoveryFunction(s, metaClass);
+
+
+ foreach (AbstractMetaEnum* cppEnum, classEnums) {
+ if (cppEnum->isAnonymous() || cppEnum->isPrivate())
+ continue;
+
+ bool hasFlags = cppEnum->typeEntry()->flags();
+ if (hasFlags) {
+ writeFlagsMethods(s, cppEnum);
+ writeFlagsNumberMethodsDefinition(s, cppEnum);
+ s << endl;
+ }
+ }
+ s << endl;
+
+ writeConverterFunctions(s, metaClass, classContext);
+ writeClassRegister(s, metaClass, classContext);
+
+ // class inject-code native/end
+ if (!metaClass->typeEntry()->codeSnips().isEmpty()) {
+ writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode, metaClass);
+ s << endl;
+ }
+}
+
+void CppGenerator::writeConstructorNative(QTextStream& s, const AbstractMetaFunction* func)
+{
+ Indentation indentation(INDENT);
+ s << functionSignature(func, wrapperName(func->ownerClass()) + QLatin1String("::"), QString(),
+ OriginalTypeDescription | SkipDefaultValues);
+ s << " : ";
+ writeFunctionCall(s, func);
+ s << " {" << endl;
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode, func, lastArg);
+ s << INDENT << "// ... middle" << endl;
+ writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode, func, lastArg);
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeDestructorNative(QTextStream &s, const AbstractMetaClass *metaClass)
+{
+ Indentation indentation(INDENT);
+ s << wrapperName(metaClass) << "::~" << wrapperName(metaClass) << "()" << endl << '{' << endl;
+ // kill pyobject
+ s << INDENT << "SbkObject* wrapper = Shiboken::BindingManager::instance().retrieveWrapper(this);" << endl;
+ s << INDENT << "Shiboken::Object::destroy(wrapper, this);" << endl;
+ s << '}' << endl;
+}
+
+static bool allArgumentsRemoved(const AbstractMetaFunction* func)
+{
+ if (func->arguments().isEmpty())
+ return false;
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ if (!func->argumentRemoved(arg->argumentIndex() + 1))
+ return false;
+ }
+ return true;
+}
+
+QString CppGenerator::getVirtualFunctionReturnTypeName(const AbstractMetaFunction* func)
+{
+ if (!func->type())
+ return QLatin1String("\"\"");
+
+ if (!func->typeReplaced(0).isEmpty())
+ return QLatin1Char('"') + func->typeReplaced(0) + QLatin1Char('"');
+
+ // SbkType would return null when the type is a container.
+ if (func->type()->typeEntry()->isContainer()) {
+ return QLatin1Char('"')
+ + reinterpret_cast<const ContainerTypeEntry*>(func->type()->typeEntry())->typeName()
+ + QLatin1Char('"');
+ }
+
+ if (avoidProtectedHack()) {
+ const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(func->type());
+ if (metaEnum && metaEnum->isProtected())
+ return QLatin1Char('"') + protectedEnumSurrogateName(metaEnum) + QLatin1Char('"');
+ }
+
+ if (func->type()->isPrimitive())
+ return QLatin1Char('"') + func->type()->name() + QLatin1Char('"');
+
+ return QString::fromLatin1("Shiboken::SbkType< %1 >()->tp_name").arg(func->type()->typeEntry()->qualifiedCppName());
+}
+
+void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFunction* func)
+{
+ //skip metaObject function, this will be written manually ahead
+ if (usePySideExtensions() && func->ownerClass() && func->ownerClass()->isQObject() &&
+ ((func->name() == QLatin1String("metaObject")) || (func->name() == QLatin1String("qt_metacall"))))
+ return;
+
+ const TypeEntry* retType = func->type() ? func->type()->typeEntry() : 0;
+ const QString funcName = func->isOperatorOverload() ? pythonOperatorFunctionName(func) : func->name();
+
+ QString prefix = wrapperName(func->ownerClass()) + QLatin1String("::");
+ s << functionSignature(func, prefix, QString(), Generator::SkipDefaultValues|Generator::OriginalTypeDescription)
+ << endl << '{' << endl;
+
+ Indentation indentation(INDENT);
+
+ QString defaultReturnExpr;
+ if (retType) {
+ foreach (const FunctionModification &mod, func->modifications()) {
+ foreach (const ArgumentModification &argMod, mod.argument_mods) {
+ if (argMod.index == 0 && !argMod.replacedDefaultExpression.isEmpty()) {
+ QRegExp regex(QLatin1String("%(\\d+)"));
+ defaultReturnExpr = argMod.replacedDefaultExpression;
+ int offset = 0;
+ while ((offset = regex.indexIn(defaultReturnExpr, offset)) != -1) {
+ int argId = regex.cap(1).toInt() - 1;
+ if (argId < 0 || argId > func->arguments().count()) {
+ qCWarning(lcShiboken) << "The expression used in return value contains an invalid index.";
+ break;
+ }
+ defaultReturnExpr.replace(regex.cap(0), func->arguments()[argId]->name());
+ }
+ }
+ }
+ }
+ if (defaultReturnExpr.isEmpty())
+ defaultReturnExpr = minimalConstructor(func->type());
+ if (defaultReturnExpr.isEmpty()) {
+ QString errorMsg = QLatin1String(__FUNCTION__) + QLatin1String(": ");
+ if (const AbstractMetaClass *c = func->implementingClass())
+ errorMsg += c->qualifiedCppName() + QLatin1String("::");
+ errorMsg += func->signature();
+ errorMsg = ShibokenGenerator::msgCouldNotFindMinimalConstructor(errorMsg, func->type()->cppSignature());
+ qCWarning(lcShiboken).noquote().nospace() << errorMsg;
+ s << endl << INDENT << "#error " << errorMsg << endl;
+ }
+ }
+
+ if (func->isAbstract() && func->isModifiedRemoved()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QString::fromLatin1("Pure virtual method '%1::%2' must be implement but was "\
+ "completely removed on type system.")
+ .arg(func->ownerClass()->name(), func->minimalSignature());
+ s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ s << '}' << endl << endl;
+ return;
+ }
+
+ //Write declaration/native injected code
+ if (func->hasInjectedCode()) {
+ CodeSnipList snips = func->injectedCodeSnips();
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionDeclaration, TypeSystem::NativeCode, func, lastArg);
+ s << endl;
+ }
+
+ s << INDENT << "Shiboken::GilState gil;" << endl;
+
+ // Get out of virtual method call if someone already threw an error.
+ s << INDENT << "if (PyErr_Occurred())" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ }
+
+ s << INDENT << "Shiboken::AutoDecRef " PYTHON_OVERRIDE_VAR "(Shiboken::BindingManager::instance().getOverride(this, \"";
+ s << funcName << "\"));" << endl;
+
+ s << INDENT << "if (" PYTHON_OVERRIDE_VAR ".isNull()) {" << endl;
+ {
+ Indentation indentation(INDENT);
+ CodeSnipList snips;
+ if (func->hasInjectedCode()) {
+ snips = func->injectedCodeSnips();
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::ShellCode, func, lastArg);
+ s << endl;
+ }
+
+ if (func->isAbstract()) {
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '";
+ s << func->ownerClass()->name() << '.' << funcName;
+ s << "()' not implemented.\");" << endl;
+ s << INDENT << "return " << (retType ? defaultReturnExpr : QString());
+ } else {
+ s << INDENT << "gil.release();" << endl;
+ s << INDENT;
+ if (retType)
+ s << "return ";
+ s << "this->::" << func->implementingClass()->qualifiedCppName() << "::";
+ writeFunctionCall(s, func, Generator::VirtualCall);
+ if (!retType)
+ s << ";\n" << INDENT << "return";
+ }
+ }
+ s << ';' << endl;
+ s << INDENT << '}' << endl << endl;
+
+ writeConversionRule(s, func, TypeSystem::TargetLangCode);
+
+ s << INDENT << "Shiboken::AutoDecRef " PYTHON_ARGS "(";
+
+ if (func->arguments().isEmpty() || allArgumentsRemoved(func)) {
+ s << "PyTuple_New(0));" << endl;
+ } else {
+ QStringList argConversions;
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+
+ QString argConv;
+ QTextStream ac(&argConv);
+ const PrimitiveTypeEntry* argType = (const PrimitiveTypeEntry*) arg->type()->typeEntry();
+ bool convert = argType->isObject()
+ || arg->type()->isQObject()
+ || argType->isValue()
+ || arg->type()->isValuePointer()
+ || arg->type()->isNativePointer()
+ || argType->isFlags()
+ || argType->isEnum()
+ || argType->isContainer()
+ || arg->type()->referenceType() == LValueReference;
+
+ if (!convert && argType->isPrimitive()) {
+ if (argType->basicReferencedTypeEntry())
+ argType = argType->basicReferencedTypeEntry();
+ convert = !m_formatUnits.contains(argType->name());
+ }
+
+ Indentation indentation(INDENT);
+ ac << INDENT;
+ if (!func->conversionRule(TypeSystem::TargetLangCode, arg->argumentIndex() + 1).isEmpty()) {
+ // Has conversion rule.
+ ac << arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX);
+ } else {
+ QString argName = arg->name();
+ if (convert)
+ writeToPythonConversion(ac, arg->type(), func->ownerClass(), argName);
+ else
+ ac << argName;
+ }
+
+ argConversions << argConv;
+ }
+
+ s << "Py_BuildValue(\"(" << getFormatUnitString(func, false) << ")\"," << endl;
+ s << argConversions.join(QLatin1String(",\n")) << endl;
+ s << INDENT << "));" << endl;
+ }
+
+ bool invalidateReturn = false;
+ QSet<int> invalidateArgs;
+ foreach (const FunctionModification &funcMod, func->modifications()) {
+ foreach (const ArgumentModification &argMod, funcMod.argument_mods) {
+ if (argMod.resetAfterUse && !invalidateArgs.contains(argMod.index)) {
+ invalidateArgs.insert(argMod.index);
+ s << INDENT << "bool invalidateArg" << argMod.index;
+ s << " = PyTuple_GET_ITEM(" PYTHON_ARGS ", " << argMod.index - 1 << ")->ob_refcnt == 1;" << endl;
+ } else if (argMod.index == 0 && argMod.ownerships[TypeSystem::TargetLangCode] == TypeSystem::CppOwnership) {
+ invalidateReturn = true;
+ }
+ }
+ }
+ s << endl;
+
+ CodeSnipList snips;
+ if (func->hasInjectedCode()) {
+ snips = func->injectedCodeSnips();
+
+ if (injectedCodeUsesPySelf(func))
+ s << INDENT << "PyObject* pySelf = BindingManager::instance().retrieveWrapper(this);" << endl;
+
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode, func, lastArg);
+ s << endl;
+ }
+
+ if (!injectedCodeCallsPythonOverride(func)) {
+ s << INDENT;
+ s << "Shiboken::AutoDecRef " PYTHON_RETURN_VAR "(PyObject_Call(" PYTHON_OVERRIDE_VAR ", " PYTHON_ARGS ", NULL));" << endl;
+
+ s << INDENT << "// An error happened in python code!" << endl;
+ s << INDENT << "if (" PYTHON_RETURN_VAR ".isNull()) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_Print();" << endl;
+ s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ if (retType) {
+ if (invalidateReturn)
+ s << INDENT << "bool invalidateArg0 = " PYTHON_RETURN_VAR "->ob_refcnt == 1;" << endl;
+
+ if (func->typeReplaced(0) != QLatin1String("PyObject")) {
+
+ s << INDENT << "// Check return type" << endl;
+ s << INDENT;
+ if (func->typeReplaced(0).isEmpty()) {
+ s << "PythonToCppFunc " PYTHON_TO_CPP_VAR " = " << cpythonIsConvertibleFunction(func->type());
+ s << PYTHON_RETURN_VAR ");" << endl;
+ s << INDENT << "if (!" PYTHON_TO_CPP_VAR ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\
+ "\"Invalid return value in function %s, expected %s, got %s.\", \"";
+ s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func);
+ s << ", " PYTHON_RETURN_VAR "->ob_type->tp_name);" << endl;
+ s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ } else {
+
+ s << INDENT << "// Check return type" << endl;
+ s << INDENT << "bool typeIsValid = ";
+ writeTypeCheck(s, func->type(), QLatin1String(PYTHON_RETURN_VAR),
+ isNumber(func->type()->typeEntry()), func->typeReplaced(0));
+ s << ';' << endl;
+ s << INDENT << "if (!typeIsValid";
+ s << (isPointerToWrapperType(func->type()) ? " && " PYTHON_RETURN_VAR " != Py_None" : "");
+ s << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\
+ "\"Invalid return value in function %s, expected %s, got %s.\", \"";
+ s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func);
+ s << ", " PYTHON_RETURN_VAR "->ob_type->tp_name);" << endl;
+ s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ }
+ }
+
+ if (!func->conversionRule(TypeSystem::NativeCode, 0).isEmpty()) {
+ // Has conversion rule.
+ writeConversionRule(s, func, TypeSystem::NativeCode, QLatin1String(CPP_RETURN_VAR));
+ } else if (!injectedCodeHasReturnValueAttribution(func, TypeSystem::NativeCode)) {
+ writePythonToCppTypeConversion(s, func->type(), QLatin1String(PYTHON_RETURN_VAR),
+ QLatin1String(CPP_RETURN_VAR), func->implementingClass());
+ }
+ }
+ }
+
+ if (invalidateReturn) {
+ s << INDENT << "if (invalidateArg0)" << endl;
+ Indentation indentation(INDENT);
+ s << INDENT << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR ".object());" << endl;
+ }
+ foreach (int argIndex, invalidateArgs) {
+ s << INDENT << "if (invalidateArg" << argIndex << ')' << endl;
+ Indentation indentation(INDENT);
+ s << INDENT << "Shiboken::Object::invalidate(PyTuple_GET_ITEM(" PYTHON_ARGS ", ";
+ s << (argIndex - 1) << "));" << endl;
+ }
+
+
+ foreach (const FunctionModification &funcMod, func->modifications()) {
+ foreach (const ArgumentModification &argMod, funcMod.argument_mods) {
+ if (argMod.ownerships.contains(TypeSystem::NativeCode)
+ && argMod.index == 0 && argMod.ownerships[TypeSystem::NativeCode] == TypeSystem::CppOwnership) {
+ s << INDENT << "if (Shiboken::Object::checkType(" PYTHON_RETURN_VAR "))" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "Shiboken::Object::releaseOwnership(" PYTHON_RETURN_VAR ");" << endl;
+ }
+ }
+ }
+
+ if (func->hasInjectedCode()) {
+ s << endl;
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode, func, lastArg);
+ }
+
+ if (retType) {
+ s << INDENT << "return ";
+ if (avoidProtectedHack() && retType->isEnum()) {
+ const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(retType);
+ bool isProtectedEnum = metaEnum && metaEnum->isProtected();
+ if (isProtectedEnum) {
+ QString typeCast;
+ if (metaEnum->enclosingClass())
+ typeCast += QLatin1String("::") + metaEnum->enclosingClass()->qualifiedCppName();
+ typeCast += QLatin1String("::") + metaEnum->name();
+ s << '(' << typeCast << ')';
+ }
+ }
+ if (func->type()->referenceType() == LValueReference && !isPointer(func->type()))
+ s << '*';
+ s << CPP_RETURN_VAR ";" << endl;
+ }
+
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeMetaObjectMethod(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ Indentation indentation(INDENT);
+ QString wrapperClassName = wrapperName(metaClass);
+ s << "const QMetaObject* " << wrapperClassName << "::metaObject() const" << endl;
+ s << '{' << endl;
+ s << INDENT << "if (QObject::d_ptr->metaObject)" << endl
+ << INDENT << INDENT << "return QObject::d_ptr->dynamicMetaObject();" << endl;
+ s << INDENT << "SbkObject* pySelf = Shiboken::BindingManager::instance().retrieveWrapper(this);" << endl;
+ s << INDENT << "if (pySelf == NULL)" << endl;
+ s << INDENT << INDENT << "return " << metaClass->qualifiedCppName() << "::metaObject();" << endl;
+ s << INDENT << "return PySide::SignalManager::retriveMetaObject(reinterpret_cast<PyObject*>(pySelf));" << endl;
+ s << '}' << endl << endl;
+
+ // qt_metacall function
+ s << "int " << wrapperClassName << "::qt_metacall(QMetaObject::Call call, int id, void** args)" << endl;
+ s << "{" << endl;
+
+ AbstractMetaFunction *func = NULL;
+ AbstractMetaFunctionList list = metaClass->queryFunctionsByName(QLatin1String("qt_metacall"));
+ if (list.size() == 1)
+ func = list[0];
+
+ CodeSnipList snips;
+ if (func) {
+ snips = func->injectedCodeSnips();
+ if (func->isUserAdded()) {
+ CodeSnipList snips = func->injectedCodeSnips();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::NativeCode, func);
+ }
+ }
+
+ s << INDENT << "int result = " << metaClass->qualifiedCppName() << "::qt_metacall(call, id, args);" << endl;
+ s << INDENT << "return result < 0 ? result : PySide::SignalManager::qt_metacall(this, call, id, args);" << endl;
+ s << "}" << endl << endl;
+
+ // qt_metacast function
+ writeMetaCast(s, metaClass);
+}
+
+void CppGenerator::writeMetaCast(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ Indentation indentation(INDENT);
+ QString wrapperClassName = wrapperName(metaClass);
+ s << "void* " << wrapperClassName << "::qt_metacast(const char* _clname)" << endl;
+ s << '{' << endl;
+ s << INDENT << "if (!_clname) return 0;" << endl;
+ s << INDENT << "SbkObject* pySelf = Shiboken::BindingManager::instance().retrieveWrapper(this);" << endl;
+ s << INDENT << "if (pySelf && PySide::inherits(Py_TYPE(pySelf), _clname))" << endl;
+ s << INDENT << INDENT << "return static_cast<void*>(const_cast< " << wrapperClassName << "* >(this));" << endl;
+ s << INDENT << "return " << metaClass->qualifiedCppName() << "::qt_metacast(_clname);" << endl;
+ s << "}" << endl << endl;
+}
+
+void CppGenerator::writeEnumConverterFunctions(QTextStream& s, const AbstractMetaEnum* metaEnum)
+{
+ if (metaEnum->isPrivate() || metaEnum->isAnonymous())
+ return;
+ writeEnumConverterFunctions(s, metaEnum->typeEntry());
+}
+
+void CppGenerator::writeEnumConverterFunctions(QTextStream& s, const TypeEntry* enumType)
+{
+ if (!enumType)
+ return;
+ QString enumFlagName = enumType->isFlags() ? QLatin1String("flag") : QLatin1String("enum");
+ QString typeName = fixedCppTypeName(enumType);
+ QString enumPythonType = cpythonTypeNameExt(enumType);
+ QString cppTypeName = getFullTypeName(enumType).trimmed();
+ if (avoidProtectedHack()) {
+ const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(enumType);
+ if (metaEnum && metaEnum->isProtected())
+ cppTypeName = protectedEnumSurrogateName(metaEnum);
+ }
+ QString code;
+ QTextStream c(&code);
+ c << INDENT << "*((" << cppTypeName << "*)cppOut) = ";
+ if (enumType->isFlags())
+ c << cppTypeName << "(QFlag((int)PySide::QFlags::getValue(reinterpret_cast<PySideQFlagsObject*>(pyIn))))";
+ else
+ c << "(" << cppTypeName << ") Shiboken::Enum::getValue(pyIn)";
+ c << ';' << endl;
+ writePythonToCppFunction(s, code, typeName, typeName);
+
+ QString pyTypeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, %1)").arg(enumPythonType);
+ writeIsPythonConvertibleToCppFunction(s, typeName, typeName, pyTypeCheck);
+
+ code.clear();
+
+ c << INDENT << "int castCppIn = *((" << cppTypeName << "*)cppIn);" << endl;
+ c << INDENT;
+ c << "return ";
+ if (enumType->isFlags())
+ c << "reinterpret_cast<PyObject*>(PySide::QFlags::newObject(castCppIn, " << enumPythonType << "))";
+
+ else
+ c << "Shiboken::Enum::newItem(" << enumPythonType << ", castCppIn)";
+ c << ';' << endl;
+ writeCppToPythonFunction(s, code, typeName, typeName);
+ s << endl;
+
+ if (enumType->isFlags())
+ return;
+
+ const FlagsTypeEntry* flags = reinterpret_cast<const EnumTypeEntry*>(enumType)->flags();
+ if (!flags)
+ return;
+
+ // QFlags part.
+
+ writeEnumConverterFunctions(s, flags);
+
+ code.clear();
+ cppTypeName = getFullTypeName(flags).trimmed();
+ c << INDENT << "*((" << cppTypeName << "*)cppOut) = " << cppTypeName;
+ c << "(QFlag((int)Shiboken::Enum::getValue(pyIn)));" << endl;
+
+ QString flagsTypeName = fixedCppTypeName(flags);
+ writePythonToCppFunction(s, code, typeName, flagsTypeName);
+ writeIsPythonConvertibleToCppFunction(s, typeName, flagsTypeName, pyTypeCheck);
+
+ code.clear();
+ c << INDENT << "Shiboken::AutoDecRef pyLong(PyNumber_Long(pyIn));" << endl;
+ c << INDENT << "*((" << cppTypeName << "*)cppOut) = " << cppTypeName;
+ c << "(QFlag((int)PyLong_AsLong(pyLong.object())));" << endl;
+ writePythonToCppFunction(s, code, QLatin1String("number"), flagsTypeName);
+ writeIsPythonConvertibleToCppFunction(s, QLatin1String("number"), flagsTypeName,
+ QLatin1String("PyNumber_Check(pyIn)"));
+}
+
+void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaClass *metaClass,
+ GeneratorContext &classContext)
+{
+ s << "// Type conversion functions." << endl << endl;
+
+ AbstractMetaEnumList classEnums = metaClass->enums();
+ foreach (AbstractMetaClass* innerClass, metaClass->innerClasses())
+ lookForEnumsInClassesNotToBeGenerated(classEnums, innerClass);
+ if (!classEnums.isEmpty())
+ s << "// Python to C++ enum conversion." << endl;
+ foreach (const AbstractMetaEnum* metaEnum, classEnums)
+ writeEnumConverterFunctions(s, metaEnum);
+
+ if (metaClass->isNamespace())
+ return;
+
+ QString typeName;
+ if (!classContext.forSmartPointer())
+ typeName = getFullTypeName(metaClass);
+ else
+ typeName = getFullTypeName(classContext.preciseType());
+
+ QString cpythonType = cpythonTypeName(metaClass);
+
+ // Returns the C++ pointer of the Python wrapper.
+ s << "// Python to C++ pointer conversion - returns the C++ object of the Python wrapper (keeps object identity)." << endl;
+
+ QString sourceTypeName = metaClass->name();
+ QString targetTypeName = metaClass->name() + QLatin1String("_PTR");
+ QString code;
+ QTextStream c(&code);
+ c << INDENT << "Shiboken::Conversions::pythonToCppPointer(&" << cpythonType << ", pyIn, cppOut);";
+ writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
+
+ // "Is convertible" function for the Python object to C++ pointer conversion.
+ QString pyTypeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, (PyTypeObject*)&%1)").arg(cpythonType);
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, pyTypeCheck, QString(), true);
+ s << endl;
+
+ // C++ pointer to a Python wrapper, keeping identity.
+ s << "// C++ to Python pointer conversion - tries to find the Python wrapper for the C++ object (keeps object identity)." << endl;
+ code.clear();
+ if (usePySideExtensions() && metaClass->isQObject())
+ {
+ c << INDENT << "return PySide::getWrapperForQObject((" << typeName << "*)cppIn, &" << cpythonType << ");" << endl;
+ } else {
+ c << INDENT << "PyObject* pyOut = (PyObject*)Shiboken::BindingManager::instance().retrieveWrapper(cppIn);" << endl;
+ c << INDENT << "if (pyOut) {" << endl;
+ {
+ Indentation indent(INDENT);
+ c << INDENT << "Py_INCREF(pyOut);" << endl;
+ c << INDENT << "return pyOut;" << endl;
+ }
+ c << INDENT << '}' << endl;
+ c << INDENT << "const char* typeName = typeid(*((" << typeName << "*)cppIn)).name();" << endl;
+ c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType;
+ c << ", const_cast<void*>(cppIn), false, false, typeName);";
+ }
+ std::swap(targetTypeName, sourceTypeName);
+ writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName);
+
+ // The conversions for an Object Type end here.
+ if (!metaClass->typeEntry()->isValue() && !metaClass->typeEntry()->isSmartPointer()) {
+ s << endl;
+ return;
+ }
+
+ // Always copies C++ value (not pointer, and not reference) to a new Python wrapper.
+ s << endl << "// C++ to Python copy conversion." << endl;
+ if (!classContext.forSmartPointer())
+ targetTypeName = metaClass->name();
+ else
+ targetTypeName = classContext.preciseType()->name();
+
+ sourceTypeName = targetTypeName + QLatin1String("_COPY");
+
+ code.clear();
+
+ QString computedWrapperName;
+ if (!classContext.forSmartPointer())
+ computedWrapperName = wrapperName(metaClass);
+ else
+ computedWrapperName = wrapperName(classContext.preciseType());
+
+ c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType << ", new ::" << computedWrapperName;
+ c << "(*((" << typeName << "*)cppIn)), true, true);";
+ writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName);
+ s << endl;
+
+ // Python to C++ copy conversion.
+ s << "// Python to C++ copy conversion." << endl;
+ if (!classContext.forSmartPointer())
+ sourceTypeName = metaClass->name();
+ else
+ sourceTypeName = classContext.preciseType()->name();
+
+ targetTypeName = QStringLiteral("%1_COPY").arg(sourceTypeName);
+ code.clear();
+
+ QString pyInVariable = QLatin1String("pyIn");
+ QString wrappedCPtrExpression;
+ if (!classContext.forSmartPointer())
+ wrappedCPtrExpression = cpythonWrapperCPtr(metaClass->typeEntry(), pyInVariable);
+ else
+ wrappedCPtrExpression = cpythonWrapperCPtr(classContext.preciseType(), pyInVariable);
+
+ c << INDENT << "*((" << typeName << "*)cppOut) = *"
+ << wrappedCPtrExpression << ';';
+ writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
+
+ // "Is convertible" function for the Python object to C++ value copy conversion.
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, pyTypeCheck);
+ s << endl;
+
+ // User provided implicit conversions.
+ CustomConversion* customConversion = metaClass->typeEntry()->customConversion();
+
+ // Implicit conversions.
+ AbstractMetaFunctionList implicitConvs;
+ if (!customConversion || !customConversion->replaceOriginalTargetToNativeConversions()) {
+ foreach (AbstractMetaFunction* func, implicitConversions(metaClass->typeEntry())) {
+ if (!func->isUserAdded())
+ implicitConvs << func;
+ }
+ }
+
+ if (!implicitConvs.isEmpty())
+ s << "// Implicit conversions." << endl;
+
+ AbstractMetaType* targetType = buildAbstractMetaTypeFromAbstractMetaClass(metaClass);
+ foreach (const AbstractMetaFunction* conv, implicitConvs) {
+ if (conv->isModifiedRemoved())
+ continue;
+
+ QString typeCheck;
+ QString toCppConv;
+ QString toCppPreConv;
+ if (conv->isConversionOperator()) {
+ const AbstractMetaClass* sourceClass = conv->ownerClass();
+ typeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, %1)").arg(cpythonTypeNameExt(sourceClass->typeEntry()));
+ toCppConv = QLatin1Char('*') + cpythonWrapperCPtr(sourceClass->typeEntry(), QLatin1String("pyIn"));
+ } else {
+ // Constructor that does implicit conversion.
+ if (!conv->typeReplaced(1).isEmpty())
+ continue;
+ const AbstractMetaType* sourceType = conv->arguments().first()->type();
+ typeCheck = cpythonCheckFunction(sourceType);
+ bool isUserPrimitiveWithoutTargetLangName = isUserPrimitive(sourceType)
+ && sourceType->typeEntry()->targetLangApiName() == sourceType->typeEntry()->name();
+ if (!isWrapperType(sourceType)
+ && !isUserPrimitiveWithoutTargetLangName
+ && !sourceType->typeEntry()->isEnum()
+ && !sourceType->typeEntry()->isFlags()
+ && !sourceType->typeEntry()->isContainer()) {
+ typeCheck += QLatin1Char('(');
+ }
+ if (isWrapperType(sourceType)) {
+ typeCheck += QLatin1String("pyIn)");
+ toCppConv = (sourceType->referenceType() == LValueReference || !isPointerToWrapperType(sourceType))
+ ? QLatin1String("*") : QString();
+ toCppConv += cpythonWrapperCPtr(sourceType->typeEntry(), QLatin1String("pyIn"));
+ } else if (typeCheck.contains(QLatin1String("%in"))) {
+ typeCheck.replace(QLatin1String("%in"), QLatin1String("pyIn"));
+ typeCheck.append(QLatin1Char(')'));
+ } else {
+ typeCheck += QLatin1String("pyIn)");
+ }
+
+ if (isUserPrimitive(sourceType)
+ || isCppPrimitive(sourceType)
+ || sourceType->typeEntry()->isContainer()
+ || sourceType->typeEntry()->isEnum()
+ || sourceType->typeEntry()->isFlags()) {
+ QTextStream pc(&toCppPreConv);
+ pc << INDENT << getFullTypeNameWithoutModifiers(sourceType) << " cppIn";
+ writeMinimalConstructorExpression(pc, sourceType);
+ pc << ';' << endl;
+ writeToCppConversion(pc, sourceType, 0, QLatin1String("pyIn"), QLatin1String("cppIn"));
+ pc << ';';
+ toCppConv.append(QLatin1String("cppIn"));
+ } else if (!isWrapperType(sourceType)) {
+ QTextStream tcc(&toCppConv);
+ writeToCppConversion(tcc, sourceType, metaClass, QLatin1String("pyIn"), QLatin1String("/*BOZO-1061*/"));
+ }
+
+
+ }
+ const AbstractMetaType* sourceType = conv->isConversionOperator()
+ ? buildAbstractMetaTypeFromAbstractMetaClass(conv->ownerClass())
+ : conv->arguments().first()->type();
+ writePythonToCppConversionFunctions(s, sourceType, targetType, typeCheck, toCppConv, toCppPreConv);
+ }
+
+ writeCustomConverterFunctions(s, customConversion);
+}
+
+void CppGenerator::writeCustomConverterFunctions(QTextStream& s, const CustomConversion* customConversion)
+{
+ if (!customConversion)
+ return;
+ const CustomConversion::TargetToNativeConversions& toCppConversions = customConversion->targetToNativeConversions();
+ if (toCppConversions.isEmpty())
+ return;
+ s << "// Python to C++ conversions for type '" << customConversion->ownerType()->qualifiedCppName() << "'." << endl;
+ foreach (CustomConversion::TargetToNativeConversion* toNative, toCppConversions)
+ writePythonToCppConversionFunctions(s, toNative, customConversion->ownerType());
+ s << endl;
+}
+
+void CppGenerator::writeConverterRegister(QTextStream &s, const AbstractMetaClass *metaClass,
+ GeneratorContext &classContext)
+{
+ if (metaClass->isNamespace())
+ return;
+ s << INDENT << "// Register Converter" << endl;
+ s << INDENT << "SbkConverter* converter = Shiboken::Conversions::createConverter(&";
+ s << cpythonTypeName(metaClass) << ',' << endl;
+ {
+ Indentation indent(INDENT);
+ QString sourceTypeName = metaClass->name();
+ QString targetTypeName = sourceTypeName + QLatin1String("_PTR");
+ s << INDENT << pythonToCppFunctionName(sourceTypeName, targetTypeName) << ',' << endl;
+ s << INDENT << convertibleToCppFunctionName(sourceTypeName, targetTypeName) << ',' << endl;
+ std::swap(targetTypeName, sourceTypeName);
+ s << INDENT << cppToPythonFunctionName(sourceTypeName, targetTypeName);
+ if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) {
+ s << ',' << endl;
+ sourceTypeName = metaClass->name() + QLatin1String("_COPY");
+ s << INDENT << cppToPythonFunctionName(sourceTypeName, targetTypeName);
+ }
+ }
+ s << ");" << endl;
+
+ s << endl;
+
+ QStringList cppSignature;
+ if (!classContext.forSmartPointer()) {
+ cppSignature = metaClass->qualifiedCppName().split(QLatin1String("::"),
+ QString::SkipEmptyParts);
+ } else {
+ cppSignature = classContext.preciseType()->cppSignature().split(QLatin1String("::"),
+ QString::SkipEmptyParts);
+ }
+ while (!cppSignature.isEmpty()) {
+ QString signature = cppSignature.join(QLatin1String("::"));
+ s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "\");" << endl;
+ s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "*\");" << endl;
+ s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "&\");" << endl;
+ cppSignature.removeFirst();
+ }
+
+ s << INDENT << "Shiboken::Conversions::registerConverterName(converter, typeid(::";
+ QString qualifiedCppNameInvocation;
+ if (!classContext.forSmartPointer())
+ qualifiedCppNameInvocation = metaClass->qualifiedCppName();
+ else
+ qualifiedCppNameInvocation = classContext.preciseType()->cppSignature();
+
+ s << qualifiedCppNameInvocation << ").name());" << endl;
+
+ if (shouldGenerateCppWrapper(metaClass)) {
+ s << INDENT << "Shiboken::Conversions::registerConverterName(converter, typeid(::";
+ s << wrapperName(metaClass) << ").name());" << endl;
+ }
+
+ s << endl;
+
+ if (!metaClass->typeEntry()->isValue() && !metaClass->typeEntry()->isSmartPointer())
+ return;
+
+ // Python to C++ copy (value, not pointer neither reference) conversion.
+ s << INDENT << "// Add Python to C++ copy (value, not pointer neither reference) conversion to type converter." << endl;
+ QString sourceTypeName = metaClass->name();
+ QString targetTypeName = sourceTypeName + QLatin1String("_COPY");
+ QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName);
+ QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName);
+ writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
+
+ // User provided implicit conversions.
+ CustomConversion* customConversion = metaClass->typeEntry()->customConversion();
+
+ // Add implicit conversions.
+ AbstractMetaFunctionList implicitConvs;
+ if (!customConversion || !customConversion->replaceOriginalTargetToNativeConversions()) {
+ foreach (AbstractMetaFunction* func, implicitConversions(metaClass->typeEntry())) {
+ if (!func->isUserAdded())
+ implicitConvs << func;
+ }
+ }
+
+ if (!implicitConvs.isEmpty())
+ s << INDENT << "// Add implicit conversions to type converter." << endl;
+
+ AbstractMetaType* targetType = buildAbstractMetaTypeFromAbstractMetaClass(metaClass);
+ foreach (const AbstractMetaFunction* conv, implicitConvs) {
+ if (conv->isModifiedRemoved())
+ continue;
+ const AbstractMetaType* sourceType;
+ if (conv->isConversionOperator()) {
+ sourceType = buildAbstractMetaTypeFromAbstractMetaClass(conv->ownerClass());
+ } else {
+ // Constructor that does implicit conversion.
+ if (!conv->typeReplaced(1).isEmpty())
+ continue;
+ sourceType = conv->arguments().first()->type();
+ }
+ QString toCpp = pythonToCppFunctionName(sourceType, targetType);
+ QString isConv = convertibleToCppFunctionName(sourceType, targetType);
+ writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
+ }
+
+ writeCustomConverterRegister(s, customConversion, QLatin1String("converter"));
+}
+
+void CppGenerator::writeCustomConverterRegister(QTextStream& s, const CustomConversion* customConversion, const QString& converterVar)
+{
+ if (!customConversion)
+ return;
+ const CustomConversion::TargetToNativeConversions& toCppConversions = customConversion->targetToNativeConversions();
+ if (toCppConversions.isEmpty())
+ return;
+ s << INDENT << "// Add user defined implicit conversions to type converter." << endl;
+ foreach (CustomConversion::TargetToNativeConversion* toNative, toCppConversions) {
+ QString toCpp = pythonToCppFunctionName(toNative, customConversion->ownerType());
+ QString isConv = convertibleToCppFunctionName(toNative, customConversion->ownerType());
+ writeAddPythonToCppConversion(s, converterVar, toCpp, isConv);
+ }
+}
+
+void CppGenerator::writeContainerConverterRegister(QTextStream& s, const AbstractMetaType* container, const QString& converterVar)
+{
+ s << INDENT << "// Add user defined container conversion to type converter." << endl;
+ QString typeName = fixedCppTypeName(container);
+ QString toCpp = pythonToCppFunctionName(typeName, typeName);
+ QString isConv = convertibleToCppFunctionName(typeName, typeName);
+ writeAddPythonToCppConversion(s, converterVar, toCpp, isConv);
+}
+
+void CppGenerator::writeContainerConverterFunctions(QTextStream& s, const AbstractMetaType* containerType)
+{
+ writeCppToPythonFunction(s, containerType);
+ writePythonToCppConversionFunctions(s, containerType);
+}
+
+void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &overloadData,
+ GeneratorContext &context)
+{
+ const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
+ const AbstractMetaClass* ownerClass = rfunc->ownerClass();
+ int minArgs = overloadData.minArgs();
+ int maxArgs = overloadData.maxArgs();
+ bool initPythonArguments;
+ bool usesNamedArguments;
+
+ // If method is a constructor...
+ if (rfunc->isConstructor()) {
+ // Check if the right constructor was called.
+ if (!ownerClass->hasPrivateDestructor()) {
+ s << INDENT;
+ s << "if (Shiboken::Object::isUserType(" PYTHON_SELF_VAR ") && !Shiboken::ObjectType::canCallConstructor(" PYTHON_SELF_VAR "->ob_type, Shiboken::SbkType< ::";
+ QString qualifiedCppName;
+ if (!context.forSmartPointer())
+ qualifiedCppName = ownerClass->qualifiedCppName();
+ else
+ qualifiedCppName = context.preciseType()->cppSignature();
+
+ s << qualifiedCppName << " >()))" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl;
+ }
+ // Declare pointer for the underlying C++ object.
+ s << INDENT << "::";
+ if (!context.forSmartPointer()) {
+ s << (shouldGenerateCppWrapper(ownerClass) ? wrapperName(ownerClass)
+ : ownerClass->qualifiedCppName());
+ } else {
+ s << context.preciseType()->cppSignature();
+ }
+ s << "* cptr = 0;" << endl;
+
+ initPythonArguments = maxArgs > 0;
+ usesNamedArguments = !ownerClass->isQObject() && overloadData.hasArgumentWithDefaultValue();
+
+ } else {
+ if (rfunc->implementingClass() &&
+ (!rfunc->implementingClass()->isNamespace() && overloadData.hasInstanceFunction())) {
+ writeCppSelfDefinition(s, rfunc, context, overloadData.hasStaticFunction());
+ }
+ if (!rfunc->isInplaceOperator() && overloadData.hasNonVoidReturnType())
+ s << INDENT << "PyObject* " PYTHON_RETURN_VAR " = 0;" << endl;
+
+ initPythonArguments = minArgs != maxArgs || maxArgs > 1;
+ usesNamedArguments = rfunc->isCallOperator() || overloadData.hasArgumentWithDefaultValue();
+ }
+
+ if (maxArgs > 0) {
+ s << INDENT << "int overloadId = -1;" << endl;
+ s << INDENT << "PythonToCppFunc " PYTHON_TO_CPP_VAR;
+ if (pythonFunctionWrapperUsesListOfArguments(overloadData))
+ s << "[] = { 0" << QString::fromLatin1(", 0").repeated(maxArgs-1) << " }";
+ s << ';' << endl;
+ writeUnusedVariableCast(s, QLatin1String(PYTHON_TO_CPP_VAR));
+ }
+
+ if (usesNamedArguments && !rfunc->isCallOperator())
+ s << INDENT << "int numNamedArgs = (kwds ? PyDict_Size(kwds) : 0);" << endl;
+
+ if (initPythonArguments) {
+ s << INDENT << "int numArgs = ";
+ if (minArgs == 0 && maxArgs == 1 && !rfunc->isConstructor() && !pythonFunctionWrapperUsesListOfArguments(overloadData))
+ s << "(" PYTHON_ARG " == 0 ? 0 : 1);" << endl;
+ else
+ writeArgumentsInitializer(s, overloadData);
+ }
+}
+
+void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFunctionList overloads,
+ GeneratorContext &classContext)
+{
+ ErrorCode errorCode(-1);
+ OverloadData overloadData(overloads, this);
+
+ const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
+ const AbstractMetaClass* metaClass = rfunc->ownerClass();
+
+ s << "static int" << endl;
+ s << cpythonFunctionName(rfunc) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* args, PyObject* kwds)" << endl;
+ s << '{' << endl;
+
+ QSet<QString> argNamesSet;
+ if (usePySideExtensions() && metaClass->isQObject()) {
+ // Write argNames variable with all known argument names.
+ foreach (const AbstractMetaFunction* func, overloadData.overloads()) {
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ if (arg->defaultValueExpression().isEmpty() || func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+ argNamesSet << arg->name();
+ }
+ }
+ QStringList argNamesList = argNamesSet.toList();
+ qSort(argNamesList.begin(), argNamesList.end());
+ if (argNamesList.isEmpty()) {
+ s << INDENT << "const char** argNames = 0;" << endl;
+ } else {
+ s << INDENT << "const char* argNames[] = {\""
+ << argNamesList.join(QLatin1String("\", \"")) << "\"};" << endl;
+ }
+ s << INDENT << "const QMetaObject* metaObject;" << endl;
+ }
+
+ s << INDENT << "SbkObject* sbkSelf = reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ");" << endl;
+
+ if (metaClass->isAbstract() || metaClass->baseClassNames().size() > 1) {
+ s << INDENT << "SbkObjectType* type = reinterpret_cast<SbkObjectType*>(" PYTHON_SELF_VAR "->ob_type);" << endl;
+ s << INDENT << "SbkObjectType* myType = reinterpret_cast<SbkObjectType*>(" << cpythonTypeNameExt(metaClass->typeEntry()) << ");" << endl;
+ }
+
+ if (metaClass->isAbstract()) {
+ s << INDENT << "if (type == myType) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError," << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "\"'" << metaClass->qualifiedCppName();
+ }
+ s << "' represents a C++ abstract class and cannot be instantiated\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}' << endl << endl;
+ }
+
+ if (metaClass->baseClassNames().size() > 1) {
+ if (!metaClass->isAbstract()) {
+ s << INDENT << "if (type != myType) {" << endl;
+ }
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "Shiboken::ObjectType::copyMultimpleheritance(type, myType);" << endl;
+ }
+ if (!metaClass->isAbstract())
+ s << INDENT << '}' << endl << endl;
+ }
+
+ writeMethodWrapperPreamble(s, overloadData, classContext);
+
+ s << endl;
+
+ if (overloadData.maxArgs() > 0)
+ writeOverloadedFunctionDecisor(s, overloadData);
+
+ writeFunctionCalls(s, overloadData, classContext);
+ s << endl;
+
+ s << INDENT << "if (PyErr_Occurred() || !Shiboken::Object::setCppPointer(sbkSelf, Shiboken::SbkType< ::" << metaClass->qualifiedCppName() << " >(), cptr)) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "delete cptr;" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+ if (overloadData.maxArgs() > 0) {
+ s << INDENT << "if (!cptr) goto " << cpythonFunctionName(rfunc) << "_TypeError;" << endl;
+ s << endl;
+ }
+
+ s << INDENT << "Shiboken::Object::setValidCpp(sbkSelf, true);" << endl;
+ // If the created C++ object has a C++ wrapper the ownership is assigned to Python
+ // (first "1") and the flag indicating that the Python wrapper holds an C++ wrapper
+ // is marked as true (the second "1"). Otherwise the default values apply:
+ // Python owns it and C++ wrapper is false.
+ if (shouldGenerateCppWrapper(overloads.first()->ownerClass()))
+ s << INDENT << "Shiboken::Object::setHasCppWrapper(sbkSelf, true);" << endl;
+ // Need to check if a wrapper for same pointer is already registered
+ // Caused by bug PYSIDE-217, where deleted objects' wrappers are not released
+ s << INDENT << "if (Shiboken::BindingManager::instance().hasWrapper(cptr)) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "Shiboken::BindingManager::instance().releaseWrapper(Shiboken::BindingManager::instance().retrieveWrapper(cptr));" << endl;
+ }
+ s << INDENT << "}" << endl;
+ s << INDENT << "Shiboken::BindingManager::instance().registerWrapper(sbkSelf, cptr);" << endl;
+
+ // Create metaObject and register signal/slot
+ if (metaClass->isQObject() && usePySideExtensions()) {
+ s << endl << INDENT << "// QObject setup" << endl;
+ s << INDENT << "PySide::Signal::updateSourceObject(" PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "metaObject = cptr->metaObject(); // <- init python qt properties" << endl;
+ s << INDENT << "if (kwds && !PySide::fillQtProperties(" PYTHON_SELF_VAR ", metaObject, kwds, argNames, " << argNamesSet.count() << "))" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ }
+
+ // Constructor code injections, position=end
+ bool hasCodeInjectionsAtEnd = false;
+ foreach(AbstractMetaFunction* func, overloads) {
+ foreach (const CodeSnip &cs, func->injectedCodeSnips()) {
+ if (cs.position == TypeSystem::CodeSnipPositionEnd) {
+ hasCodeInjectionsAtEnd = true;
+ break;
+ }
+ }
+ }
+ if (hasCodeInjectionsAtEnd) {
+ // FIXME: C++ arguments are not available in code injection on constructor when position = end.
+ s << INDENT << "switch(overloadId) {" << endl;
+ foreach(AbstractMetaFunction* func, overloads) {
+ Indentation indent(INDENT);
+ foreach (const CodeSnip &cs, func->injectedCodeSnips()) {
+ if (cs.position == TypeSystem::CodeSnipPositionEnd) {
+ s << INDENT << "case " << metaClass->functions().indexOf(func) << ':' << endl;
+ s << INDENT << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode, func);
+ }
+ s << INDENT << '}' << endl;
+ break;
+ }
+ }
+ }
+ s << '}' << endl;
+ }
+
+ s << endl;
+ s << endl << INDENT << "return 1;" << endl;
+ if (overloadData.maxArgs() > 0)
+ writeErrorSection(s, overloadData);
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunctionList overloads,
+ GeneratorContext &classContext)
+{
+ OverloadData overloadData(overloads, this);
+ const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
+
+ int maxArgs = overloadData.maxArgs();
+
+ s << "static PyObject* ";
+ s << cpythonFunctionName(rfunc) << "(PyObject* " PYTHON_SELF_VAR;
+ if (maxArgs > 0) {
+ s << ", PyObject* " << (pythonFunctionWrapperUsesListOfArguments(overloadData) ? "args" : PYTHON_ARG);
+ if (overloadData.hasArgumentWithDefaultValue() || rfunc->isCallOperator())
+ s << ", PyObject* kwds";
+ }
+ s << ')' << endl << '{' << endl;
+
+ writeMethodWrapperPreamble(s, overloadData, classContext);
+
+ s << endl;
+
+ /*
+ * Make sure reverse <</>> operators defined in other classes (specially from other modules)
+ * are called. A proper and generic solution would require an reengineering in the operator
+ * system like the extended converters.
+ *
+ * Solves #119 - QDataStream <</>> operators not working for QPixmap
+ * http://bugs.openbossa.org/show_bug.cgi?id=119
+ */
+ bool hasReturnValue = overloadData.hasNonVoidReturnType();
+ bool callExtendedReverseOperator = hasReturnValue
+ && !rfunc->isInplaceOperator()
+ && !rfunc->isCallOperator()
+ && rfunc->isOperatorOverload();
+ if (callExtendedReverseOperator) {
+ QString revOpName = ShibokenGenerator::pythonOperatorFunctionName(rfunc).insert(2, QLatin1Char('r'));
+ if (rfunc->isBinaryOperator()) {
+ s << INDENT << "if (!isReverse" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "&& Shiboken::Object::checkType(" PYTHON_ARG ")" << endl;
+ s << INDENT << "&& !PyObject_TypeCheck(" PYTHON_ARG ", " PYTHON_SELF_VAR "->ob_type)" << endl;
+ s << INDENT << "&& PyObject_HasAttrString(" PYTHON_ARG ", const_cast<char*>(\"" << revOpName << "\"))) {" << endl;
+
+ // This PyObject_CallMethod call will emit lots of warnings like
+ // "deprecated conversion from string constant to char *" during compilation
+ // due to the method name argument being declared as "char*" instead of "const char*"
+ // issue 6952 http://bugs.python.org/issue6952
+ s << INDENT << "PyObject* revOpMethod = PyObject_GetAttrString(" PYTHON_ARG ", const_cast<char*>(\"" << revOpName << "\"));" << endl;
+ s << INDENT << "if (revOpMethod && PyCallable_Check(revOpMethod)) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << PYTHON_RETURN_VAR " = PyObject_CallFunction(revOpMethod, const_cast<char*>(\"O\"), " PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "if (PyErr_Occurred() && (PyErr_ExceptionMatches(PyExc_NotImplementedError)";
+ s << " || PyErr_ExceptionMatches(PyExc_AttributeError))) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_Clear();" << endl;
+ s << INDENT << "Py_XDECREF(" PYTHON_RETURN_VAR ");" << endl;
+ s << INDENT << PYTHON_RETURN_VAR " = 0;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ }
+ s << INDENT << "}" << endl;
+ s << INDENT << "Py_XDECREF(revOpMethod);" << endl << endl;
+ }
+ s << INDENT << "}" << endl;
+ }
+ s << INDENT << "// Do not enter here if other object has implemented a reverse operator." << endl;
+ s << INDENT << "if (!" PYTHON_RETURN_VAR ") {" << endl << endl;
+ }
+
+ if (maxArgs > 0)
+ writeOverloadedFunctionDecisor(s, overloadData);
+
+ writeFunctionCalls(s, overloadData, classContext);
+
+ if (callExtendedReverseOperator)
+ s << endl << INDENT << "} // End of \"if (!" PYTHON_RETURN_VAR ")\"" << endl;
+
+ s << endl;
+
+ writeFunctionReturnErrorCheckSection(s, hasReturnValue && !rfunc->isInplaceOperator());
+
+ if (hasReturnValue) {
+ if (rfunc->isInplaceOperator()) {
+ s << INDENT << "Py_INCREF(" PYTHON_SELF_VAR ");\n";
+ s << INDENT << "return " PYTHON_SELF_VAR ";\n";
+ } else {
+ s << INDENT << "return " PYTHON_RETURN_VAR ";\n";
+ }
+ } else {
+ s << INDENT << "Py_RETURN_NONE;" << endl;
+ }
+
+ if (maxArgs > 0)
+ writeErrorSection(s, overloadData);
+
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overloadData)
+{
+ const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
+ s << "PyTuple_GET_SIZE(args);" << endl;
+
+ int minArgs = overloadData.minArgs();
+ int maxArgs = overloadData.maxArgs();
+
+ s << INDENT << "PyObject* ";
+ s << PYTHON_ARGS "[] = {"
+ << QString(maxArgs, QLatin1Char('0')).split(QLatin1String(""), QString::SkipEmptyParts).join(QLatin1String(", "))
+ << "};" << endl;
+ s << endl;
+
+ if (overloadData.hasVarargs()) {
+ maxArgs--;
+ if (minArgs > maxArgs)
+ minArgs = maxArgs;
+
+ s << INDENT << "PyObject* nonvarargs = PyTuple_GetSlice(args, 0, " << maxArgs << ");" << endl;
+ s << INDENT << "Shiboken::AutoDecRef auto_nonvarargs(nonvarargs);" << endl;
+ s << INDENT << PYTHON_ARGS "[" << maxArgs << "] = PyTuple_GetSlice(args, " << maxArgs << ", numArgs);" << endl;
+ s << INDENT << "Shiboken::AutoDecRef auto_varargs(" PYTHON_ARGS "[" << maxArgs << "]);" << endl;
+ s << endl;
+ }
+
+ bool usesNamedArguments = overloadData.hasArgumentWithDefaultValue();
+
+ s << INDENT << "// invalid argument lengths" << endl;
+ bool ownerClassIsQObject = rfunc->ownerClass() && rfunc->ownerClass()->isQObject() && rfunc->isConstructor();
+ if (usesNamedArguments) {
+ if (!ownerClassIsQObject) {
+ s << INDENT << "if (numArgs" << (overloadData.hasArgumentWithDefaultValue() ? " + numNamedArgs" : "") << " > " << maxArgs << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): too many arguments\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}';
+ }
+ if (minArgs > 0) {
+ if (ownerClassIsQObject)
+ s << INDENT;
+ else
+ s << " else ";
+ s << "if (numArgs < " << minArgs << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): not enough arguments\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}';
+ }
+ }
+ QList<int> invalidArgsLength = overloadData.invalidArgumentLengths();
+ if (!invalidArgsLength.isEmpty()) {
+ QStringList invArgsLen;
+ foreach (int i, invalidArgsLength)
+ invArgsLen << QStringLiteral("numArgs == %1").arg(i);
+ if (usesNamedArguments && (!ownerClassIsQObject || minArgs > 0))
+ s << " else ";
+ else
+ s << INDENT;
+ s << "if (" << invArgsLen.join(QLatin1String(" || ")) << ")" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "goto " << cpythonFunctionName(rfunc) << "_TypeError;";
+ }
+ s << endl << endl;
+
+ QString funcName;
+ if (rfunc->isOperatorOverload())
+ funcName = ShibokenGenerator::pythonOperatorFunctionName(rfunc);
+ else
+ funcName = rfunc->name();
+
+ QString argsVar = overloadData.hasVarargs() ? QLatin1String("nonvarargs") : QLatin1String("args");
+ s << INDENT << "if (!";
+ if (usesNamedArguments)
+ s << "PyArg_ParseTuple(" << argsVar << ", \"|" << QByteArray(maxArgs, 'O') << ':' << funcName << '"';
+ else
+ s << "PyArg_UnpackTuple(" << argsVar << ", \"" << funcName << "\", " << minArgs << ", " << maxArgs;
+ QStringList palist;
+ for (int i = 0; i < maxArgs; i++)
+ palist << QString::fromLatin1("&(" PYTHON_ARGS "[%1])").arg(i);
+ s << ", " << palist.join(QLatin1String(", ")) << "))" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << endl;
+}
+
+void CppGenerator::writeCppSelfDefinition(QTextStream &s,
+ GeneratorContext &context,
+ bool hasStaticOverload,
+ bool cppSelfAsReference)
+{
+ const AbstractMetaClass *metaClass = context.metaClass();
+ bool useWrapperClass = avoidProtectedHack() && metaClass->hasProtectedMembers();
+ QString className;
+ if (!context.forSmartPointer()) {
+ className = useWrapperClass
+ ? wrapperName(metaClass)
+ : (QLatin1String("::") + metaClass->qualifiedCppName());
+ } else {
+ className = context.preciseType()->cppSignature();
+ }
+
+ QString cppSelfAttribution;
+ QString pythonSelfVar = QLatin1String(PYTHON_SELF_VAR);
+ QString cpythonWrapperCPtrResult;
+ if (!context.forSmartPointer())
+ cpythonWrapperCPtrResult = cpythonWrapperCPtr(metaClass, pythonSelfVar);
+ else
+ cpythonWrapperCPtrResult = cpythonWrapperCPtr(context.preciseType(), pythonSelfVar);
+
+ if (cppSelfAsReference) {
+ QString cast = useWrapperClass ? QString::fromLatin1("(%1*)").arg(className) : QString();
+ cppSelfAttribution = QString::fromLatin1("%1& %2 = *(%3%4)")
+ .arg(className, QLatin1String(CPP_SELF_VAR), cast,
+ cpythonWrapperCPtrResult);
+ } else {
+ s << INDENT << className << "* " CPP_SELF_VAR " = 0;" << endl;
+ writeUnusedVariableCast(s, QLatin1String(CPP_SELF_VAR));
+ cppSelfAttribution = QString::fromLatin1("%1 = %2%3")
+ .arg(QLatin1String(CPP_SELF_VAR),
+ (useWrapperClass ? QString::fromLatin1("(%1*)").arg(className) : QString()),
+ cpythonWrapperCPtrResult);
+ }
+
+ // Checks if the underlying C++ object is valid.
+ if (hasStaticOverload && !cppSelfAsReference) {
+ s << INDENT << "if (" PYTHON_SELF_VAR ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR));
+ s << INDENT << cppSelfAttribution << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+ return;
+ }
+
+ writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR));
+ s << INDENT << cppSelfAttribution << ';' << endl;
+}
+
+void CppGenerator::writeCppSelfDefinition(QTextStream &s,
+ const AbstractMetaFunction *func,
+ GeneratorContext &context,
+ bool hasStaticOverload)
+{
+ if (!func->ownerClass() || func->isConstructor())
+ return;
+
+ if (func->isOperatorOverload() && func->isBinaryOperator()) {
+ QString checkFunc = cpythonCheckFunction(func->ownerClass()->typeEntry());
+ s << INDENT << "bool isReverse = " << checkFunc << PYTHON_ARG ")" << endl;
+ {
+ Indentation indent1(INDENT);
+ Indentation indent2(INDENT);
+ Indentation indent3(INDENT);
+ Indentation indent4(INDENT);
+ s << INDENT << "&& !" << checkFunc << PYTHON_SELF_VAR ");" << endl;
+ }
+ s << INDENT << "if (isReverse)" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "std::swap(" PYTHON_SELF_VAR ", " PYTHON_ARG ");" << endl;
+ }
+
+ writeCppSelfDefinition(s, context, hasStaticOverload);
+}
+
+void CppGenerator::writeErrorSection(QTextStream& s, OverloadData& overloadData)
+{
+ const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
+ s << endl << INDENT << cpythonFunctionName(rfunc) << "_TypeError:" << endl;
+ Indentation indentation(INDENT);
+ QString funcName = fullPythonFunctionName(rfunc);
+
+ QString argsVar = pythonFunctionWrapperUsesListOfArguments(overloadData)
+ ? QLatin1String("args") : QLatin1String(PYTHON_ARG);
+ if (verboseErrorMessagesDisabled()) {
+ s << INDENT << "Shiboken::setErrorAboutWrongArguments(" << argsVar << ", \"" << funcName << "\", 0);" << endl;
+ } else {
+ QStringList overloadSignatures;
+ foreach (const AbstractMetaFunction* f, overloadData.overloads()) {
+ QStringList args;
+ foreach(AbstractMetaArgument* arg, f->arguments()) {
+ QString strArg;
+ AbstractMetaType* argType = arg->type();
+ if (isCString(argType)) {
+ strArg = QLatin1String("\" SBK_STR_NAME \"");
+ } else if (argType->isPrimitive()) {
+ const PrimitiveTypeEntry* ptp = reinterpret_cast<const PrimitiveTypeEntry*>(argType->typeEntry());
+ while (ptp->referencedTypeEntry())
+ ptp = ptp->referencedTypeEntry();
+ strArg = ptp->name();
+ if (strArg == QLatin1String("QString")) {
+ strArg = QLatin1String("unicode");
+ } else if (strArg == QLatin1String("QChar")) {
+ strArg = QLatin1String("1-unicode");
+ } else {
+ strArg = ptp->name();
+ strArg.remove(QRegExp(QLatin1String("^signed\\s+")));
+ if (strArg == QLatin1String("double"))
+ strArg = QLatin1String("float");
+ }
+ } else if (argType->typeEntry()->isContainer()) {
+ strArg = argType->fullName();
+ if (strArg == QLatin1String("QList") || strArg == QLatin1String("QVector")
+ || strArg == QLatin1String("QLinkedList") || strArg == QLatin1String("QStack")
+ || strArg == QLatin1String("QQueue")) {
+ strArg = QLatin1String("list");
+ } else if (strArg == QLatin1String("QMap") || strArg == QLatin1String("QHash")
+ || strArg == QLatin1String("QMultiMap") || strArg == QLatin1String("QMultiHash")) {
+ strArg = QLatin1String("dict");
+ } else if (strArg == QLatin1String("QPair")) {
+ strArg = QLatin1String("2-tuple");
+ }
+ } else {
+ strArg = argType->fullName();
+ if (strArg == QLatin1String("PyUnicode"))
+ strArg = QLatin1String("unicode");
+ else if (strArg == QLatin1String("PyString"))
+ strArg = QLatin1String("str");
+ else if (strArg == QLatin1String("PyBytes"))
+ strArg = QLatin1String("\" SBK_STR_NAME \"");
+ else if (strArg == QLatin1String("PySequece"))
+ strArg = QLatin1String("list");
+ else if (strArg == QLatin1String("PyTuple"))
+ strArg = QLatin1String("tuple");
+ else if (strArg == QLatin1String("PyDict"))
+ strArg = QLatin1String("dict");
+ else if (strArg == QLatin1String("PyObject"))
+ strArg = QLatin1String("object");
+ else if (strArg == QLatin1String("PyCallable"))
+ strArg = QLatin1String("callable");
+ else if (strArg == QLatin1String("uchar"))
+ strArg = QLatin1String("buffer"); // This depends on an inject code to be true, but if it's not true
+ // the function wont work at all, so it must be true.
+ }
+ if (!arg->defaultValueExpression().isEmpty()) {
+ strArg += QLatin1String(" = ");
+ if ((isCString(argType) || isPointerToWrapperType(argType))
+ && arg->defaultValueExpression() == QLatin1String("0")) {
+ strArg += QLatin1String("None");
+ } else {
+ QString e = arg->defaultValueExpression();
+ e.replace(QLatin1String("::"), QLatin1String("."));
+ e.replace(QLatin1String("\""), QLatin1String("\\\""));
+ strArg += e;
+ }
+ }
+ args << strArg;
+ }
+ overloadSignatures << QLatin1Char('"') + args.join(QLatin1String(", ")) + QLatin1Char('"');
+ }
+ s << INDENT << "const char* overloads[] = {" << overloadSignatures.join(QLatin1String(", "))
+ << ", 0};" << endl;
+ s << INDENT << "Shiboken::setErrorAboutWrongArguments(" << argsVar << ", \"" << funcName << "\", overloads);" << endl;
+ }
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+}
+
+void CppGenerator::writeFunctionReturnErrorCheckSection(QTextStream& s, bool hasReturnValue)
+{
+ s << INDENT << "if (PyErr_Occurred()" << (hasReturnValue ? " || !" PYTHON_RETURN_VAR : "") << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ if (hasReturnValue)
+ s << INDENT << "Py_XDECREF(" PYTHON_RETURN_VAR ");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+}
+
+void CppGenerator::writeInvalidPyObjectCheck(QTextStream& s, const QString& pyObj)
+{
+ s << INDENT << "if (!Shiboken::Object::isValid(" << pyObj << "))" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+}
+
+static QString pythonToCppConverterForArgumentName(const QString& argumentName)
+{
+ static QRegExp pyArgsRegex(QLatin1String(PYTHON_ARGS"(\\[\\d+[-]?\\d*\\])"));
+ pyArgsRegex.indexIn(argumentName);
+ return QLatin1String(PYTHON_TO_CPP_VAR) + pyArgsRegex.cap(1);
+}
+
+void CppGenerator::writeTypeCheck(QTextStream& s, const AbstractMetaType* argType, QString argumentName, bool isNumber, QString customType, bool rejectNull)
+{
+ QString customCheck;
+ if (!customType.isEmpty()) {
+ AbstractMetaType* metaType;
+ customCheck = guessCPythonCheckFunction(customType, &metaType);
+ if (metaType)
+ argType = metaType;
+ }
+
+ // TODO-CONVERTER: merge this with the code below.
+ QString typeCheck;
+ if (customCheck.isEmpty())
+ typeCheck = cpythonIsConvertibleFunction(argType, argType->isEnum() ? false : isNumber);
+ else
+ typeCheck = customCheck;
+ typeCheck.append(QString::fromLatin1("(%1)").arg(argumentName));
+
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (customCheck.isEmpty() && !argType->typeEntry()->isCustom()) {
+ typeCheck = QString::fromLatin1("(%1 = %2))").arg(pythonToCppConverterForArgumentName(argumentName), typeCheck);
+ if (!isNumber && argType->typeEntry()->isCppPrimitive())
+ typeCheck.prepend(QString::fromLatin1("%1(%2) && ").arg(cpythonCheckFunction(argType), argumentName));
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
+
+ if (rejectNull)
+ typeCheck = QString::fromLatin1("(%1 != Py_None && %2)").arg(argumentName, typeCheck);
+
+ s << typeCheck;
+}
+
+static void checkTypeViability(const AbstractMetaFunction* func, const AbstractMetaType* type, int argIdx)
+{
+ if (!type
+ || !type->typeEntry()->isPrimitive()
+ || type->indirections() == 0
+ || ShibokenGenerator::isCString(type)
+ || func->argumentRemoved(argIdx)
+ || !func->typeReplaced(argIdx).isEmpty()
+ || !func->conversionRule(TypeSystem::All, argIdx).isEmpty()
+ || func->hasInjectedCode())
+ return;
+ QString prefix;
+ if (func->ownerClass())
+ prefix = func->ownerClass()->qualifiedCppName() + QLatin1String("::");
+ qCWarning(lcShiboken).noquote().nospace()
+ << QString::fromLatin1("There's no user provided way (conversion rule, argument removal, custom code, etc) "
+ "to handle the primitive %1 type '%2' in function '%3%4'.")
+ .arg(argIdx == 0 ? QStringLiteral("return") : QStringLiteral("argument"),
+ type->cppSignature(), prefix, func->signature());
+}
+
+static void checkTypeViability(const AbstractMetaFunction* func)
+{
+ if (func->isUserAdded())
+ return;
+ const AbstractMetaType* type = func->type();
+ checkTypeViability(func, type, 0);
+ for (int i = 0; i < func->arguments().count(); ++i)
+ checkTypeViability(func, func->arguments().at(i)->type(), i + 1);
+}
+
+void CppGenerator::writeTypeCheck(QTextStream& s, const OverloadData* overloadData, QString argumentName)
+{
+ QSet<const TypeEntry*> numericTypes;
+
+ foreach (OverloadData* od, overloadData->previousOverloadData()->nextOverloadData()) {
+ foreach (const AbstractMetaFunction* func, od->overloads()) {
+ checkTypeViability(func);
+ const AbstractMetaType* argType = od->argument(func)->type();
+ if (!argType->isPrimitive())
+ continue;
+ if (ShibokenGenerator::isNumber(argType->typeEntry()))
+ numericTypes << argType->typeEntry();
+ }
+ }
+
+ // This condition trusts that the OverloadData object will arrange for
+ // PyInt type to come after the more precise numeric types (e.g. float and bool)
+ const AbstractMetaType* argType = overloadData->argType();
+ bool numberType = numericTypes.count() == 1 || ShibokenGenerator::isPyInt(argType);
+ QString customType = (overloadData->hasArgumentTypeReplace() ? overloadData->argumentTypeReplaced() : QString());
+ bool rejectNull = shouldRejectNullPointerArgument(overloadData->referenceFunction(), overloadData->argPos());
+ writeTypeCheck(s, argType, argumentName, numberType, customType, rejectNull);
+}
+
+void CppGenerator::writeArgumentConversion(QTextStream& s,
+ const AbstractMetaType* argType,
+ const QString& argName, const QString& pyArgName,
+ const AbstractMetaClass* context,
+ const QString& defaultValue,
+ bool castArgumentAsUnused)
+{
+ if (argType->typeEntry()->isCustom() || argType->typeEntry()->isVarargs())
+ return;
+ if (isWrapperType(argType))
+ writeInvalidPyObjectCheck(s, pyArgName);
+ writePythonToCppTypeConversion(s, argType, pyArgName, argName, context, defaultValue);
+ if (castArgumentAsUnused)
+ writeUnusedVariableCast(s, argName);
+}
+
+const AbstractMetaType* CppGenerator::getArgumentType(const AbstractMetaFunction* func, int argPos)
+{
+ if (argPos < 0 || argPos > func->arguments().size()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("Argument index for function '%1' out of range.").arg(func->signature());
+ return 0;
+ }
+
+ const AbstractMetaType* argType = 0;
+ QString typeReplaced = func->typeReplaced(argPos);
+ if (typeReplaced.isEmpty())
+ argType = (argPos == 0) ? func->type() : func->arguments().at(argPos-1)->type();
+ else
+ argType = buildAbstractMetaTypeFromString(typeReplaced);
+ if (!argType && !m_knownPythonTypes.contains(typeReplaced)) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QString::fromLatin1("Unknown type '%1' used as argument type replacement "\
+ "in function '%2', the generated code may be broken.")
+ .arg(typeReplaced, func->signature());
+ }
+ return argType;
+}
+
+void CppGenerator::writePythonToCppTypeConversion(QTextStream& s,
+ const AbstractMetaType* type,
+ const QString& pyIn,
+ const QString& cppOut,
+ const AbstractMetaClass* /* context */,
+ const QString& defaultValue)
+{
+ const TypeEntry* typeEntry = type->typeEntry();
+ if (typeEntry->isCustom() || typeEntry->isVarargs())
+ return;
+
+ QString cppOutAux = cppOut + QLatin1String("_local");
+
+ bool treatAsPointer = isValueTypeWithCopyConstructorOnly(type);
+ bool isPointerOrObjectType = (isObjectType(type) || isPointer(type)) && !isUserPrimitive(type) && !isCppPrimitive(type);
+ bool isNotContainerEnumOrFlags = !typeEntry->isContainer() && !typeEntry->isEnum() && !typeEntry->isFlags();
+ bool mayHaveImplicitConversion = type->referenceType() == LValueReference
+ && !isUserPrimitive(type)
+ && !isCppPrimitive(type)
+ && isNotContainerEnumOrFlags
+ && !(treatAsPointer || isPointerOrObjectType);
+ QString typeName = getFullTypeNameWithoutModifiers(type);
+
+ bool isProtectedEnum = false;
+
+ if (mayHaveImplicitConversion) {
+ s << INDENT << typeName << ' ' << cppOutAux;
+ writeMinimalConstructorExpression(s, type, defaultValue);
+ s << ';' << endl;
+ } else if (avoidProtectedHack() && type->typeEntry()->isEnum()) {
+ const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(type);
+ if (metaEnum && metaEnum->isProtected()) {
+ typeName = QLatin1String("long");
+ isProtectedEnum = true;
+ }
+ }
+
+ s << INDENT << typeName;
+ if (treatAsPointer || isPointerOrObjectType) {
+ s << "* " << cppOut;
+ if (!defaultValue.isEmpty())
+ s << " = " << defaultValue;
+ } else if (type->referenceType() == LValueReference && !typeEntry->isPrimitive() && isNotContainerEnumOrFlags) {
+ s << "* " << cppOut << " = &" << cppOutAux;
+ } else {
+ s << ' ' << cppOut;
+ if (isProtectedEnum && avoidProtectedHack()) {
+ s << " = ";
+ if (defaultValue.isEmpty())
+ s << "0";
+ else
+ s << "(long)" << defaultValue;
+ } else if (isUserPrimitive(type) || typeEntry->isEnum() || typeEntry->isFlags()) {
+ writeMinimalConstructorExpression(s, typeEntry, defaultValue);
+ } else if (!type->isContainer() && !type->isSmartPointer()) {
+ writeMinimalConstructorExpression(s, type, defaultValue);
+ }
+ }
+ s << ';' << endl;
+
+ QString pythonToCppFunc = pythonToCppConverterForArgumentName(pyIn);
+
+ s << INDENT;
+ if (!defaultValue.isEmpty())
+ s << "if (" << pythonToCppFunc << ") ";
+
+ QString pythonToCppCall = QString::fromLatin1("%1(%2, &%3)").arg(pythonToCppFunc, pyIn, cppOut);
+ if (!mayHaveImplicitConversion) {
+ s << pythonToCppCall << ';' << endl;
+ return;
+ }
+
+ if (!defaultValue.isEmpty())
+ s << '{' << endl << INDENT;
+
+ s << "if (Shiboken::Conversions::isImplicitConversion(reinterpret_cast<const SbkObjectType *>("
+ << cpythonTypeNameExt(type) << "), " << pythonToCppFunc << "))" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << pythonToCppFunc << '(' << pyIn << ", &" << cppOutAux << ");" << endl;
+ }
+ s << INDENT << "else" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << pythonToCppCall << ';' << endl;
+ }
+
+ if (!defaultValue.isEmpty())
+ s << INDENT << '}';
+ s << endl;
+}
+
+static void addConversionRuleCodeSnippet(CodeSnipList& snippetList, QString& rule,
+ TypeSystem::Language /* conversionLanguage */,
+ TypeSystem::Language snippetLanguage,
+ QString outputName = QString(),
+ QString inputName = QString())
+{
+ if (rule.isEmpty())
+ return;
+ if (snippetLanguage == TypeSystem::TargetLangCode) {
+ rule.replace(QLatin1String("%in"), inputName);
+ rule.replace(QLatin1String("%out"), outputName + QLatin1String("_out"));
+ } else {
+ rule.replace(QLatin1String("%out"), outputName);
+ }
+ CodeSnip snip(0, snippetLanguage);
+ snip.position = (snippetLanguage == TypeSystem::NativeCode) ? TypeSystem::CodeSnipPositionAny : TypeSystem::CodeSnipPositionBeginning;
+ snip.addCode(rule);
+ snippetList << snip;
+}
+
+void CppGenerator::writeConversionRule(QTextStream& s, const AbstractMetaFunction* func, TypeSystem::Language language)
+{
+ CodeSnipList snippets;
+ foreach (AbstractMetaArgument* arg, func->arguments()) {
+ QString rule = func->conversionRule(language, arg->argumentIndex() + 1);
+ addConversionRuleCodeSnippet(snippets, rule, language, TypeSystem::TargetLangCode,
+ arg->name(), arg->name());
+ }
+ writeCodeSnips(s, snippets, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode, func);
+}
+
+void CppGenerator::writeConversionRule(QTextStream& s, const AbstractMetaFunction* func, TypeSystem::Language language, const QString& outputVar)
+{
+ CodeSnipList snippets;
+ QString rule = func->conversionRule(language, 0);
+ addConversionRuleCodeSnippet(snippets, rule, language, language, outputVar);
+ writeCodeSnips(s, snippets, TypeSystem::CodeSnipPositionAny, language, func);
+}
+
+void CppGenerator::writeNoneReturn(QTextStream& s, const AbstractMetaFunction* func, bool thereIsReturnValue)
+{
+ if (thereIsReturnValue && (!func->type() || func->argumentRemoved(0)) && !injectedCodeHasReturnValueAttribution(func)) {
+ s << INDENT << PYTHON_RETURN_VAR " = Py_None;" << endl;
+ s << INDENT << "Py_INCREF(Py_None);" << endl;
+ }
+}
+
+void CppGenerator::writeOverloadedFunctionDecisor(QTextStream& s, const OverloadData& overloadData)
+{
+ s << INDENT << "// Overloaded function decisor" << endl;
+ const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
+ QList<const AbstractMetaFunction*> functionOverloads = overloadData.overloadsWithoutRepetition();
+ for (int i = 0; i < functionOverloads.count(); i++)
+ s << INDENT << "// " << i << ": " << functionOverloads.at(i)->minimalSignature() << endl;
+ writeOverloadedFunctionDecisorEngine(s, &overloadData);
+ s << endl;
+
+ // Ensure that the direct overload that called this reverse
+ // is called.
+ if (rfunc->isOperatorOverload() && !rfunc->isCallOperator()) {
+ s << INDENT << "if (isReverse && overloadId == -1) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"reverse operator not implemented.\");" << endl;
+ s << INDENT << "return 0;" << endl;
+ }
+ s << INDENT << "}" << endl << endl;
+ }
+
+ s << INDENT << "// Function signature not found." << endl;
+ s << INDENT << "if (overloadId == -1) goto " << cpythonFunctionName(overloadData.referenceFunction()) << "_TypeError;" << endl;
+ s << endl;
+}
+
+void CppGenerator::writeOverloadedFunctionDecisorEngine(QTextStream& s, const OverloadData* parentOverloadData)
+{
+ bool hasDefaultCall = parentOverloadData->nextArgumentHasDefaultValue();
+ const AbstractMetaFunction* referenceFunction = parentOverloadData->referenceFunction();
+
+ // If the next argument has not an argument with a default value, it is still possible
+ // that one of the overloads for the current overload data has its final occurrence here.
+ // If found, the final occurrence of a method is attributed to the referenceFunction
+ // variable to be used further on this method on the conditional that identifies default
+ // method calls.
+ if (!hasDefaultCall) {
+ foreach (const AbstractMetaFunction* func, parentOverloadData->overloads()) {
+ if (parentOverloadData->isFinalOccurrence(func)) {
+ referenceFunction = func;
+ hasDefaultCall = true;
+ break;
+ }
+ }
+ }
+
+ int maxArgs = parentOverloadData->maxArgs();
+ // Python constructors always receive multiple arguments.
+ bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(*parentOverloadData);
+
+ // Functions without arguments are identified right away.
+ if (maxArgs == 0) {
+ s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(referenceFunction);
+ s << "; // " << referenceFunction->minimalSignature() << endl;
+ return;
+
+ // To decide if a method call is possible at this point the current overload
+ // data object cannot be the head, since it is just an entry point, or a root,
+ // for the tree of arguments and it does not represent a valid method call.
+ } else if (!parentOverloadData->isHeadOverloadData()) {
+ bool isLastArgument = parentOverloadData->nextOverloadData().isEmpty();
+ bool signatureFound = parentOverloadData->overloads().size() == 1;
+
+ // The current overload data describes the last argument of a signature,
+ // so the method can be identified right now.
+ if (isLastArgument || (signatureFound && !hasDefaultCall)) {
+ const AbstractMetaFunction* func = parentOverloadData->referenceFunction();
+ s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(func);
+ s << "; // " << func->minimalSignature() << endl;
+ return;
+ }
+ }
+
+ bool isFirst = true;
+
+ // If the next argument has a default value the decisor can perform a method call;
+ // it just need to check if the number of arguments received from Python are equal
+ // to the number of parameters preceding the argument with the default value.
+ if (hasDefaultCall) {
+ isFirst = false;
+ int numArgs = parentOverloadData->argPos() + 1;
+ s << INDENT << "if (numArgs == " << numArgs << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ const AbstractMetaFunction* func = referenceFunction;
+ foreach (OverloadData* overloadData, parentOverloadData->nextOverloadData()) {
+ const AbstractMetaFunction* defValFunc = overloadData->getFunctionWithDefaultValue();
+ if (defValFunc) {
+ func = defValFunc;
+ break;
+ }
+ }
+ s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(func);
+ s << "; // " << func->minimalSignature() << endl;
+ }
+ s << INDENT << '}';
+ }
+
+ foreach (OverloadData* overloadData, parentOverloadData->nextOverloadData()) {
+ bool signatureFound = overloadData->overloads().size() == 1
+ && !overloadData->getFunctionWithDefaultValue()
+ && !overloadData->findNextArgWithDefault();
+
+ const AbstractMetaFunction* refFunc = overloadData->referenceFunction();
+
+ QStringList typeChecks;
+ QString pyArgName = (usePyArgs && maxArgs > 1)
+ ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(overloadData->argPos())
+ : QLatin1String(PYTHON_ARG);
+ OverloadData* od = overloadData;
+ int startArg = od->argPos();
+ int sequenceArgCount = 0;
+ while (od && !od->argType()->isVarargs()) {
+ bool typeReplacedByPyObject = od->argumentTypeReplaced() == QLatin1String("PyObject");
+ if (!typeReplacedByPyObject) {
+ if (usePyArgs)
+ pyArgName = QString::fromLatin1(PYTHON_ARGS "[%1]").arg(od->argPos());
+ QString typeCheck;
+ QTextStream tck(&typeCheck);
+ const AbstractMetaFunction* func = od->referenceFunction();
+
+ if (func->isConstructor() && func->arguments().count() == 1) {
+ const AbstractMetaClass* ownerClass = func->ownerClass();
+ const ComplexTypeEntry* baseContainerType = ownerClass->typeEntry()->baseContainerType();
+ if (baseContainerType && baseContainerType == func->arguments().first()->type()->typeEntry() && isCopyable(ownerClass)) {
+ tck << '!' << cpythonCheckFunction(ownerClass->typeEntry()) << pyArgName << ')' << endl;
+ Indentation indent(INDENT);
+ tck << INDENT << "&& ";
+ }
+ }
+ writeTypeCheck(tck, od, pyArgName);
+ typeChecks << typeCheck;
+ }
+
+ sequenceArgCount++;
+
+ if (od->nextOverloadData().isEmpty()
+ || od->nextArgumentHasDefaultValue()
+ || od->nextOverloadData().size() != 1
+ || od->overloads().size() != od->nextOverloadData().first()->overloads().size()) {
+ overloadData = od;
+ od = 0;
+ } else {
+ od = od->nextOverloadData().first();
+ }
+ }
+
+ if (usePyArgs && signatureFound) {
+ AbstractMetaArgumentList args = refFunc->arguments();
+ int lastArgIsVarargs = (int) (args.size() > 1 && args.last()->type()->isVarargs());
+ int numArgs = args.size() - OverloadData::numberOfRemovedArguments(refFunc) - lastArgIsVarargs;
+ typeChecks.prepend(QString::fromLatin1("numArgs %1 %2").arg(lastArgIsVarargs ? QLatin1String(">=") : QLatin1String("==")).arg(numArgs));
+ } else if (sequenceArgCount > 1) {
+ typeChecks.prepend(QString::fromLatin1("numArgs >= %1").arg(startArg + sequenceArgCount));
+ } else if (refFunc->isOperatorOverload() && !refFunc->isCallOperator()) {
+ typeChecks.prepend(QString::fromLatin1("%1isReverse").arg(refFunc->isReverseOperator() ? QString() : QLatin1String("!")));
+ }
+
+ if (isFirst) {
+ isFirst = false;
+ s << INDENT;
+ } else {
+ s << " else ";
+ }
+ s << "if (";
+ if (typeChecks.isEmpty()) {
+ s << "true";
+ } else {
+ Indentation indent(INDENT);
+ QString separator;
+ QTextStream sep(&separator);
+ sep << endl << INDENT << "&& ";
+ s << typeChecks.join(separator);
+ }
+ s << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ writeOverloadedFunctionDecisorEngine(s, overloadData);
+ }
+ s << INDENT << "}";
+ }
+ s << endl;
+}
+
+void CppGenerator::writeFunctionCalls(QTextStream &s, const OverloadData &overloadData,
+ GeneratorContext &context)
+{
+ QList<const AbstractMetaFunction*> overloads = overloadData.overloadsWithoutRepetition();
+ s << INDENT << "// Call function/method" << endl;
+ s << INDENT << (overloads.count() > 1 ? "switch (overloadId) " : "") << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ if (overloads.count() == 1) {
+ writeSingleFunctionCall(s, overloadData, overloads.first(), context);
+ } else {
+ for (int i = 0; i < overloads.count(); i++) {
+ const AbstractMetaFunction* func = overloads.at(i);
+ s << INDENT << "case " << i << ": // " << func->signature() << endl;
+ s << INDENT << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ writeSingleFunctionCall(s, overloadData, func, context);
+ s << INDENT << "break;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ }
+ }
+ }
+ s << INDENT << '}' << endl;
+}
+
+void CppGenerator::writeSingleFunctionCall(QTextStream &s,
+ const OverloadData &overloadData,
+ const AbstractMetaFunction *func,
+ GeneratorContext &context)
+{
+ if (func->isDeprecated()) {
+ s << INDENT << "Shiboken::warning(PyExc_DeprecationWarning, 1, \"Function: '"
+ << func->signature().replace(QLatin1String("::"), QLatin1String("."))
+ << "' is marked as deprecated, please check the documentation for more information.\");" << endl;
+ }
+
+ if (func->functionType() == AbstractMetaFunction::EmptyFunction) {
+ s << INDENT << "PyErr_Format(PyExc_TypeError, \"%s is a private method.\", \""
+ << func->signature().replace(QLatin1String("::"), QLatin1String("."))
+ << "\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ return;
+ }
+
+ bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(overloadData);
+
+ // Handle named arguments.
+ writeNamedArgumentResolution(s, func, usePyArgs);
+
+ bool injectCodeCallsFunc = injectedCodeCallsCppFunction(func);
+ bool mayHaveUnunsedArguments = !func->isUserAdded() && func->hasInjectedCode() && injectCodeCallsFunc;
+ int removedArgs = 0;
+ for (int argIdx = 0; argIdx < func->arguments().count(); ++argIdx) {
+ bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, argIdx + 1).isEmpty();
+ const AbstractMetaArgument* arg = func->arguments().at(argIdx);
+ if (func->argumentRemoved(argIdx + 1)) {
+ if (!arg->defaultValueExpression().isEmpty()) {
+ QString cppArgRemoved = QString::fromLatin1(CPP_ARG_REMOVED "%1").arg(argIdx);
+ s << INDENT << getFullTypeName(arg->type()) << ' ' << cppArgRemoved;
+ s << " = " << guessScopeForDefaultValue(func, arg) << ';' << endl;
+ writeUnusedVariableCast(s, cppArgRemoved);
+ } else if (!injectCodeCallsFunc && !func->isUserAdded() && !hasConversionRule) {
+ // When an argument is removed from a method signature and no other means of calling
+ // the method are provided (as with code injection) the generator must abort.
+ qFatal(qPrintable(QString::fromLatin1("No way to call '%1::%2' with the modifications described in the type system.")
+ .arg(func->ownerClass()->name(), func->signature())), NULL);
+ }
+ removedArgs++;
+ continue;
+ }
+ if (hasConversionRule)
+ continue;
+ const AbstractMetaType* argType = getArgumentType(func, argIdx + 1);
+ if (!argType || (mayHaveUnunsedArguments && !injectedCodeUsesArgument(func, argIdx)))
+ continue;
+ int argPos = argIdx - removedArgs;
+ QString argName = QString::fromLatin1(CPP_ARG"%1").arg(argPos);
+ QString pyArgName = usePyArgs ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(argPos) : QLatin1String(PYTHON_ARG);
+ QString defaultValue = guessScopeForDefaultValue(func, arg);
+ writeArgumentConversion(s, argType, argName, pyArgName, func->implementingClass(), defaultValue, func->isUserAdded());
+ }
+
+ s << endl;
+
+ int numRemovedArgs = OverloadData::numberOfRemovedArguments(func);
+
+ s << INDENT << "if (!PyErr_Occurred()) {" << endl;
+ {
+ Indentation indentation(INDENT);
+ writeMethodCall(s, func, context, func->arguments().size() - numRemovedArgs);
+ if (!func->isConstructor())
+ writeNoneReturn(s, func, overloadData.hasNonVoidReturnType());
+ }
+ s << INDENT << '}' << endl;
+}
+
+QString CppGenerator::cppToPythonFunctionName(const QString& sourceTypeName, QString targetTypeName)
+{
+ if (targetTypeName.isEmpty())
+ targetTypeName = sourceTypeName;
+ return QString::fromLatin1("%1_CppToPython_%2").arg(sourceTypeName, targetTypeName);
+}
+
+QString CppGenerator::pythonToCppFunctionName(const QString& sourceTypeName, const QString& targetTypeName)
+{
+ return QString::fromLatin1("%1_PythonToCpp_%2").arg(sourceTypeName, targetTypeName);
+}
+QString CppGenerator::pythonToCppFunctionName(const AbstractMetaType* sourceType, const AbstractMetaType* targetType)
+{
+ return pythonToCppFunctionName(fixedCppTypeName(sourceType), fixedCppTypeName(targetType));
+}
+QString CppGenerator::pythonToCppFunctionName(const CustomConversion::TargetToNativeConversion* toNative,
+ const TypeEntry* targetType)
+{
+ return pythonToCppFunctionName(fixedCppTypeName(toNative), fixedCppTypeName(targetType));
+}
+
+QString CppGenerator::convertibleToCppFunctionName(const QString& sourceTypeName, const QString& targetTypeName)
+{
+ return QString::fromLatin1("is_%1_PythonToCpp_%2_Convertible").arg(sourceTypeName, targetTypeName);
+}
+QString CppGenerator::convertibleToCppFunctionName(const AbstractMetaType* sourceType, const AbstractMetaType* targetType)
+{
+ return convertibleToCppFunctionName(fixedCppTypeName(sourceType), fixedCppTypeName(targetType));
+}
+QString CppGenerator::convertibleToCppFunctionName(const CustomConversion::TargetToNativeConversion* toNative,
+ const TypeEntry* targetType)
+{
+ return convertibleToCppFunctionName(fixedCppTypeName(toNative), fixedCppTypeName(targetType));
+}
+
+void CppGenerator::writeCppToPythonFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, QString targetTypeName)
+{
+ QString prettyCode;
+ QTextStream c(&prettyCode);
+ formatCode(c, code, INDENT);
+ processCodeSnip(prettyCode);
+
+ s << "static PyObject* " << cppToPythonFunctionName(sourceTypeName, targetTypeName);
+ s << "(const void* cppIn) {" << endl;
+ s << prettyCode;
+ s << '}' << endl;
+}
+
+static void replaceCppToPythonVariables(QString& code, const QString& typeName)
+{
+ code.prepend(QString::fromLatin1("%1& cppInRef = *((%1*)cppIn);\n").arg(typeName));
+ code.replace(QLatin1String("%INTYPE"), typeName);
+ code.replace(QLatin1String("%OUTTYPE"), QLatin1String("PyObject*"));
+ code.replace(QLatin1String("%in"), QLatin1String("cppInRef"));
+ code.replace(QLatin1String("%out"), QLatin1String("pyOut"));
+}
+void CppGenerator::writeCppToPythonFunction(QTextStream& s, const CustomConversion* customConversion)
+{
+ QString code = customConversion->nativeToTargetConversion();
+ replaceCppToPythonVariables(code, getFullTypeName(customConversion->ownerType()));
+ writeCppToPythonFunction(s, code, fixedCppTypeName(customConversion->ownerType()));
+}
+void CppGenerator::writeCppToPythonFunction(QTextStream& s, const AbstractMetaType* containerType)
+{
+ const CustomConversion* customConversion = containerType->typeEntry()->customConversion();
+ if (!customConversion) {
+ qFatal(qPrintable(QString::fromLatin1("Can't write the C++ to Python conversion function for container type '%1' - "\
+ "no conversion rule was defined for it in the type system.")
+ .arg(containerType->typeEntry()->qualifiedCppName())), NULL);
+ }
+ if (!containerType->typeEntry()->isContainer()) {
+ writeCppToPythonFunction(s, customConversion);
+ return;
+ }
+ QString code = customConversion->nativeToTargetConversion();
+ for (int i = 0; i < containerType->instantiations().count(); ++i) {
+ AbstractMetaType* type = containerType->instantiations().at(i);
+ QString typeName = getFullTypeName(type);
+ if (type->isConstant())
+ typeName = QLatin1String("const ") + typeName;
+ code.replace(QString::fromLatin1("%INTYPE_%1").arg(i), typeName);
+ }
+ replaceCppToPythonVariables(code, getFullTypeNameWithoutModifiers(containerType));
+ processCodeSnip(code);
+ writeCppToPythonFunction(s, code, fixedCppTypeName(containerType));
+}
+
+void CppGenerator::writePythonToCppFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, const QString& targetTypeName)
+{
+ QString prettyCode;
+ QTextStream c(&prettyCode);
+ formatCode(c, code, INDENT);
+ processCodeSnip(prettyCode);
+ s << "static void " << pythonToCppFunctionName(sourceTypeName, targetTypeName);
+ s << "(PyObject* pyIn, void* cppOut) {" << endl;
+ s << prettyCode;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeIsPythonConvertibleToCppFunction(QTextStream& s,
+ const QString& sourceTypeName,
+ const QString& targetTypeName,
+ const QString& condition,
+ QString pythonToCppFuncName,
+ bool acceptNoneAsCppNull)
+{
+ if (pythonToCppFuncName.isEmpty())
+ pythonToCppFuncName = pythonToCppFunctionName(sourceTypeName, targetTypeName);
+
+ s << "static PythonToCppFunc " << convertibleToCppFunctionName(sourceTypeName, targetTypeName);
+ s << "(PyObject* pyIn) {" << endl;
+ if (acceptNoneAsCppNull) {
+ s << INDENT << "if (pyIn == Py_None)" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return Shiboken::Conversions::nonePythonToCppNullPtr;" << endl;
+ }
+ s << INDENT << "if (" << condition << ')' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return " << pythonToCppFuncName << ';' << endl;
+ }
+ s << INDENT << "return 0;" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s,
+ const AbstractMetaType* sourceType,
+ const AbstractMetaType* targetType,
+ QString typeCheck,
+ QString conversion,
+ QString preConversion)
+{
+ QString sourcePyType = cpythonTypeNameExt(sourceType);
+
+ // Python to C++ conversion function.
+ QString code;
+ QTextStream c(&code);
+ if (conversion.isEmpty())
+ conversion = QLatin1Char('*') + cpythonWrapperCPtr(sourceType->typeEntry(), QLatin1String("pyIn"));
+ if (!preConversion.isEmpty())
+ c << INDENT << preConversion << endl;
+ c << INDENT << QString::fromLatin1("*((%1*)cppOut) = %1(%2);")
+ .arg(getFullTypeName(targetType->typeEntry()), conversion);
+ QString sourceTypeName = fixedCppTypeName(sourceType);
+ QString targetTypeName = fixedCppTypeName(targetType);
+ writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
+
+ // Python to C++ convertible check function.
+ if (typeCheck.isEmpty())
+ typeCheck = QString::fromLatin1("PyObject_TypeCheck(pyIn, %1)").arg(sourcePyType);
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck);
+ s << endl;
+}
+
+void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s,
+ const CustomConversion::TargetToNativeConversion* toNative,
+ const TypeEntry* targetType)
+{
+ // Python to C++ conversion function.
+ QString code = toNative->conversion();
+ QString inType;
+ if (toNative->sourceType())
+ inType = cpythonTypeNameExt(toNative->sourceType());
+ else
+ inType = QString::fromLatin1("(&%1_Type)").arg(toNative->sourceTypeName());
+ code.replace(QLatin1String("%INTYPE"), inType);
+ code.replace(QLatin1String("%OUTTYPE"), targetType->qualifiedCppName());
+ code.replace(QLatin1String("%in"), QLatin1String("pyIn"));
+ code.replace(QLatin1String("%out"), QString::fromLatin1("*((%1*)cppOut)").arg(getFullTypeName(targetType)));
+
+ QString sourceTypeName = fixedCppTypeName(toNative);
+ QString targetTypeName = fixedCppTypeName(targetType);
+ writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
+
+ // Python to C++ convertible check function.
+ QString typeCheck = toNative->sourceTypeCheck();
+ if (typeCheck.isEmpty()) {
+ QString pyTypeName = toNative->sourceTypeName();
+ if (pyTypeName == QLatin1String("Py_None") || pyTypeName == QLatin1String("PyNone"))
+ typeCheck = QLatin1String("%in == Py_None");
+ else if (pyTypeName == QLatin1String("SbkEnumType"))
+ typeCheck = QLatin1String("Shiboken::isShibokenEnum(%in)");
+ else if (pyTypeName == QLatin1String("SbkObject"))
+ typeCheck = QLatin1String("Shiboken::Object::checkType(%in)");
+ else if (pyTypeName == QLatin1String("PyTypeObject"))
+ typeCheck = QLatin1String("PyType_Check(%in)");
+ else if (pyTypeName == QLatin1String("PyObject"))
+ typeCheck = QLatin1String("PyObject_TypeCheck(%in, &PyBaseObject_Type)");
+ else if (pyTypeName.startsWith(QLatin1String("Py")))
+ typeCheck = pyTypeName + QLatin1String("_Check(%in)");
+ }
+ if (typeCheck.isEmpty()) {
+ if (!toNative->sourceType() || toNative->sourceType()->isPrimitive()) {
+ qFatal(qPrintable(QString::fromLatin1("User added implicit conversion for C++ type '%1' must provide either an input "\
+ "type check function or a non primitive type entry.")
+ .arg(targetType->qualifiedCppName())), NULL);
+
+ }
+ typeCheck = QString::fromLatin1("PyObject_TypeCheck(%in, %1)").arg(cpythonTypeNameExt(toNative->sourceType()));
+ }
+ typeCheck.replace(QLatin1String("%in"), QLatin1String("pyIn"));
+ processCodeSnip(typeCheck);
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck);
+}
+
+void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s, const AbstractMetaType* containerType)
+{
+ const CustomConversion* customConversion = containerType->typeEntry()->customConversion();
+ if (!customConversion) {
+ //qFatal
+ return;
+ }
+ const CustomConversion::TargetToNativeConversions& toCppConversions = customConversion->targetToNativeConversions();
+ if (toCppConversions.isEmpty()) {
+ //qFatal
+ return;
+ }
+ // Python to C++ conversion function.
+ QString cppTypeName = getFullTypeNameWithoutModifiers(containerType);
+ QString code;
+ QTextStream c(&code);
+ c << INDENT << QString::fromLatin1("%1& cppOutRef = *((%1*)cppOut);").arg(cppTypeName) << endl;
+ code.append(toCppConversions.first()->conversion());
+ for (int i = 0; i < containerType->instantiations().count(); ++i) {
+ const AbstractMetaType* type = containerType->instantiations().at(i);
+ QString typeName = getFullTypeName(type);
+ if (type->isValue() && isValueTypeWithCopyConstructorOnly(type)) {
+ static QRegExp regex(QLatin1String(CONVERTTOCPP_REGEX));
+ int pos = 0;
+ while ((pos = regex.indexIn(code, pos)) != -1) {
+ pos += regex.matchedLength();
+ QStringList list = regex.capturedTexts();
+ QString varName = list.at(1);
+ QString leftCode = code.left(pos);
+ QString rightCode = code.mid(pos);
+ rightCode.replace(varName, QLatin1Char('*') + varName);
+ code = leftCode + rightCode;
+ }
+ typeName.append(QLatin1Char('*'));
+ }
+ code.replace(QString::fromLatin1("%OUTTYPE_%1").arg(i), typeName);
+ }
+ code.replace(QLatin1String("%OUTTYPE"), cppTypeName);
+ code.replace(QLatin1String("%in"), QLatin1String("pyIn"));
+ code.replace(QLatin1String("%out"), QLatin1String("cppOutRef"));
+ QString typeName = fixedCppTypeName(containerType);
+ writePythonToCppFunction(s, code, typeName, typeName);
+
+ // Python to C++ convertible check function.
+ QString typeCheck = cpythonCheckFunction(containerType);
+ if (typeCheck.isEmpty())
+ typeCheck = QLatin1String("false");
+ else
+ typeCheck = QString::fromLatin1("%1pyIn)").arg(typeCheck);
+ writeIsPythonConvertibleToCppFunction(s, typeName, typeName, typeCheck);
+ s << endl;
+}
+
+void CppGenerator::writeAddPythonToCppConversion(QTextStream& s, const QString& converterVar, const QString& pythonToCppFunc, const QString& isConvertibleFunc)
+{
+ s << INDENT << "Shiboken::Conversions::addPythonToCppValueConversion(" << converterVar << ',' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << pythonToCppFunc << ',' << endl;
+ s << INDENT << isConvertibleFunc;
+ }
+ s << ");" << endl;
+}
+
+void CppGenerator::writeNamedArgumentResolution(QTextStream& s, const AbstractMetaFunction* func, bool usePyArgs)
+{
+ AbstractMetaArgumentList args = OverloadData::getArgumentsWithDefaultValues(func);
+ if (args.isEmpty())
+ return;
+
+ QString pyErrString(QLatin1String("PyErr_SetString(PyExc_TypeError, \"") + fullPythonFunctionName(func)
+ + QLatin1String("(): got multiple values for keyword argument '%1'.\");"));
+
+ s << INDENT << "if (kwds) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyObject* ";
+ foreach (const AbstractMetaArgument* arg, args) {
+ int pyArgIndex = arg->argumentIndex() - OverloadData::numberOfRemovedArguments(func, arg->argumentIndex());
+ QString pyArgName = usePyArgs
+ ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(pyArgIndex)
+ : QLatin1String(PYTHON_ARG);
+ s << "value = PyDict_GetItemString(kwds, \"" << arg->name() << "\");" << endl;
+ s << INDENT << "if (value && " << pyArgName << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << pyErrString.arg(arg->name()) << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << "} else if (value) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << pyArgName << " = value;" << endl;
+ s << INDENT << "if (!";
+ writeTypeCheck(s, arg->type(), pyArgName, isNumber(arg->type()->typeEntry()), func->typeReplaced(arg->argumentIndex() + 1));
+ s << ')' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "goto " << cpythonFunctionName(func) << "_TypeError;" << endl;
+ }
+ }
+ s << INDENT << '}' << endl;
+ if (arg != args.last())
+ s << INDENT;
+ }
+ }
+ s << INDENT << '}' << endl;
+}
+
+QString CppGenerator::argumentNameFromIndex(const AbstractMetaFunction* func, int argIndex, const AbstractMetaClass** wrappedClass)
+{
+ *wrappedClass = 0;
+ QString pyArgName;
+ if (argIndex == -1) {
+ pyArgName = QLatin1String(PYTHON_SELF_VAR);
+ *wrappedClass = func->implementingClass();
+ } else if (argIndex == 0) {
+ AbstractMetaType *funcType = func->type();
+ AbstractMetaType *returnType = getTypeWithoutContainer(funcType);
+ if (returnType) {
+ pyArgName = QLatin1String(PYTHON_RETURN_VAR);
+ *wrappedClass = AbstractMetaClass::findClass(classes(), returnType->typeEntry()->name());
+ } else {
+ QString message = QLatin1String("Invalid Argument index (0, return value) on function modification: ")
+ + (funcType ? funcType->name() : QLatin1String("void")) + QLatin1Char(' ');
+ if (const AbstractMetaClass *declaringClass = func->declaringClass())
+ message += declaringClass->name() + QLatin1String("::");
+ message += func->name() + QLatin1String("()");
+ qCWarning(lcShiboken).noquote().nospace() << message;
+ }
+ } else {
+ int realIndex = argIndex - 1 - OverloadData::numberOfRemovedArguments(func, argIndex - 1);
+ AbstractMetaType* argType = getTypeWithoutContainer(func->arguments().at(realIndex)->type());
+
+ if (argType) {
+ *wrappedClass = AbstractMetaClass::findClass(classes(), argType->typeEntry()->name());
+ if (argIndex == 1
+ && !func->isConstructor()
+ && OverloadData::isSingleArgument(getFunctionGroups(func->implementingClass())[func->name()]))
+ pyArgName = QLatin1String(PYTHON_ARG);
+ else
+ pyArgName = QString::fromLatin1(PYTHON_ARGS "[%1]").arg(argIndex - 1);
+ }
+ }
+ return pyArgName;
+}
+
+void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *func,
+ GeneratorContext &context, int maxArgs)
+{
+ s << INDENT << "// " << func->minimalSignature() << (func->isReverseOperator() ? " [reverse operator]": "") << endl;
+ if (func->isConstructor()) {
+ foreach (const CodeSnip &cs, func->injectedCodeSnips()) {
+ if (cs.position == TypeSystem::CodeSnipPositionEnd) {
+ s << INDENT << "overloadId = " << func->ownerClass()->functions().indexOf(const_cast<AbstractMetaFunction* const>(func)) << ';' << endl;
+ break;
+ }
+ }
+ }
+
+ if (func->isAbstract()) {
+ s << INDENT << "if (Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "))) {\n";
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '";
+ s << func->ownerClass()->name() << '.' << func->name() << "()' not implemented.\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << "}\n";
+ }
+
+ // Used to provide contextual information to custom code writer function.
+ const AbstractMetaArgument* lastArg = 0;
+
+ CodeSnipList snips;
+ if (func->hasInjectedCode()) {
+ snips = func->injectedCodeSnips();
+
+ // Find the last argument available in the method call to provide
+ // the injected code writer with information to avoid invalid replacements
+ // on the %# variable.
+ if (maxArgs > 0 && maxArgs < func->arguments().size() - OverloadData::numberOfRemovedArguments(func)) {
+ int removedArgs = 0;
+ for (int i = 0; i < maxArgs + removedArgs; i++) {
+ lastArg = func->arguments().at(i);
+ if (func->argumentRemoved(i + 1))
+ removedArgs++;
+ }
+ } else if (maxArgs != 0 && !func->arguments().isEmpty()) {
+ lastArg = func->arguments().last();
+ }
+
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode, func, lastArg);
+ s << endl;
+ }
+
+ writeConversionRule(s, func, TypeSystem::NativeCode);
+
+ if (!func->isUserAdded()) {
+ QStringList userArgs;
+ if (func->functionType() != AbstractMetaFunction::CopyConstructorFunction) {
+ int removedArgs = 0;
+ for (int i = 0; i < maxArgs + removedArgs; i++) {
+ const AbstractMetaArgument* arg = func->arguments().at(i);
+ bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, arg->argumentIndex() + 1).isEmpty();
+ if (func->argumentRemoved(i + 1)) {
+ // If some argument with default value is removed from a
+ // method signature, the said value must be explicitly
+ // added to the method call.
+ removedArgs++;
+
+ // If have conversion rules I will use this for removed args
+ if (hasConversionRule)
+ userArgs << arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX);
+ else if (!arg->defaultValueExpression().isEmpty())
+ userArgs << QString::fromLatin1(CPP_ARG_REMOVED "%1").arg(i);
+ } else {
+ int idx = arg->argumentIndex() - removedArgs;
+ bool deRef = isValueTypeWithCopyConstructorOnly(arg->type())
+ || isObjectTypeUsedAsValueType(arg->type())
+ || (arg->type()->referenceType() == LValueReference && isWrapperType(arg->type()) && !isPointer(arg->type()));
+ QString argName = hasConversionRule
+ ? arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX)
+ : QString::fromLatin1("%1" CPP_ARG "%2").arg(deRef ? QLatin1String("*") : QString()).arg(idx);
+ userArgs << argName;
+ }
+ }
+
+ // If any argument's default value was modified the method must be called
+ // with this new value whenever the user doesn't pass an explicit value to it.
+ // Also, any unmodified default value coming after the last user specified
+ // argument and before the modified argument must be explicitly stated.
+ QStringList otherArgs;
+ bool otherArgsModified = false;
+ bool argsClear = true;
+ for (int i = func->arguments().size() - 1; i >= maxArgs + removedArgs; i--) {
+ const AbstractMetaArgument* arg = func->arguments().at(i);
+ bool defValModified = arg->defaultValueExpression() != arg->originalDefaultValueExpression();
+ bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, arg->argumentIndex() + 1).isEmpty();
+ if (argsClear && !defValModified && !hasConversionRule)
+ continue;
+ else
+ argsClear = false;
+ otherArgsModified |= defValModified || hasConversionRule || func->argumentRemoved(i + 1);
+ if (hasConversionRule)
+ otherArgs.prepend(arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX));
+ else
+ otherArgs.prepend(QString::fromLatin1(CPP_ARG_REMOVED "%1").arg(i));
+ }
+ if (otherArgsModified)
+ userArgs << otherArgs;
+ }
+
+ bool isCtor = false;
+ QString methodCall;
+ QTextStream mc(&methodCall);
+ QString useVAddr;
+ QTextStream uva(&useVAddr);
+ if (func->isOperatorOverload() && !func->isCallOperator()) {
+ QString firstArg = QLatin1String("(*" CPP_SELF_VAR ")");
+ if (func->isPointerOperator())
+ firstArg.remove(1, 1); // remove the de-reference operator
+
+ QString secondArg = QLatin1String(CPP_ARG0);
+ if (!func->isUnaryOperator() && shouldDereferenceArgumentPointer(func->arguments().first())) {
+ secondArg.prepend(QLatin1String("(*"));
+ secondArg.append(QLatin1Char(')'));
+ }
+
+ if (func->isUnaryOperator())
+ std::swap(firstArg, secondArg);
+
+ QString op = func->originalName();
+ op = op.right(op.size() - (sizeof("operator")/sizeof(char)-1));
+
+ if (func->isBinaryOperator()) {
+ if (func->isReverseOperator())
+ std::swap(firstArg, secondArg);
+
+ if (((op == QLatin1String("++")) || (op == QLatin1String("--"))) && !func->isReverseOperator()) {
+ s << endl << INDENT << "for(int i=0; i < " << secondArg << "; i++, " << firstArg << op << ");" << endl;
+ mc << firstArg;
+ } else {
+ mc << firstArg << ' ' << op << ' ' << secondArg;
+ }
+ } else {
+ mc << op << ' ' << secondArg;
+ }
+ } else if (!injectedCodeCallsCppFunction(func)) {
+ if (func->isConstructor()) {
+ isCtor = true;
+ QString className = wrapperName(func->ownerClass());
+
+ if (func->functionType() == AbstractMetaFunction::CopyConstructorFunction && maxArgs == 1) {
+ mc << "new ::" << className << "(*" << CPP_ARG0 << ')';
+ } else {
+ QString ctorCall = className + QLatin1Char('(') + userArgs.join(QLatin1String(", ")) + QLatin1Char(')');
+ if (usePySideExtensions() && func->ownerClass()->isQObject()) {
+ s << INDENT << "void* addr = PySide::nextQObjectMemoryAddr();" << endl;
+ uva << "if (addr) {" << endl;
+ {
+ Indentation indent(INDENT);
+
+ uva << INDENT << "cptr = " << "new (addr) ::"
+ << ctorCall << ';' << endl
+ << INDENT
+ << "PySide::setNextQObjectMemoryAddr(0);"
+ << endl;
+ }
+ uva << INDENT << "} else {" << endl;
+ {
+ Indentation indent(INDENT);
+
+ uva << INDENT << "cptr = " << "new ::"
+ << ctorCall << ';' << endl;
+ }
+ uva << INDENT << "}" << endl;
+ } else {
+ mc << "new ::" << ctorCall;
+ }
+ }
+ } else {
+ QString methodCallClassName;
+ if (context.forSmartPointer())
+ methodCallClassName = context.preciseType()->cppSignature();
+ else if (func->ownerClass())
+ methodCallClassName = func->ownerClass()->qualifiedCppName();
+
+ if (func->ownerClass()) {
+ if (!avoidProtectedHack() || !func->isProtected()) {
+ if (func->isStatic()) {
+ mc << "::" << methodCallClassName << "::";
+ } else {
+ const QString selfVarCast = func->ownerClass() == func->implementingClass()
+ ? QLatin1String(CPP_SELF_VAR)
+ : QLatin1String("reinterpret_cast<") + methodCallClassName + QLatin1String(" *>(" CPP_SELF_VAR ")");
+ if (func->isConstant()) {
+ if (avoidProtectedHack()) {
+ mc << "const_cast<const ::";
+ if (func->ownerClass()->hasProtectedMembers()) {
+ // PYSIDE-500: Need a special wrapper cast when inherited
+ const QString selfWrapCast = func->ownerClass() == func->implementingClass()
+ ? QLatin1String(CPP_SELF_VAR)
+ : QLatin1String("reinterpret_cast<") + wrapperName(func->ownerClass()) + QLatin1String(" *>(" CPP_SELF_VAR ")");
+ mc << wrapperName(func->ownerClass());
+ mc << "*>(" << selfWrapCast << ")->";
+ }
+ else {
+ mc << methodCallClassName;
+ mc << "*>(" << selfVarCast << ")->";
+ }
+ } else {
+ mc << "const_cast<const ::" << methodCallClassName;
+ mc << "*>(" << selfVarCast << ")->";
+ }
+ } else {
+ mc << selfVarCast << "->";
+ }
+ }
+
+ if (!func->isAbstract() && func->isVirtual())
+ mc << "::%CLASS_NAME::";
+
+ mc << func->originalName();
+ } else {
+ if (!func->isStatic())
+ mc << "((::" << wrapperName(func->ownerClass()) << "*) " << CPP_SELF_VAR << ")->";
+
+ if (!func->isAbstract())
+ mc << (func->isProtected() ? wrapperName(func->ownerClass()) :
+ QLatin1String("::")
+ + methodCallClassName) << "::";
+ mc << func->originalName() << "_protected";
+ }
+ } else {
+ mc << func->originalName();
+ }
+ mc << '(' << userArgs.join(QLatin1String(", ")) << ')';
+ if (!func->isAbstract() && func->isVirtual()) {
+ mc.flush();
+ if (!avoidProtectedHack() || !func->isProtected()) {
+ QString virtualCall(methodCall);
+ QString normalCall(methodCall);
+ virtualCall = virtualCall.replace(QLatin1String("%CLASS_NAME"),
+ methodCallClassName);
+ normalCall.remove(QLatin1String("::%CLASS_NAME::"));
+ methodCall.clear();
+ mc << "Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ")) ? ";
+ mc << virtualCall << " : " << normalCall;
+ }
+ }
+ }
+ }
+
+ if (!injectedCodeCallsCppFunction(func)) {
+ s << INDENT << BEGIN_ALLOW_THREADS << endl << INDENT;
+ if (isCtor) {
+ s << (useVAddr.isEmpty() ?
+ QString::fromLatin1("cptr = %1;").arg(methodCall) : useVAddr) << endl;
+ } else if (func->type() && !func->isInplaceOperator()) {
+ bool writeReturnType = true;
+ if (avoidProtectedHack()) {
+ const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(func->type());
+ if (metaEnum) {
+ QString enumName;
+ if (metaEnum->isProtected())
+ enumName = protectedEnumSurrogateName(metaEnum);
+ else
+ enumName = func->type()->cppSignature();
+ methodCall.prepend(enumName + QLatin1Char('('));
+ methodCall.append(QLatin1Char(')'));
+ s << enumName;
+ writeReturnType = false;
+ }
+ }
+ if (writeReturnType) {
+ s << func->type()->cppSignature();
+ if (isObjectTypeUsedAsValueType(func->type())) {
+ s << '*';
+ methodCall.prepend(QString::fromLatin1("new %1(").arg(func->type()->typeEntry()->qualifiedCppName()));
+ methodCall.append(QLatin1Char(')'));
+ }
+ }
+ s << " " CPP_RETURN_VAR " = ";
+ s << methodCall << ';' << endl;
+ } else {
+ s << methodCall << ';' << endl;
+ }
+ s << INDENT << END_ALLOW_THREADS << endl;
+
+ if (!func->conversionRule(TypeSystem::TargetLangCode, 0).isEmpty()) {
+ writeConversionRule(s, func, TypeSystem::TargetLangCode, QLatin1String(PYTHON_RETURN_VAR));
+ } else if (!isCtor && !func->isInplaceOperator() && func->type()
+ && !injectedCodeHasReturnValueAttribution(func, TypeSystem::TargetLangCode)) {
+ s << INDENT << PYTHON_RETURN_VAR " = ";
+ if (isObjectTypeUsedAsValueType(func->type())) {
+ s << "Shiboken::Object::newObject(reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(func->type()->typeEntry())
+ << "), " << CPP_RETURN_VAR << ", true, true)";
+ } else {
+ writeToPythonConversion(s, func->type(), func->ownerClass(), QLatin1String(CPP_RETURN_VAR));
+ }
+ s << ';' << endl;
+ }
+ }
+ }
+
+ if (func->hasInjectedCode() && !func->isConstructor()) {
+ s << endl;
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode, func, lastArg);
+ }
+
+ bool hasReturnPolicy = false;
+
+ // Ownership transference between C++ and Python.
+ QList<ArgumentModification> ownership_mods;
+ // Python object reference management.
+ QList<ArgumentModification> refcount_mods;
+ foreach (const FunctionModification &func_mod, func->modifications()) {
+ foreach (const ArgumentModification &arg_mod, func_mod.argument_mods) {
+ if (!arg_mod.ownerships.isEmpty() && arg_mod.ownerships.contains(TypeSystem::TargetLangCode))
+ ownership_mods.append(arg_mod);
+ else if (!arg_mod.referenceCounts.isEmpty())
+ refcount_mods.append(arg_mod);
+ }
+ }
+
+ // If there's already a setParent(return, me), don't use the return heuristic!
+ if (func->argumentOwner(func->ownerClass(), -1).index == 0)
+ hasReturnPolicy = true;
+
+ if (!ownership_mods.isEmpty()) {
+ s << endl << INDENT << "// Ownership transferences." << endl;
+ foreach (const ArgumentModification &arg_mod, ownership_mods) {
+ const AbstractMetaClass* wrappedClass = 0;
+ QString pyArgName = argumentNameFromIndex(func, arg_mod.index, &wrappedClass);
+ if (!wrappedClass) {
+ s << "#error Invalid ownership modification for argument " << arg_mod.index << '(' << pyArgName << ')' << endl << endl;
+ break;
+ }
+
+ if (arg_mod.index == 0 || arg_mod.owner.index == 0)
+ hasReturnPolicy = true;
+
+ // The default ownership does nothing. This is useful to avoid automatic heuristically
+ // based generation of code defining parenting.
+ if (arg_mod.ownerships[TypeSystem::TargetLangCode] == TypeSystem::DefaultOwnership)
+ continue;
+
+ s << INDENT << "Shiboken::Object::";
+ if (arg_mod.ownerships[TypeSystem::TargetLangCode] == TypeSystem::TargetLangOwnership) {
+ s << "getOwnership(" << pyArgName << ");";
+ } else if (wrappedClass->hasVirtualDestructor()) {
+ if (arg_mod.index == 0)
+ s << "releaseOwnership(" PYTHON_RETURN_VAR ");";
+ else
+ s << "releaseOwnership(" << pyArgName << ");";
+ } else {
+ s << "invalidate(" << pyArgName << ");";
+ }
+ s << endl;
+ }
+
+ } else if (!refcount_mods.isEmpty()) {
+ foreach (const ArgumentModification &arg_mod, refcount_mods) {
+ ReferenceCount refCount = arg_mod.referenceCounts.first();
+ if (refCount.action != ReferenceCount::Set
+ && refCount.action != ReferenceCount::Remove
+ && refCount.action != ReferenceCount::Add) {
+ qCWarning(lcShiboken) << "\"set\", \"add\" and \"remove\" are the only values supported by Shiboken for action attribute of reference-count tag.";
+ continue;
+ }
+ const AbstractMetaClass* wrappedClass = 0;
+
+ QString pyArgName;
+ if (refCount.action == ReferenceCount::Remove) {
+ pyArgName = QLatin1String("Py_None");
+ } else {
+ pyArgName = argumentNameFromIndex(func, arg_mod.index, &wrappedClass);
+ if (pyArgName.isEmpty()) {
+ s << "#error Invalid reference count modification for argument " << arg_mod.index << endl << endl;
+ break;
+ }
+ }
+
+ if (refCount.action == ReferenceCount::Add || refCount.action == ReferenceCount::Set)
+ s << INDENT << "Shiboken::Object::keepReference(";
+ else
+ s << INDENT << "Shiboken::Object::removeReference(";
+
+ s << "reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "), \"";
+ QString varName = arg_mod.referenceCounts.first().varName;
+ if (varName.isEmpty())
+ varName = func->minimalSignature() + QString().number(arg_mod.index);
+
+ s << varName << "\", " << pyArgName
+ << (refCount.action == ReferenceCount::Add ? ", true" : "")
+ << ");" << endl;
+
+ if (arg_mod.index == 0)
+ hasReturnPolicy = true;
+ }
+ }
+ writeParentChildManagement(s, func, !hasReturnPolicy);
+}
+
+QStringList CppGenerator::getAncestorMultipleInheritance(const AbstractMetaClass* metaClass)
+{
+ QStringList result;
+ AbstractMetaClassList baseClases = getBaseClasses(metaClass);
+ if (!baseClases.isEmpty()) {
+ foreach (const AbstractMetaClass* baseClass, baseClases) {
+ result.append(QString::fromLatin1("((size_t) static_cast<const %1*>(class_ptr)) - base")
+ .arg(baseClass->qualifiedCppName()));
+ result.append(QString::fromLatin1("((size_t) static_cast<const %1*>((%2*)((void*)class_ptr))) - base")
+ .arg(baseClass->qualifiedCppName(), metaClass->qualifiedCppName()));
+ }
+ foreach (const AbstractMetaClass* baseClass, baseClases)
+ result.append(getAncestorMultipleInheritance(baseClass));
+ }
+ return result;
+}
+
+void CppGenerator::writeMultipleInheritanceInitializerFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString className = metaClass->qualifiedCppName();
+ QStringList ancestors = getAncestorMultipleInheritance(metaClass);
+ s << "static int mi_offsets[] = { ";
+ for (int i = 0; i < ancestors.size(); i++)
+ s << "-1, ";
+ s << "-1 };" << endl;
+ s << "int*" << endl;
+ s << multipleInheritanceInitializerFunctionName(metaClass) << "(const void* cptr)" << endl;
+ s << '{' << endl;
+ s << INDENT << "if (mi_offsets[0] == -1) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "std::set<int> offsets;" << endl;
+ s << INDENT << "std::set<int>::iterator it;" << endl;
+ s << INDENT << "const " << className << "* class_ptr = reinterpret_cast<const " << className << "*>(cptr);" << endl;
+ s << INDENT << "size_t base = (size_t) class_ptr;" << endl;
+
+ foreach (const QString &ancestor, ancestors)
+ s << INDENT << "offsets.insert(" << ancestor << ");" << endl;
+
+ s << endl;
+ s << INDENT << "offsets.erase(0);" << endl;
+ s << endl;
+
+ s << INDENT << "int i = 0;" << endl;
+ s << INDENT << "for (it = offsets.begin(); it != offsets.end(); it++) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "mi_offsets[i] = *it;" << endl;
+ s << INDENT << "i++;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ }
+ s << INDENT << '}' << endl;
+ s << INDENT << "return mi_offsets;" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeSpecialCastFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString className = metaClass->qualifiedCppName();
+ s << "static void* " << cpythonSpecialCastFunctionName(metaClass) << "(void* obj, SbkObjectType* desiredType)\n";
+ s << "{\n";
+ s << INDENT << className << "* me = reinterpret_cast< ::" << className << "*>(obj);\n";
+ bool firstClass = true;
+ foreach (const AbstractMetaClass* baseClass, getAllAncestors(metaClass)) {
+ s << INDENT << (!firstClass ? "else " : "") << "if (desiredType == reinterpret_cast<SbkObjectType*>(" << cpythonTypeNameExt(baseClass->typeEntry()) << "))\n";
+ Indentation indent(INDENT);
+ s << INDENT << "return static_cast< ::" << baseClass->qualifiedCppName() << "*>(me);\n";
+ firstClass = false;
+ }
+ s << INDENT << "return me;\n";
+ s << "}\n\n";
+}
+
+void CppGenerator::writePrimitiveConverterInitialization(QTextStream& s, const CustomConversion* customConversion)
+{
+ const TypeEntry* type = customConversion->ownerType();
+ QString converter = converterObject(type);
+ s << INDENT << "// Register converter for type '" << type->qualifiedTargetLangName() << "'." << endl;
+ s << INDENT << converter << " = Shiboken::Conversions::createConverter(";
+ if (type->targetLangApiName() == type->name())
+ s << '0';
+ else if (type->targetLangApiName() == QLatin1String("PyObject"))
+ s << "&PyBaseObject_Type";
+ else
+ s << '&' << type->targetLangApiName() << "_Type";
+ QString typeName = fixedCppTypeName(type);
+ s << ", " << cppToPythonFunctionName(typeName, typeName) << ");" << endl;
+ s << INDENT << "Shiboken::Conversions::registerConverterName(" << converter << ", \"" << type->qualifiedCppName() << "\");" << endl;
+ writeCustomConverterRegister(s, customConversion, converter);
+}
+
+void CppGenerator::writeEnumConverterInitialization(QTextStream& s, const AbstractMetaEnum* metaEnum)
+{
+ if (metaEnum->isPrivate() || metaEnum->isAnonymous())
+ return;
+ writeEnumConverterInitialization(s, metaEnum->typeEntry());
+}
+
+void CppGenerator::writeEnumConverterInitialization(QTextStream& s, const TypeEntry* enumType)
+{
+ if (!enumType)
+ return;
+ QString enumFlagName = enumType->isFlags() ? QLatin1String("flag") : QLatin1String("enum");
+ QString enumPythonType = cpythonTypeNameExt(enumType);
+
+ const FlagsTypeEntry* flags = 0;
+ if (enumType->isFlags())
+ flags = reinterpret_cast<const FlagsTypeEntry*>(enumType);
+
+ s << INDENT << "// Register converter for " << enumFlagName << " '" << enumType->qualifiedCppName() << "'." << endl;
+ s << INDENT << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ QString typeName = fixedCppTypeName(enumType);
+ s << INDENT << "SbkConverter* converter = Shiboken::Conversions::createConverter(" << enumPythonType << ',' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << cppToPythonFunctionName(typeName, typeName) << ");" << endl;
+ }
+
+ if (flags) {
+ QString enumTypeName = fixedCppTypeName(flags->originator());
+ QString toCpp = pythonToCppFunctionName(enumTypeName, typeName);
+ QString isConv = convertibleToCppFunctionName(enumTypeName, typeName);
+ writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
+ }
+
+ QString toCpp = pythonToCppFunctionName(typeName, typeName);
+ QString isConv = convertibleToCppFunctionName(typeName, typeName);
+ writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
+
+ if (flags) {
+ QString toCpp = pythonToCppFunctionName(QLatin1String("number"), typeName);
+ QString isConv = convertibleToCppFunctionName(QLatin1String("number"), typeName);
+ writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
+ }
+
+ s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", converter);" << endl;
+ s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", converter);" << endl;
+ QStringList cppSignature = enumType->qualifiedCppName().split(QLatin1String("::"), QString::SkipEmptyParts);
+ while (!cppSignature.isEmpty()) {
+ QString signature = cppSignature.join(QLatin1String("::"));
+ s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"";
+ if (flags)
+ s << "QFlags<";
+ s << signature << "\");" << endl;
+ cppSignature.removeFirst();
+ }
+ }
+ s << INDENT << '}' << endl;
+
+ if (!flags)
+ writeEnumConverterInitialization(s, reinterpret_cast<const EnumTypeEntry*>(enumType)->flags());
+}
+
+void CppGenerator::writeContainerConverterInitialization(QTextStream& s, const AbstractMetaType* type)
+{
+ QByteArray cppSignature = QMetaObject::normalizedSignature(type->cppSignature().toUtf8());
+ s << INDENT << "// Register converter for type '" << cppSignature << "'." << endl;
+ QString converter = converterObject(type);
+ s << INDENT << converter << " = Shiboken::Conversions::createConverter(";
+ if (type->typeEntry()->targetLangApiName() == QLatin1String("PyObject")) {
+ s << "&PyBaseObject_Type";
+ } else {
+ QString baseName = cpythonBaseName(type->typeEntry());
+ if (baseName == QLatin1String("PySequence"))
+ baseName = QLatin1String("PyList");
+ s << '&' << baseName << "_Type";
+ }
+ QString typeName = fixedCppTypeName(type);
+ s << ", " << cppToPythonFunctionName(typeName, typeName) << ");" << endl;
+ QString toCpp = pythonToCppFunctionName(typeName, typeName);
+ QString isConv = convertibleToCppFunctionName(typeName, typeName);
+ s << INDENT << "Shiboken::Conversions::registerConverterName(" << converter << ", \"" << cppSignature << "\");" << endl;
+ if (usePySideExtensions() && cppSignature.startsWith("const ") && cppSignature.endsWith("&")) {
+ cppSignature.chop(1);
+ cppSignature.remove(0, sizeof("const ") / sizeof(char) - 1);
+ s << INDENT << "Shiboken::Conversions::registerConverterName(" << converter << ", \"" << cppSignature << "\");" << endl;
+ }
+ writeAddPythonToCppConversion(s, converterObject(type), toCpp, isConv);
+}
+
+void CppGenerator::writeExtendedConverterInitialization(QTextStream& s, const TypeEntry* externalType, const QList<const AbstractMetaClass*>& conversions)
+{
+ s << INDENT << "// Extended implicit conversions for " << externalType->qualifiedTargetLangName() << '.' << endl;
+ foreach (const AbstractMetaClass* sourceClass, conversions) {
+ const QString converterVar = QLatin1String("reinterpret_cast<SbkObjectType *>(")
+ + cppApiVariableName(externalType->targetLangPackage()) + QLatin1Char('[')
+ + getTypeIndexVariableName(externalType) + QLatin1String("])");
+ QString sourceTypeName = fixedCppTypeName(sourceClass->typeEntry());
+ QString targetTypeName = fixedCppTypeName(externalType);
+ QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName);
+ QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName);
+ writeAddPythonToCppConversion(s, converterVar, toCpp, isConv);
+ }
+}
+
+QString CppGenerator::multipleInheritanceInitializerFunctionName(const AbstractMetaClass* metaClass)
+{
+ if (!hasMultipleInheritanceInAncestry(metaClass))
+ return QString();
+ return cpythonBaseName(metaClass->typeEntry()) + QLatin1String("_mi_init");
+}
+
+typedef QHash<QString, QPair<QString, QString> >::const_iterator ProtocolIt;
+
+bool CppGenerator::supportsMappingProtocol(const AbstractMetaClass* metaClass)
+{
+ for (ProtocolIt it = m_mappingProtocol.cbegin(), end = m_mappingProtocol.cend(); it != end; ++it) {
+ if (metaClass->hasFunction(it.key()))
+ return true;
+ }
+
+ return false;
+}
+
+bool CppGenerator::supportsNumberProtocol(const AbstractMetaClass* metaClass)
+{
+ return metaClass->hasArithmeticOperatorOverload()
+ || metaClass->hasLogicalOperatorOverload()
+ || metaClass->hasBitwiseOperatorOverload()
+ || hasBoolCast(metaClass);
+}
+
+bool CppGenerator::supportsSequenceProtocol(const AbstractMetaClass* metaClass)
+{
+ for (ProtocolIt it = m_sequenceProtocol.cbegin(), end = m_sequenceProtocol.cend(); it != end; ++it) {
+ if (metaClass->hasFunction(it.key()))
+ return true;
+ }
+
+ const ComplexTypeEntry* baseType = metaClass->typeEntry()->baseContainerType();
+ if (baseType && baseType->isContainer())
+ return true;
+
+ return false;
+}
+
+bool CppGenerator::shouldGenerateGetSetList(const AbstractMetaClass* metaClass)
+{
+ foreach (AbstractMetaField* f, metaClass->fields()) {
+ if (!f->isStatic())
+ return true;
+ }
+ return false;
+}
+
+void CppGenerator::writeClassDefinition(QTextStream &s,
+ const AbstractMetaClass *metaClass,
+ GeneratorContext &classContext)
+{
+ QString tp_flags;
+ QString tp_init;
+ QString tp_new;
+ QString tp_dealloc;
+ QString tp_hash(QLatin1Char('0'));
+ QString tp_call = tp_hash;
+ QString cppClassName = metaClass->qualifiedCppName();
+ QString className = cpythonTypeName(metaClass);
+ className.remove(QRegExp(QLatin1String("_Type$")));
+ QString baseClassName(QLatin1Char('0'));
+ AbstractMetaFunctionList ctors;
+ foreach (AbstractMetaFunction* f, metaClass->queryFunctions(AbstractMetaClass::Constructors)) {
+ if (!f->isPrivate() && !f->isModifiedRemoved() && !classContext.forSmartPointer())
+ ctors.append(f);
+ }
+
+ if (!metaClass->baseClass())
+ baseClassName = QLatin1String("reinterpret_cast<PyTypeObject*>(&SbkObject_Type)");
+
+ bool onlyPrivCtor = !metaClass->hasNonPrivateConstructor();
+
+ if (metaClass->isNamespace() || metaClass->hasPrivateDestructor()) {
+ tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_GC");
+ tp_dealloc = metaClass->hasPrivateDestructor() ?
+ QLatin1String("SbkDeallocWrapperWithPrivateDtor") : QLatin1String("0");
+ tp_init = QLatin1String("0");
+ } else {
+ if (onlyPrivCtor)
+ tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_GC");
+ else
+ tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_GC");
+
+ QString deallocClassName;
+ if (shouldGenerateCppWrapper(metaClass))
+ deallocClassName = wrapperName(metaClass);
+ else
+ deallocClassName = cppClassName;
+ tp_dealloc = QLatin1String("&SbkDeallocWrapper");
+ // avoid constFirst to stay Qt 5.5 compatible
+ tp_init = (onlyPrivCtor || ctors.isEmpty()) ? QLatin1String("0") : cpythonFunctionName(ctors.first());
+ }
+
+ QString tp_getattro(QLatin1Char('0'));
+ QString tp_setattro = tp_getattro;
+ if (usePySideExtensions() && (metaClass->qualifiedCppName() == QLatin1String("QObject"))) {
+ tp_getattro = cpythonGetattroFunctionName(metaClass);
+ tp_setattro = cpythonSetattroFunctionName(metaClass);
+ } else {
+ if (classNeedsGetattroFunction(metaClass))
+ tp_getattro = cpythonGetattroFunctionName(metaClass);
+ if (classNeedsSetattroFunction(metaClass))
+ tp_setattro = cpythonSetattroFunctionName(metaClass);
+ }
+
+ if (metaClass->hasPrivateDestructor() || onlyPrivCtor)
+ tp_new = QLatin1String("0");
+ else
+ tp_new = QLatin1String("SbkObjectTpNew");
+
+ QString tp_richcompare = QString(QLatin1Char('0'));
+ if (metaClass->hasComparisonOperatorOverload())
+ tp_richcompare = cpythonBaseName(metaClass) + QLatin1String("_richcompare");
+
+ QString tp_getset = QString(QLatin1Char('0'));
+ if (shouldGenerateGetSetList(metaClass) && !classContext.forSmartPointer())
+ tp_getset = cpythonGettersSettersDefinitionName(metaClass);
+
+ // search for special functions
+ ShibokenGenerator::clearTpFuncs();
+ foreach (AbstractMetaFunction* func, metaClass->functions()) {
+ if (m_tpFuncs.contains(func->name()))
+ m_tpFuncs[func->name()] = cpythonFunctionName(func);
+ }
+ if (m_tpFuncs[QLatin1String("__repr__")] == QLatin1String("0")
+ && !metaClass->isQObject()
+ && metaClass->hasToStringCapability()) {
+ m_tpFuncs[QLatin1String("__repr__")] = writeReprFunction(s, classContext);
+ }
+
+ // class or some ancestor has multiple inheritance
+ const AbstractMetaClass* miClass = getMultipleInheritingClass(metaClass);
+ if (miClass) {
+ if (metaClass == miClass)
+ writeMultipleInheritanceInitializerFunction(s, metaClass);
+ writeSpecialCastFunction(s, metaClass);
+ s << endl;
+ }
+
+ if (!metaClass->typeEntry()->hashFunction().isEmpty())
+ tp_hash = QLatin1Char('&') + cpythonBaseName(metaClass) + QLatin1String("_HashFunc");
+
+ const AbstractMetaFunction* callOp = metaClass->findFunction(QLatin1String("operator()"));
+ if (callOp && !callOp->isModifiedRemoved())
+ tp_call = QLatin1Char('&') + cpythonFunctionName(callOp);
+
+ s << "// Class Definition -----------------------------------------------" << endl;
+ s << "extern \"C\" {" << endl;
+
+ if (supportsNumberProtocol(metaClass)) {
+ s << "static PyNumberMethods " << className + QLatin1String("_TypeAsNumber") << ";" << endl;
+ s << endl;
+ }
+
+ if (supportsSequenceProtocol(metaClass)) {
+ s << "static PySequenceMethods " << className + QLatin1String("_TypeAsSequence") << ";" << endl;
+ s << endl;
+ }
+
+ if (supportsMappingProtocol(metaClass)) {
+ s << "static PyMappingMethods " << className + QLatin1String("_TypeAsMapping") << ";" << endl;
+ s << endl;
+ }
+
+ s << "static SbkObjectType " << className + QLatin1String("_Type") << " = { { {" << endl;
+ s << INDENT << "PyVarObject_HEAD_INIT(&SbkObjectType_Type, 0)" << endl;
+ QString computedClassTargetFullName;
+ if (!classContext.forSmartPointer())
+ computedClassTargetFullName = getClassTargetFullName(metaClass);
+ else
+ computedClassTargetFullName = getClassTargetFullName(classContext.preciseType());
+
+ s << INDENT << "/*tp_name*/ \"" << computedClassTargetFullName << "\"," << endl;
+ s << INDENT << "/*tp_basicsize*/ sizeof(SbkObject)," << endl;
+ s << INDENT << "/*tp_itemsize*/ 0," << endl;
+ s << INDENT << "/*tp_dealloc*/ " << tp_dealloc << ',' << endl;
+ s << INDENT << "/*tp_print*/ 0," << endl;
+ s << INDENT << "/*tp_getattr*/ 0," << endl;
+ s << INDENT << "/*tp_setattr*/ 0," << endl;
+ s << INDENT << "/*tp_compare*/ 0," << endl;
+ s << INDENT << "/*tp_repr*/ " << m_tpFuncs[QLatin1String("__repr__")] << "," << endl;
+ s << INDENT << "/*tp_as_number*/ 0," << endl;
+ s << INDENT << "/*tp_as_sequence*/ 0," << endl;
+ s << INDENT << "/*tp_as_mapping*/ 0," << endl;
+ s << INDENT << "/*tp_hash*/ " << tp_hash << ',' << endl;
+ s << INDENT << "/*tp_call*/ " << tp_call << ',' << endl;
+ s << INDENT << "/*tp_str*/ " << m_tpFuncs[QLatin1String("__str__")] << ',' << endl;
+ s << INDENT << "/*tp_getattro*/ " << tp_getattro << ',' << endl;
+ s << INDENT << "/*tp_setattro*/ " << tp_setattro << ',' << endl;
+ s << INDENT << "/*tp_as_buffer*/ 0," << endl;
+ s << INDENT << "/*tp_flags*/ " << tp_flags << ',' << endl;
+ s << INDENT << "/*tp_doc*/ 0," << endl;
+ s << INDENT << "/*tp_traverse*/ " << className << "_traverse," << endl;
+ s << INDENT << "/*tp_clear*/ " << className << "_clear," << endl;
+ s << INDENT << "/*tp_richcompare*/ " << tp_richcompare << ',' << endl;
+ s << INDENT << "/*tp_weaklistoffset*/ 0," << endl;
+ s << INDENT << "/*tp_iter*/ " << m_tpFuncs[QLatin1String("__iter__")] << ',' << endl;
+ s << INDENT << "/*tp_iternext*/ " << m_tpFuncs[QLatin1String("__next__")] << ',' << endl;
+ s << INDENT << "/*tp_methods*/ " << className << "_methods," << endl;
+ s << INDENT << "/*tp_members*/ 0," << endl;
+ s << INDENT << "/*tp_getset*/ " << tp_getset << ',' << endl;
+ s << INDENT << "/*tp_base*/ " << baseClassName << ',' << endl;
+ s << INDENT << "/*tp_dict*/ 0," << endl;
+ s << INDENT << "/*tp_descr_get*/ 0," << endl;
+ s << INDENT << "/*tp_descr_set*/ 0," << endl;
+ s << INDENT << "/*tp_dictoffset*/ 0," << endl;
+ s << INDENT << "/*tp_init*/ " << tp_init << ',' << endl;
+ s << INDENT << "/*tp_alloc*/ 0," << endl;
+ s << INDENT << "/*tp_new*/ " << tp_new << ',' << endl;
+ s << INDENT << "/*tp_free*/ 0," << endl;
+ s << INDENT << "/*tp_is_gc*/ 0," << endl;
+ s << INDENT << "/*tp_bases*/ 0," << endl;
+ s << INDENT << "/*tp_mro*/ 0," << endl;
+ s << INDENT << "/*tp_cache*/ 0," << endl;
+ s << INDENT << "/*tp_subclasses*/ 0," << endl;
+ s << INDENT << "/*tp_weaklist*/ 0" << endl;
+ s << "}, }," << endl;
+ s << INDENT << "/*priv_data*/ 0" << endl;
+ s << "};" << endl;
+ QString suffix;
+ if (isObjectType(metaClass))
+ suffix = QLatin1String("*");
+ s << "} //extern" << endl;
+}
+
+void CppGenerator::writeMappingMethods(QTextStream &s,
+ const AbstractMetaClass *metaClass,
+ GeneratorContext &context)
+{
+
+ QMap<QString, QString> funcs;
+
+ QHash< QString, QPair< QString, QString > >::const_iterator it = m_mappingProtocol.begin();
+ for (; it != m_mappingProtocol.end(); ++it) {
+ const AbstractMetaFunction* func = metaClass->findFunction(it.key());
+ if (!func)
+ continue;
+ QString funcName = cpythonFunctionName(func);
+ QString funcArgs = it.value().first;
+ QString funcRetVal = it.value().second;
+
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
+ s << funcRetVal << ' ' << funcName << '(' << funcArgs << ')' << endl << '{' << endl;
+ writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR));
+
+ writeCppSelfDefinition(s, func, context);
+
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, lastArg);
+ s << '}' << endl << endl;
+ }
+}
+
+void CppGenerator::writeSequenceMethods(QTextStream &s,
+ const AbstractMetaClass *metaClass,
+ GeneratorContext &context)
+{
+
+ QMap<QString, QString> funcs;
+ bool injectedCode = false;
+
+ QHash< QString, QPair< QString, QString > >::const_iterator it = m_sequenceProtocol.begin();
+ for (; it != m_sequenceProtocol.end(); ++it) {
+ const AbstractMetaFunction* func = metaClass->findFunction(it.key());
+ if (!func)
+ continue;
+ injectedCode = true;
+ QString funcName = cpythonFunctionName(func);
+ QString funcArgs = it.value().first;
+ QString funcRetVal = it.value().second;
+
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
+ s << funcRetVal << ' ' << funcName << '(' << funcArgs << ')' << endl << '{' << endl;
+ writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR));
+
+ writeCppSelfDefinition(s, func, context);
+
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, snips,TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, lastArg);
+ s << '}' << endl << endl;
+ }
+
+ if (!injectedCode)
+ writeStdListWrapperMethods(s, context);
+}
+
+void CppGenerator::writeTypeAsSequenceDefinition(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ bool hasFunctions = false;
+ QMap<QString, QString> funcs;
+ for (ProtocolIt it = m_sequenceProtocol.cbegin(), end = m_sequenceProtocol.cend(); it != end; ++it) {
+ const QString &funcName = it.key();
+ const AbstractMetaFunction* func = metaClass->findFunction(funcName);
+ funcs[funcName] = func ? cpythonFunctionName(func).prepend(QLatin1Char('&')) : QString();
+ if (!hasFunctions && func)
+ hasFunctions = true;
+ }
+
+ QString baseName = cpythonBaseName(metaClass);
+
+ //use default implementation
+ if (!hasFunctions) {
+ funcs[QLatin1String("__len__")] = baseName + QLatin1String("__len__");
+ funcs[QLatin1String("__getitem__")] = baseName + QLatin1String("__getitem__");
+ funcs[QLatin1String("__setitem__")] = baseName + QLatin1String("__setitem__");
+ }
+
+ s << INDENT << "memset(&" << baseName << "_TypeAsSequence, 0, sizeof(PySequenceMethods));" << endl;
+ for (QHash<QString, QString>::const_iterator it = m_sqFuncs.cbegin(), end = m_sqFuncs.cend(); it != end; ++it) {
+ const QString& sqName = it.key();
+ if (funcs[sqName].isEmpty())
+ continue;
+ if (it.value() == QLatin1String("sq_slice"))
+ s << "#ifndef IS_PY3K" << endl;
+ s << INDENT << baseName << "_TypeAsSequence." << it.value() << " = " << funcs[sqName] << ';' << endl;
+ if (it.value() == QLatin1String("sq_slice"))
+ s << "#endif" << endl;
+ }
+}
+
+void CppGenerator::writeTypeAsMappingDefinition(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ bool hasFunctions = false;
+ QMap<QString, QString> funcs;
+ for (ProtocolIt it = m_mappingProtocol.cbegin(), end = m_mappingProtocol.cend(); it != end; ++it) {
+ const QString &funcName = it.key();
+ const AbstractMetaFunction* func = metaClass->findFunction(funcName);
+ funcs[funcName] = func ? cpythonFunctionName(func).prepend(QLatin1Char('&')) : QLatin1String("0");
+ if (!hasFunctions && func)
+ hasFunctions = true;
+ }
+
+ //use default implementation
+ if (!hasFunctions) {
+ funcs.insert(QLatin1String("__mlen__"), QString());
+ funcs.insert(QLatin1String("__mgetitem__"), QString());
+ funcs.insert(QLatin1String("__msetitem__"), QString());
+ }
+
+ QString baseName = cpythonBaseName(metaClass);
+ s << INDENT << "memset(&" << baseName << "_TypeAsMapping, 0, sizeof(PyMappingMethods));" << endl;
+ for (QHash<QString, QString>::const_iterator it = m_mpFuncs.cbegin(), end = m_mpFuncs.end(); it != end; ++it) {
+ const QString &mpName = it.key();
+ if (funcs[mpName].isEmpty())
+ continue;
+ s << INDENT << baseName << "_TypeAsMapping." << it.value() << " = " << funcs[mpName] << ';' << endl;
+ }
+}
+
+void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QMap<QString, QString> nb;
+
+ nb.insert(QLatin1String("__add__"), QString());
+ nb.insert(QLatin1String("__sub__"), QString());
+ nb.insert(QLatin1String("__mul__"), QString());
+ nb.insert(QLatin1String("__div__"), QString());
+ nb.insert(QLatin1String("__mod__"), QString());
+ nb.insert(QLatin1String("__neg__"), QString());
+ nb.insert(QLatin1String("__pos__"), QString());
+ nb.insert(QLatin1String("__invert__"), QString());
+ nb.insert(QLatin1String("__lshift__"), QString());
+ nb.insert(QLatin1String("__rshift__"), QString());
+ nb.insert(QLatin1String("__and__"), QString());
+ nb.insert(QLatin1String("__xor__"), QString());
+ nb.insert(QLatin1String("__or__"), QString());
+ nb.insert(QLatin1String("__iadd__"), QString());
+ nb.insert(QLatin1String("__isub__"), QString());
+ nb.insert(QLatin1String("__imul__"), QString());
+ nb.insert(QLatin1String("__idiv__"), QString());
+ nb.insert(QLatin1String("__imod__"), QString());
+ nb.insert(QLatin1String("__ilshift__"), QString());
+ nb.insert(QLatin1String("__irshift__"), QString());
+ nb.insert(QLatin1String("__iand__"), QString());
+ nb.insert(QLatin1String("__ixor__"), QString());
+ nb.insert(QLatin1String("__ior__"), QString());
+
+ QList<AbstractMetaFunctionList> opOverloads =
+ filterGroupedOperatorFunctions(metaClass,
+ AbstractMetaClass::ArithmeticOp
+ | AbstractMetaClass::LogicalOp
+ | AbstractMetaClass::BitwiseOp);
+
+ foreach (const AbstractMetaFunctionList &opOverload, opOverloads) {
+ const AbstractMetaFunction* rfunc = opOverload[0];
+ QString opName = ShibokenGenerator::pythonOperatorFunctionName(rfunc);
+ nb[opName] = cpythonFunctionName(rfunc);
+ }
+
+ QString baseName = cpythonBaseName(metaClass);
+
+ nb[QLatin1String("bool")] = hasBoolCast(metaClass) ? baseName + QLatin1String("___nb_bool") : QString();
+
+ s << INDENT << "memset(&" << baseName << "_TypeAsNumber, 0, sizeof(PyNumberMethods));" << endl;
+ for (QHash<QString, QString>::const_iterator it = m_nbFuncs.cbegin(), end = m_nbFuncs.cend(); it != end; ++it) {
+ const QString &nbName = it.key();
+ if (nb[nbName].isEmpty())
+ continue;
+
+ // bool is special because the field name differs on Python 2 and 3 (nb_nonzero vs nb_bool)
+ // so a shiboken macro is used.
+ if (nbName == QLatin1String("bool")) {
+ s << INDENT << "SBK_NB_BOOL(" << baseName << "_TypeAsNumber) = " << nb[nbName] << ';' << endl;
+ } else {
+ bool excludeFromPy3K = nbName == QLatin1String("__div__") || nbName == QLatin1String("__idiv__");
+ if (excludeFromPy3K) {
+ s << "#ifdef IS_PY3K" << endl;
+ s << INDENT << "SBK_UNUSED(&" << nb[nbName] << ");" << endl;
+ s << "#else" << endl;
+ }
+ s << INDENT << baseName << "_TypeAsNumber." << it.value() << " = " << nb[nbName] << ';' << endl;
+ if (excludeFromPy3K)
+ s << "#endif" << endl;
+ }
+ }
+ if (!nb[QLatin1String("__div__")].isEmpty())
+ s << INDENT << baseName << "_TypeAsNumber.nb_true_divide = " << nb[QLatin1String("__div__")] << ';' << endl;
+}
+
+void CppGenerator::writeTpTraverseFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString baseName = cpythonBaseName(metaClass);
+ s << "static int ";
+ s << baseName << "_traverse(PyObject* " PYTHON_SELF_VAR ", visitproc visit, void* arg)" << endl;
+ s << '{' << endl;
+ s << INDENT << "return reinterpret_cast<PyTypeObject*>(&SbkObject_Type)->tp_traverse(" PYTHON_SELF_VAR ", visit, arg);" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeTpClearFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString baseName = cpythonBaseName(metaClass);
+ s << "static int ";
+ s << baseName << "_clear(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << '{' << endl;
+ s << INDENT << "return reinterpret_cast<PyTypeObject*>(&SbkObject_Type)->tp_clear(" PYTHON_SELF_VAR ");" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeCopyFunction(QTextStream &s, GeneratorContext &context)
+{
+ const AbstractMetaClass *metaClass = context.metaClass();
+ QString className = cpythonTypeName(metaClass);
+ className.remove(QRegExp(QLatin1String("_Type$")));
+ s << "static PyObject* " << className << "___copy__(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << "{" << endl;
+ writeCppSelfDefinition(s, context, false, true);
+ QString conversionCode;
+ if (!context.forSmartPointer())
+ conversionCode = cpythonToPythonConversionFunction(metaClass);
+ else
+ conversionCode = cpythonToPythonConversionFunction(context.preciseType());
+
+ s << INDENT << "PyObject* " << PYTHON_RETURN_VAR << " = " << conversionCode;
+ s << CPP_SELF_VAR ");" << endl;
+ writeFunctionReturnErrorCheckSection(s);
+ s << INDENT << "return " PYTHON_RETURN_VAR ";" << endl;
+ s << "}" << endl;
+ s << endl;
+}
+
+void CppGenerator::writeGetterFunction(QTextStream &s,
+ const AbstractMetaField *metaField,
+ GeneratorContext &context)
+{
+ ErrorCode errorCode(0);
+ s << "static PyObject* " << cpythonGetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", void*)" << endl;
+ s << '{' << endl;
+
+ writeCppSelfDefinition(s, context);
+
+ AbstractMetaType* fieldType = metaField->type();
+ // Force use of pointer to return internal variable memory
+ bool newWrapperSameObject = !fieldType->isConstant() && isWrapperType(fieldType) && !isPointer(fieldType);
+
+ QString cppField;
+ if (avoidProtectedHack() && metaField->isProtected()) {
+ cppField = QString::fromLatin1("((%1*)%2)->%3()")
+ .arg(wrapperName(metaField->enclosingClass()), QLatin1String(CPP_SELF_VAR),
+ protectedFieldGetterName(metaField));
+ } else {
+ cppField = QLatin1String(CPP_SELF_VAR) + QLatin1String("->") + metaField->name();
+ if (newWrapperSameObject) {
+ cppField.prepend(QLatin1String("&("));
+ cppField.append(QLatin1Char(')'));
+ }
+ }
+ if (isCppIntegralPrimitive(fieldType) || fieldType->isEnum()) {
+ s << INDENT << getFullTypeNameWithoutModifiers(fieldType) << " cppOut_local = " << cppField << ';' << endl;
+ cppField = QLatin1String("cppOut_local");
+ } else if (avoidProtectedHack() && metaField->isProtected()) {
+ s << INDENT << getFullTypeNameWithoutModifiers(fieldType);
+ if (fieldType->isContainer() || fieldType->isFlags() || fieldType->isSmartPointer()) {
+ s << '&';
+ cppField.prepend(QLatin1Char('*'));
+ } else if ((!fieldType->isConstant() && !fieldType->isEnum() && !fieldType->isPrimitive()) || fieldType->indirections() == 1) {
+ s << '*';
+ }
+ s << " fieldValue = " << cppField << ';' << endl;
+ cppField = QLatin1String("fieldValue");
+ }
+
+ s << INDENT << "PyObject* pyOut = 0;\n";
+ if (newWrapperSameObject) {
+ // Special case colocated field with same address (first field in a struct)
+ s << INDENT << "if (reinterpret_cast<void *>("
+ << cppField
+ << ") == reinterpret_cast<void *>("
+ << CPP_SELF_VAR << ")) {\n";
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "pyOut = reinterpret_cast<PyObject *>(Shiboken::Object::findColocatedChild("
+ << "reinterpret_cast<SbkObject *>(self), reinterpret_cast<const SbkObjectType *>("
+ << cpythonTypeNameExt(fieldType)
+ << ")));\n";
+ s << INDENT << "if (pyOut) {Py_IncRef(pyOut); return pyOut;}\n";
+ }
+ s << INDENT << "}\n";
+ // Check if field wrapper has already been created.
+ s << INDENT << "else if (Shiboken::BindingManager::instance().hasWrapper(" << cppField << ")) {" << "\n";
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "pyOut = (PyObject*)Shiboken::BindingManager::instance().retrieveWrapper(" << cppField << ");" << "\n";
+ s << INDENT << "Py_IncRef(pyOut);" << "\n";
+ s << INDENT << "return pyOut;" << "\n";
+ }
+ s << INDENT << "}\n";
+ // Create and register new wrapper
+ s << INDENT << "pyOut = ";
+ s << "Shiboken::Object::newObject(reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(fieldType)
+ << "), " << cppField << ", false, true);" << endl;
+ s << INDENT << "Shiboken::Object::setParent(" PYTHON_SELF_VAR ", pyOut)";
+ } else {
+ s << INDENT << "pyOut = ";
+ writeToPythonConversion(s, fieldType, metaField->enclosingClass(), cppField);
+ }
+ s << ';' << endl;
+
+ s << INDENT << "return pyOut;" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeSetterFunction(QTextStream &s,
+ const AbstractMetaField *metaField,
+ GeneratorContext &context)
+{
+ ErrorCode errorCode(0);
+ s << "static int " << cpythonSetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* pyIn, void*)" << endl;
+ s << '{' << endl;
+
+ writeCppSelfDefinition(s, context);
+
+ s << INDENT << "if (pyIn == 0) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_TypeError, \"'";
+ s << metaField->name() << "' may not be deleted\");" << endl;
+ s << INDENT << "return -1;" << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ AbstractMetaType* fieldType = metaField->type();
+
+ s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ';' << endl;
+ s << INDENT << "if (!";
+ writeTypeCheck(s, fieldType, QLatin1String("pyIn"), isNumber(fieldType->typeEntry()));
+ s << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_TypeError, \"wrong type attributed to '";
+ s << metaField->name() << "', '" << fieldType->name() << "' or convertible type expected\");" << endl;
+ s << INDENT << "return -1;" << endl;
+ }
+ s << INDENT << '}' << endl << endl;
+
+ QString cppField = QString::fromLatin1("%1->%2").arg(QLatin1String(CPP_SELF_VAR), metaField->name());
+ s << INDENT;
+ if (avoidProtectedHack() && metaField->isProtected()) {
+ s << getFullTypeNameWithoutModifiers(fieldType);
+ s << (fieldType->indirections() == 1 ? "*" : "") << " cppOut;" << endl;
+ s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut);" << endl;
+ s << INDENT << QString::fromLatin1("((%1*)%2)->%3(cppOut)")
+ .arg(wrapperName(metaField->enclosingClass()),
+ QLatin1String(CPP_SELF_VAR), protectedFieldSetterName(metaField));
+ } else if (isCppIntegralPrimitive(fieldType) || fieldType->typeEntry()->isEnum() || fieldType->typeEntry()->isFlags()) {
+ s << getFullTypeNameWithoutModifiers(fieldType) << " cppOut_local = " << cppField << ';' << endl;
+ s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut_local);" << endl;
+ s << INDENT << cppField << " = cppOut_local";
+ } else {
+ s << getFullTypeNameWithoutModifiers(fieldType);
+ s << QString::fromLatin1("*").repeated(fieldType->indirections()) << "& cppOut_ptr = ";
+ s << cppField << ';' << endl;
+ s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut_ptr)";
+ }
+ s << ';' << endl << endl;
+
+ if (isPointerToWrapperType(fieldType)) {
+ s << INDENT << "Shiboken::Object::keepReference(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "), \"";
+ s << metaField->name() << "\", pyIn);" << endl;
+ }
+
+ s << INDENT << "return 0;" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &context)
+{
+ const AbstractMetaClass *metaClass = context.metaClass();
+ QString baseName = cpythonBaseName(metaClass);
+ s << "static PyObject* ";
+ s << baseName << "_richcompare(PyObject* " PYTHON_SELF_VAR ", PyObject* " PYTHON_ARG ", int op)" << endl;
+ s << '{' << endl;
+ writeCppSelfDefinition(s, context, false, true);
+ writeUnusedVariableCast(s, QLatin1String(CPP_SELF_VAR));
+ s << INDENT << "PyObject* " PYTHON_RETURN_VAR " = 0;" << endl;
+ s << INDENT << "PythonToCppFunc " PYTHON_TO_CPP_VAR << ';' << endl;
+ writeUnusedVariableCast(s, QLatin1String(PYTHON_TO_CPP_VAR));
+ s << endl;
+
+ s << INDENT << "switch (op) {" << endl;
+ {
+ Indentation indent(INDENT);
+ foreach (const AbstractMetaFunctionList &overloads, filterGroupedOperatorFunctions(metaClass, AbstractMetaClass::ComparisonOp)) {
+ const AbstractMetaFunction* rfunc = overloads[0];
+
+ QString operatorId = ShibokenGenerator::pythonRichCompareOperatorId(rfunc);
+ s << INDENT << "case " << operatorId << ':' << endl;
+
+ Indentation indent(INDENT);
+
+ QString op = rfunc->originalName();
+ op = op.right(op.size() - QLatin1String("operator").size());
+
+ int alternativeNumericTypes = 0;
+ foreach (const AbstractMetaFunction* func, overloads) {
+ if (!func->isStatic() &&
+ ShibokenGenerator::isNumber(func->arguments()[0]->type()->typeEntry()))
+ alternativeNumericTypes++;
+ }
+
+ bool first = true;
+ OverloadData overloadData(overloads, this);
+ foreach (OverloadData* od, overloadData.nextOverloadData()) {
+ const AbstractMetaFunction* func = od->referenceFunction();
+ if (func->isStatic())
+ continue;
+ const AbstractMetaType* argType = getArgumentType(func, 1);
+ if (!argType)
+ continue;
+ if (!first) {
+ s << " else ";
+ } else {
+ first = false;
+ s << INDENT;
+ }
+ s << "if (";
+ writeTypeCheck(s, argType, QLatin1String(PYTHON_ARG), alternativeNumericTypes == 1 || isPyInt(argType));
+ s << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "// " << func->signature() << endl;
+ writeArgumentConversion(s, argType, QLatin1String(CPP_ARG0),
+ QLatin1String(PYTHON_ARG), metaClass,
+ QString(), func->isUserAdded());
+
+ // If the function is user added, use the inject code
+ if (func->isUserAdded()) {
+ CodeSnipList snips = func->injectedCodeSnips();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, func->arguments().last());
+ } else {
+ QString expression = QString::fromLatin1("%1%2 %3 (%4" CPP_ARG0 ")")
+ .arg(func->isPointerOperator() ? QLatin1String("&") : QString(),
+ QLatin1String(CPP_SELF_VAR), op,
+ shouldDereferenceAbstractMetaTypePointer(argType) ? QLatin1String("*") : QString());
+ s << INDENT;
+ if (func->type())
+ s << func->type()->cppSignature() << " " CPP_RETURN_VAR " = ";
+ s << expression << ';' << endl;
+ s << INDENT << PYTHON_RETURN_VAR " = ";
+ if (func->type())
+ writeToPythonConversion(s, func->type(), metaClass, QLatin1String(CPP_RETURN_VAR));
+ else
+ s << "Py_None;" << endl << INDENT << "Py_INCREF(Py_None)";
+ s << ';' << endl;
+ }
+ }
+ s << INDENT << '}';
+ }
+
+ s << " else {" << endl;
+ if (operatorId == QLatin1String("Py_EQ") || operatorId == QLatin1String("Py_NE")) {
+ Indentation indent(INDENT);
+ s << INDENT << PYTHON_RETURN_VAR " = "
+ << (operatorId == QLatin1String("Py_EQ") ? "Py_False" : "Py_True") << ';' << endl;
+ s << INDENT << "Py_INCREF(" PYTHON_RETURN_VAR ");" << endl;
+ } else {
+ Indentation indent(INDENT);
+ s << INDENT << "goto " << baseName << "_RichComparison_TypeError;" << endl;
+ }
+ s << INDENT << '}' << endl << endl;
+
+ s << INDENT << "break;" << endl;
+ }
+ s << INDENT << "default:" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "goto " << baseName << "_RichComparison_TypeError;" << endl;
+ }
+ }
+ s << INDENT << '}' << endl << endl;
+
+ s << INDENT << "if (" PYTHON_RETURN_VAR " && !PyErr_Occurred())" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return " PYTHON_RETURN_VAR ";" << endl;
+ }
+ s << INDENT << baseName << "_RichComparison_TypeError:" << endl;
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"operator not implemented.\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl;
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList overloads)
+{
+ Q_ASSERT(!overloads.isEmpty());
+ OverloadData overloadData(overloads, this);
+ bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(overloadData);
+ const AbstractMetaFunction* func = overloadData.referenceFunction();
+ int min = overloadData.minArgs();
+ int max = overloadData.maxArgs();
+
+ s << '"' << func->name() << "\", (PyCFunction)" << cpythonFunctionName(func) << ", ";
+ if ((min == max) && (max < 2) && !usePyArgs) {
+ if (max == 0)
+ s << "METH_NOARGS";
+ else
+ s << "METH_O";
+ } else {
+ s << "METH_VARARGS";
+ if (overloadData.hasArgumentWithDefaultValue())
+ s << "|METH_KEYWORDS";
+ }
+ if (func->ownerClass() && overloadData.hasStaticFunction())
+ s << "|METH_STATIC";
+}
+
+void CppGenerator::writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads)
+{
+ Q_ASSERT(!overloads.isEmpty());
+ const AbstractMetaFunction* func = overloads.first();
+ if (m_tpFuncs.contains(func->name()))
+ return;
+
+ s << INDENT;
+ if (OverloadData::hasStaticAndInstanceFunctions(overloads)) {
+ s << cpythonMethodDefinitionName(func);
+ } else {
+ s << '{';
+ writeMethodDefinitionEntry(s, overloads);
+ s << '}';
+ }
+ s << ',' << endl;
+}
+
+void CppGenerator::writeEnumsInitialization(QTextStream& s, AbstractMetaEnumList& enums)
+{
+ if (enums.isEmpty())
+ return;
+ s << INDENT << "// Initialization of enums." << endl << endl;
+ foreach (const AbstractMetaEnum* cppEnum, enums) {
+ if (cppEnum->isPrivate())
+ continue;
+ writeEnumInitialization(s, cppEnum);
+ }
+}
+
+void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ const AbstractMetaClass* enclosingClass = getProperEnclosingClassForEnum(cppEnum);
+ const AbstractMetaClass* upper = enclosingClass ? enclosingClass->enclosingClass() : 0;
+ bool hasUpperEnclosingClass = upper && upper->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass;
+ QString enclosingObjectVariable;
+ if (enclosingClass)
+ enclosingObjectVariable = QLatin1Char('&') + cpythonTypeName(enclosingClass);
+ else if (hasUpperEnclosingClass)
+ enclosingObjectVariable = QLatin1String("enclosingClass");
+ else
+ enclosingObjectVariable = QLatin1String("module");
+
+ s << INDENT << "// Initialization of ";
+ s << (cppEnum->isAnonymous() ? "anonymous enum identified by enum value" : "enum");
+ s << " '" << cppEnum->name() << "'." << endl;
+
+ if (!cppEnum->isAnonymous()) {
+ FlagsTypeEntry* flags = cppEnum->typeEntry()->flags();
+ if (flags) {
+ s << INDENT << cpythonTypeNameExt(flags) << " = PySide::QFlags::create(\"" << flags->flagsName() << "\", &"
+ << cpythonEnumName(cppEnum) << "_as_number);" << endl;
+ }
+
+ s << INDENT << cpythonTypeNameExt(cppEnum->typeEntry()) << " = Shiboken::Enum::";
+ s << ((enclosingClass || hasUpperEnclosingClass) ? "createScopedEnum" : "createGlobalEnum");
+ s << '(' << enclosingObjectVariable << ',' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << '"' << cppEnum->name() << "\"," << endl;
+ s << INDENT << '"' << getClassTargetFullName(cppEnum) << "\"," << endl;
+ s << INDENT << '"' << (cppEnum->enclosingClass() ? (cppEnum->enclosingClass()->qualifiedCppName() + QLatin1String("::")) : QString());
+ s << cppEnum->name() << '"';
+ if (flags)
+ s << ',' << endl << INDENT << cpythonTypeNameExt(flags);
+ s << ");" << endl;
+ }
+ s << INDENT << "if (!" << cpythonTypeNameExt(cppEnum->typeEntry()) << ')' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl;
+ }
+ }
+
+ foreach (const AbstractMetaEnumValue* enumValue, cppEnum->values()) {
+ if (cppEnum->typeEntry()->isEnumValueRejected(enumValue->name()))
+ continue;
+
+ QString enumValueText;
+ if (!avoidProtectedHack() || !cppEnum->isProtected()) {
+ enumValueText = QLatin1String("(long) ");
+ if (cppEnum->enclosingClass())
+ enumValueText += cppEnum->enclosingClass()->qualifiedCppName() + QLatin1String("::");
+ enumValueText += enumValue->name();
+ } else {
+ enumValueText += QString::number(enumValue->value());
+ }
+
+ if (cppEnum->isAnonymous()) {
+ if (enclosingClass || hasUpperEnclosingClass) {
+ s << INDENT << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyObject* anonEnumItem = PyInt_FromLong(" << enumValueText << ");" << endl;
+ s << INDENT << "if (PyDict_SetItemString(reinterpret_cast<SbkObjectType *>(" << enclosingObjectVariable
+ << ")->super.ht_type.tp_dict, \"" << enumValue->name() << "\", anonEnumItem) < 0)" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << "Py_DECREF(anonEnumItem);" << endl;
+ }
+ s << INDENT << '}' << endl;
+ } else {
+ s << INDENT << "if (PyModule_AddIntConstant(module, \"" << enumValue->name() << "\", ";
+ s << enumValueText << ") < 0)" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ }
+ } else {
+ s << INDENT << "if (!Shiboken::Enum::";
+ s << ((enclosingClass || hasUpperEnclosingClass) ? "createScopedEnumItem" : "createGlobalEnumItem");
+ s << '(' << cpythonTypeNameExt(cppEnum->typeEntry()) << ',' << endl;
+ Indentation indent(INDENT);
+ s << INDENT << enclosingObjectVariable << ", \"" << enumValue->name() << "\", ";
+ s << enumValueText << "))" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ }
+
+ writeEnumConverterInitialization(s, cppEnum);
+
+ s << INDENT << "// End of '" << cppEnum->name() << "' enum";
+ if (cppEnum->typeEntry()->flags())
+ s << "/flags";
+ s << '.' << endl << endl;
+}
+
+void CppGenerator::writeSignalInitialization(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ // Try to check something and print some warnings
+ foreach (const AbstractMetaFunction* cppSignal, metaClass->cppSignalFunctions()) {
+ if (cppSignal->declaringClass() != metaClass)
+ continue;
+ foreach (AbstractMetaArgument* arg, cppSignal->arguments()) {
+ AbstractMetaType* metaType = arg->type();
+ const QByteArray origType =
+ QMetaObject::normalizedType(qPrintable(metaType->originalTypeDescription()));
+ const QByteArray cppSig =
+ QMetaObject::normalizedType(qPrintable(metaType->cppSignature()));
+ if ((origType != cppSig) && (!metaType->isFlags())) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Typedef used on signal " << metaClass->qualifiedCppName() << "::"
+ << cppSignal->signature();
+ }
+ }
+ }
+
+ s << INDENT << "PySide::Signal::registerSignals(&" << cpythonTypeName(metaClass) << ", &::"
+ << metaClass->qualifiedCppName() << "::staticMetaObject);" << endl;
+}
+
+void CppGenerator::writeFlagsToLong(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
+ if (!flagsEntry)
+ return;
+ s << "static PyObject* " << cpythonEnumName(cppEnum) << "_long(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << "{" << endl;
+ s << INDENT << "int val;" << endl;
+ AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
+ s << INDENT << cpythonToCppConversionFunction(flagsType) << PYTHON_SELF_VAR << ", &val);" << endl;
+ s << INDENT << "return Shiboken::Conversions::copyToPython(Shiboken::Conversions::PrimitiveTypeConverter<int>(), &val);" << endl;
+ s << "}" << endl;
+}
+
+void CppGenerator::writeFlagsNonZero(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
+ if (!flagsEntry)
+ return;
+ s << "static int " << cpythonEnumName(cppEnum) << "__nonzero(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << "{" << endl;
+
+ s << INDENT << "int val;" << endl;
+ AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
+ s << INDENT << cpythonToCppConversionFunction(flagsType) << PYTHON_SELF_VAR << ", &val);" << endl;
+ s << INDENT << "return val != 0;" << endl;
+ s << "}" << endl;
+}
+
+void CppGenerator::writeFlagsMethods(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ writeFlagsBinaryOperator(s, cppEnum, QLatin1String("and"), QLatin1String("&"));
+ writeFlagsBinaryOperator(s, cppEnum, QLatin1String("or"), QLatin1String("|"));
+ writeFlagsBinaryOperator(s, cppEnum, QLatin1String("xor"), QLatin1String("^"));
+
+ writeFlagsUnaryOperator(s, cppEnum, QLatin1String("invert"), QLatin1String("~"));
+ writeFlagsToLong(s, cppEnum);
+ writeFlagsNonZero(s, cppEnum);
+
+ s << endl;
+}
+
+void CppGenerator::writeFlagsNumberMethodsDefinition(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ QString cpythonName = cpythonEnumName(cppEnum);
+
+ s << "static PyNumberMethods " << cpythonName << "_as_number = {" << endl;
+ s << INDENT << "/*nb_add*/ 0," << endl;
+ s << INDENT << "/*nb_subtract*/ 0," << endl;
+ s << INDENT << "/*nb_multiply*/ 0," << endl;
+ s << INDENT << "#ifndef IS_PY3K" << endl;
+ s << INDENT << "/* nb_divide */ 0," << endl;
+ s << INDENT << "#endif" << endl;
+ s << INDENT << "/*nb_remainder*/ 0," << endl;
+ s << INDENT << "/*nb_divmod*/ 0," << endl;
+ s << INDENT << "/*nb_power*/ 0," << endl;
+ s << INDENT << "/*nb_negative*/ 0," << endl;
+ s << INDENT << "/*nb_positive*/ 0," << endl;
+ s << INDENT << "/*nb_absolute*/ 0," << endl;
+ s << INDENT << "/*nb_nonzero*/ " << cpythonName << "__nonzero," << endl;
+ s << INDENT << "/*nb_invert*/ (unaryfunc)" << cpythonName << "___invert__," << endl;
+ s << INDENT << "/*nb_lshift*/ 0," << endl;
+ s << INDENT << "/*nb_rshift*/ 0," << endl;
+ s << INDENT << "/*nb_and*/ (binaryfunc)" << cpythonName << "___and__," << endl;
+ s << INDENT << "/*nb_xor*/ (binaryfunc)" << cpythonName << "___xor__," << endl;
+ s << INDENT << "/*nb_or*/ (binaryfunc)" << cpythonName << "___or__," << endl;
+ s << INDENT << "#ifndef IS_PY3K" << endl;
+ s << INDENT << "/* nb_coerce */ 0," << endl;
+ s << INDENT << "#endif" << endl;
+ s << INDENT << "/*nb_int*/ " << cpythonName << "_long," << endl;
+ s << INDENT << "#ifdef IS_PY3K" << endl;
+ s << INDENT << "/*nb_reserved*/ 0," << endl;
+ s << INDENT << "/*nb_float*/ 0," << endl;
+ s << INDENT << "#else" << endl;
+ s << INDENT << "/*nb_long*/ " << cpythonName << "_long," << endl;
+ s << INDENT << "/*nb_float*/ 0," << endl;
+ s << INDENT << "/*nb_oct*/ 0," << endl;
+ s << INDENT << "/*nb_hex*/ 0," << endl;
+ s << INDENT << "#endif" << endl;
+ s << INDENT << "/*nb_inplace_add*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_subtract*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_multiply*/ 0," << endl;
+ s << INDENT << "#ifndef IS_PY3K" << endl;
+ s << INDENT << "/*nb_inplace_divide*/ 0," << endl;
+ s << INDENT << "#endif" << endl;
+ s << INDENT << "/*nb_inplace_remainder*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_power*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_lshift*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_rshift*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_and*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_xor*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_or*/ 0," << endl;
+ s << INDENT << "/*nb_floor_divide*/ 0," << endl;
+ s << INDENT << "/*nb_true_divide*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_floor_divide*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_true_divide*/ 0," << endl;
+ s << INDENT << "/*nb_index*/ 0" << endl;
+ s << "};" << endl << endl;
+}
+
+void CppGenerator::writeFlagsBinaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
+ QString pyOpName, QString cppOpName)
+{
+ FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
+ Q_ASSERT(flagsEntry);
+
+ s << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* " PYTHON_SELF_VAR ", PyObject* " PYTHON_ARG ")" << endl;
+ s << '{' << endl;
+
+ AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
+ s << INDENT << "::" << flagsEntry->originalName() << " cppResult, " CPP_SELF_VAR ", cppArg;" << endl;
+ s << "#ifdef IS_PY3K" << endl;
+ s << INDENT << CPP_SELF_VAR " = (::" << flagsEntry->originalName() << ")(int)PyLong_AsLong(" PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "cppArg = (" << flagsEntry->originalName() << ")(int)PyLong_AsLong(" PYTHON_ARG ");" << endl;
+ s << "#else" << endl;
+ s << INDENT << CPP_SELF_VAR " = (::" << flagsEntry->originalName() << ")(int)PyInt_AsLong(" PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "cppArg = (" << flagsEntry->originalName() << ")(int)PyInt_AsLong(" PYTHON_ARG ");" << endl;
+ s << "#endif" << endl << endl;
+ s << INDENT << "cppResult = " CPP_SELF_VAR " " << cppOpName << " cppArg;" << endl;
+ s << INDENT << "return ";
+ writeToPythonConversion(s, flagsType, 0, QLatin1String("cppResult"));
+ s << ';' << endl;
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeFlagsUnaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
+ QString pyOpName, QString cppOpName, bool boolResult)
+{
+ FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
+ Q_ASSERT(flagsEntry);
+
+ s << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* " PYTHON_SELF_VAR ", PyObject* " PYTHON_ARG ")" << endl;
+ s << '{' << endl;
+
+ AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
+ s << INDENT << "::" << flagsEntry->originalName() << " " CPP_SELF_VAR ";" << endl;
+ s << INDENT << cpythonToCppConversionFunction(flagsType) << PYTHON_SELF_VAR << ", &" CPP_SELF_VAR ");" << endl;
+ s << INDENT;
+ if (boolResult)
+ s << "bool";
+ else
+ s << "::" << flagsEntry->originalName();
+ s << " cppResult = " << cppOpName << CPP_SELF_VAR ";" << endl;
+ s << INDENT << "return ";
+ if (boolResult)
+ s << "PyBool_FromLong(cppResult)";
+ else
+ writeToPythonConversion(s, flagsType, 0, QLatin1String("cppResult"));
+ s << ';' << endl;
+ s << '}' << endl << endl;
+}
+
+QString CppGenerator::getInitFunctionName(GeneratorContext &context) const
+{
+ QString initFunctionName;
+ if (!context.forSmartPointer()) {
+ initFunctionName = context.metaClass()->qualifiedCppName();
+ initFunctionName.replace(QLatin1String("::"), QLatin1String("_"));
+ } else {
+ initFunctionName = getFilteredCppSignatureString(context.preciseType()->cppSignature());
+ }
+ return initFunctionName;
+}
+
+void CppGenerator::writeClassRegister(QTextStream &s,
+ const AbstractMetaClass *metaClass,
+ GeneratorContext &classContext)
+{
+ const ComplexTypeEntry* classTypeEntry = metaClass->typeEntry();
+
+ const AbstractMetaClass* enc = metaClass->enclosingClass();
+ bool hasEnclosingClass = enc && enc->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass;
+ QString enclosingObjectVariable = hasEnclosingClass ? QLatin1String("enclosingClass") : QLatin1String("module");
+
+ QString pyTypeName = cpythonTypeName(metaClass);
+ QString initFunctionName = getInitFunctionName(classContext);
+ s << "void init_" << initFunctionName;
+ s << "(PyObject* " << enclosingObjectVariable << ")" << endl;
+ s << '{' << endl;
+
+ if (supportsNumberProtocol(metaClass)) {
+ s << INDENT << "// type has number operators" << endl;
+ writeTypeAsNumberDefinition(s, metaClass);
+ s << INDENT << pyTypeName << ".super.ht_type.tp_as_number = &" << pyTypeName << "AsNumber;" << endl;
+ s << endl;
+ }
+
+ if (supportsSequenceProtocol(metaClass)) {
+ s << INDENT << "// type supports sequence protocol" << endl;
+ writeTypeAsSequenceDefinition(s, metaClass);
+ s << INDENT << pyTypeName << ".super.ht_type.tp_as_sequence = &" << pyTypeName << "AsSequence;" << endl;
+ s << endl;
+ }
+
+ if (supportsMappingProtocol(metaClass)) {
+ s << INDENT << "// type supports mapping protocol" << endl;
+ writeTypeAsMappingDefinition(s, metaClass);
+ s << INDENT << pyTypeName << ".super.ht_type.tp_as_mapping = &" << pyTypeName << "AsMapping;" << endl;
+ s << endl;
+ }
+
+ if (!classContext.forSmartPointer())
+ s << INDENT << cpythonTypeNameExt(classTypeEntry);
+ else
+ s << INDENT << cpythonTypeNameExt(classContext.preciseType());
+
+ s << " = reinterpret_cast<PyTypeObject*>(&" << pyTypeName << ");" << endl;
+ s << endl;
+
+ // Multiple inheritance
+ QString pyTypeBasesVariable = pyTypeName + QLatin1String("_bases");
+ const AbstractMetaClassList baseClasses = getBaseClasses(metaClass);
+ if (metaClass->baseClassNames().size() > 1) {
+ s << INDENT << "PyObject* " << pyTypeBasesVariable << " = PyTuple_Pack(" << baseClasses.size() << ',' << endl;
+ QStringList bases;
+ foreach (const AbstractMetaClass* base, baseClasses)
+ bases << QLatin1String("(PyObject*)") + cpythonTypeNameExt(base->typeEntry());
+ Indentation indent(INDENT);
+ QString separator;
+ QTextStream sep(&separator);
+ sep << "," << endl << INDENT;
+ s << INDENT << bases.join(separator) << ");" << endl << endl;
+ }
+
+ // Create type and insert it in the module or enclosing class.
+ s << INDENT << "if (!Shiboken::ObjectType::introduceWrapperType(" << enclosingObjectVariable;
+ QString typeName;
+ if (!classContext.forSmartPointer())
+ typeName = metaClass->name();
+ else
+ typeName = classContext.preciseType()->cppSignature();
+
+ s << ", \"" << typeName << "\", \"";
+
+ // Original name
+ if (!classContext.forSmartPointer())
+ s << metaClass->qualifiedCppName() << (isObjectType(classTypeEntry) ? "*" : "");
+ else
+ s << classContext.preciseType()->cppSignature();
+
+ s << "\"," << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "&" << pyTypeName;
+
+ // Set destructor function
+ if (!metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) {
+ QString dtorClassName = metaClass->qualifiedCppName();
+ if ((avoidProtectedHack() && metaClass->hasProtectedDestructor()) || classTypeEntry->isValue())
+ dtorClassName = wrapperName(metaClass);
+ if (classContext.forSmartPointer())
+ dtorClassName = wrapperName(classContext.preciseType());
+
+ s << ", &Shiboken::callCppDestructor< ::" << dtorClassName << " >";
+ } else if (metaClass->baseClass() || hasEnclosingClass) {
+ s << ", 0";
+ }
+
+ // Base type
+ if (metaClass->baseClass()) {
+ s << ", reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(metaClass->baseClass()->typeEntry()) << ')';
+ // The other base types
+ if (metaClass->baseClassNames().size() > 1)
+ s << ", " << pyTypeBasesVariable;
+ else if (hasEnclosingClass)
+ s << ", 0";
+ } else if (hasEnclosingClass) {
+ s << ", 0, 0";
+ }
+ if (hasEnclosingClass)
+ s << ", true";
+ s << ")) {" << endl;
+ s << INDENT << "return;" << endl;
+ }
+ s << INDENT << '}' << endl << endl;
+
+ // Register conversions for the type.
+ writeConverterRegister(s, metaClass, classContext);
+ s << endl;
+
+ // class inject-code target/beginning
+ if (!classTypeEntry->codeSnips().isEmpty()) {
+ writeCodeSnips(s, classTypeEntry->codeSnips(), TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode, metaClass);
+ s << endl;
+ }
+
+ // Fill multiple inheritance data, if needed.
+ const AbstractMetaClass* miClass = getMultipleInheritingClass(metaClass);
+ if (miClass) {
+ s << INDENT << "MultipleInheritanceInitFunction func = ";
+ if (miClass == metaClass) {
+ s << multipleInheritanceInitializerFunctionName(miClass) << ";" << endl;
+ } else {
+ s << "Shiboken::ObjectType::getMultipleIheritanceFunction(reinterpret_cast<SbkObjectType*>(";
+ s << cpythonTypeNameExt(miClass->typeEntry()) << "));" << endl;
+ }
+ s << INDENT << "Shiboken::ObjectType::setMultipleIheritanceFunction(&";
+ s << cpythonTypeName(metaClass) << ", func);" << endl;
+ s << INDENT << "Shiboken::ObjectType::setCastFunction(&" << cpythonTypeName(metaClass);
+ s << ", &" << cpythonSpecialCastFunctionName(metaClass) << ");" << endl;
+ }
+
+ // Set typediscovery struct or fill the struct of another one
+ if (metaClass->isPolymorphic() && metaClass->baseClass()) {
+ s << INDENT << "Shiboken::ObjectType::setTypeDiscoveryFunctionV2(&" << cpythonTypeName(metaClass);
+ s << ", &" << cpythonBaseName(metaClass) << "_typeDiscovery);" << endl << endl;
+ }
+
+ AbstractMetaEnumList classEnums = metaClass->enums();
+ foreach (AbstractMetaClass* innerClass, metaClass->innerClasses())
+ lookForEnumsInClassesNotToBeGenerated(classEnums, innerClass);
+
+ ErrorCode errorCode(QString::null);
+ writeEnumsInitialization(s, classEnums);
+
+ if (metaClass->hasSignals())
+ writeSignalInitialization(s, metaClass);
+
+ // Write static fields
+ foreach (const AbstractMetaField* field, metaClass->fields()) {
+ if (!field->isStatic())
+ continue;
+ s << INDENT << QLatin1String("PyDict_SetItemString(") + cpythonTypeName(metaClass) + QLatin1String(".super.ht_type.tp_dict, \"");
+ s << field->name() << "\", ";
+ writeToPythonConversion(s, field->type(), metaClass, metaClass->qualifiedCppName() + QLatin1String("::") + field->name());
+ s << ");" << endl;
+ }
+ s << endl;
+
+ // class inject-code target/end
+ if (!classTypeEntry->codeSnips().isEmpty()) {
+ s << endl;
+ writeCodeSnips(s, classTypeEntry->codeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode, metaClass);
+ }
+
+ if (usePySideExtensions()) {
+ if (avoidProtectedHack() && shouldGenerateCppWrapper(metaClass))
+ s << INDENT << wrapperName(metaClass) << "::pysideInitQtMetaTypes();\n";
+ else
+ writeInitQtMetaTypeFunctionBody(s, classContext);
+ }
+
+ if (usePySideExtensions() && metaClass->isQObject()) {
+ s << INDENT << "Shiboken::ObjectType::setSubTypeInitHook(&" << pyTypeName << ", &PySide::initQObjectSubType);" << endl;
+ s << INDENT << "PySide::initDynamicMetaObject(&" << pyTypeName << ", &::" << metaClass->qualifiedCppName()
+ << "::staticMetaObject, sizeof(::" << metaClass->qualifiedCppName() << "));" << endl;
+ }
+
+ s << '}' << endl;
+}
+
+void CppGenerator::writeInitQtMetaTypeFunctionBody(QTextStream &s, GeneratorContext &context) const
+{
+ const AbstractMetaClass* metaClass = context.metaClass();
+ // Gets all class name variants used on different possible scopes
+ QStringList nameVariants;
+ if (!context.forSmartPointer())
+ nameVariants << metaClass->name();
+ else
+ nameVariants << context.preciseType()->cppSignature();
+
+ const AbstractMetaClass* enclosingClass = metaClass->enclosingClass();
+ while (enclosingClass) {
+ if (enclosingClass->typeEntry()->generateCode())
+ nameVariants << (enclosingClass->name() + QLatin1String("::") + nameVariants.last());
+ enclosingClass = enclosingClass->enclosingClass();
+ }
+
+ QString className;
+ if (!context.forSmartPointer())
+ className = metaClass->qualifiedCppName();
+ else
+ className = context.preciseType()->cppSignature();
+
+ if (!metaClass->isNamespace() && !metaClass->isAbstract()) {
+ // Qt metatypes are registered only on their first use, so we do this now.
+ bool canBeValue = false;
+ if (!isObjectType(metaClass)) {
+ // check if there's a empty ctor
+ foreach (AbstractMetaFunction* func, metaClass->functions()) {
+ if (func->isConstructor() && !func->arguments().count()) {
+ canBeValue = true;
+ break;
+ }
+ }
+ }
+
+ if (canBeValue) {
+ foreach (const QString &name, nameVariants) {
+ if (name == QLatin1String("iterator")) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QString::fromLatin1("%1:%2 FIXME:\n"
+ " The code tried to qRegisterMetaType the unqualified name "
+ "'iterator'. This is currently fixed by a hack(ct) and needs improvement!")
+ .arg(QFile::decodeName(__FILE__)).arg(__LINE__);
+ continue;
+ }
+ s << INDENT << "qRegisterMetaType< ::" << className << " >(\"" << name << "\");" << endl;
+ }
+ }
+ }
+
+ foreach (AbstractMetaEnum* metaEnum, metaClass->enums()) {
+ if (!metaEnum->isPrivate() && !metaEnum->isAnonymous()) {
+ foreach (const QString &name, nameVariants)
+ s << INDENT << "qRegisterMetaType< ::" << metaEnum->typeEntry()->qualifiedCppName() << " >(\"" << name << "::" << metaEnum->name() << "\");" << endl;
+
+ if (metaEnum->typeEntry()->flags()) {
+ QString n = metaEnum->typeEntry()->flags()->originalName();
+ s << INDENT << "qRegisterMetaType< ::" << n << " >(\"" << n << "\");" << endl;
+ }
+ }
+ }
+}
+
+void CppGenerator::writeTypeDiscoveryFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString polymorphicExpr = metaClass->typeEntry()->polymorphicIdValue();
+
+ s << "static void* " << cpythonBaseName(metaClass) << "_typeDiscovery(void* cptr, SbkObjectType* instanceType)\n{" << endl;
+
+ if (!polymorphicExpr.isEmpty()) {
+ polymorphicExpr = polymorphicExpr.replace(QLatin1String("%1"),
+ QLatin1String(" reinterpret_cast< ::")
+ + metaClass->qualifiedCppName()
+ + QLatin1String("*>(cptr)"));
+ s << INDENT << " if (" << polymorphicExpr << ")" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return cptr;" << endl;
+ }
+ } else if (metaClass->isPolymorphic()) {
+ AbstractMetaClassList ancestors = getAllAncestors(metaClass);
+ foreach (AbstractMetaClass* ancestor, ancestors) {
+ if (ancestor->baseClass())
+ continue;
+ if (ancestor->isPolymorphic()) {
+ s << INDENT << "if (instanceType == reinterpret_cast<SbkObjectType*>(Shiboken::SbkType< ::"
+ << ancestor->qualifiedCppName() << " >()))" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return dynamic_cast< ::" << metaClass->qualifiedCppName()
+ << "*>(reinterpret_cast< ::"<< ancestor->qualifiedCppName() << "*>(cptr));" << endl;
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << metaClass->qualifiedCppName() << " inherits from a non polymorphic type ("
+ << ancestor->qualifiedCppName() << "), type discovery based on RTTI is "
+ "impossible, write a polymorphic-id-expression for this type.";
+ }
+
+ }
+ }
+ s << INDENT << "return 0;" << endl;
+ s << "}\n\n";
+}
+
+QString CppGenerator::writeSmartPointerGetterCast() {
+ return QLatin1String("const_cast<char *>(" SMART_POINTER_GETTER ")");
+}
+
+void CppGenerator::writeSetattroFunction(QTextStream &s, GeneratorContext &context)
+{
+ const AbstractMetaClass* metaClass = context.metaClass();
+ s << "static int " << cpythonSetattroFunctionName(metaClass) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* name, PyObject* value)" << endl;
+ s << '{' << endl;
+ if (usePySideExtensions()) {
+ s << INDENT << "Shiboken::AutoDecRef pp(reinterpret_cast<PyObject*>(PySide::Property::getObject(" PYTHON_SELF_VAR ", name)));" << endl;
+ s << INDENT << "if (!pp.isNull())" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return PySide::Property::setValue(reinterpret_cast<PySideProperty*>(pp.object()), " PYTHON_SELF_VAR ", value);" << endl;
+ }
+
+ if (context.forSmartPointer()) {
+ s << INDENT << "// Try to find the 'name' attribute, by retrieving the PyObject for the corresponding C++ object held by the smart pointer." << endl;
+ s << INDENT << "PyObject *rawObj = PyObject_CallMethod(" PYTHON_SELF_VAR ", "
+ << writeSmartPointerGetterCast() << ", 0);" << endl;
+ s << INDENT << "if (rawObj) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "int hasAttribute = PyObject_HasAttr(rawObj, name);" << endl;
+ s << INDENT << "if (hasAttribute) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return PyObject_GenericSetAttr(rawObj, name, value);" << endl;
+ }
+ s << INDENT << '}' << endl;
+ s << INDENT << "Py_DECREF(rawObj);" << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ }
+
+ s << INDENT << "return PyObject_GenericSetAttr(" PYTHON_SELF_VAR ", name, value);" << endl;
+ s << '}' << endl;
+}
+
+static inline QString qObjectClassName() { return QStringLiteral("QObject"); }
+static inline QString qMetaObjectClassName() { return QStringLiteral("QMetaObject"); }
+
+void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &context)
+{
+ const AbstractMetaClass* metaClass = context.metaClass();
+ s << "static PyObject* " << cpythonGetattroFunctionName(metaClass) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* name)" << endl;
+ s << '{' << endl;
+
+ QString getattrFunc;
+ if (usePySideExtensions() && metaClass->isQObject()) {
+ AbstractMetaClass *qobjectClass = AbstractMetaClass::findClass(classes(), qObjectClassName());
+ getattrFunc = QString::fromLatin1("PySide::getMetaDataFromQObject(%1, " PYTHON_SELF_VAR ", name)")
+ .arg(cpythonWrapperCPtr(qobjectClass, QLatin1String(PYTHON_SELF_VAR)));
+ } else {
+ getattrFunc = QLatin1String("PyObject_GenericGetAttr(" PYTHON_SELF_VAR ", name)");
+ }
+
+ if (classNeedsGetattroFunction(metaClass)) {
+ s << INDENT << "if (" PYTHON_SELF_VAR ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "// Search the method in the instance dict" << endl;
+ s << INDENT << "if (reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ")->ob_dict) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyObject* meth = PyDict_GetItem(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ")->ob_dict, name);" << endl;
+ s << INDENT << "if (meth) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "Py_INCREF(meth);" << endl;
+ s << INDENT << "return meth;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ }
+ s << INDENT << '}' << endl;
+ s << INDENT << "// Search the method in the type dict" << endl;
+ s << INDENT << "if (Shiboken::Object::isUserType(" PYTHON_SELF_VAR ")) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyObject* meth = PyDict_GetItem(" PYTHON_SELF_VAR "->ob_type->tp_dict, name);" << endl;
+ s << INDENT << "if (meth)" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return PyFunction_Check(meth) ? SBK_PyMethod_New(meth, " PYTHON_SELF_VAR ") : " << getattrFunc << ';' << endl;
+ }
+ }
+ s << INDENT << '}' << endl;
+
+ foreach (const AbstractMetaFunction* func, getMethodsWithBothStaticAndNonStaticMethods(metaClass)) {
+ QString defName = cpythonMethodDefinitionName(func);
+ s << INDENT << "static PyMethodDef non_static_" << defName << " = {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << defName << ".ml_name," << endl;
+ s << INDENT << defName << ".ml_meth," << endl;
+ s << INDENT << defName << ".ml_flags & (~METH_STATIC)," << endl;
+ s << INDENT << defName << ".ml_doc," << endl;
+ }
+ s << INDENT << "};" << endl;
+ s << INDENT << "if (Shiboken::String::compare(name, \"" << func->name() << "\") == 0)" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return PyCFunction_NewEx(&non_static_" << defName << ", " PYTHON_SELF_VAR ", 0);" << endl;
+ }
+ }
+ s << INDENT << '}' << endl;
+ }
+
+ if (context.forSmartPointer()) {
+ s << INDENT << "PyObject *tmp = " << getattrFunc << ';' << endl;
+ s << INDENT << "if (tmp) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return tmp;" << endl;
+ }
+ s << INDENT << "} else {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "if (!PyErr_ExceptionMatches(PyExc_AttributeError)) return NULL;" << endl;
+ s << INDENT << "PyErr_Clear();" << endl;
+
+ s << INDENT << "// Try to find the 'name' attribute, by retrieving the PyObject for "
+ "the corresponding C++ object held by the smart pointer." << endl;
+ s << INDENT << "PyObject *rawObj = PyObject_CallMethod(" PYTHON_SELF_VAR ", "
+ << writeSmartPointerGetterCast() << ", 0);" << endl;
+ s << INDENT << "if (rawObj) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyObject *attribute = PyObject_GetAttr(rawObj, name);" << endl;
+ s << INDENT << "if (attribute) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "tmp = attribute;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ s << INDENT << "Py_DECREF(rawObj);" << endl;
+ }
+ s << INDENT << '}' << endl;
+ s << INDENT << "if (!tmp) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyTypeObject *tp = Py_TYPE(self);" << endl;
+ s << INDENT << "PyErr_Format(PyExc_AttributeError," << endl;
+ s << INDENT << " \"'%.50s' object has no attribute '%.400s'\"," << endl;
+ s << INDENT << " tp->tp_name, PyBytes_AS_STRING(name));" << endl;
+ s << INDENT << "return NULL;" << endl;
+ }
+ s << INDENT << "} else {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return tmp;" << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ }
+ s << INDENT << '}' << endl;
+
+ } else {
+ s << INDENT << "return " << getattrFunc << ';' << endl;
+ }
+ s << '}' << endl;
+}
+
+bool CppGenerator::finishGeneration()
+{
+ //Generate CPython wrapper file
+ QString classInitDecl;
+ QTextStream s_classInitDecl(&classInitDecl);
+ QString classPythonDefines;
+ QTextStream s_classPythonDefines(&classPythonDefines);
+
+ QSet<Include> includes;
+ QString globalFunctionImpl;
+ QTextStream s_globalFunctionImpl(&globalFunctionImpl);
+ QString globalFunctionDecl;
+ QTextStream s_globalFunctionDef(&globalFunctionDecl);
+
+ Indentation indent(INDENT);
+
+ const FunctionGroupMap &functionGroups = getFunctionGroups();
+ for (FunctionGroupMapIt it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
+ AbstractMetaFunctionList overloads;
+ foreach (AbstractMetaFunction* func, it.value()) {
+ if (!func->isModifiedRemoved()) {
+ overloads.append(func);
+ if (func->typeEntry())
+ includes << func->typeEntry()->include();
+ }
+ }
+
+ if (overloads.isEmpty())
+ continue;
+
+ // Dummy context to satisfy the API.
+ GeneratorContext classContext;
+ writeMethodWrapper(s_globalFunctionImpl, overloads, classContext);
+ writeMethodDefinition(s_globalFunctionDef, overloads);
+ }
+
+ //this is a temporary solution before new type revison implementation
+ //We need move QMetaObject register before QObject
+ Dependencies additionalDependencies;
+ const AbstractMetaClassList &allClasses = classes();
+ if (AbstractMetaClass::findClass(allClasses, qObjectClassName()) != Q_NULLPTR
+ && AbstractMetaClass::findClass(allClasses, qMetaObjectClassName()) != Q_NULLPTR) {
+ Dependency dependency;
+ dependency.parent = qMetaObjectClassName();
+ dependency.child = qObjectClassName();
+ additionalDependencies.append(dependency);
+ }
+ const AbstractMetaClassList lst = classesTopologicalSorted(additionalDependencies);
+
+ foreach (const AbstractMetaClass* cls, lst) {
+ if (!shouldGenerate(cls))
+ continue;
+
+ s_classInitDecl << "void init_" << cls->qualifiedCppName().replace(QLatin1String("::"), QLatin1String("_")) << "(PyObject* module);" << endl;
+
+ QString defineStr = QLatin1String("init_") + cls->qualifiedCppName().replace(QLatin1String("::"), QLatin1String("_"));
+
+ if (cls->enclosingClass() && (cls->enclosingClass()->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass))
+ defineStr += QLatin1Char('(') + cpythonTypeNameExt(cls->enclosingClass()->typeEntry()) + QLatin1String("->tp_dict);");
+ else
+ defineStr += QLatin1String("(module);");
+ s_classPythonDefines << INDENT << defineStr << endl;
+ }
+
+ // Initialize smart pointer types.
+ foreach (const AbstractMetaType *metaType, instantiatedSmartPointers()) {
+ GeneratorContext context(0, metaType, true);
+ QString initFunctionName = getInitFunctionName(context);
+ s_classInitDecl << "void init_" << initFunctionName << "(PyObject* module);" << endl;
+ QString defineStr = QLatin1String("init_") + initFunctionName;
+ defineStr += QLatin1String("(module);");
+ s_classPythonDefines << INDENT << defineStr << endl;
+ }
+
+ QString moduleFileName(outputDirectory() + QLatin1Char('/') + subDirectoryForPackage(packageName()));
+ moduleFileName += QLatin1Char('/') + moduleName().toLower() + QLatin1String("_module_wrapper.cpp");
+
+ QFile file(moduleFileName);
+ verifyDirectoryFor(file);
+ if (!file.open(QFile::WriteOnly)) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Error writing file: " << QDir::toNativeSeparators(moduleFileName);
+ return false;
+ }
+
+ QTextStream s(&file);
+
+ // write license comment
+ s << licenseComment() << endl;
+
+ s << "#include <sbkpython.h>" << endl;
+ s << "#include <shiboken.h>" << endl;
+ s << "#include <algorithm>" << endl;
+ if (usePySideExtensions()) {
+ s << includeQDebug;
+ s << "#include <pyside.h>" << endl;
+ }
+
+ s << "#include \"" << getModuleHeaderFileName() << '"' << endl << endl;
+ foreach (const Include& include, includes)
+ s << include;
+ s << endl;
+
+ // Global enums
+ AbstractMetaEnumList globalEnums = this->globalEnums();
+ foreach (const AbstractMetaClass* metaClass, classes()) {
+ const AbstractMetaClass* encClass = metaClass->enclosingClass();
+ if (encClass && encClass->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass)
+ continue;
+ lookForEnumsInClassesNotToBeGenerated(globalEnums, metaClass);
+ }
+
+ TypeDatabase* typeDb = TypeDatabase::instance();
+ TypeSystemTypeEntry* moduleEntry = reinterpret_cast<TypeSystemTypeEntry*>(typeDb->findType(packageName()));
+
+ //Extra includes
+ s << endl << "// Extra includes" << endl;
+ QList<Include> extraIncludes;
+ if (moduleEntry)
+ extraIncludes = moduleEntry->extraIncludes();
+ foreach (AbstractMetaEnum* cppEnum, globalEnums)
+ extraIncludes.append(cppEnum->typeEntry()->extraIncludes());
+ qSort(extraIncludes.begin(), extraIncludes.end());
+ foreach (const Include& inc, extraIncludes)
+ s << inc;
+ s << endl;
+
+ s << "// Current module's type array." << endl;
+ s << "PyTypeObject** " << cppApiVariableName() << ';' << endl;
+
+ s << "// Current module's converter array." << endl;
+ s << "SbkConverter** " << convertersVariableName() << ';' << endl;
+
+ CodeSnipList snips;
+ if (moduleEntry)
+ snips = moduleEntry->codeSnips();
+
+ // module inject-code native/beginning
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode);
+ s << endl;
+ }
+
+ // cleanup staticMetaObject attribute
+ if (usePySideExtensions()) {
+ s << "void cleanTypesAttributes(void) {" << endl;
+ s << INDENT << "for (int i = 0, imax = SBK_" << moduleName() << "_IDX_COUNT; i < imax; i++) {" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "PyObject *pyType = reinterpret_cast<PyObject*>(" << cppApiVariableName() << "[i]);" << endl;
+ s << INDENT << "if (pyType && PyObject_HasAttrString(pyType, \"staticMetaObject\"))"<< endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "PyObject_SetAttrString(pyType, \"staticMetaObject\", Py_None);" << endl;
+ }
+ }
+ s << INDENT << "}" << endl;
+ s << "}" << endl;
+ }
+
+ s << "// Global functions ";
+ s << "------------------------------------------------------------" << endl;
+ s << globalFunctionImpl << endl;
+
+ s << "static PyMethodDef " << moduleName() << "_methods[] = {" << endl;
+ s << globalFunctionDecl;
+ s << INDENT << "{0} // Sentinel" << endl << "};" << endl << endl;
+
+ s << "// Classes initialization functions ";
+ s << "------------------------------------------------------------" << endl;
+ s << classInitDecl << endl;
+
+ if (!globalEnums.isEmpty()) {
+ QString converterImpl;
+ QTextStream convImpl(&converterImpl);
+
+ s << "// Enum definitions ";
+ s << "------------------------------------------------------------" << endl;
+ foreach (const AbstractMetaEnum* cppEnum, globalEnums) {
+ if (cppEnum->isAnonymous() || cppEnum->isPrivate())
+ continue;
+ writeEnumConverterFunctions(s, cppEnum);
+ s << endl;
+ }
+
+ if (!converterImpl.isEmpty()) {
+ s << "// Enum converters ";
+ s << "------------------------------------------------------------" << endl;
+ s << "namespace Shiboken" << endl << '{' << endl;
+ s << converterImpl << endl;
+ s << "} // namespace Shiboken" << endl << endl;
+ }
+ }
+
+ QStringList requiredModules = typeDb->requiredTargetImports();
+ if (!requiredModules.isEmpty())
+ s << "// Required modules' type and converter arrays." << endl;
+ foreach (const QString& requiredModule, requiredModules) {
+ s << "PyTypeObject** " << cppApiVariableName(requiredModule) << ';' << endl;
+ s << "SbkConverter** " << convertersVariableName(requiredModule) << ';' << endl;
+ }
+ s << endl;
+
+ s << "// Module initialization ";
+ s << "------------------------------------------------------------" << endl;
+ ExtendedConverterData extendedConverters = getExtendedConverters();
+ if (!extendedConverters.isEmpty()) {
+ s << endl << "// Extended Converters." << endl << endl;
+ for (ExtendedConverterData::const_iterator it = extendedConverters.cbegin(), end = extendedConverters.cend(); it != end; ++it) {
+ const TypeEntry *externalType = it.key();
+ s << "// Extended implicit conversions for " << externalType->qualifiedTargetLangName() << '.' << endl;
+ foreach (const AbstractMetaClass* sourceClass, extendedConverters[externalType]) {
+ AbstractMetaType* sourceType = buildAbstractMetaTypeFromAbstractMetaClass(sourceClass);
+ AbstractMetaType* targetType = buildAbstractMetaTypeFromTypeEntry(externalType);
+ writePythonToCppConversionFunctions(s, sourceType, targetType);
+ }
+ }
+ }
+
+ QList<const CustomConversion*> typeConversions = getPrimitiveCustomConversions();
+ if (!typeConversions.isEmpty()) {
+ s << endl << "// Primitive Type converters." << endl << endl;
+ foreach (const CustomConversion* conversion, typeConversions) {
+ s << "// C++ to Python conversion for type '" << conversion->ownerType()->qualifiedCppName() << "'." << endl;
+ writeCppToPythonFunction(s, conversion);
+ writeCustomConverterFunctions(s, conversion);
+ }
+ s << endl;
+ }
+
+ QList<const AbstractMetaType*> containers = instantiatedContainers();
+ if (!containers.isEmpty()) {
+ s << "// Container Type converters." << endl << endl;
+ foreach (const AbstractMetaType* container, containers) {
+ s << "// C++ to Python conversion for type '" << container->cppSignature() << "'." << endl;
+ writeContainerConverterFunctions(s, container);
+ }
+ s << endl;
+ }
+
+ s << "#if defined _WIN32 || defined __CYGWIN__" << endl;
+ s << " #define SBK_EXPORT_MODULE __declspec(dllexport)" << endl;
+ s << "#elif __GNUC__ >= 4" << endl;
+ s << " #define SBK_EXPORT_MODULE __attribute__ ((visibility(\"default\")))" << endl;
+ s << "#else" << endl;
+ s << " #define SBK_EXPORT_MODULE" << endl;
+ s << "#endif" << endl << endl;
+
+ s << "#ifdef IS_PY3K" << endl;
+ s << "static struct PyModuleDef moduledef = {" << endl;
+ s << " /* m_base */ PyModuleDef_HEAD_INIT," << endl;
+ s << " /* m_name */ \"" << moduleName() << "\"," << endl;
+ s << " /* m_doc */ 0," << endl;
+ s << " /* m_size */ -1," << endl;
+ s << " /* m_methods */ " << moduleName() << "_methods," << endl;
+ s << " /* m_reload */ 0," << endl;
+ s << " /* m_traverse */ 0," << endl;
+ s << " /* m_clear */ 0," << endl;
+ s << " /* m_free */ 0" << endl;
+ s << "};" << endl << endl;
+ s << "#endif" << endl;
+ s << "SBK_MODULE_INIT_FUNCTION_BEGIN(" << moduleName() << ")" << endl;
+
+ ErrorCode errorCode(QLatin1String("SBK_MODULE_INIT_ERROR"));
+ // module inject-code target/beginning
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode);
+ s << endl;
+ }
+
+ foreach (const QString& requiredModule, typeDb->requiredTargetImports()) {
+ s << INDENT << "{" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "Shiboken::AutoDecRef requiredModule(Shiboken::Module::import(\"" << requiredModule << "\"));" << endl;
+ s << INDENT << "if (requiredModule.isNull())" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "return SBK_MODULE_INIT_ERROR;" << endl;
+ }
+ s << INDENT << cppApiVariableName(requiredModule) << " = Shiboken::Module::getTypes(requiredModule);" << endl;
+ s << INDENT << convertersVariableName(requiredModule) << " = Shiboken::Module::getTypeConverters(requiredModule);" << endl;
+ }
+ s << INDENT << "}" << endl << endl;
+ }
+
+ int maxTypeIndex = getMaxTypeIndex() + instantiatedSmartPointers().size();
+ if (maxTypeIndex) {
+ s << INDENT << "// Create an array of wrapper types for the current module." << endl;
+ s << INDENT << "static PyTypeObject* cppApi[SBK_" << moduleName() << "_IDX_COUNT];" << endl;
+ s << INDENT << cppApiVariableName() << " = cppApi;" << endl << endl;
+ }
+
+ s << INDENT << "// Create an array of primitive type converters for the current module." << endl;
+ s << INDENT << "static SbkConverter* sbkConverters[SBK_" << moduleName() << "_CONVERTERS_IDX_COUNT" << "];" << endl;
+ s << INDENT << convertersVariableName() << " = sbkConverters;" << endl << endl;
+
+ s << "#ifdef IS_PY3K" << endl;
+ s << INDENT << "PyObject* module = Shiboken::Module::create(\"" << moduleName() << "\", &moduledef);" << endl;
+ s << "#else" << endl;
+ s << INDENT << "PyObject* module = Shiboken::Module::create(\"" << moduleName() << "\", ";
+ s << moduleName() << "_methods);" << endl;
+ s << "#endif" << endl << endl;
+
+ //s << INDENT << "// Initialize converters for primitive types." << endl;
+ //s << INDENT << "initConverters();" << endl << endl;
+
+ s << INDENT << "// Initialize classes in the type system" << endl;
+ s << classPythonDefines;
+
+ if (!typeConversions.isEmpty()) {
+ s << endl;
+ foreach (const CustomConversion* conversion, typeConversions) {
+ writePrimitiveConverterInitialization(s, conversion);
+ s << endl;
+ }
+ }
+
+ if (!containers.isEmpty()) {
+ s << endl;
+ foreach (const AbstractMetaType* container, containers) {
+ writeContainerConverterInitialization(s, container);
+ s << endl;
+ }
+ }
+
+ if (!extendedConverters.isEmpty()) {
+ s << endl;
+ for (ExtendedConverterData::const_iterator it = extendedConverters.cbegin(), end = extendedConverters.cend(); it != end; ++it) {
+ writeExtendedConverterInitialization(s, it.key(), it.value());
+ s << endl;
+ }
+ }
+
+ writeEnumsInitialization(s, globalEnums);
+
+ s << INDENT << "// Register primitive types converters." << endl;
+ foreach(const PrimitiveTypeEntry* pte, primitiveTypes()) {
+ if (!pte->generateCode() || !pte->isCppPrimitive())
+ continue;
+ const TypeEntry *referencedType = pte->basicReferencedTypeEntry();
+ if (!referencedType)
+ continue;
+ QString converter = converterObject(referencedType);
+ QStringList cppSignature = pte->qualifiedCppName().split(QLatin1String("::"), QString::SkipEmptyParts);
+ while (!cppSignature.isEmpty()) {
+ QString signature = cppSignature.join(QLatin1String("::"));
+ s << INDENT << "Shiboken::Conversions::registerConverterName(" << converter << ", \"" << signature << "\");" << endl;
+ cppSignature.removeFirst();
+ }
+ }
+ // Register type resolver for all containers found in signals.
+ QSet<QByteArray> typeResolvers;
+ foreach (AbstractMetaClass* metaClass, classes()) {
+ if (!metaClass->isQObject() || !metaClass->typeEntry()->generateCode())
+ continue;
+ foreach (AbstractMetaFunction* func, metaClass->functions()) {
+ if (func->isSignal()) {
+ foreach (AbstractMetaArgument* arg, func->arguments()) {
+ if (arg->type()->isContainer()) {
+ QString value = translateType(arg->type(), metaClass, ExcludeConst | ExcludeReference);
+ if (value.startsWith(QLatin1String("::")))
+ value.remove(0, 2);
+ typeResolvers << QMetaObject::normalizedType(value.toUtf8().constData());
+ }
+ }
+ }
+ }
+ }
+
+ s << endl;
+ if (maxTypeIndex)
+ s << INDENT << "Shiboken::Module::registerTypes(module, " << cppApiVariableName() << ");" << endl;
+ s << INDENT << "Shiboken::Module::registerTypeConverters(module, " << convertersVariableName() << ");" << endl;
+
+ s << endl << INDENT << "if (PyErr_Occurred()) {" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "PyErr_Print();" << endl;
+ s << INDENT << "Py_FatalError(\"can't initialize module " << moduleName() << "\");" << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ // module inject-code target/end
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode);
+ s << endl;
+ }
+
+ // module inject-code native/end
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode);
+ s << endl;
+ }
+
+ if (usePySideExtensions()) {
+ foreach (AbstractMetaEnum* metaEnum, globalEnums)
+ if (!metaEnum->isAnonymous()) {
+ s << INDENT << "qRegisterMetaType< ::" << metaEnum->typeEntry()->qualifiedCppName() << " >(\"" << metaEnum->name() << "\");" << endl;
+ }
+
+ // cleanup staticMetaObject attribute
+ s << INDENT << "PySide::registerCleanupFunction(cleanTypesAttributes);" << endl;
+ }
+
+ s << "SBK_MODULE_INIT_FUNCTION_END" << endl;
+
+ return true;
+}
+
+static ArgumentOwner getArgumentOwner(const AbstractMetaFunction* func, int argIndex)
+{
+ ArgumentOwner argOwner = func->argumentOwner(func->ownerClass(), argIndex);
+ if (argOwner.index == ArgumentOwner::InvalidIndex)
+ argOwner = func->argumentOwner(func->declaringClass(), argIndex);
+ return argOwner;
+}
+
+bool CppGenerator::writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, int argIndex, bool useHeuristicPolicy)
+{
+ const int numArgs = func->arguments().count();
+ bool ctorHeuristicEnabled = func->isConstructor() && useCtorHeuristic() && useHeuristicPolicy;
+
+ bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(OverloadData(getFunctionGroups(func->implementingClass())[func->name()], this));
+
+ ArgumentOwner argOwner = getArgumentOwner(func, argIndex);
+ ArgumentOwner::Action action = argOwner.action;
+ int parentIndex = argOwner.index;
+ int childIndex = argIndex;
+ if (ctorHeuristicEnabled && argIndex > 0 && numArgs) {
+ AbstractMetaArgument* arg = func->arguments().at(argIndex-1);
+ if (arg->name() == QLatin1String("parent") && isObjectType(arg->type())) {
+ action = ArgumentOwner::Add;
+ parentIndex = argIndex;
+ childIndex = -1;
+ }
+ }
+
+ QString parentVariable;
+ QString childVariable;
+ if (action != ArgumentOwner::Invalid) {
+ if (!usePyArgs && argIndex > 1)
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Argument index for parent tag out of bounds: " << func->signature();
+
+ if (action == ArgumentOwner::Remove) {
+ parentVariable = QLatin1String("Py_None");
+ } else {
+ if (parentIndex == 0) {
+ parentVariable = QLatin1String(PYTHON_RETURN_VAR);
+ } else if (parentIndex == -1) {
+ parentVariable = QLatin1String(PYTHON_SELF_VAR);
+ } else {
+ parentVariable = usePyArgs
+ ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(parentIndex - 1)
+ : QLatin1String(PYTHON_ARG);
+ }
+ }
+
+ if (childIndex == 0) {
+ childVariable = QLatin1String(PYTHON_RETURN_VAR);
+ } else if (childIndex == -1) {
+ childVariable = QLatin1String(PYTHON_SELF_VAR);
+ } else {
+ childVariable = usePyArgs
+ ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(childIndex - 1)
+ : QLatin1String(PYTHON_ARG);
+ }
+
+ s << INDENT << "Shiboken::Object::setParent(" << parentVariable << ", " << childVariable << ");\n";
+ return true;
+ }
+
+ return false;
+}
+
+void CppGenerator::writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, bool useHeuristicForReturn)
+{
+ const int numArgs = func->arguments().count();
+
+ // -1 = return value
+ // 0 = self
+ // 1..n = func. args.
+ for (int i = -1; i <= numArgs; ++i)
+ writeParentChildManagement(s, func, i, useHeuristicForReturn);
+
+ if (useHeuristicForReturn)
+ writeReturnValueHeuristics(s, func);
+}
+
+void CppGenerator::writeReturnValueHeuristics(QTextStream& s, const AbstractMetaFunction* func, const QString& self)
+{
+ AbstractMetaType *type = func->type();
+ if (!useReturnValueHeuristic()
+ || !func->ownerClass()
+ || !type
+ || func->isStatic()
+ || func->isConstructor()
+ || !func->typeReplaced(0).isEmpty()) {
+ return;
+ }
+
+ ArgumentOwner argOwner = getArgumentOwner(func, ArgumentOwner::ReturnIndex);
+ if (argOwner.action == ArgumentOwner::Invalid || argOwner.index != ArgumentOwner::ThisIndex) {
+ if (isPointerToWrapperType(type))
+ s << INDENT << "Shiboken::Object::setParent(" << self << ", " PYTHON_RETURN_VAR ");" << endl;
+ }
+}
+
+void CppGenerator::writeHashFunction(QTextStream &s, GeneratorContext &context)
+{
+ const AbstractMetaClass *metaClass = context.metaClass();
+ s << "static Py_hash_t " << cpythonBaseName(metaClass) << "_HashFunc(PyObject* self) {" << endl;
+ writeCppSelfDefinition(s, context);
+ s << INDENT << "return " << metaClass->typeEntry()->hashFunction() << '(';
+ s << (isObjectType(metaClass) ? "" : "*") << CPP_SELF_VAR << ");" << endl;
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeStdListWrapperMethods(QTextStream &s, GeneratorContext &context)
+{
+ const AbstractMetaClass *metaClass = context.metaClass();
+ ErrorCode errorCode(0);
+
+ // __len__
+ s << "Py_ssize_t " << cpythonBaseName(metaClass->typeEntry()) << "__len__(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << '{' << endl;
+ writeCppSelfDefinition(s, context);
+ s << INDENT << "return " CPP_SELF_VAR "->size();" << endl;
+ s << '}' << endl;
+
+ // __getitem__
+ s << "PyObject* " << cpythonBaseName(metaClass->typeEntry()) << "__getitem__(PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i)" << endl;
+ s << '{' << endl;
+ writeCppSelfDefinition(s, context);
+ writeIndexError(s, QLatin1String("index out of bounds"));
+
+ s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = " CPP_SELF_VAR "->begin();" << endl;
+ s << INDENT << "for (Py_ssize_t pos = 0; pos < _i; pos++) _item++;" << endl;
+
+ const AbstractMetaType* itemType = metaClass->templateBaseClassInstantiations().first();
+
+ s << INDENT << "return ";
+ writeToPythonConversion(s, itemType, metaClass, QLatin1String("*_item"));
+ s << ';' << endl;
+ s << '}' << endl;
+
+ // __setitem__
+ ErrorCode errorCode2(-1);
+ s << "int " << cpythonBaseName(metaClass->typeEntry()) << "__setitem__(PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i, PyObject* pyArg)" << endl;
+ s << '{' << endl;
+ writeCppSelfDefinition(s, context);
+ writeIndexError(s, QLatin1String("list assignment index out of range"));
+
+ s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ';' << endl;
+ s << INDENT << "if (!";
+ writeTypeCheck(s, itemType, QLatin1String("pyArg"), isNumber(itemType->typeEntry()));
+ s << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_TypeError, \"attributed value with wrong type, '";
+ s << itemType->name() << "' or other convertible type expected\");" << endl;
+ s << INDENT << "return -1;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ writeArgumentConversion(s, itemType, QLatin1String("cppValue"), QLatin1String("pyArg"), metaClass);
+
+ s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = " CPP_SELF_VAR "->begin();" << endl;
+ s << INDENT << "for (Py_ssize_t pos = 0; pos < _i; pos++) _item++;" << endl;
+ s << INDENT << "*_item = cppValue;" << endl;
+ s << INDENT << "return 0;" << endl;
+ s << '}' << endl;
+}
+void CppGenerator::writeIndexError(QTextStream& s, const QString& errorMsg)
+{
+ s << INDENT << "if (_i < 0 || _i >= (Py_ssize_t) " CPP_SELF_VAR "->size()) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_IndexError, \"" << errorMsg << "\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+}
+
+QString CppGenerator::writeReprFunction(QTextStream &s, GeneratorContext &context)
+{
+ const AbstractMetaClass *metaClass = context.metaClass();
+ QString funcName = cpythonBaseName(metaClass) + QLatin1String("__repr__");
+ s << "extern \"C\"" << endl;
+ s << '{' << endl;
+ s << "static PyObject* " << funcName << "(PyObject* self)" << endl;
+ s << '{' << endl;
+ writeCppSelfDefinition(s, context);
+ s << INDENT << "QBuffer buffer;" << endl;
+ s << INDENT << "buffer.open(QBuffer::ReadWrite);" << endl;
+ s << INDENT << "QDebug dbg(&buffer);" << endl;
+ s << INDENT << "dbg << " << (metaClass->typeEntry()->isValue() ? "*" : "") << CPP_SELF_VAR ";" << endl;
+ s << INDENT << "buffer.close();" << endl;
+ s << INDENT << "QByteArray str = buffer.data();" << endl;
+ s << INDENT << "int idx = str.indexOf('(');" << endl;
+ s << INDENT << "if (idx >= 0)" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "str.replace(0, idx, Py_TYPE(self)->tp_name);" << endl;
+ }
+ s << INDENT << "PyObject* mod = PyDict_GetItemString(Py_TYPE(self)->tp_dict, \"__module__\");" << endl;
+ s << INDENT << "if (mod)" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return Shiboken::String::fromFormat(\"<%s.%s at %p>\", Shiboken::String::toCString(mod), str.constData(), self);" << endl;
+ }
+ s << INDENT << "else" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return Shiboken::String::fromFormat(\"<%s at %p>\", str.constData(), self);" << endl;
+ }
+ s << '}' << endl;
+ s << "} // extern C" << endl << endl;;
+ return funcName;
+}
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h
new file mode 100644
index 000000000..5dc3f5a15
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.h
@@ -0,0 +1,370 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef CPPGENERATOR_H
+#define CPPGENERATOR_H
+
+#include "shibokengenerator.h"
+
+/**
+ * The CppGenerator generate the implementations of C++ bindings classes.
+ */
+class CppGenerator : public ShibokenGenerator
+{
+public:
+ CppGenerator();
+protected:
+ QString fileNamePrefix() const;
+ QString fileNameForContext(GeneratorContext &context) const;
+ QList<AbstractMetaFunctionList> filterGroupedOperatorFunctions(const AbstractMetaClass* metaClass,
+ uint query);
+ void generateClass(QTextStream& s, GeneratorContext &classContext);
+ bool finishGeneration();
+
+private:
+ void writeConstructorNative(QTextStream& s, const AbstractMetaFunction* func);
+ void writeDestructorNative(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ QString getVirtualFunctionReturnTypeName(const AbstractMetaFunction* func);
+ void writeVirtualMethodNative(QTextStream& s, const AbstractMetaFunction* func);
+
+ void writeMetaObjectMethod(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeMetaCast(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeEnumConverterFunctions(QTextStream& s, const TypeEntry* enumType);
+ void writeEnumConverterFunctions(QTextStream& s, const AbstractMetaEnum* metaEnum);
+ void writeConverterFunctions(QTextStream &s, const AbstractMetaClass *metaClass,
+ GeneratorContext &classContext);
+ void writeCustomConverterFunctions(QTextStream& s, const CustomConversion* customConversion);
+ void writeConverterRegister(QTextStream &s, const AbstractMetaClass *metaClass,
+ GeneratorContext &classContext);
+ void writeCustomConverterRegister(QTextStream& s, const CustomConversion* customConversion, const QString& converterVar);
+ void writeContainerConverterRegister(QTextStream& s, const AbstractMetaType* container, const QString& converterVar);
+
+ void writeContainerConverterFunctions(QTextStream& s, const AbstractMetaType* containerType);
+
+ void writeMethodWrapperPreamble(QTextStream &s, OverloadData &overloadData,
+ GeneratorContext &context);
+ void writeConstructorWrapper(QTextStream &s, const AbstractMetaFunctionList overloads, GeneratorContext &classContext);
+ void writeDestructorWrapper(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeMethodWrapper(QTextStream &s, const AbstractMetaFunctionList overloads,
+ GeneratorContext &classContext);
+ void writeArgumentsInitializer(QTextStream& s, OverloadData& overloadData);
+ void writeCppSelfDefinition(QTextStream &s,
+ const AbstractMetaFunction *func,
+ GeneratorContext &context,
+ bool hasStaticOverload = false);
+ void writeCppSelfDefinition(QTextStream &s,
+ GeneratorContext &context,
+ bool hasStaticOverload = false,
+ bool cppSelfAsReference = false);
+
+ void writeErrorSection(QTextStream& s, OverloadData& overloadData);
+ void writeFunctionReturnErrorCheckSection(QTextStream& s, bool hasReturnValue = true);
+
+ /// Writes the check section for the validity of wrapped C++ objects.
+ void writeInvalidPyObjectCheck(QTextStream& s, const QString& pyObj);
+
+ void writeTypeCheck(QTextStream& s, const AbstractMetaType* argType, QString argumentName, bool isNumber = false, QString customType = QString(), bool rejectNull = false);
+ void writeTypeCheck(QTextStream& s, const OverloadData* overloadData, QString argumentName);
+
+ void writeTypeDiscoveryFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeSetattroFunction(QTextStream &s, GeneratorContext &context);
+ void writeGetattroFunction(QTextStream &s, GeneratorContext &context);
+ QString writeSmartPointerGetterCast();
+
+ /**
+ * Writes Python to C++ conversions for arguments on Python wrappers.
+ * If implicit conversions, and thus new object allocation, are needed,
+ * code to deallocate a possible new instance is also generated.
+ * \param s text stream to write
+ * \param argType a pointer to the argument type to be converted
+ * \param argName C++ argument name
+ * \param pyArgName Python argument name
+ * \param context the current meta class
+ * \param defaultValue an optional default value to be used instead of the conversion result
+ * \param castArgumentAsUnused if true the converted argument is cast as unused to avoid compiler warnings
+ */
+ void writeArgumentConversion(QTextStream& s, const AbstractMetaType* argType,
+ const QString& argName, const QString& pyArgName,
+ const AbstractMetaClass* context = 0,
+ const QString& defaultValue = QString(),
+ bool castArgumentAsUnused = false);
+
+ /**
+ * Returns the AbstractMetaType for a function argument.
+ * If the argument type was modified in the type system, this method will
+ * try to build a new type based on the type name defined in the type system.
+ * \param func The function which owns the argument.
+ * \param argPos Argument position in the function signature.
+ * Note that the position 0 represents the return value, and the function
+ * parameters start counting on 1.
+ * \param newType It is set to true if the type returned is a new object that must be deallocated.
+ * \return The type of the argument indicated by \p argPos.
+ */
+ const AbstractMetaType* getArgumentType(const AbstractMetaFunction* func, int argPos);
+
+ void writePythonToCppTypeConversion(QTextStream& s,
+ const AbstractMetaType* type,
+ const QString& pyIn,
+ const QString& cppOut,
+ const AbstractMetaClass* context = 0,
+ const QString& defaultValue = QString());
+
+ /// Writes the conversion rule for arguments of regular and virtual methods.
+ void writeConversionRule(QTextStream& s, const AbstractMetaFunction* func, TypeSystem::Language language);
+ /// Writes the conversion rule for the return value of a method.
+ void writeConversionRule(QTextStream& s, const AbstractMetaFunction* func, TypeSystem::Language language, const QString& outputVar);
+
+ /**
+ * Set the Python method wrapper return value variable to Py_None if
+ * there are return types different from void in any of the other overloads
+ * for the function passed as parameter.
+ * \param s text stream to write
+ * \param func a pointer to the function that will possibly return Py_None
+ * \param thereIsReturnValue indicates if the return type of any of the other overloads
+ * for this function is different from 'void'
+ */
+ void writeNoneReturn(QTextStream& s, const AbstractMetaFunction* func, bool thereIsReturnValue);
+
+ /**
+ * Writes the Python function wrapper overload decisor that selects which C++
+ * method/function to call with the received Python arguments.
+ * \param s text stream to write
+ * \param overloadData the overload data describing all the possible overloads for the function/method
+ */
+ void writeOverloadedFunctionDecisor(QTextStream& s, const OverloadData& overloadData);
+ /// Recursive auxiliar method to the other writeOverloadedFunctionDecisor.
+ void writeOverloadedFunctionDecisorEngine(QTextStream& s, const OverloadData* parentOverloadData);
+
+ /// Writes calls to all the possible method/function overloads.
+ void writeFunctionCalls(QTextStream &s,
+ const OverloadData &overloadData,
+ GeneratorContext &context);
+
+ /// Writes the call to a single function usually from a collection of overloads.
+ void writeSingleFunctionCall(QTextStream &s,
+ const OverloadData &overloadData,
+ const AbstractMetaFunction *func,
+ GeneratorContext &context);
+
+ /// Returns the name of a C++ to Python conversion function.
+ static QString cppToPythonFunctionName(const QString& sourceTypeName, QString targetTypeName = QString());
+
+ /// Returns the name of a Python to C++ conversion function.
+ static QString pythonToCppFunctionName(const QString& sourceTypeName, const QString& targetTypeName);
+ static QString pythonToCppFunctionName(const AbstractMetaType* sourceType, const AbstractMetaType* targetType);
+ static QString pythonToCppFunctionName(const CustomConversion::TargetToNativeConversion* toNative, const TypeEntry* targetType);
+
+ /// Returns the name of a Python to C++ convertible check function.
+ static QString convertibleToCppFunctionName(const QString& sourceTypeName, const QString& targetTypeName);
+ static QString convertibleToCppFunctionName(const AbstractMetaType* sourceType, const AbstractMetaType* targetType);
+ static QString convertibleToCppFunctionName(const CustomConversion::TargetToNativeConversion* toNative, const TypeEntry* targetType);
+
+ /// Writes a C++ to Python conversion function.
+ void writeCppToPythonFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, QString targetTypeName = QString());
+ void writeCppToPythonFunction(QTextStream& s, const CustomConversion* customConversion);
+ void writeCppToPythonFunction(QTextStream& s, const AbstractMetaType* containerType);
+
+ /// Writes a Python to C++ conversion function.
+ void writePythonToCppFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, const QString& targetTypeName);
+
+ /// Writes a Python to C++ convertible check function.
+ void writeIsPythonConvertibleToCppFunction(QTextStream& s,
+ const QString& sourceTypeName,
+ const QString& targetTypeName,
+ const QString& condition,
+ QString pythonToCppFuncName = QString(),
+ bool acceptNoneAsCppNull = false);
+
+ /// Writes a pair of Python to C++ conversion and check functions.
+ void writePythonToCppConversionFunctions(QTextStream& s,
+ const AbstractMetaType* sourceType,
+ const AbstractMetaType* targetType,
+ QString typeCheck = QString(),
+ QString conversion = QString(),
+ QString preConversion = QString());
+ /// Writes a pair of Python to C++ conversion and check functions for implicit conversions.
+ void writePythonToCppConversionFunctions(QTextStream& s,
+ const CustomConversion::TargetToNativeConversion* toNative,
+ const TypeEntry* targetType);
+
+ /// Writes a pair of Python to C++ conversion and check functions for instantiated container types.
+ void writePythonToCppConversionFunctions(QTextStream& s, const AbstractMetaType* containerType);
+
+ void writeAddPythonToCppConversion(QTextStream& s, const QString& converterVar, const QString& pythonToCppFunc, const QString& isConvertibleFunc);
+
+ void writeNamedArgumentResolution(QTextStream& s, const AbstractMetaFunction* func, bool usePyArgs);
+
+ /// Returns a string containing the name of an argument for the given function and argument index.
+ QString argumentNameFromIndex(const AbstractMetaFunction* func, int argIndex, const AbstractMetaClass** wrappedClass);
+ void writeMethodCall(QTextStream &s, const AbstractMetaFunction *func,
+ GeneratorContext &context, int maxArgs = 0);
+
+ QString getInitFunctionName(GeneratorContext &context) const;
+
+ void writeClassRegister(QTextStream &s,
+ const AbstractMetaClass *metaClass,
+ GeneratorContext &classContext);
+ void writeClassDefinition(QTextStream &s,
+ const AbstractMetaClass *metaClass,
+ GeneratorContext &classContext);
+ void writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList overloads);
+ void writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads);
+
+ /// Writes the implementation of all methods part of python sequence protocol
+ void writeSequenceMethods(QTextStream &s,
+ const AbstractMetaClass *metaClass,
+ GeneratorContext &context);
+ void writeTypeAsSequenceDefinition(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ /// Writes the PyMappingMethods structure for types that supports the python mapping protocol.
+ void writeTypeAsMappingDefinition(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeMappingMethods(QTextStream &s,
+ const AbstractMetaClass *metaClass,
+ GeneratorContext &context);
+
+ void writeTypeAsNumberDefinition(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeTpTraverseFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeTpClearFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeCopyFunction(QTextStream &s, GeneratorContext &context);
+
+ void writeGetterFunction(QTextStream &s,
+ const AbstractMetaField *metaField,
+ GeneratorContext &context);
+ void writeSetterFunction(QTextStream &s,
+ const AbstractMetaField *metaField,
+ GeneratorContext &context);
+
+ void writeRichCompareFunction(QTextStream &s, GeneratorContext &context);
+ void writeToPythonFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeEnumsInitialization(QTextStream& s, AbstractMetaEnumList& enums);
+ void writeEnumInitialization(QTextStream& s, const AbstractMetaEnum* metaEnum);
+
+ void writeSignalInitialization(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeFlagsMethods(QTextStream& s, const AbstractMetaEnum* cppEnum);
+ void writeFlagsToLong(QTextStream& s, const AbstractMetaEnum* cppEnum);
+ void writeFlagsNonZero(QTextStream& s, const AbstractMetaEnum* cppEnum);
+ void writeFlagsNumberMethodsDefinition(QTextStream& s, const AbstractMetaEnum* cppEnum);
+ void writeFlagsBinaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
+ QString pyOpName, QString cppOpName);
+ void writeFlagsUnaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
+ QString pyOpName, QString cppOpName, bool boolResult = false);
+
+ /// Writes the function that registers the multiple inheritance information for the classes that need it.
+ void writeMultipleInheritanceInitializerFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+ /// Writes the implementation of special cast functions, used when we need to cast a class with multiple inheritance.
+ void writeSpecialCastFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writePrimitiveConverterInitialization(QTextStream& s, const CustomConversion* customConversion);
+ void writeEnumConverterInitialization(QTextStream& s, const TypeEntry* enumType);
+ void writeEnumConverterInitialization(QTextStream& s, const AbstractMetaEnum* metaEnum);
+ void writeContainerConverterInitialization(QTextStream& s, const AbstractMetaType* type);
+ void writeExtendedConverterInitialization(QTextStream& s, const TypeEntry* externalType, const QList<const AbstractMetaClass*>& conversions);
+
+ void writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, bool userHeuristicForReturn);
+ bool writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, int argIndex, bool userHeuristicPolicy);
+ void writeReturnValueHeuristics(QTextStream& s, const AbstractMetaFunction* func, const QString& self = QLatin1String(PYTHON_SELF_VAR));
+ void writeInitQtMetaTypeFunctionBody(QTextStream &s, GeneratorContext &context) const;
+
+ /**
+ * Returns the multiple inheritance initializer function for the given class.
+ * \param metaClass the class for whom the function name must be generated.
+ * \return name of the multiple inheritance information initializer function or
+ * an empty string if there is no multiple inheritance in its ancestry.
+ */
+ QString multipleInheritanceInitializerFunctionName(const AbstractMetaClass* metaClass);
+
+ /// Returns a list of all classes to which the given class could be cast.
+ QStringList getAncestorMultipleInheritance(const AbstractMetaClass* metaClass);
+
+ /// Returns true if the given class supports the python number protocol
+ bool supportsNumberProtocol(const AbstractMetaClass* metaClass);
+
+ /// Returns true if the given class supports the python sequence protocol
+ bool supportsSequenceProtocol(const AbstractMetaClass* metaClass);
+
+ /// Returns true if the given class supports the python mapping protocol
+ bool supportsMappingProtocol(const AbstractMetaClass* metaClass);
+
+ /// Returns true if generator should produce getters and setters for the given class.
+ bool shouldGenerateGetSetList(const AbstractMetaClass* metaClass);
+
+ void writeHashFunction(QTextStream &s, GeneratorContext &context);
+
+ /// Write default implementations for sequence protocol
+ void writeStdListWrapperMethods(QTextStream &s, GeneratorContext &context);
+ /// Helper function for writeStdListWrapperMethods.
+ void writeIndexError(QTextStream& s, const QString& errorMsg);
+
+ QString writeReprFunction(QTextStream &s, GeneratorContext &context);
+
+ bool hasBoolCast(const AbstractMetaClass* metaClass) const;
+
+ // Number protocol structure members names.
+ static QHash<QString, QString> m_nbFuncs;
+
+ // Maps special function names to function parameters and return types
+ // used by CPython API in the sequence protocol.
+ QHash<QString, QPair<QString, QString> > m_sequenceProtocol;
+ // Sequence protocol structure members names.
+ static QHash<QString, QString> m_sqFuncs;
+
+ // Maps special function names to function parameters and return types
+ // used by CPython API in the mapping protocol.
+ QHash<QString, QPair<QString, QString> > m_mappingProtocol;
+ // Mapping protocol structure members names.
+ static QHash<QString, QString> m_mpFuncs;
+
+ static QString m_currentErrorCode;
+
+ /// Helper class to set and restore the current error code.
+ class ErrorCode {
+ public:
+ explicit ErrorCode(QString errorCode) {
+ m_savedErrorCode = CppGenerator::m_currentErrorCode;
+ CppGenerator::m_currentErrorCode = errorCode;
+ }
+ explicit ErrorCode(int errorCode) {
+ m_savedErrorCode = CppGenerator::m_currentErrorCode;
+ CppGenerator::m_currentErrorCode = QString::number(errorCode);
+ }
+ ~ErrorCode() {
+ CppGenerator::m_currentErrorCode = m_savedErrorCode;
+ }
+ private:
+ QString m_savedErrorCode;
+ };
+};
+
+#endif // CPPGENERATOR_H
diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.cpp b/sources/shiboken2/generator/shiboken2/headergenerator.cpp
new file mode 100644
index 000000000..5ef5d5612
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/headergenerator.cpp
@@ -0,0 +1,558 @@
+/****************************************************************************
+**
+** 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 "headergenerator.h"
+#include <abstractmetalang.h>
+#include <typedatabase.h>
+#include <reporthandler.h>
+#include <fileout.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QTextStream>
+#include <QtCore/QVariant>
+#include <QtCore/QRegExp>
+#include <QtCore/QDebug>
+
+QString HeaderGenerator::fileNamePrefix() const
+{
+ return QLatin1String("_wrapper.h");
+}
+
+QString HeaderGenerator::fileNameForContext(GeneratorContext &context) const
+{
+ const AbstractMetaClass *metaClass = context.metaClass();
+ if (!context.forSmartPointer()) {
+ QString fileNameBase = metaClass->qualifiedCppName().toLower();
+ fileNameBase.replace(QLatin1String("::"), QLatin1String("_"));
+ return fileNameBase + fileNamePrefix();
+ } else {
+ const AbstractMetaType *smartPointerType = context.preciseType();
+ QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass);
+ return fileNameBase + fileNamePrefix();
+ }
+}
+
+void HeaderGenerator::writeCopyCtor(QTextStream& s, const AbstractMetaClass* metaClass) const
+{
+ s << INDENT << wrapperName(metaClass) << "(const " << metaClass->qualifiedCppName() << "& self)";
+ s << " : " << metaClass->qualifiedCppName() << "(self)" << endl;
+ s << INDENT << "{" << endl;
+ s << INDENT << "}" << endl << endl;
+}
+
+void HeaderGenerator::writeProtectedFieldAccessors(QTextStream& s, const AbstractMetaField* field) const
+{
+ AbstractMetaType *metaType = field->type();
+ QString fieldType = metaType->cppSignature();
+ QString fieldName = field->enclosingClass()->qualifiedCppName() + QLatin1String("::") + field->name();
+
+ // Force use of pointer to return internal variable memory
+ bool useReference = (!metaType->isConstant() &&
+ !metaType->isEnum() &&
+ !metaType->isPrimitive() &&
+ metaType->indirections() == 0);
+
+
+ // Get function
+ s << INDENT << "inline " << fieldType
+ << (useReference ? '*' : ' ')
+ << ' ' << protectedFieldGetterName(field) << "()"
+ << " { return "
+ << (useReference ? '&' : ' ') << "this->" << fieldName << "; }" << endl;
+
+ // Set function
+ s << INDENT << "inline void " << protectedFieldSetterName(field) << '(' << fieldType << " value)"
+ << " { " << fieldName << " = value; }" << endl;
+}
+
+void HeaderGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
+{
+ AbstractMetaClass *metaClass = classContext.metaClass();
+ if (ReportHandler::isDebug(ReportHandler::SparseDebug))
+ qCDebug(lcShiboken) << "Generating header for " << metaClass->fullName();
+ m_inheritedOverloads.clear();
+ Indentation indent(INDENT);
+
+ // write license comment
+ s << licenseComment();
+
+ QString wrapperName;
+ if (!classContext.forSmartPointer()) {
+ wrapperName = HeaderGenerator::wrapperName(metaClass);
+ } else {
+ wrapperName = HeaderGenerator::wrapperName(classContext.preciseType());
+ }
+ QString headerGuard = getFilteredCppSignatureString(wrapperName).toUpper();
+
+ // Header
+ s << "#ifndef SBK_" << headerGuard << "_H" << endl;
+ s << "#define SBK_" << headerGuard << "_H" << endl<< endl;
+
+ if (!avoidProtectedHack())
+ s << "#define protected public" << endl << endl;
+
+ s << "#include <shiboken.h>" << endl << endl;
+
+ //Includes
+ s << metaClass->typeEntry()->include() << endl;
+
+ if (shouldGenerateCppWrapper(metaClass)) {
+
+ if (usePySideExtensions() && metaClass->isQObject())
+ s << "namespace PySide { class DynamicQMetaObject; }\n\n";
+
+ // Class
+ s << "class " << wrapperName;
+ s << " : public " << metaClass->qualifiedCppName();
+
+ s << endl << '{' << endl << "public:" << endl;
+
+ bool hasVirtualFunction = false;
+ foreach (AbstractMetaFunction *func, filterFunctions(metaClass)) {
+ if (func->isVirtual())
+ hasVirtualFunction = true;
+ writeFunction(s, func);
+ }
+
+ if (avoidProtectedHack() && metaClass->hasProtectedFields()) {
+ foreach (AbstractMetaField* field, metaClass->fields()) {
+ if (!field->isProtected())
+ continue;
+ writeProtectedFieldAccessors(s, field);
+ }
+ }
+
+ //destructor
+ // PYSIDE-504: When C++ 11 is used, then the destructor must always be written.
+ // See generator.h for further reference.
+ if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor() || alwaysGenerateDestructor) {
+ s << INDENT;
+ if (avoidProtectedHack() && metaClass->hasPrivateDestructor())
+ s << "// C++11: need to declare (unimplemented) destructor because "
+ "the base class destructor is private." << endl;
+ if (metaClass->hasVirtualDestructor() || hasVirtualFunction)
+ s << "virtual ";
+ s << '~' << wrapperName << "();" << endl;
+ }
+
+ writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), TypeSystem::CodeSnipPositionDeclaration, TypeSystem::NativeCode);
+
+ if ((!avoidProtectedHack() || !metaClass->hasPrivateDestructor())
+ && usePySideExtensions() && metaClass->isQObject()) {
+ s << "public:\n";
+ s << INDENT << "virtual int qt_metacall(QMetaObject::Call call, int id, void** args);" << endl;
+ s << INDENT << "virtual void* qt_metacast(const char* _clname);" << endl;
+ }
+
+ if (m_inheritedOverloads.size()) {
+ s << INDENT << "// Inherited overloads, because the using keyword sux" << endl;
+ writeInheritedOverloads(s);
+ }
+
+ if (usePySideExtensions())
+ s << INDENT << "static void pysideInitQtMetaTypes();" << endl;
+
+ s << "};" << endl << endl;
+ }
+
+ s << "#endif // SBK_" << headerGuard << "_H" << endl << endl;
+}
+
+void HeaderGenerator::writeFunction(QTextStream& s, const AbstractMetaFunction* func)
+{
+
+ // do not write copy ctors here.
+ if (!func->isPrivate() && func->functionType() == AbstractMetaFunction::CopyConstructorFunction) {
+ writeCopyCtor(s, func->ownerClass());
+ return;
+ }
+ if (func->isUserAdded())
+ return;
+
+ if (avoidProtectedHack() && func->isProtected() && !func->isConstructor() && !func->isOperatorOverload()) {
+ s << INDENT << "inline " << (func->isStatic() ? "static " : "");
+ s << functionSignature(func, QString(), QLatin1String("_protected"), Generator::EnumAsInts|Generator::OriginalTypeDescription)
+ << " { ";
+ s << (func->type() ? "return " : "");
+ if (!func->isAbstract())
+ s << func->ownerClass()->qualifiedCppName() << "::";
+ s << func->originalName() << '(';
+ QStringList args;
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ QString argName = arg->name();
+ const TypeEntry* enumTypeEntry = 0;
+ if (arg->type()->isFlags())
+ enumTypeEntry = reinterpret_cast<const FlagsTypeEntry*>(arg->type()->typeEntry())->originator();
+ else if (arg->type()->isEnum())
+ enumTypeEntry = arg->type()->typeEntry();
+ if (enumTypeEntry)
+ argName = QString::fromLatin1("%1(%2)").arg(arg->type()->cppSignature(), argName);
+ args << argName;
+ }
+ s << args.join(QLatin1String(", ")) << ')';
+ s << "; }" << endl;
+ }
+
+ // pure virtual functions need a default implementation
+ if ((func->isPrivate() && !visibilityModifiedToPrivate(func))
+ || (func->isModifiedRemoved() && !func->isAbstract()))
+ return;
+
+ if (avoidProtectedHack() && func->ownerClass()->hasPrivateDestructor()
+ && (func->isAbstract() || func->isVirtual()))
+ return;
+
+ if (func->isConstructor() || func->isAbstract() || func->isVirtual()) {
+ s << INDENT;
+ Options virtualOption = Generator::OriginalTypeDescription;
+
+ if (func->isVirtual() || func->isAbstract())
+ s << "virtual ";
+ else if (!func->hasSignatureModifications())
+ virtualOption = Generator::NoOption;
+
+ s << functionSignature(func, QString(), QString(), virtualOption) << ';' << endl;
+
+ // Check if this method hide other methods in base classes
+ foreach (const AbstractMetaFunction* f, func->ownerClass()->functions()) {
+ if (f != func
+ && !f->isConstructor()
+ && !f->isPrivate()
+ && !f->isVirtual()
+ && !f->isAbstract()
+ && !f->isStatic()
+ && f->name() == func->name()) {
+ m_inheritedOverloads << f;
+ }
+ }
+
+ // TODO: when modified an abstract method ceases to be virtual but stays abstract
+ //if (func->isModifiedRemoved() && func->isAbstract()) {
+ //}
+ }
+}
+
+static void _writeTypeIndexDefineLine(QTextStream& s, const QString& variableName, int typeIndex)
+{
+ s << "#define ";
+ s.setFieldWidth(60);
+ s << variableName;
+ s.setFieldWidth(0);
+ s << ' ' << typeIndex << endl;
+}
+void HeaderGenerator::writeTypeIndexDefineLine(QTextStream& s, const TypeEntry* typeEntry)
+{
+ if (!typeEntry || !typeEntry->generateCode())
+ return;
+ s.setFieldAlignment(QTextStream::AlignLeft);
+ int typeIndex = getTypeIndex(typeEntry);
+ _writeTypeIndexDefineLine(s, getTypeIndexVariableName(typeEntry), typeIndex);
+ if (typeEntry->isComplex()) {
+ const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(typeEntry);
+ if (cType->baseContainerType()) {
+ const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes(), cType);
+ if (metaClass->templateBaseClass())
+ _writeTypeIndexDefineLine(s, getTypeIndexVariableName(metaClass, true), typeIndex);
+ }
+ }
+ if (typeEntry->isEnum()) {
+ const EnumTypeEntry* ete = reinterpret_cast<const EnumTypeEntry*>(typeEntry);
+ if (ete->flags())
+ writeTypeIndexDefineLine(s, ete->flags());
+ }
+}
+
+void HeaderGenerator::writeTypeIndexDefine(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ if (!metaClass->typeEntry()->generateCode())
+ return;
+ writeTypeIndexDefineLine(s, metaClass->typeEntry());
+ foreach (const AbstractMetaEnum* metaEnum, metaClass->enums()) {
+ if (metaEnum->isPrivate())
+ continue;
+ writeTypeIndexDefineLine(s, metaEnum->typeEntry());
+ }
+}
+
+bool HeaderGenerator::finishGeneration()
+{
+ // Generate the main header for this module.
+ // This header should be included by binding modules
+ // extendind on top of this one.
+ QSet<Include> includes;
+ QString macros;
+ QTextStream macrosStream(&macros);
+ QString sbkTypeFunctions;
+ QTextStream typeFunctions(&sbkTypeFunctions);
+ QString protectedEnumSurrogates;
+ QTextStream protEnumsSurrogates(&protectedEnumSurrogates);
+
+ Indentation indent(INDENT);
+
+ macrosStream << "// Type indices" << endl;
+ AbstractMetaEnumList globalEnums = this->globalEnums();
+ foreach (const AbstractMetaClass* metaClass, classes()) {
+ writeTypeIndexDefine(macrosStream, metaClass);
+ lookForEnumsInClassesNotToBeGenerated(globalEnums, metaClass);
+ }
+
+ foreach (const AbstractMetaEnum* metaEnum, globalEnums)
+ writeTypeIndexDefineLine(macrosStream, metaEnum->typeEntry());
+
+ // Write the smart pointer define indexes.
+ int smartPointerCountIndex = getMaxTypeIndex();
+ int smartPointerCount = 0;
+ foreach (const AbstractMetaType *metaType, instantiatedSmartPointers()) {
+ QString variableName = getTypeIndexVariableName(metaType);
+ macrosStream << "#define ";
+ macrosStream.setFieldWidth(60);
+ macrosStream << variableName;
+ macrosStream.setFieldWidth(0);
+ macrosStream << ' ' << smartPointerCountIndex << " // " << metaType->cppSignature()
+ << endl;
+ ++smartPointerCountIndex;
+ ++smartPointerCount;
+ }
+
+
+ macrosStream << "#define ";
+ macrosStream.setFieldWidth(60);
+ macrosStream << QLatin1String("SBK_") + moduleName() + QLatin1String("_IDX_COUNT");
+ macrosStream.setFieldWidth(0);
+ macrosStream << ' ' << getMaxTypeIndex() + smartPointerCount << endl << endl;
+ macrosStream << "// This variable stores all Python types exported by this module." << endl;
+ macrosStream << "extern PyTypeObject** " << cppApiVariableName() << ';' << endl << endl;
+ macrosStream << "// This variable stores all type converters exported by this module." << endl;
+ macrosStream << "extern SbkConverter** " << convertersVariableName() << ';' << endl << endl;
+
+ // TODO-CONVERTER ------------------------------------------------------------------------------
+ // Using a counter would not do, a fix must be made to APIExtractor's getTypeIndex().
+ macrosStream << "// Converter indices" << endl;
+ QList<const PrimitiveTypeEntry*> primitives = primitiveTypes();
+ int pCount = 0;
+ foreach (const PrimitiveTypeEntry* ptype, primitives) {
+ /* Note: do not generate indices for typedef'd primitive types
+ * as they'll use the primitive type converters instead, so we
+ * don't need to create any other.
+ */
+ if (!ptype->generateCode() || !ptype->customConversion())
+ continue;
+
+ _writeTypeIndexDefineLine(macrosStream, getTypeIndexVariableName(ptype), pCount++);
+ }
+
+ foreach (const AbstractMetaType* container, instantiatedContainers()) {
+ //_writeTypeIndexDefineLine(macrosStream, getTypeIndexVariableName(container), pCount);
+ // DEBUG
+ QString variableName = getTypeIndexVariableName(container);
+ macrosStream << "#define ";
+ macrosStream.setFieldWidth(60);
+ macrosStream << variableName;
+ macrosStream.setFieldWidth(0);
+ macrosStream << ' ' << pCount << " // " << container->cppSignature() << endl;
+ // DEBUG
+ pCount++;
+ }
+
+ // Because on win32 the compiler will not accept a zero length array.
+ if (pCount == 0)
+ pCount++;
+ _writeTypeIndexDefineLine(macrosStream, QStringLiteral("SBK_%1_CONVERTERS_IDX_COUNT").arg(moduleName()), pCount);
+ macrosStream << endl;
+ // TODO-CONVERTER ------------------------------------------------------------------------------
+
+ macrosStream << "// Macros for type check" << endl;
+ foreach (const AbstractMetaEnum* cppEnum, globalEnums) {
+ if (cppEnum->isAnonymous() || cppEnum->isPrivate())
+ continue;
+ includes << cppEnum->typeEntry()->include();
+ writeProtectedEnumSurrogate(protEnumsSurrogates, cppEnum);
+ writeSbkTypeFunction(typeFunctions, cppEnum);
+ }
+
+ foreach (AbstractMetaClass* metaClass, classes()) {
+ if (!shouldGenerate(metaClass))
+ continue;
+
+ //Includes
+ const TypeEntry* classType = metaClass->typeEntry();
+ includes << classType->include();
+
+ foreach (const AbstractMetaEnum* cppEnum, metaClass->enums()) {
+ if (cppEnum->isAnonymous() || cppEnum->isPrivate())
+ continue;
+ EnumTypeEntry* enumType = cppEnum->typeEntry();
+ includes << enumType->include();
+ writeProtectedEnumSurrogate(protEnumsSurrogates, cppEnum);
+ writeSbkTypeFunction(typeFunctions, cppEnum);
+ }
+
+ if (!metaClass->isNamespace())
+ writeSbkTypeFunction(typeFunctions, metaClass);
+ }
+
+ foreach (const AbstractMetaType *metaType, instantiatedSmartPointers()) {
+ const TypeEntry *classType = metaType->typeEntry();
+ includes << classType->include();
+ writeSbkTypeFunction(typeFunctions, metaType);
+ }
+
+ QString moduleHeaderFileName(outputDirectory()
+ + QDir::separator() + subDirectoryForPackage(packageName())
+ + QDir::separator() + getModuleHeaderFileName());
+
+ QString includeShield(QLatin1String("SBK_") + moduleName().toUpper() + QLatin1String("_PYTHON_H"));
+
+ FileOut file(moduleHeaderFileName);
+ QTextStream& s = file.stream;
+ // write license comment
+ s << licenseComment() << endl << endl;
+
+ s << "#ifndef " << includeShield << endl;
+ s << "#define " << includeShield << endl<< endl;
+ if (!avoidProtectedHack()) {
+ s << "//workaround to access protected functions" << endl;
+ s << "#define protected public" << endl << endl;
+ }
+
+ s << "#include <sbkpython.h>" << endl;
+ s << "#include <conversions.h>" << endl;
+ s << "#include <sbkenum.h>" << endl;
+ s << "#include <basewrapper.h>" << endl;
+ s << "#include <bindingmanager.h>" << endl;
+ s << "#include <memory>" << endl << endl;
+ if (usePySideExtensions())
+ s << "#include <pysidesignal.h>" << endl;
+
+ QStringList requiredTargetImports = TypeDatabase::instance()->requiredTargetImports();
+ if (!requiredTargetImports.isEmpty()) {
+ s << "// Module Includes" << endl;
+ foreach (const QString& requiredModule, requiredTargetImports)
+ s << "#include <" << getModuleHeaderFileName(requiredModule) << ">" << endl;
+ s << endl;
+ }
+
+ s << "// Binded library includes" << endl;
+ foreach (const Include& include, includes)
+ s << include;
+
+ if (!primitiveTypes().isEmpty()) {
+ s << "// Conversion Includes - Primitive Types" << endl;
+ foreach (const PrimitiveTypeEntry* ptype, primitiveTypes())
+ s << ptype->include();
+ s << endl;
+ }
+
+ if (!containerTypes().isEmpty()) {
+ s << "// Conversion Includes - Container Types" << endl;
+ foreach (const ContainerTypeEntry* ctype, containerTypes())
+ s << ctype->include();
+ s << endl;
+ }
+
+ s << macros << endl;
+
+ if (!protectedEnumSurrogates.isEmpty()) {
+ s << "// Protected enum surrogates" << endl;
+ s << protectedEnumSurrogates << endl;
+ }
+
+ s << "namespace Shiboken" << endl << '{' << endl << endl;
+
+ s << "// PyType functions, to get the PyObjectType for a type T\n";
+ s << sbkTypeFunctions << endl;
+
+ s << "} // namespace Shiboken" << endl << endl;
+
+ s << "#endif // " << includeShield << endl << endl;
+
+ return file.done() != FileOut::Failure;
+}
+
+void HeaderGenerator::writeProtectedEnumSurrogate(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ if (avoidProtectedHack() && cppEnum->isProtected())
+ s << "enum " << protectedEnumSurrogateName(cppEnum) << " {};" << endl;
+}
+
+void HeaderGenerator::writeSbkTypeFunction(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ QString enumName;
+ if (avoidProtectedHack() && cppEnum->isProtected()) {
+ enumName = protectedEnumSurrogateName(cppEnum);
+ } else {
+ enumName = cppEnum->name();
+ if (cppEnum->enclosingClass())
+ enumName = cppEnum->enclosingClass()->qualifiedCppName() + QLatin1String("::") + enumName;
+ }
+
+ s << "template<> inline PyTypeObject* SbkType< ::" << enumName << " >() ";
+ s << "{ return " << cpythonTypeNameExt(cppEnum->typeEntry()) << "; }\n";
+
+ FlagsTypeEntry* flag = cppEnum->typeEntry()->flags();
+ if (flag) {
+ s << "template<> inline PyTypeObject* SbkType< ::" << flag->name() << " >() "
+ << "{ return " << cpythonTypeNameExt(flag) << "; }\n";
+ }
+}
+
+void HeaderGenerator::writeSbkTypeFunction(QTextStream& s, const AbstractMetaClass* cppClass)
+{
+ s << "template<> inline PyTypeObject* SbkType< ::" << cppClass->qualifiedCppName() << " >() "
+ << "{ return reinterpret_cast<PyTypeObject*>(" << cpythonTypeNameExt(cppClass->typeEntry()) << "); }\n";
+}
+
+void HeaderGenerator::writeSbkTypeFunction(QTextStream &s, const AbstractMetaType *metaType)
+{
+ s << "template<> inline PyTypeObject* SbkType< ::" << metaType->cppSignature() << " >() "
+ << "{ return reinterpret_cast<PyTypeObject*>(" << cpythonTypeNameExt(metaType) << "); }\n";
+}
+
+void HeaderGenerator::writeInheritedOverloads(QTextStream& s)
+{
+ foreach (const AbstractMetaFunction* func, m_inheritedOverloads) {
+ s << INDENT << "inline ";
+ s << functionSignature(func, QString(), QString(), Generator::EnumAsInts|Generator::OriginalTypeDescription) << " { ";
+ s << (func->type() ? "return " : "");
+ s << func->ownerClass()->qualifiedCppName() << "::" << func->originalName() << '(';
+ QStringList args;
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ QString argName = arg->name();
+ const TypeEntry* enumTypeEntry = 0;
+ if (arg->type()->isFlags())
+ enumTypeEntry = reinterpret_cast<const FlagsTypeEntry*>(arg->type()->typeEntry())->originator();
+ else if (arg->type()->isEnum())
+ enumTypeEntry = arg->type()->typeEntry();
+ if (enumTypeEntry)
+ argName = arg->type()->cppSignature() + QLatin1Char('(') + argName + QLatin1Char(')');
+ args << argName;
+ }
+ s << args.join(QLatin1String(", ")) << ')';
+ s << "; }" << endl;
+ }
+}
diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.h b/sources/shiboken2/generator/shiboken2/headergenerator.h
new file mode 100644
index 000000000..72dcbf69f
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/headergenerator.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef HEADERGENERATOR_H
+#define HEADERGENERATOR_H
+
+#include "shibokengenerator.h"
+
+#include <QtCore/QSet>
+
+class AbstractMetaFunction;
+
+/**
+ * The HeaderGenerator generate the declarations of C++ bindings classes.
+ */
+class HeaderGenerator : public ShibokenGenerator
+{
+public:
+ QMap<QString, QString> options() const { return QMap<QString, QString>(); }
+protected:
+ QString fileNamePrefix() const;
+ QString fileNameForContext(GeneratorContext &context) const;
+ void generateClass(QTextStream& s, GeneratorContext &classContext);
+ bool finishGeneration();
+
+private:
+ void writeCopyCtor(QTextStream &s, const AbstractMetaClass* metaClass) const;
+ void writeProtectedFieldAccessors(QTextStream& s, const AbstractMetaField* field) const;
+ void writeFunction(QTextStream& s, const AbstractMetaFunction* func);
+ void writeSbkTypeFunction(QTextStream& s, const AbstractMetaEnum* cppEnum);
+ void writeSbkTypeFunction(QTextStream& s, const AbstractMetaClass* cppClass);
+ void writeSbkTypeFunction(QTextStream &s, const AbstractMetaType *metaType);
+ void writeTypeIndexDefineLine(QTextStream& s, const TypeEntry* typeEntry);
+ void writeTypeIndexDefine(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeProtectedEnumSurrogate(QTextStream& s, const AbstractMetaEnum* cppEnum);
+ void writeInheritedOverloads(QTextStream& s);
+
+ QSet<const AbstractMetaFunction*> m_inheritedOverloads;
+};
+
+#endif // HEADERGENERATOR_H
+
diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.cpp b/sources/shiboken2/generator/shiboken2/overloaddata.cpp
new file mode 100644
index 000000000..8731fe911
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/overloaddata.cpp
@@ -0,0 +1,1079 @@
+/****************************************************************************
+**
+** 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 <abstractmetalang.h>
+#include <reporthandler.h>
+#include <graph.h>
+#include "overloaddata.h"
+#include "shibokengenerator.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QTemporaryFile>
+
+static const TypeEntry *getReferencedTypeEntry(const TypeEntry *typeEntry)
+{
+ if (typeEntry->isPrimitive()) {
+ const PrimitiveTypeEntry* pte = dynamic_cast<const PrimitiveTypeEntry*>(typeEntry);
+ while (pte->referencedTypeEntry())
+ pte = pte->referencedTypeEntry();
+ typeEntry = pte;
+ }
+ return typeEntry;
+}
+
+static QString getTypeName(const AbstractMetaType* type)
+{
+ const TypeEntry* typeEntry = getReferencedTypeEntry(type->typeEntry());
+ QString typeName = typeEntry->name();
+ if (typeEntry->isContainer()) {
+ QStringList types;
+ foreach (const AbstractMetaType* cType, type->instantiations()) {
+ const TypeEntry *typeEntry = getReferencedTypeEntry(cType->typeEntry());
+ types << typeEntry->name();
+ }
+ typeName += QLatin1Char('<') + types.join(QLatin1Char(',')) + QLatin1String(" >");
+ }
+ return typeName;
+}
+
+static QString getTypeName(const OverloadData* ov)
+{
+ return ov->hasArgumentTypeReplace() ? ov->argumentTypeReplaced() : getTypeName(ov->argType());
+}
+
+static bool typesAreEqual(const AbstractMetaType* typeA, const AbstractMetaType* typeB)
+{
+ if (typeA->typeEntry() == typeB->typeEntry()) {
+ if (typeA->isContainer() || typeA->isSmartPointer()) {
+ if (typeA->instantiations().size() != typeB->instantiations().size())
+ return false;
+
+ for (int i = 0; i < typeA->instantiations().size(); ++i) {
+ if (!typesAreEqual(typeA->instantiations().at(i), typeB->instantiations().at(i)))
+ return false;
+ }
+ return true;
+ }
+
+ return !(ShibokenGenerator::isCString(typeA) ^ ShibokenGenerator::isCString(typeB));
+ }
+ return false;
+}
+
+
+/**
+ * OverloadSortData just helps writing clearer code in the
+ * OverloadData::sortNextOverloads method.
+ */
+struct OverloadSortData
+{
+ OverloadSortData() : counter(0) {};
+
+ /**
+ * Adds a typeName into the type map without associating it with
+ * a OverloadData. This is done to express type dependencies that could
+ * or could not appear in overloaded signatures not processed yet.
+ */
+ void mapType(const QString& typeName)
+ {
+ if (map.contains(typeName))
+ return;
+ map[typeName] = counter;
+ if (!reverseMap.contains(counter))
+ reverseMap[counter] = 0;
+ counter++;
+ }
+
+ void mapType(OverloadData* overloadData)
+ {
+ QString typeName = getTypeName(overloadData);
+ map[typeName] = counter;
+ reverseMap[counter] = overloadData;
+ counter++;
+ }
+
+ int lastProcessedItemId() { return counter - 1; }
+
+ int counter;
+ QHash<QString, int> map; // typeName -> id
+ QHash<int, OverloadData*> reverseMap; // id -> OverloadData;
+};
+
+/**
+ * Helper function that returns the name of a container get from containerType argument and
+ * an instantiation taken either from an implicit conversion expressed by the function argument,
+ * or from the string argument implicitConvTypeName.
+ */
+static QString getImplicitConversionTypeName(const AbstractMetaType* containerType,
+ const AbstractMetaType* instantiation,
+ const AbstractMetaFunction* function,
+ const QString& implicitConvTypeName = QString())
+{
+ QString impConv;
+ if (!implicitConvTypeName.isEmpty())
+ impConv = implicitConvTypeName;
+ else if (function->isConversionOperator())
+ impConv = function->ownerClass()->typeEntry()->name();
+ else
+ impConv = getTypeName(function->arguments().first()->type());
+
+ QStringList types;
+ foreach (const AbstractMetaType* otherType, containerType->instantiations())
+ types << (otherType == instantiation ? impConv : getTypeName(otherType));
+
+ const ContainerTypeEntry* containerTypeEntry = dynamic_cast<const ContainerTypeEntry*>(containerType->typeEntry());
+ return containerTypeEntry->qualifiedCppName() + QLatin1Char('<')
+ + types.join(QLatin1String(", ")) + QLatin1String(" >");
+}
+
+static QString msgCyclicDependency(const QString &funcName, const QString &graphName,
+ const QList<const AbstractMetaFunction *> &involvedConversions)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Cyclic dependency found on overloaddata for \"" << funcName
+ << "\" method! The graph boy saved the graph at \"" << QDir::toNativeSeparators(graphName)
+ << "\".";
+ if (const int count = involvedConversions.size()) {
+ str << " Implicit conversions (" << count << "): ";
+ for (int i = 0; i < count; ++i) {
+ if (i)
+ str << ", \"";
+ str << involvedConversions.at(i)->signature() << '"';
+ if (const AbstractMetaClass *c = involvedConversions.at(i)->implementingClass())
+ str << '(' << c->name() << ')';
+ }
+ }
+ return result;
+}
+
+/**
+ * Topologically sort the overloads by implicit convertion order
+ *
+ * This avoids using an implicit conversion if there's an explicit
+ * overload for the convertible type. So, if there's an implicit convert
+ * like TargetType(ConvertibleType foo) and both are in the overload list,
+ * ConvertibleType is checked before TargetType.
+ *
+ * Side effects: Modifies m_nextOverloadData
+ */
+void OverloadData::sortNextOverloads()
+{
+ OverloadSortData sortData;
+ bool checkPyObject = false;
+ int pyobjectIndex = 0;
+ bool checkPySequence = false;
+ int pySeqIndex = 0;
+ bool checkQString = false;
+ int qstringIndex = 0;
+ bool checkQVariant = false;
+ int qvariantIndex = 0;
+ bool checkPyBuffer = false;
+ int pyBufferIndex = 0;
+
+ // Primitive types that are not int, long, short,
+ // char and their respective unsigned counterparts.
+ QStringList nonIntegerPrimitives;
+ nonIntegerPrimitives << QLatin1String("float") << QLatin1String("double")
+ << QLatin1String("bool");
+
+ // Signed integer primitive types.
+ QStringList signedIntegerPrimitives;
+ signedIntegerPrimitives << QLatin1String("int") << QLatin1String("short")
+ << QLatin1String("long");
+
+ // sort the children overloads
+ foreach(OverloadData *ov, m_nextOverloadData)
+ ov->sortNextOverloads();
+
+ if (m_nextOverloadData.size() <= 1)
+ return;
+
+ // Populates the OverloadSortData object containing map and reverseMap, to map type names to ids,
+ // these ids will be used by the topological sort algorithm, because is easier and faster to work
+ // with graph sorting using integers.
+ foreach(OverloadData* ov, m_nextOverloadData) {
+ sortData.mapType(ov);
+
+ const QString typeName(getTypeName(ov));
+
+ if (!checkPyObject && typeName.contains(QLatin1String("PyObject"))) {
+ checkPyObject = true;
+ pyobjectIndex = sortData.lastProcessedItemId();
+ } else if (!checkPySequence && typeName == QLatin1String("PySequence")) {
+ checkPySequence = true;
+ pySeqIndex = sortData.lastProcessedItemId();
+ } else if (!checkPyBuffer && typeName == QLatin1String("PyBuffer")) {
+ checkPyBuffer = true;
+ pyBufferIndex = sortData.lastProcessedItemId();
+ } else if (!checkQVariant && typeName == QLatin1String("QVariant")) {
+ checkQVariant = true;
+ qvariantIndex = sortData.lastProcessedItemId();
+ } else if (!checkQString && typeName == QLatin1String("QString")) {
+ checkQString = true;
+ qstringIndex = sortData.lastProcessedItemId();
+ }
+
+ foreach (const AbstractMetaType* instantiation, ov->argType()->instantiations()) {
+ // Add dependencies for type instantiation of container.
+ QString typeName = getTypeName(instantiation);
+ sortData.mapType(typeName);
+
+ // Build dependency for implicit conversion types instantiations for base container.
+ // For example, considering signatures "method(list<PointF>)" and "method(list<Point>)",
+ // and being PointF implicitly convertible from Point, an list<T> instantiation with T
+ // as Point must come before the PointF instantiation, or else list<Point> will never
+ // be called. In the case of primitive types, list<double> must come before list<int>.
+ if (instantiation->isPrimitive() && (signedIntegerPrimitives.contains(instantiation->name()))) {
+ foreach (const QString& primitive, nonIntegerPrimitives)
+ sortData.mapType(getImplicitConversionTypeName(ov->argType(), instantiation, 0, primitive));
+ } else {
+ foreach (const AbstractMetaFunction* function, m_generator->implicitConversions(instantiation))
+ sortData.mapType(getImplicitConversionTypeName(ov->argType(), instantiation, function));
+ }
+ }
+ }
+
+
+ // Create the graph of type dependencies based on implicit conversions.
+ Graph graph(sortData.reverseMap.count());
+ // All C++ primitive types, add any forgotten type AT THE END OF THIS LIST!
+ const char* primitiveTypes[] = {"int",
+ "unsigned int",
+ "long",
+ "unsigned long",
+ "short",
+ "unsigned short",
+ "bool",
+ "unsigned char",
+ "char",
+ "float",
+ "double",
+ "const char*"
+ };
+ const int numPrimitives = sizeof(primitiveTypes)/sizeof(const char*);
+ bool hasPrimitive[numPrimitives];
+ for (int i = 0; i < numPrimitives; ++i)
+ hasPrimitive[i] = sortData.map.contains(QLatin1String(primitiveTypes[i]));
+
+ if (checkPySequence && checkPyObject)
+ graph.addEdge(pySeqIndex, pyobjectIndex);
+
+ QStringList classesWithIntegerImplicitConversion;
+
+ QList<const AbstractMetaFunction *> involvedConversions;
+
+ foreach(OverloadData* ov, m_nextOverloadData) {
+ const AbstractMetaType* targetType = ov->argType();
+ const QString targetTypeEntryName(getTypeName(ov));
+ int targetTypeId = sortData.map[targetTypeEntryName];
+
+ // Process implicit conversions
+ foreach(AbstractMetaFunction* function, m_generator->implicitConversions(targetType)) {
+ QString convertibleType;
+ if (function->isConversionOperator())
+ convertibleType = function->ownerClass()->typeEntry()->name();
+ else
+ convertibleType = getTypeName(function->arguments().first()->type());
+
+ if (convertibleType == QLatin1String("int") || convertibleType == QLatin1String("unsigned int"))
+ classesWithIntegerImplicitConversion << targetTypeEntryName;
+
+ if (!sortData.map.contains(convertibleType))
+ continue;
+
+ int convertibleTypeId = sortData.map[convertibleType];
+
+ // If a reverse pair already exists, remove it. Probably due to the
+ // container check (This happened to QVariant and QHash)
+ graph.removeEdge(targetTypeId, convertibleTypeId);
+ graph.addEdge(convertibleTypeId, targetTypeId);
+ involvedConversions.append(function);
+ }
+
+ // Process inheritance relationships
+ if (targetType->isValue() || targetType->isObject()) {
+ const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_generator->classes(), targetType->typeEntry());
+ foreach (const AbstractMetaClass* ancestor, m_generator->getAllAncestors(metaClass)) {
+ QString ancestorTypeName = ancestor->typeEntry()->name();
+ if (!sortData.map.contains(ancestorTypeName))
+ continue;
+ int ancestorTypeId = sortData.map[ancestorTypeName];
+ graph.removeEdge(ancestorTypeId, targetTypeId);
+ graph.addEdge(targetTypeId, ancestorTypeId);
+ }
+ }
+
+ // Process template instantiations
+ foreach (const AbstractMetaType* instantiation, targetType->instantiations()) {
+ if (sortData.map.contains(getTypeName(instantiation))) {
+ int convertible = sortData.map[getTypeName(instantiation)];
+
+ if (!graph.containsEdge(targetTypeId, convertible)) // Avoid cyclic dependency.
+ graph.addEdge(convertible, targetTypeId);
+
+ if (instantiation->isPrimitive() && (signedIntegerPrimitives.contains(instantiation->name()))) {
+ foreach (const QString& primitive, nonIntegerPrimitives) {
+ QString convertibleTypeName = getImplicitConversionTypeName(ov->argType(), instantiation, 0, primitive);
+ if (!graph.containsEdge(targetTypeId, sortData.map[convertibleTypeName])) // Avoid cyclic dependency.
+ graph.addEdge(sortData.map[convertibleTypeName], targetTypeId);
+ }
+
+ } else {
+ foreach (const AbstractMetaFunction* function, m_generator->implicitConversions(instantiation)) {
+ QString convertibleTypeName = getImplicitConversionTypeName(ov->argType(), instantiation, function);
+ if (!graph.containsEdge(targetTypeId, sortData.map[convertibleTypeName])) { // Avoid cyclic dependency.
+ graph.addEdge(sortData.map[convertibleTypeName], targetTypeId);
+ involvedConversions.append(function);
+ }
+ }
+ }
+ }
+ }
+
+
+ if ((checkPySequence || checkPyObject || checkPyBuffer)
+ && !targetTypeEntryName.contains(QLatin1String("PyObject"))
+ && !targetTypeEntryName.contains(QLatin1String("PyBuffer"))
+ && !targetTypeEntryName.contains(QLatin1String("PySequence"))) {
+ if (checkPySequence) {
+ // PySequence will be checked after all more specific types, but before PyObject.
+ graph.addEdge(targetTypeId, pySeqIndex);
+ } else if (checkPyBuffer) {
+ // PySequence will be checked after all more specific types, but before PyObject.
+ graph.addEdge(targetTypeId, pyBufferIndex);
+ } else {
+ // Add dependency on PyObject, so its check is the last one (too generic).
+ graph.addEdge(targetTypeId, pyobjectIndex);
+ }
+ } else if (checkQVariant && targetTypeEntryName != QLatin1String("QVariant")) {
+ if (!graph.containsEdge(qvariantIndex, targetTypeId)) // Avoid cyclic dependency.
+ graph.addEdge(targetTypeId, qvariantIndex);
+ } else if (checkQString && ShibokenGenerator::isPointer(ov->argType())
+ && targetTypeEntryName != QLatin1String("QString")
+ && targetTypeEntryName != QLatin1String("QByteArray")
+ && (!checkPyObject || targetTypeId != pyobjectIndex)) {
+ if (!graph.containsEdge(qstringIndex, targetTypeId)) // Avoid cyclic dependency.
+ graph.addEdge(targetTypeId, qstringIndex);
+ }
+
+ if (targetType->isEnum()) {
+ // Enum values must precede primitive types.
+ for (int i = 0; i < numPrimitives; ++i) {
+ if (hasPrimitive[i])
+ graph.addEdge(targetTypeId, sortData.map[QLatin1String(primitiveTypes[i])]);
+ }
+ }
+ }
+
+ // QByteArray args need to be checked after QString args
+ if (sortData.map.contains(QLatin1String("QString")) && sortData.map.contains(QLatin1String("QByteArray")))
+ graph.addEdge(sortData.map[QLatin1String("QString")], sortData.map[QLatin1String("QByteArray")]);
+
+ foreach(OverloadData* ov, m_nextOverloadData) {
+ const AbstractMetaType* targetType = ov->argType();
+ if (!targetType->isEnum())
+ continue;
+
+ QString targetTypeEntryName = getTypeName(targetType);
+ // Enum values must precede types implicitly convertible from "int" or "unsigned int".
+ foreach (const QString& implicitFromInt, classesWithIntegerImplicitConversion)
+ graph.addEdge(sortData.map[targetTypeEntryName], sortData.map[implicitFromInt]);
+ }
+
+
+ // Special case for double(int i) (not tracked by m_generator->implicitConversions
+ foreach (const QString& signedIntegerName, signedIntegerPrimitives) {
+ if (sortData.map.contains(signedIntegerName)) {
+ foreach (const QString& nonIntegerName, nonIntegerPrimitives) {
+ if (sortData.map.contains(nonIntegerName))
+ graph.addEdge(sortData.map[nonIntegerName], sortData.map[signedIntegerName]);
+ }
+ }
+ }
+
+ // sort the overloads topologically based on the dependency graph.
+ QLinkedList<int> unmappedResult = graph.topologicalSort();
+ if (unmappedResult.isEmpty()) {
+ QString funcName = referenceFunction()->name();
+ if (referenceFunction()->ownerClass())
+ funcName.prepend(referenceFunction()->ownerClass()->name() + QLatin1Char('.'));
+
+ // Dump overload graph
+ QString graphName = QDir::tempPath() + QLatin1Char('/') + funcName + QLatin1String(".dot");
+ QHash<QString, int>::const_iterator it = sortData.map.begin();
+ QHash<int, QString> nodeNames;
+ for (; it != sortData.map.end(); ++it)
+ nodeNames.insert(it.value(), it.key());
+ graph.dumpDot(nodeNames, graphName);
+ qCWarning(lcShiboken).noquote() << qPrintable(msgCyclicDependency(funcName, graphName, involvedConversions));
+ }
+
+ m_nextOverloadData.clear();
+ foreach(int i, unmappedResult) {
+ if (!sortData.reverseMap[i])
+ continue;
+ m_nextOverloadData << sortData.reverseMap[i];
+ }
+}
+
+/**
+ * Root constructor for OverloadData
+ *
+ * This constructor receives the list of overloads for a given function and iterates generating
+ * the graph of OverloadData instances. Each OverloadData instance references an argument/type
+ * combination.
+ *
+ * Example:
+ * addStuff(double, PyObject *)
+ * addStuff(double, int)
+ *
+ * Given these two overloads, there will be the following graph:
+ *
+ * addStuff - double - PyObject*
+ * \- int
+ *
+ */
+OverloadData::OverloadData(const AbstractMetaFunctionList& overloads, const ShibokenGenerator* generator)
+ : m_minArgs(256), m_maxArgs(0), m_argPos(-1), m_argType(0),
+ m_headOverloadData(this), m_previousOverloadData(0), m_generator(generator)
+{
+ foreach (const AbstractMetaFunction* func, overloads) {
+ m_overloads.append(func);
+ int argSize = func->arguments().size() - numberOfRemovedArguments(func);
+ if (m_minArgs > argSize)
+ m_minArgs = argSize;
+ else if (m_maxArgs < argSize)
+ m_maxArgs = argSize;
+ OverloadData* currentOverloadData = this;
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+ currentOverloadData = currentOverloadData->addOverloadData(func, arg);
+ }
+ }
+
+ // Sort the overload possibilities so that the overload decisor code goes for the most
+ // important cases first, based on the topological order of the implicit conversions
+ sortNextOverloads();
+
+ // Fix minArgs
+ if (minArgs() > maxArgs())
+ m_headOverloadData->m_minArgs = maxArgs();
+}
+
+OverloadData::OverloadData(OverloadData* headOverloadData, const AbstractMetaFunction* func,
+ const AbstractMetaType* argType, int argPos)
+ : m_minArgs(256), m_maxArgs(0), m_argPos(argPos), m_argType(argType),
+ m_headOverloadData(headOverloadData), m_previousOverloadData(0)
+{
+ if (func)
+ this->addOverload(func);
+}
+
+void OverloadData::addOverload(const AbstractMetaFunction* func)
+{
+ int origNumArgs = func->arguments().size();
+ int removed = numberOfRemovedArguments(func);
+ int numArgs = origNumArgs - removed;
+
+ if (numArgs > m_headOverloadData->m_maxArgs)
+ m_headOverloadData->m_maxArgs = numArgs;
+
+ if (numArgs < m_headOverloadData->m_minArgs)
+ m_headOverloadData->m_minArgs = numArgs;
+
+ for (int i = 0; m_headOverloadData->m_minArgs > 0 && i < origNumArgs; i++) {
+ if (func->argumentRemoved(i + 1))
+ continue;
+ if (!ShibokenGenerator::getDefaultValue(func, func->arguments()[i]).isEmpty()) {
+ int fixedArgIndex = i - removed;
+ if (fixedArgIndex < m_headOverloadData->m_minArgs)
+ m_headOverloadData->m_minArgs = fixedArgIndex;
+ }
+ }
+
+ m_overloads.append(func);
+}
+
+OverloadData* OverloadData::addOverloadData(const AbstractMetaFunction* func,
+ const AbstractMetaArgument* arg)
+{
+ const AbstractMetaType* argType = arg->type();
+ OverloadData* overloadData = 0;
+ if (!func->isOperatorOverload()) {
+ foreach (OverloadData* tmp, m_nextOverloadData) {
+ // TODO: 'const char *', 'char *' and 'char' will have the same TypeEntry?
+
+ // If an argument have a type replacement, then we should create a new overloaddata
+ // for it, unless the next argument also have a identical type replacement.
+ QString replacedArg = func->typeReplaced(tmp->m_argPos + 1);
+ bool argsReplaced = !replacedArg.isEmpty() || !tmp->m_argTypeReplaced.isEmpty();
+ if ((!argsReplaced && typesAreEqual(tmp->m_argType, argType))
+ || (argsReplaced && replacedArg == tmp->argumentTypeReplaced())) {
+ tmp->addOverload(func);
+ overloadData = tmp;
+ }
+ }
+ }
+
+ if (!overloadData) {
+ overloadData = new OverloadData(m_headOverloadData, func, argType, m_argPos + 1);
+ overloadData->m_previousOverloadData = this;
+ overloadData->m_generator = this->m_generator;
+ QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1);
+
+ if (!typeReplaced.isEmpty())
+ overloadData->m_argTypeReplaced = typeReplaced;
+ m_nextOverloadData.append(overloadData);
+ }
+
+ return overloadData;
+}
+
+QStringList OverloadData::returnTypes() const
+{
+ QSet<QString> retTypes;
+ foreach (const AbstractMetaFunction* func, m_overloads) {
+ if (!func->typeReplaced(0).isEmpty())
+ retTypes << func->typeReplaced(0);
+ else if (func->type() && !func->argumentRemoved(0))
+ retTypes << func->type()->cppSignature();
+ else
+ retTypes << QLatin1String("void");
+ }
+ return QStringList(retTypes.toList());
+}
+
+bool OverloadData::hasNonVoidReturnType() const
+{
+ QStringList retTypes = returnTypes();
+ return !retTypes.contains(QLatin1String("void")) || retTypes.size() > 1;
+}
+
+bool OverloadData::hasVarargs() const
+{
+ foreach (const AbstractMetaFunction* func, m_overloads) {
+ AbstractMetaArgumentList args = func->arguments();
+ if (args.size() > 1 && args.last()->type()->isVarargs())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasAllowThread() const
+{
+ foreach (const AbstractMetaFunction* func, m_overloads) {
+ if (func->allowThread())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasStaticFunction(const AbstractMetaFunctionList& overloads)
+{
+ foreach (const AbstractMetaFunction* func, overloads) {
+ if (func->isStatic())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasStaticFunction() const
+{
+ foreach (const AbstractMetaFunction* func, m_overloads) {
+ if (func->isStatic())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasInstanceFunction(const AbstractMetaFunctionList& overloads)
+{
+ foreach (const AbstractMetaFunction* func, overloads) {
+ if (!func->isStatic())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasInstanceFunction() const
+{
+ foreach (const AbstractMetaFunction* func, m_overloads) {
+ if (!func->isStatic())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasStaticAndInstanceFunctions(const AbstractMetaFunctionList& overloads)
+{
+ return OverloadData::hasStaticFunction(overloads) && OverloadData::hasInstanceFunction(overloads);
+}
+
+bool OverloadData::hasStaticAndInstanceFunctions() const
+{
+ return OverloadData::hasStaticFunction() && OverloadData::hasInstanceFunction();
+}
+
+const AbstractMetaFunction* OverloadData::referenceFunction() const
+{
+ return m_overloads.first();
+}
+
+const AbstractMetaArgument* OverloadData::argument(const AbstractMetaFunction* func) const
+{
+ if (isHeadOverloadData() || !m_overloads.contains(func))
+ return 0;
+
+ int argPos = 0;
+ int removed = 0;
+ for (int i = 0; argPos <= m_argPos; i++) {
+ if (func->argumentRemoved(i + 1))
+ removed++;
+ else
+ argPos++;
+ }
+
+ return func->arguments()[m_argPos + removed];
+}
+
+OverloadDataList OverloadData::overloadDataOnPosition(OverloadData* overloadData, int argPos) const
+{
+ OverloadDataList overloadDataList;
+ if (overloadData->argPos() == argPos) {
+ overloadDataList.append(overloadData);
+ } else if (overloadData->argPos() < argPos) {
+ foreach (OverloadData* pd, overloadData->nextOverloadData())
+ overloadDataList += overloadDataOnPosition(pd, argPos);
+ }
+ return overloadDataList;
+}
+
+OverloadDataList OverloadData::overloadDataOnPosition(int argPos) const
+{
+ OverloadDataList overloadDataList;
+ overloadDataList += overloadDataOnPosition(m_headOverloadData, argPos);
+ return overloadDataList;
+}
+
+bool OverloadData::nextArgumentHasDefaultValue() const
+{
+ foreach (OverloadData* overloadData, m_nextOverloadData) {
+ if (overloadData->getFunctionWithDefaultValue())
+ return true;
+ }
+ return false;
+}
+
+static OverloadData* _findNextArgWithDefault(OverloadData* overloadData)
+{
+ if (overloadData->getFunctionWithDefaultValue())
+ return overloadData;
+
+ OverloadData* result = 0;
+ foreach (OverloadData* odata, overloadData->nextOverloadData()) {
+ OverloadData* tmp = _findNextArgWithDefault(odata);
+ if (!result || (tmp && result->argPos() > tmp->argPos()))
+ result = tmp;
+ }
+ return result;
+}
+
+OverloadData* OverloadData::findNextArgWithDefault()
+{
+ return _findNextArgWithDefault(this);
+}
+
+bool OverloadData::isFinalOccurrence(const AbstractMetaFunction* func) const
+{
+ foreach (const OverloadData* pd, m_nextOverloadData) {
+ if (pd->overloads().contains(func))
+ return false;
+ }
+ return true;
+}
+
+QList<const AbstractMetaFunction*> OverloadData::overloadsWithoutRepetition() const
+{
+ QList<const AbstractMetaFunction*> overloads = m_overloads;
+ foreach (const AbstractMetaFunction* func, m_overloads) {
+ if (func->minimalSignature().endsWith(QLatin1String("const")))
+ continue;
+ foreach (const AbstractMetaFunction* f, overloads) {
+ if ((func->minimalSignature() + QLatin1String("const")) == f->minimalSignature()) {
+ overloads.removeOne(f);
+ break;
+ }
+ }
+ }
+ return overloads;
+}
+
+const AbstractMetaFunction* OverloadData::getFunctionWithDefaultValue() const
+{
+ foreach (const AbstractMetaFunction* func, m_overloads) {
+ int removedArgs = 0;
+ for (int i = 0; i <= m_argPos + removedArgs; i++) {
+ if (func->argumentRemoved(i + 1))
+ removedArgs++;
+ }
+ if (!ShibokenGenerator::getDefaultValue(func, func->arguments()[m_argPos + removedArgs]).isEmpty())
+ return func;
+ }
+ return 0;
+}
+
+QList<int> OverloadData::invalidArgumentLengths() const
+{
+ QSet<int> validArgLengths;
+
+ foreach (const AbstractMetaFunction* func, m_headOverloadData->m_overloads) {
+ const AbstractMetaArgumentList args = func->arguments();
+ int offset = 0;
+ for (int i = 0; i < args.size(); ++i) {
+ if (func->argumentRemoved(i+1)) {
+ offset++;
+ } else {
+ if (!ShibokenGenerator::getDefaultValue(func, args[i]).isEmpty())
+ validArgLengths << i-offset;
+ }
+ }
+ validArgLengths << args.size() - offset;
+ }
+
+ QList<int> invalidArgLengths;
+ for (int i = minArgs() + 1; i < maxArgs(); i++) {
+ if (!validArgLengths.contains(i))
+ invalidArgLengths.append(i);
+ }
+
+ return invalidArgLengths;
+}
+
+int OverloadData::numberOfRemovedArguments(const AbstractMetaFunction* func, int finalArgPos)
+{
+ int removed = 0;
+ if (finalArgPos < 0) {
+ for (int i = 0; i < func->arguments().size(); i++) {
+ if (func->argumentRemoved(i + 1))
+ removed++;
+ }
+ } else {
+ for (int i = 0; i < finalArgPos + removed; i++) {
+ if (func->argumentRemoved(i + 1))
+ removed++;
+ }
+ }
+ return removed;
+}
+
+QPair<int, int> OverloadData::getMinMaxArguments(const AbstractMetaFunctionList& overloads)
+{
+ int minArgs = 10000;
+ int maxArgs = 0;
+ for (int i = 0; i < overloads.size(); i++) {
+ const AbstractMetaFunction* func = overloads[i];
+ int origNumArgs = func->arguments().size();
+ int removed = numberOfRemovedArguments(func);
+ int numArgs = origNumArgs - removed;
+ if (maxArgs < numArgs)
+ maxArgs = numArgs;
+ if (minArgs > numArgs)
+ minArgs = numArgs;
+ for (int j = 0; j < origNumArgs; j++) {
+ if (func->argumentRemoved(j + 1))
+ continue;
+ int fixedArgIndex = j - removed;
+ if (fixedArgIndex < minArgs && !ShibokenGenerator::getDefaultValue(func, func->arguments()[j]).isEmpty())
+ minArgs = fixedArgIndex;
+ }
+ }
+ return QPair<int, int>(minArgs, maxArgs);
+}
+
+bool OverloadData::isSingleArgument(const AbstractMetaFunctionList& overloads)
+{
+ bool singleArgument = true;
+ foreach (const AbstractMetaFunction* func, overloads) {
+ if (func->arguments().size() - numberOfRemovedArguments(func) != 1) {
+ singleArgument = false;
+ break;
+ }
+ }
+ return singleArgument;
+}
+
+void OverloadData::dumpGraph(QString filename) const
+{
+ QFile file(filename);
+ if (file.open(QFile::WriteOnly)) {
+ QTextStream s(&file);
+ s << m_headOverloadData->dumpGraph();
+ }
+}
+
+static inline QString toHtml(QString s)
+{
+ s.replace(QLatin1Char('<'), QLatin1String("&lt;"));
+ s.replace(QLatin1Char('>'), QLatin1String("&gt;"));
+ s.replace(QLatin1Char('&'), QLatin1String("&amp;"));
+ return s;
+}
+
+QString OverloadData::dumpGraph() const
+{
+ QString indent(4, QLatin1Char(' '));
+ QString result;
+ QTextStream s(&result);
+ if (m_argPos == -1) {
+ const AbstractMetaFunction* rfunc = referenceFunction();
+ s << "digraph OverloadedFunction {" << endl;
+ s << indent << "graph [fontsize=12 fontname=freemono labelloc=t splines=true overlap=false rankdir=LR];" << endl;
+
+ // Shows all function signatures
+ s << "legend [fontsize=9 fontname=freemono shape=rect label=\"";
+ foreach (const AbstractMetaFunction* func, overloads()) {
+ s << "f" << functionNumber(func) << " : ";
+ if (func->type())
+ s << toHtml(func->type()->cppSignature());
+ else
+ s << "void";
+ s << ' ' << toHtml(func->minimalSignature()) << "\\l";
+ }
+ s << "\"];" << endl;
+
+ // Function box title
+ s << indent << '"' << rfunc->name() << "\" [shape=plaintext style=\"filled,bold\" margin=0 fontname=freemono fillcolor=white penwidth=1 ";
+ s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">";
+ s << "<tr><td bgcolor=\"black\" align=\"center\" cellpadding=\"6\" colspan=\"2\"><font color=\"white\">";
+ if (rfunc->ownerClass())
+ s << rfunc->ownerClass()->name() << "::";
+ s << toHtml(rfunc->name()) << "</font>";
+ if (rfunc->isVirtual()) {
+ s << "<br/><font color=\"white\" point-size=\"10\">&lt;&lt;";
+ if (rfunc->isAbstract())
+ s << "pure ";
+ s << "virtual&gt;&gt;</font>";
+ }
+ s << "</td></tr>";
+
+ // Function return type
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">original type</td><td bgcolor=\"gray\" align=\"left\">";
+ if (rfunc->type())
+ s << toHtml(rfunc->type()->cppSignature());
+ else
+ s << "void";
+ s << "</td></tr>";
+
+ // Shows type changes for all function signatures
+ foreach (const AbstractMetaFunction* func, overloads()) {
+ if (func->typeReplaced(0).isEmpty())
+ continue;
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func);
+ s << "-type</td><td bgcolor=\"gray\" align=\"left\">";
+ s << toHtml(func->typeReplaced(0)) << "</td></tr>";
+ }
+
+ // Minimum and maximum number of arguments
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">minArgs</td><td bgcolor=\"gray\" align=\"left\">";
+ s << minArgs() << "</td></tr>";
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">maxArgs</td><td bgcolor=\"gray\" align=\"left\">";
+ s << maxArgs() << "</td></tr>";
+
+ if (rfunc->ownerClass()) {
+ if (rfunc->implementingClass() != rfunc->ownerClass())
+ s << "<tr><td align=\"right\">implementor</td><td align=\"left\">" << rfunc->implementingClass()->name() << "</td></tr>";
+ if (rfunc->declaringClass() != rfunc->ownerClass() && rfunc->declaringClass() != rfunc->implementingClass())
+ s << "<tr><td align=\"right\">declarator</td><td align=\"left\">" << rfunc->declaringClass()->name() << "</td></tr>";
+ }
+
+ // Overloads for the signature to present point
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">";
+ foreach (const AbstractMetaFunction* func, overloads())
+ s << 'f' << functionNumber(func) << ' ';
+ s << "</td></tr>";
+
+ s << "</table>> ];" << endl;
+
+ foreach (const OverloadData* pd, nextOverloadData())
+ s << indent << '"' << rfunc->name() << "\" -> " << pd->dumpGraph();
+
+ s << "}" << endl;
+ } else {
+ QString argId = QLatin1String("arg_") + QString::number(quintptr(this));
+ s << argId << ';' << endl;
+
+ s << indent << '"' << argId << "\" [shape=\"plaintext\" style=\"filled,bold\" margin=\"0\" fontname=\"freemono\" fillcolor=\"white\" penwidth=1 ";
+ s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">";
+
+ // Argument box title
+ s << "<tr><td bgcolor=\"black\" align=\"left\" cellpadding=\"2\" colspan=\"2\">";
+ s << "<font color=\"white\" point-size=\"11\">arg #" << argPos() << "</font></td></tr>";
+
+ // Argument type information
+ QString type = hasArgumentTypeReplace() ? argumentTypeReplaced() : argType()->cppSignature();
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">type</td><td bgcolor=\"gray\" align=\"left\">";
+ s << toHtml(type) << "</td></tr>";
+ if (hasArgumentTypeReplace()) {
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">orig. type</td><td bgcolor=\"gray\" align=\"left\">";
+ s << toHtml(argType()->cppSignature()) << "</td></tr>";
+ }
+
+ // Overloads for the signature to present point
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">";
+ foreach (const AbstractMetaFunction* func, overloads())
+ s << 'f' << functionNumber(func) << ' ';
+ s << "</td></tr>";
+
+ // Show default values (original and modified) for various functions
+ foreach (const AbstractMetaFunction* func, overloads()) {
+ const AbstractMetaArgument* arg = argument(func);
+ if (!arg)
+ continue;
+ QString argDefault = ShibokenGenerator::getDefaultValue(func, arg);
+ if (!argDefault.isEmpty() ||
+ argDefault != arg->originalDefaultValueExpression()) {
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func);
+ s << "-default</td><td bgcolor=\"gray\" align=\"left\">";
+ s << argDefault << "</td></tr>";
+ }
+ if (argDefault != arg->originalDefaultValueExpression()) {
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func);
+ s << "-orig-default</td><td bgcolor=\"gray\" align=\"left\">";
+ s << arg->originalDefaultValueExpression() << "</td></tr>";
+ }
+ }
+
+ s << "</table>>];" << endl;
+
+ foreach (const OverloadData* pd, nextOverloadData())
+ s << indent << argId << " -> " << pd->dumpGraph();
+ }
+ return result;
+}
+
+int OverloadData::functionNumber(const AbstractMetaFunction* func) const
+{
+ return m_headOverloadData->m_overloads.indexOf(func);
+}
+
+OverloadData::~OverloadData()
+{
+ while (!m_nextOverloadData.isEmpty())
+ delete m_nextOverloadData.takeLast();
+}
+
+bool OverloadData::hasArgumentTypeReplace() const
+{
+ return !m_argTypeReplaced.isEmpty();
+}
+
+QString OverloadData::argumentTypeReplaced() const
+{
+ return m_argTypeReplaced;
+}
+
+bool OverloadData::hasArgumentWithDefaultValue(const AbstractMetaFunctionList& overloads)
+{
+ if (OverloadData::getMinMaxArguments(overloads).second == 0)
+ return false;
+ foreach (const AbstractMetaFunction* func, overloads) {
+ if (hasArgumentWithDefaultValue(func))
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasArgumentWithDefaultValue() const
+{
+ if (maxArgs() == 0)
+ return false;
+ foreach (const AbstractMetaFunction* func, overloads()) {
+ if (hasArgumentWithDefaultValue(func))
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasArgumentWithDefaultValue(const AbstractMetaFunction* func)
+{
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+ if (!ShibokenGenerator::getDefaultValue(func, arg).isEmpty())
+ return true;
+ }
+ return false;
+}
+
+AbstractMetaArgumentList OverloadData::getArgumentsWithDefaultValues(const AbstractMetaFunction* func)
+{
+ AbstractMetaArgumentList args;
+ foreach (AbstractMetaArgument* arg, func->arguments()) {
+ if (ShibokenGenerator::getDefaultValue(func, arg).isEmpty()
+ || func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+ args << arg;
+ }
+ return args;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void OverloadData::formatDebug(QDebug &d) const
+{
+ const int count = m_overloads.size();
+ d << "argType=" << m_argType << ", minArgs=" << m_minArgs << ", maxArgs=" << m_maxArgs
+ << ", argPos=" << m_argPos << ", argTypeReplaced=\"" << m_argTypeReplaced
+ << "\", overloads[" << count << "]=(";
+ const int oldVerbosity = d.verbosity();
+ d.setVerbosity(3);
+ for (int i = 0; i < count; ++i) {
+ if (i)
+ d << '\n';
+ d << m_overloads.at(i);
+ }
+ d << ')';
+ d.setVerbosity(oldVerbosity);
+}
+
+QDebug operator<<(QDebug d, const OverloadData *od)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "OverloadData(";
+ if (od)
+ od->formatDebug(d);
+ else
+ d << '0';
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.h b/sources/shiboken2/generator/shiboken2/overloaddata.h
new file mode 100644
index 000000000..959b96d0b
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/overloaddata.h
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef OVERLOADDATA_H
+#define OVERLOADDATA_H
+
+#include <abstractmetalang_typedefs.h>
+#include <QtCore/QList>
+#include <QtCore/QBitArray>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+class ShibokenGenerator;
+
+class OverloadData;
+typedef QList<OverloadData*> OverloadDataList;
+
+class OverloadData
+{
+public:
+ OverloadData(const AbstractMetaFunctionList& overloads, const ShibokenGenerator* generator);
+ ~OverloadData();
+
+ int minArgs() const { return m_headOverloadData->m_minArgs; }
+ int maxArgs() const { return m_headOverloadData->m_maxArgs; }
+ int argPos() const { return m_argPos; }
+
+ const AbstractMetaType* argType() const { return m_argType; }
+
+ /// Returns a string list containing all the possible return types (including void) for the current OverloadData.
+ QStringList returnTypes() const;
+
+ /// Returns true if any of the overloads for the current OverloadData has a return type different from void.
+ bool hasNonVoidReturnType() const;
+
+ /// Returns true if any of the overloads for the current OverloadData has a varargs argument.
+ bool hasVarargs() const;
+
+ /// Returns true if any of the overloads for the current OverloadData allows threads when called.
+ bool hasAllowThread() const;
+
+ /// Returns true if any of the overloads for the current OverloadData is static.
+ bool hasStaticFunction() const;
+
+ /// Returns true if any of the overloads passed as argument is static.
+ static bool hasStaticFunction(const AbstractMetaFunctionList& overloads);
+
+ /// Returns true if any of the overloads for the current OverloadData is not static.
+ bool hasInstanceFunction() const;
+
+ /// Returns true if any of the overloads passed as argument is not static.
+ static bool hasInstanceFunction(const AbstractMetaFunctionList& overloads);
+
+ /// Returns true if among the overloads for the current OverloadData there are static and non-static methods altogether.
+ bool hasStaticAndInstanceFunctions() const;
+
+ /// Returns true if among the overloads passed as argument there are static and non-static methods altogether.
+ static bool hasStaticAndInstanceFunctions(const AbstractMetaFunctionList& overloads);
+
+ const AbstractMetaFunction* referenceFunction() const;
+ const AbstractMetaArgument* argument(const AbstractMetaFunction* func) const;
+ OverloadDataList overloadDataOnPosition(int argPos) const;
+
+ bool isHeadOverloadData() const { return this == m_headOverloadData; }
+
+ /// Returns the root OverloadData object that represents all the overloads.
+ OverloadData* headOverloadData() const { return m_headOverloadData; }
+
+ /// Returns the function that has a default value at the current OverloadData argument position, otherwise returns null.
+ const AbstractMetaFunction* getFunctionWithDefaultValue() const;
+
+ bool nextArgumentHasDefaultValue() const;
+ /// Returns the nearest occurrence, including this instance, of an argument with a default value.
+ OverloadData* findNextArgWithDefault();
+ bool isFinalOccurrence(const AbstractMetaFunction* func) const;
+
+ /// Returns the list of overloads removing repeated constant functions (ex.: "foo()" and "foo()const", the second is removed).
+ QList<const AbstractMetaFunction*> overloadsWithoutRepetition() const;
+ const QList<const AbstractMetaFunction*>& overloads() const { return m_overloads; }
+ OverloadDataList nextOverloadData() const { return m_nextOverloadData; }
+ OverloadData* previousOverloadData() const { return m_previousOverloadData; }
+
+ QList<int> invalidArgumentLengths() const;
+
+ static int numberOfRemovedArguments(const AbstractMetaFunction* func, int finalArgPos = -1);
+ static QPair<int, int> getMinMaxArguments(const AbstractMetaFunctionList& overloads);
+ /// Returns true if all overloads have no more than one argument.
+ static bool isSingleArgument(const AbstractMetaFunctionList& overloads);
+
+ void dumpGraph(QString filename) const;
+ QString dumpGraph() const;
+
+ bool hasArgumentTypeReplace() const;
+ QString argumentTypeReplaced() const;
+
+ bool hasArgumentWithDefaultValue() const;
+ static bool hasArgumentWithDefaultValue(const AbstractMetaFunctionList& overloads);
+ static bool hasArgumentWithDefaultValue(const AbstractMetaFunction* func);
+
+ /// Returns a list of function arguments which have default values and were not removed.
+ static AbstractMetaArgumentList getArgumentsWithDefaultValues(const AbstractMetaFunction* func);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &) const;
+#endif
+
+private:
+ OverloadData(OverloadData* headOverloadData, const AbstractMetaFunction* func,
+ const AbstractMetaType* argType, int argPos);
+
+ void addOverload(const AbstractMetaFunction* func);
+ OverloadData* addOverloadData(const AbstractMetaFunction* func, const AbstractMetaArgument* arg);
+
+ void sortNextOverloads();
+
+ int functionNumber(const AbstractMetaFunction* func) const;
+ OverloadDataList overloadDataOnPosition(OverloadData* overloadData, int argPos) const;
+
+ int m_minArgs;
+ int m_maxArgs;
+ int m_argPos;
+ const AbstractMetaType* m_argType;
+ QString m_argTypeReplaced;
+ QList<const AbstractMetaFunction*> m_overloads;
+
+ OverloadData* m_headOverloadData;
+ OverloadDataList m_nextOverloadData;
+ OverloadData* m_previousOverloadData;
+ const ShibokenGenerator* m_generator;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug, const OverloadData *);
+#endif
+
+#endif // OVERLOADDATA_H
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
new file mode 100644
index 000000000..7b664e105
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
@@ -0,0 +1,2674 @@
+/****************************************************************************
+**
+** 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 "shibokengenerator.h"
+#include <abstractmetalang.h>
+#include "overloaddata.h"
+#include <reporthandler.h>
+#include <typedatabase.h>
+#include <iostream>
+
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <limits>
+#include <memory>
+
+#define NULL_VALUE "NULL"
+#define AVOID_PROTECTED_HACK "avoid-protected-hack"
+#define PARENT_CTOR_HEURISTIC "enable-parent-ctor-heuristic"
+#define RETURN_VALUE_HEURISTIC "enable-return-value-heuristic"
+#define ENABLE_PYSIDE_EXTENSIONS "enable-pyside-extensions"
+#define DISABLE_VERBOSE_ERROR_MESSAGES "disable-verbose-error-messages"
+#define USE_ISNULL_AS_NB_NONZERO "use-isnull-as-nb_nonzero"
+
+//static void dumpFunction(AbstractMetaFunctionList lst);
+
+QHash<QString, QString> ShibokenGenerator::m_pythonPrimitiveTypeName = QHash<QString, QString>();
+QHash<QString, QString> ShibokenGenerator::m_pythonOperators = QHash<QString, QString>();
+QHash<QString, QString> ShibokenGenerator::m_formatUnits = QHash<QString, QString>();
+QHash<QString, QString> ShibokenGenerator::m_tpFuncs = QHash<QString, QString>();
+QStringList ShibokenGenerator::m_knownPythonTypes = QStringList();
+
+static QString resolveScopePrefix(const AbstractMetaClass* scope, const QString& value)
+{
+ if (!scope)
+ return QString();
+
+ QString name;
+ QStringList parts = scope->qualifiedCppName().split(QLatin1String("::"), QString::SkipEmptyParts);
+ for(int i = (parts.size() - 1) ; i >= 0; i--) {
+ if (!value.startsWith(parts[i] + QLatin1String("::")))
+ name = parts[i] + QLatin1String("::") + name;
+ else
+ name.clear();
+ }
+
+ return name;
+}
+ShibokenGenerator::ShibokenGenerator() : Generator()
+{
+ if (m_pythonPrimitiveTypeName.isEmpty())
+ ShibokenGenerator::initPrimitiveTypesCorrespondences();
+
+ if (m_tpFuncs.isEmpty())
+ ShibokenGenerator::clearTpFuncs();
+
+ if (m_knownPythonTypes.isEmpty())
+ ShibokenGenerator::initKnownPythonTypes();
+
+ m_metaTypeFromStringCache = AbstractMetaTypeCache();
+
+ m_typeSystemConvName[TypeSystemCheckFunction] = QLatin1String("checkType");
+ m_typeSystemConvName[TypeSystemIsConvertibleFunction] = QLatin1String("isConvertible");
+ m_typeSystemConvName[TypeSystemToCppFunction] = QLatin1String("toCpp");
+ m_typeSystemConvName[TypeSystemToPythonFunction] = QLatin1String("toPython");
+ m_typeSystemConvRegEx[TypeSystemCheckFunction] = QRegExp(QLatin1String(CHECKTYPE_REGEX));
+ m_typeSystemConvRegEx[TypeSystemIsConvertibleFunction] = QRegExp(QLatin1String(ISCONVERTIBLE_REGEX));
+ m_typeSystemConvRegEx[TypeSystemToPythonFunction] = QRegExp(QLatin1String(CONVERTTOPYTHON_REGEX));
+ m_typeSystemConvRegEx[TypeSystemToCppFunction] = QRegExp(QLatin1String(CONVERTTOCPP_REGEX));
+}
+
+ShibokenGenerator::~ShibokenGenerator()
+{
+ // TODO-CONVERTER: it must be caching types that were not created here.
+ //qDeleteAll(m_metaTypeFromStringCache.values());
+}
+
+void ShibokenGenerator::clearTpFuncs()
+{
+ m_tpFuncs.insert(QLatin1String("__str__"), QLatin1String("0"));
+ m_tpFuncs.insert(QLatin1String("__repr__"), QLatin1String("0"));
+ m_tpFuncs.insert(QLatin1String("__iter__"), QLatin1String("0"));
+ m_tpFuncs.insert(QLatin1String("__next__"), QLatin1String("0"));
+}
+
+void ShibokenGenerator::initPrimitiveTypesCorrespondences()
+{
+ // Python primitive types names
+ m_pythonPrimitiveTypeName.clear();
+
+ // PyBool
+ m_pythonPrimitiveTypeName.insert(QLatin1String("bool"), QLatin1String("PyBool"));
+
+ // PyInt
+ m_pythonPrimitiveTypeName.insert(QLatin1String("char"), QLatin1String("SbkChar"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("signed char"), QLatin1String("SbkChar"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned char"), QLatin1String("SbkChar"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("int"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("signed int"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("uint"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned int"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("short"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("ushort"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("signed short"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("signed short int"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned short"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned short int"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("long"), QLatin1String("PyInt"));
+
+ // PyFloat
+ m_pythonPrimitiveTypeName.insert(QLatin1String("double"), QLatin1String("PyFloat"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("float"), QLatin1String("PyFloat"));
+
+ // PyLong
+ m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned long"), QLatin1String("PyLong"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("signed long"), QLatin1String("PyLong"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("ulong"), QLatin1String("PyLong"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned long int"), QLatin1String("PyLong"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("long long"), QLatin1String("PyLong"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("__int64"), QLatin1String("PyLong"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned long long"), QLatin1String("PyLong"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned __int64"), QLatin1String("PyLong"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("size_t"), QLatin1String("PyLong"));
+
+ // Python operators
+ m_pythonOperators.clear();
+
+ // call operator
+ m_pythonOperators.insert(QLatin1String("operator()"), QLatin1String("call"));
+
+ // Arithmetic operators
+ m_pythonOperators.insert(QLatin1String("operator+"), QLatin1String("add"));
+ m_pythonOperators.insert(QLatin1String("operator-"), QLatin1String("sub"));
+ m_pythonOperators.insert(QLatin1String("operator*"), QLatin1String("mul"));
+ m_pythonOperators.insert(QLatin1String("operator/"), QLatin1String("div"));
+ m_pythonOperators.insert(QLatin1String("operator%"), QLatin1String("mod"));
+
+ // Inplace arithmetic operators
+ m_pythonOperators.insert(QLatin1String("operator+="), QLatin1String("iadd"));
+ m_pythonOperators.insert(QLatin1String("operator-="), QLatin1String("isub"));
+ m_pythonOperators.insert(QLatin1String("operator++"), QLatin1String("iadd"));
+ m_pythonOperators.insert(QLatin1String("operator--"), QLatin1String("isub"));
+ m_pythonOperators.insert(QLatin1String("operator*="), QLatin1String("imul"));
+ m_pythonOperators.insert(QLatin1String("operator/="), QLatin1String("idiv"));
+ m_pythonOperators.insert(QLatin1String("operator%="), QLatin1String("imod"));
+
+ // Bitwise operators
+ m_pythonOperators.insert(QLatin1String("operator&"), QLatin1String("and"));
+ m_pythonOperators.insert(QLatin1String("operator^"), QLatin1String("xor"));
+ m_pythonOperators.insert(QLatin1String("operator|"), QLatin1String("or"));
+ m_pythonOperators.insert(QLatin1String("operator<<"), QLatin1String("lshift"));
+ m_pythonOperators.insert(QLatin1String("operator>>"), QLatin1String("rshift"));
+ m_pythonOperators.insert(QLatin1String("operator~"), QLatin1String("invert"));
+
+ // Inplace bitwise operators
+ m_pythonOperators.insert(QLatin1String("operator&="), QLatin1String("iand"));
+ m_pythonOperators.insert(QLatin1String("operator^="), QLatin1String("ixor"));
+ m_pythonOperators.insert(QLatin1String("operator|="), QLatin1String("ior"));
+ m_pythonOperators.insert(QLatin1String("operator<<="), QLatin1String("ilshift"));
+ m_pythonOperators.insert(QLatin1String("operator>>="), QLatin1String("irshift"));
+
+ // Comparison operators
+ m_pythonOperators.insert(QLatin1String("operator=="), QLatin1String("eq"));
+ m_pythonOperators.insert(QLatin1String("operator!="), QLatin1String("ne"));
+ m_pythonOperators.insert(QLatin1String("operator<"), QLatin1String("lt"));
+ m_pythonOperators.insert(QLatin1String("operator>"), QLatin1String("gt"));
+ m_pythonOperators.insert(QLatin1String("operator<="), QLatin1String("le"));
+ m_pythonOperators.insert(QLatin1String("operator>="), QLatin1String("ge"));
+
+ // Initialize format units for C++->Python->C++ conversion
+ m_formatUnits.clear();
+ m_formatUnits.insert(QLatin1String("char"), QLatin1String("b"));
+ m_formatUnits.insert(QLatin1String("unsigned char"), QLatin1String("B"));
+ m_formatUnits.insert(QLatin1String("int"), QLatin1String("i"));
+ m_formatUnits.insert(QLatin1String("unsigned int"), QLatin1String("I"));
+ m_formatUnits.insert(QLatin1String("short"), QLatin1String("h"));
+ m_formatUnits.insert(QLatin1String("unsigned short"), QLatin1String("H"));
+ m_formatUnits.insert(QLatin1String("long"), QLatin1String("l"));
+ m_formatUnits.insert(QLatin1String("unsigned long"), QLatin1String("k"));
+ m_formatUnits.insert(QLatin1String("long long"), QLatin1String("L"));
+ m_formatUnits.insert(QLatin1String("__int64"), QLatin1String("L"));
+ m_formatUnits.insert(QLatin1String("unsigned long long"), QLatin1String("K"));
+ m_formatUnits.insert(QLatin1String("unsigned __int64"), QLatin1String("K"));
+ m_formatUnits.insert(QLatin1String("double"), QLatin1String("d"));
+ m_formatUnits.insert(QLatin1String("float"), QLatin1String("f"));
+}
+
+void ShibokenGenerator::initKnownPythonTypes()
+{
+ m_knownPythonTypes.clear();
+ m_knownPythonTypes << QLatin1String("PyBool") << QLatin1String("PyInt")
+ << QLatin1String("PyFloat") << QLatin1String("PyLong") << QLatin1String("PyObject")
+ << QLatin1String("PyString") << QLatin1String("PyBuffer") << QLatin1String("PySequence")
+ << QLatin1String("PyTuple") << QLatin1String("PyList") << QLatin1String("PyDict")
+ << QLatin1String("PyObject*") << QLatin1String("PyObject *") << QLatin1String("PyTupleObject*");
+}
+
+QString ShibokenGenerator::translateTypeForWrapperMethod(const AbstractMetaType* cType,
+ const AbstractMetaClass* context,
+ Options options) const
+{
+ if (cType->isArray())
+ return translateTypeForWrapperMethod(cType->arrayElementType(), context, options) + QLatin1String("[]");
+
+ if (avoidProtectedHack() && cType->isEnum()) {
+ const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(cType);
+ if (metaEnum && metaEnum->isProtected())
+ return protectedEnumSurrogateName(metaEnum);
+ }
+
+ return translateType(cType, context, options);
+}
+
+bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass* metaClass) const
+{
+ bool result = metaClass->isPolymorphic() || metaClass->hasVirtualDestructor();
+ if (avoidProtectedHack()) {
+ result = result || metaClass->hasProtectedFields() || metaClass->hasProtectedDestructor();
+ if (!result && metaClass->hasProtectedFunctions()) {
+ int protectedFunctions = 0;
+ int protectedOperators = 0;
+ foreach (const AbstractMetaFunction* func, metaClass->functions()) {
+ if (!func->isProtected() || func->isSignal() || func->isModifiedRemoved())
+ continue;
+ else if (func->isOperatorOverload())
+ protectedOperators++;
+ else
+ protectedFunctions++;
+ }
+ result = result || (protectedFunctions > protectedOperators);
+ }
+ } else {
+ result = result && !metaClass->hasPrivateDestructor();
+ }
+ return result && !metaClass->isNamespace();
+}
+
+void ShibokenGenerator::lookForEnumsInClassesNotToBeGenerated(AbstractMetaEnumList& enumList, const AbstractMetaClass* metaClass)
+{
+ if (!metaClass)
+ return;
+
+ if (metaClass->typeEntry()->codeGeneration() == TypeEntry::GenerateForSubclass) {
+ foreach (const AbstractMetaEnum* metaEnum, metaClass->enums()) {
+ if (metaEnum->isPrivate() || metaEnum->typeEntry()->codeGeneration() == TypeEntry::GenerateForSubclass)
+ continue;
+ if (!enumList.contains(const_cast<AbstractMetaEnum*>(metaEnum)))
+ enumList.append(const_cast<AbstractMetaEnum*>(metaEnum));
+ }
+ lookForEnumsInClassesNotToBeGenerated(enumList, metaClass->enclosingClass());
+ }
+}
+
+static const AbstractMetaClass* getProperEnclosingClass(const AbstractMetaClass* metaClass)
+{
+ if (!metaClass)
+ return 0;
+
+ if (metaClass->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass)
+ return metaClass;
+
+ return getProperEnclosingClass(metaClass->enclosingClass());
+}
+
+const AbstractMetaClass* ShibokenGenerator::getProperEnclosingClassForEnum(const AbstractMetaEnum* metaEnum)
+{
+ return getProperEnclosingClass(metaEnum->enclosingClass());
+}
+
+QString ShibokenGenerator::wrapperName(const AbstractMetaClass* metaClass) const
+{
+ if (shouldGenerateCppWrapper(metaClass)) {
+ QString result = metaClass->name();
+ if (metaClass->enclosingClass()) // is a inner class
+ result.replace(QLatin1String("::"), QLatin1String("_"));
+
+ result += QLatin1String("Wrapper");
+ return result;
+ } else {
+ return metaClass->qualifiedCppName();
+ }
+}
+
+QString ShibokenGenerator::wrapperName(const AbstractMetaType *metaType) const
+{
+ return metaType->cppSignature();
+}
+
+QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction* func)
+{
+ QString funcName;
+ if (func->isOperatorOverload())
+ funcName = ShibokenGenerator::pythonOperatorFunctionName(func);
+ else
+ funcName = func->name();
+ if (func->ownerClass()) {
+ QString fullName = func->ownerClass()->fullName();
+ if (func->isConstructor())
+ funcName = fullName;
+ else
+ funcName.prepend(fullName + QLatin1Char('.'));
+ }
+ return funcName;
+}
+
+QString ShibokenGenerator::protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum)
+{
+ return metaEnum->fullName().replace(QLatin1Char('.'), QLatin1Char('_')).replace(QLatin1String("::"), QLatin1String("_")) + QLatin1String("_Surrogate");
+}
+
+QString ShibokenGenerator::protectedFieldGetterName(const AbstractMetaField* field)
+{
+ return QStringLiteral("protected_%1_getter").arg(field->name());
+}
+
+QString ShibokenGenerator::protectedFieldSetterName(const AbstractMetaField* field)
+{
+ return QStringLiteral("protected_%1_setter").arg(field->name());
+}
+
+QString ShibokenGenerator::cpythonFunctionName(const AbstractMetaFunction* func)
+{
+ QString result;
+
+ // PYSIDE-331: For inherited functions, we need to find the same labels.
+ // Therefore we use the implementing class.
+ if (func->implementingClass()) {
+ result = cpythonBaseName(func->implementingClass()->typeEntry());
+ if (func->isConstructor()) {
+ result += QLatin1String("_Init");
+ } else {
+ result += QLatin1String("Func_");
+ if (func->isOperatorOverload())
+ result += ShibokenGenerator::pythonOperatorFunctionName(func);
+ else
+ result += func->name();
+ }
+ } else {
+ result = QLatin1String("Sbk") + moduleName() + QLatin1String("Module_") + func->name();
+ }
+
+ return result;
+}
+
+QString ShibokenGenerator::cpythonMethodDefinitionName(const AbstractMetaFunction* func)
+{
+ if (!func->ownerClass())
+ return QString();
+ return QStringLiteral("%1Method_%2").arg(cpythonBaseName(func->ownerClass()->typeEntry()), func->name());
+}
+
+QString ShibokenGenerator::cpythonGettersSettersDefinitionName(const AbstractMetaClass* metaClass)
+{
+ return cpythonBaseName(metaClass) + QLatin1String("_getsetlist");
+}
+
+QString ShibokenGenerator::cpythonSetattroFunctionName(const AbstractMetaClass* metaClass)
+{
+ return cpythonBaseName(metaClass) + QLatin1String("_setattro");
+}
+
+
+QString ShibokenGenerator::cpythonGetattroFunctionName(const AbstractMetaClass* metaClass)
+{
+ return cpythonBaseName(metaClass) + QLatin1String("_getattro");
+}
+
+QString ShibokenGenerator::cpythonGetterFunctionName(const AbstractMetaField* metaField)
+{
+ return QStringLiteral("%1_get_%2").arg(cpythonBaseName(metaField->enclosingClass()), metaField->name());
+}
+
+QString ShibokenGenerator::cpythonSetterFunctionName(const AbstractMetaField* metaField)
+{
+ return QStringLiteral("%1_set_%2").arg(cpythonBaseName(metaField->enclosingClass()), metaField->name());
+}
+
+static QString cpythonEnumFlagsName(QString moduleName, QString qualifiedCppName)
+{
+ QString result = QStringLiteral("Sbk%1_%2").arg(moduleName, qualifiedCppName);
+ result.replace(QLatin1String("::"), QLatin1String("_"));
+ return result;
+}
+
+static QString searchForEnumScope(const AbstractMetaClass* metaClass, const QString& value)
+{
+ QString enumValueName = value.trimmed();
+
+ if (!metaClass)
+ return QString();
+
+ foreach (const AbstractMetaEnum* metaEnum, metaClass->enums()) {
+ foreach (const AbstractMetaEnumValue* enumValue, metaEnum->values()) {
+ if (enumValueName == enumValue->name())
+ return metaClass->qualifiedCppName();
+ }
+ }
+ // PYSIDE-331: We need to also search the base classes.
+ QString ret = searchForEnumScope(metaClass->enclosingClass(), enumValueName);
+ if (ret.isEmpty())
+ ret = searchForEnumScope(metaClass->baseClass(), enumValueName);
+ return ret;
+}
+
+/*
+ * This function uses some heuristics to find out the scope for a given
+ * argument default value. New situations may arise in the future and
+ * this method should be updated, do it with care.
+ */
+QString ShibokenGenerator::guessScopeForDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg)
+{
+ QString value = getDefaultValue(func, arg);
+
+ if (value.isEmpty())
+ return QString();
+
+ if (isPointer(arg->type()))
+ return value;
+
+ static QRegExp enumValueRegEx(QLatin1String("^([A-Za-z_]\\w*)?$"));
+ QString prefix;
+ QString suffix;
+
+ if (arg->type()->isEnum()) {
+ const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(arg->type());
+ if (metaEnum)
+ prefix = resolveScopePrefix(metaEnum->enclosingClass(), value);
+ } else if (arg->type()->isFlags()) {
+ static QRegExp numberRegEx(QLatin1String("^\\d+$")); // Numbers to flags
+ if (numberRegEx.exactMatch(value)) {
+ QString typeName = translateTypeForWrapperMethod(arg->type(), func->implementingClass());
+ if (arg->type()->isConstant())
+ typeName.remove(0, sizeof("const ") / sizeof(char) - 1);
+ switch (arg->type()->referenceType()) {
+ case NoReference:
+ break;
+ case LValueReference:
+ typeName.chop(1);
+ break;
+ case RValueReference:
+ typeName.chop(2);
+ break;
+ }
+ prefix = typeName + QLatin1Char('(');
+ suffix = QLatin1Char(')');
+ }
+
+ static QRegExp enumCombinationRegEx(QLatin1String("^([A-Za-z_][\\w:]*)\\(([^,\\(\\)]*)\\)$")); // FlagName(EnumItem|EnumItem|...)
+ if (prefix.isEmpty() && enumCombinationRegEx.indexIn(value) != -1) {
+ QString flagName = enumCombinationRegEx.cap(1);
+ QStringList enumItems = enumCombinationRegEx.cap(2).split(QLatin1Char('|'));
+ QString scope = searchForEnumScope(func->implementingClass(), enumItems.first());
+ if (!scope.isEmpty())
+ scope.append(QLatin1String("::"));
+
+ QStringList fixedEnumItems;
+ foreach (const QString& enumItem, enumItems)
+ fixedEnumItems << QString(scope + enumItem);
+
+ if (!fixedEnumItems.isEmpty()) {
+ prefix = flagName + QLatin1Char('(');
+ value = fixedEnumItems.join(QLatin1Char('|'));
+ suffix = QLatin1Char(')');
+ }
+ }
+ } else if (arg->type()->typeEntry()->isValue()) {
+ const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes(), arg->type()->typeEntry());
+ if (enumValueRegEx.exactMatch(value)&& value != QLatin1String("NULL"))
+ prefix = resolveScopePrefix(metaClass, value);
+ } else if (arg->type()->isPrimitive() && arg->type()->name() == QLatin1String("int")) {
+ if (enumValueRegEx.exactMatch(value) && func->implementingClass())
+ prefix = resolveScopePrefix(func->implementingClass(), value);
+ } else if(arg->type()->isPrimitive()) {
+ static QRegExp unknowArgumentRegEx(QLatin1String("^(?:[A-Za-z_][\\w:]*\\()?([A-Za-z_]\\w*)(?:\\))?$")); // [PrimitiveType(] DESIREDNAME [)]
+ if (unknowArgumentRegEx.indexIn(value) != -1 && func->implementingClass()) {
+ foreach (const AbstractMetaField* field, func->implementingClass()->fields()) {
+ if (unknowArgumentRegEx.cap(1).trimmed() == field->name()) {
+ QString fieldName = field->name();
+ if (field->isStatic()) {
+ prefix = resolveScopePrefix(func->implementingClass(), value);
+ fieldName.prepend(prefix);
+ prefix.clear();
+ } else {
+ fieldName.prepend(QLatin1String(CPP_SELF_VAR "->"));
+ }
+ value.replace(unknowArgumentRegEx.cap(1), fieldName);
+ break;
+ }
+ }
+ }
+ }
+
+ if (!prefix.isEmpty())
+ value.prepend(prefix);
+ if (!suffix.isEmpty())
+ value.append(suffix);
+
+ return value;
+}
+
+QString ShibokenGenerator::cpythonEnumName(const EnumTypeEntry* enumEntry)
+{
+ QString p = enumEntry->targetLangPackage();
+ p.replace(QLatin1Char('.'), QLatin1Char('_'));
+ return cpythonEnumFlagsName(p, enumEntry->qualifiedCppName());
+}
+
+QString ShibokenGenerator::cpythonEnumName(const AbstractMetaEnum *metaEnum)
+{
+ return cpythonEnumName(metaEnum->typeEntry());
+}
+
+QString ShibokenGenerator::cpythonFlagsName(const FlagsTypeEntry* flagsEntry)
+{
+ QString p = flagsEntry->targetLangPackage();
+ p.replace(QLatin1Char('.'), QLatin1Char('_'));
+ return cpythonEnumFlagsName(p, flagsEntry->originalName());
+}
+
+QString ShibokenGenerator::cpythonFlagsName(const AbstractMetaEnum *metaEnum)
+{
+ const FlagsTypeEntry *flags = metaEnum->typeEntry()->flags();
+ if (!flags)
+ return QString();
+ return cpythonFlagsName(flags);
+}
+
+QString ShibokenGenerator::cpythonSpecialCastFunctionName(const AbstractMetaClass* metaClass)
+{
+ return cpythonBaseName(metaClass->typeEntry()) + QLatin1String("SpecialCastFunction");
+}
+
+QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClass* metaClass, QString argName)
+{
+ return cpythonWrapperCPtr(metaClass->typeEntry(), argName);
+}
+
+QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType *metaType, QString argName)
+{
+ if (!ShibokenGenerator::isWrapperType(metaType->typeEntry()))
+ return QString();
+ return QLatin1String("reinterpret_cast< ::") + metaType->cppSignature()
+ + QLatin1String(" *>(Shiboken::Conversions::cppPointer(") + cpythonTypeNameExt(metaType)
+ + QLatin1String(", reinterpret_cast<SbkObject *>(") + argName + QLatin1String(")))");
+}
+
+QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntry* type, QString argName)
+{
+ if (!ShibokenGenerator::isWrapperType(type))
+ return QString();
+ return QLatin1String("reinterpret_cast< ::") + type->qualifiedCppName()
+ + QLatin1String(" *>(Shiboken::Conversions::cppPointer(") + cpythonTypeNameExt(type)
+ + QLatin1String(", reinterpret_cast<SbkObject *>(") + argName + QLatin1String(")))");
+}
+
+QString ShibokenGenerator::getFunctionReturnType(const AbstractMetaFunction* func, Options) const
+{
+ if (func->ownerClass() && func->isConstructor())
+ return func->ownerClass()->qualifiedCppName() + QLatin1Char('*');
+
+ return translateTypeForWrapperMethod(func->type(), func->implementingClass());
+}
+
+void ShibokenGenerator::writeToPythonConversion(QTextStream & s, const AbstractMetaType* type,
+ const AbstractMetaClass * /* context */,
+ const QString& argumentName)
+{
+ s << cpythonToPythonConversionFunction(type) << argumentName << ')';
+}
+
+void ShibokenGenerator::writeToCppConversion(QTextStream& s, const AbstractMetaClass* metaClass,
+ const QString& inArgName, const QString& outArgName)
+{
+ s << cpythonToCppConversionFunction(metaClass) << inArgName << ", &" << outArgName << ')';
+}
+
+void ShibokenGenerator::writeToCppConversion(QTextStream& s, const AbstractMetaType* type, const AbstractMetaClass* context,
+ const QString& inArgName, const QString& outArgName)
+{
+ s << cpythonToCppConversionFunction(type, context) << inArgName << ", &" << outArgName << ')';
+}
+
+bool ShibokenGenerator::shouldRejectNullPointerArgument(const AbstractMetaFunction* func, int argIndex)
+{
+ if (argIndex < 0 || argIndex >= func->arguments().count())
+ return false;
+
+ const AbstractMetaArgument* arg = func->arguments().at(argIndex);
+ if (isValueTypeWithCopyConstructorOnly(arg->type()))
+ return true;
+
+ // Argument type is not a pointer, a None rejection should not be
+ // necessary because the type checking would handle that already.
+ if (!isPointer(arg->type()))
+ return false;
+ if (func->argumentRemoved(argIndex + 1))
+ return false;
+ foreach (const FunctionModification &funcMod, func->modifications()) {
+ foreach (const ArgumentModification &argMod, funcMod.argument_mods) {
+ if (argMod.index == argIndex + 1 && argMod.noNullPointers)
+ return true;
+ }
+ }
+ return false;
+}
+
+QString ShibokenGenerator::getFormatUnitString(const AbstractMetaFunction* func, bool incRef) const
+{
+ QString result;
+ const char objType = (incRef ? 'O' : 'N');
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+
+ if (!func->typeReplaced(arg->argumentIndex() + 1).isEmpty()) {
+ result += QLatin1Char(objType);
+ } else if (arg->type()->isQObject()
+ || arg->type()->isObject()
+ || arg->type()->isValue()
+ || arg->type()->isValuePointer()
+ || arg->type()->isNativePointer()
+ || arg->type()->isEnum()
+ || arg->type()->isFlags()
+ || arg->type()->isContainer()
+ || arg->type()->isSmartPointer()
+ || arg->type()->referenceType() == LValueReference) {
+ result += QLatin1Char(objType);
+ } else if (arg->type()->isPrimitive()) {
+ const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) arg->type()->typeEntry();
+ if (ptype->basicReferencedTypeEntry())
+ ptype = ptype->basicReferencedTypeEntry();
+ if (m_formatUnits.contains(ptype->name()))
+ result += m_formatUnits[ptype->name()];
+ else
+ result += QLatin1Char(objType);
+ } else if (isCString(arg->type())) {
+ result += QLatin1Char('z');
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Method: " << func->ownerClass()->qualifiedCppName()
+ << "::" << func->signature() << " => Arg:"
+ << arg->name() << "index: " << arg->argumentIndex()
+ << " - cannot be handled properly. Use an inject-code to fix it!";
+ result += QLatin1Char('?');
+ }
+ }
+ return result;
+}
+
+QString ShibokenGenerator::cpythonBaseName(const AbstractMetaType* type)
+{
+ if (isCString(type))
+ return QLatin1String("PyString");
+ return cpythonBaseName(type->typeEntry());
+}
+
+QString ShibokenGenerator::cpythonBaseName(const AbstractMetaClass* metaClass)
+{
+ return cpythonBaseName(metaClass->typeEntry());
+}
+
+QString ShibokenGenerator::cpythonBaseName(const TypeEntry* type)
+{
+ QString baseName;
+ if (ShibokenGenerator::isWrapperType(type) || type->isNamespace()) { // && type->referenceType() == NoReference) {
+ baseName = QLatin1String("Sbk_") + type->name();
+ } else if (type->isPrimitive()) {
+ const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) type;
+ while (ptype->basicReferencedTypeEntry())
+ ptype = ptype->basicReferencedTypeEntry();
+ if (ptype->targetLangApiName() == ptype->name())
+ baseName = pythonPrimitiveTypeName(ptype->name());
+ else
+ baseName = ptype->targetLangApiName();
+ } else if (type->isEnum()) {
+ baseName = cpythonEnumName((const EnumTypeEntry*) type);
+ } else if (type->isFlags()) {
+ baseName = cpythonFlagsName((const FlagsTypeEntry*) type);
+ } else if (type->isContainer()) {
+ const ContainerTypeEntry* ctype = (const ContainerTypeEntry*) type;
+ switch (ctype->type()) {
+ case ContainerTypeEntry::ListContainer:
+ case ContainerTypeEntry::StringListContainer:
+ case ContainerTypeEntry::LinkedListContainer:
+ case ContainerTypeEntry::VectorContainer:
+ case ContainerTypeEntry::StackContainer:
+ case ContainerTypeEntry::QueueContainer:
+ //baseName = "PyList";
+ //break;
+ case ContainerTypeEntry::PairContainer:
+ //baseName = "PyTuple";
+ baseName = QLatin1String("PySequence");
+ break;
+ case ContainerTypeEntry::SetContainer:
+ baseName = QLatin1String("PySet");
+ break;
+ case ContainerTypeEntry::MapContainer:
+ case ContainerTypeEntry::MultiMapContainer:
+ case ContainerTypeEntry::HashContainer:
+ case ContainerTypeEntry::MultiHashContainer:
+ baseName = QLatin1String("PyDict");
+ break;
+ default:
+ Q_ASSERT(false);
+ }
+ } else {
+ baseName = QLatin1String("PyObject");
+ }
+ return baseName.replace(QLatin1String("::"), QLatin1String("_"));
+}
+
+QString ShibokenGenerator::cpythonTypeName(const AbstractMetaClass* metaClass)
+{
+ return cpythonTypeName(metaClass->typeEntry());
+}
+
+QString ShibokenGenerator::cpythonTypeName(const TypeEntry* type)
+{
+ return cpythonBaseName(type) + QLatin1String("_Type");
+}
+
+QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntry* type)
+{
+ return cppApiVariableName(type->targetLangPackage()) + QLatin1Char('[')
+ + getTypeIndexVariableName(type) + QLatin1Char(']');
+}
+
+QString ShibokenGenerator::converterObject(const AbstractMetaType* type)
+{
+ if (isCString(type))
+ return QLatin1String("Shiboken::Conversions::PrimitiveTypeConverter<const char*>()");
+ if (isVoidPointer(type))
+ return QLatin1String("Shiboken::Conversions::PrimitiveTypeConverter<void*>()");
+ if (type->typeEntry()->isContainer()) {
+ return convertersVariableName(type->typeEntry()->targetLangPackage())
+ + QLatin1Char('[') + getTypeIndexVariableName(type) + QLatin1Char(']');
+ }
+ return converterObject(type->typeEntry());
+}
+
+QString ShibokenGenerator::converterObject(const TypeEntry* type)
+{
+ if (isCppPrimitive(type))
+ return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(type->qualifiedCppName());
+ if (isWrapperType(type) || type->isEnum() || type->isFlags())
+ return QString::fromLatin1("SBK_CONVERTER(%1)").arg(cpythonTypeNameExt(type));
+
+ if (type->isArray()) {
+ qDebug() << "Warning: no idea how to handle the Qt5 type " << type->qualifiedCppName();
+ return QString::null;
+ }
+
+ /* the typedef'd primitive types case */
+ const PrimitiveTypeEntry* pte = dynamic_cast<const PrimitiveTypeEntry*>(type);
+ if (!pte) {
+ qDebug() << "Warning: the Qt5 primitive type is unknown" << type->qualifiedCppName();
+ return QString::null;
+ }
+ if (pte->basicReferencedTypeEntry())
+ pte = pte->basicReferencedTypeEntry();
+ if (pte->isPrimitive() && !pte->isCppPrimitive() && !pte->customConversion())
+ return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(pte->qualifiedCppName());
+
+ return convertersVariableName(type->targetLangPackage())
+ + QLatin1Char('[') + getTypeIndexVariableName(type) + QLatin1Char(']');
+}
+
+QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType* type)
+{
+ return cppApiVariableName(type->typeEntry()->targetLangPackage()) + QLatin1Char('[')
+ + getTypeIndexVariableName(type) + QLatin1Char(']');
+}
+
+static QString msgUnknownOperator(const AbstractMetaFunction* func)
+{
+ QString result = QLatin1String("Unknown operator: \"") + func->originalName() + QLatin1Char('"');
+ if (const AbstractMetaClass *c = func->implementingClass())
+ result += QLatin1String(" in class: ") + c->name();
+ return result;
+}
+
+static inline QString unknownOperator() { return QStringLiteral("__UNKNOWN_OPERATOR__"); }
+
+QString ShibokenGenerator::cpythonOperatorFunctionName(const AbstractMetaFunction* func)
+{
+ if (!func->isOperatorOverload())
+ return QString();
+ const QString pythonOp = pythonOperatorFunctionName(func->originalName());
+ if (pythonOp == unknownOperator())
+ qCWarning(lcShiboken).noquote().nospace() << msgUnknownOperator(func);
+ return QLatin1String("Sbk") + func->ownerClass()->name()
+ + QLatin1Char('_') + pythonOp;
+}
+
+QString ShibokenGenerator::fixedCppTypeName(const CustomConversion::TargetToNativeConversion* toNative)
+{
+ if (toNative->sourceType())
+ return fixedCppTypeName(toNative->sourceType());
+ return toNative->sourceTypeName();
+}
+QString ShibokenGenerator::fixedCppTypeName(const AbstractMetaType* type)
+{
+ return fixedCppTypeName(type->typeEntry(), type->cppSignature());
+}
+
+static QString _fixedCppTypeName(QString typeName)
+{
+ typeName.remove(QLatin1Char(' '));
+ typeName.replace(QLatin1Char('.'), QLatin1Char('_'));
+ typeName.replace(QLatin1Char(','), QLatin1Char('_'));
+ typeName.replace(QLatin1Char('<'), QLatin1Char('_'));
+ typeName.replace(QLatin1Char('>'), QLatin1Char('_'));
+ typeName.replace(QLatin1String("::"), QLatin1String("_"));
+ typeName.replace(QLatin1String("*"), QLatin1String("PTR"));
+ typeName.replace(QLatin1String("&"), QLatin1String("REF"));
+ return typeName;
+}
+QString ShibokenGenerator::fixedCppTypeName(const TypeEntry* type, QString typeName)
+{
+ if (typeName.isEmpty())
+ typeName = type->qualifiedCppName();
+ if (!(type->codeGeneration() & TypeEntry::GenerateTargetLang)) {
+ typeName.prepend(QLatin1Char('_'));
+ typeName.prepend(type->targetLangPackage());
+ }
+ return _fixedCppTypeName(typeName);
+}
+
+QString ShibokenGenerator::pythonPrimitiveTypeName(const QString& cppTypeName)
+{
+ QString rv = ShibokenGenerator::m_pythonPrimitiveTypeName.value(cppTypeName, QString());
+ if (rv.isEmpty()) {
+ // activate this when some primitive types are missing,
+ // i.e. when shiboken itself fails to build.
+ // In general, this is valid while just called by isNumeric()
+ // used on Qt5, 2015-09-20
+ if (false) {
+ std::cerr << "primitive type not found: " << qPrintable(cppTypeName) << std::endl;
+ abort();
+ }
+ }
+ return rv;
+}
+
+QString ShibokenGenerator::pythonPrimitiveTypeName(const PrimitiveTypeEntry* type)
+{
+ while (type->basicReferencedTypeEntry())
+ type = type->basicReferencedTypeEntry();
+ return pythonPrimitiveTypeName(type->name());
+}
+
+QString ShibokenGenerator::pythonOperatorFunctionName(QString cppOpFuncName)
+{
+ QString value = m_pythonOperators.value(cppOpFuncName);
+ if (value.isEmpty())
+ return unknownOperator();
+ value.prepend(QLatin1String("__"));
+ value.append(QLatin1String("__"));
+ return value;
+}
+
+QString ShibokenGenerator::pythonOperatorFunctionName(const AbstractMetaFunction* func)
+{
+ QString op = pythonOperatorFunctionName(func->originalName());
+ if (op == unknownOperator())
+ qCWarning(lcShiboken).noquote().nospace() << msgUnknownOperator(func);
+ if (func->arguments().isEmpty()) {
+ if (op == QLatin1String("__sub__"))
+ op = QLatin1String("__neg__");
+ else if (op == QLatin1String("__add__"))
+ op = QLatin1String("__pos__");
+ } else if (func->isStatic() && func->arguments().size() == 2) {
+ // If a operator overload function has 2 arguments and
+ // is static we assume that it is a reverse operator.
+ op = op.insert(2, QLatin1Char('r'));
+ }
+ return op;
+}
+
+QString ShibokenGenerator::pythonRichCompareOperatorId(QString cppOpFuncName)
+{
+ return QLatin1String("Py_") + m_pythonOperators.value(cppOpFuncName).toUpper();
+}
+
+QString ShibokenGenerator::pythonRichCompareOperatorId(const AbstractMetaFunction* func)
+{
+ return pythonRichCompareOperatorId(func->originalName());
+}
+
+bool ShibokenGenerator::isNumber(QString cpythonApiName)
+{
+ return cpythonApiName == QLatin1String("PyInt")
+ || cpythonApiName == QLatin1String("PyFloat")
+ || cpythonApiName == QLatin1String("PyLong")
+ || cpythonApiName == QLatin1String("PyBool");
+}
+
+bool ShibokenGenerator::isNumber(const TypeEntry* type)
+{
+ if (!type->isPrimitive())
+ return false;
+ return isNumber(pythonPrimitiveTypeName((const PrimitiveTypeEntry*) type));
+}
+
+bool ShibokenGenerator::isNumber(const AbstractMetaType* type)
+{
+ return isNumber(type->typeEntry());
+}
+
+bool ShibokenGenerator::isPyInt(const TypeEntry* type)
+{
+ if (!type->isPrimitive())
+ return false;
+ return pythonPrimitiveTypeName((const PrimitiveTypeEntry*) type) == QLatin1String("PyInt");
+}
+
+bool ShibokenGenerator::isPyInt(const AbstractMetaType* type)
+{
+ return isPyInt(type->typeEntry());
+}
+
+bool ShibokenGenerator::isPairContainer(const AbstractMetaType* type)
+{
+ return type->isContainer()
+ && static_cast<const ContainerTypeEntry *>(type->typeEntry())->type() == ContainerTypeEntry::PairContainer;
+}
+
+bool ShibokenGenerator::isWrapperType(const TypeEntry* type)
+{
+ if (type->isComplex())
+ return ShibokenGenerator::isWrapperType((const ComplexTypeEntry*)type);
+ return type->isObject() || type->isValue() || type->isSmartPointer();
+}
+bool ShibokenGenerator::isWrapperType(const ComplexTypeEntry* type)
+{
+ return isObjectType(type) || type->isValue() || type->isSmartPointer();
+}
+bool ShibokenGenerator::isWrapperType(const AbstractMetaType* metaType)
+{
+ return isObjectType(metaType)
+ || metaType->typeEntry()->isValue()
+ || metaType->typeEntry()->isSmartPointer();
+}
+
+bool ShibokenGenerator::isPointerToWrapperType(const AbstractMetaType* type)
+{
+ return (isObjectType(type) && type->indirections() == 1) || type->isValuePointer();
+}
+
+bool ShibokenGenerator::isObjectTypeUsedAsValueType(const AbstractMetaType* type)
+{
+ return type->typeEntry()->isObject() && type->referenceType() == NoReference && type->indirections() == 0;
+}
+
+bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const AbstractMetaClass* metaClass)
+{
+ if (!metaClass || !metaClass->typeEntry()->isValue())
+ return false;
+ AbstractMetaFunctionList ctors = metaClass->queryFunctions(AbstractMetaClass::Constructors);
+ if (ctors.count() != 1)
+ return false;
+ return ctors.first()->functionType() == AbstractMetaFunction::CopyConstructorFunction;
+}
+
+bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const TypeEntry* type) const
+{
+ if (!type || !type->isValue())
+ return false;
+ return isValueTypeWithCopyConstructorOnly(AbstractMetaClass::findClass(classes(), type));
+}
+
+bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const AbstractMetaType* type) const
+{
+ if (!type || !type->typeEntry()->isValue())
+ return false;
+ return isValueTypeWithCopyConstructorOnly(type->typeEntry());
+}
+
+bool ShibokenGenerator::isUserPrimitive(const TypeEntry* type)
+{
+ if (!type->isPrimitive())
+ return false;
+ const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type;
+ if (trueType->basicReferencedTypeEntry())
+ trueType = trueType->basicReferencedTypeEntry();
+ return trueType->isPrimitive() && !trueType->isCppPrimitive()
+ && trueType->qualifiedCppName() != QLatin1String("std::string");
+}
+
+bool ShibokenGenerator::isUserPrimitive(const AbstractMetaType* type)
+{
+ if (type->indirections() != 0)
+ return false;
+ return isUserPrimitive(type->typeEntry());
+}
+
+bool ShibokenGenerator::isCppPrimitive(const TypeEntry* type)
+{
+ if (type->isCppPrimitive())
+ return true;
+ if (!type->isPrimitive())
+ return false;
+ const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type;
+ if (trueType->basicReferencedTypeEntry())
+ trueType = trueType->basicReferencedTypeEntry();
+ return trueType->qualifiedCppName() == QLatin1String("std::string");
+}
+
+bool ShibokenGenerator::isCppPrimitive(const AbstractMetaType* type)
+{
+ if (isCString(type) || isVoidPointer(type))
+ return true;
+ if (type->indirections() != 0)
+ return false;
+ return isCppPrimitive(type->typeEntry());
+}
+
+bool ShibokenGenerator::shouldDereferenceArgumentPointer(const AbstractMetaArgument* arg)
+{
+ return shouldDereferenceAbstractMetaTypePointer(arg->type());
+}
+
+bool ShibokenGenerator::shouldDereferenceAbstractMetaTypePointer(const AbstractMetaType* metaType)
+{
+ return metaType->referenceType() == LValueReference && isWrapperType(metaType) && !isPointer(metaType);
+}
+
+bool ShibokenGenerator::visibilityModifiedToPrivate(const AbstractMetaFunction* func)
+{
+ foreach (const FunctionModification &mod, func->modifications()) {
+ if (mod.modifiers & Modification::Private)
+ return true;
+ }
+ return false;
+}
+
+QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType, bool genericNumberType)
+{
+ QString customCheck;
+ if (metaType->typeEntry()->isCustom()) {
+ AbstractMetaType* type;
+ customCheck = guessCPythonCheckFunction(metaType->typeEntry()->name(), &type);
+ if (type)
+ metaType = type;
+ if (!customCheck.isEmpty())
+ return customCheck;
+ }
+
+ if (isCppPrimitive(metaType)) {
+ if (isCString(metaType))
+ return QLatin1String("Shiboken::String::check");
+ if (isVoidPointer(metaType))
+ return QLatin1String("PyObject_Check");
+ return cpythonCheckFunction(metaType->typeEntry(), genericNumberType);
+ } else if (metaType->typeEntry()->isContainer()) {
+ QString typeCheck = QLatin1String("Shiboken::Conversions::");
+ ContainerTypeEntry::Type type = ((const ContainerTypeEntry*)metaType->typeEntry())->type();
+ if (type == ContainerTypeEntry::ListContainer
+ || type == ContainerTypeEntry::StringListContainer
+ || type == ContainerTypeEntry::LinkedListContainer
+ || type == ContainerTypeEntry::VectorContainer
+ || type == ContainerTypeEntry::StackContainer
+ || type == ContainerTypeEntry::SetContainer
+ || type == ContainerTypeEntry::QueueContainer) {
+ const AbstractMetaType* type = metaType->instantiations().first();
+ if (isPointerToWrapperType(type)) {
+ typeCheck += QString::fromLatin1("checkSequenceTypes(%1, ").arg(cpythonTypeNameExt(type));
+ } else if (isWrapperType(type)) {
+ typeCheck += QLatin1String("convertibleSequenceTypes(reinterpret_cast<const SbkObjectType *>(");
+ typeCheck += cpythonTypeNameExt(type);
+ typeCheck += QLatin1String("), ");
+ } else {
+ typeCheck += QString::fromLatin1("convertibleSequenceTypes(%1, ").arg(converterObject(type));
+ }
+ } else if (type == ContainerTypeEntry::MapContainer
+ || type == ContainerTypeEntry::MultiMapContainer
+ || type == ContainerTypeEntry::HashContainer
+ || type == ContainerTypeEntry::MultiHashContainer
+ || type == ContainerTypeEntry::PairContainer) {
+ QString pyType = (type == ContainerTypeEntry::PairContainer) ? QLatin1String("Pair") : QLatin1String("Dict");
+ const AbstractMetaType* firstType = metaType->instantiations().first();
+ const AbstractMetaType* secondType = metaType->instantiations().last();
+ if (isPointerToWrapperType(firstType) && isPointerToWrapperType(secondType)) {
+ typeCheck += QString::fromLatin1("check%1Types(%2, %3, ").arg(pyType)
+ .arg(cpythonTypeNameExt(firstType), cpythonTypeNameExt(secondType));
+ } else {
+ typeCheck += QString::fromLatin1("convertible%1Types(%2, %3, %4, %5, ")
+ .arg(pyType, converterObject(firstType),
+ isPointerToWrapperType(firstType) ? QLatin1String("true") : QLatin1String("false"),
+ converterObject(secondType),
+ isPointerToWrapperType(secondType) ? QLatin1String("true") : QLatin1String("false"));
+ }
+ }
+ return typeCheck;
+ }
+ return cpythonCheckFunction(metaType->typeEntry(), genericNumberType);
+}
+
+QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry* type, bool genericNumberType)
+{
+ QString customCheck;
+ if (type->isCustom()) {
+ AbstractMetaType* metaType;
+ customCheck = guessCPythonCheckFunction(type->name(), &metaType);
+ if (metaType)
+ return cpythonCheckFunction(metaType, genericNumberType);
+ return customCheck;
+ }
+
+ if (type->isEnum() || type->isFlags() || isWrapperType(type))
+ return QString::fromLatin1("SbkObject_TypeCheck(%1, ").arg(cpythonTypeNameExt(type));
+ else if (isCppPrimitive(type))
+ return pythonPrimitiveTypeName((const PrimitiveTypeEntry*)type) + QLatin1String("_Check");
+ QString typeCheck;
+ if (type->targetLangApiName() == type->name())
+ typeCheck = cpythonIsConvertibleFunction(type);
+ else if (type->targetLangApiName() == QLatin1String("PyUnicode"))
+ typeCheck = QLatin1String("Shiboken::String::check");
+ else
+ typeCheck = type->targetLangApiName() + QLatin1String("_Check");
+ return typeCheck;
+}
+
+QString ShibokenGenerator::guessCPythonCheckFunction(const QString& type, AbstractMetaType** metaType)
+{
+ *metaType = 0;
+ if (type == QLatin1String("PyTypeObject"))
+ return QLatin1String("PyType_Check");
+
+ if (type == QLatin1String("PyBuffer"))
+ return QLatin1String("Shiboken::Buffer::checkType");
+
+ if (type == QLatin1String("str"))
+ return QLatin1String("Shiboken::String::check");
+
+ *metaType = buildAbstractMetaTypeFromString(type);
+ if (*metaType && !(*metaType)->typeEntry()->isCustom())
+ return QString();
+
+ return type + QLatin1String("_Check");
+}
+
+QString ShibokenGenerator::guessCPythonIsConvertible(const QString& type)
+{
+ if (type == QLatin1String("PyTypeObject"))
+ return QLatin1String("PyType_Check");
+
+ AbstractMetaType* metaType = buildAbstractMetaTypeFromString(type);
+ if (metaType && !metaType->typeEntry()->isCustom())
+ return cpythonIsConvertibleFunction(metaType);
+
+ return type + QLatin1String("_Check");
+}
+
+QString ShibokenGenerator::cpythonIsConvertibleFunction(const TypeEntry* type,
+ bool /* genericNumberType */,
+ bool /* checkExact */)
+{
+ if (isWrapperType(type)) {
+ QString result = QLatin1String("Shiboken::Conversions::");
+ result += (type->isValue() && !isValueTypeWithCopyConstructorOnly(type))
+ ? QLatin1String("isPythonToCppValueConvertible")
+ : QLatin1String("isPythonToCppPointerConvertible");
+ result += QLatin1String("(reinterpret_cast<SbkObjectType *>(")
+ + cpythonTypeNameExt(type) + QLatin1String("), ");
+ return result;
+ }
+ return QString::fromLatin1("Shiboken::Conversions::isPythonToCppConvertible(%1, ")
+ .arg(converterObject(type));
+}
+QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType* metaType,
+ bool /* genericNumberType */)
+{
+ QString customCheck;
+ if (metaType->typeEntry()->isCustom()) {
+ AbstractMetaType* type;
+ customCheck = guessCPythonCheckFunction(metaType->typeEntry()->name(), &type);
+ if (type)
+ metaType = type;
+ if (!customCheck.isEmpty())
+ return customCheck;
+ }
+
+ if (isWrapperType(metaType)) {
+ QString result = QLatin1String("Shiboken::Conversions::");
+ if (isPointer(metaType) || isValueTypeWithCopyConstructorOnly(metaType))
+ result += QLatin1String("isPythonToCppPointerConvertible");
+ else if (metaType->referenceType() == LValueReference)
+ result += QLatin1String("isPythonToCppReferenceConvertible");
+ else
+ result += QLatin1String("isPythonToCppValueConvertible");
+ result += QLatin1String("(reinterpret_cast<const SbkObjectType *>(")
+ + cpythonTypeNameExt(metaType) + QLatin1String("), ");
+ return result;
+ }
+ return QStringLiteral("Shiboken::Conversions::isPythonToCppConvertible(%1, ")
+ .arg(converterObject(metaType));
+}
+
+QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaArgument *metaArg, bool genericNumberType)
+{
+ return cpythonIsConvertibleFunction(metaArg->type(), genericNumberType);
+}
+
+QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaClass* metaClass)
+{
+ return QLatin1String("Shiboken::Conversions::pythonToCppPointer(reinterpret_cast<SbkObjectType *>(")
+ + cpythonTypeNameExt(metaClass->typeEntry()) + QLatin1String("), ");
+}
+
+QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaType *type,
+ const AbstractMetaClass * /* context */)
+{
+ if (isWrapperType(type)) {
+ return QLatin1String("Shiboken::Conversions::pythonToCpp")
+ + (isPointer(type) ? QLatin1String("Pointer") : QLatin1String("Copy"))
+ + QLatin1String("(reinterpret_cast<SbkObjectType *>(")
+ + cpythonTypeNameExt(type) + QLatin1String("), ");
+ }
+ return QStringLiteral("Shiboken::Conversions::pythonToCppCopy(%1, ")
+ .arg(converterObject(type));
+}
+
+QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaType *type,
+ const AbstractMetaClass * /* context */)
+{
+ if (isWrapperType(type)) {
+ QString conversion;
+ if (type->referenceType() == LValueReference && !(type->isValue() && type->isConstant()) && !isPointer(type))
+ conversion = QLatin1String("reference");
+ else if (type->isValue() || type->isSmartPointer())
+ conversion = QLatin1String("copy");
+ else
+ conversion = QLatin1String("pointer");
+ QString result = QLatin1String("Shiboken::Conversions::") + conversion
+ + QLatin1String("ToPython(reinterpret_cast<const SbkObjectType *>(")
+ + cpythonTypeNameExt(type) + QLatin1String("), ");
+ if (conversion != QLatin1String("pointer"))
+ result += QLatin1Char('&');
+ return result;
+ }
+ return QStringLiteral("Shiboken::Conversions::copyToPython(%1, %2")
+ .arg(converterObject(type),
+ (isCString(type) || isVoidPointer(type)) ? QString() : QLatin1String("&"));
+}
+
+QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaClass* metaClass)
+{
+ return cpythonToPythonConversionFunction(metaClass->typeEntry());
+}
+
+QString ShibokenGenerator::cpythonToPythonConversionFunction(const TypeEntry* type)
+{
+ if (isWrapperType(type)) {
+ const QString conversion = type->isValue() ? QLatin1String("copy") : QLatin1String("pointer");
+ QString result = QLatin1String("Shiboken::Conversions::") + conversion
+ + QLatin1String("ToPython(reinterpret_cast<const SbkObjectType *>(") + cpythonTypeNameExt(type)
+ + QLatin1String("), ");
+ if (conversion != QLatin1String("pointer"))
+ result += QLatin1Char('&');
+ return result;
+ }
+
+ return QStringLiteral("Shiboken::Conversions::copyToPython(%1, &").arg(converterObject(type));
+}
+
+QString ShibokenGenerator::argumentString(const AbstractMetaFunction *func,
+ const AbstractMetaArgument *argument,
+ Options options) const
+{
+ QString modified_type;
+ if (!(options & OriginalTypeDescription))
+ modified_type = func->typeReplaced(argument->argumentIndex() + 1);
+ QString arg;
+
+ if (modified_type.isEmpty())
+ arg = translateType(argument->type(), func->implementingClass(), options);
+ else
+ arg = modified_type.replace(QLatin1Char('$'), QLatin1Char('.'));
+
+ if (!(options & Generator::SkipName)) {
+ arg += QLatin1Char(' ');
+ arg += argument->name();
+ }
+
+ QList<ReferenceCount> referenceCounts;
+ referenceCounts = func->referenceCounts(func->implementingClass(), argument->argumentIndex() + 1);
+ if ((options & Generator::SkipDefaultValues) != Generator::SkipDefaultValues &&
+ !argument->originalDefaultValueExpression().isEmpty())
+ {
+ QString default_value = argument->originalDefaultValueExpression();
+ if (default_value == QLatin1String("NULL"))
+ default_value = QLatin1String(NULL_VALUE);
+
+ //WORKAROUND: fix this please
+ if (default_value.startsWith(QLatin1String("new ")))
+ default_value.remove(0, 4);
+
+ arg += QLatin1String(" = ") + default_value;
+ }
+
+ return arg;
+}
+
+void ShibokenGenerator::writeArgument(QTextStream &s,
+ const AbstractMetaFunction *func,
+ const AbstractMetaArgument *argument,
+ Options options) const
+{
+ s << argumentString(func, argument, options);
+}
+
+void ShibokenGenerator::writeFunctionArguments(QTextStream &s,
+ const AbstractMetaFunction *func,
+ Options options) const
+{
+ AbstractMetaArgumentList arguments = func->arguments();
+
+ if (options & Generator::WriteSelf) {
+ s << func->implementingClass()->name() << '&';
+ if (!(options & SkipName))
+ s << " " PYTHON_SELF_VAR;
+ }
+
+ int argUsed = 0;
+ for (int i = 0; i < arguments.size(); ++i) {
+ if ((options & Generator::SkipRemovedArguments) && func->argumentRemoved(i+1))
+ continue;
+
+ if ((options & Generator::WriteSelf) || argUsed != 0)
+ s << ", ";
+ writeArgument(s, func, arguments[i], options);
+ argUsed++;
+ }
+}
+
+QString ShibokenGenerator::functionReturnType(const AbstractMetaFunction* func, Options options) const
+{
+ QString modifiedReturnType = QString(func->typeReplaced(0));
+ if (!modifiedReturnType.isNull() && !(options & OriginalTypeDescription))
+ return modifiedReturnType;
+ else
+ return translateType(func->type(), func->implementingClass(), options);
+}
+
+QString ShibokenGenerator::functionSignature(const AbstractMetaFunction *func,
+ QString prepend,
+ QString append,
+ Options options,
+ int /* argCount */) const
+{
+ QString result;
+ QTextStream s(&result);
+ // The actual function
+ if (!(func->isEmptyFunction() ||
+ func->isNormal() ||
+ func->isSignal())) {
+ options |= Generator::SkipReturnType;
+ } else {
+ s << functionReturnType(func, options) << ' ';
+ }
+
+ // name
+ QString name(func->originalName());
+ if (func->isConstructor())
+ name = wrapperName(func->ownerClass());
+
+ s << prepend << name << append << '(';
+ writeFunctionArguments(s, func, options);
+ s << ')';
+
+ if (func->isConstant() && !(options & Generator::ExcludeMethodConst))
+ s << " const";
+
+ return result;
+}
+
+void ShibokenGenerator::writeArgumentNames(QTextStream &s,
+ const AbstractMetaFunction *func,
+ Options options) const
+{
+ AbstractMetaArgumentList arguments = func->arguments();
+ int argCount = 0;
+ for (int j = 0, max = arguments.size(); j < max; j++) {
+
+ if ((options & Generator::SkipRemovedArguments) && (func->argumentRemoved(arguments.at(j)->argumentIndex()+1)))
+ continue;
+
+ s << ((argCount > 0) ? ", " : "") << arguments.at(j)->name();
+
+ if (((options & Generator::VirtualCall) == 0)
+ && (!func->conversionRule(TypeSystem::NativeCode, arguments.at(j)->argumentIndex() + 1).isEmpty()
+ || !func->conversionRule(TypeSystem::TargetLangCode, arguments.at(j)->argumentIndex() + 1).isEmpty())
+ && !func->isConstructor()) {
+ s << CONV_RULE_OUT_VAR_SUFFIX;
+ }
+
+ argCount++;
+ }
+}
+
+void ShibokenGenerator::writeFunctionCall(QTextStream& s,
+ const AbstractMetaFunction* func,
+ Options options) const
+{
+ if (!(options & Generator::SkipName))
+ s << (func->isConstructor() ? func->ownerClass()->qualifiedCppName() : func->originalName());
+ s << '(';
+ writeArgumentNames(s, func, options);
+ s << ')';
+}
+
+void ShibokenGenerator::writeUnusedVariableCast(QTextStream& s, const QString& variableName)
+{
+ s << INDENT << "SBK_UNUSED(" << variableName<< ')' << endl;
+}
+
+AbstractMetaFunctionList ShibokenGenerator::filterFunctions(const AbstractMetaClass* metaClass)
+{
+ AbstractMetaFunctionList result;
+ foreach (AbstractMetaFunction *func, metaClass->functions()) {
+ if (func->isSignal() || func->isDestructor() || func->usesRValueReferences()
+ || (func->isModifiedRemoved() && !func->isAbstract()
+ && (!avoidProtectedHack() || !func->isProtected())))
+ continue;
+ result << func;
+ }
+ return result;
+}
+
+ShibokenGenerator::ExtendedConverterData ShibokenGenerator::getExtendedConverters() const
+{
+ ExtendedConverterData extConvs;
+ foreach (const AbstractMetaClass* metaClass, classes()) {
+ // Use only the classes for the current module.
+ if (!shouldGenerate(metaClass))
+ continue;
+ foreach (AbstractMetaFunction* convOp, metaClass->operatorOverloads(AbstractMetaClass::ConversionOp)) {
+ // Get only the conversion operators that return a type from another module,
+ // that are value-types and were not removed in the type system.
+ const TypeEntry* convType = convOp->type()->typeEntry();
+ if ((convType->codeGeneration() & TypeEntry::GenerateTargetLang)
+ || !convType->isValue()
+ || convOp->isModifiedRemoved())
+ continue;
+ extConvs[convType].append(convOp->ownerClass());
+ }
+ }
+ return extConvs;
+}
+
+QList<const CustomConversion*> ShibokenGenerator::getPrimitiveCustomConversions()
+{
+ QList<const CustomConversion*> conversions;
+ foreach (const PrimitiveTypeEntry* type, primitiveTypes()) {
+ if (!shouldGenerateTypeEntry(type) || !isUserPrimitive(type) || !type->customConversion())
+ continue;
+
+ conversions << type->customConversion();
+ }
+ return conversions;
+}
+
+static QString getArgumentsFromMethodCall(const QString& str)
+{
+ // It would be way nicer to be able to use a Perl like
+ // regular expression that accepts temporary variables
+ // to count the parenthesis.
+ // For more information check this:
+ // http://perl.plover.com/yak/regex/samples/slide083.html
+ static QLatin1String funcCall("%CPPSELF.%FUNCTION_NAME");
+ int pos = str.indexOf(funcCall);
+ if (pos == -1)
+ return QString();
+ pos = pos + funcCall.size();
+ while (str.at(pos) == QLatin1Char(' ') || str.at(pos) == QLatin1Char('\t'))
+ ++pos;
+ if (str.at(pos) == QLatin1Char('('))
+ ++pos;
+ int begin = pos;
+ int counter = 1;
+ while (counter != 0) {
+ if (str.at(pos) == QLatin1Char('('))
+ ++counter;
+ else if (str.at(pos) == QLatin1Char(')'))
+ --counter;
+ ++pos;
+ }
+ return str.mid(begin, pos-begin-1);
+}
+
+QString ShibokenGenerator::getCodeSnippets(const CodeSnipList& codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language)
+{
+ QString code;
+ QTextStream c(&code);
+ foreach (const CodeSnip &snip, codeSnips) {
+ if ((position != TypeSystem::CodeSnipPositionAny && snip.position != position) || !(snip.language & language))
+ continue;
+ QString snipCode;
+ QTextStream sc(&snipCode);
+ formatCode(sc, snip.code(), INDENT);
+ c << snipCode;
+ }
+ return code;
+}
+void ShibokenGenerator::processCodeSnip(QString& code, const AbstractMetaClass* context)
+{
+ if (context) {
+ // Replace template variable by the Python Type object
+ // for the class context in which the variable is used.
+ code.replace(QLatin1String("%PYTHONTYPEOBJECT"),
+ cpythonTypeName(context) + QLatin1String(".super.ht_type"));
+ code.replace(QLatin1String("%TYPE"), wrapperName(context));
+ code.replace(QLatin1String("%CPPTYPE"), context->name());
+ }
+
+ // replace "toPython" converters
+ replaceConvertToPythonTypeSystemVariable(code);
+
+ // replace "toCpp" converters
+ replaceConvertToCppTypeSystemVariable(code);
+
+ // replace "isConvertible" check
+ replaceIsConvertibleToCppTypeSystemVariable(code);
+
+ // replace "checkType" check
+ replaceTypeCheckTypeSystemVariable(code);
+}
+
+ShibokenGenerator::ArgumentVarReplacementList ShibokenGenerator::getArgumentReplacement(const AbstractMetaFunction* func,
+ bool usePyArgs, TypeSystem::Language language,
+ const AbstractMetaArgument* lastArg)
+{
+ ArgumentVarReplacementList argReplacements;
+ TypeSystem::Language convLang = (language == TypeSystem::TargetLangCode)
+ ? TypeSystem::NativeCode : TypeSystem::TargetLangCode;
+ int removed = 0;
+ for (int i = 0; i < func->arguments().size(); ++i) {
+ const AbstractMetaArgument* arg = func->arguments().at(i);
+ QString argValue;
+ if (language == TypeSystem::TargetLangCode) {
+ bool hasConversionRule = !func->conversionRule(convLang, i+1).isEmpty();
+ bool argRemoved = func->argumentRemoved(i+1);
+ removed = removed + (int) argRemoved;
+ if (argRemoved && hasConversionRule)
+ argValue = arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX);
+ else if (argRemoved || (lastArg && arg->argumentIndex() > lastArg->argumentIndex()))
+ argValue = QLatin1String(CPP_ARG_REMOVED) + QString::number(i);
+ if (!argRemoved && argValue.isEmpty()) {
+ int argPos = i - removed;
+ const AbstractMetaType* type = arg->type();
+ QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1);
+ if (!typeReplaced.isEmpty()) {
+ AbstractMetaType* builtType = buildAbstractMetaTypeFromString(typeReplaced);
+ if (builtType)
+ type = builtType;
+ }
+ if (type->typeEntry()->isCustom()) {
+ argValue = usePyArgs
+ ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(argPos)
+ : QLatin1String(PYTHON_ARG);
+ } else {
+ argValue = hasConversionRule
+ ? arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX)
+ : QLatin1String(CPP_ARG) + QString::number(argPos);
+ if (isWrapperType(type)) {
+ if (type->referenceType() == LValueReference && !isPointer(type))
+ argValue.prepend(QLatin1Char('*'));
+ }
+ }
+ }
+ } else {
+ argValue = arg->name();
+ }
+ if (!argValue.isEmpty())
+ argReplacements << ArgumentVarReplacementPair(arg, argValue);
+
+ }
+ return argReplacements;
+}
+
+void ShibokenGenerator::writeCodeSnips(QTextStream& s,
+ const CodeSnipList& codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language,
+ const AbstractMetaClass* context)
+{
+ QString code = getCodeSnippets(codeSnips, position, language);
+ if (code.isEmpty())
+ return;
+ processCodeSnip(code, context);
+ s << INDENT << "// Begin code injection" << endl;
+ s << code;
+ s << INDENT << "// End of code injection" << endl;
+}
+
+void ShibokenGenerator::writeCodeSnips(QTextStream& s,
+ const CodeSnipList& codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language,
+ const AbstractMetaFunction* func,
+ const AbstractMetaArgument* lastArg)
+{
+ QString code = getCodeSnippets(codeSnips, position, language);
+ if (code.isEmpty())
+ return;
+
+ // Calculate the real number of arguments.
+ int argsRemoved = 0;
+ for (int i = 0; i < func->arguments().size(); i++) {
+ if (func->argumentRemoved(i+1))
+ argsRemoved++;
+ }
+
+ OverloadData od(getFunctionGroups(func->implementingClass())[func->name()], this);
+ bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(od);
+
+ // Replace %PYARG_# variables.
+ code.replace(QLatin1String("%PYARG_0"), QLatin1String(PYTHON_RETURN_VAR));
+
+ static QRegExp pyArgsRegex(QLatin1String("%PYARG_(\\d+)"));
+ if (language == TypeSystem::TargetLangCode) {
+ if (usePyArgs) {
+ code.replace(pyArgsRegex, QLatin1String(PYTHON_ARGS"[\\1-1]"));
+ } else {
+ static QRegExp pyArgsRegexCheck(QLatin1String("%PYARG_([2-9]+)"));
+ if (pyArgsRegexCheck.indexIn(code) != -1) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Wrong index for %PYARG variable (" << pyArgsRegexCheck.cap(1) << ") on " << func->signature();
+ return;
+ }
+ code.replace(QLatin1String("%PYARG_1"), QLatin1String(PYTHON_ARG));
+ }
+ } else {
+ // Replaces the simplest case of attribution to a
+ // Python argument on the binding virtual method.
+ static QRegExp pyArgsAttributionRegex(QLatin1String("%PYARG_(\\d+)\\s*=[^=]\\s*([^;]+)"));
+ code.replace(pyArgsAttributionRegex, QLatin1String("PyTuple_SET_ITEM(" PYTHON_ARGS ", \\1-1, \\2)"));
+ code.replace(pyArgsRegex, QLatin1String("PyTuple_GET_ITEM(" PYTHON_ARGS ", \\1-1)"));
+ }
+
+ // Replace %ARG#_TYPE variables.
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ QString argTypeVar = QStringLiteral("%ARG%1_TYPE").arg(arg->argumentIndex() + 1);
+ QString argTypeVal = arg->type()->cppSignature();
+ code.replace(argTypeVar, argTypeVal);
+ }
+
+ int pos = 0;
+ static QRegExp cppArgTypeRegexCheck(QLatin1String("%ARG(\\d+)_TYPE"));
+ while ((pos = cppArgTypeRegexCheck.indexIn(code, pos)) != -1) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Wrong index for %ARG#_TYPE variable (" << cppArgTypeRegexCheck.cap(1)
+ << ") on " << func->signature();
+ pos += cppArgTypeRegexCheck.matchedLength();
+ }
+
+ // Replace template variable for return variable name.
+ if (func->isConstructor()) {
+ code.replace(QLatin1String("%0."), QLatin1String("cptr->"));
+ code.replace(QLatin1String("%0"), QLatin1String("cptr"));
+ } else if (func->type()) {
+ QString returnValueOp = isPointerToWrapperType(func->type())
+ ? QLatin1String("%1->") : QLatin1String("%1.");
+ if (ShibokenGenerator::isWrapperType(func->type()))
+ code.replace(QLatin1String("%0."), returnValueOp.arg(QLatin1String(CPP_RETURN_VAR)));
+ code.replace(QLatin1String("%0"), QLatin1String(CPP_RETURN_VAR));
+ }
+
+ // Replace template variable for self Python object.
+ QString pySelf = (language == TypeSystem::NativeCode) ? QLatin1String("pySelf") : QLatin1String(PYTHON_SELF_VAR);
+ code.replace(QLatin1String("%PYSELF"), pySelf);
+
+ // Replace template variable for a pointer to C++ of this object.
+ if (func->implementingClass()) {
+ QString replacement = func->isStatic() ? QLatin1String("%1::") : QLatin1String("%1->");
+ QString cppSelf;
+ if (func->isStatic())
+ cppSelf = func->ownerClass()->qualifiedCppName();
+ else if (language == TypeSystem::NativeCode)
+ cppSelf = QLatin1String("this");
+ else
+ cppSelf = QLatin1String(CPP_SELF_VAR);
+
+ // On comparison operator CPP_SELF_VAR is always a reference.
+ if (func->isComparisonOperator())
+ replacement = QLatin1String("%1.");
+
+ if (func->isVirtual() && !func->isAbstract() && (!avoidProtectedHack() || !func->isProtected())) {
+ QString methodCallArgs = getArgumentsFromMethodCall(code);
+ if (!methodCallArgs.isNull()) {
+ const QString pattern = QStringLiteral("%CPPSELF.%FUNCTION_NAME(%1)").arg(methodCallArgs);
+ if (func->name() == QLatin1String("metaObject")) {
+ QString wrapperClassName = wrapperName(func->ownerClass());
+ QString cppSelfVar = avoidProtectedHack()
+ ? QLatin1String("%CPPSELF")
+ : QStringLiteral("reinterpret_cast<%1*>(%CPPSELF)").arg(wrapperClassName);
+ code.replace(pattern,
+ QString::fromLatin1("(Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(%1))"
+ " ? %2->::%3::%FUNCTION_NAME(%4)"
+ " : %CPPSELF.%FUNCTION_NAME(%4))").arg(pySelf, cppSelfVar, wrapperClassName, methodCallArgs));
+ } else {
+ code.replace(pattern,
+ QString::fromLatin1("(Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(%1))"
+ " ? %CPPSELF->::%TYPE::%FUNCTION_NAME(%2)"
+ " : %CPPSELF.%FUNCTION_NAME(%2))").arg(pySelf, methodCallArgs));
+ }
+ }
+ }
+
+ code.replace(QLatin1String("%CPPSELF."), replacement.arg(cppSelf));
+ code.replace(QLatin1String("%CPPSELF"), cppSelf);
+
+ if (code.indexOf(QLatin1String("%BEGIN_ALLOW_THREADS")) > -1) {
+ if (code.count(QLatin1String("%BEGIN_ALLOW_THREADS")) == code.count(QLatin1String("%END_ALLOW_THREADS"))) {
+ code.replace(QLatin1String("%BEGIN_ALLOW_THREADS"), QLatin1String(BEGIN_ALLOW_THREADS));
+ code.replace(QLatin1String("%END_ALLOW_THREADS"), QLatin1String(END_ALLOW_THREADS));
+ } else {
+ qCWarning(lcShiboken) << "%BEGIN_ALLOW_THREADS and %END_ALLOW_THREADS mismatch";
+ }
+ }
+
+ // replace template variable for the Python Type object for the
+ // class implementing the method in which the code snip is written
+ if (func->isStatic()) {
+ code.replace(QLatin1String("%PYTHONTYPEOBJECT"),
+ cpythonTypeName(func->implementingClass()) + QLatin1String(".super.ht_type"));
+ } else {
+ code.replace(QLatin1String("%PYTHONTYPEOBJECT."), pySelf + QLatin1String("->ob_type->"));
+ code.replace(QLatin1String("%PYTHONTYPEOBJECT"), pySelf + QLatin1String("->ob_type"));
+ }
+ }
+
+ // Replaces template %ARGUMENT_NAMES and %# variables by argument variables and values.
+ // Replaces template variables %# for individual arguments.
+ ArgumentVarReplacementList argReplacements = getArgumentReplacement(func, usePyArgs, language, lastArg);
+
+ QStringList args;
+ foreach (const ArgumentVarReplacementPair &pair, argReplacements) {
+ if (pair.second.startsWith(QLatin1String(CPP_ARG_REMOVED)))
+ continue;
+ args << pair.second;
+ }
+ code.replace(QLatin1String("%ARGUMENT_NAMES"), args.join(QLatin1String(", ")));
+
+ foreach (const ArgumentVarReplacementPair &pair, argReplacements) {
+ const AbstractMetaArgument* arg = pair.first;
+ int idx = arg->argumentIndex() + 1;
+ AbstractMetaType* type = arg->type();
+ QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1);
+ if (!typeReplaced.isEmpty()) {
+ AbstractMetaType* builtType = buildAbstractMetaTypeFromString(typeReplaced);
+ if (builtType)
+ type = builtType;
+ }
+ if (isWrapperType(type)) {
+ QString replacement = pair.second;
+ if (type->referenceType() == LValueReference && !isPointer(type))
+ replacement.remove(0, 1);
+ if (type->referenceType() == LValueReference || isPointer(type))
+ code.replace(QString::fromLatin1("%%1.").arg(idx), replacement + QLatin1String("->"));
+ }
+ code.replace(QRegExp(QString::fromLatin1("%%1\\b").arg(idx)), pair.second);
+ }
+
+ if (language == TypeSystem::NativeCode) {
+ // Replaces template %PYTHON_ARGUMENTS variable with a pointer to the Python tuple
+ // containing the converted virtual method arguments received from C++ to be passed
+ // to the Python override.
+ code.replace(QLatin1String("%PYTHON_ARGUMENTS"), QLatin1String(PYTHON_ARGS));
+
+ // replace variable %PYTHON_METHOD_OVERRIDE for a pointer to the Python method
+ // override for the C++ virtual method in which this piece of code was inserted
+ code.replace(QLatin1String("%PYTHON_METHOD_OVERRIDE"), QLatin1String(PYTHON_OVERRIDE_VAR));
+ }
+
+ if (avoidProtectedHack()) {
+ // If the function being processed was added by the user via type system,
+ // Shiboken needs to find out if there are other overloads for the same method
+ // name and if any of them is of the protected visibility. This is used to replace
+ // calls to %FUNCTION_NAME on user written custom code for calls to the protected
+ // dispatcher.
+ bool hasProtectedOverload = false;
+ if (func->isUserAdded()) {
+ foreach (const AbstractMetaFunction* f, getFunctionOverloads(func->ownerClass(), func->name()))
+ hasProtectedOverload |= f->isProtected();
+ }
+
+ if (func->isProtected() || hasProtectedOverload) {
+ code.replace(QLatin1String("%TYPE::%FUNCTION_NAME"),
+ QStringLiteral("%1::%2_protected")
+ .arg(wrapperName(func->ownerClass()), func->originalName()));
+ code.replace(QLatin1String("%FUNCTION_NAME"),
+ func->originalName() + QLatin1String("_protected"));
+ }
+ }
+
+ if (func->isConstructor() && shouldGenerateCppWrapper(func->ownerClass()))
+ code.replace(QLatin1String("%TYPE"), wrapperName(func->ownerClass()));
+
+ if (func->ownerClass())
+ code.replace(QLatin1String("%CPPTYPE"), func->ownerClass()->name());
+
+ replaceTemplateVariables(code, func);
+
+ processCodeSnip(code);
+ s << INDENT << "// Begin code injection" << endl;
+ s << code;
+ s << INDENT << "// End of code injection" << endl;
+}
+
+// Returns true if the string is an expression,
+// and false if it is a variable.
+static bool isVariable(const QString& code)
+{
+ static QRegExp expr(QLatin1String("\\s*\\*?\\s*[A-Za-z_][A-Za-z_0-9.]*\\s*(?:\\[[^\\[]+\\])*"));
+ return expr.exactMatch(code.trimmed());
+}
+
+// A miniature normalizer that puts a type string into a format
+// suitable for comparison with AbstractMetaType::cppSignature()
+// result.
+static QString miniNormalizer(const QString& varType)
+{
+ QString normalized = varType.trimmed();
+ if (normalized.isEmpty())
+ return normalized;
+ if (normalized.startsWith(QLatin1String("::")))
+ normalized.remove(0, 2);
+ QString suffix;
+ while (normalized.endsWith(QLatin1Char('*')) || normalized.endsWith(QLatin1Char('&'))) {
+ suffix.prepend(normalized.at(normalized.count() - 1));
+ normalized.chop(1);
+ normalized = normalized.trimmed();
+ }
+ const QString result = normalized + QLatin1Char(' ') + suffix;
+ return result.trimmed();
+}
+// The position must indicate the first character after the opening '('.
+// ATTENTION: do not modify this function to trim any resulting string!
+// This must be done elsewhere.
+static QString getConverterTypeSystemVariableArgument(const QString& code, int pos)
+{
+ QString arg;
+ int parenthesisDepth = 0;
+ int count = 0;
+ while (pos + count < code.count()) {
+ char c = code.at(pos+count).toLatin1(); // toAscii is gone
+ if (c == '(') {
+ ++parenthesisDepth;
+ } else if (c == ')') {
+ if (parenthesisDepth == 0) {
+ arg = code.mid(pos, count).trimmed();
+ break;
+ }
+ --parenthesisDepth;
+ }
+ ++count;
+ }
+ if (parenthesisDepth != 0)
+ qFatal("Unbalanced parenthesis on type system converter variable call.");
+ return arg;
+}
+typedef QPair<QString, QString> StringPair;
+void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString& code)
+{
+ QRegExp& regex = m_typeSystemConvRegEx[converterVariable];
+ int pos = 0;
+ QList<StringPair> replacements;
+ while ((pos = regex.indexIn(code, pos)) != -1) {
+ pos += regex.matchedLength();
+ QStringList list = regex.capturedTexts();
+ QString conversionString = list.first();
+ QString conversionTypeName = list.last();
+ const AbstractMetaType* conversionType = buildAbstractMetaTypeFromString(conversionTypeName);
+ if (!conversionType) {
+ qFatal(qPrintable(QString::fromLatin1("Could not find type '%1' for use in '%2' conversion. "
+ "Make sure to use the full C++ name, e.g. 'Namespace::Class'.")
+ .arg(conversionTypeName).arg(m_typeSystemConvName[converterVariable])), NULL);
+
+ }
+ QString conversion;
+ QTextStream c(&conversion);
+ switch (converterVariable) {
+ case TypeSystemToCppFunction: {
+ int end = pos - list.first().count();
+ int start = end;
+ while (start > 0 && code.at(start) != QLatin1Char('\n'))
+ --start;
+ while (code.at(start).isSpace())
+ ++start;
+ QString varType = code.mid(start, end - start);
+ conversionString = varType + list.first();
+ varType = miniNormalizer(varType);
+ QString varName = list.at(1).trimmed();
+ if (!varType.isEmpty()) {
+ if (varType != conversionType->cppSignature()) {
+ qFatal(qPrintable(QString::fromLatin1("Types of receiver variable ('%1') and %CONVERTTOCPP type system variable ('%2') differ.")
+ .arg(varType, conversionType->cppSignature())), NULL);
+ }
+ c << getFullTypeName(conversionType) << ' ' << varName;
+ writeMinimalConstructorExpression(c, conversionType);
+ c << ';' << endl;
+ Indentation indent(INDENT);
+ c << INDENT;
+ }
+ c << cpythonToCppConversionFunction(conversionType);
+ QString prefix;
+ if (varName.startsWith(QLatin1Char('*'))) {
+ varName.remove(0, 1);
+ varName = varName.trimmed();
+ } else {
+ prefix = QLatin1Char('&');
+ }
+ QString arg = getConverterTypeSystemVariableArgument(code, pos);
+ conversionString += arg;
+ c << arg << ", " << prefix << '(' << varName << ')';
+ break;
+ }
+ case TypeSystemCheckFunction:
+ conversion = cpythonCheckFunction(conversionType);
+ if (conversionType->typeEntry()->isPrimitive()
+ && (conversionType->typeEntry()->name() == QLatin1String("PyObject")
+ || !conversion.endsWith(QLatin1Char(' ')))) {
+ c << '(';
+ break;
+ }
+ case TypeSystemIsConvertibleFunction:
+ if (conversion.isEmpty())
+ conversion = cpythonIsConvertibleFunction(conversionType);
+ case TypeSystemToPythonFunction:
+ if (conversion.isEmpty())
+ conversion = cpythonToPythonConversionFunction(conversionType);
+ default: {
+ QString arg = getConverterTypeSystemVariableArgument(code, pos);
+ conversionString += arg;
+ if (converterVariable == TypeSystemToPythonFunction && !isVariable(arg)) {
+ qFatal(qPrintable(QString::fromLatin1("Only variables are acceptable as argument to %%CONVERTTOPYTHON type system variable on code snippet: '%1'")
+ .arg(code)), NULL);
+ }
+ if (conversion.contains(QLatin1String("%in"))) {
+ conversion.prepend(QLatin1Char('('));
+ conversion.replace(QLatin1String("%in"), arg);
+ } else {
+ c << arg;
+ }
+ }
+ }
+ replacements.append(qMakePair(conversionString, conversion));
+ }
+ foreach (const StringPair &rep, replacements)
+ code.replace(rep.first, rep.second);
+}
+
+bool ShibokenGenerator::injectedCodeUsesCppSelf(const AbstractMetaFunction* func)
+{
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
+ foreach (const CodeSnip &snip, snips) {
+ if (snip.code().contains(QLatin1String("%CPPSELF")))
+ return true;
+ }
+ return false;
+}
+
+bool ShibokenGenerator::injectedCodeUsesPySelf(const AbstractMetaFunction* func)
+{
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::NativeCode);
+ foreach (const CodeSnip &snip, snips) {
+ if (snip.code().contains(QLatin1String("%PYSELF")))
+ return true;
+ }
+ return false;
+}
+
+bool ShibokenGenerator::injectedCodeCallsCppFunction(const AbstractMetaFunction* func)
+{
+ QString funcCall = func->originalName() + QLatin1Char('(');
+ QString wrappedCtorCall;
+ if (func->isConstructor()) {
+ funcCall.prepend(QLatin1String("new "));
+ wrappedCtorCall = QStringLiteral("new %1(").arg(wrapperName(func->ownerClass()));
+ }
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
+ foreach (const CodeSnip &snip, snips) {
+ if (snip.code().contains(QLatin1String("%FUNCTION_NAME(")) || snip.code().contains(funcCall)
+ || (func->isConstructor()
+ && ((func->ownerClass()->isPolymorphic() && snip.code().contains(wrappedCtorCall))
+ || snip.code().contains(QLatin1String("new %TYPE("))))
+ )
+ return true;
+ }
+ return false;
+}
+
+bool ShibokenGenerator::injectedCodeCallsPythonOverride(const AbstractMetaFunction* func)
+{
+ static QRegExp overrideCallRegexCheck(QLatin1String("PyObject_Call\\s*\\(\\s*%PYTHON_METHOD_OVERRIDE\\s*,"));
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::NativeCode);
+ foreach (const CodeSnip &snip, snips) {
+ if (overrideCallRegexCheck.indexIn(snip.code()) != -1)
+ return true;
+ }
+ return false;
+}
+
+bool ShibokenGenerator::injectedCodeHasReturnValueAttribution(const AbstractMetaFunction* func, TypeSystem::Language language)
+{
+ static QRegExp retValAttributionRegexCheck_native(QLatin1String("%0\\s*=[^=]\\s*.+"));
+ static QRegExp retValAttributionRegexCheck_target(QLatin1String("%PYARG_0\\s*=[^=]\\s*.+"));
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, language);
+ foreach (const CodeSnip &snip, snips) {
+ if (language == TypeSystem::TargetLangCode) {
+ if (retValAttributionRegexCheck_target.indexIn(snip.code()) != -1)
+ return true;
+ } else {
+ if (retValAttributionRegexCheck_native.indexIn(snip.code()) != -1)
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ShibokenGenerator::injectedCodeUsesArgument(const AbstractMetaFunction* func, int argumentIndex)
+{
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny);
+ foreach (const CodeSnip &snip, snips) {
+ QString code = snip.code();
+ if (code.contains(QLatin1String("%ARGUMENT_NAMES")))
+ return true;
+ if (code.contains(QRegExp(QStringLiteral("%%1\\b").arg(argumentIndex + 1))))
+ return true;
+ }
+ return false;
+}
+
+bool ShibokenGenerator::hasMultipleInheritanceInAncestry(const AbstractMetaClass* metaClass)
+{
+ if (!metaClass || metaClass->baseClassNames().isEmpty())
+ return false;
+ if (metaClass->baseClassNames().size() > 1)
+ return true;
+ return hasMultipleInheritanceInAncestry(metaClass->baseClass());
+}
+
+typedef QMap<QString, AbstractMetaFunctionList> FunctionGroupMap;
+typedef FunctionGroupMap::const_iterator FunctionGroupMapIt;
+
+bool ShibokenGenerator::classNeedsGetattroFunction(const AbstractMetaClass* metaClass)
+{
+ if (!metaClass)
+ return false;
+ if (metaClass->typeEntry()->isSmartPointer())
+ return true;
+ const FunctionGroupMap &functionGroup = getFunctionGroups(metaClass);
+ for (FunctionGroupMapIt it = functionGroup.cbegin(), end = functionGroup.cend(); it != end; ++it) {
+ AbstractMetaFunctionList overloads;
+ foreach (AbstractMetaFunction* func, it.value()) {
+ if (func->isAssignmentOperator() || func->isCastOperator() || func->isModifiedRemoved()
+ || func->isPrivate() || func->ownerClass() != func->implementingClass()
+ || func->isConstructor() || func->isOperatorOverload())
+ continue;
+ overloads.append(func);
+ }
+ if (overloads.isEmpty())
+ continue;
+ if (OverloadData::hasStaticAndInstanceFunctions(overloads))
+ return true;
+ }
+ return false;
+}
+
+bool ShibokenGenerator::classNeedsSetattroFunction(const AbstractMetaClass *metaClass)
+{
+ if (!metaClass)
+ return false;
+ if (metaClass->typeEntry()->isSmartPointer())
+ return true;
+ return false;
+}
+
+AbstractMetaFunctionList ShibokenGenerator::getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass* metaClass)
+{
+ AbstractMetaFunctionList methods;
+ if (metaClass) {
+ const FunctionGroupMap &functionGroups = getFunctionGroups(metaClass);
+ for (FunctionGroupMapIt it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
+ AbstractMetaFunctionList overloads;
+ foreach (AbstractMetaFunction* func, it.value()) {
+ if (func->isAssignmentOperator() || func->isCastOperator() || func->isModifiedRemoved()
+ || func->isPrivate() || func->ownerClass() != func->implementingClass()
+ || func->isConstructor() || func->isOperatorOverload())
+ continue;
+ overloads.append(func);
+ }
+ if (overloads.isEmpty())
+ continue;
+ if (OverloadData::hasStaticAndInstanceFunctions(overloads))
+ methods.append(overloads.first());
+ }
+ }
+ return methods;
+}
+
+AbstractMetaClassList ShibokenGenerator::getBaseClasses(const AbstractMetaClass* metaClass) const
+{
+ AbstractMetaClassList baseClasses;
+ if (metaClass) {
+ foreach (const QString &parent, metaClass->baseClassNames()) {
+ AbstractMetaClass *clazz = AbstractMetaClass::findClass(classes(), parent);
+ if (clazz)
+ baseClasses << clazz;
+ }
+ }
+ return baseClasses;
+}
+
+const AbstractMetaClass* ShibokenGenerator::getMultipleInheritingClass(const AbstractMetaClass* metaClass)
+{
+ if (!metaClass || metaClass->baseClassNames().isEmpty())
+ return 0;
+ if (metaClass->baseClassNames().size() > 1)
+ return metaClass;
+ return getMultipleInheritingClass(metaClass->baseClass());
+}
+
+AbstractMetaClassList ShibokenGenerator::getAllAncestors(const AbstractMetaClass* metaClass) const
+{
+ AbstractMetaClassList result;
+ if (metaClass) {
+ AbstractMetaClassList baseClasses = getBaseClasses(metaClass);
+ foreach (AbstractMetaClass* base, baseClasses) {
+ result.append(base);
+ result.append(getAllAncestors(base));
+ }
+ }
+ return result;
+}
+
+QString ShibokenGenerator::getModuleHeaderFileName(const QString& moduleName) const
+{
+ QString result = moduleName.isEmpty() ? packageName() : moduleName;
+ result.replace(QLatin1Char('.'), QLatin1Char('_'));
+ return result.toLower() + QLatin1String("_python.h");
+}
+
+QString ShibokenGenerator::extendedIsConvertibleFunctionName(const TypeEntry* targetType) const
+{
+ QString p = targetType->targetLangPackage();
+ p.replace(QLatin1Char('.'), QLatin1Char('_'));
+ return QStringLiteral("ExtendedIsConvertible_%1_%2").arg(p, targetType->name());
+}
+
+QString ShibokenGenerator::extendedToCppFunctionName(const TypeEntry* targetType) const
+{
+ QString p = targetType->targetLangPackage();
+ p.replace(QLatin1Char('.'), QLatin1Char('_'));
+ return QStringLiteral("ExtendedToCpp_%1_%2").arg(p, targetType->name());
+}
+
+bool ShibokenGenerator::isCopyable(const AbstractMetaClass *metaClass)
+
+{
+ if (metaClass->isNamespace() || isObjectType(metaClass))
+ return false;
+ else if (metaClass->typeEntry()->copyable() == ComplexTypeEntry::Unknown)
+ return metaClass->hasCloneOperator();
+ else
+ return (metaClass->typeEntry()->copyable() == ComplexTypeEntry::CopyableSet);
+
+ return false;
+}
+
+AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromString(QString typeSignature)
+{
+ typeSignature = typeSignature.trimmed();
+ if (typeSignature.startsWith(QLatin1String("::")))
+ typeSignature.remove(0, 2);
+
+ if (m_metaTypeFromStringCache.contains(typeSignature))
+ return m_metaTypeFromStringCache.value(typeSignature);
+
+ QString typeString = typeSignature;
+ bool isConst = typeString.startsWith(QLatin1String("const "));
+ if (isConst)
+ typeString.remove(0, sizeof("const ") / sizeof(char) - 1);
+
+ ReferenceType refType = NoReference;
+ if (typeString.endsWith(QLatin1String("&&"))) {
+ refType = RValueReference;
+ typeString.chop(2);
+ typeString = typeString.trimmed();
+ } else if (typeString.endsWith(QLatin1Char('&'))) {
+ refType = LValueReference;
+ typeString.chop(1);
+ typeString = typeString.trimmed();
+ }
+
+ int indirections = 0;
+ while (typeString.endsWith(QLatin1Char('*'))) {
+ ++indirections;
+ typeString.chop(1);
+ typeString = typeString.trimmed();
+ }
+
+ if (typeString.startsWith(QLatin1String("::")))
+ typeString.remove(0, 2);
+
+ QString adjustedTypeName = typeString;
+ QStringList instantiatedTypes;
+ int lpos = typeString.indexOf(QLatin1Char('<'));
+ if (lpos > -1) {
+ int rpos = typeString.lastIndexOf(QLatin1Char('>'));
+ if ((lpos != -1) && (rpos != -1)) {
+ QString type = typeString.mid(lpos + 1, rpos - lpos - 1);
+ int depth = 0;
+ int start = 0;
+ for (int i = 0; i < type.count(); ++i) {
+ if (type.at(i) == QLatin1Char('<')) {
+ ++depth;
+ } else if (type.at(i) == QLatin1Char('>')) {
+ --depth;
+ } else if (type.at(i) == QLatin1Char(',') && depth == 0) {
+ instantiatedTypes << type.mid(start, i - start).trimmed();
+ start = i + 1;
+ }
+ }
+ instantiatedTypes << type.mid(start).trimmed();
+ adjustedTypeName.truncate(lpos);
+ }
+ }
+
+ TypeEntry* typeEntry = TypeDatabase::instance()->findType(adjustedTypeName);
+
+ AbstractMetaType* metaType = 0;
+ if (typeEntry) {
+ metaType = new AbstractMetaType();
+ metaType->setTypeEntry(typeEntry);
+ metaType->setIndirections(indirections);
+ metaType->setReferenceType(refType);
+ metaType->setConstant(isConst);
+ metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern);
+ foreach (const QString& instantiation, instantiatedTypes) {
+ AbstractMetaType* tmplArgType = buildAbstractMetaTypeFromString(instantiation);
+ metaType->addInstantiation(tmplArgType);
+ }
+ metaType->decideUsagePattern();
+ m_metaTypeFromStringCache.insert(typeSignature, metaType);
+ }
+ return metaType;
+}
+
+AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(const TypeEntry* typeEntry)
+{
+ QString typeName = typeEntry->qualifiedCppName();
+ if (typeName.startsWith(QLatin1String("::")))
+ typeName.remove(0, 2);
+ if (m_metaTypeFromStringCache.contains(typeName))
+ return m_metaTypeFromStringCache.value(typeName);
+ AbstractMetaType* metaType = new AbstractMetaType;
+ metaType->setTypeEntry(typeEntry);
+ metaType->setIndirections(0);
+ metaType->setReferenceType(NoReference);
+ metaType->setConstant(false);
+ metaType->decideUsagePattern();
+ m_metaTypeFromStringCache.insert(typeName, metaType);
+ return metaType;
+}
+AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromAbstractMetaClass(const AbstractMetaClass* metaClass)
+{
+ return ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(metaClass->typeEntry());
+}
+
+/*
+static void dumpFunction(AbstractMetaFunctionList lst)
+{
+ qDebug() << "DUMP FUNCTIONS: ";
+ foreach (AbstractMetaFunction *func, lst)
+ qDebug() << "*" << func->ownerClass()->name()
+ << func->signature()
+ << "Private: " << func->isPrivate()
+ << "Empty: " << func->isEmptyFunction()
+ << "Static:" << func->isStatic()
+ << "Signal:" << func->isSignal()
+ << "ClassImplements: " << (func->ownerClass() != func->implementingClass())
+ << "is operator:" << func->isOperatorOverload()
+ << "is global:" << func->isInGlobalScope();
+}
+*/
+
+static bool isGroupable(const AbstractMetaFunction* func)
+{
+ if (func->isSignal() || func->isDestructor() || (func->isModifiedRemoved() && !func->isAbstract()))
+ return false;
+ // weird operator overloads
+ if (func->name() == QLatin1String("operator[]") || func->name() == QLatin1String("operator->")) // FIXME: what about cast operators?
+ return false;;
+ return true;
+}
+
+QMap< QString, AbstractMetaFunctionList > ShibokenGenerator::getFunctionGroups(const AbstractMetaClass* scope)
+{
+ AbstractMetaFunctionList lst = scope ? scope->functions() : globalFunctions();
+
+ QMap<QString, AbstractMetaFunctionList> results;
+ foreach (AbstractMetaFunction* func, lst) {
+ if (isGroupable(func))
+ results[func->name()].append(func);
+ }
+ return results;
+}
+
+AbstractMetaFunctionList ShibokenGenerator::getInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen)
+{
+ AbstractMetaFunctionList results;
+ AbstractMetaClass* basis;
+ if (func->ownerClass() && (basis = func->ownerClass()->baseClass(), basis)) {
+ for (; basis; basis = basis->baseClass()) {
+ const AbstractMetaFunction* inFunc = basis->findFunction(func->name());
+ if (inFunc && !seen->contains(inFunc->minimalSignature())) {
+ seen->insert(inFunc->minimalSignature());
+ AbstractMetaFunction* newFunc = inFunc->copy();
+ newFunc->setImplementingClass(func->implementingClass());
+ results << newFunc;
+ }
+ }
+ }
+ return results;
+}
+
+AbstractMetaFunctionList ShibokenGenerator::getFunctionAndInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen)
+{
+ AbstractMetaFunctionList results;
+ seen->insert(func->minimalSignature());
+ results << const_cast<AbstractMetaFunction *>(func) << getInheritedOverloads(func, seen);
+ return results;
+}
+
+AbstractMetaFunctionList ShibokenGenerator::getFunctionOverloads(const AbstractMetaClass* scope, const QString& functionName)
+{
+ AbstractMetaFunctionList lst = scope ? scope->functions() : globalFunctions();
+
+ AbstractMetaFunctionList results;
+ QSet<QString> seenSignatures;
+ foreach (AbstractMetaFunction* func, lst) {
+ if (func->name() != functionName)
+ continue;
+ if (isGroupable(func)) {
+ // PYSIDE-331: look also into base classes.
+ results << getFunctionAndInheritedOverloads(func, &seenSignatures);
+ }
+ }
+ return results;
+}
+
+QPair< int, int > ShibokenGenerator::getMinMaxArguments(const AbstractMetaFunction* metaFunction)
+{
+ AbstractMetaFunctionList overloads = getFunctionOverloads(metaFunction->ownerClass(), metaFunction->name());
+
+ int minArgs = std::numeric_limits<int>::max();
+ int maxArgs = 0;
+ foreach (const AbstractMetaFunction* func, overloads) {
+ int numArgs = 0;
+ foreach (const AbstractMetaArgument* arg, func->arguments()) {
+ if (!func->argumentRemoved(arg->argumentIndex() + 1))
+ numArgs++;
+ }
+ maxArgs = std::max(maxArgs, numArgs);
+ minArgs = std::min(minArgs, numArgs);
+ }
+ return qMakePair(minArgs, maxArgs);
+}
+
+QMap<QString, QString> ShibokenGenerator::options() const
+{
+ QMap<QString, QString> opts(Generator::options());
+ opts.insert(QLatin1String(AVOID_PROTECTED_HACK),
+ QLatin1String("Avoid the use of the '#define protected public' hack."));
+ opts.insert(QLatin1String(PARENT_CTOR_HEURISTIC),
+ QLatin1String("Enable heuristics to detect parent relationship on constructors."));
+ opts.insert(QLatin1String(RETURN_VALUE_HEURISTIC),
+ QLatin1String("Enable heuristics to detect parent relationship on return values (USE WITH CAUTION!)"));
+ opts.insert(QLatin1String(ENABLE_PYSIDE_EXTENSIONS),
+ QLatin1String("Enable PySide extensions, such as support for signal/slots, use this if you are creating a binding for a Qt-based library."));
+ opts.insert(QLatin1String(DISABLE_VERBOSE_ERROR_MESSAGES),
+ QLatin1String("Disable verbose error messages. Turn the python code hard to debug but safe few kB on the generated bindings."));
+ opts.insert(QLatin1String(USE_ISNULL_AS_NB_NONZERO),
+ QLatin1String("If a class have an isNull()const method, it will be used to compute the value of boolean casts"));
+ return opts;
+}
+
+static void getCode(QStringList& code, const CodeSnipList& codeSnips)
+{
+ foreach (const CodeSnip& snip, codeSnips)
+ code.append(snip.code());
+}
+
+static void getCode(QStringList& code, const TypeEntry* type)
+{
+ getCode(code, type->codeSnips());
+
+ CustomConversion* customConversion = type->customConversion();
+ if (!customConversion)
+ return;
+
+ if (!customConversion->nativeToTargetConversion().isEmpty())
+ code.append(customConversion->nativeToTargetConversion());
+
+ const CustomConversion::TargetToNativeConversions& toCppConversions = customConversion->targetToNativeConversions();
+ if (toCppConversions.isEmpty())
+ return;
+
+ foreach (CustomConversion::TargetToNativeConversion* toNative, toCppConversions)
+ code.append(toNative->conversion());
+}
+
+bool ShibokenGenerator::doSetup(const QMap<QString, QString>& args)
+{
+ m_useCtorHeuristic = args.contains(QLatin1String(PARENT_CTOR_HEURISTIC));
+ m_usePySideExtensions = args.contains(QLatin1String(ENABLE_PYSIDE_EXTENSIONS));
+ m_userReturnValueHeuristic = args.contains(QLatin1String(RETURN_VALUE_HEURISTIC));
+ m_verboseErrorMessagesDisabled = args.contains(QLatin1String(DISABLE_VERBOSE_ERROR_MESSAGES));
+ m_useIsNullAsNbNonZero = args.contains(QLatin1String(USE_ISNULL_AS_NB_NONZERO));
+ m_avoidProtectedHack = args.contains(QLatin1String(AVOID_PROTECTED_HACK));
+
+ TypeDatabase* td = TypeDatabase::instance();
+ QStringList snips;
+ foreach (const PrimitiveTypeEntry* type, primitiveTypes())
+ getCode(snips, type);
+ foreach (const ContainerTypeEntry* type, containerTypes())
+ getCode(snips, type);
+ foreach (const AbstractMetaClass* metaClass, classes())
+ getCode(snips, metaClass->typeEntry());
+ getCode(snips, td->findType(packageName()));
+ const FunctionGroupMap &functionGroups = getFunctionGroups();
+ for (FunctionGroupMapIt it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
+ foreach (AbstractMetaFunction* func, it.value())
+ getCode(snips, func->injectedCodeSnips());
+ }
+
+ foreach (const QString& code, snips) {
+ collectContainerTypesFromConverterMacros(code, true);
+ collectContainerTypesFromConverterMacros(code, false);
+ }
+
+ return true;
+}
+
+void ShibokenGenerator::collectContainerTypesFromConverterMacros(const QString& code, bool toPythonMacro)
+{
+ QString convMacro = toPythonMacro ? QLatin1String("%CONVERTTOPYTHON[") : QLatin1String("%CONVERTTOCPP[");
+ int offset = toPythonMacro ? sizeof("%CONVERTTOPYTHON") : sizeof("%CONVERTTOCPP");
+ int start = 0;
+ while ((start = code.indexOf(convMacro, start)) != -1) {
+ int end = code.indexOf(QLatin1Char(']'), start);
+ start += offset;
+ if (code.at(start) != QLatin1Char('%')) {
+ QString typeString = code.mid(start, end - start);
+ AbstractMetaType* type = buildAbstractMetaTypeFromString(typeString);
+ addInstantiatedContainersAndSmartPointers(type, type->originalTypeDescription());
+ }
+ start = end;
+ }
+}
+
+bool ShibokenGenerator::useCtorHeuristic() const
+{
+ return m_useCtorHeuristic;
+}
+
+bool ShibokenGenerator::useReturnValueHeuristic() const
+{
+ return m_userReturnValueHeuristic;
+}
+
+bool ShibokenGenerator::usePySideExtensions() const
+{
+ return m_usePySideExtensions;
+}
+
+bool ShibokenGenerator::useIsNullAsNbNonZero() const
+{
+ return m_useIsNullAsNbNonZero;
+}
+
+bool ShibokenGenerator::avoidProtectedHack() const
+{
+ return m_avoidProtectedHack;
+}
+
+QString ShibokenGenerator::cppApiVariableName(const QString& moduleName) const
+{
+ QString result = moduleName.isEmpty() ? ShibokenGenerator::packageName() : moduleName;
+ result.replace(QLatin1Char('.'), QLatin1Char('_'));
+ result.prepend(QLatin1String("Sbk"));
+ result.append(QLatin1String("Types"));
+ return result;
+}
+
+QString ShibokenGenerator::convertersVariableName(const QString& moduleName) const
+{
+ QString result = cppApiVariableName(moduleName);
+ result.chop(1);
+ result.append(QLatin1String("Converters"));
+ return result;
+}
+
+static QString processInstantiationsVariableName(const AbstractMetaType* type)
+{
+ QString res = QLatin1Char('_') + _fixedCppTypeName(type->typeEntry()->qualifiedCppName()).toUpper();
+ foreach (const AbstractMetaType* instantiation, type->instantiations()) {
+ res += instantiation->isContainer()
+ ? processInstantiationsVariableName(instantiation)
+ : QLatin1Char('_') + _fixedCppTypeName(instantiation->cppSignature()).toUpper();
+ }
+ return res;
+}
+QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClass* metaClass, bool alternativeTemplateName)
+{
+ if (alternativeTemplateName) {
+ const AbstractMetaClass* templateBaseClass = metaClass->templateBaseClass();
+ if (!templateBaseClass)
+ return QString();
+ QString base = _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper();
+ QString instantiations;
+ foreach (const AbstractMetaType* instantiation, metaClass->templateBaseClassInstantiations())
+ instantiations += processInstantiationsVariableName(instantiation);
+ return QString::fromLatin1("SBK_%1%2_IDX").arg(base, instantiations);
+ }
+ return getTypeIndexVariableName(metaClass->typeEntry());
+}
+QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry* type)
+{
+ if (type->isCppPrimitive()) {
+ const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type;
+ if (trueType->basicReferencedTypeEntry())
+ type = trueType->basicReferencedTypeEntry();
+ }
+ return QString::fromLatin1("SBK_%1_IDX").arg(_fixedCppTypeName(type->qualifiedCppName()).toUpper());
+}
+QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType* type)
+{
+ return QString::fromLatin1("SBK%1%2_IDX")
+ .arg(type->typeEntry()->isContainer() ? QLatin1Char('_') + moduleName().toUpper() : QString(),
+ processInstantiationsVariableName(type));
+}
+
+bool ShibokenGenerator::verboseErrorMessagesDisabled() const
+{
+ return m_verboseErrorMessagesDisabled;
+}
+
+bool ShibokenGenerator::pythonFunctionWrapperUsesListOfArguments(const OverloadData& overloadData)
+{
+ if (overloadData.referenceFunction()->isCallOperator())
+ return true;
+ if (overloadData.referenceFunction()->isOperatorOverload())
+ return false;
+ int maxArgs = overloadData.maxArgs();
+ int minArgs = overloadData.minArgs();
+ return (minArgs != maxArgs)
+ || (maxArgs > 1)
+ || overloadData.referenceFunction()->isConstructor()
+ || overloadData.hasArgumentWithDefaultValue();
+}
+
+Generator::Options ShibokenGenerator::getConverterOptions(const AbstractMetaType* metaType)
+{
+ // exclude const on Objects
+ Options flags;
+ const TypeEntry* type = metaType->typeEntry();
+ bool isCStr = isCString(metaType);
+ if (metaType->indirections() && !isCStr) {
+ flags = ExcludeConst;
+ } else if (metaType->isContainer()
+ || (type->isPrimitive() && !isCStr)
+ // const refs become just the value, but pure refs must remain pure.
+ || (type->isValue() && metaType->isConstant() && metaType->referenceType() == LValueReference)) {
+ flags = ExcludeConst | ExcludeReference;
+ }
+ return flags;
+}
+
+QString ShibokenGenerator::getDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg)
+{
+ if (!arg->defaultValueExpression().isEmpty())
+ return arg->defaultValueExpression();
+
+ //Check modifications
+ foreach(FunctionModification m, func->modifications()) {
+ foreach(ArgumentModification am, m.argument_mods) {
+ if (am.index == (arg->argumentIndex() + 1))
+ return am.replacedDefaultExpression;
+ }
+ }
+ return QString();
+}
+
+void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const AbstractMetaType* type, const QString& defaultCtor)
+{
+ if (defaultCtor.isEmpty() && isCppPrimitive(type))
+ return;
+ QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor;
+ if (ctor.isEmpty()) {
+ const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->cppSignature());
+ qCWarning(lcShiboken()).noquote() << message;
+ s << ";\n#error " << message << '\n';
+ } else {
+ s << " = " << ctor;
+ }
+}
+
+void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const TypeEntry* type, const QString& defaultCtor)
+{
+ if (defaultCtor.isEmpty() && isCppPrimitive(type))
+ return;
+ QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor;
+
+ if (ctor.isEmpty()) {
+ const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->qualifiedCppName());
+ qCWarning(lcShiboken()).noquote() << message;
+ s << ";\n#error " << message << endl;
+ } else {
+ s << " = " << ctor;
+ }
+}
+
+bool ShibokenGenerator::isCppIntegralPrimitive(const TypeEntry* type)
+{
+ if (!type->isCppPrimitive())
+ return false;
+ const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type;
+ if (trueType->basicReferencedTypeEntry())
+ trueType = trueType->basicReferencedTypeEntry();
+ QString typeName = trueType->qualifiedCppName();
+ return !typeName.contains(QLatin1String("double"))
+ && !typeName.contains(QLatin1String("float"))
+ && !typeName.contains(QLatin1String("wchar"));
+}
+bool ShibokenGenerator::isCppIntegralPrimitive(const AbstractMetaType* type)
+{
+ return isCppIntegralPrimitive(type->typeEntry());
+}
+
+QString ShibokenGenerator::msgCouldNotFindMinimalConstructor(const QString &where, const QString &type)
+{
+ return where + QLatin1String(": Could not find a minimal constructor for type '") + type
+ + QLatin1String("'. This will result in a compilation error.");
+}
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
new file mode 100644
index 000000000..837e7d640
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
@@ -0,0 +1,554 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef SHIBOKENGENERATOR_H
+#define SHIBOKENGENERATOR_H
+
+#define CONV_RULE_OUT_VAR_SUFFIX "_out"
+#define CPP_ARG "cppArg"
+#define CPP_ARG0 CPP_ARG"0"
+#define CPP_ARG_REMOVED "removed_" CPP_ARG
+#define CPP_RETURN_VAR "cppResult"
+#define CPP_SELF_VAR "cppSelf"
+#define PYTHON_ARG "pyArg"
+#define PYTHON_ARGS PYTHON_ARG "s"
+#define PYTHON_OVERRIDE_VAR "pyOverride"
+#define PYTHON_RETURN_VAR "pyResult"
+#define PYTHON_SELF_VAR "self"
+#define THREAD_STATE_SAVER_VAR "threadStateSaver"
+#define BEGIN_ALLOW_THREADS "PyThreadState* _save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS"
+#define END_ALLOW_THREADS "PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS"
+#define PYTHON_TO_CPP_VAR "pythonToCpp"
+#define SMART_POINTER_GETTER "kSmartPointerGetter"
+
+#define CHECKTYPE_REGEX "%CHECKTYPE\\[([^\\[]*)\\]\\("
+#define ISCONVERTIBLE_REGEX "%ISCONVERTIBLE\\[([^\\[]*)\\]\\("
+#define CONVERTTOPYTHON_REGEX "%CONVERTTOPYTHON\\[([^\\[]*)\\]\\("
+#define CONVERTTOCPP_REGEX "(\\*?%?[a-zA-Z_][\\w\\.]*(?:\\[[^\\[^<^>]+\\])*)"\
+ "(?:\\s+)=(?:\\s+)%CONVERTTOCPP\\[([^\\[]*)\\]\\("
+
+#include <generator.h>
+
+#include "typesystem.h"
+
+class DocParser;
+class CodeSnip;
+class OverloadData;
+
+QT_FORWARD_DECLARE_CLASS(QTextStream)
+
+/**
+ * Abstract generator that contains common methods used in CppGenerator and HeaderGenerator.
+ */
+class ShibokenGenerator : public Generator
+{
+public:
+ ShibokenGenerator();
+ virtual ~ShibokenGenerator();
+
+ QString translateTypeForWrapperMethod(const AbstractMetaType* cType,
+ const AbstractMetaClass* context, Options opt = NoOption) const;
+
+ /**
+ * Returns a map with all functions grouped, the function name is used as key.
+ * Example of return value: { "foo" -> ["foo(int)", "foo(int, long)], "bar" -> "bar(double)"}
+ * \param scope Where to search for functions, null means all global functions.
+ */
+ QMap<QString, AbstractMetaFunctionList> getFunctionGroups(const AbstractMetaClass* scope = 0);
+
+ /**
+ * Returns all different inherited overloads of func.
+ * The function can be called multiple times without duplication.
+ * \param func the metafunction to be searched in subclasses.
+ * \param seen the function's minimal signatures already seen.
+ */
+ AbstractMetaFunctionList getInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen);
+
+ /**
+ * Returns all different inherited overloads of func, and includes func as well.
+ * The function can be called multiple times without duplication.
+ * \param func the metafunction to be searched in subclasses.
+ * \param seen the function's minimal signatures already seen.
+ */
+ AbstractMetaFunctionList getFunctionAndInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen);
+
+ /**
+ * Returns all overloads for a function named \p functionName.
+ * \param scope scope used to search for overloads.
+ * \param functionName the function name.
+ */
+ AbstractMetaFunctionList getFunctionOverloads(const AbstractMetaClass* scope, const QString& functionName);
+ /**
+ * Returns the minimun and maximun number of arguments which this function and all overloads
+ * can accept. Arguments removed by typesystem are considered as well.
+ */
+ QPair<int, int> getMinMaxArguments(const AbstractMetaFunction* metaFunction);
+ /**
+ * Write a function argument in the C++ in the text stream \p s.
+ * This function just call \code s << argumentString(); \endcode
+ * \param s text stream used to write the output.
+ * \param func the current metafunction.
+ * \param argument metaargument information to be parsed.
+ * \param options some extra options.
+ */
+ void writeArgument(QTextStream &s,
+ const AbstractMetaFunction* func,
+ const AbstractMetaArgument* argument,
+ Options options = NoOption) const;
+ /**
+ * Create a QString in the C++ format to an function argument.
+ * \param func the current metafunction.
+ * \param argument metaargument information to be parsed.
+ * \param options some extra options.
+ */
+ QString argumentString(const AbstractMetaFunction* func,
+ const AbstractMetaArgument* argument,
+ Options options = NoOption) const;
+
+ void writeArgumentNames(QTextStream &s,
+ const AbstractMetaFunction* func,
+ Options options = NoOption) const;
+
+ /**
+ * Function used to write the fucntion arguments on the class buffer.
+ * \param s the class output buffer
+ * \param func the pointer to metafunction information
+ * \param count the number of function arguments
+ * \param options some extra options used during the parser
+ */
+ void writeFunctionArguments(QTextStream &s,
+ const AbstractMetaFunction* func,
+ Options options = NoOption) const;
+ QString functionReturnType(const AbstractMetaFunction* func, Options options = NoOption) const;
+
+ /// Utility function for writeCodeSnips.
+ typedef QPair<const AbstractMetaArgument*, QString> ArgumentVarReplacementPair;
+ typedef QList<ArgumentVarReplacementPair> ArgumentVarReplacementList;
+ ArgumentVarReplacementList getArgumentReplacement(const AbstractMetaFunction* func,
+ bool usePyArgs, TypeSystem::Language language,
+ const AbstractMetaArgument* lastArg);
+
+ /// Write user's custom code snippets at class or module level.
+ void writeCodeSnips(QTextStream& s,
+ const QList<CodeSnip>& codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language,
+ const AbstractMetaClass* context = 0);
+ /// Write user's custom code snippets at function level.
+ void writeCodeSnips(QTextStream& s,
+ const QList<CodeSnip>& codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language,
+ const AbstractMetaFunction* func,
+ const AbstractMetaArgument* lastArg = 0);
+
+ /// Returns a string with the user's custom code snippets that comply with \p position and \p language.
+ QString getCodeSnippets(const QList<CodeSnip>& codeSnips, TypeSystem::CodeSnipPosition position, TypeSystem::Language language);
+
+ /// Replaces variables for the user's custom code at global or class level.
+ void processCodeSnip(QString& code, const AbstractMetaClass* context = 0);
+
+ /// Replaces the %CONVERTTOPYTHON type system variable.
+ inline void replaceConvertToPythonTypeSystemVariable(QString& code)
+ {
+ replaceConverterTypeSystemVariable(TypeSystemToPythonFunction, code);
+ }
+ /// Replaces the %CONVERTTOCPP type system variable.
+ inline void replaceConvertToCppTypeSystemVariable(QString& code)
+ {
+ replaceConverterTypeSystemVariable(TypeSystemToCppFunction, code);
+ }
+ /// Replaces the %ISCONVERTIBLE type system variable.
+ inline void replaceIsConvertibleToCppTypeSystemVariable(QString& code)
+ {
+ replaceConverterTypeSystemVariable(TypeSystemIsConvertibleFunction, code);
+ }
+ /// Replaces the %CHECKTYPE type system variable.
+ inline void replaceTypeCheckTypeSystemVariable(QString& code)
+ {
+ replaceConverterTypeSystemVariable(TypeSystemCheckFunction, code);
+ }
+
+ /**
+ * Verifies if any of the function's code injections of the "target"
+ * type needs the type system variable "%CPPSELF".
+ * \param func the function to check
+ * \return true if the function's target code snippets use "%CPPSELF"
+ */
+ bool injectedCodeUsesCppSelf(const AbstractMetaFunction* func);
+
+ /**
+ * Verifies if any of the function's code injections of the "native"
+ * type needs the type system variable "%PYSELF".
+ * \param func the function to check
+ * \return true if the function's native code snippets use "%PYSELF"
+ */
+ bool injectedCodeUsesPySelf(const AbstractMetaFunction* func);
+
+ /**
+ * Verifies if any of the function's code injections makes a call
+ * to the C++ method. This is used by the generator to avoid writing calls
+ * to C++ when the user custom code already does this.
+ * \param func the function to check
+ * \return true if the function's code snippets call the wrapped C++ function
+ */
+ bool injectedCodeCallsCppFunction(const AbstractMetaFunction* func);
+
+ /**
+ * Verifies if any of the function's code injections of the "native" class makes a
+ * call to the C++ method. This is used by the generator to avoid writing calls to
+ * Python overrides of C++ virtual methods when the user custom code already does this.
+ * \param func the function to check
+ * \return true if the function's code snippets call the Python override for a C++ virtual method
+ */
+ bool injectedCodeCallsPythonOverride(const AbstractMetaFunction* func);
+
+ /**
+ * Verifies if any of the function's code injections attributes values to
+ * the return variable (%0 or %PYARG_0).
+ * \param func the function to check
+ * \param language the kind of code snip
+ * \return true if the function's code attributes values to "%0" or "%PYARG_0"
+ */
+ bool injectedCodeHasReturnValueAttribution(const AbstractMetaFunction* func, TypeSystem::Language language = TypeSystem::TargetLangCode);
+
+ /**
+ * Verifies if any of the function's code injections uses the type system variable
+ * for function arguments of a given index.
+ */
+ bool injectedCodeUsesArgument(const AbstractMetaFunction* func, int argumentIndex);
+
+ /**
+ * Function which parse the metafunction information
+ * \param func the function witch will be parserd
+ * \param option some extra options
+ * \param arg_count the number of function arguments
+ */
+ QString functionSignature(const AbstractMetaFunction* func,
+ QString prepend = QString(),
+ QString append = QString(),
+ Options options = NoOption,
+ int arg_count = -1) const;
+
+ /// Returns true if there are cases of multiple inheritance in any of its ancestors.
+ bool hasMultipleInheritanceInAncestry(const AbstractMetaClass* metaClass);
+
+ /// Returns true if the class needs to have a getattro function.
+ bool classNeedsGetattroFunction(const AbstractMetaClass* metaClass);
+
+ /// Returns true if the class needs to have a setattro function.
+ bool classNeedsSetattroFunction(const AbstractMetaClass *metaClass);
+
+ /// Returns a list of methods of the given class where each one is part of a different overload with both static and non-static method.
+ AbstractMetaFunctionList getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass* metaClass);
+
+ /// Returns a list of parent classes for a given class.
+ AbstractMetaClassList getBaseClasses(const AbstractMetaClass* metaClass) const;
+
+ /// Returns a list of all ancestor classes for the given class.
+ AbstractMetaClassList getAllAncestors(const AbstractMetaClass* metaClass) const;
+
+ const AbstractMetaClass* getMultipleInheritingClass(const AbstractMetaClass* metaClass);
+
+ void writeToPythonConversion(QTextStream& s, const AbstractMetaType* type,
+ const AbstractMetaClass* context, const QString& argumentName);
+ void writeToCppConversion(QTextStream& s, const AbstractMetaType* type, const AbstractMetaClass* context, const QString& inArgName, const QString& outArgName);
+ void writeToCppConversion(QTextStream& s, const AbstractMetaClass* metaClass, const QString& inArgName, const QString& outArgName);
+
+ /// Returns true if the argument is a pointer that rejects NULL values.
+ bool shouldRejectNullPointerArgument(const AbstractMetaFunction* func, int argIndex);
+
+ /// Verifies if the class should have a C++ wrapper generated for it, instead of only a Python wrapper.
+ bool shouldGenerateCppWrapper(const AbstractMetaClass* metaClass) const;
+
+ /// Adds enums eligible for generation from classes/namespaces marked not to be generated.
+ static void lookForEnumsInClassesNotToBeGenerated(AbstractMetaEnumList& enumList, const AbstractMetaClass* metaClass);
+ /// Returns the enclosing class for an enum, or NULL if it should be global.
+ const AbstractMetaClass* getProperEnclosingClassForEnum(const AbstractMetaEnum* metaEnum);
+
+ QString wrapperName(const AbstractMetaClass* metaClass) const;
+ QString wrapperName(const AbstractMetaType *metaType) const;
+
+ static QString fullPythonFunctionName(const AbstractMetaFunction* func);
+ static QString protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum);
+ static QString protectedFieldGetterName(const AbstractMetaField* field);
+ static QString protectedFieldSetterName(const AbstractMetaField* field);
+
+ static QString pythonPrimitiveTypeName(const QString& cppTypeName);
+ static QString pythonPrimitiveTypeName(const PrimitiveTypeEntry* type);
+
+ static QString pythonOperatorFunctionName(QString cppOpFuncName);
+ static QString pythonOperatorFunctionName(const AbstractMetaFunction* func);
+ static QString pythonRichCompareOperatorId(QString cppOpFuncName);
+ static QString pythonRichCompareOperatorId(const AbstractMetaFunction* func);
+
+ static QString cpythonOperatorFunctionName(const AbstractMetaFunction* func);
+
+ static QString fixedCppTypeName(const CustomConversion::TargetToNativeConversion* toNative);
+ static QString fixedCppTypeName(const AbstractMetaType* type);
+ static QString fixedCppTypeName(const TypeEntry* type, QString typeName = QString());
+
+ static bool isNumber(QString cpythonApiName);
+ static bool isNumber(const TypeEntry* type);
+ static bool isNumber(const AbstractMetaType* type);
+ static bool isPyInt(const TypeEntry* type);
+ static bool isPyInt(const AbstractMetaType* type);
+ static bool isPairContainer(const AbstractMetaType* type);
+
+ /**
+ * Returns true if the type passed has a Python wrapper for it.
+ * Although namespace has a Python wrapper, it's not considered a type.
+ */
+ static bool isWrapperType(const TypeEntry* type);
+ static bool isWrapperType(const ComplexTypeEntry* type);
+ static bool isWrapperType(const AbstractMetaType* metaType);
+
+ /**
+ * Checks if the type is an Object/QObject or pointer to Value Type.
+ * In other words, tells if the type is "T*" and T has a Python wrapper.
+ */
+ static bool isPointerToWrapperType(const AbstractMetaType* type);
+
+ /**
+ * Returns true if \p type is an Object Type used as a value.
+ */
+ static bool isObjectTypeUsedAsValueType(const AbstractMetaType* type);
+
+ static bool isValueTypeWithCopyConstructorOnly(const AbstractMetaClass* metaClass);
+ bool isValueTypeWithCopyConstructorOnly(const TypeEntry* type) const;
+ bool isValueTypeWithCopyConstructorOnly(const AbstractMetaType* type) const;
+
+ /// Returns true if the type is a primitive but not a C++ primitive.
+ static bool isUserPrimitive(const TypeEntry* type);
+ static bool isUserPrimitive(const AbstractMetaType* type);
+
+ /// Returns true if the type is a C++ primitive, a void*, a const char*, or a std::string.
+ static bool isCppPrimitive(const TypeEntry* type);
+ static bool isCppPrimitive(const AbstractMetaType* type);
+
+ /// Returns true if the type is a C++ integral primitive, i.e. bool, char, int, long, and their unsigned counterparts.
+ static bool isCppIntegralPrimitive(const TypeEntry* type);
+ static bool isCppIntegralPrimitive(const AbstractMetaType* type);
+
+ /// Checks if an argument type should be dereferenced by the Python method wrapper before calling the C++ method.
+ static bool shouldDereferenceArgumentPointer(const AbstractMetaArgument* arg);
+ /// Checks if a meta type should be dereferenced by the Python method wrapper passing it to C++.
+ static bool shouldDereferenceAbstractMetaTypePointer(const AbstractMetaType* metaType);
+
+ static bool visibilityModifiedToPrivate(const AbstractMetaFunction* func);
+
+ QString converterObject(const AbstractMetaType* type);
+ QString converterObject(const TypeEntry* type);
+
+ QString cpythonBaseName(const AbstractMetaClass* metaClass);
+ QString cpythonBaseName(const TypeEntry* type);
+ QString cpythonBaseName(const AbstractMetaType* type);
+ QString cpythonTypeName(const AbstractMetaClass* metaClass);
+ QString cpythonTypeName(const TypeEntry* type);
+ QString cpythonTypeNameExt(const TypeEntry* type);
+ QString cpythonTypeNameExt(const AbstractMetaType* type);
+ QString cpythonCheckFunction(const TypeEntry* type, bool genericNumberType = false);
+ QString cpythonCheckFunction(const AbstractMetaType* metaType, bool genericNumberType = false);
+ /**
+ * Receives the argument \p type and tries to find the appropriate AbstractMetaType for it
+ * or a custom type check.
+ * \param type A string representing the type to be discovered.
+ * \param metaType A pointer to an AbstractMetaType pointer, to where write a new meta type object
+ * if one is produced from the \p type string. This object must be deallocated by
+ * the caller. It will set the target variable to NULL, is \p type is a Python type.
+ * \return A custom check if \p type is a custom type, or an empty string if \p metaType
+ * receives an existing type object.
+ */
+ QString guessCPythonCheckFunction(const QString& type, AbstractMetaType** metaType);
+ QString cpythonIsConvertibleFunction(const TypeEntry* type, bool genericNumberType = false, bool checkExact = false);
+ QString cpythonIsConvertibleFunction(const AbstractMetaType* metaType, bool genericNumberType = false);
+ QString cpythonIsConvertibleFunction(const AbstractMetaArgument* metaArg, bool genericNumberType = false);
+ QString guessCPythonIsConvertible(const QString& type);
+
+ QString cpythonToCppConversionFunction(const AbstractMetaClass* metaClass);
+ QString cpythonToCppConversionFunction(const AbstractMetaType* type, const AbstractMetaClass* context = 0);
+ QString cpythonToPythonConversionFunction(const AbstractMetaType* type, const AbstractMetaClass* context = 0);
+ QString cpythonToPythonConversionFunction(const AbstractMetaClass* metaClass);
+ QString cpythonToPythonConversionFunction(const TypeEntry* type);
+
+ QString cpythonFunctionName(const AbstractMetaFunction* func);
+ QString cpythonMethodDefinitionName(const AbstractMetaFunction* func);
+ QString cpythonGettersSettersDefinitionName(const AbstractMetaClass* metaClass);
+ QString cpythonGetattroFunctionName(const AbstractMetaClass* metaClass);
+ QString cpythonSetattroFunctionName(const AbstractMetaClass* metaClass);
+ QString cpythonGetterFunctionName(const AbstractMetaField* metaField);
+ QString cpythonSetterFunctionName(const AbstractMetaField* metaField);
+ QString cpythonWrapperCPtr(const AbstractMetaClass* metaClass, QString argName = QLatin1String(PYTHON_SELF_VAR));
+ QString cpythonWrapperCPtr(const AbstractMetaType *metaType, QString argName);
+ QString cpythonWrapperCPtr(const TypeEntry* type, QString argName);
+
+ /// Guesses the scope to where belongs an argument's default value.
+ QString guessScopeForDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg);
+
+ QString cpythonEnumName(const EnumTypeEntry* enumEntry);
+ QString cpythonEnumName(const AbstractMetaEnum* metaEnum);
+
+ QString cpythonFlagsName(const FlagsTypeEntry* flagsEntry);
+ QString cpythonFlagsName(const AbstractMetaEnum* metaEnum);
+ /// Returns the special cast function name, the function used to proper cast class with multiple inheritance.
+ QString cpythonSpecialCastFunctionName(const AbstractMetaClass* metaClass);
+
+ QString getFunctionReturnType(const AbstractMetaFunction* func, Options options = NoOption) const;
+ QString getFormatUnitString(const AbstractMetaFunction* func, bool incRef = false) const;
+
+ /// Returns the file name for the module global header. If no module name is provided the current will be used.
+ QString getModuleHeaderFileName(const QString& moduleName = QString()) const;
+
+ QString extendedIsConvertibleFunctionName(const TypeEntry* targetType) const;
+ QString extendedToCppFunctionName(const TypeEntry* targetType) const;
+
+ QMap< QString, QString > options() const;
+
+ /// Returns true if the user enabled the so called "parent constructor heuristic".
+ bool useCtorHeuristic() const;
+ /// Returns true if the user enabled the so called "return value heuristic".
+ bool useReturnValueHeuristic() const;
+ /// Returns true if the user enabled PySide extensions.
+ bool usePySideExtensions() const;
+ /// Returns true if the generator should use the result of isNull()const to compute boolean casts.
+ bool useIsNullAsNbNonZero() const;
+ /// Returns true if the generated code should use the "#define protected public" hack.
+ bool avoidProtectedHack() const;
+ QString cppApiVariableName(const QString& moduleName = QString()) const;
+ QString convertersVariableName(const QString& moduleName = QString()) const;
+ /**
+ * Returns the type index variable name for a given class. If \p alternativeTemplateName is true
+ * and the class is a typedef for a template class instantiation, it will return an alternative name
+ * made of the template class and the instantiation values, or an empty string if the class isn't
+ * derived from a template class at all.
+ */
+ QString getTypeIndexVariableName(const AbstractMetaClass* metaClass, bool alternativeTemplateName = false);
+ QString getTypeIndexVariableName(const TypeEntry* type);
+ QString getTypeIndexVariableName(const AbstractMetaType* type);
+
+ /// Returns true if the user don't want verbose error messages on the generated bindings.
+ bool verboseErrorMessagesDisabled() const;
+
+ /**
+ * Builds an AbstractMetaType object from a QString.
+ * Returns NULL if no type could be built from the string.
+ * \param typeSignature The string describing the type to be built.
+ * \return A new AbstractMetaType object that must be deleted by the caller, or a NULL pointer in case of failure.
+ */
+ AbstractMetaType* buildAbstractMetaTypeFromString(QString typeSignature);
+
+ /// Creates an AbstractMetaType object from a TypeEntry.
+ AbstractMetaType* buildAbstractMetaTypeFromTypeEntry(const TypeEntry* typeEntry);
+ /// Creates an AbstractMetaType object from an AbstractMetaClass.
+ AbstractMetaType* buildAbstractMetaTypeFromAbstractMetaClass(const AbstractMetaClass* metaClass);
+
+ void writeMinimalConstructorExpression(QTextStream& s, const AbstractMetaType* type, const QString& defaultCtor = QString());
+ void writeMinimalConstructorExpression(QTextStream& s, const TypeEntry* type, const QString& defaultCtor = QString());
+
+ /**
+ * Helper function to return the flags to be used by a meta type when
+ * it needs to write some converter code.
+ */
+ static Options getConverterOptions(const AbstractMetaType* metaType);
+
+ /**
+ * Helper function to find for argument default value
+ */
+ static QString getDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg);
+protected:
+ bool doSetup(const QMap<QString, QString>& args);
+ void collectContainerTypesFromConverterMacros(const QString& code, bool toPythonMacro);
+ // verify whether the class is copyable
+ bool isCopyable(const AbstractMetaClass* metaClass);
+
+ bool m_native_jump_table;
+ static QHash<QString, QString> m_pythonPrimitiveTypeName;
+ static QHash<QString, QString> m_pythonOperators;
+ static QHash<QString, QString> m_formatUnits;
+ static QHash<QString, QString> m_tpFuncs;
+ static QStringList m_knownPythonTypes;
+
+ void clearTpFuncs();
+
+ const char* name() const { return "Shiboken"; }
+
+ /// Initializes correspondences between primitive and Python types.
+ static void initPrimitiveTypesCorrespondences();
+ /// Initializes a list of Python known type names.
+ static void initKnownPythonTypes();
+
+ void writeFunctionCall(QTextStream& s,
+ const AbstractMetaFunction* metaFunc,
+ Options options = NoOption) const;
+
+ void writeUnusedVariableCast(QTextStream& s, const QString& variableName);
+
+ AbstractMetaFunctionList filterFunctions(const AbstractMetaClass* metaClass);
+
+ // All data about extended converters: the type entries of the target type, and a
+ // list of AbstractMetaClasses accepted as argument for the conversion.
+ typedef QHash<const TypeEntry*, QList<const AbstractMetaClass*> > ExtendedConverterData;
+ /// Returns all extended conversions for the current module.
+ ExtendedConverterData getExtendedConverters() const;
+
+ /// Returns a list of converters for the non wrapper types of the current module.
+ QList<const CustomConversion*> getPrimitiveCustomConversions();
+
+ /// Returns true if the Python wrapper for the received OverloadData must accept a list of arguments.
+ static bool pythonFunctionWrapperUsesListOfArguments(const OverloadData& overloadData);
+
+ Indentor INDENT;
+
+ enum TypeSystemConverterVariable {
+ TypeSystemCheckFunction = 0,
+ TypeSystemIsConvertibleFunction,
+ TypeSystemToCppFunction,
+ TypeSystemToPythonFunction,
+ TypeSystemConverterVariables
+ };
+ void replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString& code);
+
+ static QString msgCouldNotFindMinimalConstructor(const QString &where, const QString &type);
+
+private:
+ bool m_useCtorHeuristic;
+ bool m_userReturnValueHeuristic;
+ bool m_usePySideExtensions;
+ bool m_verboseErrorMessagesDisabled;
+ bool m_useIsNullAsNbNonZero;
+ bool m_avoidProtectedHack;
+
+ typedef QHash<QString, AbstractMetaType*> AbstractMetaTypeCache;
+ AbstractMetaTypeCache m_metaTypeFromStringCache;
+
+ /// Type system converter variable replacement names and regular expressions.
+ QString m_typeSystemConvName[TypeSystemConverterVariables];
+ QRegExp m_typeSystemConvRegEx[TypeSystemConverterVariables];
+};
+
+#endif // SHIBOKENGENERATOR_H
diff --git a/sources/shiboken2/generator/shibokenconfig.h.in b/sources/shiboken2/generator/shibokenconfig.h.in
new file mode 100644
index 000000000..2c86a4a3c
--- /dev/null
+++ b/sources/shiboken2/generator/shibokenconfig.h.in
@@ -0,0 +1,6 @@
+#ifndef SHIBOKENCONFIG_H
+#define SHIBOKENCONFIG_H
+
+#define SHIBOKEN_VERSION "@shiboken2_VERSION@"
+
+#endif