diff options
author | Hugo Parente Lima <hugo.pl@gmail.com> | 2012-02-28 23:44:50 -0300 |
---|---|---|
committer | Hugo Parente Lima <hugo.pl@gmail.com> | 2012-03-09 19:06:21 -0300 |
commit | bd2df4ea6fd11f1285c07591367259f3900a93fc (patch) | |
tree | 9a61c0af4eb09e18682bfaf20d8b2ad58dbee5e3 /generators | |
parent | 363d1104a92a8d4a9bb7eb5838dcf941d710d042 (diff) |
generators directory renamed to generator.
This makes sense as now there only one generator that you can
tweak it into different modes (a.k.a. generator sets).
Reviewer: Trust me
Diffstat (limited to 'generators')
-rw-r--r-- | generators/CMakeLists.txt | 32 | ||||
-rw-r--r-- | generators/generator.cpp | 708 | ||||
-rw-r--r-- | generators/generator.h | 341 | ||||
-rw-r--r-- | generators/main.cpp | 443 | ||||
-rw-r--r-- | generators/qtdoc/CMakeLists.txt | 21 | ||||
-rw-r--r-- | generators/qtdoc/qtdocgenerator.cpp | 1652 | ||||
-rw-r--r-- | generators/qtdoc/qtdocgenerator.h | 226 | ||||
-rw-r--r-- | generators/shiboken/CMakeLists.txt | 30 | ||||
-rw-r--r-- | generators/shiboken/cppgenerator.cpp | 5125 | ||||
-rw-r--r-- | generators/shiboken/cppgenerator.h | 334 | ||||
-rw-r--r-- | generators/shiboken/headergenerator.cpp | 494 | ||||
-rw-r--r-- | generators/shiboken/headergenerator.h | 56 | ||||
-rw-r--r-- | generators/shiboken/overloaddata.cpp | 1002 | ||||
-rw-r--r-- | generators/shiboken/overloaddata.h | 147 | ||||
-rw-r--r-- | generators/shiboken/shibokengenerator.cpp | 2466 | ||||
-rw-r--r-- | generators/shiboken/shibokengenerator.h | 536 | ||||
-rw-r--r-- | generators/shiboken/shibokennormalize.cpp | 274 | ||||
-rw-r--r-- | generators/shiboken/shibokennormalize_p.h | 41 | ||||
-rw-r--r-- | generators/shibokenconfig.h.in | 7 |
19 files changed, 0 insertions, 13935 deletions
diff --git a/generators/CMakeLists.txt b/generators/CMakeLists.txt deleted file mode 100644 index 37a6f3cc9..000000000 --- a/generators/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -project(shibokengenerator) - -set(shiboken_SRC -generator.cpp -shiboken/cppgenerator.cpp -shiboken/headergenerator.cpp -shiboken/overloaddata.cpp -shiboken/shibokengenerator.cpp -shiboken/shibokennormalize.cpp -qtdoc/qtdocgenerator.cpp -main.cpp -) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/shiboken - ${CMAKE_CURRENT_SOURCE_DIR}/qtdoc - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ${APIEXTRACTOR_INCLUDE_DIR} - ${QT_INCLUDE_DIR} - ${QT_QTCORE_INCLUDE_DIR} - ${QT_QTXML_INCLUDE_DIR}) - -add_executable(shiboken ${shiboken_SRC}) -set_target_properties(shiboken PROPERTIES OUTPUT_NAME shiboken${shiboken_SUFFIX}) -target_link_libraries(shiboken - ${APIEXTRACTOR_LIBRARY} - ${QT_QTCORE_LIBRARY} - ${QT_QTXML_LIBRARY}) - -configure_file(shibokenconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/shibokenconfig.h" @ONLY) - -install(TARGETS shiboken DESTINATION bin) diff --git a/generators/generator.cpp b/generators/generator.cpp deleted file mode 100644 index 9f81b93ad..000000000 --- a/generators/generator.cpp +++ /dev/null @@ -1,708 +0,0 @@ -/* - * This file is part of the API Extractor project. - * - * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: PySide team <contact@pyside.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "generator.h" -#include "reporthandler.h" -#include "fileout.h" -#include "apiextractor.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; - int numGeneratedWritten; - QStringList instantiatedContainersNames; - QList<const AbstractMetaType*> instantiatedContainers; -}; - -Generator::Generator() : m_d(new GeneratorPrivate) -{ - m_d->numGenerated = 0; - m_d->numGeneratedWritten = 0; - m_d->instantiatedContainers = QList<const AbstractMetaType*>(); - m_d->instantiatedContainersNames = 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; - foreach (QList<TypeEntry*> entryList, allEntries.values()) { - foreach (TypeEntry* entry, entryList) { - if (entry->type() == TypeEntry::TypeSystemType && entry->generateCode()) { - entryFound = entry; - break; - } - } - if (entryFound) - break; - } - if (entryFound) - m_d->packageName = entryFound->name(); - else - ReportHandler::warning("Couldn't find the package name!!"); - - collectInstantiatedContainers(); - - return doSetup(args); -} - -QString Generator::getSimplifiedContainerTypeName(const AbstractMetaType* type) -{ - if (!type->typeEntry()->isContainer()) - return type->cppSignature(); - QString typeName = type->cppSignature(); - if (type->isConstant()) - typeName.remove(0, sizeof("const ") / sizeof(char) - 1); - if (type->isReference()) - typeName.chop(1); - while (typeName.endsWith('*') || typeName.endsWith(' ')) - typeName.chop(1); - return typeName; -} - -void Generator::addInstantiatedContainers(const AbstractMetaType* type) -{ - if (!type) - return; - foreach (const AbstractMetaType* t, type->instantiations()) - addInstantiatedContainers(t); - if (!type->typeEntry()->isContainer()) - return; - QString typeName = getSimplifiedContainerTypeName(type); - if (!m_d->instantiatedContainersNames.contains(typeName)) { - m_d->instantiatedContainersNames.append(typeName); - m_d->instantiatedContainers.append(type); - } -} - -void Generator::collectInstantiatedContainers(const AbstractMetaFunction* func) -{ - addInstantiatedContainers(func->type()); - foreach (const AbstractMetaArgument* arg, func->arguments()) - addInstantiatedContainers(arg->type()); -} - -void Generator::collectInstantiatedContainers(const AbstractMetaClass* metaClass) -{ - if (!metaClass->typeEntry()->generateCode()) - return; - foreach (const AbstractMetaFunction* func, metaClass->functions()) - collectInstantiatedContainers(func); - foreach (const AbstractMetaField* field, metaClass->fields()) - addInstantiatedContainers(field->type()); - foreach (AbstractMetaClass* innerClass, metaClass->innerClasses()) - collectInstantiatedContainers(innerClass); -} - -void Generator::collectInstantiatedContainers() -{ - foreach (const AbstractMetaFunction* func, globalFunctions()) - collectInstantiatedContainers(func); - foreach (const AbstractMetaClass* metaClass, classes()) - collectInstantiatedContainers(metaClass); -} - -QList<const AbstractMetaType*> Generator::instantiatedContainers() const -{ - return m_d->instantiatedContainers; -} - -QMap< QString, QString > Generator::options() const -{ - return QMap<QString, QString>(); -} - -AbstractMetaClassList Generator::classes() const -{ - return m_d->apiextractor->classes(); -} - -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('.') + 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; -} - -int Generator::numGeneratedAndWritten() const -{ - return m_d->numGeneratedWritten; -} - -void Generator::generate() -{ - foreach (AbstractMetaClass *cls, m_d->apiextractor->classes()) { - if (!shouldGenerate(cls)) - continue; - - QString fileName = fileNameForClass(cls); - if (fileName.isNull()) - continue; - ReportHandler::debugSparse(QString("generating: %1").arg(fileName)); - - FileOut fileOut(outputDirectory() + '/' + subDirectoryForClass(cls) + '/' + fileName); - generateClass(fileOut.stream, cls); - - if (fileOut.done()) - ++m_d->numGeneratedWritten; - ++m_d->numGenerated; - } - 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())) - ReportHandler::warning(QString("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("%TYPE", cpp_class->name()); - - foreach (AbstractMetaArgument *arg, func->arguments()) - code.replace("%" + QString::number(arg->argumentIndex() + 1), arg->name()); - - //template values - code.replace("%RETURN_TYPE", translateType(func->type(), cpp_class)); - code.replace("%FUNCTION_NAME", func->originalName()); - - if (code.contains("%ARGUMENT_NAMES")) { - QString str; - QTextStream aux_stream(&str); - writeArgumentNames(aux_stream, func, Generator::SkipRemovedArguments); - code.replace("%ARGUMENT_NAMES", str); - } - - if (code.contains("%ARGUMENTS")) { - QString str; - QTextStream aux_stream(&str); - writeFunctionArguments(aux_stream, func, Options(SkipDefaultValues) | SkipRemovedArguments); - code.replace("%ARGUMENTS", str); - } -} - -QTextStream& formatCode(QTextStream &s, const QString& code, Indentor &indentor) -{ - // detect number of spaces before the first character - QStringList lst(code.split("\n")); - QRegExp nonSpaceRegex("[^\\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("\\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()) { - const AbstractMetaClass* metaClass = classes().findClass(type); - if (metaClass) - 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() == "char"; -} - -bool Generator::isVoidPointer(const AbstractMetaType* type) -{ - return type->isNativePointer() - && type->indirections() == 1 - && type->name() == "void"; -} - -QString Generator::getFullTypeName(const TypeEntry* type) const -{ - return QString("%1%2").arg(type->isCppPrimitive() ? "" : "::").arg(type->qualifiedCppName()); -} - -QString Generator::getFullTypeName(const AbstractMetaType* type) const -{ - if (isCString(type)) - return "const char*"; - if (isVoidPointer(type)) - return "void*"; - if (type->typeEntry()->isContainer()) - return QString("::%1").arg(type->cppSignature()); - QString typeName; - if (type->typeEntry()->isComplex() && type->hasInstantiations()) - typeName = getFullTypeNameWithoutModifiers(type); - else - typeName = getFullTypeName(type->typeEntry()); - return typeName + QString("*").repeated(type->indirections()); -} - -QString Generator::getFullTypeName(const AbstractMetaClass* metaClass) const -{ - return QString("::%1").arg(metaClass->qualifiedCppName()); -} - -QString Generator::getFullTypeNameWithoutModifiers(const AbstractMetaType* type) const -{ - if (isCString(type)) - return "const char*"; - if (isVoidPointer(type)) - return "void*"; - if (!type->hasInstantiations()) - return getFullTypeName(type->typeEntry()); - QString typeName = type->cppSignature(); - if (type->isConstant()) - typeName.remove(0, sizeof("const ") / sizeof(char) - 1); - if (type->isReference()) - typeName.chop(1); - while (typeName.endsWith('*') || typeName.endsWith(' ')) - typeName.chop(1); - return QString("::%1").arg(typeName); -} - -QString Generator::minimalConstructor(const AbstractMetaType* type) const -{ - if (!type || (type->isReference() && Generator::isObjectType(type))) - return QString(); - - if (type->isContainer()) { - QString ctor = type->cppSignature(); - if (ctor.endsWith("*")) - return QString("0"); - if (ctor.startsWith("const ")) - ctor.remove(0, sizeof("const ") / sizeof(char) - 1); - if (ctor.endsWith("&")) { - ctor.chop(1); - ctor = ctor.trimmed(); - } - return QString("::%1()").arg(ctor); - } - - if (type->isNativePointer()) - return QString("((%1*)0)").arg(type->typeEntry()->qualifiedCppName()); - - if (Generator::isPointer(type)) - return QString("((::%1*)0)").arg(type->typeEntry()->qualifiedCppName()); - - if (type->typeEntry()->isComplex()) { - const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(type->typeEntry()); - QString ctor = cType->defaultConstructor(); - if (!ctor.isEmpty()) - return ctor; - ctor = minimalConstructor(classes().findClass(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()) - return QString("((%1)0)").arg(type->qualifiedCppName()); - - if (type->isEnum() || type->isFlags()) - return QString("((::%1)0)").arg(type->qualifiedCppName()); - - 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()) ? QString("::%1()").arg(type->qualifiedCppName()) : ctor; - } - - if (type->isComplex()) - return minimalConstructor(classes().findClass(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->isCopyConstructor()) - 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(); - QString fixedTypeName = QString("%1<%2 >").arg(qualifiedCppName).arg(templateTypes.join(", ")); - - // Empty constructor. - if (maxArgs == 0) - return QString("::%1()").arg(qualifiedCppName); - - 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->isCopyConstructor()) - 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("::%1(%2)").arg(qualifiedCppName).arg(args.join(", ")); - - 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("::%1(%2)").arg(qualifiedCppName) - .arg(args.join(", ")); - } - } - - 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 = "void"; - } else if (cType->isArray()) { - s = translateType(cType->arrayElementType(), context, options) + "[]"; - } else if (options & Generator::EnumAsInts && (cType->isEnum() || cType->isFlags())) { - s = "int"; - } else { - if (options & Generator::OriginalName) { - s = cType->originalTypeDescription().trimmed(); - if ((options & Generator::ExcludeReference) && s.endsWith("&")) - s = s.left(s.size()-1); - - // remove only the last const (avoid remove template const) - if (options & Generator::ExcludeConst) { - int index = s.lastIndexOf("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->setReference(false); - - s = copyType->cppSignature(); - if (!copyType->typeEntry()->isVoid() && !copyType->typeEntry()->isCppPrimitive()) - s.prepend("::"); - 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(".", 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('.'); - name.prepend(context->name()); - context = context->enclosingClass(); - } - if (includePackageName) { - name.prepend('.'); - 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); -} diff --git a/generators/generator.h b/generators/generator.h deleted file mode 100644 index 92f7219ca..000000000 --- a/generators/generator.h +++ /dev/null @@ -1,341 +0,0 @@ -/* - * This file is part of the API Extractor project. - * - * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: PySide team <contact@pyside.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef GENERATOR_H -#define GENERATOR_H - -#include <QtCore/QObject> -#include <QtCore/QDir> -#include <QtCore/QLinkedList> -#include <abstractmetalang.h> - -class ApiExtractor; -class AbstractMetaBuilder; -class QFile; - -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); - -/** - * 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 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 - */ - void generate(); - - /// Returns the number of generated items - int numGenerated() const; - - /// Returns the number of generated items written - int numGeneratedAndWritten() 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. - * \param metaClass the AbstractMetaClass for which the file name must be - * returned - * \return the file name used to write the binding code for the class - */ - virtual QString fileNameForClass(const AbstractMetaClass* metaClass) 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, const AbstractMetaClass* metaClass) = 0; - virtual void 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; - - static QString getSimplifiedContainerTypeName(const AbstractMetaType* type); - void addInstantiatedContainers(const AbstractMetaType* type); - -private: - struct GeneratorPrivate; - GeneratorPrivate* m_d; - void collectInstantiatedContainers(const AbstractMetaFunction* func); - void collectInstantiatedContainers(const AbstractMetaClass* metaClass); - void collectInstantiatedContainers(); -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(Generator::Options) -typedef QLinkedList<Generator*> GeneratorList; - -/** -* 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/generators/main.cpp b/generators/main.cpp deleted file mode 100644 index f9f94f7ac..000000000 --- a/generators/main.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/* - * This file is part of the PySide project. - * - * Copyright (C) 2009-2012 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: PySide team <contact@pyside.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <QCoreApplication> -#include <QLinkedList> -#include <QLibrary> -#include <QDomDocument> -#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(); - } - -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; -} - -} - -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("="); - QString key; - QString value; - if (split > 0) { - key = line.left(split - 1).trimmed(); - value = 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["arg-1"] = value; - else if (key == "typesystem-file") - args["arg-2"] = value; - else - args[key] = value; - } - - if (!includePaths.isEmpty()) - args["include-paths"] = includePaths.join(PATH_SPLITTER); - - if (!typesystemPaths.isEmpty()) - args["typesystem-paths"] = typesystemPaths.join(PATH_SPLITTER); - if (!apiVersions.isEmpty()) - args["api-version"] = apiVersions.join("|"); - 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("--project-file")) { - int split = arg.indexOf("="); - 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 (QString arg, arguments) { - arg = arg.trimmed(); - if (arg.startsWith("--")) { - int split = arg.indexOf("="); - 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("-")) { - args[arg.mid(1)] = QString(); - } else { - argNum++; - args[QString("arg-%1").arg(argNum)] = arg; - } - } - return args; -} - -void printUsage(const GeneratorList& generators) -{ - QTextStream s(stdout); - s << "Usage:\n " - << "shiboken [options] header-file typesystem-file\n\n" - << "General options:\n"; - QMap<QString, QString> generalOptions; - generalOptions.insert("project-file=<file>", "text file containing a description of the binding project. Replaces and overrides command line arguments"); - generalOptions.insert("debug-level=[sparse|medium|full]", "Set the debug level"); - generalOptions.insert("silent", "Avoid printing any message"); - generalOptions.insert("help", "Display this help and exit"); - generalOptions.insert("no-suppress-warnings", "Show all warnings"); - generalOptions.insert("output-directory=<path>", "The directory where the generated files will be written"); - generalOptions.insert("include-paths=<path>[" PATH_SPLITTER "<path>" PATH_SPLITTER "...]", "Include paths used by the C++ parser"); - generalOptions.insert("typesystem-paths=<path>[" PATH_SPLITTER "<path>" PATH_SPLITTER "...]", "Paths used when searching for typesystems"); - generalOptions.insert("documentation-only", "Do not generates any code, just the documentation"); - generalOptions.insert("license-file=<license-file>", "File used for copyright headers of generated files"); - generalOptions.insert("version", "Output version information and exit"); - generalOptions.insert("generator-set=<\"generator module\">", "generator-set to be used. e.g. qtdoc"); - generalOptions.insert("api-version=<\"package mask\">,<\"version\">", "Specify the supported api version used to generate the bindings"); - generalOptions.insert("drop-type-entries=\"<TypeEntry0>[;TypeEntry1;...]\"", "Semicolon separated list of type system entries (classes, namespaces, global functions and enums) to be dropped from generation."); - printOptions(s, generalOptions); - - foreach (Generator* 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) 2009-2012 Nokia Corporation and/or its subsidiary(-ies)" << std::endl; -} - -static inline void errorPrint(const QString& s, - const bool& verAndBanner = false) -{ - if (verAndBanner) - printVerAndBanner(); - - std::cerr << s.toAscii().constData() << std::endl; -} - -int main(int argc, char *argv[]) -{ - // needed by qxmlpatterns - QCoreApplication app(argc, argv); - - // Store command arguments in a map - QMap<QString, QString> args = getCommandLineArgs(); - ArgsHandler argsHandler(args); - GeneratorList generators; - - if (argsHandler.argExistsRemove("version")) { - printVerAndBanner(); - return EXIT_SUCCESS; - } - - QString generatorSet = argsHandler.removeArg("generator-set"); - // Also check "generatorSet" command line argument for backward compatibility. - if (generatorSet.isEmpty()) - generatorSet = argsHandler.removeArg("generatorSet"); - - // Pre-defined generator sets. - if (generatorSet == "qtdoc") { - generators << new QtDocGenerator; - } else if (generatorSet.isEmpty() || generatorSet == "shiboken") { - generators << new CppGenerator << new HeaderGenerator; - } else { - errorPrint("shiboken: Unknown generator set, try \"shiboken\" or \"qtdoc\"."); - return EXIT_FAILURE; - } - - if (argsHandler.argExistsRemove("help")) { - printUsage(generators); - return EXIT_SUCCESS; - } - - QString licenseComment; - QString licenseFileName = argsHandler.removeArg("license-file"); - if (!licenseFileName.isEmpty()) { - if (QFile::exists(licenseFileName)) { - QFile licenseFile(licenseFileName); - if (licenseFile.open(QIODevice::ReadOnly)) - licenseComment = licenseFile.readAll(); - } else { - errorPrint(QString("Couldn't find the file containing the license heading: %1"). - arg(qPrintable(licenseFileName))); - return EXIT_FAILURE; - } - } - - QString outputDirectory = argsHandler.removeArg("output-directory"); - if (outputDirectory.isEmpty()) - outputDirectory = "out"; - - if (!QDir(outputDirectory).exists()) { - if (!QDir().mkpath(outputDirectory)) { - ReportHandler::warning("Can't create output directory: "+outputDirectory); - return EXIT_FAILURE; - } - } - - // Create and set-up API Extractor - ApiExtractor extractor; - extractor.setLogDirectory(outputDirectory); - - if (argsHandler.argExistsRemove("silent")) { - extractor.setSilent(true); - } else { - QString level = argsHandler.removeArg("debug-level"); - if (!level.isEmpty()) { - if (level == "sparse") - extractor.setDebugLevel(ReportHandler::SparseDebug); - else if (level == "medium") - extractor.setDebugLevel(ReportHandler::MediumDebug); - else if (level == "full") - extractor.setDebugLevel(ReportHandler::FullDebug); - } - } - if (argsHandler.argExistsRemove("no-suppress-warnings")) - extractor.setSuppressWarnings(false); - - if (argsHandler.argExists("api-version")) { - QStringList versions = argsHandler.removeArg("api-version").split("|"); - foreach (QString fullVersion, versions) { - QStringList parts = fullVersion.split(","); - QString package; - QString version; - package = parts.count() == 1 ? "*" : parts.first(); - version = parts.last(); - extractor.setApiVersion(package, version.toAscii()); - } - } - - if (argsHandler.argExists("drop-type-entries")) - extractor.setDropTypeEntries(argsHandler.removeArg("drop-type-entries")); - - QString path = argsHandler.removeArg("typesystem-paths"); - if (!path.isEmpty()) - extractor.addTypesystemSearchPath(path.split(PATH_SPLITTER)); - - path = argsHandler.removeArg("include-paths"); - if (!path.isEmpty()) - extractor.addIncludePath(path.split(PATH_SPLITTER)); - - QString cppFileName = argsHandler.removeArg("arg-1"); - QString typeSystemFileName = argsHandler.removeArg("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("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 (Generator* 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("shiboken: Called with wrong arguments."); - std::cout << "Note: use --help option for more information." << std::endl; - return EXIT_FAILURE; - } - - extractor.setCppFileName(cppFileName); - extractor.setTypeSystem(typeSystemFileName); - if (!extractor.run()) - return EXIT_FAILURE; - - if (!extractor.classCount()) - ReportHandler::warning("No C++ classes found!"); - - foreach (Generator* g, generators) { - g->setOutputDirectory(outputDirectory); - g->setLicenseComment(licenseComment); - if (g->setup(extractor, args)) - g->generate(); - } - qDeleteAll(generators); - - ReportHandler::flush(); - std::cout << "Done, " << ReportHandler::warningCount(); - std::cout << " warnings (" << ReportHandler::suppressedCount() << " known issues)"; - std::cout << std::endl; -} diff --git a/generators/qtdoc/CMakeLists.txt b/generators/qtdoc/CMakeLists.txt deleted file mode 100644 index 541e7c6ee..000000000 --- a/generators/qtdoc/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -project(qtdoc_generator) - -set(qtdoc_generator_SRC -qtdocgenerator.cpp -) - -include_directories(${generators_SOURCE_DIR} - ${QT_QTCORE_INCLUDE_DIR} - ${APIEXTRACTOR_INCLUDE_DIR}) -add_executable(docgenerator main.cpp) -set_target_properties(docgenerator PROPERTIES OUTPUT_NAME docgenerator${generator_SUFFIX}) - -target_link_libraries(docgenerator ${QT_QTCORE_LIBRARY}) - -add_library(qtdoc_generator SHARED ${qtdoc_generator_SRC}) -target_link_libraries(qtdoc_generator ${APIEXTRACTOR_LIBRARY} ${QT_QTCORE_LIBRARY} genrunner) -set_property(TARGET qtdoc_generator PROPERTY PREFIX "") - -install(TARGETS qtdoc_generator DESTINATION ${generator_plugin_DIR}) -install(TARGETS docgenerator DESTINATION bin) - diff --git a/generators/qtdoc/qtdocgenerator.cpp b/generators/qtdoc/qtdocgenerator.cpp deleted file mode 100644 index 593456405..000000000 --- a/generators/qtdoc/qtdocgenerator.cpp +++ /dev/null @@ -1,1652 +0,0 @@ -/* - * This file is part of the PySide project. - * - * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: PySide team <contact@pyside.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "qtdocgenerator.h" -#include <reporthandler.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() == "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 += c; - - return out; -} - -static QString escape(QString& str) -{ - return str - .replace("*", "\\*") - .replace("_", "\\_"); -} - -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("heading", &QtXmlToSphinx::handleHeadingTag); - m_handlerMap.insert("brief", &QtXmlToSphinx::handleParaTag); - m_handlerMap.insert("para", &QtXmlToSphinx::handleParaTag); - m_handlerMap.insert("italic", &QtXmlToSphinx::handleItalicTag); - m_handlerMap.insert("bold", &QtXmlToSphinx::handleBoldTag); - m_handlerMap.insert("see-also", &QtXmlToSphinx::handleSeeAlsoTag); - m_handlerMap.insert("snippet", &QtXmlToSphinx::handleSnippetTag); - m_handlerMap.insert("dots", &QtXmlToSphinx::handleDotsTag); - m_handlerMap.insert("codeline", &QtXmlToSphinx::handleDotsTag); - m_handlerMap.insert("table", &QtXmlToSphinx::handleTableTag); - m_handlerMap.insert("header", &QtXmlToSphinx::handleRowTag); - m_handlerMap.insert("row", &QtXmlToSphinx::handleRowTag); - m_handlerMap.insert("item", &QtXmlToSphinx::handleItemTag); - m_handlerMap.insert("argument", &QtXmlToSphinx::handleArgumentTag); - m_handlerMap.insert("teletype", &QtXmlToSphinx::handleArgumentTag); - m_handlerMap.insert("link", &QtXmlToSphinx::handleLinkTag); - m_handlerMap.insert("inlineimage", &QtXmlToSphinx::handleImageTag); - m_handlerMap.insert("image", &QtXmlToSphinx::handleImageTag); - m_handlerMap.insert("list", &QtXmlToSphinx::handleListTag); - m_handlerMap.insert("term", &QtXmlToSphinx::handleTermTag); - m_handlerMap.insert("raw", &QtXmlToSphinx::handleRawTag); - m_handlerMap.insert("underline", &QtXmlToSphinx::handleItalicTag); - m_handlerMap.insert("superscript", &QtXmlToSphinx::handleSuperScriptTag); - m_handlerMap.insert("code", &QtXmlToSphinx::handleCodeTag); - m_handlerMap.insert("badcode", &QtXmlToSphinx::handleCodeTag); - m_handlerMap.insert("legalese", &QtXmlToSphinx::handleCodeTag); - m_handlerMap.insert("section", &QtXmlToSphinx::handleAnchorTag); - m_handlerMap.insert("quotefile", &QtXmlToSphinx::handleQuoteFileTag); - - // ignored tags - m_handlerMap.insert("generatedlist", &QtXmlToSphinx::handleIgnoredTag); - m_handlerMap.insert("tableofcontents", &QtXmlToSphinx::handleIgnoredTag); - m_handlerMap.insert("quotefromfile", &QtXmlToSphinx::handleIgnoredTag); - m_handlerMap.insert("skipto", &QtXmlToSphinx::handleIgnoredTag); - m_handlerMap.insert("target", &QtXmlToSphinx::handleIgnoredTag); - - // useless tags - m_handlerMap.insert("description", &QtXmlToSphinx::handleUselessTag); - m_handlerMap.insert("definition", &QtXmlToSphinx::handleUselessTag); - m_handlerMap.insert("printuntil", &QtXmlToSphinx::handleUselessTag); - m_handlerMap.insert("relation", &QtXmlToSphinx::handleUselessTag); - - // Doxygen tags - m_handlerMap.insert("title", &QtXmlToSphinx::handleHeadingTag); - m_handlerMap.insert("ref", &QtXmlToSphinx::handleParaTag); - m_handlerMap.insert("computeroutput", &QtXmlToSphinx::handleParaTag); - m_handlerMap.insert("detaileddescription", &QtXmlToSphinx::handleParaTag); - m_handlerMap.insert("name", &QtXmlToSphinx::handleParaTag); - m_handlerMap.insert("listitem", &QtXmlToSphinx::handleItemTag); - m_handlerMap.insert("parametername", &QtXmlToSphinx::handleItemTag); - m_handlerMap.insert("parameteritem", &QtXmlToSphinx::handleItemTag); - m_handlerMap.insert("ulink", &QtXmlToSphinx::handleLinkTag); - m_handlerMap.insert("itemizedlist", &QtXmlToSphinx::handleListTag); - m_handlerMap.insert("parameternamelist", &QtXmlToSphinx::handleListTag); - m_handlerMap.insert("parameterlist", &QtXmlToSphinx::handleListTag); - - // Doxygen ignored tags - m_handlerMap.insert("highlight", &QtXmlToSphinx::handleIgnoredTag); - m_handlerMap.insert("linebreak", &QtXmlToSphinx::handleIgnoredTag); - m_handlerMap.insert("programlisting", &QtXmlToSphinx::handleIgnoredTag); - m_handlerMap.insert("xreftitle", &QtXmlToSphinx::handleIgnoredTag); - m_handlerMap.insert("sp", &QtXmlToSphinx::handleIgnoredTag); - m_handlerMap.insert("entry", &QtXmlToSphinx::handleIgnoredTag); - m_handlerMap.insert("simplesect", &QtXmlToSphinx::handleIgnoredTag); - m_handlerMap.insert("verbatim", &QtXmlToSphinx::handleIgnoredTag); - m_handlerMap.insert("xrefsect", &QtXmlToSphinx::handleIgnoredTag); - m_handlerMap.insert("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('.'); - 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() + "." + functionSpec.join("."); - } else { - return function; - } -} - -QString QtXmlToSphinx::resolveContextForMethod(const QString& methodName) -{ - QString currentClass = m_context.split(".").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 QLatin1String("~") + 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()) { - m_output << INDENT << "XML Error: " + reader.errorString() + "\n" + doc; - ReportHandler::warning("XML Error: " + reader.errorString() + "\n" + doc); - 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('/'); - location.append(path); - result = readFromLocation(location, identifier, &ok); - if (ok) - break; - } - if (!ok) - ReportHandler::warning("Couldn't read code snippet file: {"+ locations.join("|") + '}' + 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) - ReportHandler::warning("Couldn't read code snippet file: "+inputFile.fileName()); - else - *ok = false; - return QString(); - } - - QRegExp searchString("//!\\s*\\[" + identifier + "\\]"); - QRegExp codeSnippetCode("//!\\s*\\[[\\w\\d\\s]+\\]"); - QString code; - QString line; - bool identifierIsEmpty = identifier.isEmpty(); - bool getCode = false; - - while (!inputFile.atEnd()) { - line = inputFile.readLine(); - if (identifierIsEmpty) { - code += line; - } else if (getCode && !line.contains(searchString)) { - code += line.replace(codeSnippetCode, ""); - } else if (line.contains(searchString)) { - if (getCode) - break; - else - getCode = true; - } - } - - if (!identifierIsEmpty && !getCode) - ReportHandler::warning("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("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("**Warning:**")) - result.replace(0, 12, ".. warning:: "); - else if (result.startsWith("**Note:**")) - result.replace(0, 9, ".. 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 == '*' || end == '`') && start != ' ' && !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) { - bool consecutiveSnippet = m_lastTagName == "snippet" || m_lastTagName == "dots" || m_lastTagName == "codeline"; - if (consecutiveSnippet) { - m_output.flush(); - m_output.string()->chop(2); - } - QString location = reader.attributes().value("location").toString(); - QString identifier = reader.attributes().value("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 (QString line, code.split("\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) { - bool consecutiveSnippet = m_lastTagName == "snippet" || m_lastTagName == "dots" || m_lastTagName == "codeline"; - if (consecutiveSnippet) { - m_output.flush(); - m_output.string()->chop(2); - } - Indentation indentation(INDENT); - pushOutputBuffer(); - m_output << INDENT; - int indent = reader.attributes().value("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("::", "."); - } 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("colspan").toString().toShort(); - cell.rowSpan = reader.attributes().value("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() == "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("type").toString(); - if (listType == "enum") { - m_currentTable << (TableRow() << "Constant" << "Description"); - m_tableHasHeader = true; - } - INDENT.indent--; - } else if (token == QXmlStreamReader::EndElement) { - INDENT.indent++; - if (!m_currentTable.isEmpty()) { - if (listType == "bullet") { - m_output << endl; - foreach (TableCell cell, m_currentTable.first()) { - QStringList itemLines = cell.data.split('\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 == "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 = "` "; - if (m_insideBold) { - l_linktag.prepend("**"); - l_linktagending.append("**"); - } else if (m_insideItalic) { - l_linktag.prepend('*'); - l_linktagending.append('*'); - } - l_type = reader.attributes().value("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 == "property") - l_type = "function"; - - if (l_type == "typedef") - l_type = "class"; - - QString linkSource; - if (l_type == "function" || l_type == "class") { - linkSource = "raw"; - } else if (l_type == "enum") { - linkSource = "enum"; - } else if (l_type == "page") { - linkSource = "page"; - } else { - linkSource = "href"; - } - - l_linkref = reader.attributes().value(linkSource).toString(); - l_linkref.replace("::", "."); - l_linkref.remove("()"); - - if (l_type == "function" && !m_context.isEmpty()) { - l_linktag = " :meth:`"; - QStringList rawlinklist = l_linkref.split("."); - if (rawlinklist.size() == 1 || rawlinklist.first() == m_context) { - QString context = resolveContextForMethod(rawlinklist.last()); - if (!l_linkref.startsWith(context)) - l_linkref.prepend(context + '.'); - } else { - l_linkref = expandFunction(l_linkref); - } - } else if (l_type == "function" && m_context.isEmpty()) { - l_linktag = " :func:`"; - } else if (l_type == "class") { - l_linktag = " :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("."); - QStringList splittedContext = m_context.split("."); - if (rawlinklist.size() == 1 || rawlinklist.first() == splittedContext.last()) { - splittedContext.removeLast(); - l_linkref.prepend('~' + splittedContext.join(".") + '.'); - } - } - } else if (l_type == "enum") { - l_linktag = " :attr:`"; - } else if (l_type == "page" && l_linkref == m_generator->moduleName()) { - l_linktag = " :mod:`"; - } else { - l_linktag = " :ref:`"; - } - - } else if (token == QXmlStreamReader::Characters) { - QString linktext = reader.text().toString(); - linktext.replace("::", "."); - QString item = l_linkref.split(".").last(); - if (l_linkref == linktext - || (l_linkref + "()") == linktext - || item == linktext - || (item + "()") == linktext) - l_linktext.clear(); - else - l_linktext = linktext + QLatin1String("<"); - } else if (token == QXmlStreamReader::EndElement) { - if (!l_linktext.isEmpty()) - l_linktagending.prepend('>'); - 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("href").toString(); - QDir dir(m_generator->outputDirectory() + '/' + m_generator->packageName().replace(".", "/")); - QString imgPath = dir.relativeFilePath(m_generator->libSourceDir() + "/doc/src/") + '/' + href; - - if (reader.name() == "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("format").toString(); - m_output << INDENT << ".. raw:: " << format.toLower() << endl << endl; - } else if (token == QXmlStreamReader::Characters) { - QStringList lst(reader.text().toString().split("\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("format").toString(); - m_output << INDENT << "::" << endl << endl; - INDENT.indent++; - } else if (token == QXmlStreamReader::Characters) { - QStringList lst(reader.text().toString().split("\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) - ReportHandler::warning("Unknow 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("id")) - anchor = reader.attributes().value("id").toString(); - else if (reader.attributes().hasAttribute("name")) - anchor = reader.attributes().value("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 = ""; - } -} - -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() + '/'); - 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("\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 += " " + 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()) { - ReportHandler::warning("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('\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('\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("+"); - for (int i = 0, max = colWidths.count(); i < max; ++i) { - horizontalLine += createRepeatedChar(colWidths[i], '-'); - horizontalLine += '+'; - } - - // 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('\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] : ""); - 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("operator+", "__add__"); - operatorsHash.insert("operator+=", "__iadd__"); - operatorsHash.insert("operator-", "__sub__"); - operatorsHash.insert("operator-=", "__isub__"); - operatorsHash.insert("operator*", "__mul__"); - operatorsHash.insert("operator*=", "__imul__"); - operatorsHash.insert("operator/", "__div__"); - operatorsHash.insert("operator/=", "__idiv__"); - operatorsHash.insert("operator%", "__mod__"); - operatorsHash.insert("operator%=", "__imod__"); - operatorsHash.insert("operator<<", "__lshift__"); - operatorsHash.insert("operator<<=", "__ilshift__"); - operatorsHash.insert("operator>>", "__rshift__"); - operatorsHash.insert("operator>>=", "__irshift__"); - operatorsHash.insert("operator&", "__and__"); - operatorsHash.insert("operator&=", "__iand__"); - operatorsHash.insert("operator|", "__or__"); - operatorsHash.insert("operator|=", "__ior__"); - operatorsHash.insert("operator^", "__xor__"); - operatorsHash.insert("operator^=", "__ixor__"); - operatorsHash.insert("operator==", "__eq__"); - operatorsHash.insert("operator!=", "__ne__"); - operatorsHash.insert("operator<", "__lt__"); - operatorsHash.insert("operator<=", "__le__"); - operatorsHash.insert("operator>", "__gt__"); - operatorsHash.insert("operator>=", "__ge__"); - hashInitialized = true; - } - - QHash<QString, QString>::const_iterator it = operatorsHash.find(cppFunc->name()); - QString result = it != operatorsHash.end() ? it.value() : cppFunc->name(); - return result.replace("::", "."); -} - -QtDocGenerator::QtDocGenerator() : m_docParser(0) -{ -} - -QtDocGenerator::~QtDocGenerator() -{ - delete m_docParser; -} - -QString QtDocGenerator::fileNameForClass(const AbstractMetaClass* cppClass) const -{ - return QString("%1.rst").arg(getClassTargetFullName(cppClass, false)); -} - -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("\n"); - QRegExp regex("\\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 << QString(":ref:`%1`").arg(getClassTargetFullName(c, false)); - s << classes.join(", ") << endl << endl; -} - -void QtDocGenerator::generateClass(QTextStream& s, const AbstractMetaClass* metaClass) -{ - ReportHandler::debugSparse("Generating Documentation for " + metaClass->fullName()); - - m_packages[metaClass->package()] << fileNameForClass(metaClass); - - 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, DocModification::Prepend, metaClass, 0); - if (!writeInjectDocumentation(s, DocModification::Replace, 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, DocModification::Append, 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) + '.'; - else if (func->implementingClass() && func->implementingClass()->enclosingClass()) - className = getClassTargetFullName(func->implementingClass()->enclosingClass()) + '.'; - QString funcName = getFuncName(func); - - QString str("def :meth:`"); - - str += funcName; - str += '<'; - if (!funcName.startsWith(className)) - str += className; - str += funcName; - str += ">` ("; - str += parseArgDocStyle(cppClass, func); - str += ')'; - - 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, "Functions", functionList); - writeFunctionBlock(s, "Virtual functions", virtualList); - writeFunctionBlock(s, "Slots", slotList); - writeFunctionBlock(s, "Signals", signalList); - writeFunctionBlock(s, "Static functions", staticFunctionList); - } -} - -void QtDocGenerator::writeFunctionBlock(QTextStream& s, const QString& title, QStringList& functions) -{ - if (functions.size() > 0) { - s << title << endl - << QString('^').repeated(title.size()) << 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(".. 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(".. 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 = ".. class:: "; - static const QString sectionTitleSpace = QString(sectionTitle.size(), ' '); - - 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 += '['; - optArgs++; - } - - if (arg->argumentIndex() > 0) - ret += ", "; - - ret += arg->name(); - - if (thisIsoptional) { - QString defValue = arg->defaultValueExpression(); - if (defValue == "QString()") { - defValue = "\"\""; - } else if (defValue == "QStringList()" || defValue.startsWith("QVector") || defValue.startsWith("QList")) { - defValue = "list()"; - } else if (defValue == "QVariant()") { - defValue = "None"; - } else { - defValue.replace("::", "."); - if (defValue == "0" && (arg->type()->isQObject() || arg->type()->isObject())) - defValue = "None"; - } - ret += "=" + defValue; - } - } - - ret += QString(']').repeated(optArgs); - return ret; -} - -void QtDocGenerator::writeDocSnips(QTextStream &s, - const CodeSnipList &codeSnips, - CodeSnip::Position position, - TypeSystem::Language language) -{ - Indentation indentation(INDENT); - QStringList invalidStrings; - const static QString startMarkup("[sphinx-begin]"); - const static QString endMarkup("[sphinx-end]"); - - invalidStrings << "*" << "//" << "/*" << "*/"; - - 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("\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] == ' ') - offset++; - else if (row[i] == '\n') - offset = 0; - else - break; - } - } - row = row.mid(offset); - s << row << endl; - currenRow++; - } - - code = code.mid(endBlock+endMarkup.size()); - } - } -} - -bool QtDocGenerator::writeInjectDocumentation(QTextStream& s, - DocModification::Mode 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. - if (func) { - writeDocSnips(s, func->injectedCodeSnips(), - (mode == DocModification::Prepend ? CodeSnip::Beginning : CodeSnip::End), - TypeSystem::TargetLangCode); - } else { - writeDocSnips(s, cppClass->typeEntry()->codeSnips(), - (mode == DocModification::Prepend ? CodeSnip::Beginning : CodeSnip::End), - TypeSystem::TargetLangCode); - } - return didSomething; -} - -void QtDocGenerator::writeFunctionSignature(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func) -{ - QString className; - if (!func->isConstructor()) - className = getClassTargetFullName(cppClass) + '.'; - else if (func->implementingClass() && func->implementingClass()->enclosingClass()) - className = getClassTargetFullName(func->implementingClass()->enclosingClass()) + '.'; - - 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() == "QString") { - strType = "unicode"; - } else if (type->name() == "QVariant") { - strType = "object"; - } else if (type->name() == "QStringList") { - strType = "list of strings"; - } else if (type->isConstant() && type->name() == "char" && type->indirections() == 1) { - strType = "str"; - } else if (type->name().startsWith("unsigned short")) { - strType = "int"; - } else if (type->name().startsWith("unsigned ")) { // uint and ulong - strType = "long"; - } else if (type->isContainer()) { - QString strType = translateType(type, cppClass, Options(ExcludeConst) | ExcludeReference); - strType.remove("*"); - strType.remove(">"); - strType.remove("<"); - strType.replace("::", "."); - if (strType.contains("QList") || strType.contains("QVector")) { - strType.replace("QList", "list of "); - strType.replace("QVector", "list of "); - } else if (strType.contains("QHash") || strType.contains("QMap")) { - strType.remove("QHash"); - strType.remove("QMap"); - QStringList types = strType.split(","); - strType = QString("Dictionary with keys of type %1 and values of type %2.") - .arg(types[0]).arg(types[1]); - } - } else { - QString refTag; - if (type->isEnum()) - refTag = "attr"; - else - refTag = "class"; - strType = ':' + refTag + ":`" + type->fullName() + '`'; - } - 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, DocModification::Prepend, cppClass, func); - if (!writeInjectDocumentation(s, DocModification::Replace, cppClass, func)) - writeFormatedText(s, func->documentation(), cppClass); - writeInjectDocumentation(s, DocModification::Append, cppClass, func); - } -} - -static void writeFancyToc(QTextStream& s, const QStringList& items, int cols = 4) -{ - typedef QMap<QChar, QStringList> TocMap; - TocMap tocMap; - QChar Q('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(¤tColData); - 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; -} - -void QtDocGenerator::finishGeneration() -{ - if (classes().isEmpty()) - return; - - QMap<QString, QStringList>::iterator it = m_packages.begin(); - for (; it != m_packages.end(); ++it) { - QString outputDir = outputDirectory() + '/' + QString(it.key()).replace(".", "/"); - FileOut output(outputDir + "/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() + "?*.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 + '/' + *it2; - if (QFile::exists(newFilePath)) - QFile::remove(newFilePath); - if (!QFile::copy(m_extraSectionDir + '/' + origFileName, newFilePath)) { - ReportHandler::warning("Error copying extra doc " + (m_extraSectionDir + '/' + origFileName) - + " to " + 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 + '/' + it.key() + ".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) { - QtXmlToSphinx x(this, moduleDoc.value(), QString(it.key()).remove(0, it.key().lastIndexOf('.') + 1)); - s << x; - } else { - s << moduleDoc.value(); - } - } - } -} - -bool QtDocGenerator::doSetup(const QMap<QString, QString>& args) -{ - m_libSourceDir = args.value("library-source-dir"); - m_docDataDir = args.value("documentation-data-dir"); -#ifdef __WIN32__ -# define PATH_SEP ";" -#else -# define PATH_SEP ":" -#endif - m_codeSnippetDirs = args.value("documentation-code-snippets-dir", m_libSourceDir).split(PATH_SEP); - m_extraSectionDir = args.value("documentation-extra-sections-dir"); - - m_docParser = args.value("doc-parser") == "doxygen" ? reinterpret_cast<DocParser*>(new DoxygenParser) : reinterpret_cast<DocParser*>(new QtDocParser); - ReportHandler::warning("doc-parser: " + args.value("doc-parser")); - - if (m_libSourceDir.isEmpty() || m_docDataDir.isEmpty()) { - ReportHandler::warning("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("doc-parser", "The documentation parser used to interpret the documentaion input files (qdoc3|doxygen)"); - options.insert("library-source-dir", "Directory where library source code is located"); - options.insert("documentation-data-dir", "Directory with XML files generated by documentation tool (qdoc3 or Doxygen)"); - options.insert("documentation-code-snippets-dir", "Directory used to search code snippets used by the documentation"); - options.insert("documentation-extra-sections-dir", "Directory used to search for extra documentation sections"); - return options; -} - diff --git a/generators/qtdoc/qtdocgenerator.h b/generators/qtdoc/qtdocgenerator.h deleted file mode 100644 index 247b48363..000000000 --- a/generators/qtdoc/qtdocgenerator.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - * This file is part of the PySide project. - * - * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: PySide team <contact@pyside.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ -#ifndef DOCGENERATOR_H -#define DOCGENERATOR_H - -#include <QtCore/QStack> -#include <QtCore/QHash> -#include <QtCore/QTextStream> -#include <QXmlStreamReader> -#include <abstractmetalang.h> -#include "generator.h" -#include "docparser.h" - -class QtDocParser; -class AbstractMetaFunction; -class AbstractMetaClass; -class QXmlStreamReader; -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(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 fileNameForClass(const AbstractMetaClass* cppClass) const; - void generateClass(QTextStream& s, const AbstractMetaClass* metaClass); - void 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, DocModification::Mode mode, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func); - void writeDocSnips(QTextStream &s, const CodeSnipList &codeSnips, CodeSnip::Position 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/generators/shiboken/CMakeLists.txt b/generators/shiboken/CMakeLists.txt deleted file mode 100644 index 57aac33ad..000000000 --- a/generators/shiboken/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -project(shibokengenerator) - -set(shiboken_SRC -../generator.cpp -cppgenerator.cpp -headergenerator.cpp -overloaddata.cpp -shibokengenerator.cpp -shibokennormalize.cpp -main.cpp -) - -include_directories(${generators_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} - ${APIEXTRACTOR_INCLUDE_DIR} - ${QT_INCLUDE_DIR} - ${QT_QTCORE_INCLUDE_DIR} - ${QT_QTXML_INCLUDE_DIR}) - -add_executable(shiboken ${shiboken_SRC}) -set_target_properties(shiboken PROPERTIES OUTPUT_NAME shiboken${shiboken_SUFFIX}) -target_link_libraries(shiboken - ${APIEXTRACTOR_LIBRARY} - ${QT_QTCORE_LIBRARY} - ${QT_QTXML_LIBRARY}) - -configure_file(shibokenconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/shibokenconfig.h" @ONLY) - -install(TARGETS shiboken DESTINATION bin) diff --git a/generators/shiboken/cppgenerator.cpp b/generators/shiboken/cppgenerator.cpp deleted file mode 100644 index fa19f7a3d..000000000 --- a/generators/shiboken/cppgenerator.cpp +++ /dev/null @@ -1,5125 +0,0 @@ -/* - * This file is part of the Shiboken Python Bindings Generator project. - * - * Copyright (C) 2009-2012 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: PySide team <contact@pyside.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <memory> - -#include "cppgenerator.h" -#include "shibokennormalize_p.h" -#include <reporthandler.h> -#include <typedatabase.h> - -#include <QtCore/QDir> -#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("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["__add__"] = "nb_add"; - m_nbFuncs["__sub__"] = "nb_subtract"; - m_nbFuncs["__mul__"] = "nb_multiply"; - m_nbFuncs["__div__"] = "nb_divide"; - m_nbFuncs["__mod__"] = "nb_remainder"; - m_nbFuncs["__neg__"] = "nb_negative"; - m_nbFuncs["__pos__"] = "nb_positive"; - m_nbFuncs["__invert__"] = "nb_invert"; - m_nbFuncs["__lshift__"] = "nb_lshift"; - m_nbFuncs["__rshift__"] = "nb_rshift"; - m_nbFuncs["__and__"] = "nb_and"; - m_nbFuncs["__xor__"] = "nb_xor"; - m_nbFuncs["__or__"] = "nb_or"; - m_nbFuncs["__iadd__"] = "nb_inplace_add"; - m_nbFuncs["__isub__"] = "nb_inplace_subtract"; - m_nbFuncs["__imul__"] = "nb_multiply"; - m_nbFuncs["__idiv__"] = "nb_divide"; - m_nbFuncs["__imod__"] = "nb_remainder"; - m_nbFuncs["__ilshift__"] = "nb_inplace_lshift"; - m_nbFuncs["__irshift__"] = "nb_inplace_rshift"; - m_nbFuncs["__iand__"] = "nb_inplace_and"; - m_nbFuncs["__ixor__"] = "nb_inplace_xor"; - m_nbFuncs["__ior__"] = "nb_inplace_or"; - m_nbFuncs["bool"] = "nb_nonzero"; - - // sequence protocol functions - typedef QPair<QString, QString> StrPair; - m_sequenceProtocol.insert("__len__", StrPair("PyObject* " PYTHON_SELF_VAR, "Py_ssize_t")); - m_sequenceProtocol.insert("__getitem__", StrPair("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i", "PyObject*")); - m_sequenceProtocol.insert("__setitem__", StrPair("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i, PyObject* _value", "int")); - m_sequenceProtocol.insert("__getslice__", StrPair("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i1, Py_ssize_t _i2", "PyObject*")); - m_sequenceProtocol.insert("__setslice__", StrPair("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i1, Py_ssize_t _i2, PyObject* _value", "int")); - m_sequenceProtocol.insert("__contains__", StrPair("PyObject* " PYTHON_SELF_VAR ", PyObject* _value", "int")); - m_sequenceProtocol.insert("__concat__", StrPair("PyObject* " PYTHON_SELF_VAR ", PyObject* _other", "PyObject*")); - - // Sequence protocol structure members names - m_sqFuncs["__concat__"] = "sq_concat"; - m_sqFuncs["__contains__"] = "sq_contains"; - m_sqFuncs["__getitem__"] = "sq_item"; - m_sqFuncs["__getslice__"] = "sq_slice"; - m_sqFuncs["__len__"] = "sq_length"; - m_sqFuncs["__setitem__"] = "sq_ass_item"; - m_sqFuncs["__setslice__"] = "sq_ass_slice"; - - // mapping protocol function - m_mappingProtocol.insert("__mlen__", StrPair("PyObject* " PYTHON_SELF_VAR, "Py_ssize_t")); - m_mappingProtocol.insert("__mgetitem__", StrPair("PyObject* " PYTHON_SELF_VAR ", PyObject* _key", "PyObject*")); - m_mappingProtocol.insert("__msetitem__", StrPair("PyObject* " PYTHON_SELF_VAR ", PyObject* _key, PyObject* _value", "int")); - - // Sequence protocol structure members names - m_mpFuncs["__mlen__"] = "mp_length"; - m_mpFuncs["__mgetitem__"] = "mp_subscript"; - m_mpFuncs["__msetitem__"] = "mp_ass_subscript"; -} - -QString CppGenerator::fileNameForClass(const AbstractMetaClass *metaClass) const -{ - return metaClass->qualifiedCppName().toLower().replace("::", "_") + QLatin1String("_wrapper.cpp"); -} - -QList<AbstractMetaFunctionList> CppGenerator::filterGroupedOperatorFunctions(const AbstractMetaClass* metaClass, - uint query) -{ - // ( func_name, num_args ) => func_list - QMap<QPair<QString, int >, AbstractMetaFunctionList> results; - foreach (AbstractMetaFunction* func, metaClass->operatorOverloads(query)) { - if (func->isModifiedRemoved() || func->name() == "operator[]" || func->name() == "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("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->aliasedTypeEntry()) - pte = pte->aliasedTypeEntry(); - return func && func->isConstant() && pte->name() == "bool" && func->arguments().isEmpty(); -} - -/*! - 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, const AbstractMetaClass *metaClass) -{ - ReportHandler::debugSparse("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 << "#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 << "#include \"" << getModuleHeaderFileName() << '"' << endl << endl; - - QString headerfile = fileNameForClass(metaClass); - headerfile.replace(".cpp", ".h"); - s << "#include \"" << headerfile << '"' << endl; - foreach (AbstractMetaClass* innerClass, metaClass->innerClasses()) { - if (shouldGenerate(innerClass)) { - QString headerfile = fileNameForClass(innerClass); - headerfile.replace(".cpp", ".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 (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; - - // class inject-code native/beginning - if (!metaClass->typeEntry()->codeSnips().isEmpty()) { - writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), CodeSnip::Beginning, 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, metaClass); - s << "}\n\n"; - } - - foreach (const AbstractMetaFunction* func, filterFunctions(metaClass)) { - if ((func->isPrivate() && !visibilityModifiedToPrivate(func)) - || (func->isModifiedRemoved() && !func->isAbstract())) - continue; - if (func->isConstructor() && !func->isCopyConstructor() && !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; - foreach (AbstractMetaFunctionList allOverloads, getFunctionGroups(metaClass).values()) { - AbstractMetaFunctionList overloads; - foreach (AbstractMetaFunction* func, allOverloads) { - if (!func->isAssignmentOperator() - && !func->isCastOperator() - && !func->isModifiedRemoved() - && (!func->isPrivate() || func->functionType() == AbstractMetaFunction::EmptyFunction) - && func->ownerClass() == func->implementingClass() - && (func->name() != "qt_metacall")) - overloads.append(func); - } - - if (overloads.isEmpty()) - continue; - - const AbstractMetaFunction* rfunc = overloads.first(); - if (m_sequenceProtocol.contains(rfunc->name()) || m_mappingProtocol.contains(rfunc->name())) - continue; - - if (rfunc->isConstructor()) - writeConstructorWrapper(s, overloads); - // call operators - else if (rfunc->name() == "operator()") - writeMethodWrapper(s, overloads); - else if (!rfunc->isOperatorOverload()) { - writeMethodWrapper(s, overloads); - 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).replace(QRegExp("_Type$"), ""); - - if (metaClass->typeEntry()->isValue()) - writeCopyFunction(s, metaClass); - - // Write single method definitions - s << singleMethodDefinitions; - - // Write methods definition - s << "static PyMethodDef " << className << "_methods[] = {" << endl; - s << methodsDefinitions << endl; - if (metaClass->typeEntry()->isValue()) - 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() == "QObject") { - writeGetattroFunction(s, metaClass); - s << endl; - writeSetattroFunction(s, metaClass); - s << endl; - } else if (classNeedsGetattroFunction(metaClass)) { - writeGetattroFunction(s, metaClass); - s << endl; - } - - if (hasBoolCast(metaClass)) { - ErrorCode errorCode(-1); - s << "static int " << cpythonBaseName(metaClass) << "___nb_bool(PyObject* " PYTHON_SELF_VAR ")" << endl; - s << '{' << endl; - writeCppSelfDefinition(s, metaClass); - 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)) { - QList<AbstractMetaFunctionList> opOverloads = filterGroupedOperatorFunctions( - metaClass, - AbstractMetaClass::ArithmeticOp - | AbstractMetaClass::LogicalOp - | AbstractMetaClass::BitwiseOp); - - foreach (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); - } - } - - if (supportsSequenceProtocol(metaClass)) { - writeSequenceMethods(s, metaClass); - } - - if (supportsMappingProtocol(metaClass)) { - writeMappingMethods(s, metaClass); - } - - if (metaClass->hasComparisonOperatorOverload()) { - s << "// Rich comparison" << endl; - writeRichCompareFunction(s, metaClass); - } - - if (shouldGenerateGetSetList(metaClass)) { - foreach (const AbstractMetaField* metaField, metaClass->fields()) { - if (metaField->isStatic()) - continue; - writeGetterFunction(s, metaField); - if (!metaField->type()->isConstant()) - writeSetterFunction(s, metaField); - 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) : "0"); - s << "}," << endl; - } - s << INDENT << "{0} // Sentinel" << endl; - s << "};" << endl << endl; - } - - s << "} // extern \"C\"" << endl << endl; - - if (!metaClass->typeEntry()->hashFunction().isEmpty()) - writeHashFunction(s, metaClass); - - // Write tp_traverse and tp_clear functions. - writeTpTraverseFunction(s, metaClass); - writeTpClearFunction(s, metaClass); - - writeClassDefinition(s, metaClass); - 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); - writeClassRegister(s, metaClass); - - // class inject-code native/end - if (!metaClass->typeEntry()->codeSnips().isEmpty()) { - writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), CodeSnip::End, TypeSystem::NativeCode, metaClass); - s << endl; - } -} - -void CppGenerator::writeConstructorNative(QTextStream& s, const AbstractMetaFunction* func) -{ - Indentation indentation(INDENT); - s << functionSignature(func, wrapperName(func->ownerClass()) + "::", "", - OriginalTypeDescription | SkipDefaultValues); - s << " : "; - writeFunctionCall(s, func); - s << " {" << endl; - const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last(); - writeCodeSnips(s, func->injectedCodeSnips(), CodeSnip::Beginning, TypeSystem::NativeCode, func, lastArg); - s << INDENT << "// ... middle" << endl; - writeCodeSnips(s, func->injectedCodeSnips(), CodeSnip::End, 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 "\"\""; - - if (!func->typeReplaced(0).isEmpty()) - return '"' + func->typeReplaced(0) + '"'; - - // SbkType would return null when the type is a container. - if (func->type()->typeEntry()->isContainer()) - return '"' + reinterpret_cast<const ContainerTypeEntry*>(func->type()->typeEntry())->typeName() + '"'; - - if (avoidProtectedHack()) { - const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(func->type()); - if (metaEnum && metaEnum->isProtected()) - return '"' + protectedEnumSurrogateName(metaEnum) + '"'; - } - - if (func->type()->isPrimitive()) - return '"' + func->type()->name() + '"'; - - return QString("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() == "metaObject") || (func->name() == "qt_metacall"))) - return; - - const TypeEntry* retType = func->type() ? func->type()->typeEntry() : 0; - const QString funcName = func->isOperatorOverload() ? pythonOperatorFunctionName(func) : func->name(); - - QString prefix = QString("%1::").arg(wrapperName(func->ownerClass())); - s << functionSignature(func, prefix, "", Generator::SkipDefaultValues|Generator::OriginalTypeDescription) << endl; - s << '{' << endl; - - Indentation indentation(INDENT); - - QString defaultReturnExpr; - if (retType) { - foreach (FunctionModification mod, func->modifications()) { - foreach (ArgumentModification argMod, mod.argument_mods) { - if (argMod.index == 0 && !argMod.replacedDefaultExpression.isEmpty()) { - QRegExp regex("%(\\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()) { - ReportHandler::warning("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 = QString(MIN_CTOR_ERROR_MSG).arg(func->type()->cppSignature()); - ReportHandler::warning(errorMsg); - s << endl << INDENT << "#error " << errorMsg << endl; - } - } - - if (func->isAbstract() && func->isModifiedRemoved()) { - ReportHandler::warning(QString("Pure virtual method '%1::%2' must be implement but was "\ - "completely removed on type system.") - .arg(func->ownerClass()->name()) - .arg(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, CodeSnip::Declaration, 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, CodeSnip::Beginning, 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 : ""); - } else { - s << INDENT << "gil.release();" << endl; - s << INDENT << "return this->::" << func->implementingClass()->qualifiedCppName() << "::"; - writeFunctionCall(s, func, Generator::VirtualCall); - } - } - 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()->isReference(); - - if (!convert && argType->isPrimitive()) { - if (argType->basicAliasedTypeEntry()) - argType = argType->basicAliasedTypeEntry(); - convert = !m_formatUnits.contains(argType->name()); - } - - Indentation indentation(INDENT); - ac << INDENT; - if (!func->conversionRule(TypeSystem::TargetLangCode, arg->argumentIndex() + 1).isEmpty()) { - // Has conversion rule. - ac << QString("%1"CONV_RULE_OUT_VAR_SUFFIX).arg(arg->name()); - } 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(",\n") << endl; - s << INDENT << "));" << endl; - } - - bool invalidateReturn = false; - foreach (FunctionModification funcMod, func->modifications()) { - foreach (ArgumentModification argMod, funcMod.argument_mods) { - if (argMod.resetAfterUse) { - 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, CodeSnip::Beginning, 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) != "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(), 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, CPP_RETURN_VAR); - } else if (!injectedCodeHasReturnValueAttribution(func, TypeSystem::NativeCode)) { - writePythonToCppTypeConversion(s, func->type(), PYTHON_RETURN_VAR, 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 (FunctionModification funcMod, func->modifications()) { - foreach (ArgumentModification argMod, funcMod.argument_mods) { - if (argMod.resetAfterUse) { - s << INDENT << "if (invalidateArg" << argMod.index << ')' << endl; - Indentation indentation(INDENT); - s << INDENT << "Shiboken::Object::invalidate(PyTuple_GET_ITEM(" PYTHON_ARGS ", "; - s << (argMod.index - 1) << "));" << endl; - } else 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, CodeSnip::End, 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 += QString("::%1").arg(metaEnum->enclosingClass()->qualifiedCppName()); - typeCast += QString("::%1").arg(metaEnum->name()); - s << '(' << typeCast << ')'; - } - } - if (func->type()->isReference() && !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 QT_VERSION >= 0x040700" << endl; - s << INDENT << "if (QObject::d_ptr->metaObject) return QObject::d_ptr->metaObject;" << endl; - s << INDENT << "#endif" << endl; - s << INDENT << "SbkObject* pySelf = Shiboken::BindingManager::instance().retrieveWrapper(this);" << 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("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, CodeSnip::Any, 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() ? "flag" : "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(PySide::QFlags::getValue(reinterpret_cast<PySideQFlagsObject*>(pyIn))))"; - else - c << "(" << cppTypeName << ") Shiboken::Enum::getValue(pyIn)"; - c << ';' << endl; - writePythonToCppFunction(s, code, typeName, typeName); - - QString pyTypeCheck = QString("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(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(PyLong_AsLong(pyLong.object())));" << endl; - writePythonToCppFunction(s, code, "number", flagsTypeName); - writeIsPythonConvertibleToCppFunction(s, "number", flagsTypeName, "PyNumber_Check(pyIn)"); -} - -void CppGenerator::writeConverterFunctions(QTextStream& s, const AbstractMetaClass* metaClass) -{ - 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 = getFullTypeName(metaClass); - 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 = QString("%1_PTR").arg(metaClass->name()); - 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 = QString("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(); - 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()) { - 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; - sourceTypeName = QString("%1_COPY").arg(metaClass->name()); - targetTypeName = metaClass->name(); - code.clear(); - c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType << ", new ::" << wrapperName(metaClass); - c << "(*((" << typeName << "*)cppIn)), true, true);"; - writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName); - s << endl; - - // Python to C++ copy conversion. - s << "// Python to C++ copy conversion." << endl; - sourceTypeName = metaClass->name(); - targetTypeName = QString("%1_COPY").arg(sourceTypeName); - code.clear(); - c << INDENT << "*((" << typeName << "*)cppOut) = *" << cpythonWrapperCPtr(metaClass->typeEntry(), "pyIn") << ';'; - 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 = QString("PyObject_TypeCheck(pyIn, %1)").arg(cpythonTypeNameExt(sourceClass->typeEntry())); - toCppConv = QString("*%1").arg(cpythonWrapperCPtr(sourceClass->typeEntry(), "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 += '('; - } - if (isWrapperType(sourceType)) { - typeCheck = QString("%1pyIn)").arg(typeCheck); - toCppConv = QString("%1%2") - .arg((sourceType->isReference() || !isPointerToWrapperType(sourceType)) ? "*" : "") - .arg(cpythonWrapperCPtr(sourceType->typeEntry(), "pyIn")); - } else if (typeCheck.contains("%in")) { - typeCheck.replace("%in", "pyIn"); - typeCheck = QString("%1)").arg(typeCheck); - } else { - typeCheck = QString("%1pyIn)").arg(typeCheck); - } - - 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, "pyIn", "cppIn"); - pc << ';'; - toCppConv.append("cppIn"); - } else if (!isWrapperType(sourceType)) { - QTextStream tcc(&toCppConv); - writeToCppConversion(tcc, sourceType, metaClass, "pyIn", "/*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) -{ - 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 = QString("%1_PTR").arg(metaClass->name()); - 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()) { - s << ',' << endl; - sourceTypeName = QString("%1_COPY").arg(metaClass->name()); - s << INDENT << cppToPythonFunctionName(sourceTypeName, targetTypeName); - } - } - s << ");" << endl; - - s << endl; - - QStringList cppSignature = metaClass->qualifiedCppName().split("::", QString::SkipEmptyParts); - while (!cppSignature.isEmpty()) { - QString signature = cppSignature.join("::"); - 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(::"; - s << metaClass->qualifiedCppName() << ").name());" << endl; - if (shouldGenerateCppWrapper(metaClass)) { - s << INDENT << "Shiboken::Conversions::registerConverterName(converter, typeid(::"; - s << wrapperName(metaClass) << ").name());" << endl; - } - - s << endl; - - if (!metaClass->typeEntry()->isValue()) - 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 = QString("%1_COPY").arg(metaClass->name()); - QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName); - QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName); - writeAddPythonToCppConversion(s, "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, "converter", toCpp, isConv); - } - - writeCustomConverterRegister(s, customConversion, "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) -{ - 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< ::"; - s << ownerClass->qualifiedCppName() << " >()))" << endl; - Indentation indent(INDENT); - s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl; - } - // Declare pointer for the underlying C++ object. - s << INDENT << "::"; - s << (shouldGenerateCppWrapper(ownerClass) ? wrapperName(ownerClass) : ownerClass->qualifiedCppName()); - s << "* cptr = 0;" << endl; - - initPythonArguments = maxArgs > 0; - usesNamedArguments = !ownerClass->isQObject() && overloadData.hasArgumentWithDefaultValue(); - - } else { - if (rfunc->implementingClass() && - (!rfunc->implementingClass()->isNamespace() && overloadData.hasInstanceFunction())) { - writeCppSelfDefinition(s, rfunc, 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(", 0").repeated(maxArgs-1) << " }"; - s << ';' << endl; - writeUnusedVariableCast(s, 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) -{ - 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("\", \"") << "\"};" << 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); - - s << endl; - - if (overloadData.maxArgs() > 0) - writeOverloadedFunctionDecisor(s, overloadData); - - writeFunctionCalls(s, overloadData); - 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; - 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 (CodeSnip cs, func->injectedCodeSnips()) { - if (cs.position == CodeSnip::End) { - 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 (CodeSnip cs, func->injectedCodeSnips()) { - if (cs.position == CodeSnip::End) { - s << INDENT << "case " << metaClass->functions().indexOf(func) << ':' << endl; - s << INDENT << '{' << endl; - { - Indentation indent(INDENT); - writeCodeSnips(s, func->injectedCodeSnips(), CodeSnip::End, 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) -{ - 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); - - 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, '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); - - 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, '0').split("", QString::SkipEmptyParts).join(", ") << "};" << 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 << QString("numArgs == %1").arg(i); - if (usesNamedArguments && (!ownerClassIsQObject || minArgs > 0)) - s << " else "; - else - s << INDENT; - s << "if (" << invArgsLen.join(" || ") << ")" << 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() ? "nonvarargs" : "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("&(" PYTHON_ARGS "[%1])").arg(i); - s << ", " << palist.join(", ") << "))" << endl; - { - Indentation indent(INDENT); - s << INDENT << "return " << m_currentErrorCode << ';' << endl; - } - s << endl; -} - -void CppGenerator::writeCppSelfDefinition(QTextStream& s, const AbstractMetaClass* metaClass, bool hasStaticOverload, bool cppSelfAsReference) -{ - bool useWrapperClass = avoidProtectedHack() && metaClass->hasProtectedMembers(); - QString className = useWrapperClass ? wrapperName(metaClass) : QString("::%1").arg(metaClass->qualifiedCppName()); - - QString cppSelfAttribution; - if (cppSelfAsReference) { - QString cast = useWrapperClass ? QString("(%1*)").arg(className) : QString(); - cppSelfAttribution = QString("%1& %2 = *(%3%4)") - .arg(className) - .arg(CPP_SELF_VAR) - .arg(cast) - .arg(cpythonWrapperCPtr(metaClass, PYTHON_SELF_VAR)); - } else { - s << INDENT << className << "* " CPP_SELF_VAR " = 0;" << endl; - writeUnusedVariableCast(s, CPP_SELF_VAR); - cppSelfAttribution = QString("%1 = %2%3") - .arg(CPP_SELF_VAR) - .arg(useWrapperClass ? QString("(%1*)").arg(className) : "") - .arg(cpythonWrapperCPtr(metaClass, PYTHON_SELF_VAR)); - } - - // Checks if the underlying C++ object is valid. - if (hasStaticOverload && !cppSelfAsReference) { - s << INDENT << "if (" PYTHON_SELF_VAR ") {" << endl; - { - Indentation indent(INDENT); - writeInvalidPyObjectCheck(s, PYTHON_SELF_VAR); - s << INDENT << cppSelfAttribution << ';' << endl; - } - s << INDENT << '}' << endl; - return; - } - - writeInvalidPyObjectCheck(s, PYTHON_SELF_VAR); - s << INDENT << cppSelfAttribution << ';' << endl; -} - -void CppGenerator::writeCppSelfDefinition(QTextStream& s, const AbstractMetaFunction* func, 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, func->ownerClass(), 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) ? "args" : 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 = "\"SBK_STR_NAME\""; - } else if (argType->isPrimitive()) { - const PrimitiveTypeEntry* ptp = reinterpret_cast<const PrimitiveTypeEntry*>(argType->typeEntry()); - while (ptp->aliasedTypeEntry()) - ptp = ptp->aliasedTypeEntry(); - strArg = ptp->name(); - if (strArg == "QString") { - strArg = "unicode"; - } else if (strArg == "QChar") { - strArg = "1-unicode"; - } else { - strArg = ptp->name().replace(QRegExp("^signed\\s+"), ""); - if (strArg == "double") - strArg = "float"; - } - } else if (argType->typeEntry()->isContainer()) { - strArg = argType->fullName(); - if (strArg == "QList" || strArg == "QVector" - || strArg == "QLinkedList" || strArg == "QStack" - || strArg == "QQueue") { - strArg = "list"; - } else if (strArg == "QMap" || strArg == "QHash" - || strArg == "QMultiMap" || strArg == "QMultiHash") { - strArg = "dict"; - } else if (strArg == "QPair") { - strArg == "2-tuple"; - } - } else { - strArg = argType->fullName(); - if (strArg == "PyUnicode") - strArg = "unicode"; - else if (strArg == "PyString") - strArg = "str"; - else if (strArg == "PyBytes") - strArg = "\"SBK_STR_NAME\""; - else if (strArg == "PySequece") - strArg = "list"; - else if (strArg == "PyTuple") - strArg = "tuple"; - else if (strArg == "PyDict") - strArg = "dict"; - else if (strArg == "PyObject") - strArg = "object"; - else if (strArg == "PyCallable") - strArg = "callable"; - else if (strArg == "uchar") - strArg = "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 += " = "; - if ((isCString(argType) || isPointerToWrapperType(argType)) - && arg->defaultValueExpression() == "0") { - strArg += "None"; - } else { - strArg += arg->defaultValueExpression().replace("::", ".").replace("\"", "\\\""); - } - } - args << strArg; - } - overloadSignatures << "\""+args.join(", ")+"\""; - } - s << INDENT << "const char* overloads[] = {" << overloadSignatures.join(", ") << ", 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(PYTHON_ARGS"(\\[\\d+[-]?\\d*\\])"); - pyArgsRegex.indexIn(argumentName); - return QString(PYTHON_TO_CPP_VAR"%1").arg(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("(%1)").arg(argumentName)); - - // TODO-CONVERTER ----------------------------------------------------------------------- - if (customCheck.isEmpty() && !argType->typeEntry()->isCustom()) { - typeCheck = QString("(%1 = %2))").arg(pythonToCppConverterForArgumentName(argumentName)).arg(typeCheck); - if (!isNumber && argType->typeEntry()->isCppPrimitive()) - typeCheck.prepend(QString("%1(%2) && ").arg(cpythonCheckFunction(argType)).arg(argumentName)); - } - // TODO-CONVERTER ----------------------------------------------------------------------- - - if (rejectNull) - typeCheck = QString("(%1 != Py_None && %2)").arg(argumentName).arg(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 = QString("%1::").arg(func->ownerClass()->qualifiedCppName()); - ReportHandler::warning(QString("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 ? "return" : "argument") - .arg(type->cppSignature()) - .arg(prefix) - .arg(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() : ""); - 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()) { - ReportHandler::warning(QString("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)) { - ReportHandler::warning(QString("Unknown type '%1' used as argument type replacement "\ - "in function '%2', the generated code may be broken.") - .arg(typeReplaced) - .arg(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 = QString("%1_local").arg(cppOut); - - 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->isReference() - && !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 = "long"; - isProtectedEnum = true; - } - } - - s << INDENT << typeName; - if (treatAsPointer || isPointerOrObjectType) { - s << "* " << cppOut << (defaultValue.isEmpty() ? "" : QString(" = %1").arg(defaultValue)); - } else if (type->isReference() && !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()) { - writeMinimalConstructorExpression(s, type, defaultValue); - } - } - s << ';' << endl; - - QString pythonToCppFunc = pythonToCppConverterForArgumentName(pyIn); - - s << INDENT; - if (!defaultValue.isEmpty()) - s << "if (" << pythonToCppFunc << ") "; - - QString pythonToCppCall = QString("%1(%2, &%3)").arg(pythonToCppFunc).arg(pyIn).arg(cppOut); - if (!mayHaveImplicitConversion) { - s << pythonToCppCall << ';' << endl; - return; - } - - if (!defaultValue.isEmpty()) - s << '{' << endl << INDENT; - - s << "if (Shiboken::Conversions::isImplicitConversion((SbkObjectType*)"; - s << 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("%in", inputName); - rule.replace("%out", QString("%1_out").arg(outputName)); - } else { - rule.replace("%out", outputName); - } - CodeSnip snip(0, snippetLanguage); - snip.position = (snippetLanguage == TypeSystem::NativeCode) ? CodeSnip::Any : CodeSnip::Beginning; - 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, CodeSnip::Beginning, 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, CodeSnip::Any, 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(PYTHON_ARGS "[%1]").arg(overloadData->argPos()) : PYTHON_ARG; - OverloadData* od = overloadData; - int startArg = od->argPos(); - int sequenceArgCount = 0; - while (od && !od->argType()->isVarargs()) { - bool typeReplacedByPyObject = od->argumentTypeReplaced() == "PyObject"; - if (!typeReplacedByPyObject) { - if (usePyArgs) - pyArgName = QString(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("numArgs %1 %2").arg(lastArgIsVarargs ? ">=" : "==").arg(numArgs)); - } else if (sequenceArgCount > 1) { - typeChecks.prepend(QString("numArgs >= %1").arg(startArg + sequenceArgCount)); - } else if (refFunc->isOperatorOverload() && !refFunc->isCallOperator()) { - typeChecks.prepend(QString("%1isReverse").arg(refFunc->isReverseOperator() ? "" : "!")); - } - - 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) -{ - 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()); - } 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); - s << INDENT << "break;" << endl; - } - s << INDENT << '}' << endl; - } - } - } - s << INDENT << '}' << endl; -} - -void CppGenerator::writeSingleFunctionCall(QTextStream& s, const OverloadData& overloadData, const AbstractMetaFunction* func) -{ - if (func->isDeprecated()) { - s << INDENT << "Shiboken::warning(PyExc_DeprecationWarning, 1, \"Function: '" - << func->signature().replace("::", ".") - << "' 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("::", ".") << "\");" << 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(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("No way to call '%1::%2' with the modifications described in the type system.") - .arg(func->ownerClass()->name()) - .arg(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(CPP_ARG"%1").arg(argPos); - QString pyArgName = usePyArgs ? QString(PYTHON_ARGS "[%1]").arg(argPos) : 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, 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("%1_CppToPython_%2").arg(sourceTypeName).arg(targetTypeName); -} - -QString CppGenerator::pythonToCppFunctionName(const QString& sourceTypeName, const QString& targetTypeName) -{ - return QString("%1_PythonToCpp_%2").arg(sourceTypeName).arg(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("is_%1_PythonToCpp_%2_Convertible").arg(sourceTypeName).arg(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("%1& cppInRef = *((%1*)cppIn);\n").arg(typeName)); - code.replace("%INTYPE", typeName); - code.replace("%OUTTYPE", "PyObject*"); - code.replace("%in", "cppInRef"); - code.replace("%out", "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("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) - code.replace(QString("%INTYPE_%1").arg(i), getFullTypeName(containerType->instantiations().at(i))); - 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 = QString("*%1").arg(cpythonWrapperCPtr(sourceType->typeEntry(), "pyIn")); - if (!preConversion.isEmpty()) - c << INDENT << preConversion << endl; - c << INDENT << QString("*((%1*)cppOut) = %1(%2);") - .arg(getFullTypeName(targetType->typeEntry())) - .arg(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("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("(&%1_Type)").arg(toNative->sourceTypeName()); - code.replace("%INTYPE", inType); - code.replace("%OUTTYPE", targetType->qualifiedCppName()); - code.replace("%in", "pyIn"); - code.replace("%out", QString("*((%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 == "Py_None" || pyTypeName == "PyNone") - typeCheck = "%in == Py_None"; - else if (pyTypeName == "SbkEnumType") - typeCheck = "Shiboken::isShibokenEnum(%in)"; - else if (pyTypeName == "SbkObject") - typeCheck = "Shiboken::Object::checkType(%in)"; - else if (pyTypeName == "PyTypeObject") - typeCheck = "PyType_Check(%in)"; - else if (pyTypeName == "PyObject") - typeCheck = "PyObject_TypeCheck(%in, &PyBaseObject_Type)"; - else if (pyTypeName.startsWith("Py")) - typeCheck= QString("%1_Check(%in)").arg(pyTypeName); - } - if (typeCheck.isEmpty()) { - if (!toNative->sourceType() || toNative->sourceType()->isPrimitive()) { - qFatal(qPrintable(QString("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("PyObject_TypeCheck(%in, %1)").arg(cpythonTypeNameExt(toNative->sourceType())); - } - typeCheck.replace("%in", "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("%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(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, "*"+varName); - code = leftCode + rightCode; - } - typeName.append('*'); - } - code.replace(QString("%OUTTYPE_%1").arg(i), typeName); - } - code.replace("%OUTTYPE", cppTypeName); - code.replace("%in", "pyIn"); - code.replace("%out", "cppOutRef"); - QString typeName = fixedCppTypeName(containerType); - writePythonToCppFunction(s, code, typeName, typeName); - - // Python to C++ convertible check function. - QString typeCheck = cpythonCheckFunction(containerType); - if (typeCheck.isEmpty()) - typeCheck = "false"; - else - typeCheck = QString("%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("PyErr_SetString(PyExc_TypeError, \"" + fullPythonFunctionName(func) - + "(): 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(PYTHON_ARGS "[%1]").arg(pyArgIndex) : 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 = QString(PYTHON_SELF_VAR); - *wrappedClass = func->implementingClass(); - } else if (argIndex == 0) { - AbstractMetaType* returnType = getTypeWithoutContainer(func->type()); - if (returnType) { - pyArgName = PYTHON_RETURN_VAR; - *wrappedClass = classes().findClass(returnType->typeEntry()->name()); - } else { - ReportHandler::warning("Invalid Argument index on function modification: " + func->name()); - } - } else { - int realIndex = argIndex - 1 - OverloadData::numberOfRemovedArguments(func, argIndex - 1); - AbstractMetaType* argType = getTypeWithoutContainer(func->arguments().at(realIndex)->type()); - - if (argType) { - *wrappedClass = classes().findClass(argType->typeEntry()->name()); - if (argIndex == 1 - && !func->isConstructor() - && OverloadData::isSingleArgument(getFunctionGroups(func->implementingClass())[func->name()])) - pyArgName = QString(PYTHON_ARG); - else - pyArgName = QString(PYTHON_ARGS "[%1]").arg(argIndex - 1); - } - } - return pyArgName; -} - -void CppGenerator::writeMethodCall(QTextStream& s, const AbstractMetaFunction* func, int maxArgs) -{ - s << INDENT << "// " << func->minimalSignature() << (func->isReverseOperator() ? " [reverse operator]": "") << endl; - if (func->isConstructor()) { - foreach (CodeSnip cs, func->injectedCodeSnips()) { - if (cs.position == CodeSnip::End) { - 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, CodeSnip::Beginning, TypeSystem::TargetLangCode, func, lastArg); - s << endl; - } - - writeConversionRule(s, func, TypeSystem::NativeCode); - - if (!func->isUserAdded()) { - QStringList userArgs; - if (!func->isCopyConstructor()) { - 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 << QString("%1"CONV_RULE_OUT_VAR_SUFFIX).arg(arg->name()); - else if (!arg->defaultValueExpression().isEmpty()) - userArgs << QString(CPP_ARG_REMOVED"%1").arg(i); - } else { - int idx = arg->argumentIndex() - removedArgs; - bool deRef = isValueTypeWithCopyConstructorOnly(arg->type()) - || isObjectTypeUsedAsValueType(arg->type()) - || (arg->type()->isReference() && isWrapperType(arg->type()) && !isPointer(arg->type())); - QString argName = hasConversionRule - ? QString("%1"CONV_RULE_OUT_VAR_SUFFIX).arg(arg->name()) - : QString("%1"CPP_ARG"%2").arg(deRef ? "*" : "").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(QString("%1"CONV_RULE_OUT_VAR_SUFFIX).arg(arg->name())); - else - otherArgs.prepend(QString(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("(*" CPP_SELF_VAR ")"); - if (func->isPointerOperator()) - firstArg.remove(1, 1); // remove the de-reference operator - - QString secondArg(CPP_ARG0); - if (!func->isUnaryOperator() && shouldDereferenceArgumentPointer(func->arguments().first())) { - secondArg.prepend("(*"); - secondArg.append(')'); - } - - 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 == "++") || (op == "--")) && !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() || func->isCopyConstructor()) { - isCtor = true; - QString className = wrapperName(func->ownerClass()); - - if (func->isCopyConstructor() && maxArgs == 1) { - mc << "new ::" << className << "(*" << CPP_ARG0 << ')'; - } else { - QString ctorCall = className + '(' + userArgs.join(", ") + ')'; - 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 { - if (func->ownerClass()) { - if (!avoidProtectedHack() || !func->isProtected()) { - if (func->isStatic()) { - mc << "::" << func->ownerClass()->qualifiedCppName() << "::"; - } else { - if (func->isConstant()) { - if (avoidProtectedHack()) { - mc << "const_cast<const ::"; - if (func->ownerClass()->hasProtectedMembers()) - mc << wrapperName(func->ownerClass()); - else - mc << func->ownerClass()->qualifiedCppName(); - mc << "*>(" CPP_SELF_VAR ")->"; - } else { - mc << "const_cast<const ::" << func->ownerClass()->qualifiedCppName(); - mc << "*>(" CPP_SELF_VAR ")->"; - } - } else { - mc << CPP_SELF_VAR "->"; - } - } - - 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()) : "::" + func->ownerClass()->qualifiedCppName()) << "::"; - mc << func->originalName() << "_protected"; - } - } else { - mc << func->originalName(); - } - mc << '(' << userArgs.join(", ") << ')'; - if (!func->isAbstract() && func->isVirtual()) { - mc.flush(); - if (!avoidProtectedHack() || !func->isProtected()) { - QString virtualCall(methodCall); - QString normalCall(methodCall); - virtualCall = virtualCall.replace("%CLASS_NAME", func->ownerClass()->qualifiedCppName()); - normalCall = normalCall.replace("::%CLASS_NAME::", ""); - methodCall = ""; - 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("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 + '('); - methodCall.append(')'); - s << enumName; - writeReturnType = false; - } - } - if (writeReturnType) { - s << func->type()->cppSignature(); - if (isObjectTypeUsedAsValueType(func->type())) { - s << '*'; - methodCall.prepend(QString("new %1(").arg(func->type()->typeEntry()->qualifiedCppName())); - methodCall.append(')'); - } - } - 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, 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((SbkObjectType*)" << cpythonTypeNameExt(func->type()->typeEntry()); - s << ", " << CPP_RETURN_VAR << ", true, true)"; - } else { - writeToPythonConversion(s, func->type(), func->ownerClass(), CPP_RETURN_VAR); - } - s << ';' << endl; - } - } - } - - if (func->hasInjectedCode() && !func->isConstructor()) { - s << endl; - writeCodeSnips(s, snips, CodeSnip::End, 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 (FunctionModification func_mod, func->modifications()) { - foreach (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 (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 (ArgumentModification arg_mod, refcount_mods) { - ReferenceCount refCount = arg_mod.referenceCounts.first(); - if (refCount.action != ReferenceCount::Set - && refCount.action != ReferenceCount::Remove - && refCount.action != ReferenceCount::Add) { - ReportHandler::warning("\"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 = "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("((size_t) static_cast<const %1*>(class_ptr)) - base").arg(baseClass->qualifiedCppName())); - result.append(QString("((size_t) static_cast<const %1*>((%2*)((void*)class_ptr))) - base").arg(baseClass->qualifiedCppName()).arg(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 (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() == "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() ? "flag" : "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, "converter", toCpp, isConv); - } - - QString toCpp = pythonToCppFunctionName(typeName, typeName); - QString isConv = convertibleToCppFunctionName(typeName, typeName); - writeAddPythonToCppConversion(s, "converter", toCpp, isConv); - - if (flags) { - QString toCpp = pythonToCppFunctionName("number", typeName); - QString isConv = convertibleToCppFunctionName("number", typeName); - writeAddPythonToCppConversion(s, "converter", toCpp, isConv); - } - - s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", converter);" << endl; - s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", converter);" << endl; - QStringList cppSignature = enumType->qualifiedCppName().split("::", QString::SkipEmptyParts); - while (!cppSignature.isEmpty()) { - QString signature = cppSignature.join("::"); - 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().toAscii()); - s << INDENT << "// Register converter for type '" << cppSignature << "'." << endl; - QString converter = converterObject(type); - s << INDENT << converter << " = Shiboken::Conversions::createConverter("; - if (type->typeEntry()->targetLangApiName() == "PyObject") { - s << "&PyBaseObject_Type"; - } else { - QString baseName = cpythonBaseName(type->typeEntry()); - if (baseName == "PySequence") - baseName = "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) { - QString converterVar = QString("(SbkObjectType*)%1[%2]") - .arg(cppApiVariableName(externalType->targetLangPackage())) - .arg(getTypeIndexVariableName(externalType)); - 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 QString("%1_mi_init").arg(cpythonBaseName(metaClass->typeEntry())); -} - -bool CppGenerator::supportsMappingProtocol(const AbstractMetaClass* metaClass) -{ - foreach(QString funcName, m_mappingProtocol.keys()) { - if (metaClass->hasFunction(funcName)) - 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) -{ - foreach(QString funcName, m_sequenceProtocol.keys()) { - if (metaClass->hasFunction(funcName)) - 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) -{ - QString tp_flags; - QString tp_init; - QString tp_new; - QString tp_dealloc; - QString tp_hash('0'); - QString tp_call('0'); - QString cppClassName = metaClass->qualifiedCppName(); - QString className = cpythonTypeName(metaClass).replace(QRegExp("_Type$"), ""); - QString baseClassName('0'); - AbstractMetaFunctionList ctors; - foreach (AbstractMetaFunction* f, metaClass->queryFunctions(AbstractMetaClass::Constructors)) { - if (!f->isPrivate() && !f->isModifiedRemoved()) - ctors.append(f); - } - - if (!metaClass->baseClass()) - baseClassName = "reinterpret_cast<PyTypeObject*>(&SbkObject_Type)"; - - bool onlyPrivCtor = !metaClass->hasNonPrivateConstructor(); - - if (metaClass->isNamespace() || metaClass->hasPrivateDestructor()) { - tp_flags = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_GC"; - tp_dealloc = metaClass->hasPrivateDestructor() ? - "SbkDeallocWrapperWithPrivateDtor" : "0"; - tp_init = "0"; - } else { - if (onlyPrivCtor) - tp_flags = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_GC"; - else - tp_flags = "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 = "&SbkDeallocWrapper"; - tp_init = onlyPrivCtor || ctors.isEmpty() ? "0" : cpythonFunctionName(ctors.first()); - } - - QString tp_getattro('0'); - QString tp_setattro('0'); - if (usePySideExtensions() && (metaClass->qualifiedCppName() == "QObject")) { - tp_getattro = cpythonGetattroFunctionName(metaClass); - tp_setattro = cpythonSetattroFunctionName(metaClass); - } else if (classNeedsGetattroFunction(metaClass)) { - tp_getattro = cpythonGetattroFunctionName(metaClass); - } - - if (metaClass->hasPrivateDestructor() || onlyPrivCtor) - tp_new = "0"; - else - tp_new = "SbkObjectTpNew"; - - QString tp_richcompare = QString('0'); - if (metaClass->hasComparisonOperatorOverload()) - tp_richcompare = cpythonBaseName(metaClass) + "_richcompare"; - - QString tp_getset = QString('0'); - if (shouldGenerateGetSetList(metaClass)) - 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["__repr__"] == "0" - && !metaClass->isQObject() - && metaClass->hasToStringCapability()) { - m_tpFuncs["__repr__"] = writeReprFunction(s, metaClass); - } - - // 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 = '&' + cpythonBaseName(metaClass) + "_HashFunc"; - - const AbstractMetaFunction* callOp = metaClass->findFunction("operator()"); - if (callOp && !callOp->isModifiedRemoved()) - tp_call = '&' + cpythonFunctionName(callOp); - - - s << "// Class Definition -----------------------------------------------" << endl; - s << "extern \"C\" {" << endl; - s << "static SbkObjectType " << className + "_Type" << " = { { {" << endl; - s << INDENT << "PyVarObject_HEAD_INIT(&SbkObjectType_Type, 0)" << endl; - s << INDENT << "/*tp_name*/ \"" << getClassTargetFullName(metaClass) << "\"," << 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["__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["__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["__iter__"] << ',' << endl; - s << INDENT << "/*tp_iternext*/ " << m_tpFuncs["__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 = "*"; - s << "} //extern" << endl; -} - -void CppGenerator::writeMappingMethods(QTextStream& s, const AbstractMetaClass* metaClass) -{ - - 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(CodeSnip::Any, TypeSystem::TargetLangCode); - s << funcRetVal << ' ' << funcName << '(' << funcArgs << ')' << endl << '{' << endl; - writeInvalidPyObjectCheck(s, PYTHON_SELF_VAR); - - writeCppSelfDefinition(s, func); - - const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last(); - writeCodeSnips(s, snips, CodeSnip::Any, TypeSystem::TargetLangCode, func, lastArg); - s << '}' << endl << endl; - } -} - -void CppGenerator::writeSequenceMethods(QTextStream& s, const AbstractMetaClass* metaClass) -{ - - 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(CodeSnip::Any, TypeSystem::TargetLangCode); - s << funcRetVal << ' ' << funcName << '(' << funcArgs << ')' << endl << '{' << endl; - writeInvalidPyObjectCheck(s, PYTHON_SELF_VAR); - - writeCppSelfDefinition(s, func); - - const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last(); - writeCodeSnips(s, snips,CodeSnip::Any, TypeSystem::TargetLangCode, func, lastArg); - s << '}' << endl << endl; - } - - if (!injectedCode) - writeStdListWrapperMethods(s, metaClass); -} - -void CppGenerator::writeTypeAsSequenceDefinition(QTextStream& s, const AbstractMetaClass* metaClass) -{ - bool hasFunctions = false; - QMap<QString, QString> funcs; - foreach(QString funcName, m_sequenceProtocol.keys()) { - const AbstractMetaFunction* func = metaClass->findFunction(funcName); - funcs[funcName] = func ? cpythonFunctionName(func).prepend("&") : QString(); - if (!hasFunctions && func) - hasFunctions = true; - } - - QString baseName = cpythonBaseName(metaClass); - - //use default implementation - if (!hasFunctions) { - funcs["__len__"] = baseName + "__len__"; - funcs["__getitem__"] = baseName + "__getitem__"; - funcs["__setitem__"] = baseName + "__setitem__"; - } - - s << INDENT << "memset(&" << baseName << "_Type.super.as_sequence, 0, sizeof(PySequenceMethods));" << endl; - foreach (const QString& sqName, m_sqFuncs.keys()) { - if (funcs[sqName].isEmpty()) - continue; - if (m_sqFuncs[sqName] == "sq_slice") - s << "#ifndef IS_PY3K" << endl; - s << INDENT << baseName << "_Type.super.as_sequence." << m_sqFuncs[sqName] << " = " << funcs[sqName] << ';' << endl; - if (m_sqFuncs[sqName] == "sq_slice") - s << "#endif" << endl; - } -} - -void CppGenerator::writeTypeAsMappingDefinition(QTextStream& s, const AbstractMetaClass* metaClass) -{ - bool hasFunctions = false; - QMap<QString, QString> funcs; - foreach(QString funcName, m_mappingProtocol.keys()) { - const AbstractMetaFunction* func = metaClass->findFunction(funcName); - funcs[funcName] = func ? cpythonFunctionName(func).prepend("&") : "0"; - if (!hasFunctions && func) - hasFunctions = true; - } - - //use default implementation - if (!hasFunctions) { - funcs["__mlen__"] = QString(); - funcs["__mgetitem__"] = QString(); - funcs["__msetitem__"] = QString(); - } - - QString baseName = cpythonBaseName(metaClass); - s << INDENT << "memset(&" << baseName << "_Type.super.as_mapping, 0, sizeof(PyMappingMethods));" << endl; - foreach (const QString& mpName, m_mpFuncs.keys()) { - if (funcs[mpName].isEmpty()) - continue; - s << INDENT << baseName << "_Type.super.as_mapping." << m_mpFuncs[mpName] << " = " << funcs[mpName] << ';' << endl; - } -} - -void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMetaClass* metaClass) -{ - QMap<QString, QString> nb; - - nb["__add__"] = QString(); - nb["__sub__"] = QString(); - nb["__mul__"] = QString(); - nb["__div__"] = QString(); - nb["__mod__"] = QString(); - nb["__neg__"] = QString(); - nb["__pos__"] = QString(); - nb["__invert__"] = QString(); - nb["__lshift__"] = QString(); - nb["__rshift__"] = QString(); - nb["__and__"] = QString(); - nb["__xor__"] = QString(); - nb["__or__"] = QString(); - nb["__iadd__"] = QString(); - nb["__isub__"] = QString(); - nb["__imul__"] = QString(); - nb["__idiv__"] = QString(); - nb["__imod__"] = QString(); - nb["__ilshift__"] = QString(); - nb["__irshift__"] = QString(); - nb["__iand__"] = QString(); - nb["__ixor__"] = QString(); - nb["__ior__"] = QString(); - - QList<AbstractMetaFunctionList> opOverloads = - filterGroupedOperatorFunctions(metaClass, - AbstractMetaClass::ArithmeticOp - | AbstractMetaClass::LogicalOp - | AbstractMetaClass::BitwiseOp); - - foreach (AbstractMetaFunctionList opOverload, opOverloads) { - const AbstractMetaFunction* rfunc = opOverload[0]; - QString opName = ShibokenGenerator::pythonOperatorFunctionName(rfunc); - nb[opName] = cpythonFunctionName(rfunc); - } - - QString baseName = cpythonBaseName(metaClass); - - nb["bool"] = hasBoolCast(metaClass) ? baseName + "___nb_bool" : QString(); - - s << INDENT << "memset(&" << baseName << "_Type.super.as_number, 0, sizeof(PyNumberMethods));" << endl; - foreach (const QString& nbName, m_nbFuncs.keys()) { - 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 == "bool") { - s << INDENT << "SBK_NB_BOOL(" << baseName << "_Type.super.as_number) = " << nb[nbName] << ';' << endl; - } else { - bool excludeFromPy3K = nbName == "__div__" || nbName == "__idiv__"; - if (excludeFromPy3K) - s << "#ifndef IS_PY3K" << endl; - s << INDENT << baseName << "_Type.super.as_number." << m_nbFuncs[nbName] << " = " << nb[nbName] << ';' << endl; - if (excludeFromPy3K) - s << "#endif" << endl; - } - } - if (!nb["__div__"].isEmpty()) - s << INDENT << baseName << "_Type.super.as_number.nb_true_divide = " << nb["__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, const AbstractMetaClass* metaClass) -{ - QString className = cpythonTypeName(metaClass).replace(QRegExp("_Type$"), ""); - s << "static PyObject* " << className << "___copy__(PyObject* " PYTHON_SELF_VAR ")" << endl; - s << "{" << endl; - writeCppSelfDefinition(s, metaClass, false, true); - s << INDENT << "PyObject* " << PYTHON_RETURN_VAR << " = " << cpythonToPythonConversionFunction(metaClass); - 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) -{ - ErrorCode errorCode(0); - s << "static PyObject* " << cpythonGetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", void*)" << endl; - s << '{' << endl; - - writeCppSelfDefinition(s, metaField->enclosingClass()); - - 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("((%1*)%2)->%3()").arg(wrapperName(metaField->enclosingClass())) - .arg(CPP_SELF_VAR) - .arg(protectedFieldGetterName(metaField)); - } else { - cppField = QString("%2->%3").arg(CPP_SELF_VAR).arg(metaField->name()); - if (newWrapperSameObject) { - cppField.prepend("&("); - cppField.append(')'); - } - } - if (isCppIntegralPrimitive(fieldType) || fieldType->isEnum()) { - s << INDENT << getFullTypeNameWithoutModifiers(fieldType) << " cppOut_local = " << cppField << ';' << endl; - cppField = "cppOut_local"; - } else if (avoidProtectedHack() && metaField->isProtected()) { - s << INDENT << getFullTypeNameWithoutModifiers(fieldType); - if (fieldType->isContainer() || fieldType->isFlags()) { - s << '&'; - cppField.prepend('*'); - } else if ((!fieldType->isConstant() && !fieldType->isEnum() && !fieldType->isPrimitive()) || fieldType->indirections() == 1) { - s << '*'; - } - s << " fieldValue = " << cppField << ';' << endl; - cppField = "fieldValue"; - } - - s << INDENT << "PyObject* pyOut = "; - if (newWrapperSameObject) { - s << "Shiboken::Object::newObject((SbkObjectType*)" << cpythonTypeNameExt(fieldType); - s << ", " << cppField << ", false, true);" << endl; - s << INDENT << "Shiboken::Object::setParent(" PYTHON_SELF_VAR ", pyOut)"; - } else { - writeToPythonConversion(s, fieldType, metaField->enclosingClass(), cppField); - } - s << ';' << endl; - - s << INDENT << "return pyOut;" << endl; - s << '}' << endl; -} - -void CppGenerator::writeSetterFunction(QTextStream& s, const AbstractMetaField* metaField) -{ - ErrorCode errorCode(0); - s << "static int " << cpythonSetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* pyIn, void*)" << endl; - s << '{' << endl; - - writeCppSelfDefinition(s, metaField->enclosingClass()); - - 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, "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("%1->%2").arg(CPP_SELF_VAR).arg(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("((%1*)%2)->%3(cppOut)").arg(wrapperName(metaField->enclosingClass())) - .arg(CPP_SELF_VAR) - .arg(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("*").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, const AbstractMetaClass* 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, metaClass, false, true); - writeUnusedVariableCast(s, CPP_SELF_VAR); - s << INDENT << "PyObject* " PYTHON_RETURN_VAR " = 0;" << endl; - s << INDENT << "PythonToCppFunc " PYTHON_TO_CPP_VAR << ';' << endl; - writeUnusedVariableCast(s, PYTHON_TO_CPP_VAR); - s << endl; - - s << INDENT << "switch (op) {" << endl; - { - Indentation indent(INDENT); - foreach (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() - QString("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, PYTHON_ARG, alternativeNumericTypes == 1 || isPyInt(argType)); - s << ") {" << endl; - { - Indentation indent(INDENT); - s << INDENT << "// " << func->signature() << endl; - writeArgumentConversion(s, argType, CPP_ARG0, 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, CodeSnip::Any, TypeSystem::TargetLangCode, func, func->arguments().last()); - } else { - QString expression = QString("%1%2 %3 (%4" CPP_ARG0 ")") - .arg(func->isPointerOperator() ? "&" : "") - .arg(CPP_SELF_VAR).arg(op) - .arg(shouldDereferenceAbstractMetaTypePointer(argType) ? "*" : ""); - 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, CPP_RETURN_VAR); - else - s << "Py_None;" << endl << INDENT << "Py_INCREF(Py_None)"; - s << ';' << endl; - } - } - s << INDENT << '}'; - } - - s << " else {" << endl; - if (operatorId == "Py_EQ" || operatorId == "Py_NE") { - Indentation indent(INDENT); - s << INDENT << PYTHON_RETURN_VAR " = " << (operatorId == "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 = '&' + cpythonTypeName(enclosingClass); - else if (hasUpperEnclosingClass) - enclosingObjectVariable = "enclosingClass"; - else - enclosingObjectVariable = "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() + "::" : ""); - 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 = "(long) "; - if (cppEnum->enclosingClass()) - enumValueText += cppEnum->enclosingClass()->qualifiedCppName() + "::"; - 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(((SbkObjectType*)" << enclosingObjectVariable; - s << ")->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(); - QByteArray origType = SBK_NORMALIZED_TYPE(qPrintable(metaType->originalTypeDescription())); - QByteArray cppSig = SBK_NORMALIZED_TYPE(qPrintable(metaType->cppSignature())); - if ((origType != cppSig) && (!metaType->isFlags())) - ReportHandler::warning("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, "and", "&"); - writeFlagsBinaryOperator(s, cppEnum, "or", "|"); - writeFlagsBinaryOperator(s, cppEnum, "xor", "^"); - - writeFlagsUnaryOperator(s, cppEnum, "invert", "~"); - 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() << ")PyLong_AsLong(" PYTHON_SELF_VAR ");" << endl; - s << INDENT << "cppArg = (" << flagsEntry->originalName() << ")PyLong_AsLong(" PYTHON_ARG ");" << endl; - s << "#else" << endl; - s << INDENT << CPP_SELF_VAR " = (::" << flagsEntry->originalName() << ")PyInt_AsLong(" PYTHON_SELF_VAR ");" << endl; - s << INDENT << "cppArg = (" << flagsEntry->originalName() << ")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, "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, "cppResult"); - s << ';' << endl; - s << '}' << endl << endl; -} - -void CppGenerator::writeClassRegister(QTextStream& s, const AbstractMetaClass* metaClass) -{ - const ComplexTypeEntry* classTypeEntry = metaClass->typeEntry(); - - const AbstractMetaClass* enc = metaClass->enclosingClass(); - bool hasEnclosingClass = enc && enc->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass; - QString enclosingObjectVariable = hasEnclosingClass ? "enclosingClass" : "module"; - - QString pyTypeName = cpythonTypeName(metaClass); - s << "void init_" << metaClass->qualifiedCppName().replace("::", "_"); - 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 << ".super.as_number;" << 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 << ".super.as_sequence;" << 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 << ".super.as_mapping;" << endl; - s << endl; - } - - s << INDENT << cpythonTypeNameExt(classTypeEntry); - s << " = reinterpret_cast<PyTypeObject*>(&" << pyTypeName << ");" << endl; - s << endl; - - // Multiple inheritance - QString pyTypeBasesVariable = QString("%1_bases").arg(pyTypeName); - 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 << "(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; - s << ", \"" << metaClass->name() << "\", \""; - // Original name - s << metaClass->qualifiedCppName() << (isObjectType(classTypeEntry) ? "*" : ""); - 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); - s << ", &Shiboken::callCppDestructor< ::" << dtorClassName << " >"; - } else if (metaClass->baseClass() || hasEnclosingClass) { - s << ", 0"; - } - - // Base type - if (metaClass->baseClass()) { - s << ", (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); - s << endl; - - // class inject-code target/beginning - if (!classTypeEntry->codeSnips().isEmpty()) { - writeCodeSnips(s, classTypeEntry->codeSnips(), CodeSnip::Beginning, 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(""); - writeEnumsInitialization(s, classEnums); - - if (metaClass->hasSignals()) - writeSignalInitialization(s, metaClass); - - // Write static fields - foreach (const AbstractMetaField* field, metaClass->fields()) { - if (!field->isStatic()) - continue; - s << INDENT << "PyDict_SetItemString(" + cpythonTypeName(metaClass) + ".super.ht_type.tp_dict, \""; - s << field->name() << "\", "; - writeToPythonConversion(s, field->type(), metaClass, metaClass->qualifiedCppName() + "::" + field->name()); - s << ");" << endl; - } - s << endl; - - // class inject-code target/end - if (!classTypeEntry->codeSnips().isEmpty()) { - s << endl; - writeCodeSnips(s, classTypeEntry->codeSnips(), CodeSnip::End, TypeSystem::TargetLangCode, metaClass); - } - - if (usePySideExtensions()) { - if (avoidProtectedHack() && shouldGenerateCppWrapper(metaClass)) - s << INDENT << wrapperName(metaClass) << "::pysideInitQtMetaTypes();\n"; - else - writeInitQtMetaTypeFunctionBody(s, metaClass); - } - - 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, const AbstractMetaClass* metaClass) const -{ - // Gets all class name variants used on different possible scopes - QStringList nameVariants; - nameVariants << metaClass->name(); - const AbstractMetaClass* enclosingClass = metaClass->enclosingClass(); - while (enclosingClass) { - if (enclosingClass->typeEntry()->generateCode()) - nameVariants << (enclosingClass->name() + "::" + nameVariants.last()); - enclosingClass = enclosingClass->enclosingClass(); - } - - const QString className = metaClass->qualifiedCppName(); - 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 (QString name, nameVariants) - s << INDENT << "qRegisterMetaType< ::" << className << " >(\"" << name << "\");" << endl; - } - } - - foreach (AbstractMetaEnum* metaEnum, metaClass->enums()) { - if (!metaEnum->isPrivate() && !metaEnum->isAnonymous()) { - foreach (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("%1", " reinterpret_cast< ::" + metaClass->qualifiedCppName() + "*>(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 { - ReportHandler::warning(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"; -} - -void CppGenerator::writeSetattroFunction(QTextStream& s, const AbstractMetaClass* 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; - } - s << INDENT << "return PyObject_GenericSetAttr(" PYTHON_SELF_VAR ", name, value);" << endl; - s << '}' << endl; -} - -void CppGenerator::writeGetattroFunction(QTextStream& s, const AbstractMetaClass* metaClass) -{ - s << "static PyObject* " << cpythonGetattroFunctionName(metaClass) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* name)" << endl; - s << '{' << endl; - - QString getattrFunc; - if (usePySideExtensions() && metaClass->isQObject()) { - AbstractMetaClass* qobjectClass = classes().findClass("QObject"); - getattrFunc = QString("PySide::getMetaDataFromQObject(%1, " PYTHON_SELF_VAR ", name)") - .arg(cpythonWrapperCPtr(qobjectClass, PYTHON_SELF_VAR)); - } else { - getattrFunc = "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)) { - s << INDENT << "if (Shiboken::String::compare(name, \"" << func->name() << "\") == 0)" << endl; - Indentation indent(INDENT); - s << INDENT << "return PyCFunction_NewEx(&" << cpythonMethodDefinitionName(func) << ", " PYTHON_SELF_VAR ", 0);" << endl; - } - } - s << INDENT << '}' << endl; - } - s << INDENT << "return " << getattrFunc << ';' << endl; - s << '}' << endl; -} - -void 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); - - foreach (AbstractMetaFunctionList globalOverloads, getFunctionGroups().values()) { - AbstractMetaFunctionList overloads; - foreach (AbstractMetaFunction* func, globalOverloads) { - if (!func->isModifiedRemoved()) { - overloads.append(func); - if (func->typeEntry()) - includes << func->typeEntry()->include(); - } - } - - if (overloads.isEmpty()) - continue; - - writeMethodWrapper(s_globalFunctionImpl, overloads); - writeMethodDefinition(s_globalFunctionDef, overloads); - } - - //this is a temporary solution before new type revison implementation - //We need move QMetaObject register before QObject - AbstractMetaClassList lst = classes(); - AbstractMetaClass* klassQObject = lst.findClass("QObject"); - AbstractMetaClass* klassQMetaObject = lst.findClass("QMetaObject"); - if (klassQObject && klassQMetaObject) { - lst.removeAll(klassQMetaObject); - int indexOf = lst.indexOf(klassQObject); - lst.insert(indexOf, klassQMetaObject); - } - - foreach (const AbstractMetaClass* cls, lst) { - if (!shouldGenerate(cls)) - continue; - - s_classInitDecl << "void init_" << cls->qualifiedCppName().replace("::", "_") << "(PyObject* module);" << endl; - - QString defineStr = "init_" + cls->qualifiedCppName().replace("::", "_"); - - if (cls->enclosingClass() && (cls->enclosingClass()->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass)) - defineStr += "(" + cpythonTypeNameExt(cls->enclosingClass()->typeEntry()) +"->tp_dict);"; - else - defineStr += "(module);"; - s_classPythonDefines << INDENT << defineStr << endl; - } - - QString moduleFileName(outputDirectory() + "/" + subDirectoryForPackage(packageName())); - moduleFileName += "/" + moduleName().toLower() + "_module_wrapper.cpp"; - - QFile file(moduleFileName); - verifyDirectoryFor(file); - if (!file.open(QFile::WriteOnly)) { - ReportHandler::warning("Error writing file: " + moduleFileName); - return; - } - - 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 << "#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, CodeSnip::Beginning, 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; - foreach (const TypeEntry* externalType, extendedConverters.keys()) { - 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("SBK_MODULE_INIT_ERROR"); - // module inject-code target/beginning - if (!snips.isEmpty()) { - writeCodeSnips(s, snips, CodeSnip::Beginning, 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 << "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(); - 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; - foreach (const TypeEntry* externalType, extendedConverters.keys()) { - writeExtendedConverterInitialization(s, externalType, extendedConverters[externalType]); - 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* alias = pte->basicAliasedTypeEntry(); - if (!alias) - continue; - QString converter = converterObject(alias); - QStringList cppSignature = pte->qualifiedCppName().split("::", QString::SkipEmptyParts); - while (!cppSignature.isEmpty()) { - QString signature = cppSignature.join("::"); - 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("::")) - value.remove(0, 2); - typeResolvers << SBK_NORMALIZED_TYPE(value.toAscii().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, CodeSnip::End, TypeSystem::TargetLangCode); - s << endl; - } - - // module inject-code native/end - if (!snips.isEmpty()) { - writeCodeSnips(s, snips, CodeSnip::End, 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; -} - -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() == "parent" && isObjectType(arg->type())) { - action = ArgumentOwner::Add; - parentIndex = argIndex; - childIndex = -1; - } - } - - QString parentVariable; - QString childVariable; - if (action != ArgumentOwner::Invalid) { - if (!usePyArgs && argIndex > 1) - ReportHandler::warning("Argument index for parent tag out of bounds: "+func->signature()); - - if (action == ArgumentOwner::Remove) { - parentVariable = "Py_None"; - } else { - if (parentIndex == 0) - parentVariable = PYTHON_RETURN_VAR; - else if (parentIndex == -1) - parentVariable = PYTHON_SELF_VAR; - else - parentVariable = usePyArgs ? QString(PYTHON_ARGS "[%1]").arg(QString::number(parentIndex-1)) : PYTHON_ARG; - } - - if (childIndex == 0) - childVariable = PYTHON_RETURN_VAR; - else if (childIndex == -1) - childVariable = PYTHON_SELF_VAR; - else - childVariable = usePyArgs ? QString(PYTHON_ARGS "[%1]").arg(QString::number(childIndex-1)) : 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, const AbstractMetaClass* metaClass) -{ - s << "static Py_hash_t " << cpythonBaseName(metaClass) << "_HashFunc(PyObject* self) {" << endl; - writeCppSelfDefinition(s, metaClass); - s << INDENT << "return " << metaClass->typeEntry()->hashFunction() << '('; - s << (isObjectType(metaClass) ? "" : "*") << CPP_SELF_VAR << ");" << endl; - s << '}' << endl << endl; -} - -void CppGenerator::writeStdListWrapperMethods(QTextStream& s, const AbstractMetaClass* metaClass) -{ - ErrorCode errorCode(0); - - // __len__ - s << "Py_ssize_t " << cpythonBaseName(metaClass->typeEntry()) << "__len__(PyObject* " PYTHON_SELF_VAR ")" << endl; - s << '{' << endl; - writeCppSelfDefinition(s, metaClass); - 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, metaClass); - writeIndexError(s, "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, "*_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, metaClass); - writeIndexError(s, "list assignment index out of range"); - - s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ';' << endl; - s << INDENT << "if (!"; - writeTypeCheck(s, itemType, "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, "cppValue", "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, const AbstractMetaClass* metaClass) -{ - QString funcName = cpythonBaseName(metaClass) + "__repr__"; - s << "extern \"C\"" << endl; - s << '{' << endl; - s << "static PyObject* " << funcName << "(PyObject* self)" << endl; - s << '{' << endl; - writeCppSelfDefinition(s, metaClass); - 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/generators/shiboken/cppgenerator.h b/generators/shiboken/cppgenerator.h deleted file mode 100644 index 625514996..000000000 --- a/generators/shiboken/cppgenerator.h +++ /dev/null @@ -1,334 +0,0 @@ -/* - * This file is part of the Shiboken Python Bindings Generator project. - * - * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: PySide team <contact@pyside.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef CPPGENERATOR_H -#define CPPGENERATOR_H - -#include "shibokengenerator.h" -#include "overloaddata.h" - -/** - * The CppGenerator generate the implementations of C++ bindings classes. - */ -class CppGenerator : public ShibokenGenerator -{ -public: - CppGenerator(); -protected: - QString fileNameForClass(const AbstractMetaClass* metaClass) const; - QList<AbstractMetaFunctionList> filterGroupedOperatorFunctions(const AbstractMetaClass* metaClass, - uint query); - void generateClass(QTextStream& s, const AbstractMetaClass* metaClass); - void 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); - void writeCustomConverterFunctions(QTextStream& s, const CustomConversion* customConversion); - void writeConverterRegister(QTextStream& s, const AbstractMetaClass* metaClass); - 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); - void writeConstructorWrapper(QTextStream& s, const AbstractMetaFunctionList overloads); - void writeDestructorWrapper(QTextStream& s, const AbstractMetaClass* metaClass); - void writeMethodWrapper(QTextStream& s, const AbstractMetaFunctionList overloads); - void writeArgumentsInitializer(QTextStream& s, OverloadData& overloadData); - void writeCppSelfDefinition(QTextStream& s, const AbstractMetaFunction* func, bool hasStaticOverload = false); - void writeCppSelfDefinition(QTextStream& s, const AbstractMetaClass* metaClass, 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 = "", bool rejectNull = false); - void writeTypeCheck(QTextStream& s, const OverloadData* overloadData, QString argumentName); - - void writeTypeDiscoveryFunction(QTextStream& s, const AbstractMetaClass* metaClass); - - void writeSetattroFunction(QTextStream& s, const AbstractMetaClass* metaClass); - void writeGetattroFunction(QTextStream& s, const AbstractMetaClass* metaClass); - - /** - * 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); - - /// Writes the call to a single function usually from a collection of overloads. - void writeSingleFunctionCall(QTextStream& s, const OverloadData& overloadData, const AbstractMetaFunction* func); - - /// 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, int maxArgs = 0); - - void writeClassRegister(QTextStream& s, const AbstractMetaClass* metaClass); - void writeClassDefinition(QTextStream& s, const AbstractMetaClass* metaClass); - 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); - 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); - - 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, const AbstractMetaClass *metaClass); - - void writeGetterFunction(QTextStream& s, const AbstractMetaField* metaField); - void writeSetterFunction(QTextStream& s, const AbstractMetaField* metaField); - - void writeRichCompareFunction(QTextStream& s, const AbstractMetaClass* metaClass); - 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 = PYTHON_SELF_VAR); - void writeInitQtMetaTypeFunctionBody(QTextStream& s, const AbstractMetaClass* metaClass) 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, const AbstractMetaClass* metaClass); - - /// Write default implementations for sequence protocol - void writeStdListWrapperMethods(QTextStream& s, const AbstractMetaClass* metaClass); - /// Helper function for writeStdListWrapperMethods. - void writeIndexError(QTextStream& s, const QString& errorMsg); - - QString writeReprFunction(QTextStream& s, const AbstractMetaClass* metaClass); - - 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/generators/shiboken/headergenerator.cpp b/generators/shiboken/headergenerator.cpp deleted file mode 100644 index 9be272067..000000000 --- a/generators/shiboken/headergenerator.cpp +++ /dev/null @@ -1,494 +0,0 @@ -/* - * This file is part of the Shiboken Python Bindings Generator project. - * - * Copyright (C) 2009-2012 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: PySide team <contact@pyside.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "headergenerator.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::fileNameForClass(const AbstractMetaClass* metaClass) const -{ - return metaClass->qualifiedCppName().toLower().replace("::", "_") + QLatin1String("_wrapper.h"); -} - -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() + "::" + 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, const AbstractMetaClass* metaClass) -{ - ReportHandler::debugSparse("Generating header for " + metaClass->fullName()); - m_inheritedOverloads.clear(); - Indentation indent(INDENT); - - // write license comment - s << licenseComment(); - - QString wrapperName = HeaderGenerator::wrapperName(metaClass); - QString headerGuard = wrapperName.replace("::", "_").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 - if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor()) { - s << INDENT; - if (metaClass->hasVirtualDestructor() || hasVirtualFunction) - s << "virtual "; - s << "~" << wrapperName << "();" << endl; - } - - writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), CodeSnip::Declaration, 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->isCopyConstructor()) { - 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, "", "_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("%1(%2)").arg(arg->type()->cppSignature()).arg(argName); - args << argName; - } - s << args.join(", ") << ')'; - 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, "", "", 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; - break; - } - } - - // 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 = classes().findClass(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()); - } -} - -void 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(¯os); - 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()); - macrosStream << "#define "; - macrosStream.setFieldWidth(60); - macrosStream << "SBK_"+moduleName()+"_IDX_COUNT"; - macrosStream.setFieldWidth(0); - macrosStream << ' ' << getMaxTypeIndex() << 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, QString("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); - } - - QString moduleHeaderFileName(outputDirectory() - + QDir::separator() + subDirectoryForPackage(packageName()) - + QDir::separator() + getModuleHeaderFileName()); - - QString includeShield("SBK_" + moduleName().toUpper() + "_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; -} - -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() + "::" + 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::writeInheritedOverloads(QTextStream& s) -{ - foreach (const AbstractMetaFunction* func, m_inheritedOverloads) { - s << INDENT << "inline "; - s << functionSignature(func, "", "", 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 = QString("%1(%2)").arg(arg->type()->cppSignature()).arg(argName); - args << argName; - } - s << args.join(", ") << ')'; - s << "; }" << endl; - } -} diff --git a/generators/shiboken/headergenerator.h b/generators/shiboken/headergenerator.h deleted file mode 100644 index e830efaee..000000000 --- a/generators/shiboken/headergenerator.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is part of the Shiboken Python Bindings Generator project. - * - * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: PySide team <contact@pyside.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef HEADERGENERATOR_H -#define HEADERGENERATOR_H - -#include "shibokengenerator.h" - -/** - * 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 fileNameForClass(const AbstractMetaClass* metaClass) const; - void generateClass(QTextStream& s, const AbstractMetaClass* metaClass); - void 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 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/generators/shiboken/overloaddata.cpp b/generators/shiboken/overloaddata.cpp deleted file mode 100644 index 57084558e..000000000 --- a/generators/shiboken/overloaddata.cpp +++ /dev/null @@ -1,1002 +0,0 @@ -/* - * This file is part of the Shiboken Python Bindings Generator project. - * - * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: PySide team <contact@pyside.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include <QtCore/QFile> -#include <reporthandler.h> -#include <graph.h> -#include "overloaddata.h" -#include "shibokengenerator.h" -#include <QTemporaryFile> - -static const TypeEntry* getAliasedTypeEntry(const TypeEntry* typeEntry) -{ - if (typeEntry->isPrimitive()) { - const PrimitiveTypeEntry* pte = reinterpret_cast<const PrimitiveTypeEntry*>(typeEntry); - while (pte->aliasedTypeEntry()) - pte = pte->aliasedTypeEntry(); - typeEntry = pte; - } - return typeEntry; -} - -static QString getTypeName(const AbstractMetaType* type) -{ - const TypeEntry* typeEntry = getAliasedTypeEntry(type->typeEntry()); - QString typeName = typeEntry->name(); - if (typeEntry->isContainer()) { - QStringList types; - foreach (const AbstractMetaType* cType, type->instantiations()) { - const TypeEntry* typeEntry = getAliasedTypeEntry(cType->typeEntry()); - types << typeEntry->name(); - } - typeName += QString("<%1 >").arg(types.join(",")); - } - 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()) { - 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 = reinterpret_cast<const ContainerTypeEntry*>(containerType->typeEntry()); - return containerTypeEntry->qualifiedCppName() + '<' + types.join(", ") + " >"; -} - -/** - * 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 << "float" << "double" << "bool"; - - // Signed integer primitive types. - QStringList signedIntegerPrimitives; - signedIntegerPrimitives << "int" << "short" << "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("PyObject")) { - checkPyObject = true; - pyobjectIndex = sortData.lastProcessedItemId(); - } else if (!checkPySequence && typeName == "PySequence") { - checkPySequence = true; - pySeqIndex = sortData.lastProcessedItemId(); - } else if (!checkPyBuffer && typeName == "PyBuffer") { - checkPyBuffer = true; - pyBufferIndex = sortData.lastProcessedItemId(); - } else if (!checkQVariant && typeName == "QVariant") { - checkQVariant = true; - qvariantIndex = sortData.lastProcessedItemId(); - } else if (!checkQString && typeName == "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(primitiveTypes[i]); - - if (checkPySequence && checkPyObject) - graph.addEdge(pySeqIndex, pyobjectIndex); - - QStringList classesWithIntegerImplicitConversion; - - 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 == "int" || convertibleType == "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); - } - - // Process inheritance relationships - if (targetType->isValue() || targetType->isObject()) { - const AbstractMetaClass* metaClass = m_generator->classes().findClass(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); - } - } - } - } - - - if ((checkPySequence || checkPyObject || checkPyBuffer) - && !targetTypeEntryName.contains("PyObject") - && !targetTypeEntryName.contains("PyBuffer") - && !targetTypeEntryName.contains("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 != "QVariant") { - if (!graph.containsEdge(qvariantIndex, targetTypeId)) // Avoid cyclic dependency. - graph.addEdge(targetTypeId, qvariantIndex); - } else if (checkQString && ShibokenGenerator::isPointer(ov->argType()) - && targetTypeEntryName != "QString" - && targetTypeEntryName != "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[primitiveTypes[i]]); - } - } - } - - // QByteArray args need to be checked after QString args - if (sortData.map.contains("QString") && sortData.map.contains("QByteArray")) - graph.addEdge(sortData.map["QString"], sortData.map["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() + '.'); - - // Dump overload graph - QString graphName = QDir::tempPath() + '/' + funcName + ".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); - ReportHandler::warning(QString("Cyclic dependency found on overloaddata for '%1' method! The graph boy saved the graph at %2.").arg(qPrintable(funcName)).arg(qPrintable(graphName))); - } - - 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 << "void"; - } - return QStringList(retTypes.toList()); -} - -bool OverloadData::hasNonVoidReturnType() const -{ - QStringList retTypes = returnTypes(); - return !retTypes.contains("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("const")) - continue; - foreach (const AbstractMetaFunction* f, overloads) { - if ((func->minimalSignature() + "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(); - } -} - -QString OverloadData::dumpGraph() const -{ - QString indent(4, ' '); - 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 << func->type()->cppSignature().replace('<', "<").replace('>', ">"); - else - s << "void"; - s << ' ' << func->minimalSignature().replace('<', "<").replace('>', ">") << "\\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 << rfunc->name().replace('<', "<").replace('>', ">") << "</font>"; - if (rfunc->isVirtual()) { - s << "<br/><font color=\"white\" point-size=\"10\"><<"; - if (rfunc->isAbstract()) - s << "pure "; - s << "virtual>></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 << rfunc->type()->cppSignature().replace('<', "<").replace('>', ">"); - 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 << func->typeReplaced(0).replace('<', "<").replace('>', ">") << "</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 = QString("arg_%1").arg((ulong)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 << type.replace("&", "&") << "</td></tr>"; - if (hasArgumentTypeReplace()) { - s << "<tr><td bgcolor=\"gray\" align=\"right\">orig. type</td><td bgcolor=\"gray\" align=\"left\">"; - s << argType()->cppSignature().replace("&", "&") << "</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; -} - diff --git a/generators/shiboken/overloaddata.h b/generators/shiboken/overloaddata.h deleted file mode 100644 index a0bd4640c..000000000 --- a/generators/shiboken/overloaddata.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * This file is part of the Shiboken Python Bindings Generator project. - * - * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: PySide team <contact@pyside.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef OVERLOADDATA_H -#define OVERLOADDATA_H - -#include <abstractmetalang.h> -#include <QtCore/QList> -#include <QtCore/QBitArray> - -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); - -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; -}; - - -#endif // OVERLOADDATA_H diff --git a/generators/shiboken/shibokengenerator.cpp b/generators/shiboken/shibokengenerator.cpp deleted file mode 100644 index 2ae213dbb..000000000 --- a/generators/shiboken/shibokengenerator.cpp +++ /dev/null @@ -1,2466 +0,0 @@ -/* - * This file is part of the Shiboken Python Bindings Generator project. - * - * Copyright (C) 2009-2012 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: PySide team <contact@pyside.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#include "shibokengenerator.h" -#include "overloaddata.h" -#include <reporthandler.h> -#include <typedatabase.h> - -#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("::", QString::SkipEmptyParts); - for(int i = (parts.size() - 1) ; i >= 0; i--) { - if (!value.startsWith(parts[i] + "::")) - name = parts[i] + "::" + name; - else - name = ""; - } - - 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] = "checkType"; - m_typeSystemConvName[TypeSystemIsConvertibleFunction] = "isConvertible"; - m_typeSystemConvName[TypeSystemToCppFunction] = "toCpp"; - m_typeSystemConvName[TypeSystemToPythonFunction] = "toPython"; - m_typeSystemConvRegEx[TypeSystemCheckFunction] = QRegExp(CHECKTYPE_REGEX); - m_typeSystemConvRegEx[TypeSystemIsConvertibleFunction] = QRegExp(ISCONVERTIBLE_REGEX); - m_typeSystemConvRegEx[TypeSystemToPythonFunction] = QRegExp(CONVERTTOPYTHON_REGEX); - m_typeSystemConvRegEx[TypeSystemToCppFunction] = QRegExp(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["__str__"] = QString("0"); - m_tpFuncs["__repr__"] = QString("0"); - m_tpFuncs["__iter__"] = QString("0"); - m_tpFuncs["__next__"] = QString("0"); -} - -void ShibokenGenerator::initPrimitiveTypesCorrespondences() -{ - // Python primitive types names - m_pythonPrimitiveTypeName.clear(); - - // PyBool - m_pythonPrimitiveTypeName["bool"] = "PyBool"; - - // PyInt - m_pythonPrimitiveTypeName["char"] = "SbkChar"; - m_pythonPrimitiveTypeName["signed char"] = "SbkChar"; - m_pythonPrimitiveTypeName["unsigned char"] = "SbkChar"; - m_pythonPrimitiveTypeName["int"] = "PyInt"; - m_pythonPrimitiveTypeName["signed int"] = "PyInt"; - m_pythonPrimitiveTypeName["uint"] = "PyInt"; - m_pythonPrimitiveTypeName["unsigned int"] = "PyInt"; - m_pythonPrimitiveTypeName["short"] = "PyInt"; - m_pythonPrimitiveTypeName["ushort"] = "PyInt"; - m_pythonPrimitiveTypeName["signed short"] = "PyInt"; - m_pythonPrimitiveTypeName["signed short int"] = "PyInt"; - m_pythonPrimitiveTypeName["unsigned short"] = "PyInt"; - m_pythonPrimitiveTypeName["unsigned short int"] = "PyInt"; - m_pythonPrimitiveTypeName["long"] = "PyInt"; - - // PyFloat - m_pythonPrimitiveTypeName["double"] = "PyFloat"; - m_pythonPrimitiveTypeName["float"] = "PyFloat"; - - // PyLong - m_pythonPrimitiveTypeName["unsigned long"] = "PyLong"; - m_pythonPrimitiveTypeName["signed long"] = "PyLong"; - m_pythonPrimitiveTypeName["ulong"] = "PyLong"; - m_pythonPrimitiveTypeName["long long"] = "PyLong"; - m_pythonPrimitiveTypeName["__int64"] = "PyLong"; - m_pythonPrimitiveTypeName["unsigned long long"] = "PyLong"; - m_pythonPrimitiveTypeName["unsigned __int64"] = "PyLong"; - - // Python operators - m_pythonOperators.clear(); - - // call operator - m_pythonOperators["operator()"] = "call"; - - // Arithmetic operators - m_pythonOperators["operator+"] = "add"; - m_pythonOperators["operator-"] = "sub"; - m_pythonOperators["operator*"] = "mul"; - m_pythonOperators["operator/"] = "div"; - m_pythonOperators["operator%"] = "mod"; - - // Inplace arithmetic operators - m_pythonOperators["operator+="] = "iadd"; - m_pythonOperators["operator-="] = "isub"; - m_pythonOperators["operator++"] = "iadd"; - m_pythonOperators["operator--"] = "isub"; - m_pythonOperators["operator*="] = "imul"; - m_pythonOperators["operator/="] = "idiv"; - m_pythonOperators["operator%="] = "imod"; - - // Bitwise operators - m_pythonOperators["operator&"] = "and"; - m_pythonOperators["operator^"] = "xor"; - m_pythonOperators["operator|"] = "or"; - m_pythonOperators["operator<<"] = "lshift"; - m_pythonOperators["operator>>"] = "rshift"; - m_pythonOperators["operator~"] = "invert"; - - // Inplace bitwise operators - m_pythonOperators["operator&="] = "iand"; - m_pythonOperators["operator^="] = "ixor"; - m_pythonOperators["operator|="] = "ior"; - m_pythonOperators["operator<<="] = "ilshift"; - m_pythonOperators["operator>>="] = "irshift"; - - // Comparison operators - m_pythonOperators["operator=="] = "eq"; - m_pythonOperators["operator!="] = "ne"; - m_pythonOperators["operator<"] = "lt"; - m_pythonOperators["operator>"] = "gt"; - m_pythonOperators["operator<="] = "le"; - m_pythonOperators["operator>="] = "ge"; - - // Initialize format units for C++->Python->C++ conversion - m_formatUnits.clear(); - m_formatUnits.insert("char", "b"); - m_formatUnits.insert("unsigned char", "B"); - m_formatUnits.insert("int", "i"); - m_formatUnits.insert("unsigned int", "I"); - m_formatUnits.insert("short", "h"); - m_formatUnits.insert("unsigned short", "H"); - m_formatUnits.insert("long", "l"); - m_formatUnits.insert("unsigned long", "k"); - m_formatUnits.insert("long long", "L"); - m_formatUnits.insert("__int64", "L"); - m_formatUnits.insert("unsigned long long", "K"); - m_formatUnits.insert("unsigned __int64", "K"); - m_formatUnits.insert("double", "d"); - m_formatUnits.insert("float", "f"); -} - -void ShibokenGenerator::initKnownPythonTypes() -{ - m_knownPythonTypes.clear(); - m_knownPythonTypes << "PyBool" << "PyInt" << "PyFloat" << "PyLong"; - m_knownPythonTypes << "PyObject" << "PyString" << "PyBuffer"; - m_knownPythonTypes << "PySequence" << "PyTuple" << "PyList" << "PyDict"; - m_knownPythonTypes << "PyObject*" << "PyObject *" << "PyTupleObject*"; -} - -QString ShibokenGenerator::translateTypeForWrapperMethod(const AbstractMetaType* cType, - const AbstractMetaClass* context, - Options options) const -{ - if (cType->isArray()) - return translateTypeForWrapperMethod(cType->arrayElementType(), context, options) + "[]"; - - 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("::", "_"); - - result +="Wrapper"; - return result; - } else { - return metaClass->qualifiedCppName(); - } -} - -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 + '.'); - } - return funcName; -} - -QString ShibokenGenerator::protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum) -{ - return metaEnum->fullName().replace(".", "_") + "_Surrogate"; -} - -QString ShibokenGenerator::protectedFieldGetterName(const AbstractMetaField* field) -{ - return QString("protected_%1_getter").arg(field->name()); -} - -QString ShibokenGenerator::protectedFieldSetterName(const AbstractMetaField* field) -{ - return QString("protected_%1_setter").arg(field->name()); -} - -QString ShibokenGenerator::cpythonFunctionName(const AbstractMetaFunction* func) -{ - QString result; - - if (func->ownerClass()) { - result = cpythonBaseName(func->ownerClass()->typeEntry()); - if (func->isConstructor() || func->isCopyConstructor()) { - result += "_Init"; - } else { - result += "Func_"; - if (func->isOperatorOverload()) - result += ShibokenGenerator::pythonOperatorFunctionName(func); - else - result += func->name(); - } - } else { - result = "Sbk" + moduleName() + "Module_" + func->name(); - } - - return result; -} - -QString ShibokenGenerator::cpythonMethodDefinitionName(const AbstractMetaFunction* func) -{ - if (!func->ownerClass()) - return QString(); - return QString("%1Method_%2").arg(cpythonBaseName(func->ownerClass()->typeEntry())).arg(func->name()); -} - -QString ShibokenGenerator::cpythonGettersSettersDefinitionName(const AbstractMetaClass* metaClass) -{ - return QString("%1_getsetlist").arg(cpythonBaseName(metaClass)); -} - -QString ShibokenGenerator::cpythonSetattroFunctionName(const AbstractMetaClass* metaClass) -{ - return QString("%1_setattro").arg(cpythonBaseName(metaClass)); -} - - -QString ShibokenGenerator::cpythonGetattroFunctionName(const AbstractMetaClass* metaClass) -{ - return QString("%1_getattro").arg(cpythonBaseName(metaClass)); -} - -QString ShibokenGenerator::cpythonGetterFunctionName(const AbstractMetaField* metaField) -{ - return QString("%1_get_%2").arg(cpythonBaseName(metaField->enclosingClass())).arg(metaField->name()); -} - -QString ShibokenGenerator::cpythonSetterFunctionName(const AbstractMetaField* metaField) -{ - return QString("%1_set_%2").arg(cpythonBaseName(metaField->enclosingClass())).arg(metaField->name()); -} - -static QString cpythonEnumFlagsName(QString moduleName, QString qualifiedCppName) -{ - QString result = QString("Sbk%1_%2").arg(moduleName).arg(qualifiedCppName); - result.replace("::", "_"); - 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(); - } - } - - return searchForEnumScope(metaClass->enclosingClass(), enumValueName); -} - -/* - * 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(); - - static QRegExp enumValueRegEx("^([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("^\\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); - if (arg->type()->isReference()) - typeName.chop(1); - prefix = typeName + '('; - suffix = ')'; - } - - static QRegExp enumCombinationRegEx("^([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("|"); - QString scope = searchForEnumScope(func->implementingClass(), enumItems.first()); - if (!scope.isEmpty()) - scope.append("::"); - - QStringList fixedEnumItems; - foreach (const QString& enumItem, enumItems) - fixedEnumItems << QString(scope + enumItem); - - if (!fixedEnumItems.isEmpty()) { - prefix = flagName + '('; - value = fixedEnumItems.join("|"); - suffix = ')'; - } - } - } else if (arg->type()->typeEntry()->isValue()) { - const AbstractMetaClass* metaClass = classes().findClass(arg->type()->typeEntry()); - if (enumValueRegEx.exactMatch(value)) - prefix = resolveScopePrefix(metaClass, value); - } else if (arg->type()->isPrimitive() && arg->type()->name() == "int") { - if (enumValueRegEx.exactMatch(value) && func->implementingClass()) - prefix = resolveScopePrefix(func->implementingClass(), value); - } else if(arg->type()->isPrimitive()) { - static QRegExp unknowArgumentRegEx("^(?:[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= ""; - } else { - fieldName.prepend(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) -{ - return cpythonEnumFlagsName(enumEntry->targetLangPackage().replace(".", "_"), enumEntry->qualifiedCppName()); -} - -QString ShibokenGenerator::cpythonFlagsName(const FlagsTypeEntry* flagsEntry) -{ - return cpythonEnumFlagsName(flagsEntry->targetLangPackage().replace(".", "_"), flagsEntry->originalName()); -} - -QString ShibokenGenerator::cpythonSpecialCastFunctionName(const AbstractMetaClass* metaClass) -{ - return cpythonBaseName(metaClass->typeEntry())+"SpecialCastFunction"; -} - -QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClass* metaClass, QString argName) -{ - return cpythonWrapperCPtr(metaClass->typeEntry(), argName); -} - -QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType* metaType, QString argName) -{ - return cpythonWrapperCPtr(metaType->typeEntry(), argName); -} - -QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntry* type, QString argName) -{ - if (!ShibokenGenerator::isWrapperType(type)) - return QString(); - return QString("((::%1*)Shiboken::Conversions::cppPointer(%2, (SbkObject*)%3))") - .arg(type->qualifiedCppName()) - .arg(cpythonTypeNameExt(type)) - .arg(argName); -} - -QString ShibokenGenerator::getFunctionReturnType(const AbstractMetaFunction* func, Options options) const -{ - if (func->ownerClass() && (func->isConstructor() || func->isCopyConstructor())) - return func->ownerClass()->qualifiedCppName() + '*'; - - 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 (FunctionModification funcMod, func->modifications()) { - foreach (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 += 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()->isReference()) { - result += objType; - } else if (arg->type()->isPrimitive()) { - const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) arg->type()->typeEntry(); - if (ptype->basicAliasedTypeEntry()) - ptype = ptype->basicAliasedTypeEntry(); - if (m_formatUnits.contains(ptype->name())) - result += m_formatUnits[ptype->name()]; - else - result += objType; - } else if (isCString(arg->type())) { - result += 'z'; - } else { - QString report; - QTextStream(&report) << "Method: " << func->ownerClass()->qualifiedCppName() - << "::" << func->signature() << " => Arg:" - << arg->name() << "index: " << arg->argumentIndex() - << " - cannot be handled properly. Use an inject-code to fix it!"; - ReportHandler::warning(report); - result += '?'; - } - } - return result; -} - -QString ShibokenGenerator::cpythonBaseName(const AbstractMetaType* type) -{ - if (isCString(type)) - return QString("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->isReference()) { - baseName = "Sbk_" + type->name(); - } else if (type->isPrimitive()) { - const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) type; - while (ptype->basicAliasedTypeEntry()) - ptype = ptype->basicAliasedTypeEntry(); - if (ptype->targetLangApiName() == ptype->name()) - baseName = m_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 = "PySequence"; - break; - case ContainerTypeEntry::SetContainer: - baseName = "PySet"; - break; - case ContainerTypeEntry::MapContainer: - case ContainerTypeEntry::MultiMapContainer: - case ContainerTypeEntry::HashContainer: - case ContainerTypeEntry::MultiHashContainer: - baseName = "PyDict"; - break; - default: - Q_ASSERT(false); - } - } else { - baseName = "PyObject"; - } - return baseName.replace("::", "_"); -} - -QString ShibokenGenerator::cpythonTypeName(const AbstractMetaClass* metaClass) -{ - return cpythonTypeName(metaClass->typeEntry()); -} - -QString ShibokenGenerator::cpythonTypeName(const TypeEntry* type) -{ - return cpythonBaseName(type) + "_Type"; -} - -QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntry* type) -{ - return cppApiVariableName(type->targetLangPackage()) + '[' + getTypeIndexVariableName(type) + ']'; -} - -QString ShibokenGenerator::converterObject(const AbstractMetaType* type) -{ - if (isCString(type)) - return "Shiboken::Conversions::PrimitiveTypeConverter<const char*>()"; - if (isVoidPointer(type)) - return "Shiboken::Conversions::PrimitiveTypeConverter<void*>()"; - if (type->typeEntry()->isContainer()) - return QString("%1[%2]").arg(convertersVariableName(type->typeEntry()->targetLangPackage())).arg(getTypeIndexVariableName(type)); - - return converterObject(type->typeEntry()); -} - -QString ShibokenGenerator::converterObject(const TypeEntry* type) -{ - if (isCppPrimitive(type)) - return QString("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(type->qualifiedCppName()); - if (isWrapperType(type) || type->isEnum() || type->isFlags()) - return QString("SBK_CONVERTER(%1)").arg(cpythonTypeNameExt(type)); - - /* the typedef'd primitive types case */ - const PrimitiveTypeEntry* pte = reinterpret_cast<const PrimitiveTypeEntry*>(type); - if (pte->basicAliasedTypeEntry()) - pte = pte->basicAliasedTypeEntry(); - if (pte->isPrimitive() && !pte->isCppPrimitive() && !pte->customConversion()) - return QString("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(pte->qualifiedCppName()); - - return QString("%1[%2]").arg(convertersVariableName(type->targetLangPackage())).arg(getTypeIndexVariableName(type)); -} - -QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType* type) -{ - return cppApiVariableName(type->typeEntry()->targetLangPackage()) + '[' + getTypeIndexVariableName(type) + ']'; -} - -QString ShibokenGenerator::cpythonOperatorFunctionName(const AbstractMetaFunction* func) -{ - if (!func->isOperatorOverload()) - return QString(); - return QString("Sbk") + func->ownerClass()->name() - + '_' + pythonOperatorFunctionName(func->originalName()); -} - -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) -{ - return typeName.replace(" ", "") - .replace(".", "_") - .replace(",", "_") - .replace("<", "_") - .replace(">", "_") - .replace("::", "_") - .replace("*", "PTR") - .replace("&", "REF"); -} -QString ShibokenGenerator::fixedCppTypeName(const TypeEntry* type, QString typeName) -{ - if (typeName.isEmpty()) - typeName = type->qualifiedCppName(); - if (!(type->codeGeneration() & TypeEntry::GenerateTargetLang)) - typeName.prepend(QString("%1_").arg(type->targetLangPackage())); - return _fixedCppTypeName(typeName); -} - -QString ShibokenGenerator::pythonPrimitiveTypeName(const QString& cppTypeName) -{ - return ShibokenGenerator::m_pythonPrimitiveTypeName.value(cppTypeName, QString()); -} - -QString ShibokenGenerator::pythonPrimitiveTypeName(const PrimitiveTypeEntry* type) -{ - while (type->basicAliasedTypeEntry()) - type = type->basicAliasedTypeEntry(); - return pythonPrimitiveTypeName(type->name()); -} - -QString ShibokenGenerator::pythonOperatorFunctionName(QString cppOpFuncName) -{ - QString value = m_pythonOperators.value(cppOpFuncName); - if (value.isEmpty()) { - ReportHandler::warning("Unknown operator: "+cppOpFuncName); - value = "UNKNOWN_OPERATOR"; - } - value.prepend("__").append("__"); - return value; -} - -QString ShibokenGenerator::pythonOperatorFunctionName(const AbstractMetaFunction* func) -{ - QString op = pythonOperatorFunctionName(func->originalName()); - if (func->arguments().isEmpty()) { - if (op == "__sub__") - op = QString("__neg__"); - else if (op == "__add__") - op = QString("__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, 'r'); - } - return op; -} - -QString ShibokenGenerator::pythonRichCompareOperatorId(QString cppOpFuncName) -{ - return QString("Py_%1").arg(m_pythonOperators.value(cppOpFuncName).toUpper()); -} - -QString ShibokenGenerator::pythonRichCompareOperatorId(const AbstractMetaFunction* func) -{ - return pythonRichCompareOperatorId(func->originalName()); -} - -bool ShibokenGenerator::isNumber(QString cpythonApiName) -{ - return cpythonApiName == "PyInt" - || cpythonApiName == "PyFloat" - || cpythonApiName == "PyLong" - || cpythonApiName == "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) == "PyInt"; -} - -bool ShibokenGenerator::isPyInt(const AbstractMetaType* type) -{ - return isPyInt(type->typeEntry()); -} - -bool ShibokenGenerator::isPairContainer(const AbstractMetaType* type) -{ - return type->isContainer() - && ((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(); -} -bool ShibokenGenerator::isWrapperType(const ComplexTypeEntry* type) -{ - return isObjectType(type) || type->isValue(); -} -bool ShibokenGenerator::isWrapperType(const AbstractMetaType* metaType) -{ - return isObjectType(metaType) - || metaType->typeEntry()->isValue(); -} - -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->isReference() && 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()->isCopyConstructor(); -} - -bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const TypeEntry* type) const -{ - if (!type || !type->isValue()) - return false; - return isValueTypeWithCopyConstructorOnly(classes().findClass(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->basicAliasedTypeEntry()) - trueType = trueType->basicAliasedTypeEntry(); - return trueType->isPrimitive() && !trueType->isCppPrimitive() && trueType->qualifiedCppName() != "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->basicAliasedTypeEntry()) - trueType = trueType->basicAliasedTypeEntry(); - return trueType->qualifiedCppName() == "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->isReference() && isWrapperType(metaType) && !isPointer(metaType); -} - -bool ShibokenGenerator::visibilityModifiedToPrivate(const AbstractMetaFunction* func) -{ - foreach (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 "Shiboken::String::check"; - if (isVoidPointer(metaType)) - return "PyObject_Check"; - return cpythonCheckFunction(metaType->typeEntry(), genericNumberType); - } else if (metaType->typeEntry()->isContainer()) { - QString typeCheck = "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("checkSequenceTypes(%1, ").arg(cpythonTypeNameExt(type)); - else if (isWrapperType(type)) - typeCheck += QString("convertibleSequenceTypes((SbkObjectType*)%1, ").arg(cpythonTypeNameExt(type)); - else - typeCheck += QString("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) ? "Pair" : "Dict"; - const AbstractMetaType* firstType = metaType->instantiations().first(); - const AbstractMetaType* secondType = metaType->instantiations().last(); - if (isPointerToWrapperType(firstType) && isPointerToWrapperType(secondType)) { - typeCheck += QString("check%1Types(%2, %3, ").arg(pyType) - .arg(cpythonTypeNameExt(firstType)) - .arg(cpythonTypeNameExt(secondType)); - } else { - typeCheck += QString("convertible%1Types(%2, %3, %4, %5, ").arg(pyType) - .arg(converterObject(firstType)) - .arg(isPointerToWrapperType(firstType) ? "true" : "false") - .arg(converterObject(secondType)) - .arg(isPointerToWrapperType(secondType) ? "true" : "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("SbkObject_TypeCheck(%1, ").arg(cpythonTypeNameExt(type)); - else if (isCppPrimitive(type)) - return QString("%1_Check").arg(pythonPrimitiveTypeName((const PrimitiveTypeEntry*)type)); - QString typeCheck; - if (type->targetLangApiName() == type->name()) - typeCheck = cpythonIsConvertibleFunction(type); - else if (type->targetLangApiName() == "PyUnicode") - typeCheck = "Shiboken::String::check"; - else - typeCheck = QString("%1_Check").arg(type->targetLangApiName()); - return typeCheck; -} - -QString ShibokenGenerator::guessCPythonCheckFunction(const QString& type, AbstractMetaType** metaType) -{ - *metaType = 0; - if (type == "PyTypeObject") - return "PyType_Check"; - - if (type == "PyBuffer") - return "Shiboken::Buffer::checkType"; - - if (type == "str") - return "Shiboken::String::check"; - - *metaType = buildAbstractMetaTypeFromString(type); - if (*metaType && !(*metaType)->typeEntry()->isCustom()) - return QString(); - - return QString("%1_Check").arg(type); -} - -QString ShibokenGenerator::guessCPythonIsConvertible(const QString& type) -{ - if (type == "PyTypeObject") - return "PyType_Check"; - - AbstractMetaType* metaType = buildAbstractMetaTypeFromString(type); - if (metaType && !metaType->typeEntry()->isCustom()) - return cpythonIsConvertibleFunction(metaType); - - return QString("%1_Check").arg(type); -} - -QString ShibokenGenerator::cpythonIsConvertibleFunction(const TypeEntry* type, bool genericNumberType, bool checkExact) -{ - if (isWrapperType(type)) { - QString isConv = (type->isValue() && !isValueTypeWithCopyConstructorOnly(type)) - ? "isPythonToCppValueConvertible" - : "isPythonToCppPointerConvertible"; - return QString("Shiboken::Conversions::%1((SbkObjectType*)%2, ") - .arg(isConv).arg(cpythonTypeNameExt(type)); - } - return QString("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 isConv; - if (isPointer(metaType) || isValueTypeWithCopyConstructorOnly(metaType)) - isConv = "isPythonToCppPointerConvertible"; - else if (metaType->isReference()) - isConv = "isPythonToCppReferenceConvertible"; - else - isConv = "isPythonToCppValueConvertible"; - return QString("Shiboken::Conversions::%1((SbkObjectType*)%2, ") - .arg(isConv).arg(cpythonTypeNameExt(metaType)); - } - return QString("Shiboken::Conversions::isPythonToCppConvertible(%1, ") - .arg(converterObject(metaType)); -} - -QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaClass* metaClass) -{ - return QString("Shiboken::Conversions::pythonToCppPointer((SbkObjectType*)%1, ") - .arg(cpythonTypeNameExt(metaClass->typeEntry())); -} -QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaType* type, const AbstractMetaClass* context) -{ - if (isWrapperType(type)) { - return QString("Shiboken::Conversions::pythonToCpp%1((SbkObjectType*)%2, ") - .arg(isPointer(type) ? "Pointer" : "Copy") - .arg(cpythonTypeNameExt(type)); - } - return QString("Shiboken::Conversions::pythonToCppCopy(%1, ") - .arg(converterObject(type)); -} - -QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaType* type, const AbstractMetaClass* context) -{ - if (isWrapperType(type)) { - QString conversion; - if (type->isReference() && !(type->isValue() && type->isConstant()) && !isPointer(type)) - conversion = "reference"; - else if (type->isValue()) - conversion = "copy"; - else - conversion = "pointer"; - return QString("Shiboken::Conversions::%1ToPython((SbkObjectType*)%2, %3") - .arg(conversion).arg(cpythonTypeNameExt(type)).arg(conversion == "pointer" ? "" : "&"); - } - return QString("Shiboken::Conversions::copyToPython(%1, %2") - .arg(converterObject(type)) - .arg((isCString(type) || isVoidPointer(type)) ? "" : "&"); -} - -QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaClass* metaClass) -{ - return cpythonToPythonConversionFunction(metaClass->typeEntry()); -} - -QString ShibokenGenerator::cpythonToPythonConversionFunction(const TypeEntry* type) -{ - if (isWrapperType(type)) { - QString conversion; - if (type->isValue()) - conversion = "copy"; - else - conversion = "pointer"; - return QString("Shiboken::Conversions::%1ToPython((SbkObjectType*)%2, %3") - .arg(conversion).arg(cpythonTypeNameExt(type)).arg(conversion == "pointer" ? "" : "&"); - } - - return QString("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('$', '.'); - - if (!(options & Generator::SkipName)) { - arg += " "; - 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 == "NULL") - default_value = NULL_VALUE; - - //WORKAROUND: fix this please - if (default_value.startsWith("new ")) - default_value.remove(0, 4); - - arg += " = " + 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()) { - //skip signals - if (func->isSignal() || func->isDestructor() - || (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 QString funcCall("%CPPSELF.%FUNCTION_NAME"); - int pos = str.indexOf(funcCall); - if (pos == -1) - return QString(); - pos = pos + funcCall.count(); - while (str.at(pos) == ' ' || str.at(pos) == '\t') - ++pos; - if (str.at(pos) == '(') - ++pos; - int begin = pos; - int counter = 1; - while (counter != 0) { - if (str.at(pos) == '(') - ++counter; - else if (str.at(pos) == ')') - --counter; - ++pos; - } - return str.mid(begin, pos-begin-1); -} - -QString ShibokenGenerator::getCodeSnippets(const CodeSnipList& codeSnips, - CodeSnip::Position position, - TypeSystem::Language language) -{ - QString code; - QTextStream c(&code); - foreach (CodeSnip snip, codeSnips) { - if ((position != CodeSnip::Any && 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("%PYTHONTYPEOBJECT", cpythonTypeName(context) + ".super.ht_type"); - code.replace("%TYPE", wrapperName(context)); - code.replace("%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 = QString("%1"CONV_RULE_OUT_VAR_SUFFIX).arg(arg->name()); - else if (argRemoved || (lastArg && arg->argumentIndex() > lastArg->argumentIndex())) - argValue = QString(CPP_ARG_REMOVED"%1").arg(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(PYTHON_ARGS"[%1]").arg(argPos) : PYTHON_ARG; - } else { - argValue = hasConversionRule - ? QString("%1"CONV_RULE_OUT_VAR_SUFFIX).arg(arg->name()) - : QString(CPP_ARG"%1").arg(argPos); - if (isWrapperType(type)) { - if (type->isReference() && !isPointer(type)) - argValue.prepend('*'); - } - } - } - } else { - argValue = arg->name(); - } - if (!argValue.isEmpty()) - argReplacements << ArgumentVarReplacementPair(arg, argValue); - - } - return argReplacements; -} - -void ShibokenGenerator::writeCodeSnips(QTextStream& s, - const CodeSnipList& codeSnips, - CodeSnip::Position 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, - CodeSnip::Position 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("%PYARG_0", PYTHON_RETURN_VAR); - - static QRegExp pyArgsRegex("%PYARG_(\\d+)"); - if (language == TypeSystem::TargetLangCode) { - if (usePyArgs) { - code.replace(pyArgsRegex, PYTHON_ARGS"[\\1-1]"); - } else { - static QRegExp pyArgsRegexCheck("%PYARG_([2-9]+)"); - if (pyArgsRegexCheck.indexIn(code) != -1) { - ReportHandler::warning("Wrong index for %PYARG variable ("+pyArgsRegexCheck.cap(1)+") on "+func->signature()); - return; - } - code.replace("%PYARG_1", PYTHON_ARG); - } - } else { - // Replaces the simplest case of attribution to a - // Python argument on the binding virtual method. - static QRegExp pyArgsAttributionRegex("%PYARG_(\\d+)\\s*=[^=]\\s*([^;]+)"); - code.replace(pyArgsAttributionRegex, "PyTuple_SET_ITEM(" PYTHON_ARGS ", \\1-1, \\2)"); - code.replace(pyArgsRegex, "PyTuple_GET_ITEM(" PYTHON_ARGS ", \\1-1)"); - } - - // Replace %ARG#_TYPE variables. - foreach (const AbstractMetaArgument* arg, func->arguments()) { - QString argTypeVar = QString("%ARG%1_TYPE").arg(arg->argumentIndex() + 1); - QString argTypeVal = arg->type()->cppSignature(); - code.replace(argTypeVar, argTypeVal); - } - - int pos = 0; - static QRegExp cppArgTypeRegexCheck("%ARG(\\d+)_TYPE"); - while ((pos = cppArgTypeRegexCheck.indexIn(code, pos)) != -1) { - ReportHandler::warning("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("%0.", QString("%1->").arg("cptr")); - code.replace("%0", "cptr"); - } else if (func->type()) { - QString returnValueOp = isPointerToWrapperType(func->type()) ? "%1->" : "%1."; - if (ShibokenGenerator::isWrapperType(func->type())) - code.replace("%0.", returnValueOp.arg(CPP_RETURN_VAR)); - code.replace("%0", CPP_RETURN_VAR); - } - - // Replace template variable for self Python object. - QString pySelf = (language == TypeSystem::NativeCode) ? "pySelf" : PYTHON_SELF_VAR; - code.replace("%PYSELF", pySelf); - - // Replace template variable for a pointer to C++ of this object. - if (func->implementingClass()) { - QString replacement = func->isStatic() ? "%1::" : "%1->"; - QString cppSelf; - if (func->isStatic()) - cppSelf = func->ownerClass()->qualifiedCppName(); - else if (language == TypeSystem::NativeCode) - cppSelf = "this"; - else - cppSelf = CPP_SELF_VAR; - - // On comparison operator CPP_SELF_VAR is always a reference. - if (func->isComparisonOperator()) - replacement = "%1."; - - if (func->isVirtual() && !func->isAbstract() && (!avoidProtectedHack() || !func->isProtected())) { - QString methodCallArgs = getArgumentsFromMethodCall(code); - if (!methodCallArgs.isNull()) { - if (func->name() == "metaObject") { - QString wrapperClassName = wrapperName(func->ownerClass()); - QString cppSelfVar = avoidProtectedHack() ? QString("%CPPSELF") : QString("reinterpret_cast<%1*>(%CPPSELF)").arg(wrapperClassName); - code.replace(QString("%CPPSELF.%FUNCTION_NAME(%1)").arg(methodCallArgs), - QString("(Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(%1))" - " ? %2->::%3::%FUNCTION_NAME(%4)" - " : %CPPSELF.%FUNCTION_NAME(%4))").arg(pySelf).arg(cppSelfVar).arg(wrapperClassName).arg(methodCallArgs)); - } else { - code.replace(QString("%CPPSELF.%FUNCTION_NAME(%1)").arg(methodCallArgs), - QString("(Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(%1))" - " ? %CPPSELF->::%TYPE::%FUNCTION_NAME(%2)" - " : %CPPSELF.%FUNCTION_NAME(%2))").arg(pySelf).arg(methodCallArgs)); - } - } - } - - code.replace("%CPPSELF.", replacement.arg(cppSelf)); - code.replace("%CPPSELF", cppSelf); - - if (code.indexOf("%BEGIN_ALLOW_THREADS") > -1) { - if (code.count("%BEGIN_ALLOW_THREADS") == code.count("%END_ALLOW_THREADS")) { - code.replace("%BEGIN_ALLOW_THREADS", BEGIN_ALLOW_THREADS); - code.replace("%END_ALLOW_THREADS", END_ALLOW_THREADS); - } else { - ReportHandler::warning("%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("%PYTHONTYPEOBJECT", cpythonTypeName(func->implementingClass()) + ".super.ht_type"); - } else { - code.replace("%PYTHONTYPEOBJECT.", QString("%1->ob_type->").arg(pySelf)); - code.replace("%PYTHONTYPEOBJECT", QString("%1->ob_type").arg(pySelf)); - } - } - - // 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 (ArgumentVarReplacementPair pair, argReplacements) { - if (pair.second.startsWith(CPP_ARG_REMOVED)) - continue; - args << pair.second; - } - code.replace("%ARGUMENT_NAMES", args.join(", ")); - - foreach (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->isReference() && !isPointer(type)) - replacement.remove(0, 1); - if (type->isReference() || isPointer(type)) - code.replace(QString("%%1.").arg(idx), QString("%1->").arg(replacement)); - } - code.replace(QString("%%1").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("%PYTHON_ARGUMENTS", 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("%PYTHON_METHOD_OVERRIDE", 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("%TYPE::%FUNCTION_NAME", - QString("%1::%2_protected") - .arg(wrapperName(func->ownerClass())) - .arg(func->originalName())); - code.replace("%FUNCTION_NAME", QString("%1_protected").arg(func->originalName())); - } - } - - if (func->isConstructor() && shouldGenerateCppWrapper(func->ownerClass())) - code.replace("%TYPE", wrapperName(func->ownerClass())); - - if (func->ownerClass()) - code.replace("%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("\\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("::")) - normalized.remove(0, 2); - QString suffix; - while (normalized.endsWith('*') || normalized.endsWith('&')) { - suffix.prepend(normalized.at(normalized.count() - 1)); - normalized.chop(1); - normalized = normalized.trimmed(); - } - return QString("%1 %2").arg(normalized).arg(suffix).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).toAscii(); - 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("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) != '\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("Types of receiver variable ('%1') and %CONVERTTOCPP type system variable ('%2') differ.") - .arg(varType).arg(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('*')) { - varName.remove(0, 1); - varName = varName.trimmed(); - } else { - prefix = '&'; - } - QString arg = getConverterTypeSystemVariableArgument(code, pos); - conversionString += arg; - c << arg << ", " << prefix << '(' << varName << ')'; - break; - } - case TypeSystemCheckFunction: - conversion = cpythonCheckFunction(conversionType); - if (conversionType->typeEntry()->isPrimitive() && (conversionType->typeEntry()->name() == "PyObject" || !conversion.endsWith(' '))) { - 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("Only variables are acceptable as argument to %%CONVERTTOPYTHON type system variable on code snippet: '%1'") - .arg(code)), NULL); - } - if (conversion.contains("%in")) { - conversion.prepend('('); - conversion.replace("%in", arg); - } else { - c << arg; - } - } - } - replacements.append(qMakePair(conversionString, conversion)); - } - foreach (StringPair rep, replacements) - code.replace(rep.first, rep.second); -} - -bool ShibokenGenerator::injectedCodeUsesCppSelf(const AbstractMetaFunction* func) -{ - CodeSnipList snips = func->injectedCodeSnips(CodeSnip::Any, TypeSystem::TargetLangCode); - foreach (CodeSnip snip, snips) { - if (snip.code().contains("%CPPSELF")) - return true; - } - return false; -} - -bool ShibokenGenerator::injectedCodeUsesPySelf(const AbstractMetaFunction* func) -{ - CodeSnipList snips = func->injectedCodeSnips(CodeSnip::Any, TypeSystem::NativeCode); - foreach (CodeSnip snip, snips) { - if (snip.code().contains("%PYSELF")) - return true; - } - return false; -} - -bool ShibokenGenerator::injectedCodeCallsCppFunction(const AbstractMetaFunction* func) -{ - QString funcCall = QString("%1(").arg(func->originalName()); - QString wrappedCtorCall; - if (func->isConstructor()) { - funcCall.prepend("new "); - wrappedCtorCall = QString("new %1(").arg(wrapperName(func->ownerClass())); - } - CodeSnipList snips = func->injectedCodeSnips(CodeSnip::Any, TypeSystem::TargetLangCode); - foreach (CodeSnip snip, snips) { - if (snip.code().contains("%FUNCTION_NAME(") || snip.code().contains(funcCall) - || (func->isConstructor() - && ((func->ownerClass()->isPolymorphic() && snip.code().contains(wrappedCtorCall)) - || snip.code().contains("new %TYPE("))) - ) - return true; - } - return false; -} - -bool ShibokenGenerator::injectedCodeCallsPythonOverride(const AbstractMetaFunction* func) -{ - static QRegExp overrideCallRegexCheck("PyObject_Call\\s*\\(\\s*%PYTHON_METHOD_OVERRIDE\\s*,"); - CodeSnipList snips = func->injectedCodeSnips(CodeSnip::Any, TypeSystem::NativeCode); - foreach (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("%0\\s*=[^=]\\s*.+"); - static QRegExp retValAttributionRegexCheck_target("%PYARG_0\\s*=[^=]\\s*.+"); - CodeSnipList snips = func->injectedCodeSnips(CodeSnip::Any, language); - foreach (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(CodeSnip::Any); - foreach (CodeSnip snip, snips) { - QString code = snip.code(); - if (code.contains("%ARGUMENT_NAMES")) - return true; - if (code.contains(QString("%%1").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()); -} - -bool ShibokenGenerator::classNeedsGetattroFunction(const AbstractMetaClass* metaClass) -{ - if (!metaClass) - return false; - foreach (AbstractMetaFunctionList allOverloads, getFunctionGroups(metaClass).values()) { - AbstractMetaFunctionList overloads; - foreach (AbstractMetaFunction* func, allOverloads) { - 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; -} - -AbstractMetaFunctionList ShibokenGenerator::getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass* metaClass) -{ - AbstractMetaFunctionList methods; - if (metaClass) { - foreach (AbstractMetaFunctionList allOverloads, getFunctionGroups(metaClass).values()) { - AbstractMetaFunctionList overloads; - foreach (AbstractMetaFunction* func, allOverloads) { - 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 (QString parent, metaClass->baseClassNames()) { - AbstractMetaClass* clazz = classes().findClass(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(".", "_"); - return QString("%1_python.h").arg(result.toLower()); -} - -QString ShibokenGenerator::extendedIsConvertibleFunctionName(const TypeEntry* targetType) const -{ - return QString("ExtendedIsConvertible_%1_%2").arg(targetType->targetLangPackage().replace('.', '_')).arg(targetType->name()); -} - -QString ShibokenGenerator::extendedToCppFunctionName(const TypeEntry* targetType) const -{ - return QString("ExtendedToCpp_%1_%2").arg(targetType->targetLangPackage().replace('.', '_')).arg(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("::")) - typeSignature = typeSignature.mid(2); - - if (m_metaTypeFromStringCache.contains(typeSignature)) - return m_metaTypeFromStringCache.value(typeSignature); - - QString typeString = typeSignature; - bool isConst = typeString.startsWith("const "); - if (isConst) - typeString.remove(0, sizeof("const ") / sizeof(char) - 1); - - int indirections = typeString.count("*"); - while (typeString.endsWith("*")) { - typeString.chop(1); - typeString = typeString.trimmed(); - } - - bool isReference = typeString.endsWith("&"); - if (isReference) { - typeString.chop(1); - typeString = typeString.trimmed(); - } - - if (typeString.startsWith("::")) - typeString.remove(0, 2); - - QString adjustedTypeName = typeString; - QStringList instantiatedTypes; - int lpos = typeString.indexOf('<'); - if (lpos > -1) { - int rpos = typeString.lastIndexOf('>'); - 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) == '<') { - ++depth; - } else if (type.at(i) == '>') { - --depth; - } else if (type.at(i) == ',' && depth == 0) { - instantiatedTypes << type.mid(start, i - start).trimmed(); - start = i + 1; - } - } - instantiatedTypes << type.mid(start).trimmed(); - adjustedTypeName = adjustedTypeName.left(lpos); - } - } - - TypeEntry* typeEntry = TypeDatabase::instance()->findType(adjustedTypeName); - - AbstractMetaType* metaType = 0; - if (typeEntry) { - metaType = new AbstractMetaType(); - metaType->setTypeEntry(typeEntry); - metaType->setIndirections(indirections); - metaType->setReference(isReference); - 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("::")) - typeName = typeName.mid(2); - if (m_metaTypeFromStringCache.contains(typeName)) - return m_metaTypeFromStringCache.value(typeName); - AbstractMetaType* metaType = new AbstractMetaType; - metaType->setTypeEntry(typeEntry); - metaType->setIndirections(0); - metaType->setReference(false); - 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() == "operator[]" || func->name() == "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::getFunctionOverloads(const AbstractMetaClass* scope, const QString& functionName) -{ - AbstractMetaFunctionList lst = scope ? scope->functions() : globalFunctions(); - - AbstractMetaFunctionList results; - foreach (AbstractMetaFunction* func, lst) { - if (func->name() != functionName) - continue; - if (isGroupable(func)) - results << func; - } - 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(AVOID_PROTECTED_HACK, "Avoid the use of the '#define protected public' hack."); - opts.insert(PARENT_CTOR_HEURISTIC, "Enable heuristics to detect parent relationship on constructors."); - opts.insert(RETURN_VALUE_HEURISTIC, "Enable heuristics to detect parent relationship on return values (USE WITH CAUTION!)"); - opts.insert(ENABLE_PYSIDE_EXTENSIONS, "Enable PySide extensions, such as support for signal/slots, use this if you are creating a binding for a Qt-based library."); - opts.insert(DISABLE_VERBOSE_ERROR_MESSAGES, "Disable verbose error messages. Turn the python code hard to debug but safe few kB on the generated bindings."); - opts.insert(USE_ISNULL_AS_NB_NONZERO, "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(PARENT_CTOR_HEURISTIC); - m_usePySideExtensions = args.contains(ENABLE_PYSIDE_EXTENSIONS); - m_userReturnValueHeuristic = args.contains(RETURN_VALUE_HEURISTIC); - m_verboseErrorMessagesDisabled = args.contains(DISABLE_VERBOSE_ERROR_MESSAGES); - m_useIsNullAsNbNonZero = args.contains(USE_ISNULL_AS_NB_NONZERO); - m_avoidProtectedHack = args.contains(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())); - foreach (AbstractMetaFunctionList globalOverloads, getFunctionGroups().values()) { - foreach (AbstractMetaFunction* func, globalOverloads) - 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 ? "%CONVERTTOPYTHON[" : "%CONVERTTOCPP["; - int offset = toPythonMacro ? sizeof("%CONVERTTOPYTHON") : sizeof("%CONVERTTOCPP"); - int start = 0; - while ((start = code.indexOf(convMacro, start)) != -1) { - int end = code.indexOf("]", start); - start += offset; - if (code.at(start) != '%') { - QString typeString = code.mid(start, end - start); - AbstractMetaType* type = buildAbstractMetaTypeFromString(typeString); - addInstantiatedContainers(type); - } - 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(".", "_"); - result.prepend("Sbk"); - result.append("Types"); - return result; -} - -QString ShibokenGenerator::convertersVariableName(const QString& moduleName) const -{ - QString result = cppApiVariableName(moduleName); - result.chop(1); - result.append("Converters"); - return result; -} - -static QString processInstantiationsVariableName(const AbstractMetaType* type) -{ - QString res = QString("_%1").arg(_fixedCppTypeName(type->typeEntry()->qualifiedCppName()).toUpper()); - foreach (const AbstractMetaType* instantiation, type->instantiations()) { - res += instantiation->isContainer() - ? processInstantiationsVariableName(instantiation) - : QString("_%1").arg(_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("SBK_%1%2_IDX").arg(base).arg(instantiations); - } - return getTypeIndexVariableName(metaClass->typeEntry()); -} -QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry* type) -{ - if (type->isCppPrimitive()) { - const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type; - if (trueType->basicAliasedTypeEntry()) - type = trueType->basicAliasedTypeEntry(); - } - return QString("SBK_%1_IDX").arg(_fixedCppTypeName(type->qualifiedCppName()).toUpper()); -} -QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType* type) -{ - return QString("SBK%1%2_IDX") - .arg(type->typeEntry()->isContainer() ? "_"+moduleName().toUpper() : "") - .arg(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->isReference())) { - 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()) - qFatal(qPrintable(QString(MIN_CTOR_ERROR_MSG).arg(type->cppSignature())), NULL); - 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()) - qFatal(qPrintable(QString(MIN_CTOR_ERROR_MSG).arg(type->qualifiedCppName())), NULL); - s << " = " << ctor; -} - -bool ShibokenGenerator::isCppIntegralPrimitive(const TypeEntry* type) -{ - if (!type->isCppPrimitive()) - return false; - const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type; - if (trueType->basicAliasedTypeEntry()) - trueType = trueType->basicAliasedTypeEntry(); - QString typeName = trueType->qualifiedCppName(); - return !typeName.contains("double") && !typeName.contains("float") && !typeName.contains("wchar"); -} -bool ShibokenGenerator::isCppIntegralPrimitive(const AbstractMetaType* type) -{ - return isCppIntegralPrimitive(type->typeEntry()); -} diff --git a/generators/shiboken/shibokengenerator.h b/generators/shiboken/shibokengenerator.h deleted file mode 100644 index 4a73cbc9d..000000000 --- a/generators/shiboken/shibokengenerator.h +++ /dev/null @@ -1,536 +0,0 @@ -/* - * This file is part of the Shiboken Python Bindings Generator project. - * - * Copyright (C) 2009-2012 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: PySide team <contact@pyside.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#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 MIN_CTOR_ERROR_MSG "Could not find a minimal constructor for type '%1'. "\ - "This will result in a compilation error." -#define PYTHON_TO_CPP_VAR "pythonToCpp" - -#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 <QtCore/QTextStream> - -#include "overloaddata.h" - -class DocParser; - -/** - * 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 ofg 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 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 CodeSnipList& codeSnips, - CodeSnip::Position position, - TypeSystem::Language language, - const AbstractMetaClass* context = 0); - /// Write user's custom code snippets at function level. - void writeCodeSnips(QTextStream& s, - const CodeSnipList& codeSnips, - CodeSnip::Position 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 CodeSnipList& codeSnips, CodeSnip::Position 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 append = "", - 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 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; - - 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); - inline QString cpythonIsConvertibleFunction(const AbstractMetaArgument* metaArg, bool genericNumberType = false) - { - return cpythonIsConvertibleFunction(metaArg->type(), genericNumberType); - } - 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 = 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); - inline QString cpythonEnumName(const AbstractMetaEnum* metaEnum) - { - return cpythonEnumName(metaEnum->typeEntry()); - } - - QString cpythonFlagsName(const FlagsTypeEntry* flagsEntry); - inline QString cpythonFlagsName(const AbstractMetaEnum* metaEnum) - { - FlagsTypeEntry* flags = metaEnum->typeEntry()->flags(); - if (!flags) - return QString(); - return cpythonFlagsName(flags); - } - /// 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); - -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/generators/shiboken/shibokennormalize.cpp b/generators/shiboken/shibokennormalize.cpp deleted file mode 100644 index 01aad9732..000000000 --- a/generators/shiboken/shibokennormalize.cpp +++ /dev/null @@ -1,274 +0,0 @@ -/* - * This file is part of the PySide project. - * This code was extracted from qmetaobject_p.h present on Qt4.7. - * - * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: PySide team <contact@pyside.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "shibokennormalize_p.h" -#include <QVarLengthArray> - -#if (QT_VERSION < QT_VERSION_CHECK(4, 7, 0)) - -// mirrored in moc's utils.h -static inline bool is_ident_char(char s) -{ - return ((s >= 'a' && s <= 'z') - || (s >= 'A' && s <= 'Z') - || (s >= '0' && s <= '9') - || s == '_' - ); -} - -static inline bool is_space(char s) -{ - return (s == ' ' || s == '\t'); -} - -static void qRemoveWhitespace(const char *s, char *d) -{ - char last = 0; - while (*s && is_space(*s)) - s++; - while (*s) { - while (*s && !is_space(*s)) - last = *d++ = *s++; - while (*s && is_space(*s)) - s++; - if (*s && ((is_ident_char(*s) && is_ident_char(last)) - || ((*s == ':') && (last == '<')))) { - last = *d++ = ' '; - } - } - *d = '\0'; -} - -// This code is shared with moc.cpp -static QByteArray normalizeTypeInternalQt47(const char *t, const char *e, bool fixScope = false, bool adjustConst = true) -{ - int len = e - t; - /* - Convert 'char const *' into 'const char *'. Start at index 1, - not 0, because 'const char *' is already OK. - */ - QByteArray constbuf; - for (int i = 1; i < len; i++) { - if ( t[i] == 'c' - && strncmp(t + i + 1, "onst", 4) == 0 - && (i + 5 >= len || !is_ident_char(t[i + 5])) - && !is_ident_char(t[i-1]) - ) { - constbuf = QByteArray(t, len); - if (is_space(t[i-1])) - constbuf.remove(i-1, 6); - else - constbuf.remove(i, 5); - constbuf.prepend("const "); - t = constbuf.data(); - e = constbuf.data() + constbuf.length(); - break; - } - /* - We musn't convert 'char * const *' into 'const char **' - and we must beware of 'Bar<const Bla>'. - */ - if (t[i] == '&' || t[i] == '*' ||t[i] == '<') - break; - } - if (adjustConst && e > t + 6 && strncmp("const ", t, 6) == 0) { - if (*(e-1) == '&') { // treat const reference as value - t += 6; - --e; - } else if (is_ident_char(*(e-1)) || *(e-1) == '>') { // treat const value as value - t += 6; - } - } - QByteArray result; - result.reserve(len); - -#if 1 - // consume initial 'const ' - if (strncmp("const ", t, 6) == 0) { - t+= 6; - result += "const "; - } -#endif - - // some type substitutions for 'unsigned x' - if (strncmp("unsigned", t, 8) == 0) { - // make sure "unsigned" is an isolated word before making substitutions - if (!t[8] || !is_ident_char(t[8])) { - if (strncmp(" int", t+8, 4) == 0) { - t += 8+4; - result += "uint"; - } else if (strncmp(" long", t+8, 5) == 0) { - if ((strlen(t + 8 + 5) < 4 || strncmp(t + 8 + 5, " int", 4) != 0) // preserve '[unsigned] long int' - && (strlen(t + 8 + 5) < 5 || strncmp(t + 8 + 5, " long", 5) != 0) // preserve '[unsigned] long long' - ) { - t += 8+5; - result += "ulong"; - } - } else if (strncmp(" short", t+8, 6) != 0 // preserve unsigned short - && strncmp(" char", t+8, 5) != 0) { // preserve unsigned char - // treat rest (unsigned) as uint - t += 8; - result += "uint"; - } - } - } else { - // discard 'struct', 'class', and 'enum'; they are optional - // and we don't want them in the normalized signature - struct { - const char *keyword; - int len; - } optional[] = { - { "struct ", 7 }, - { "class ", 6 }, - { "enum ", 5 }, - { 0, 0 } - }; - int i = 0; - do { - if (strncmp(optional[i].keyword, t, optional[i].len) == 0) { - t += optional[i].len; - break; - } - } while (optional[++i].keyword != 0); - } - - bool star = false; - while (t != e) { - char c = *t++; - if (fixScope && c == ':' && *t == ':' ) { - ++t; - c = *t++; - int i = result.size() - 1; - while (i >= 0 && is_ident_char(result.at(i))) - --i; - result.resize(i + 1); - } - star = star || c == '*'; - result += c; - if (c == '<') { - //template recursion - const char* tt = t; - int templdepth = 1; - while (t != e) { - c = *t++; - if (c == '<') - ++templdepth; - if (c == '>') - --templdepth; - if (templdepth == 0 || (templdepth == 1 && c == ',')) { - result += normalizeTypeInternalQt47(tt, t-1, fixScope, false); - result += c; - if (templdepth == 0) { - if (*t == '>') - result += ' '; // avoid >> - break; - } - tt = t; - } - } - } - - // cv qualifers can appear after the type as well - if (!is_ident_char(c) && t != e && (e - t >= 5 && strncmp("const", t, 5) == 0) - && (e - t == 5 || !is_ident_char(t[5]))) { - t += 5; - while (t != e && is_space(*t)) - ++t; - if (adjustConst && t != e && *t == '&') { - // treat const ref as value - ++t; - } else if (adjustConst && !star) { - // treat const as value - } else if (!star) { - // move const to the front (but not if const comes after a *) - result.prepend("const "); - } else { - // keep const after a * - result += "const"; - } - } - } - - return result; -} - -static char *qNormalizeTypeQt47(char *d, int &templdepth, QByteArray &result) -{ - const char *t = d; - while (*d && (templdepth - || (*d != ',' && *d != ')'))) { - if (*d == '<') - ++templdepth; - if (*d == '>') - --templdepth; - ++d; - } - if (strncmp("void", t, d - t) != 0) - result += normalizeTypeInternalQt47(t, d); - - return d; -} - - -QByteArray QMetaObject_normalizedTypeQt47(const char *type) -{ - QByteArray result; - - if (!type || !*type) - return result; - - QVarLengthArray<char> stackbuf(qstrlen(type) + 1); - qRemoveWhitespace(type, stackbuf.data()); - int templdepth = 0; - qNormalizeTypeQt47(stackbuf.data(), templdepth, result); - - return result; -} - -QByteArray QMetaObject_normalizedSignatureQt47(const char *method) -{ - QByteArray result; - if (!method || !*method) - return result; - int len = int(strlen(method)); - QVarLengthArray<char> stackbuf(len + 1); - char *d = stackbuf.data(); - qRemoveWhitespace(method, d); - - result.reserve(len); - - int argdepth = 0; - int templdepth = 0; - while (*d) { - if (argdepth == 1) - d = qNormalizeTypeQt47(d, templdepth, result); - if (*d == '(') - ++argdepth; - if (*d == ')') - --argdepth; - result += *d++; - } - - return result; -} -#endif diff --git a/generators/shiboken/shibokennormalize_p.h b/generators/shiboken/shibokennormalize_p.h deleted file mode 100644 index 0a55b5075..000000000 --- a/generators/shiboken/shibokennormalize_p.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is part of the PySide project. - * - * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: PySide team <contact@pyside.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef SHIBOKENNORMALIZE_P_H -#define SHIBOKENNORMALIZE_P_H - -#include <QMetaObject> -#include <QByteArray> - - -#if (QT_VERSION < QT_VERSION_CHECK(4, 7, 0)) - QByteArray QMetaObject_normalizedTypeQt47(const char *type); - QByteArray QMetaObject_normalizedSignatureQt47(const char *type); - - #define SBK_NORMALIZED_TYPE(x) QMetaObject_normalizedTypeQt47(x) - #define SBK_NORMALIZED_SIGNATURE(x) QMetaObject_normalizedSignatureQt47(x) -#else - #define SBK_NORMALIZED_TYPE(x) QMetaObject::normalizedType(x) - #define SBK_NORMALIZED_SIGNATURE(x) QMetaObject::normalizedSignature(x) -#endif - -#endif //SHIBOKENNORMALIZE_P_H diff --git a/generators/shibokenconfig.h.in b/generators/shibokenconfig.h.in deleted file mode 100644 index 7d844a940..000000000 --- a/generators/shibokenconfig.h.in +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef SHIBOKENCONFIG_H -#define SHIBOKENCONFIG_H - -#define GENERATOR_BINARY "@GENERATORRUNNER_BINARY@" -#define SHIBOKEN_VERSION "@shiboken_VERSION@" - -#endif |