aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/generator
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2/generator')
-rw-r--r--sources/shiboken2/generator/CMakeLists.txt63
-rw-r--r--sources/shiboken2/generator/__init__.py.in2
-rw-r--r--sources/shiboken2/generator/_config.py.in9
-rw-r--r--sources/shiboken2/generator/generator.cpp964
-rw-r--r--sources/shiboken2/generator/generator.h421
-rw-r--r--sources/shiboken2/generator/indentor.h85
-rw-r--r--sources/shiboken2/generator/main.cpp642
-rw-r--r--sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp2408
-rw-r--r--sources/shiboken2/generator/qtdoc/qtdocgenerator.h284
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp6024
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.h384
-rw-r--r--sources/shiboken2/generator/shiboken2/headergenerator.cpp639
-rw-r--r--sources/shiboken2/generator/shiboken2/headergenerator.h70
-rw-r--r--sources/shiboken2/generator/shiboken2/overloaddata.cpp1091
-rw-r--r--sources/shiboken2/generator/shiboken2/overloaddata.h163
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.cpp2756
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.h546
-rw-r--r--sources/shiboken2/generator/shibokenconfig.h.in6
18 files changed, 0 insertions, 16557 deletions
diff --git a/sources/shiboken2/generator/CMakeLists.txt b/sources/shiboken2/generator/CMakeLists.txt
deleted file mode 100644
index 15b965d9d..000000000
--- a/sources/shiboken2/generator/CMakeLists.txt
+++ /dev/null
@@ -1,63 +0,0 @@
-project(shibokengenerator)
-
-set(shiboken2_SRC
-generator.cpp
-shiboken2/cppgenerator.cpp
-shiboken2/headergenerator.cpp
-shiboken2/overloaddata.cpp
-shiboken2/shibokengenerator.cpp
-main.cpp
-)
-
-add_executable(shiboken2 ${shiboken2_SRC})
-add_executable(Shiboken2::shiboken2 ALIAS shiboken2)
-add_dependencies(shiboken2 apiextractor)
-set_target_properties(shiboken2 PROPERTIES OUTPUT_NAME shiboken2${shiboken2_SUFFIX})
-target_include_directories(shiboken2 PRIVATE
- ${CMAKE_CURRENT_SOURCE_DIR}/shiboken2
- ${CMAKE_CURRENT_SOURCE_DIR}/qtdoc
- ${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_CURRENT_BINARY_DIR}
- ${apiextractor_SOURCE_DIR}
- )
-target_link_libraries(shiboken2 apiextractor Qt5::Core)
-if (NOT DISABLE_DOCSTRINGS)
- target_sources(shiboken2 PRIVATE qtdoc/qtdocgenerator.cpp)
- target_compile_definitions(shiboken2 PUBLIC DOCSTRINGS_ENABLED)
-endif()
-
-configure_file(shibokenconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/shibokenconfig.h" @ONLY)
-
-install(TARGETS shiboken2
- EXPORT Shiboken2Targets
- DESTINATION bin)
-
-set(shiboken_generator_package_name "shiboken2_generator")
-
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/_config.py.in"
- "${CMAKE_CURRENT_BINARY_DIR}/_config.py" @ONLY)
-install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_config.py"
- DESTINATION "${PYTHON_SITE_PACKAGES}/${shiboken_generator_package_name}")
-
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in"
- "${CMAKE_CURRENT_BINARY_DIR}/__init__.py" @ONLY)
-install(FILES "${CMAKE_CURRENT_BINARY_DIR}/__init__.py"
- DESTINATION "${PYTHON_SITE_PACKAGES}/${shiboken_generator_package_name}")
-
-# shiboken2 setuptools entry point
-install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../shiboken_tool.py
- DESTINATION bin
- PERMISSIONS
- OWNER_EXECUTE OWNER_WRITE OWNER_READ
- GROUP_EXECUTE GROUP_READ
- WORLD_EXECUTE WORLD_READ)
-
-# Use absolute path instead of relative path, to avoid ninja build errors due to
-# duplicate file dependency inconsistency.
-set(shiboken_version_relative_path "${CMAKE_CURRENT_SOURCE_DIR}/../shiboken_version.py")
-get_filename_component(shiboken_version_path ${shiboken_version_relative_path} ABSOLUTE)
-configure_file("${shiboken_version_path}"
- "${CMAKE_CURRENT_BINARY_DIR}/_git_shiboken_generator_version.py" @ONLY)
-
-install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_git_shiboken_generator_version.py"
- DESTINATION "${PYTHON_SITE_PACKAGES}/${shiboken_generator_package_name}")
diff --git a/sources/shiboken2/generator/__init__.py.in b/sources/shiboken2/generator/__init__.py.in
deleted file mode 100644
index 4be6a833b..000000000
--- a/sources/shiboken2/generator/__init__.py.in
+++ /dev/null
@@ -1,2 +0,0 @@
-__version__ = "@FINAL_PACKAGE_VERSION@"
-__version_info__ = (@shiboken_MAJOR_VERSION@, @shiboken_MINOR_VERSION@, @shiboken_MICRO_VERSION@, "@shiboken_PRE_RELEASE_VERSION_TYPE@", "@shiboken_PRE_RELEASE_VERSION@")
diff --git a/sources/shiboken2/generator/_config.py.in b/sources/shiboken2/generator/_config.py.in
deleted file mode 100644
index 985735fa4..000000000
--- a/sources/shiboken2/generator/_config.py.in
+++ /dev/null
@@ -1,9 +0,0 @@
-version = "@FINAL_PACKAGE_VERSION@"
-version_info = (@shiboken_MAJOR_VERSION@, @shiboken_MINOR_VERSION@, @shiboken_MICRO_VERSION@, "@shiboken_PRE_RELEASE_VERSION_TYPE@", "@shiboken_PRE_RELEASE_VERSION@")
-
-@PACKAGE_BUILD_DATE@
-@PACKAGE_BUILD_COMMIT_DATE@
-@PACKAGE_BUILD_COMMIT_HASH@
-@PACKAGE_BUILD_COMMIT_HASH_DESCRIBED@
-@PACKAGE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT@
-@PACKAGE_SETUP_PY_PACKAGE_VERSION_ASSIGNMENT@
diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp
deleted file mode 100644
index 585102b01..000000000
--- a/sources/shiboken2/generator/generator.cpp
+++ /dev/null
@@ -1,964 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "generator.h"
-#include "abstractmetalang.h"
-#include "parser/codemodel.h"
-#include "messages.h"
-#include "reporthandler.h"
-#include "fileout.h"
-#include "apiextractor.h"
-#include "typesystem.h"
-
-#include <QtCore/QDir>
-#include <QtCore/QFile>
-#include <QtCore/QFileInfo>
-#include <QtCore/QRegularExpression>
-#include <QDebug>
-#include <typedatabase.h>
-
-/**
- * DefaultValue is used for storing default values of types for which code is
- * generated in different contexts:
- *
- * Context | Example: "Class *" | Example: "Class" with default Constructor
- * --------------------+-------------------------------+------------------------------------------
- * Variable | var{nullptr}; | var;
- * initializations | |
- * --------------------+-------------------------------+------------------------------------------
- * Return values | return nullptr; | return {}
- * --------------------+-------------------------------+------------------------------------------
- * constructor | static_cast<Class *>(nullptr) | Class()
- * arguments lists | |
- * (recursive, precise | |
- * matching). | |
- */
-
-DefaultValue::DefaultValue(Type t, QString value) :
- m_type(t), m_value(std::move(value))
-{
-}
-
-DefaultValue::DefaultValue(QString customValue) :
- m_type(Custom), m_value(std::move(customValue))
-{
-}
-
-QString DefaultValue::returnValue() const
-{
- switch (m_type) {
- case DefaultValue::Error:
- return QLatin1String("#error");
- case DefaultValue::Boolean:
- return QLatin1String("false");
- case DefaultValue::CppScalar:
- return QLatin1String("0");
- case DefaultValue::Custom:
- case DefaultValue::Enum:
- return m_value;
- case DefaultValue::Pointer:
- return QLatin1String("nullptr");
- case DefaultValue::Void:
- return QString();
- case DefaultValue::DefaultConstructorWithDefaultValues:
- return m_value + QLatin1String("()");
- case DefaultValue::DefaultConstructor:
- break;
- }
- return QLatin1String("{}");
-}
-
-QString DefaultValue::initialization() const
-{
- switch (m_type) {
- case DefaultValue::Error:
- return QLatin1String("#error");
- case DefaultValue::Boolean:
- return QLatin1String("{false}");
- case DefaultValue::CppScalar:
- return QLatin1String("{0}");
- case DefaultValue::Custom:
- return QLatin1String(" = ") + m_value;
- case DefaultValue::Enum:
- return QLatin1Char('{') + m_value + QLatin1Char('}');
- case DefaultValue::Pointer:
- return QLatin1String("{nullptr}");
- case DefaultValue::Void:
- Q_ASSERT(false);
- break;
- case DefaultValue::DefaultConstructor:
- case DefaultValue::DefaultConstructorWithDefaultValues:
- break;
- }
- return QString();
-}
-
-QString DefaultValue::constructorParameter() const
-{
- switch (m_type) {
- case DefaultValue::Error:
- return QLatin1String("#error");
- case DefaultValue::Boolean:
- return QLatin1String("false");
- case DefaultValue::CppScalar: {
- // PYSIDE-846: Use static_cast in case of "unsigned long" and similar
- const QString cast = m_value.contains(QLatin1Char(' '))
- ? QLatin1String("static_cast<") + m_value + QLatin1Char('>')
- : m_value;
- return cast + QLatin1String("(0)");
- }
- case DefaultValue::Custom:
- case DefaultValue::Enum:
- return m_value;
- case DefaultValue::Pointer:
- // Be precise here to be able to differentiate between constructors
- // taking different pointer types, cf
- // QTreeWidgetItemIterator(QTreeWidget *) and
- // QTreeWidgetItemIterator(QTreeWidgetItemIterator *).
- return QLatin1String("static_cast<") + m_value + QLatin1String("*>(nullptr)");
- case DefaultValue::Void:
- Q_ASSERT(false);
- break;
- case DefaultValue::DefaultConstructor:
- case DefaultValue::DefaultConstructorWithDefaultValues:
- break;
- }
- return m_value + QLatin1String("()");
-}
-
-struct Generator::GeneratorPrivate
-{
- const ApiExtractor *apiextractor = nullptr;
- QString outDir;
- // License comment
- QString licenseComment;
- QString moduleName;
- QStringList instantiatedContainersNames;
- QVector<const AbstractMetaType *> instantiatedContainers;
- QVector<const AbstractMetaType *> instantiatedSmartPointers;
-
-};
-
-Generator::Generator() : m_d(new GeneratorPrivate)
-{
-}
-
-Generator::~Generator()
-{
- delete m_d;
-}
-
-bool Generator::setup(const ApiExtractor &extractor)
-{
- m_d->apiextractor = &extractor;
- const auto moduleEntry = TypeDatabase::instance()->defaultTypeSystemType();
- if (!moduleEntry || !moduleEntry->generateCode()) {
- qCWarning(lcShiboken) << "Couldn't find the package name!!";
- return false;
- }
-
- collectInstantiatedContainersAndSmartPointers();
-
- return doSetup();
-}
-
-QString Generator::getSimplifiedContainerTypeName(const AbstractMetaType *type)
-{
- const QString signature = type->cppSignature();
- if (!type->typeEntry()->isContainer() && !type->typeEntry()->isSmartPointer())
- return signature;
- QString typeName = signature;
- if (type->isConstant())
- typeName.remove(0, sizeof("const ") / sizeof(char) - 1);
- switch (type->referenceType()) {
- case NoReference:
- break;
- case LValueReference:
- typeName.chop(1);
- break;
- case RValueReference:
- typeName.chop(2);
- break;
- }
- while (typeName.endsWith(QLatin1Char('*')) || typeName.endsWith(QLatin1Char(' ')))
- typeName.chop(1);
- return typeName;
-}
-
-// Strip a "const QSharedPtr<const Foo> &" or similar to "QSharedPtr<Foo>" (PYSIDE-1016/454)
-const AbstractMetaType *canonicalSmartPtrInstantiation(const AbstractMetaType *type)
-{
- AbstractMetaTypeList instantiations = type->instantiations();
- Q_ASSERT(instantiations.size() == 1);
- const bool needsFix = type->isConstant() || type->referenceType() != NoReference;
- const bool pointeeNeedsFix = instantiations.constFirst()->isConstant();
- if (!needsFix && !pointeeNeedsFix)
- return type;
- auto fixedType = type->copy();
- fixedType->setReferenceType(NoReference);
- fixedType->setConstant(false);
- if (pointeeNeedsFix) {
- auto fixedPointeeType = instantiations.constFirst()->copy();
- fixedPointeeType->setConstant(false);
- fixedType->setInstantiations(AbstractMetaTypeList(1, fixedPointeeType));
- }
- return fixedType;
-}
-
-static inline const TypeEntry *pointeeTypeEntry(const AbstractMetaType *smartPtrType)
-{
- return smartPtrType->instantiations().constFirst()->typeEntry();
-}
-
-void Generator::addInstantiatedContainersAndSmartPointers(const AbstractMetaType *type,
- const QString &context)
-{
- if (!type)
- return;
- const AbstractMetaTypeList &instantiations = type->instantiations();
- for (const AbstractMetaType *t : instantiations)
- addInstantiatedContainersAndSmartPointers(t, context);
- const auto typeEntry = type->typeEntry();
- const bool isContainer = typeEntry->isContainer();
- if (!isContainer
- && !(typeEntry->isSmartPointer() && typeEntry->generateCode())) {
- return;
- }
- if (type->hasTemplateChildren()) {
- QString piece = isContainer ? QStringLiteral("container") : QStringLiteral("smart pointer");
- QString warning =
- QString::fromLatin1("Skipping instantiation of %1 '%2' because it has template"
- " arguments.").arg(piece, type->originalTypeDescription());
- if (!context.isEmpty())
- warning.append(QStringLiteral(" Calling context: %1").arg(context));
-
- qCWarning(lcShiboken).noquote().nospace() << warning;
- return;
-
- }
- QString typeName = getSimplifiedContainerTypeName(type);
- if (isContainer) {
- if (!m_d->instantiatedContainersNames.contains(typeName)) {
- m_d->instantiatedContainersNames.append(typeName);
- m_d->instantiatedContainers.append(type);
- }
- } else {
- // Is smart pointer. Check if the (const?) pointee is already known
- auto pt = pointeeTypeEntry(type);
- const bool present =
- std::any_of(m_d->instantiatedSmartPointers.cbegin(), m_d->instantiatedSmartPointers.cend(),
- [pt] (const AbstractMetaType *t) {
- return pointeeTypeEntry(t) == pt;
- });
- if (!present)
- m_d->instantiatedSmartPointers.append(canonicalSmartPtrInstantiation(type));
- }
-
-}
-
-void Generator::collectInstantiatedContainersAndSmartPointers(const AbstractMetaFunction *func)
-{
- addInstantiatedContainersAndSmartPointers(func->type(), func->signature());
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (const AbstractMetaArgument *arg : arguments)
- addInstantiatedContainersAndSmartPointers(arg->type(), func->signature());
-}
-
-void Generator::collectInstantiatedContainersAndSmartPointers(const AbstractMetaClass *metaClass)
-{
- if (!metaClass->typeEntry()->generateCode())
- return;
- const AbstractMetaFunctionList &funcs = metaClass->functions();
- for (const AbstractMetaFunction *func : funcs)
- collectInstantiatedContainersAndSmartPointers(func);
- const AbstractMetaFieldList &fields = metaClass->fields();
- for (const AbstractMetaField *field : fields)
- addInstantiatedContainersAndSmartPointers(field->type(), field->name());
- const AbstractMetaClassList &innerClasses = metaClass->innerClasses();
- for (AbstractMetaClass *innerClass : innerClasses)
- collectInstantiatedContainersAndSmartPointers(innerClass);
-}
-
-void Generator::collectInstantiatedContainersAndSmartPointers()
-{
- const AbstractMetaFunctionList &funcs = globalFunctions();
- for (const AbstractMetaFunction *func : funcs)
- collectInstantiatedContainersAndSmartPointers(func);
- const AbstractMetaClassList &classList = classes();
- for (const AbstractMetaClass *metaClass : classList)
- collectInstantiatedContainersAndSmartPointers(metaClass);
-}
-
-QVector<const AbstractMetaType *> Generator::instantiatedContainers() const
-{
- return m_d->instantiatedContainers;
-}
-
-QVector<const AbstractMetaType *> Generator::instantiatedSmartPointers() const
-{
- return m_d->instantiatedSmartPointers;
-}
-
-Generator::OptionDescriptions Generator::options() const
-{
- return OptionDescriptions();
-}
-
-bool Generator::handleOption(const QString & /* key */, const QString & /* value */)
-{
- return false;
-}
-
-AbstractMetaClassList Generator::classes() const
-{
- return m_d->apiextractor->classes();
-}
-
-AbstractMetaClassList Generator::classesTopologicalSorted(const Dependencies &additionalDependencies) const
-{
- return m_d->apiextractor->classesTopologicalSorted(additionalDependencies);
-}
-
-AbstractMetaFunctionList Generator::globalFunctions() const
-{
- return m_d->apiextractor->globalFunctions();
-}
-
-AbstractMetaEnumList Generator::globalEnums() const
-{
- return m_d->apiextractor->globalEnums();
-}
-
-PrimitiveTypeEntryList Generator::primitiveTypes() const
-{
- return m_d->apiextractor->primitiveTypes();
-}
-
-ContainerTypeEntryList Generator::containerTypes() const
-{
- return m_d->apiextractor->containerTypes();
-}
-
-const AbstractMetaEnum *Generator::findAbstractMetaEnum(const TypeEntry *typeEntry) const
-{
- return m_d->apiextractor->findAbstractMetaEnum(typeEntry);
-}
-
-const AbstractMetaEnum *Generator::findAbstractMetaEnum(const AbstractMetaType *metaType) const
-{
- return m_d->apiextractor->findAbstractMetaEnum(metaType->typeEntry());
-}
-
-QString Generator::licenseComment() const
-{
- return m_d->licenseComment;
-}
-
-void Generator::setLicenseComment(const QString &licenseComment)
-{
- m_d->licenseComment = licenseComment;
-}
-
-QString Generator::packageName() const
-{
- return TypeDatabase::instance()->defaultPackageName();
-}
-
-QString Generator::moduleName() const
-{
- if (m_d->moduleName.isEmpty()) {
- m_d->moduleName = packageName();
- m_d->moduleName.remove(0, m_d->moduleName.lastIndexOf(QLatin1Char('.')) + 1);
- }
- return m_d->moduleName;
-}
-
-QString Generator::outputDirectory() const
-{
- return m_d->outDir;
-}
-
-void Generator::setOutputDirectory(const QString &outDir)
-{
- m_d->outDir = outDir;
-}
-
-bool Generator::generateFileForContext(GeneratorContext &context)
-{
- AbstractMetaClass *cls = context.metaClass();
-
- if (!shouldGenerate(cls))
- return true;
-
- const QString fileName = fileNameForContext(context);
- if (fileName.isEmpty())
- return true;
- if (ReportHandler::isDebug(ReportHandler::SparseDebug))
- qCDebug(lcShiboken) << "generating: " << fileName;
-
- QString filePath = outputDirectory() + QLatin1Char('/') + subDirectoryForClass(cls)
- + QLatin1Char('/') + fileName;
- FileOut fileOut(filePath);
-
- generateClass(fileOut.stream, context);
-
- return fileOut.done() != FileOut::Failure;
-}
-
-QString Generator::getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType,
- const AbstractMetaClass *smartPointerClass) const
-{
- const AbstractMetaType *innerType = smartPointerType->getSmartPointerInnerType();
- QString fileName = smartPointerClass->qualifiedCppName().toLower();
- fileName.replace(QLatin1String("::"), QLatin1String("_"));
- fileName.append(QLatin1String("_"));
- fileName.append(innerType->name().toLower());
-
- return fileName;
-}
-
-bool Generator::generate()
-{
- const AbstractMetaClassList &classList = m_d->apiextractor->classes();
- for (AbstractMetaClass *cls : classList) {
- GeneratorContext context(cls);
- if (!generateFileForContext(context))
- return false;
- }
-
- const auto smartPointers = m_d->apiextractor->smartPointers();
- for (const AbstractMetaType *type : qAsConst(m_d->instantiatedSmartPointers)) {
- AbstractMetaClass *smartPointerClass =
- AbstractMetaClass::findClass(smartPointers, type->typeEntry());
- if (!smartPointerClass) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgCannotFindSmartPointer(type->cppSignature(),
- smartPointers)));
- return false;
- }
- GeneratorContext context(smartPointerClass, type, true);
- if (!generateFileForContext(context))
- return false;
- }
- return finishGeneration();
-}
-
-bool Generator::shouldGenerateTypeEntry(const TypeEntry *type) const
-{
- return (type->codeGeneration() & TypeEntry::GenerateTargetLang)
- && NamespaceTypeEntry::isVisibleScope(type);
-}
-
-bool Generator::shouldGenerate(const AbstractMetaClass *metaClass) const
-{
- return shouldGenerateTypeEntry(metaClass->typeEntry());
-}
-
-void verifyDirectoryFor(const QString &file)
-{
- QDir dir = QFileInfo(file).absoluteDir();
- if (!dir.exists()) {
- if (!dir.mkpath(dir.absolutePath())) {
- qCWarning(lcShiboken).noquote().nospace()
- << QStringLiteral("unable to create directory '%1'").arg(dir.absolutePath());
- }
- }
-}
-
-void Generator::replaceTemplateVariables(QString &code, const AbstractMetaFunction *func)
-{
- const AbstractMetaClass *cpp_class = func->ownerClass();
- if (cpp_class)
- code.replace(QLatin1String("%TYPE"), cpp_class->name());
-
- const AbstractMetaArgumentList &argument = func->arguments();
- for (AbstractMetaArgument *arg : argument)
- code.replace(QLatin1Char('%') + QString::number(arg->argumentIndex() + 1), arg->name());
-
- //template values
- code.replace(QLatin1String("%RETURN_TYPE"), translateType(func->type(), cpp_class));
- code.replace(QLatin1String("%FUNCTION_NAME"), func->originalName());
-
- if (code.contains(QLatin1String("%ARGUMENT_NAMES"))) {
- QString str;
- QTextStream aux_stream(&str);
- writeArgumentNames(aux_stream, func, Generator::SkipRemovedArguments);
- code.replace(QLatin1String("%ARGUMENT_NAMES"), str);
- }
-
- if (code.contains(QLatin1String("%ARGUMENTS"))) {
- QString str;
- QTextStream aux_stream(&str);
- writeFunctionArguments(aux_stream, func, Options(SkipDefaultValues) | SkipRemovedArguments);
- code.replace(QLatin1String("%ARGUMENTS"), str);
- }
-}
-
-QTextStream &formatCode(QTextStream &s, const QString &code, Indentor &indentor)
-{
- // detect number of spaces before the first character
- const QStringList lst(code.split(QLatin1Char('\n')));
- static const QRegularExpression nonSpaceRegex(QStringLiteral("[^\\s]"));
- Q_ASSERT(nonSpaceRegex.isValid());
- int spacesToRemove = 0;
- for (const QString &line : lst) {
- if (!line.trimmed().isEmpty()) {
- spacesToRemove = line.indexOf(nonSpaceRegex);
- if (spacesToRemove == -1)
- spacesToRemove = 0;
- break;
- }
- }
-
- static const QRegularExpression emptyLine(QStringLiteral("^\\s*[\\r]?[\\n]?\\s*$"));
- Q_ASSERT(emptyLine.isValid());
-
- for (QString line : lst) {
- if (!line.isEmpty() && !emptyLine.match(line).hasMatch()) {
- while (line.constEnd()->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 << Qt::endl;
- }
- return s;
-}
-
-AbstractMetaFunctionList Generator::implicitConversions(const TypeEntry *type) const
-{
- if (type->isValue()) {
- if (const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes(), type))
- return metaClass->implicitConversions();
- }
- return AbstractMetaFunctionList();
-}
-
-AbstractMetaFunctionList Generator::implicitConversions(const AbstractMetaType *metaType) const
-{
- return implicitConversions(metaType->typeEntry());
-}
-
-bool Generator::isObjectType(const TypeEntry *type)
-{
- if (type->isComplex())
- return Generator::isObjectType(static_cast<const ComplexTypeEntry *>(type));
- return type->isObject();
-}
-bool Generator::isObjectType(const ComplexTypeEntry *type)
-{
- return type->isObject();
-}
-bool Generator::isObjectType(const AbstractMetaClass *metaClass)
-{
- return Generator::isObjectType(metaClass->typeEntry());
-}
-bool Generator::isObjectType(const AbstractMetaType *metaType)
-{
- return isObjectType(metaType->typeEntry());
-}
-
-bool Generator::isPointer(const AbstractMetaType *type)
-{
- return type->indirections() > 0
- || type->isNativePointer()
- || type->isValuePointer();
-}
-
-bool Generator::isCString(const AbstractMetaType *type)
-{
- return type->isNativePointer()
- && type->indirections() == 1
- && type->name() == QLatin1String("char");
-}
-
-bool Generator::isVoidPointer(const AbstractMetaType *type)
-{
- return type->isNativePointer()
- && type->indirections() == 1
- && type->name() == QLatin1String("void");
-}
-
-QString Generator::getFullTypeName(const TypeEntry *type) const
-{
- QString result = type->qualifiedCppName();
- if (type->isArray())
- type = static_cast<const ArrayTypeEntry *>(type)->nestedTypeEntry();
- if (!type->isCppPrimitive())
- result.prepend(QLatin1String("::"));
- return result;
-}
-
-QString Generator::getFullTypeName(const AbstractMetaType *type) const
-{
- if (isCString(type))
- return QLatin1String("const char*");
- if (isVoidPointer(type))
- return QLatin1String("void*");
- if (type->typeEntry()->isContainer())
- return QLatin1String("::") + type->cppSignature();
- QString typeName;
- if (type->typeEntry()->isComplex() && type->hasInstantiations())
- typeName = getFullTypeNameWithoutModifiers(type);
- else
- typeName = getFullTypeName(type->typeEntry());
- return typeName + QString::fromLatin1("*").repeated(type->indirections());
-}
-
-QString Generator::getFullTypeName(const AbstractMetaClass *metaClass) const
-{
- return QLatin1String("::") + metaClass->qualifiedCppName();
-}
-
-QString Generator::getFullTypeNameWithoutModifiers(const AbstractMetaType *type) const
-{
- if (isCString(type))
- return QLatin1String("const char*");
- if (isVoidPointer(type))
- return QLatin1String("void*");
- if (!type->hasInstantiations())
- return getFullTypeName(type->typeEntry());
- QString typeName = type->cppSignature();
- if (type->isConstant())
- typeName.remove(0, sizeof("const ") / sizeof(char) - 1);
- switch (type->referenceType()) {
- case NoReference:
- break;
- case LValueReference:
- typeName.chop(1);
- break;
- case RValueReference:
- typeName.chop(2);
- break;
- }
- while (typeName.endsWith(QLatin1Char('*')) || typeName.endsWith(QLatin1Char(' ')))
- typeName.chop(1);
- return QLatin1String("::") + typeName;
-}
-
-DefaultValue Generator::minimalConstructor(const AbstractMetaType *type) const
-{
- if (!type || (type->referenceType() == LValueReference && Generator::isObjectType(type)))
- return DefaultValue(DefaultValue::Error);
-
- if (type->isContainer()) {
- QString ctor = type->cppSignature();
- if (ctor.endsWith(QLatin1Char('*'))) {
- ctor.chop(1);
- return DefaultValue(DefaultValue::Pointer, ctor.trimmed());
- }
- if (ctor.startsWith(QLatin1String("const ")))
- ctor.remove(0, sizeof("const ") / sizeof(char) - 1);
- if (ctor.endsWith(QLatin1Char('&'))) {
- ctor.chop(1);
- ctor = ctor.trimmed();
- }
- return DefaultValue(DefaultValue::DefaultConstructor, QLatin1String("::") + ctor);
- }
-
- if (type->isNativePointer())
- return DefaultValue(DefaultValue::Pointer, type->typeEntry()->qualifiedCppName());
- if (Generator::isPointer(type))
- return DefaultValue(DefaultValue::Pointer, QLatin1String("::") + type->typeEntry()->qualifiedCppName());
-
- if (type->typeEntry()->isComplex()) {
- auto cType = static_cast<const ComplexTypeEntry *>(type->typeEntry());
- if (cType->hasDefaultConstructor())
- return DefaultValue(DefaultValue::Custom, cType->defaultConstructor());
- auto ctor = minimalConstructor(AbstractMetaClass::findClass(classes(), cType));
- if (ctor.isValid() && type->hasInstantiations()) {
- QString v = ctor.value();
- v.replace(getFullTypeName(cType), getFullTypeNameWithoutModifiers(type));
- ctor.setValue(v);
- }
- return ctor;
- }
-
- return minimalConstructor(type->typeEntry());
-}
-
-DefaultValue Generator::minimalConstructor(const TypeEntry *type) const
-{
- if (!type)
- return DefaultValue(DefaultValue::Error);
-
- if (type->isCppPrimitive()) {
- const QString &name = type->qualifiedCppName();
- return name == QLatin1String("bool")
- ? DefaultValue(DefaultValue::Boolean)
- : DefaultValue(DefaultValue::CppScalar, name);
- }
-
- if (type->isEnum()) {
- const auto enumEntry = static_cast<const EnumTypeEntry *>(type);
- if (const auto *nullValue = enumEntry->nullValue())
- return DefaultValue(DefaultValue::Enum, nullValue->name());
- return DefaultValue(DefaultValue::Custom,
- QLatin1String("static_cast< ::") + type->qualifiedCppName()
- + QLatin1String(">(0)"));
- }
-
- if (type->isFlags()) {
- return DefaultValue(DefaultValue::Custom,
- type->qualifiedCppName() + QLatin1String("(0)"));
- }
-
- if (type->isPrimitive()) {
- QString ctor = static_cast<const PrimitiveTypeEntry *>(type)->defaultConstructor();
- // If a non-C++ (i.e. defined by the user) primitive type does not have
- // a default constructor defined by the user, the empty constructor is
- // heuristically returned. If this is wrong the build of the generated
- // bindings will tell.
- return ctor.isEmpty()
- ? DefaultValue(DefaultValue::DefaultConstructorWithDefaultValues, QLatin1String("::")
- + type->qualifiedCppName())
- : DefaultValue(DefaultValue::Custom, ctor);
- }
-
- if (type->isComplex())
- return minimalConstructor(AbstractMetaClass::findClass(classes(), type));
-
- return DefaultValue(DefaultValue::Error);
-}
-
-static QString constructorCall(const QString &qualifiedCppName, const QStringList &args)
-{
- return QLatin1String("::") + qualifiedCppName + QLatin1Char('(')
- + args.join(QLatin1String(", ")) + QLatin1Char(')');
-}
-
-DefaultValue Generator::minimalConstructor(const AbstractMetaClass *metaClass) const
-{
- if (!metaClass)
- return DefaultValue(DefaultValue::Error);
-
- auto cType = static_cast<const ComplexTypeEntry *>(metaClass->typeEntry());
- if (cType->hasDefaultConstructor())
- return DefaultValue(DefaultValue::Custom, cType->defaultConstructor());
-
- const QString qualifiedCppName = cType->qualifiedCppName();
- // Obtain a list of constructors sorted by complexity and number of arguments
- QMultiMap<int, const AbstractMetaFunction *> candidates;
- const AbstractMetaFunctionList &constructors = metaClass->queryFunctions(AbstractMetaClass::Constructors);
- for (const AbstractMetaFunction *ctor : constructors) {
- if (!ctor->isUserAdded() && !ctor->isPrivate()
- && ctor->functionType() == AbstractMetaFunction::ConstructorFunction) {
- // No arguments: Default constructible
- const auto &arguments = ctor->arguments();
- if (arguments.isEmpty()) {
- return DefaultValue(DefaultValue::DefaultConstructor,
- QLatin1String("::") + qualifiedCppName);
- }
- // First argument has unmodified default: Default constructible with values
- if (arguments.constFirst()->hasUnmodifiedDefaultValueExpression()) {
- return DefaultValue(DefaultValue::DefaultConstructorWithDefaultValues,
- QLatin1String("::") + qualifiedCppName);
- }
- // Examine arguments, exclude functions taking a self parameter
- bool simple = true;
- bool suitable = true;
- for (int i = 0, size = arguments.size();
- suitable && i < size && !arguments.at(i)->hasOriginalDefaultValueExpression(); ++i) {
- const AbstractMetaArgument *arg = arguments.at(i);
- const TypeEntry *aType = arg->type()->typeEntry();
- suitable &= aType != cType;
- simple &= aType->isCppPrimitive() || aType->isEnum() || isPointer(arg->type());
- }
- if (suitable)
- candidates.insert(arguments.size() + (simple ? 0 : 100), ctor);
- }
- }
-
- for (auto it = candidates.cbegin(), end = candidates.cend(); it != end; ++it) {
- const AbstractMetaArgumentList &arguments = it.value()->arguments();
- QStringList args;
- bool ok = true;
- for (int i =0, size = arguments.size(); ok && i < size; ++i) {
- const AbstractMetaArgument *arg = arguments.at(i);
- if (arg->hasModifiedDefaultValueExpression()) {
- args << arg->defaultValueExpression(); // Spell out modified values
- break;
- }
- if (arg->hasOriginalDefaultValueExpression())
- break;
- auto argValue = minimalConstructor(arg->type());
- ok &= argValue.isValid();
- args << argValue.constructorParameter();
- }
- if (ok)
- return DefaultValue(DefaultValue::Custom, constructorCall(qualifiedCppName, args));
- }
-
- return DefaultValue(DefaultValue::Error);
-}
-
-// Should int be used for a (protected) enum when generating the public wrapper?
-bool Generator::useEnumAsIntForProtectedHack(const AbstractMetaType *metaType) const
-{
- if (metaType->isFlags())
- return true;
- if (!metaType->isEnum())
- return false;
- const AbstractMetaEnum *metaEnum = findAbstractMetaEnum(metaType);
- if (!metaEnum)
- return true;
- if (metaEnum->attributes() & AbstractMetaAttributes::Public) // No reason, type is public
- return false;
- // Only ordinary C-enums can be used as int, scoped enums fail when used
- // as function arguments.
- if (metaEnum->enumKind() == EnumKind::EnumClass)
- qWarning(lcShiboken, "%s", qPrintable(msgCannotUseEnumAsInt(metaEnum->name())));
- return true;
-}
-
-QString Generator::translateType(const AbstractMetaType *cType,
- const AbstractMetaClass *context,
- Options options) const
-{
- QString s;
- static int constLen = strlen("const");
-
- if (context && cType &&
- context->typeEntry()->isGenericClass() &&
- cType->originalTemplateType()) {
- cType = cType->originalTemplateType();
- }
-
- if (!cType) {
- s = QLatin1String("void");
- } else if (cType->isArray()) {
- s = translateType(cType->arrayElementType(), context, options) + QLatin1String("[]");
- } else if ((options & Generator::EnumAsInts) && useEnumAsIntForProtectedHack(cType)) {
- s = QLatin1String("int");
- } else {
- if (options & Generator::OriginalName) {
- s = cType->originalTypeDescription().trimmed();
- if ((options & Generator::ExcludeReference) && s.endsWith(QLatin1Char('&')))
- s.chop(1);
-
- // remove only the last const (avoid remove template const)
- if (options & Generator::ExcludeConst) {
- int index = s.lastIndexOf(QLatin1String("const"));
-
- if (index >= (s.size() - (constLen + 1))) // (VarType const) or (VarType const[*|&])
- s = s.remove(index, constLen);
- }
- } else if (options & Generator::ExcludeConst || options & Generator::ExcludeReference) {
- AbstractMetaType *copyType = cType->copy();
-
- if (options & Generator::ExcludeConst)
- copyType->setConstant(false);
-
- if (options & Generator::ExcludeReference)
- copyType->setReferenceType(NoReference);
-
- s = copyType->cppSignature();
- if (!copyType->typeEntry()->isVoid() && !copyType->typeEntry()->isCppPrimitive())
- s.prepend(QLatin1String("::"));
- delete copyType;
- } else {
- s = cType->cppSignature();
- }
- }
-
- return s;
-}
-
-
-QString Generator::subDirectoryForClass(const AbstractMetaClass *clazz) const
-{
- return subDirectoryForPackage(clazz->package());
-}
-
-QString Generator::subDirectoryForPackage(QString packageNameIn) const
-{
- if (packageNameIn.isEmpty())
- packageNameIn = packageName();
- packageNameIn.replace(QLatin1Char('.'), QDir::separator());
- return packageNameIn;
-}
-
-template<typename T>
-static QString getClassTargetFullName_(const T *t, bool includePackageName)
-{
- QString name = t->name();
- const AbstractMetaClass *context = t->enclosingClass();
- while (context) {
- // If the type was marked as 'visible=false' we should not use it in
- // the type name
- if (NamespaceTypeEntry::isVisibleScope(context->typeEntry())) {
- name.prepend(QLatin1Char('.'));
- name.prepend(context->name());
- }
- context = context->enclosingClass();
- }
- if (includePackageName) {
- name.prepend(QLatin1Char('.'));
- name.prepend(t->package());
- }
- return name;
-}
-
-QString getClassTargetFullName(const AbstractMetaClass *metaClass, bool includePackageName)
-{
- return getClassTargetFullName_(metaClass, includePackageName);
-}
-
-QString getClassTargetFullName(const AbstractMetaEnum *metaEnum, bool includePackageName)
-{
- return getClassTargetFullName_(metaEnum, includePackageName);
-}
-
-QString getClassTargetFullName(const AbstractMetaType *metaType, bool includePackageName)
-{
- QString name = metaType->cppSignature();
- name.replace(QLatin1String("::"), QLatin1String("_"));
- name.replace(QLatin1Char('<'), QLatin1Char('_'));
- name.remove(QLatin1Char('>'));
- name.remove(QLatin1Char(' '));
- if (includePackageName) {
- name.prepend(QLatin1Char('.'));
- name.prepend(metaType->package());
- }
- return name;
-}
-
-QString getFilteredCppSignatureString(QString signature)
-{
- signature.replace(QLatin1String("::"), QLatin1String("_"));
- signature.replace(QLatin1Char('<'), QLatin1Char('_'));
- signature.replace(QLatin1Char('>'), QLatin1Char('_'));
- signature.replace(QLatin1Char(' '), QLatin1Char('_'));
- return signature;
-}
diff --git a/sources/shiboken2/generator/generator.h b/sources/shiboken2/generator/generator.h
deleted file mode 100644
index dde281f0e..000000000
--- a/sources/shiboken2/generator/generator.h
+++ /dev/null
@@ -1,421 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef GENERATOR_H
-#define GENERATOR_H
-
-#include "indentor.h"
-#include <abstractmetalang_typedefs.h>
-#include <typedatabase_typedefs.h>
-#include <dependency.h>
-#include <QtCore/QObject>
-#include <QtCore/QSharedPointer>
-#include <QtCore/QTextStream>
-#include <QtCore/QVector>
-
-class ApiExtractor;
-class AbstractMetaBuilder;
-class AbstractMetaFunction;
-class AbstractMetaClass;
-class AbstractMetaEnum;
-class TypeEntry;
-class ComplexTypeEntry;
-class AbstractMetaType;
-class EnumTypeEntry;
-class FlagsTypeEntry;
-
-QT_BEGIN_NAMESPACE
-class QFile;
-QT_END_NAMESPACE
-
-class PrimitiveTypeEntry;
-class ContainerTypeEntry;
-
-QTextStream &formatCode(QTextStream &s, const QString &code, Indentor &indentor);
-void verifyDirectoryFor(const QString &file);
-
-QString getClassTargetFullName(const AbstractMetaClass *metaClass, bool includePackageName = true);
-QString getClassTargetFullName(const AbstractMetaEnum *metaEnum, bool includePackageName = true);
-QString getClassTargetFullName(const AbstractMetaType *metaType, bool includePackageName = true);
-QString getFilteredCppSignatureString(QString signature);
-
-/**
- * PYSIDE-504: Handling the "protected hack"
- *
- * The problem: Creating wrappers when the class has private destructors.
- * You can see an example on Windows in qclipboard_wrapper.h and others.
- * Simply search for the text "// C++11: need to declare (unimplemented) destructor".
- *
- * The protected hack is the definition "#define protected public".
- * For most compilers, this "hack" is enabled, because the problem of private
- * destructors simply vanishes.
- *
- * If one does not want to use this hack, then a new problem arises:
- * C++11 requires that a destructor is declared in a wrapper class when it is
- * private in the base class. There is no implementation allowed!
- *
- * Unfortunately, MSVC in recent versions supports C++11, and due to restrictive
- * rules, it is impossible to use the hack with this compiler.
- * More unfortunate: Clang, when C++11 is enabled, also enforces a declaration
- * of a private destructor, but it falsely then creates a linker error!
- *
- * Originally, we wanted to remove the protected hack. But due to the Clang
- * problem, we gave up on removal of the protected hack and use it always
- * when we can. This might change again when the Clang problem is solved.
- */
-
-#ifdef Q_CC_MSVC
-const int alwaysGenerateDestructor = 1;
-#else
-const int alwaysGenerateDestructor = 0;
-#endif
-
-class DefaultValue
-{
-public:
- enum Type
- {
- Error,
- Boolean,
- CppScalar, // A C++ scalar type (int,..) specified by value()
- Custom, // A custom constructor/expression, uses value() as is
- DefaultConstructor, // For classes named value()
- DefaultConstructorWithDefaultValues, // as DefaultConstructor, but can't return {} though.
- Enum, // Enum value as specified by value()
- Pointer, // Pointer of type value()
- Void // "", for return values only
- };
-
- explicit DefaultValue(Type t = Error, QString value = QString());
- explicit DefaultValue(QString customValue);
-
- bool isValid() const { return m_type != Error; }
-
- QString returnValue() const;
- QString initialization() const;
- QString constructorParameter() const;
-
- QString value() const { return m_value; }
- void setValue(const QString &value) { m_value = value; }
-
- Type type() const { return m_type; }
- void setType(Type type) { m_type = type; }
-
-private:
- Type m_type;
- QString m_value;
-};
-
-/**
- * A GeneratorContext object contains a pointer to an AbstractMetaClass and/or a specialized
- * AbstractMetaType, for which code is currently being generated.
- *
- * The main case is when the context contains only an AbstractMetaClass pointer, which is used
- * by different methods to generate appropriate expressions, functions, type names, etc.
- *
- * The second case is for generation of code for smart pointers. In this case the m_metaClass member
- * contains the generic template class of the smart pointer, and the m_preciseClassType member
- * contains the instantiated template type, e.g. a concrete shared_ptr<int>. To
- * distinguish this case, the member m_forSmartPointer is set to true.
- *
- * In the future the second case might be generalized for all template type instantiations.
- */
-class GeneratorContext {
-public:
- GeneratorContext() = default;
- GeneratorContext(AbstractMetaClass *metaClass,
- const AbstractMetaType *preciseType = nullptr,
- bool forSmartPointer = false)
- : m_metaClass(metaClass),
- m_preciseClassType(preciseType),
- m_forSmartPointer(forSmartPointer) {}
-
-
- AbstractMetaClass *metaClass() const { return m_metaClass; }
- bool forSmartPointer() const { return m_forSmartPointer; }
- const AbstractMetaType *preciseType() const { return m_preciseClassType; }
-
-private:
- AbstractMetaClass *m_metaClass = nullptr;
- const AbstractMetaType *m_preciseClassType = nullptr;
- bool m_forSmartPointer = false;
-};
-
-/**
- * Base class for all generators. The default implementations does nothing,
- * you must subclass this to create your own generators.
- */
-class Generator
-{
-public:
- using OptionDescription = QPair<QString, QString>;
- using OptionDescriptions = QVector<OptionDescription>;
-
- /// Optiosn used around the generator code
- enum Option {
- NoOption = 0x00000000,
- ExcludeConst = 0x00000001,
- ExcludeReference = 0x00000002,
-
- EnumAsInts = 0x00000004,
- SkipName = 0x00000008,
- SkipReturnType = 0x00000010,
- OriginalName = 0x00000020,
- VirtualCall = 0x00000040,
- OriginalTypeDescription = 0x00000080,
- SkipRemovedArguments = 0x00000100,
-
- SkipDefaultValues = 0x00000200,
-
- WriteSelf = 0x00000400,
- ExcludeMethodConst = 0x00000800,
-
- ForceValueType = ExcludeReference | ExcludeConst
- };
- Q_DECLARE_FLAGS(Options, Option)
-
- Generator();
- virtual ~Generator();
-
- bool setup(const ApiExtractor &extractor);
-
- virtual OptionDescriptions options() const;
- virtual bool handleOption(const QString &key, const QString &value);
-
- /// Returns the classes used to generate the binding code.
- AbstractMetaClassList classes() const;
-
- /// Returns the output directory
- QString outputDirectory() const;
-
- /// Set the output directory
- void setOutputDirectory(const QString &outDir);
-
- /**
- * Start the code generation, be sure to call setClasses before callign this method.
- * For each class it creates a QTextStream, call the write method with the current
- * class and the associated text stream, then write the text stream contents if needed.
- * \see #write
- */
- bool generate();
-
- /// 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 generator's name. Used for cosmetic purposes.
- virtual const char *name() const = 0;
-
- /**
- * 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
- */
- 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);
-
-protected:
- /// Returns the classes, topologically ordered, used to generate the binding code.
- ///
- /// The classes are ordered such that derived classes appear later in the list than
- /// their parent classes.
- AbstractMetaClassList classesTopologicalSorted(const Dependencies &additionalDependencies = Dependencies()) const;
-
- /// Returns all global functions found by APIExtractor
- AbstractMetaFunctionList globalFunctions() const;
-
- /// Returns all global enums found by APIExtractor
- AbstractMetaEnumList globalEnums() const;
-
- /// Returns all primitive types found by APIExtractor
- PrimitiveTypeEntryList primitiveTypes() const;
-
- /// Returns all container types found by APIExtractor
- ContainerTypeEntryList containerTypes() const;
-
- /// Returns an AbstractMetaEnum for a given TypeEntry that is an EnumTypeEntry, or nullptr if not found.
- const AbstractMetaEnum *findAbstractMetaEnum(const TypeEntry *typeEntry) const;
-
- /// Returns an AbstractMetaEnum for a given AbstractMetaType that holds an EnumTypeEntry, or nullptr if not found.
- const AbstractMetaEnum *findAbstractMetaEnum(const AbstractMetaType *metaType) const;
-
- /// Generates a file for given AbstractMetaClass or AbstractMetaType (smart pointer case).
- bool generateFileForContext(GeneratorContext &context);
-
- /// Returns the file base name for a smart pointer.
- QString getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType,
- const AbstractMetaClass *smartPointerClass) const;
-
- /// Returns 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);
-
- /**
- * Returns the package name.
- */
- QString packageName() const;
-
- // 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.
- */
- DefaultValue minimalConstructor(const TypeEntry *type) const;
- DefaultValue minimalConstructor(const AbstractMetaType *type) const;
- DefaultValue minimalConstructor(const AbstractMetaClass *metaClass) const;
-
- /**
- * Returns the file name used to write the binding code of an AbstractMetaClass/Type.
- * \param context the GeneratorContext which contains an AbstractMetaClass or AbstractMetaType
- * for which the file name must be returned
- * \return the file name used to write the binding code for the class
- */
- virtual QString fileNameSuffix() const = 0;
- virtual QString fileNameForContext(GeneratorContext &context) const = 0;
-
-
- virtual bool doSetup() = 0;
-
- /**
- * Write the bindding code for an AbstractMetaClass.
- * This is called by generate method.
- * \param s text stream to write the generated output
- * \param metaClass the class that should be generated
- */
- virtual void generateClass(QTextStream &s, GeneratorContext &classContext) = 0;
- virtual bool finishGeneration() = 0;
-
- /**
- * Returns the subdirectory path for a given package
- * (aka module, aka library) name.
- * If the target language separates the package modules with characters other
- * than dots ('.') the generator subclass must overload this method.
- * /param packageName complete package name for which to return the subdirectory path
- * or nothing the use the name of the currently processed package
- * /return a string representing the subdirectory path for the given package
- */
- virtual QString subDirectoryForPackage(QString packageName = QString()) const;
-
- QVector<const AbstractMetaType *> instantiatedContainers() const;
- QVector<const AbstractMetaType *> instantiatedSmartPointers() const;
-
- static QString getSimplifiedContainerTypeName(const AbstractMetaType *type);
- void addInstantiatedContainersAndSmartPointers(const AbstractMetaType *type,
- const QString &context);
-
-private:
- bool useEnumAsIntForProtectedHack(const AbstractMetaType *cType) const;
-
- struct GeneratorPrivate;
- GeneratorPrivate *m_d;
- void collectInstantiatedContainersAndSmartPointers(const AbstractMetaFunction *func);
- void collectInstantiatedContainersAndSmartPointers(const AbstractMetaClass *metaClass);
- void collectInstantiatedContainersAndSmartPointers();
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(Generator::Options)
-using GeneratorPtr = QSharedPointer<Generator>;
-using Generators = QVector<GeneratorPtr>;
-
-#endif // GENERATOR_H
-
diff --git a/sources/shiboken2/generator/indentor.h b/sources/shiboken2/generator/indentor.h
deleted file mode 100644
index 111259f12..000000000
--- a/sources/shiboken2/generator/indentor.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef INDENTOR_H
-#define INDENTOR_H
-
-#include <QtCore/QTextStream>
-
-/**
-* Utility class to store the indentation level, use it in a QTextStream.
-*/
-
-template <int tabWidth>
-class IndentorBase
-{
-public:
- int total() const { return tabWidth * indent; }
-
- int indent = 0;
-};
-
-using Indentor = IndentorBase<4>;
-using Indentor1 = IndentorBase<1>;
-
-/**
-* Class that use the RAII idiom to set and unset the indentation level.
-*/
-
-template <int tabWidth>
-class IndentationBase
-{
-public:
- using Indentor = IndentorBase<tabWidth>;
-
- IndentationBase(Indentor &indentor, int count = 1) : m_count(count), indentor(indentor)
- {
- indentor.indent += m_count;
- }
-
- ~IndentationBase()
- {
- indentor.indent -= m_count;
- }
-
-private:
- const int m_count;
- Indentor &indentor;
-};
-
-using Indentation = IndentationBase<4>;
-
-template <int tabWidth>
-inline QTextStream &operator <<(QTextStream &s, const IndentorBase<tabWidth> &indentor)
-{
- for (int i = 0, total = indentor.total(); i < total; ++i)
- s << ' ';
- return s;
-}
-
-#endif // GENERATOR_H
diff --git a/sources/shiboken2/generator/main.cpp b/sources/shiboken2/generator/main.cpp
deleted file mode 100644
index 089ecb48f..000000000
--- a/sources/shiboken2/generator/main.cpp
+++ /dev/null
@@ -1,642 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QCoreApplication>
-#include <QLibrary>
-#include <QtCore/QFile>
-#include <QtCore/QDir>
-#include <iostream>
-#include <apiextractor.h>
-#include <fileout.h>
-#include <typedatabase.h>
-#include <messages.h>
-#include "generator.h"
-#include "shibokenconfig.h"
-#include "cppgenerator.h"
-#include "headergenerator.h"
-#include "qtdocgenerator.h"
-
-#ifdef _WINDOWS
-static const QChar pathSplitter = QLatin1Char(';');
-#else
-static const QChar pathSplitter = QLatin1Char(':');
-#endif
-
-static inline QString languageLevelOption() { return QStringLiteral("language-level"); }
-static inline QString includePathOption() { return QStringLiteral("include-paths"); }
-static inline QString frameworkIncludePathOption() { return QStringLiteral("framework-include-paths"); }
-static inline QString systemIncludePathOption() { return QStringLiteral("system-include-paths"); }
-static inline QString typesystemPathOption() { return QStringLiteral("typesystem-paths"); }
-static inline QString helpOption() { return QStringLiteral("help"); }
-static inline QString diffOption() { return QStringLiteral("diff"); }
-static inline QString dryrunOption() { return QStringLiteral("dry-run"); }
-static inline QString skipDeprecatedOption() { return QStringLiteral("skip-deprecated"); }
-
-static const char helpHint[] = "Note: use --help or -h for more information.\n";
-
-using CommandArgumentMap = QMap<QString, QString>;
-
-using OptionDescriptions = Generator::OptionDescriptions;
-
-static void printOptions(QTextStream &s, const OptionDescriptions &options)
-{
- s.setFieldAlignment(QTextStream::AlignLeft);
- for (const auto &od : options) {
- if (!od.first.startsWith(QLatin1Char('-')))
- s << "--";
- s << od.first;
- if (od.second.isEmpty()) {
- s << ", ";
- } else {
- s << Qt::endl;
- const auto lines = od.second.splitRef(QLatin1Char('\n'));
- for (const auto &line : lines)
- s << " " << line << Qt::endl;
- s << Qt::endl;
- }
- }
-}
-
-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 frameworkIncludePaths;
- QStringList systemIncludePaths;
- QStringList typesystemPaths;
- QStringList apiVersions;
- QString languageLevel;
-
- while (!projectFile.atEnd()) {
- line = projectFile.readLine().trimmed();
- if (line.isEmpty())
- continue;
-
- int split = line.indexOf('=');
- QByteArray key;
- QString value;
- if (split > 0) {
- key = line.left(split - 1).trimmed();
- value = QString::fromUtf8(line.mid(split + 1).trimmed());
- } else {
- key = line;
- }
-
- if (key == "include-path")
- includePaths << QDir::toNativeSeparators(value);
- else if (key == "framework-include-path")
- frameworkIncludePaths << QDir::toNativeSeparators(value);
- else if (key == "system-include-paths")
- systemIncludePaths << QDir::toNativeSeparators(value);
- else if (key == "typesystem-path")
- typesystemPaths << QDir::toNativeSeparators(value);
- else if (key == "language-level")
- languageLevel = value;
- else if (key == "api-version")
- apiVersions << value;
- else if (key == "header-file")
- args.insert(QLatin1String("arg-1"), value);
- else if (key == "typesystem-file")
- args.insert(QLatin1String("arg-2"), value);
- else
- args.insert(QString::fromUtf8(key), value);
- }
-
- if (!includePaths.isEmpty())
- args.insert(includePathOption(), includePaths.join(pathSplitter));
-
- if (!frameworkIncludePaths.isEmpty())
- args.insert(frameworkIncludePathOption(),
- frameworkIncludePaths.join(pathSplitter));
- if (!systemIncludePaths.isEmpty()) {
- args.insert(systemIncludePathOption(),
- systemIncludePaths.join(pathSplitter));
- }
-
- if (!typesystemPaths.isEmpty())
- args.insert(typesystemPathOption(), typesystemPaths.join(pathSplitter));
- if (!apiVersions.isEmpty())
- args.insert(QLatin1String("api-version"), apiVersions.join(QLatin1Char('|')));
- if (!languageLevel.isEmpty())
- args.insert(languageLevelOption(), languageLevel);
- return true;
-}
-
-static CommandArgumentMap getInitializedArguments()
-{
- CommandArgumentMap args;
- QStringList arguments = QCoreApplication::arguments();
- QString appName = arguments.constFirst();
- arguments.removeFirst();
-
- QString projectFileName;
- for (const QString &arg : qAsConst(arguments)) {
- if (arg.startsWith(QLatin1String("--project-file"))) {
- int split = arg.indexOf(QLatin1Char('='));
- if (split > 0)
- projectFileName = arg.mid(split + 1).trimmed();
- break;
- }
- }
-
- if (projectFileName.isEmpty())
- 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;
-}
-
-// Concatenate values of path arguments that can occur multiple times on the
-// command line.
-static void addPathOptionValue(const QString &option, const QString &value,
- CommandArgumentMap &args)
-{
- const CommandArgumentMap::iterator it = args.find(option);
- if (it != args.end())
- it.value().append(pathSplitter + value);
- else
- args.insert(option, value);
-}
-
-static void getCommandLineArg(QString arg, int &argNum, QMap<QString, QString> &args)
-{
- if (arg.startsWith(QLatin1String("--"))) {
- arg.remove(0, 2);
- const int split = arg.indexOf(QLatin1Char('='));
- if (split < 0) {
- args.insert(arg, QString());
- return;
- }
- const QString option = arg.left(split);
- const QString value = arg.mid(split + 1).trimmed();
- if (option == includePathOption() || option == frameworkIncludePathOption()
- || option == systemIncludePathOption() || option == typesystemPathOption()) {
- addPathOptionValue(option, value, args);
- } else {
- args.insert(option, value);
- }
- return;
- }
- if (arg.startsWith(QLatin1Char('-'))) {
- arg.remove(0, 1);
- if (arg.startsWith(QLatin1Char('I'))) // Shorthand path arguments -I/usr/include...
- addPathOptionValue(includePathOption(), arg.mid(1), args);
- else if (arg.startsWith(QLatin1Char('F')))
- addPathOptionValue(frameworkIncludePathOption(), arg.mid(1), args);
- else if (arg.startsWith(QLatin1String("isystem")))
- addPathOptionValue(systemIncludePathOption(), arg.mid(7), args);
- else if (arg.startsWith(QLatin1Char('T')))
- addPathOptionValue(typesystemPathOption(), arg.mid(1), args);
- else if (arg == QLatin1String("h"))
- args.insert(helpOption(), QString());
- else if (arg.startsWith(QLatin1String("std=")))
- args.insert(languageLevelOption(), arg.mid(4));
- else
- args.insert(arg, QString());
- return;
- }
- argNum++;
- args.insert(QStringLiteral("arg-") + QString::number(argNum), arg);
-}
-
-static QMap<QString, QString> getCommandLineArgs()
-{
- QMap<QString, QString> args = getInitializedArguments();
- QStringList arguments = QCoreApplication::arguments();
- arguments.removeFirst();
-
- int argNum = 0;
- for (const QString &carg : qAsConst(arguments))
- getCommandLineArg(carg.trimmed(), argNum, args);
-
- return args;
-}
-
-static inline Generators docGenerators()
-{
- Generators result;
-#ifdef DOCSTRINGS_ENABLED
- result.append(GeneratorPtr(new QtDocGenerator));
-#endif
- return result;
-}
-
-static inline Generators shibokenGenerators()
-{
- Generators result;
- result << GeneratorPtr(new CppGenerator) << GeneratorPtr(new HeaderGenerator);
- return result;
-}
-
-static inline QString languageLevelDescription()
-{
- return QLatin1String("C++ Language level (c++11..c++17, default=")
- + QLatin1String(clang::languageLevelOption(clang::emulatedCompilerLanguageLevel()))
- + QLatin1Char(')');
-}
-
-void printUsage()
-{
- QTextStream s(stdout);
- s << "Usage:\n "
- << "shiboken [options] header-file typesystem-file\n\n"
- << "General options:\n";
- QString pathSyntax;
- QTextStream(&pathSyntax) << "<path>[" << pathSplitter << "<path>"
- << pathSplitter << "...]";
- OptionDescriptions generalOptions = OptionDescriptions()
- << qMakePair(QLatin1String("api-version=<\"package mask\">,<\"version\">"),
- QLatin1String("Specify the supported api version used to generate the bindings"))
- << qMakePair(QLatin1String("debug-level=[sparse|medium|full]"),
- QLatin1String("Set the debug level"))
- << qMakePair(QLatin1String("documentation-only"),
- QLatin1String("Do not generates any code, just the documentation"))
- << qMakePair(QLatin1String("drop-type-entries=\"<TypeEntry0>[;TypeEntry1;...]\""),
- QLatin1String("Semicolon separated list of type system entries (classes, namespaces,\n"
- "global functions and enums) to be dropped from generation."))
- << qMakePair(QLatin1String("-F<path>"), QString())
- << qMakePair(QLatin1String("framework-include-paths=") + pathSyntax,
- QLatin1String("Framework include paths used by the C++ parser"))
- << qMakePair(QLatin1String("-isystem<path>"), QString())
- << qMakePair(QLatin1String("system-include-paths=") + pathSyntax,
- QLatin1String("System include paths used by the C++ parser"))
- << qMakePair(QLatin1String("generator-set=<\"generator module\">"),
- QLatin1String("generator-set to be used. e.g. qtdoc"))
- << qMakePair(skipDeprecatedOption(),
- QLatin1String("Skip deprecated functions"))
- << qMakePair(diffOption(),
- QLatin1String("Print a diff of wrapper files"))
- << qMakePair(dryrunOption(),
- QLatin1String("Dry run, do not generate wrapper files"))
- << qMakePair(QLatin1String("-h"), QString())
- << qMakePair(helpOption(),
- QLatin1String("Display this help and exit"))
- << qMakePair(QLatin1String("-I<path>"), QString())
- << qMakePair(QLatin1String("include-paths=") + pathSyntax,
- QLatin1String("Include paths used by the C++ parser"))
- << qMakePair(languageLevelOption() + QLatin1String("=, -std=<level>"),
- languageLevelDescription())
- << qMakePair(QLatin1String("license-file=<license-file>"),
- QLatin1String("File used for copyright headers of generated files"))
- << qMakePair(QLatin1String("no-suppress-warnings"),
- QLatin1String("Show all warnings"))
- << qMakePair(QLatin1String("output-directory=<path>"),
- QLatin1String("The directory where the generated files will be written"))
- << qMakePair(QLatin1String("project-file=<file>"),
- QLatin1String("text file containing a description of the binding project.\n"
- "Replaces and overrides command line arguments"))
- << qMakePair(QLatin1String("silent"),
- QLatin1String("Avoid printing any message"))
- << qMakePair(QLatin1String("-T<path>"), QString())
- << qMakePair(QLatin1String("typesystem-paths=") + pathSyntax,
- QLatin1String("Paths used when searching for typesystems"))
- << qMakePair(QLatin1String("version"),
- QLatin1String("Output version information and exit"));
- printOptions(s, generalOptions);
-
- const Generators generators = shibokenGenerators() + docGenerators();
- for (const GeneratorPtr &generator : generators) {
- const OptionDescriptions options = generator->options();
- if (!options.isEmpty()) {
- s << Qt::endl << generator->name() << " options:\n\n";
- printOptions(s, generator->options());
- }
- }
-}
-
-static inline void printVerAndBanner()
-{
- std::cout << "shiboken v" SHIBOKEN_VERSION << std::endl;
- std::cout << "Copyright (C) 2016 The Qt Company Ltd." << std::endl;
-}
-
-static inline void errorPrint(const QString &s)
-{
- QStringList arguments = QCoreApplication::arguments();
- arguments.pop_front();
- std::cerr << "shiboken: " << qPrintable(s)
- << "\nCommand line: " << qPrintable(arguments.join(QLatin1Char(' '))) << '\n';
-}
-
-static void parseIncludePathOption(const QString &option, HeaderType headerType,
- CommandArgumentMap &args,
- ApiExtractor &extractor)
-{
- const CommandArgumentMap::iterator it = args.find(option);
- if (it != args.end()) {
- const QStringList includePathListList =
- it.value().split(pathSplitter, QString::SkipEmptyParts);
- args.erase(it);
- for (const QString &s : includePathListList) {
- auto path = QFile::encodeName(QDir::cleanPath(s));
- extractor.addIncludePath(HeaderPath{path, headerType});
- }
- }
-}
-
-int main(int argc, char *argv[])
-{
- // PYSIDE-757: Request a deterministic ordering of QHash in the code model
- // and type system.
- qSetGlobalQHashSeed(0);
- // needed by qxmlpatterns
- QCoreApplication app(argc, argv);
- ReportHandler::install();
- qCDebug(lcShiboken()).noquote().nospace() << QCoreApplication::arguments().join(QLatin1Char(' '));
-
- // Store command arguments in a map
- CommandArgumentMap args = getCommandLineArgs();
- Generators generators;
-
- CommandArgumentMap::iterator ait = args.find(QLatin1String("version"));
- if (ait != args.end()) {
- args.erase(ait);
- printVerAndBanner();
- return EXIT_SUCCESS;
- }
-
- QString generatorSet;
- ait = args.find(QLatin1String("generator-set"));
- if (ait == args.end()) // Also check QLatin1String("generatorSet") command line argument for backward compatibility.
- ait = args.find(QLatin1String("generatorSet"));
- if (ait != args.end()) {
- generatorSet = ait.value();
- args.erase(ait);
- }
-
- // Pre-defined generator sets.
- if (generatorSet == QLatin1String("qtdoc")) {
- generators = docGenerators();
- if (generators.isEmpty()) {
- errorPrint(QLatin1String("Doc strings extractions was not enabled in this shiboken build."));
- return EXIT_FAILURE;
- }
- } else if (generatorSet.isEmpty() || generatorSet == QLatin1String("shiboken")) {
- generators = shibokenGenerators();
- } else {
- errorPrint(QLatin1String("Unknown generator set, try \"shiboken\" or \"qtdoc\"."));
- return EXIT_FAILURE;
- }
-
- ait = args.find(QLatin1String("help"));
- if (ait != args.end()) {
- args.erase(ait);
- printUsage();
- return EXIT_SUCCESS;
- }
-
- ait = args.find(diffOption());
- if (ait != args.end()) {
- args.erase(ait);
- FileOut::diff = true;
- }
-
- ait = args.find(dryrunOption());
- if (ait != args.end()) {
- args.erase(ait);
- FileOut::dummy = true;
- }
-
- QString licenseComment;
- ait = args.find(QLatin1String("license-file"));
- if (ait != args.end()) {
- QFile licenseFile(ait.value());
- args.erase(ait);
- if (licenseFile.open(QIODevice::ReadOnly)) {
- licenseComment = QString::fromUtf8(licenseFile.readAll());
- } else {
- errorPrint(QStringLiteral("Could not open the file \"%1\" containing the license heading: %2").
- arg(QDir::toNativeSeparators(licenseFile.fileName()), licenseFile.errorString()));
- return EXIT_FAILURE;
- }
- }
-
- QString outputDirectory = QLatin1String("out");
- ait = args.find(QLatin1String("output-directory"));
- if (ait != args.end()) {
- outputDirectory = ait.value();
- args.erase(ait);
- }
-
- if (!QDir(outputDirectory).exists()) {
- if (!QDir().mkpath(outputDirectory)) {
- qCWarning(lcShiboken).noquote().nospace()
- << "Can't create output directory: " << QDir::toNativeSeparators(outputDirectory);
- return EXIT_FAILURE;
- }
- }
-
- // Create and set-up API Extractor
- ApiExtractor extractor;
- extractor.setLogDirectory(outputDirectory);
- ait = args.find(skipDeprecatedOption());
- if (ait != args.end()) {
- extractor.setSkipDeprecated(true);
- args.erase(ait);
- }
-
- ait = args.find(QLatin1String("silent"));
- if (ait != args.end()) {
- extractor.setSilent(true);
- args.erase(ait);
- } else {
- ait = args.find(QLatin1String("debug-level"));
- if (ait != args.end()) {
- const QString level = ait.value();
- args.erase(ait);
- if (level == QLatin1String("sparse"))
- extractor.setDebugLevel(ReportHandler::SparseDebug);
- else if (level == QLatin1String("medium"))
- extractor.setDebugLevel(ReportHandler::MediumDebug);
- else if (level == QLatin1String("full"))
- extractor.setDebugLevel(ReportHandler::FullDebug);
- }
- }
- ait = args.find(QLatin1String("no-suppress-warnings"));
- if (ait != args.end()) {
- args.erase(ait);
- extractor.setSuppressWarnings(false);
- }
- ait = args.find(QLatin1String("api-version"));
- if (ait != args.end()) {
- const QStringList &versions = ait.value().split(QLatin1Char('|'));
- args.erase(ait);
- for (const QString &fullVersion : versions) {
- QStringList parts = fullVersion.split(QLatin1Char(','));
- QString package;
- QString version;
- package = parts.count() == 1 ? QLatin1String("*") : parts.constFirst();
- version = parts.constLast();
- if (!extractor.setApiVersion(package, version)) {
- errorPrint(msgInvalidVersion(package, version));
- return EXIT_FAILURE;
- }
- }
- }
-
- ait = args.find(QLatin1String("drop-type-entries"));
- if (ait != args.end()) {
- extractor.setDropTypeEntries(ait.value());
- args.erase(ait);
- }
-
- ait = args.find(QLatin1String("typesystem-paths"));
- if (ait != args.end()) {
- extractor.addTypesystemSearchPath(ait.value().split(pathSplitter));
- args.erase(ait);
- }
-
- parseIncludePathOption(includePathOption(), HeaderType::Standard,
- args, extractor);
- parseIncludePathOption(frameworkIncludePathOption(), HeaderType::Framework,
- args, extractor);
- parseIncludePathOption(systemIncludePathOption(), HeaderType::System,
- args, extractor);
-
- ait = args.find(QLatin1String("arg-1"));
- if (ait == args.end()) {
- errorPrint(QLatin1String("Required argument header-file is missing."));
- return EXIT_FAILURE;
- }
- const QString cppFileName = ait.value();
- args.erase(ait);
- const QFileInfo cppFileNameFi(cppFileName);
- if (!cppFileNameFi.isFile() && !cppFileNameFi.isSymLink()) {
- errorPrint(QLatin1Char('"') + cppFileName + QLatin1String("\" does not exist."));
- return EXIT_FAILURE;
- }
-
- ait = args.find(QLatin1String("arg-2"));
- if (ait == args.end()) {
- errorPrint(QLatin1String("Required argument typesystem-file is missing."));
- return EXIT_FAILURE;
- }
- const QString typeSystemFileName = ait.value();
- args.erase(ait);
- QString messagePrefix = QFileInfo(typeSystemFileName).baseName();
- if (messagePrefix.startsWith(QLatin1String("typesystem_")))
- messagePrefix.remove(0, 11);
- ReportHandler::setPrefix(QLatin1Char('(') + messagePrefix + QLatin1Char(')'));
-
- // Pass option to all generators (Cpp/Header generator have the same options)
- for (ait = args.begin(); ait != args.end(); ) {
- bool found = false;
- for (const GeneratorPtr &generator : qAsConst(generators))
- found |= generator->handleOption(ait.key(), ait.value());
- if (found)
- ait = args.erase(ait);
- else
- ++ait;
- }
-
- ait = args.find(languageLevelOption());
- if (ait != args.end()) {
- const QByteArray languageLevelBA = ait.value().toLatin1();
- args.erase(ait);
- const LanguageLevel level = clang::languageLevelFromOption(languageLevelBA.constData());
- if (level == LanguageLevel::Default) {
- std::cout << "Invalid argument for language level: \""
- << languageLevelBA.constData() << "\"\n" << helpHint;
- return EXIT_FAILURE;
- }
- extractor.setLanguageLevel(level);
- }
-
- /* 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.
- */
- args.remove(QLatin1String("project-file"));
- CommandArgumentMap projectFileArgs = getInitializedArguments();
- for (auto it = projectFileArgs.cbegin(), end = projectFileArgs.cend(); it != end; ++it)
- args.remove(it.key());
-
- if (!args.isEmpty()) {
- errorPrint(msgLeftOverArguments(args));
- std::cout << helpHint;
- return EXIT_FAILURE;
- }
-
- if (typeSystemFileName.isEmpty()) {
- std::cout << "You must specify a Type System file." << std::endl << helpHint;
- return EXIT_FAILURE;
- }
-
- extractor.setCppFileName(cppFileNameFi.absoluteFilePath());
- extractor.setTypeSystem(typeSystemFileName);
-
- if (!extractor.run()) {
- errorPrint(QLatin1String("Error running ApiExtractor."));
- return EXIT_FAILURE;
- }
-
- if (!extractor.classCount())
- qCWarning(lcShiboken) << "No C++ classes found!";
-
- qCDebug(lcShiboken) << extractor << '\n'
- << *TypeDatabase::instance();
-
- for (const GeneratorPtr &g : qAsConst(generators)) {
- g->setOutputDirectory(outputDirectory);
- g->setLicenseComment(licenseComment);
- ReportHandler::startProgress(QByteArray("Running ") + g->name() + "...");
- const bool ok = g->setup(extractor) && g->generate();
- ReportHandler::endProgress();
- if (!ok) {
- errorPrint(QLatin1String("Error running generator: ")
- + QLatin1String(g->name()) + QLatin1Char('.'));
- return EXIT_FAILURE;
- }
- }
-
- const QByteArray doneMessage = ReportHandler::doneMessage();
- qCDebug(lcShiboken, "%s", doneMessage.constData());
- std::cout << doneMessage.constData() << std::endl;
-
- return EXIT_SUCCESS;
-}
diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
deleted file mode 100644
index 2b7efd6e7..000000000
--- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp
+++ /dev/null
@@ -1,2408 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qtdocgenerator.h"
-#include <abstractmetalang.h>
-#include <messages.h>
-#include <reporthandler.h>
-#include <typesystem.h>
-#include <qtdocparser.h>
-#include <doxygenparser.h>
-#include <typedatabase.h>
-#include <algorithm>
-#include <QtCore/QStack>
-#include <QtCore/QRegularExpression>
-#include <QtCore/QTextStream>
-#include <QtCore/QXmlStreamReader>
-#include <QtCore/QFile>
-#include <QtCore/QDir>
-#include <fileout.h>
-#include <limits>
-
-static Indentor INDENT;
-
-static inline QString additionalDocumentationOption() { return QStringLiteral("additional-documentation"); }
-
-static inline QString nameAttribute() { return QStringLiteral("name"); }
-static inline QString titleAttribute() { return QStringLiteral("title"); }
-static inline QString fullTitleAttribute() { return QStringLiteral("fulltitle"); }
-static inline QString briefAttribute() { return QStringLiteral("brief"); }
-static inline QString briefStartElement() { return QStringLiteral("<brief>"); }
-static inline QString briefEndElement() { return QStringLiteral("</brief>"); }
-
-static inline QString none() { return QStringLiteral("None"); }
-
-static void stripPythonQualifiers(QString *s)
-{
- const int lastSep = s->lastIndexOf(QLatin1Char('.'));
- if (lastSep != -1)
- s->remove(0, lastSep + 1);
-}
-
-static bool shouldSkip(const AbstractMetaFunction* func)
-{
- // Constructors go to separate section
- if (DocParser::skipForQuery(func) || func->isConstructor())
- return true;
-
- // Search a const clone (QImage::bits() vs QImage::bits() const)
- if (func->isConstant())
- return false;
-
- const AbstractMetaArgumentList funcArgs = func->arguments();
- const AbstractMetaFunctionList &ownerFunctions = func->ownerClass()->functions();
- for (AbstractMetaFunction *f : ownerFunctions) {
- 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 false;
-}
-
-static bool functionSort(const AbstractMetaFunction* func1, const AbstractMetaFunction* func2)
-{
- return func1->name() < func2->name();
-}
-
-class Pad
-{
-public:
- explicit Pad(char c, int count) : m_char(c), m_count(count) {}
-
- void write(QTextStream &str) const
- {
- for (int i = 0; i < m_count; ++i)
- str << m_char;
- }
-
-private:
- const char m_char;
- const int m_count;
-};
-
-inline QTextStream &operator<<(QTextStream &str, const Pad &pad)
-{
- pad.write(str);
- return str;
-}
-
-template <class String>
-static int writeEscapedRstText(QTextStream &str, const String &s)
-{
- int escaped = 0;
- for (const QChar &c : s) {
- switch (c.unicode()) {
- case '*':
- case '`':
- case '_':
- case '\\':
- str << '\\';
- ++escaped;
- break;
- }
- str << c;
- }
- return s.size() + escaped;
-}
-
-class escape
-{
-public:
- explicit escape(const QStringRef &s) : m_string(s) {}
-
- void write(QTextStream &str) const { writeEscapedRstText(str, m_string); }
-
-private:
- const QStringRef m_string;
-};
-
-inline QTextStream &operator<<(QTextStream &str, const escape &e)
-{
- e.write(str);
- return str;
-}
-
-// Return last character of a QString-buffered stream.
-static QChar lastChar(const QTextStream &str)
-{
- const QString *string = str.string();
- Q_ASSERT(string);
- return string->isEmpty() ? QChar() : *(string->crbegin());
-}
-
-static QTextStream &ensureEndl(QTextStream &s)
-{
- if (lastChar(s) != QLatin1Char('\n'))
- s << Qt::endl;
- return s;
-}
-
-static inline QVersionNumber versionOf(const TypeEntry *te)
-{
- if (te) {
- const auto version = te->version();
- if (!version.isNull() && version > QVersionNumber(0, 0))
- return version;
- }
- return QVersionNumber();
-}
-
-struct rstVersionAdded
-{
- explicit rstVersionAdded(const QVersionNumber &v) : m_version(v) {}
-
- const QVersionNumber m_version;
-};
-
-static QTextStream &operator<<(QTextStream &s, const rstVersionAdded &v)
-{
- s << ".. versionadded:: "<< v.m_version.toString() << "\n\n";
- return s;
-}
-
-static QByteArray rstDeprecationNote(const char *what)
-{
- return QByteArrayLiteral(".. note:: This ")
- + what + QByteArrayLiteral(" is deprecated.\n\n");
-}
-
-// RST anchor string: Anything else but letters, numbers, '_' or '.' replaced by '-'
-static inline bool isValidRstLabelChar(QChar c)
-{
- return c.isLetterOrNumber() || c == QLatin1Char('_') || c == QLatin1Char('.');
-}
-
-static QString toRstLabel(QString s)
-{
- for (int i = 0, size = s.size(); i < size; ++i) {
- if (!isValidRstLabelChar(s.at(i)))
- s[i] = QLatin1Char('-');
- }
- return s;
-}
-
-class rstLabel
-{
-public:
- explicit rstLabel(const QString &l) : m_label(l) {}
-
- friend QTextStream &operator<<(QTextStream &str, const rstLabel &a)
- {
- str << ".. _" << toRstLabel(a.m_label) << ":\n\n";
- return str;
- }
-
-private:
- const QString &m_label;
-};
-
-struct QtXmlToSphinx::LinkContext
-{
- enum Type
- {
- Method = 0x1, Function = 0x2,
- FunctionMask = Method | Function,
- Class = 0x4, Attribute = 0x8, Module = 0x10,
- Reference = 0x20, External= 0x40
- };
-
- enum Flags { InsideBold = 0x1, InsideItalic = 0x2 };
-
- explicit LinkContext(const QString &ref) : linkRef(ref) {}
-
- QString linkRef;
- QString linkText;
- Type type = Reference;
- int flags = 0;
-};
-
-static const char *linkKeyWord(QtXmlToSphinx::LinkContext::Type type)
-{
- switch (type) {
- case QtXmlToSphinx::LinkContext::Method:
- return ":meth:";
- case QtXmlToSphinx::LinkContext::Function:
- return ":func:";
- case QtXmlToSphinx::LinkContext::Class:
- return ":class:";
- case QtXmlToSphinx::LinkContext::Attribute:
- return ":attr:";
- case QtXmlToSphinx::LinkContext::Module:
- return ":mod:";
- case QtXmlToSphinx::LinkContext::Reference:
- return ":ref:";
- case QtXmlToSphinx::LinkContext::External:
- break;
- case QtXmlToSphinx::LinkContext::FunctionMask:
- break;
- }
- return "";
-}
-
-QTextStream &operator<<(QTextStream &str, const QtXmlToSphinx::LinkContext &linkContext)
-{
- // Temporarily turn off bold/italic since links do not work within
- if (linkContext.flags & QtXmlToSphinx::LinkContext::InsideBold)
- str << "**";
- else if (linkContext.flags & QtXmlToSphinx::LinkContext::InsideItalic)
- str << '*';
- str << ' ' << linkKeyWord(linkContext.type) << '`';
- const bool isExternal = linkContext.type == QtXmlToSphinx::LinkContext::External;
- if (!linkContext.linkText.isEmpty()) {
- writeEscapedRstText(str, linkContext.linkText);
- if (isExternal && !linkContext.linkText.endsWith(QLatin1Char(' ')))
- str << ' ';
- str << '<';
- }
- // Convert page titles to RST labels
- str << (linkContext.type == QtXmlToSphinx::LinkContext::Reference
- ? toRstLabel(linkContext.linkRef) : linkContext.linkRef);
- if (!linkContext.linkText.isEmpty())
- str << '>';
- str << '`';
- if (isExternal)
- str << '_';
- str << ' ';
- if (linkContext.flags & QtXmlToSphinx::LinkContext::InsideBold)
- str << "**";
- else if (linkContext.flags & QtXmlToSphinx::LinkContext::InsideItalic)
- str << '*';
- return str;
-}
-
-QtXmlToSphinx::QtXmlToSphinx(QtDocGenerator* generator, const QString& doc, const QString& context)
- : m_tableHasHeader(false), m_context(context), m_generator(generator), m_insideBold(false), m_insideItalic(false)
-{
- m_handlerMap.insert(QLatin1String("heading"), &QtXmlToSphinx::handleHeadingTag);
- m_handlerMap.insert(QLatin1String("brief"), &QtXmlToSphinx::handleParaTag);
- m_handlerMap.insert(QLatin1String("para"), &QtXmlToSphinx::handleParaTag);
- m_handlerMap.insert(QLatin1String("italic"), &QtXmlToSphinx::handleItalicTag);
- m_handlerMap.insert(QLatin1String("bold"), &QtXmlToSphinx::handleBoldTag);
- m_handlerMap.insert(QLatin1String("see-also"), &QtXmlToSphinx::handleSeeAlsoTag);
- m_handlerMap.insert(QLatin1String("snippet"), &QtXmlToSphinx::handleSnippetTag);
- m_handlerMap.insert(QLatin1String("dots"), &QtXmlToSphinx::handleDotsTag);
- m_handlerMap.insert(QLatin1String("codeline"), &QtXmlToSphinx::handleDotsTag);
- m_handlerMap.insert(QLatin1String("table"), &QtXmlToSphinx::handleTableTag);
- m_handlerMap.insert(QLatin1String("header"), &QtXmlToSphinx::handleRowTag);
- m_handlerMap.insert(QLatin1String("row"), &QtXmlToSphinx::handleRowTag);
- m_handlerMap.insert(QLatin1String("item"), &QtXmlToSphinx::handleItemTag);
- m_handlerMap.insert(QLatin1String("argument"), &QtXmlToSphinx::handleArgumentTag);
- m_handlerMap.insert(QLatin1String("teletype"), &QtXmlToSphinx::handleArgumentTag);
- m_handlerMap.insert(QLatin1String("link"), &QtXmlToSphinx::handleLinkTag);
- m_handlerMap.insert(QLatin1String("inlineimage"), &QtXmlToSphinx::handleInlineImageTag);
- m_handlerMap.insert(QLatin1String("image"), &QtXmlToSphinx::handleImageTag);
- m_handlerMap.insert(QLatin1String("list"), &QtXmlToSphinx::handleListTag);
- m_handlerMap.insert(QLatin1String("term"), &QtXmlToSphinx::handleTermTag);
- m_handlerMap.insert(QLatin1String("raw"), &QtXmlToSphinx::handleRawTag);
- m_handlerMap.insert(QLatin1String("underline"), &QtXmlToSphinx::handleItalicTag);
- m_handlerMap.insert(QLatin1String("superscript"), &QtXmlToSphinx::handleSuperScriptTag);
- m_handlerMap.insert(QLatin1String("code"), &QtXmlToSphinx::handleCodeTag);
- m_handlerMap.insert(QLatin1String("badcode"), &QtXmlToSphinx::handleCodeTag);
- m_handlerMap.insert(QLatin1String("legalese"), &QtXmlToSphinx::handleCodeTag);
- m_handlerMap.insert(QLatin1String("rst"), &QtXmlToSphinx::handleRstPassTroughTag);
- m_handlerMap.insert(QLatin1String("section"), &QtXmlToSphinx::handleAnchorTag);
- m_handlerMap.insert(QLatin1String("quotefile"), &QtXmlToSphinx::handleQuoteFileTag);
-
- // ignored tags
- m_handlerMap.insert(QLatin1String("generatedlist"), &QtXmlToSphinx::handleIgnoredTag);
- m_handlerMap.insert(QLatin1String("tableofcontents"), &QtXmlToSphinx::handleIgnoredTag);
- m_handlerMap.insert(QLatin1String("quotefromfile"), &QtXmlToSphinx::handleIgnoredTag);
- m_handlerMap.insert(QLatin1String("skipto"), &QtXmlToSphinx::handleIgnoredTag);
- m_handlerMap.insert(QLatin1String("target"), &QtXmlToSphinx::handleTargetTag);
- m_handlerMap.insert(QLatin1String("page"), &QtXmlToSphinx::handlePageTag);
- m_handlerMap.insert(QLatin1String("group"), &QtXmlToSphinx::handlePageTag);
-
- // useless tags
- m_handlerMap.insert(QLatin1String("description"), &QtXmlToSphinx::handleUselessTag);
- m_handlerMap.insert(QLatin1String("definition"), &QtXmlToSphinx::handleUselessTag);
- m_handlerMap.insert(QLatin1String("printuntil"), &QtXmlToSphinx::handleUselessTag);
- m_handlerMap.insert(QLatin1String("relation"), &QtXmlToSphinx::handleUselessTag);
-
- // Doxygen tags
- m_handlerMap.insert(QLatin1String("title"), &QtXmlToSphinx::handleHeadingTag);
- m_handlerMap.insert(QLatin1String("ref"), &QtXmlToSphinx::handleParaTag);
- m_handlerMap.insert(QLatin1String("computeroutput"), &QtXmlToSphinx::handleParaTag);
- m_handlerMap.insert(QLatin1String("detaileddescription"), &QtXmlToSphinx::handleParaTag);
- m_handlerMap.insert(QLatin1String("name"), &QtXmlToSphinx::handleParaTag);
- m_handlerMap.insert(QLatin1String("listitem"), &QtXmlToSphinx::handleItemTag);
- m_handlerMap.insert(QLatin1String("parametername"), &QtXmlToSphinx::handleItemTag);
- m_handlerMap.insert(QLatin1String("parameteritem"), &QtXmlToSphinx::handleItemTag);
- m_handlerMap.insert(QLatin1String("ulink"), &QtXmlToSphinx::handleLinkTag);
- m_handlerMap.insert(QLatin1String("itemizedlist"), &QtXmlToSphinx::handleListTag);
- m_handlerMap.insert(QLatin1String("parameternamelist"), &QtXmlToSphinx::handleListTag);
- m_handlerMap.insert(QLatin1String("parameterlist"), &QtXmlToSphinx::handleListTag);
-
- // Doxygen ignored tags
- m_handlerMap.insert(QLatin1String("highlight"), &QtXmlToSphinx::handleIgnoredTag);
- m_handlerMap.insert(QLatin1String("linebreak"), &QtXmlToSphinx::handleIgnoredTag);
- m_handlerMap.insert(QLatin1String("programlisting"), &QtXmlToSphinx::handleIgnoredTag);
- m_handlerMap.insert(QLatin1String("xreftitle"), &QtXmlToSphinx::handleIgnoredTag);
- m_handlerMap.insert(QLatin1String("sp"), &QtXmlToSphinx::handleIgnoredTag);
- m_handlerMap.insert(QLatin1String("entry"), &QtXmlToSphinx::handleIgnoredTag);
- m_handlerMap.insert(QLatin1String("simplesect"), &QtXmlToSphinx::handleIgnoredTag);
- m_handlerMap.insert(QLatin1String("verbatim"), &QtXmlToSphinx::handleIgnoredTag);
- m_handlerMap.insert(QLatin1String("xrefsect"), &QtXmlToSphinx::handleIgnoredTag);
- m_handlerMap.insert(QLatin1String("xrefdescription"), &QtXmlToSphinx::handleIgnoredTag);
-
- m_result = transform(doc);
-}
-
-void QtXmlToSphinx::pushOutputBuffer()
-{
- auto *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) const
-{
- const int firstDot = function.indexOf(QLatin1Char('.'));
- const AbstractMetaClass *metaClass = nullptr;
- if (firstDot != -1) {
- const QStringRef className = function.leftRef(firstDot);
- const AbstractMetaClassList &classes = m_generator->classes();
- for (const AbstractMetaClass *cls : classes) {
- if (cls->name() == className) {
- metaClass = cls;
- break;
- }
- }
- }
-
- return metaClass
- ? metaClass->typeEntry()->qualifiedTargetLangName()
- + function.right(function.size() - firstDot)
- : function;
-}
-
-QString QtXmlToSphinx::resolveContextForMethod(const QString& methodName) const
-{
- const QStringRef currentClass = m_context.splitRef(QLatin1Char('.')).constLast();
-
- const AbstractMetaClass *metaClass = nullptr;
- const AbstractMetaClassList &classes = m_generator->classes();
- for (const AbstractMetaClass *cls : classes) {
- if (cls->name() == currentClass) {
- metaClass = cls;
- break;
- }
- }
-
- if (metaClass) {
- AbstractMetaFunctionList funcList;
- const AbstractMetaFunctionList &methods = metaClass->queryFunctionsByName(methodName);
- for (AbstractMetaFunction *func : methods) {
- if (methodName == func->name())
- funcList.append(func);
- }
-
- const AbstractMetaClass *implementingClass = nullptr;
- for (AbstractMetaFunction *func : qAsConst(funcList)) {
- implementingClass = func->implementingClass();
- if (implementingClass->name() == currentClass)
- break;
- }
-
- if (implementingClass)
- return implementingClass->typeEntry()->qualifiedTargetLangName();
- }
-
- return QLatin1Char('~') + m_context;
-}
-
-QString QtXmlToSphinx::transform(const QString& doc)
-{
- Q_ASSERT(m_buffers.isEmpty());
- Indentation indentation(INDENT);
- if (doc.trimmed().isEmpty())
- return doc;
-
- pushOutputBuffer();
-
- QXmlStreamReader reader(doc);
-
- while (!reader.atEnd()) {
- QXmlStreamReader::TokenType token = reader.readNext();
- if (reader.hasError()) {
- QString message;
- QTextStream(&message) << "XML Error "
- << reader.errorString() << " at " << reader.lineNumber()
- << ':' << reader.columnNumber() << '\n' << doc;
- m_output << INDENT << message;
- qCWarning(lcShiboken).noquote().nospace() << message;
- break;
- }
-
- if (token == QXmlStreamReader::StartElement) {
- QStringRef tagName = reader.name();
- TagHandler handler = m_handlerMap.value(tagName.toString(), &QtXmlToSphinx::handleUnknownTag);
- if (!m_handlers.isEmpty() && ( (m_handlers.top() == &QtXmlToSphinx::handleIgnoredTag) ||
- (m_handlers.top() == &QtXmlToSphinx::handleRawTag)) )
- handler = &QtXmlToSphinx::handleIgnoredTag;
-
- m_handlers.push(handler);
- }
- if (!m_handlers.isEmpty())
- (this->*(m_handlers.top()))(reader);
-
- if (token == QXmlStreamReader::EndElement) {
- m_handlers.pop();
- m_lastTagName = reader.name().toString();
- }
- }
-
- if (!m_inlineImages.isEmpty()) {
- // Write out inline image definitions stored in handleInlineImageTag().
- m_output << Qt::endl;
- for (const InlineImage &img : qAsConst(m_inlineImages))
- m_output << ".. |" << img.tag << "| image:: " << img.href << Qt::endl;
- m_output << Qt::endl;
- m_inlineImages.clear();
- }
-
- m_output.flush();
- QString retval = popOutputBuffer();
- Q_ASSERT(m_buffers.isEmpty());
- return retval;
-}
-
-static QString resolveFile(const QStringList &locations, const QString &path)
-{
- for (QString location : locations) {
- location.append(QLatin1Char('/'));
- location.append(path);
- if (QFileInfo::exists(location))
- return location;
- }
- return QString();
-}
-
-QString QtXmlToSphinx::readFromLocations(const QStringList &locations, const QString &path,
- const QString &identifier, QString *errorMessage)
-{
- QString resolvedPath;
- if (path.endsWith(QLatin1String(".cpp"))) {
- const QString pySnippet = path.left(path.size() - 3) + QLatin1String("py");
- resolvedPath = resolveFile(locations, pySnippet);
- }
- if (resolvedPath.isEmpty())
- resolvedPath = resolveFile(locations, path);
- if (resolvedPath.isEmpty()) {
- QTextStream(errorMessage) << "Could not resolve \"" << path << "\" in \""
- << locations.join(QLatin1String("\", \""));
- return QString(); // null
- }
- qCDebug(lcShiboken).noquote().nospace() << "snippet file " << path
- << " [" << identifier << ']' << " resolved to " << resolvedPath;
- return readFromLocation(resolvedPath, identifier, errorMessage);
-}
-
-QString QtXmlToSphinx::readFromLocation(const QString &location, const QString &identifier,
- QString *errorMessage)
-{
- QFile inputFile;
- inputFile.setFileName(location);
- if (!inputFile.open(QIODevice::ReadOnly)) {
- QTextStream(errorMessage) << "Could not read code snippet file: "
- << QDir::toNativeSeparators(inputFile.fileName())
- << ": " << inputFile.errorString();
- return QString(); // null
- }
-
- QString code = QLatin1String(""); // non-null
- if (identifier.isEmpty()) {
- while (!inputFile.atEnd())
- code += QString::fromUtf8(inputFile.readLine());
- return code;
- }
-
- const QRegularExpression searchString(QLatin1String("//!\\s*\\[")
- + identifier + QLatin1String("\\]"));
- Q_ASSERT(searchString.isValid());
- static const QRegularExpression codeSnippetCode(QLatin1String("//!\\s*\\[[\\w\\d\\s]+\\]"));
- Q_ASSERT(codeSnippetCode.isValid());
-
- bool getCode = false;
-
- while (!inputFile.atEnd()) {
- QString line = QString::fromUtf8(inputFile.readLine());
- if (getCode && !line.contains(searchString)) {
- line.remove(codeSnippetCode);
- code += line;
- } else if (line.contains(searchString)) {
- if (getCode)
- break;
- getCode = true;
- }
- }
-
- if (!getCode) {
- QTextStream(errorMessage) << "Code snippet file found ("
- << QDir::toNativeSeparators(location) << "), but snippet ["
- << identifier << "] not found.";
- return QString(); // null
- }
-
- return code;
-}
-
-void QtXmlToSphinx::handleHeadingTag(QXmlStreamReader& reader)
-{
- static int headingSize = 0;
- static char type;
- static char types[] = { '-', '^' };
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement) {
- uint typeIdx = reader.attributes().value(QLatin1String("level")).toUInt();
- if (typeIdx >= sizeof(types))
- type = types[sizeof(types)-1];
- else
- type = types[typeIdx];
- } else if (token == QXmlStreamReader::EndElement) {
- m_output << Pad(type, headingSize) << Qt::endl << Qt::endl;
- } else if (token == QXmlStreamReader::Characters) {
- m_output << Qt::endl << Qt::endl;
- headingSize = writeEscapedRstText(m_output, reader.text().trimmed());
- m_output << Qt::endl;
- }
-}
-
-void QtXmlToSphinx::handleParaTag(QXmlStreamReader& reader)
-{
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement) {
- pushOutputBuffer();
- } else if (token == QXmlStreamReader::EndElement) {
- QString result = popOutputBuffer().simplified();
- if (result.startsWith(QLatin1String("**Warning:**")))
- result.replace(0, 12, QLatin1String(".. warning:: "));
- else if (result.startsWith(QLatin1String("**Note:**")))
- result.replace(0, 9, QLatin1String(".. note:: "));
-
- m_output << INDENT << result << Qt::endl << Qt::endl;
- } else if (token == QXmlStreamReader::Characters) {
- const QStringRef text = reader.text();
- const QChar end = lastChar(m_output);
- if (!text.isEmpty() && INDENT.indent == 0 && !end.isNull()) {
- QChar start = text[0];
- if ((end == QLatin1Char('*') || end == QLatin1Char('`')) && start != QLatin1Char(' ') && !start.isPunct())
- m_output << '\\';
- }
- m_output << INDENT << escape(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().trimmed();
-}
-
-static inline QString functionLinkType() { return QStringLiteral("function"); }
-static inline QString classLinkType() { return QStringLiteral("class"); }
-
-static inline QString fixLinkType(const QStringRef &type)
-{
- // TODO: create a flag PROPERTY-AS-FUNCTION to ask if the properties
- // are recognized as such or not in the binding
- if (type == QLatin1String("property"))
- return functionLinkType();
- if (type == QLatin1String("typedef"))
- return classLinkType();
- return type.toString();
-}
-
-static inline QString linkSourceAttribute(const QString &type)
-{
- if (type == functionLinkType() || type == classLinkType())
- return QLatin1String("raw");
- return type == QLatin1String("enum") || type == QLatin1String("page")
- ? type : QLatin1String("href");
-}
-
-// "See also" links may appear as nested links:
-// <see-also>QAbstractXmlReceiver<link raw="isValid()" href="qxmlquery.html#isValid" type="function">isValid()</link>
-// which is handled in handleLinkTag
-// or direct text:
-// <see-also>rootIsDecorated()</see-also>
-// which is handled here.
-
-void QtXmlToSphinx::handleSeeAlsoTag(QXmlStreamReader& reader)
-{
- switch (reader.tokenType()) {
- case QXmlStreamReader::StartElement:
- m_output << INDENT << ".. seealso:: ";
- break;
- case QXmlStreamReader::Characters: {
- // Direct embedded link: <see-also>rootIsDecorated()</see-also>
- const QStringRef textR = reader.text().trimmed();
- if (!textR.isEmpty()) {
- const QString text = textR.toString();
- if (m_seeAlsoContext.isNull()) {
- const QString type = text.endsWith(QLatin1String("()"))
- ? functionLinkType() : classLinkType();
- m_seeAlsoContext.reset(handleLinkStart(type, text));
- }
- handleLinkText(m_seeAlsoContext.data(), text);
- }
- }
- break;
- case QXmlStreamReader::EndElement:
- if (!m_seeAlsoContext.isNull()) { // direct, no nested </link> seen
- handleLinkEnd(m_seeAlsoContext.data());
- m_seeAlsoContext.reset();
- }
- m_output << Qt::endl << Qt::endl;
- break;
- default:
- break;
- }
-}
-
-static inline QString fallbackPathAttribute() { return QStringLiteral("path"); }
-
-static inline bool snippetComparison()
-{
- return ReportHandler::debugLevel() >= ReportHandler::FullDebug;
-}
-
-template <class Indent> // const char*/class Indentor
-void formatSnippet(QTextStream &str, Indent indent, const QString &snippet)
-{
- const QVector<QStringRef> lines = snippet.splitRef(QLatin1Char('\n'));
- for (const QStringRef &line : lines) {
- if (!line.trimmed().isEmpty())
- str << indent << line;
- str << Qt::endl;
- }
-}
-
-static QString msgSnippetComparison(const QString &location, const QString &identifier,
- const QString &pythonCode, const QString &fallbackCode)
-{
- QString result;
- QTextStream str(&result);
- str << "Python snippet " << location;
- if (!identifier.isEmpty())
- str << " [" << identifier << ']';
- str << ":\n";
- formatSnippet(str, " ", pythonCode);
- str << "Corresponding fallback snippet:\n";
- formatSnippet(str, " ", fallbackCode);
- str << "-- end --\n";
- return result;
-}
-
-void QtXmlToSphinx::handleSnippetTag(QXmlStreamReader& reader)
-{
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement) {
- const bool consecutiveSnippet = m_lastTagName == QLatin1String("snippet")
- || m_lastTagName == QLatin1String("dots") || m_lastTagName == QLatin1String("codeline");
- if (consecutiveSnippet) {
- m_output.flush();
- m_output.string()->chop(2);
- }
- QString location = reader.attributes().value(QLatin1String("location")).toString();
- QString identifier = reader.attributes().value(QLatin1String("identifier")).toString();
- QString errorMessage;
- const QString pythonCode =
- readFromLocations(m_generator->codeSnippetDirs(), location, identifier, &errorMessage);
- if (!errorMessage.isEmpty())
- qCWarning(lcShiboken, "%s", qPrintable(msgTagWarning(reader, m_context, m_lastTagName, errorMessage)));
- // Fall back to C++ snippet when "path" attribute is present.
- // Also read fallback snippet when comparison is desired.
- QString fallbackCode;
- if ((pythonCode.isEmpty() || snippetComparison())
- && reader.attributes().hasAttribute(fallbackPathAttribute())) {
- const QString fallback = reader.attributes().value(fallbackPathAttribute()).toString();
- if (QFileInfo::exists(fallback)) {
- if (pythonCode.isEmpty())
- qCWarning(lcShiboken, "%s", qPrintable(msgFallbackWarning(reader, m_context, m_lastTagName, location, identifier, fallback)));
- fallbackCode = readFromLocation(fallback, identifier, &errorMessage);
- if (!errorMessage.isEmpty())
- qCWarning(lcShiboken, "%s", qPrintable(msgTagWarning(reader, m_context, m_lastTagName, errorMessage)));
- }
- }
-
- if (!pythonCode.isEmpty() && !fallbackCode.isEmpty() && snippetComparison())
- qCDebug(lcShiboken, "%s", qPrintable(msgSnippetComparison(location, identifier, pythonCode, fallbackCode)));
-
- if (!consecutiveSnippet)
- m_output << INDENT << "::\n\n";
-
- Indentation indentation(INDENT);
- const QString code = pythonCode.isEmpty() ? fallbackCode : pythonCode;
- if (code.isEmpty())
- m_output << INDENT << "<Code snippet \"" << location << ':' << identifier << "\" not found>\n";
- else
- formatSnippet(m_output, INDENT, code);
- m_output << Qt::endl;
- }
-}
-void QtXmlToSphinx::handleDotsTag(QXmlStreamReader& reader)
-{
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement) {
- const bool consecutiveSnippet = m_lastTagName == QLatin1String("snippet")
- || m_lastTagName == QLatin1String("dots") || m_lastTagName == QLatin1String("codeline");
- if (consecutiveSnippet) {
- m_output.flush();
- m_output.string()->chop(2);
- } else {
- m_output << INDENT << "::\n\n";
- }
- Indentation indentation(INDENT);
- pushOutputBuffer();
- m_output << INDENT;
- int indent = reader.attributes().value(QLatin1String("indent")).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.setHeaderEnabled(m_tableHasHeader);
- m_currentTable.normalize();
- m_output << ensureEndl << m_currentTable;
- m_currentTable.clear();
- }
-}
-
-void QtXmlToSphinx::handleTermTag(QXmlStreamReader& reader)
-{
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement) {
- pushOutputBuffer();
- } else if (token == QXmlStreamReader::Characters) {
- m_output << reader.text().toString().replace(QLatin1String("::"), QLatin1String("."));
- } else if (token == QXmlStreamReader::EndElement) {
- TableCell cell;
- cell.data = popOutputBuffer().trimmed();
- m_currentTable.appendRow(TableRow(1, cell));
- }
-}
-
-
-void QtXmlToSphinx::handleItemTag(QXmlStreamReader& reader)
-{
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement) {
- if (m_currentTable.isEmpty())
- m_currentTable.appendRow({});
- TableRow& row = m_currentTable.last();
- TableCell cell;
- cell.colSpan = reader.attributes().value(QLatin1String("colspan")).toShort();
- cell.rowSpan = reader.attributes().value(QLatin1String("rowspan")).toShort();
- row << cell;
- pushOutputBuffer();
- } else if (token == QXmlStreamReader::EndElement) {
- QString data = popOutputBuffer().trimmed();
- if (!m_currentTable.isEmpty()) {
- TableRow& row = m_currentTable.last();
- if (!row.isEmpty())
- row.last().data = data;
- }
- }
-}
-
-void QtXmlToSphinx::handleRowTag(QXmlStreamReader& reader)
-{
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement) {
- m_tableHasHeader = reader.name() == QLatin1String("header");
- m_currentTable.appendRow({});
- }
-}
-
-enum ListType { BulletList, OrderedList, EnumeratedList };
-
-static inline ListType webXmlListType(const QStringRef &t)
-{
- if (t == QLatin1String("enum"))
- return EnumeratedList;
- if (t == QLatin1String("ordered"))
- return OrderedList;
- return BulletList;
-}
-
-void QtXmlToSphinx::handleListTag(QXmlStreamReader& reader)
-{
- // BUG We do not support a list inside a table cell
- static ListType listType = BulletList;
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement) {
- listType = webXmlListType(reader.attributes().value(QLatin1String("type")));
- if (listType == EnumeratedList) {
- m_currentTable.appendRow(TableRow{TableCell(QLatin1String("Constant")),
- TableCell(QLatin1String("Description"))});
- m_tableHasHeader = true;
- }
- INDENT.indent--;
- } else if (token == QXmlStreamReader::EndElement) {
- INDENT.indent++;
- if (!m_currentTable.isEmpty()) {
- switch (listType) {
- case BulletList:
- case OrderedList: {
- m_output << Qt::endl;
- const char *separator = listType == BulletList ? "* " : "#. ";
- const char *indent = listType == BulletList ? " " : " ";
- for (const TableCell &cell : m_currentTable.constFirst()) {
- const QVector<QStringRef> itemLines = cell.data.splitRef(QLatin1Char('\n'));
- m_output << INDENT << separator << itemLines.constFirst() << Qt::endl;
- for (int i = 1, max = itemLines.count(); i < max; ++i)
- m_output << INDENT << indent << itemLines[i] << Qt::endl;
- }
- m_output << Qt::endl;
- }
- break;
- case EnumeratedList:
- m_currentTable.setHeaderEnabled(m_tableHasHeader);
- m_currentTable.normalize();
- m_output << ensureEndl << m_currentTable;
- break;
- }
- }
- m_currentTable.clear();
- }
-}
-
-void QtXmlToSphinx::handleLinkTag(QXmlStreamReader& reader)
-{
- switch (reader.tokenType()) {
- case QXmlStreamReader::StartElement: {
- // <link> embedded in <see-also> means the characters of <see-also> are no link.
- m_seeAlsoContext.reset();
- const QString type = fixLinkType(reader.attributes().value(QLatin1String("type")));
- const QString ref = reader.attributes().value(linkSourceAttribute(type)).toString();
- m_linkContext.reset(handleLinkStart(type, ref));
- }
- break;
- case QXmlStreamReader::Characters:
- Q_ASSERT(!m_linkContext.isNull());
- handleLinkText(m_linkContext.data(), reader.text().toString());
- break;
- case QXmlStreamReader::EndElement:
- Q_ASSERT(!m_linkContext.isNull());
- handleLinkEnd(m_linkContext.data());
- m_linkContext.reset();
- break;
- default:
- break;
- }
-}
-
-QtXmlToSphinx::LinkContext *QtXmlToSphinx::handleLinkStart(const QString &type, QString ref) const
-{
- ref.replace(QLatin1String("::"), QLatin1String("."));
- ref.remove(QLatin1String("()"));
- auto *result = new LinkContext(ref);
-
- if (m_insideBold)
- result->flags |= LinkContext::InsideBold;
- else if (m_insideItalic)
- result->flags |= LinkContext::InsideItalic;
-
- if (type == functionLinkType() && !m_context.isEmpty()) {
- result->type = LinkContext::Method;
- const QVector<QStringRef> rawlinklist = result->linkRef.splitRef(QLatin1Char('.'));
- if (rawlinklist.size() == 1 || rawlinklist.constFirst() == m_context) {
- QString context = resolveContextForMethod(rawlinklist.constLast().toString());
- if (!result->linkRef.startsWith(context))
- result->linkRef.prepend(context + QLatin1Char('.'));
- } else {
- result->linkRef = expandFunction(result->linkRef);
- }
- } else if (type == functionLinkType() && m_context.isEmpty()) {
- result->type = LinkContext::Function;
- } else if (type == classLinkType()) {
- result->type = LinkContext::Class;
- if (const TypeEntry *type = TypeDatabase::instance()->findType(result->linkRef)) {
- result->linkRef = type->qualifiedTargetLangName();
- } else { // fall back to the old heuristic if the type wasn't found.
- const QVector<QStringRef> rawlinklist = result->linkRef.splitRef(QLatin1Char('.'));
- QStringList splittedContext = m_context.split(QLatin1Char('.'));
- if (rawlinklist.size() == 1 || rawlinklist.constFirst() == splittedContext.constLast()) {
- splittedContext.removeLast();
- result->linkRef.prepend(QLatin1Char('~') + splittedContext.join(QLatin1Char('.'))
- + QLatin1Char('.'));
- }
- }
- } else if (type == QLatin1String("enum")) {
- result->type = LinkContext::Attribute;
- } else if (type == QLatin1String("page")) {
- // Module, external web page or reference
- if (result->linkRef == m_generator->moduleName())
- result->type = LinkContext::Module;
- else if (result->linkRef.startsWith(QLatin1String("http")))
- result->type = LinkContext::External;
- else
- result->type = LinkContext::Reference;
- } else if (type == QLatin1String("external")) {
- result->type = LinkContext::External;
- } else {
- result->type = LinkContext::Reference;
- }
- return result;
-}
-
-// <link raw="Model/View Classes" href="model-view-programming.html#model-view-classes"
-// type="page" page="Model/View Programming">Model/View Classes</link>
-// <link type="page" page="http://doc.qt.io/qt-5/class.html">QML types</link>
-// <link raw="Qt Quick" href="qtquick-index.html" type="page" page="Qt Quick">Qt Quick</link>
-// <link raw="QObject" href="qobject.html" type="class">QObject</link>
-// <link raw="Qt::Window" href="qt.html#WindowType-enum" type="enum" enum="Qt::WindowType">Qt::Window</link>
-// <link raw="QNetworkSession::reject()" href="qnetworksession.html#reject" type="function">QNetworkSession::reject()</link>
-
-static QString fixLinkText(const QtXmlToSphinx::LinkContext *linkContext,
- QString linktext)
-{
- if (linkContext->type == QtXmlToSphinx::LinkContext::External
- || linkContext->type == QtXmlToSphinx::LinkContext::Reference) {
- return linktext;
- }
- // For the language reference documentation, strip the module name.
- // Clear the link text if that matches the function/class/enumeration name.
- const int lastSep = linktext.lastIndexOf(QLatin1String("::"));
- if (lastSep != -1)
- linktext.remove(0, lastSep + 2);
- else
- stripPythonQualifiers(&linktext);
- if (linkContext->linkRef == linktext)
- return QString();
- if ((linkContext->type & QtXmlToSphinx::LinkContext::FunctionMask) != 0
- && (linkContext->linkRef + QLatin1String("()")) == linktext) {
- return QString();
- }
- return linktext;
-}
-
-void QtXmlToSphinx::handleLinkText(LinkContext *linkContext, const QString &linktext) const
-{
- linkContext->linkText = fixLinkText(linkContext, linktext);
-}
-
-void QtXmlToSphinx::handleLinkEnd(LinkContext *linkContext)
-{
- m_output << *linkContext;
-}
-
-// Copy images that are placed in a subdirectory "images" under the webxml files
-// by qdoc to a matching subdirectory under the "rst/PySide2/<module>" directory
-static bool copyImage(const QString &href, const QString &docDataDir,
- const QString &context, const QString &outputDir,
- QString *errorMessage)
-{
- const QChar slash = QLatin1Char('/');
- const int lastSlash = href.lastIndexOf(slash);
- const QString imagePath = lastSlash != -1 ? href.left(lastSlash) : QString();
- const QString imageFileName = lastSlash != -1 ? href.right(href.size() - lastSlash - 1) : href;
- QFileInfo imageSource(docDataDir + slash + href);
- if (!imageSource.exists()) {
- QTextStream(errorMessage) << "Image " << href << " does not exist in "
- << QDir::toNativeSeparators(docDataDir);
- return false;
- }
- // Determine directory from context, "Pyside2.QtGui.QPainter" ->"Pyside2/QtGui".
- // FIXME: Not perfect yet, should have knowledge about namespaces (DataVis3D) or
- // nested classes "Pyside2.QtGui.QTouchEvent.QTouchPoint".
- QString relativeTargetDir = context;
- const int lastDot = relativeTargetDir.lastIndexOf(QLatin1Char('.'));
- if (lastDot != -1)
- relativeTargetDir.truncate(lastDot);
- relativeTargetDir.replace(QLatin1Char('.'), slash);
- if (!imagePath.isEmpty())
- relativeTargetDir += slash + imagePath;
-
- const QString targetDir = outputDir + slash + relativeTargetDir;
- const QString targetFileName = targetDir + slash + imageFileName;
- if (QFileInfo::exists(targetFileName))
- return true;
- if (!QFileInfo::exists(targetDir)) {
- const QDir outDir(outputDir);
- if (!outDir.mkpath(relativeTargetDir)) {
- QTextStream(errorMessage) << "Cannot create " << QDir::toNativeSeparators(relativeTargetDir)
- << " under " << QDir::toNativeSeparators(outputDir);
- return false;
- }
- }
-
- QFile source(imageSource.absoluteFilePath());
- if (!source.copy(targetFileName)) {
- QTextStream(errorMessage) << "Cannot copy " << QDir::toNativeSeparators(source.fileName())
- << " to " << QDir::toNativeSeparators(targetFileName) << ": "
- << source.errorString();
- return false;
- }
- qCDebug(lcShiboken()).noquote().nospace() << __FUNCTION__ << " href=\""
- << href << "\", context=\"" << context << "\", docDataDir=\""
- << docDataDir << "\", outputDir=\"" << outputDir << "\", copied \""
- << source.fileName() << "\"->\"" << targetFileName << '"';
- return true;
-}
-
-bool QtXmlToSphinx::copyImage(const QString &href) const
-{
- QString errorMessage;
- const bool result =
- ::copyImage(href, m_generator->docDataDir(), m_context,
- m_generator->outputDirectory(), &errorMessage);
- if (!result)
- qCWarning(lcShiboken, "%s", qPrintable(errorMessage));
- return result;
-}
-
-void QtXmlToSphinx::handleImageTag(QXmlStreamReader& reader)
-{
- if (reader.tokenType() != QXmlStreamReader::StartElement)
- return;
- const QString href = reader.attributes().value(QLatin1String("href")).toString();
- if (copyImage(href))
- m_output << INDENT << ".. image:: " << href << Qt::endl << Qt::endl;
-}
-
-void QtXmlToSphinx::handleInlineImageTag(QXmlStreamReader& reader)
-{
- if (reader.tokenType() != QXmlStreamReader::StartElement)
- return;
- const QString href = reader.attributes().value(QLatin1String("href")).toString();
- if (!copyImage(href))
- return;
- // Handle inline images by substitution references. Insert a unique tag
- // enclosed by '|' and define it further down. Determine tag from the base
- //file name with number.
- QString tag = href;
- int pos = tag.lastIndexOf(QLatin1Char('/'));
- if (pos != -1)
- tag.remove(0, pos + 1);
- pos = tag.indexOf(QLatin1Char('.'));
- if (pos != -1)
- tag.truncate(pos);
- tag += QString::number(m_inlineImages.size() + 1);
- m_inlineImages.append(InlineImage{tag, href});
- m_output << '|' << tag << '|' << ' ';
-}
-
-void QtXmlToSphinx::handleRawTag(QXmlStreamReader& reader)
-{
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement) {
- QString format = reader.attributes().value(QLatin1String("format")).toString();
- m_output << INDENT << ".. raw:: " << format.toLower() << Qt::endl << Qt::endl;
- } else if (token == QXmlStreamReader::Characters) {
- const QVector<QStringRef> lst(reader.text().split(QLatin1Char('\n')));
- for (const QStringRef &row : lst)
- m_output << INDENT << INDENT << row << Qt::endl;
- } else if (token == QXmlStreamReader::EndElement) {
- m_output << Qt::endl << Qt::endl;
- }
-}
-
-void QtXmlToSphinx::handleCodeTag(QXmlStreamReader& reader)
-{
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement) {
- m_output << INDENT << "::\n\n";
- INDENT.indent++;
- } else if (token == QXmlStreamReader::Characters) {
- const QVector<QStringRef> lst(reader.text().split(QLatin1Char('\n')));
- for (const QStringRef &row : lst)
- m_output << INDENT << INDENT << row << Qt::endl;
- } else if (token == QXmlStreamReader::EndElement) {
- m_output << Qt::endl << Qt::endl;
- INDENT.indent--;
- }
-}
-
-void QtXmlToSphinx::handleUnknownTag(QXmlStreamReader& reader)
-{
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement)
- qCDebug(lcShiboken).noquote().nospace() << "Unknown QtDoc tag: \"" << reader.name().toString() << "\".";
-}
-
-void QtXmlToSphinx::handleSuperScriptTag(QXmlStreamReader& reader)
-{
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement) {
- m_output << " :sup:`";
- pushOutputBuffer();
- } else if (token == QXmlStreamReader::Characters) {
- m_output << reader.text().toString();
- } else if (token == QXmlStreamReader::EndElement) {
- m_output << popOutputBuffer();
- m_output << '`';
- }
-}
-
-void QtXmlToSphinx::handlePageTag(QXmlStreamReader &reader)
-{
- if (reader.tokenType() != QXmlStreamReader::StartElement)
- return;
-
- const QStringRef title = reader.attributes().value(titleAttribute());
- if (!title.isEmpty())
- m_output << rstLabel(title.toString());
-
- const QStringRef fullTitle = reader.attributes().value(fullTitleAttribute());
- const int size = fullTitle.isEmpty()
- ? writeEscapedRstText(m_output, title)
- : writeEscapedRstText(m_output, fullTitle);
-
- m_output << Qt::endl << Pad('*', size) << Qt::endl << Qt::endl;
-}
-
-void QtXmlToSphinx::handleTargetTag(QXmlStreamReader &reader)
-{
- if (reader.tokenType() != QXmlStreamReader::StartElement)
- return;
- const QStringRef name = reader.attributes().value(nameAttribute());
- if (!name.isEmpty())
- m_output << INDENT << rstLabel(name.toString());
-}
-
-void QtXmlToSphinx::handleIgnoredTag(QXmlStreamReader&)
-{
-}
-
-void QtXmlToSphinx::handleUselessTag(QXmlStreamReader&)
-{
- // Tag "description" just marks the init of "Detailed description" title.
- // Tag "definition" just marks enums. We have a different way to process them.
-}
-
-void QtXmlToSphinx::handleAnchorTag(QXmlStreamReader& reader)
-{
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement) {
- QString anchor;
- if (reader.attributes().hasAttribute(QLatin1String("id")))
- anchor = reader.attributes().value(QLatin1String("id")).toString();
- else if (reader.attributes().hasAttribute(QLatin1String("name")))
- anchor = reader.attributes().value(QLatin1String("name")).toString();
- if (!anchor.isEmpty() && m_opened_anchor != anchor) {
- m_opened_anchor = anchor;
- if (!m_context.isEmpty())
- anchor.prepend(m_context + QLatin1Char('_'));
- m_output << INDENT << rstLabel(anchor);
- }
- } else if (token == QXmlStreamReader::EndElement) {
- m_opened_anchor.clear();
- }
-}
-
-void QtXmlToSphinx::handleRstPassTroughTag(QXmlStreamReader& reader)
-{
- if (reader.tokenType() == QXmlStreamReader::Characters)
- m_output << reader.text();
-}
-
-void QtXmlToSphinx::handleQuoteFileTag(QXmlStreamReader& reader)
-{
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::Characters) {
- QString location = reader.text().toString();
- location.prepend(m_generator->libSourceDir() + QLatin1Char('/'));
- QString errorMessage;
- QString code = readFromLocation(location, QString(), &errorMessage);
- if (!errorMessage.isEmpty())
- qCWarning(lcShiboken(), "%s", qPrintable(msgTagWarning(reader, m_context, m_lastTagName, errorMessage)));
- m_output << INDENT << "::\n\n";
- Indentation indentation(INDENT);
- if (code.isEmpty())
- m_output << INDENT << "<Code snippet \"" << location << "\" not found>\n";
- else
- formatCode(m_output, code, INDENT);
- m_output << Qt::endl;
- }
-}
-
-bool QtXmlToSphinx::convertToRst(QtDocGenerator *generator,
- const QString &sourceFileName,
- const QString &targetFileName,
- const QString &context, QString *errorMessage)
-{
- QFile sourceFile(sourceFileName);
- if (!sourceFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
- if (errorMessage)
- *errorMessage = msgCannotOpenForReading(sourceFile);
- return false;
- }
- const QString doc = QString::fromUtf8(sourceFile.readAll());
- sourceFile.close();
-
- FileOut targetFile(targetFileName);
- QtXmlToSphinx x(generator, doc, context);
- targetFile.stream << x;
- return targetFile.done(errorMessage) != FileOut::Failure;
-}
-
-void QtXmlToSphinx::Table::normalize()
-{
- if (m_normalized || isEmpty())
- return;
-
- //QDoc3 generates tables with wrong number of columns. We have to
- //check and if necessary, merge the last columns.
- int maxCols = -1;
- for (const auto &row : qAsConst(m_rows)) {
- if (row.count() > maxCols)
- maxCols = row.count();
- }
- if (maxCols <= 0)
- return;
- // add col spans
- for (int row = 0; row < m_rows.count(); ++row) {
- for (int col = 0; col < m_rows.at(row).count(); ++col) {
- QtXmlToSphinx::TableCell& cell = m_rows[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) {
- m_rows[row].insert(col + 1, newCell);
- }
- cell.colSpan = 0;
- col++;
- } else if (mergeCols) {
- m_rows[row][maxCols - 1].data += QLatin1Char(' ') + cell.data;
- }
- }
- }
-
- // row spans
- const int numCols = m_rows.constFirst().count();
- for (int col = 0; col < numCols; ++col) {
- for (int row = 0; row < m_rows.count(); ++row) {
- if (col < m_rows[row].count()) {
- QtXmlToSphinx::TableCell& cell = m_rows[row][col];
- if (cell.rowSpan > 0) {
- QtXmlToSphinx::TableCell newCell;
- newCell.rowSpan = -1;
- int targetRow = row + 1;
- const int targetEndRow =
- std::min(targetRow + cell.rowSpan - 1, m_rows.count());
- cell.rowSpan = 0;
- for ( ; targetRow < targetEndRow; ++targetRow)
- m_rows[targetRow].insert(col, newCell);
- row++;
- }
- }
- }
- }
- m_normalized = true;
-}
-
-QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table)
-{
- table.format(s);
- return s;
-}
-
-void QtXmlToSphinx::Table::format (QTextStream& s) const
-{
- if (isEmpty())
- return;
-
- if (!isNormalized()) {
- qCDebug(lcShiboken) << "Attempt to print an unnormalized table!";
- return;
- }
-
- // calc width and height of each column and row
- const int headerColumnCount = m_rows.constFirst().count();
- QVector<int> colWidths(headerColumnCount);
- QVector<int> rowHeights(m_rows.count());
- for (int i = 0, maxI = m_rows.count(); i < maxI; ++i) {
- const QtXmlToSphinx::TableRow& row = m_rows.at(i);
- for (int j = 0, maxJ = std::min(row.count(), colWidths.size()); j < maxJ; ++j) {
- const QVector<QStringRef> rowLines = row[j].data.splitRef(QLatin1Char('\n')); // cache this would be a good idea
- for (const QStringRef &str : rowLines)
- colWidths[j] = std::max(colWidths[j], str.count());
- rowHeights[i] = std::max(rowHeights[i], row[j].data.count(QLatin1Char('\n')) + 1);
- }
- }
-
- if (!*std::max_element(colWidths.begin(), colWidths.end()))
- return; // empty table (table with empty cells)
-
- // create a horizontal line to be used later.
- QString horizontalLine = QLatin1String("+");
- for (int i = 0, max = colWidths.count(); i < max; ++i) {
- horizontalLine += QString(colWidths.at(i), QLatin1Char('-'));
- horizontalLine += QLatin1Char('+');
- }
-
- // write table rows
- for (int i = 0, maxI = m_rows.count(); i < maxI; ++i) { // for each row
- const QtXmlToSphinx::TableRow& row = m_rows.at(i);
-
- // print line
- s << INDENT << '+';
- for (int col = 0; col < headerColumnCount; ++col) {
- char c;
- if (col >= row.length() || row[col].rowSpan == -1)
- c = ' ';
- else if (i == 1 && hasHeader())
- c = '=';
- else
- c = '-';
- s << Pad(c, colWidths.at(col)) << '+';
- }
- s << Qt::endl;
-
-
- // Print the table cells
- for (int rowLine = 0; rowLine < rowHeights[i]; ++rowLine) { // for each line in a row
- int j = 0;
- for (int maxJ = std::min(row.count(), headerColumnCount); j < maxJ; ++j) { // for each column
- const QtXmlToSphinx::TableCell& cell = row[j];
- const QVector<QStringRef> rowLines = cell.data.splitRef(QLatin1Char('\n')); // FIXME: Cache this!!!
- if (!j) // First column, so we need print the identation
- s << INDENT;
-
- if (!j || !cell.colSpan)
- s << '|';
- else
- s << ' ';
- if (rowLine < rowLines.count())
- s << qSetFieldWidth(colWidths[j]) << Qt::left << rowLines.at(rowLine) << qSetFieldWidth(0);
- else
- s << Pad(' ', colWidths.at(j));
- }
- for ( ; j < headerColumnCount; ++j) // pad
- s << '|' << Pad(' ', colWidths.at(j));
- s << "|\n";
- }
- }
- s << INDENT << horizontalLine << Qt::endl << Qt::endl;
-}
-
-static QString getFuncName(const AbstractMetaFunction* cppFunc) {
- static bool hashInitialized = false;
- static QHash<QString, QString> operatorsHash;
- if (!hashInitialized) {
- operatorsHash.insert(QLatin1String("operator+"), QLatin1String("__add__"));
- operatorsHash.insert(QLatin1String("operator+="), QLatin1String("__iadd__"));
- operatorsHash.insert(QLatin1String("operator-"), QLatin1String("__sub__"));
- operatorsHash.insert(QLatin1String("operator-="), QLatin1String("__isub__"));
- operatorsHash.insert(QLatin1String("operator*"), QLatin1String("__mul__"));
- operatorsHash.insert(QLatin1String("operator*="), QLatin1String("__imul__"));
- operatorsHash.insert(QLatin1String("operator/"), QLatin1String("__div__"));
- operatorsHash.insert(QLatin1String("operator/="), QLatin1String("__idiv__"));
- operatorsHash.insert(QLatin1String("operator%"), QLatin1String("__mod__"));
- operatorsHash.insert(QLatin1String("operator%="), QLatin1String("__imod__"));
- operatorsHash.insert(QLatin1String("operator<<"), QLatin1String("__lshift__"));
- operatorsHash.insert(QLatin1String("operator<<="), QLatin1String("__ilshift__"));
- operatorsHash.insert(QLatin1String("operator>>"), QLatin1String("__rshift__"));
- operatorsHash.insert(QLatin1String("operator>>="), QLatin1String("__irshift__"));
- operatorsHash.insert(QLatin1String("operator&"), QLatin1String("__and__"));
- operatorsHash.insert(QLatin1String("operator&="), QLatin1String("__iand__"));
- operatorsHash.insert(QLatin1String("operator|"), QLatin1String("__or__"));
- operatorsHash.insert(QLatin1String("operator|="), QLatin1String("__ior__"));
- operatorsHash.insert(QLatin1String("operator^"), QLatin1String("__xor__"));
- operatorsHash.insert(QLatin1String("operator^="), QLatin1String("__ixor__"));
- operatorsHash.insert(QLatin1String("operator=="), QLatin1String("__eq__"));
- operatorsHash.insert(QLatin1String("operator!="), QLatin1String("__ne__"));
- operatorsHash.insert(QLatin1String("operator<"), QLatin1String("__lt__"));
- operatorsHash.insert(QLatin1String("operator<="), QLatin1String("__le__"));
- operatorsHash.insert(QLatin1String("operator>"), QLatin1String("__gt__"));
- operatorsHash.insert(QLatin1String("operator>="), QLatin1String("__ge__"));
- hashInitialized = true;
- }
-
- QHash<QString, QString>::const_iterator it = operatorsHash.constFind(cppFunc->name());
- QString result = it != operatorsHash.cend() ? it.value() : cppFunc->name();
- result.replace(QLatin1String("::"), QLatin1String("."));
- return result;
-}
-
-QtDocGenerator::QtDocGenerator() : m_docParser(nullptr)
-{
-}
-
-QtDocGenerator::~QtDocGenerator()
-{
- delete m_docParser;
-}
-
-QString QtDocGenerator::fileNameSuffix() const
-{
- return QLatin1String(".rst");
-}
-
-bool QtDocGenerator::shouldGenerate(const AbstractMetaClass *cls) const
-{
- return Generator::shouldGenerate(cls)
- && cls->typeEntry()->type() != TypeEntry::SmartPointerType;
-}
-
-QString QtDocGenerator::fileNameForContext(GeneratorContext &context) const
-{
- const AbstractMetaClass *metaClass = context.metaClass();
- if (!context.forSmartPointer()) {
- return getClassTargetFullName(metaClass, false) + fileNameSuffix();
- }
- const AbstractMetaType *smartPointerType = context.preciseType();
- QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass);
- return fileNameBase + fileNameSuffix();
-}
-
-void QtDocGenerator::writeFormattedText(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 {
- const QString &value = doc.value();
- const QVector<QStringRef> lines = value.splitRef(QLatin1Char('\n'));
- int typesystemIndentation = std::numeric_limits<int>::max();
- // check how many spaces must be removed from the beginning of each line
- for (const QStringRef &line : lines) {
- const auto it = std::find_if(line.cbegin(), line.cend(),
- [] (QChar c) { return !c.isSpace(); });
- if (it != line.cend())
- typesystemIndentation = qMin(typesystemIndentation, int(it - line.cbegin()));
- }
- if (typesystemIndentation == std::numeric_limits<int>::max())
- typesystemIndentation = 0;
- for (const QStringRef &line : lines) {
- s << INDENT
- << (typesystemIndentation > 0 && typesystemIndentation < line.size()
- ? line.right(line.size() - typesystemIndentation) : line)
- << Qt::endl;
- }
- }
-
- s << Qt::endl;
-}
-
-static void writeInheritedByList(QTextStream& s, const AbstractMetaClass* metaClass, const AbstractMetaClassList& allClasses)
-{
- AbstractMetaClassList res;
- for (AbstractMetaClass *c : allClasses) {
- if (c != metaClass && c->inheritsFrom(metaClass))
- res << c;
- }
-
- if (res.isEmpty())
- return;
-
- s << "**Inherited by:** ";
- QStringList classes;
- for (AbstractMetaClass *c : qAsConst(res))
- classes << QLatin1String(":ref:`") + getClassTargetFullName(c, false) + QLatin1Char('`');
- s << classes.join(QLatin1String(", ")) << Qt::endl << Qt::endl;
-}
-
-// Extract the <brief> section from a WebXML (class) documentation and remove it
-// from the source.
-static bool extractBrief(Documentation *sourceDoc, Documentation *brief)
-{
- if (sourceDoc->format() != Documentation::Native)
- return false;
- QString value = sourceDoc->value();
- const int briefStart = value.indexOf(briefStartElement());
- if (briefStart < 0)
- return false;
- const int briefEnd = value.indexOf(briefEndElement(), briefStart + briefStartElement().size());
- if (briefEnd < briefStart)
- return false;
- const int briefLength = briefEnd + briefEndElement().size() - briefStart;
- brief->setFormat(Documentation::Native);
- QString briefValue = value.mid(briefStart, briefLength);
- briefValue.insert(briefValue.size() - briefEndElement().size(),
- QLatin1String("<rst> More_...</rst>"));
- brief->setValue(briefValue);
- value.remove(briefStart, briefLength);
- sourceDoc->setValue(value);
- return true;
-}
-
-void QtDocGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
-{
- AbstractMetaClass *metaClass = classContext.metaClass();
- qCDebug(lcShiboken).noquote().nospace() << "Generating Documentation for " << metaClass->fullName();
-
- m_packages[metaClass->package()] << fileNameForContext(classContext);
-
- m_docParser->setPackageName(metaClass->package());
- m_docParser->fillDocumentation(const_cast<AbstractMetaClass*>(metaClass));
-
- s << ".. currentmodule:: " << metaClass->package() << Qt::endl;
- QString className = getClassTargetFullName(metaClass, false);
- s << ".. _" << className << ":\n\n";
-
- s << className << Qt::endl;
- s << Pad('*', className.count()) << Qt::endl << Qt::endl;
-
- auto documentation = metaClass->documentation();
- Documentation brief;
- if (extractBrief(&documentation, &brief))
- writeFormattedText(s, brief, metaClass);
-
- s << ".. inheritance-diagram:: " << getClassTargetFullName(metaClass, true) << Qt::endl
- << " :parts: 2\n\n"; // TODO: This would be a parameter in the future...
-
-
- writeInheritedByList(s, metaClass, classes());
-
- const auto version = versionOf(metaClass->typeEntry());
- if (!version.isNull())
- s << rstVersionAdded(version);
- if (metaClass->attributes().testFlag(AbstractMetaAttributes::Deprecated))
- s << rstDeprecationNote("class");
-
- writeFunctionList(s, metaClass);
-
- //Function list
- AbstractMetaFunctionList functionList = metaClass->functions();
- std::sort(functionList.begin(), functionList.end(), functionSort);
-
- s << "\nDetailed Description\n"
- "--------------------\n\n"
- << ".. _More:\n";
-
- writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, metaClass, nullptr);
- if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, metaClass, nullptr))
- writeFormattedText(s, documentation, metaClass);
-
- if (!metaClass->isNamespace())
- writeConstructors(s, metaClass);
- writeEnums(s, metaClass);
- if (!metaClass->isNamespace())
- writeFields(s, metaClass);
-
-
- for (AbstractMetaFunction *func : qAsConst(functionList)) {
- if (shouldSkip(func))
- continue;
-
- if (func->isStatic())
- s << ".. staticmethod:: ";
- else
- s << ".. method:: ";
-
- writeFunction(s, metaClass, func);
- }
-
- writeInjectDocumentation(s, TypeSystem::DocModificationAppend, metaClass, nullptr);
-}
-
-void QtDocGenerator::writeFunctionList(QTextStream& s, const AbstractMetaClass* cppClass)
-{
- QStringList functionList;
- QStringList virtualList;
- QStringList signalList;
- QStringList slotList;
- QStringList staticFunctionList;
-
- const AbstractMetaFunctionList &classFunctions = cppClass->functions();
- for (AbstractMetaFunction *func : classFunctions) {
- if (shouldSkip(func))
- continue;
-
- QString className;
- if (!func->isConstructor())
- className = getClassTargetFullName(cppClass) + QLatin1Char('.');
- else if (func->implementingClass() && func->implementingClass()->enclosingClass())
- className = getClassTargetFullName(func->implementingClass()->enclosingClass()) + QLatin1Char('.');
- QString funcName = getFuncName(func);
-
- QString str = QLatin1String("def :meth:`");
-
- str += funcName;
- str += QLatin1Char('<');
- if (!funcName.startsWith(className))
- str += className;
- str += funcName;
- str += QLatin1String(">` (");
- str += parseArgDocStyle(cppClass, func);
- str += QLatin1Char(')');
-
- if (func->isStatic())
- staticFunctionList << str;
- else if (func->isVirtual())
- virtualList << str;
- else if (func->isSignal())
- signalList << str;
- else if (func->isSlot())
- slotList << str;
- else
- functionList << str;
- }
-
- if (!functionList.isEmpty() || !staticFunctionList.isEmpty()) {
- QtXmlToSphinx::Table functionTable;
-
- s << "\nSynopsis\n--------\n\n";
-
- writeFunctionBlock(s, QLatin1String("Functions"), functionList);
- writeFunctionBlock(s, QLatin1String("Virtual functions"), virtualList);
- writeFunctionBlock(s, QLatin1String("Slots"), slotList);
- writeFunctionBlock(s, QLatin1String("Signals"), signalList);
- writeFunctionBlock(s, QLatin1String("Static functions"), staticFunctionList);
- }
-}
-
-void QtDocGenerator::writeFunctionBlock(QTextStream& s, const QString& title, QStringList& functions)
-{
- if (!functions.isEmpty()) {
- s << title << Qt::endl
- << QString(title.size(), QLatin1Char('^')) << Qt::endl;
-
- std::sort(functions.begin(), functions.end());
-
- s << ".. container:: function_list\n\n";
- Indentation indentation(INDENT);
- for (const QString &func : qAsConst(functions))
- s << INDENT << '*' << ' ' << func << Qt::endl;
-
- s << Qt::endl << Qt::endl;
- }
-}
-
-void QtDocGenerator::writeEnums(QTextStream& s, const AbstractMetaClass* cppClass)
-{
- static const QString section_title = QLatin1String(".. attribute:: ");
-
- const AbstractMetaEnumList &enums = cppClass->enums();
- for (AbstractMetaEnum *en : enums) {
- s << section_title << getClassTargetFullName(cppClass) << '.' << en->name() << Qt::endl << Qt::endl;
- writeFormattedText(s, en->documentation(), cppClass);
- const auto version = versionOf(en->typeEntry());
- if (!version.isNull())
- s << rstVersionAdded(version);
- }
-
-}
-
-void QtDocGenerator::writeFields(QTextStream& s, const AbstractMetaClass* cppClass)
-{
- static const QString section_title = QLatin1String(".. attribute:: ");
-
- const AbstractMetaFieldList &fields = cppClass->fields();
- for (AbstractMetaField *field : fields) {
- s << section_title << getClassTargetFullName(cppClass) << "." << field->name() << Qt::endl << Qt::endl;
- //TODO: request for member ‘documentation’ is ambiguous
- writeFormattedText(s, field->AbstractMetaAttributes::documentation(), cppClass);
- }
-}
-
-void QtDocGenerator::writeConstructors(QTextStream& s, const AbstractMetaClass* cppClass)
-{
- static const QString sectionTitle = QLatin1String(".. class:: ");
-
- AbstractMetaFunctionList lst = cppClass->queryFunctions(AbstractMetaClass::Constructors | AbstractMetaClass::Visible);
- for (int i = lst.size() - 1; i >= 0; --i) {
- if (lst.at(i)->isModifiedRemoved() || lst.at(i)->functionType() == AbstractMetaFunction::MoveConstructorFunction)
- lst.removeAt(i);
- }
-
- bool first = true;
- QHash<QString, AbstractMetaArgument*> arg_map;
-
- IndentorBase<1> indent1;
- indent1.indent = INDENT.total();
- for (AbstractMetaFunction *func : qAsConst(lst)) {
- s << indent1;
- if (first) {
- first = false;
- s << sectionTitle;
- indent1.indent += sectionTitle.size();
- }
- s << functionSignature(cppClass, func) << "\n\n";
-
- const auto version = versionOf(func->typeEntry());
- if (!version.isNull())
- s << indent1 << rstVersionAdded(version);
- if (func->attributes().testFlag(AbstractMetaAttributes::Deprecated))
- s << indent1 << rstDeprecationNote("constructor");
-
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (AbstractMetaArgument *arg : arguments) {
- if (!arg_map.contains(arg->name())) {
- arg_map.insert(arg->name(), arg);
- }
- }
- }
-
- s << Qt::endl;
-
- for (QHash<QString, AbstractMetaArgument*>::const_iterator it = arg_map.cbegin(), end = arg_map.cend(); it != end; ++it) {
- Indentation indentation(INDENT, 2);
- writeParameterType(s, cppClass, it.value());
- }
-
- s << Qt::endl;
-
- for (AbstractMetaFunction *func : qAsConst(lst))
- writeFormattedText(s, func->documentation(), cppClass);
-}
-
-QString QtDocGenerator::parseArgDocStyle(const AbstractMetaClass* /* cppClass */,
- const AbstractMetaFunction* func)
-{
- QString ret;
- int optArgs = 0;
-
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (AbstractMetaArgument *arg : arguments) {
-
- if (func->argumentRemoved(arg->argumentIndex() + 1))
- continue;
-
- bool thisIsoptional = !arg->defaultValueExpression().isEmpty();
- if (optArgs || thisIsoptional) {
- ret += QLatin1Char('[');
- optArgs++;
- }
-
- if (arg->argumentIndex() > 0)
- ret += QLatin1String(", ");
-
- ret += arg->name();
-
- if (thisIsoptional) {
- QString defValue = arg->defaultValueExpression();
- if (defValue == QLatin1String("QString()")) {
- defValue = QLatin1String("\"\"");
- } else if (defValue == QLatin1String("QStringList()")
- || defValue.startsWith(QLatin1String("QVector"))
- || defValue.startsWith(QLatin1String("QList"))) {
- defValue = QLatin1String("list()");
- } else if (defValue == QLatin1String("QVariant()")) {
- defValue = none();
- } else {
- defValue.replace(QLatin1String("::"), QLatin1String("."));
- if (defValue == QLatin1String("nullptr"))
- defValue = none();
- else if (defValue == QLatin1String("0") && arg->type()->isObject())
- defValue = none();
- }
- ret += QLatin1Char('=') + defValue;
- }
- }
-
- ret += QString(optArgs, QLatin1Char(']'));
- return ret;
-}
-
-void QtDocGenerator::writeDocSnips(QTextStream &s,
- const CodeSnipList &codeSnips,
- TypeSystem::CodeSnipPosition position,
- TypeSystem::Language language)
-{
- Indentation indentation(INDENT);
- QStringList invalidStrings;
- const static QString startMarkup = QLatin1String("[sphinx-begin]");
- const static QString endMarkup = QLatin1String("[sphinx-end]");
-
- invalidStrings << QLatin1String("*") << QLatin1String("//") << QLatin1String("/*") << QLatin1String("*/");
-
- for (const 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);
- const QStringList rows = codeBlock.split(QLatin1Char('\n'));
- int currentRow = 0;
- int offset = 0;
-
- for (QString row : rows) {
- for (const QString &invalidString : qAsConst(invalidStrings))
- row.remove(invalidString);
-
- if (row.trimmed().size() == 0) {
- if (currentRow == 0)
- continue;
- s << Qt::endl;
- }
-
- if (currentRow == 0) {
- //find offset
- for (auto c : row) {
- if (c == QLatin1Char(' '))
- offset++;
- else if (c == QLatin1Char('\n'))
- offset = 0;
- else
- break;
- }
- }
- s << row.midRef(offset) << Qt::endl;
- currentRow++;
- }
-
- code = code.mid(endBlock+endMarkup.size());
- }
- }
-}
-
-bool QtDocGenerator::writeInjectDocumentation(QTextStream& s,
- TypeSystem::DocModificationMode mode,
- const AbstractMetaClass* cppClass,
- const AbstractMetaFunction* func)
-{
- Indentation indentation(INDENT);
- bool didSomething = false;
-
- const DocModificationList &mods = cppClass->typeEntry()->docModifications();
- for (const DocModification &mod : mods) {
- 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);
- writeFormattedText(s, doc, cppClass);
- didSomething = true;
- }
- }
- }
-
- s << Qt::endl;
-
- // TODO: Deprecate the use of doc string on glue code.
- // This is pre "add-function" and "inject-documentation" tags.
- const TypeSystem::CodeSnipPosition pos = mode == TypeSystem::DocModificationPrepend
- ? TypeSystem::CodeSnipPositionBeginning : TypeSystem::CodeSnipPositionEnd;
- if (func)
- writeDocSnips(s, func->injectedCodeSnips(), pos, TypeSystem::TargetLangCode);
- else
- writeDocSnips(s, cppClass->typeEntry()->codeSnips(), pos, TypeSystem::TargetLangCode);
- return didSomething;
-}
-
-QString QtDocGenerator::functionSignature(const AbstractMetaClass* cppClass, const AbstractMetaFunction* func)
-{
- QString className;
- if (!func->isConstructor())
- className = getClassTargetFullName(cppClass) + QLatin1Char('.');
- else if (func->implementingClass() && func->implementingClass()->enclosingClass())
- className = getClassTargetFullName(func->implementingClass()->enclosingClass()) + QLatin1Char('.');
-
- QString funcName = getFuncName(func);
- if (!funcName.startsWith(className))
- funcName = className + funcName;
-
- return funcName + QLatin1Char('(') + parseArgDocStyle(cppClass, func)
- + QLatin1Char(')');
-}
-
-QString QtDocGenerator::translateToPythonType(const AbstractMetaType* type, const AbstractMetaClass* cppClass)
-{
- QString strType;
- const QString name = type->name();
- if (name == QLatin1String("QString")) {
- strType = QLatin1String("unicode");
- } else if (name == QLatin1String("QVariant")) {
- strType = QLatin1String("object");
- } else if (name == QLatin1String("QStringList")) {
- strType = QLatin1String("list of strings");
- } else if (type->isConstant() && name == QLatin1String("char") && type->indirections() == 1) {
- strType = QLatin1String("str");
- } else if (name.startsWith(QLatin1String("unsigned short"))) {
- strType = QLatin1String("int");
- } else if (name.startsWith(QLatin1String("unsigned "))) { // uint and ulong
- strType = QLatin1String("long");
- } else if (type->isContainer()) {
- QString strType = translateType(type, cppClass, Options(ExcludeConst) | ExcludeReference);
- strType.remove(QLatin1Char('*'));
- strType.remove(QLatin1Char('>'));
- strType.remove(QLatin1Char('<'));
- strType.replace(QLatin1String("::"), QLatin1String("."));
- if (strType.contains(QLatin1String("QList")) || strType.contains(QLatin1String("QVector"))) {
- strType.replace(QLatin1String("QList"), QLatin1String("list of "));
- strType.replace(QLatin1String("QVector"), QLatin1String("list of "));
- } else if (strType.contains(QLatin1String("QHash")) || strType.contains(QLatin1String("QMap"))) {
- strType.remove(QLatin1String("QHash"));
- strType.remove(QLatin1String("QMap"));
- QStringList types = strType.split(QLatin1Char(','));
- strType = QString::fromLatin1("Dictionary with keys of type %1 and values of type %2.")
- .arg(types[0], types[1]);
- }
- } else {
- QString refTag;
- if (type->isEnum())
- refTag = QLatin1String("attr");
- else
- refTag = QLatin1String("class");
- strType = QLatin1Char(':') + refTag + QLatin1String(":`") + name + QLatin1Char('`');
- }
- return strType;
-}
-
-void QtDocGenerator::writeParameterType(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaArgument* arg)
-{
- s << INDENT << ":param " << arg->name() << ": "
- << translateToPythonType(arg->type(), cppClass) << Qt::endl;
-}
-
-void QtDocGenerator::writeFunctionParametersType(QTextStream &s, const AbstractMetaClass *cppClass,
- const AbstractMetaFunction *func)
-{
- s << Qt::endl;
- const AbstractMetaArgumentList &funcArgs = func->arguments();
- for (AbstractMetaArgument *arg : funcArgs) {
-
- if (func->argumentRemoved(arg->argumentIndex() + 1))
- continue;
-
- writeParameterType(s, cppClass, arg);
- }
-
- if (!func->isConstructor() && func->type()) {
-
- QString retType;
- // check if the return type was modified
- const FunctionModificationList &mods = func->modifications();
- for (const FunctionModification &mod : mods) {
- for (const 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 << Qt::endl;
- }
- s << Qt::endl;
-}
-
-void QtDocGenerator::writeFunction(QTextStream& s, const AbstractMetaClass* cppClass,
- const AbstractMetaFunction* func)
-{
- s << functionSignature(cppClass, func) << "\n\n";
-
- {
- Indentation indentation(INDENT);
- writeFunctionParametersType(s, cppClass, func);
- const auto version = versionOf(func->typeEntry());
- if (!version.isNull())
- s << INDENT << rstVersionAdded(version);
- if (func->attributes().testFlag(AbstractMetaAttributes::Deprecated))
- s << INDENT << rstDeprecationNote("function");
- }
-
- writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, cppClass, func);
- if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, cppClass, func))
- writeFormattedText(s, func->documentation(), cppClass);
- writeInjectDocumentation(s, TypeSystem::DocModificationAppend, cppClass, func);
-}
-
-static void writeFancyToc(QTextStream& s, const QStringList& items, int cols = 4)
-{
- using TocMap = QMap<QChar, QStringList>;
- TocMap tocMap;
- QChar Q = QLatin1Char('Q');
- QChar idx;
- for (QString item : items) {
- if (item.isEmpty())
- continue;
- if (item.startsWith(Q) && item.length() > 1)
- idx = item[1];
- else
- idx = item[0]; // To group classes without the 'Q' prefix
-
- item.chop(4); // Remove the .rst extension
- tocMap[idx] << item;
- }
- QtXmlToSphinx::Table table;
- QtXmlToSphinx::TableRow row;
-
- int itemsPerCol = (items.size() + tocMap.size()*2) / cols;
- QString currentColData;
- int i = 0;
- QTextStream ss(&currentColData);
- QMutableMapIterator<QChar, QStringList> it(tocMap);
- while (it.hasNext()) {
- it.next();
- std::sort(it.value().begin(), it.value().end());
-
- if (i)
- ss << Qt::endl;
-
- ss << "**" << it.key() << "**\n\n";
- i += 2; // a letter title is equivalent to two entries in space
- for (const QString &item : qAsConst(it.value())) {
- ss << "* :doc:`" << item << "`\n";
- ++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.appendRow(row);
- table.normalize();
- s << ".. container:: pysidetoc\n\n";
- s << table;
-}
-
-bool QtDocGenerator::finishGeneration()
-{
- if (!classes().isEmpty())
- writeModuleDocumentation();
- if (!m_additionalDocumentationList.isEmpty())
- writeAdditionalDocumentation();
- return true;
-}
-
-void QtDocGenerator::writeModuleDocumentation()
-{
- QMap<QString, QStringList>::iterator it = m_packages.begin();
- for (; it != m_packages.end(); ++it) {
- QString key = it.key();
- key.replace(QLatin1Char('.'), QLatin1Char('/'));
- QString outputDir = outputDirectory() + QLatin1Char('/') + key;
- FileOut output(outputDir + QLatin1String("/index.rst"));
- QTextStream& s = output.stream;
-
- s << ".. module:: " << it.key() << Qt::endl << Qt::endl;
-
- const QString &title = it.key();
- s << title << Qt::endl;
- s << Pad('*', title.length()) << Qt::endl << Qt::endl;
-
- /* Avoid showing "Detailed Description for *every* class in toc tree */
- Indentation indentation(INDENT);
- // Store the it.key() in a QString so that it can be stripped off unwanted
- // information when neeeded. For example, the RST files in the extras directory
- // doesn't include the PySide# prefix in their names.
- const QString moduleName = it.key();
- const int lastIndex = moduleName.lastIndexOf(QLatin1Char('.'));
-
- // Search for extra-sections
- if (!m_extraSectionDir.isEmpty()) {
- QDir extraSectionDir(m_extraSectionDir);
- if (!extraSectionDir.exists())
- qCWarning(lcShiboken) << m_extraSectionDir << "doesn't exist";
-
- QStringList fileList = extraSectionDir.entryList(QStringList() << (moduleName.mid(lastIndex + 1) + QLatin1String("?*.rst")), QDir::Files);
- QStringList::iterator it2 = fileList.begin();
- for (; it2 != fileList.end(); ++it2) {
- QString origFileName(*it2);
- it2->remove(0, moduleName.indexOf(QLatin1Char('.')));
- QString newFilePath = outputDir + QLatin1Char('/') + *it2;
- if (QFile::exists(newFilePath))
- QFile::remove(newFilePath);
- if (!QFile::copy(m_extraSectionDir + QLatin1Char('/') + origFileName, newFilePath)) {
- qCDebug(lcShiboken).noquote().nospace() << "Error copying extra doc "
- << QDir::toNativeSeparators(m_extraSectionDir + QLatin1Char('/') + origFileName)
- << " to " << QDir::toNativeSeparators(newFilePath);
- }
- }
- it.value().append(fileList);
- }
-
- writeFancyToc(s, it.value());
-
- s << INDENT << ".. container:: hide\n\n";
- {
- Indentation indentation(INDENT);
- s << INDENT << ".. toctree::\n";
- Indentation deeperIndentation(INDENT);
- s << INDENT << ":maxdepth: 1\n\n";
- for (const QString &className : qAsConst(it.value()))
- s << INDENT << className << Qt::endl;
- s << Qt::endl << Qt::endl;
- }
-
- s << "Detailed Description\n--------------------\n\n";
-
- // module doc is always wrong and C++istic, so go straight to the extra directory!
- QFile moduleDoc(m_extraSectionDir + QLatin1Char('/') + moduleName.mid(lastIndex + 1) + QLatin1String(".rst"));
- if (moduleDoc.open(QIODevice::ReadOnly | QIODevice::Text)) {
- s << moduleDoc.readAll();
- moduleDoc.close();
- } else {
- // try the normal way
- Documentation moduleDoc = m_docParser->retrieveModuleDocumentation(it.key());
- if (moduleDoc.format() == Documentation::Native) {
- QString context = it.key();
- stripPythonQualifiers(&context);
- QtXmlToSphinx x(this, moduleDoc.value(), context);
- s << x;
- } else {
- s << moduleDoc.value();
- }
- }
- }
-}
-
-static inline QString msgNonExistentAdditionalDocFile(const QString &dir,
- const QString &fileName)
-{
- const QString result = QLatin1Char('"') + fileName
- + QLatin1String("\" does not exist in ")
- + QDir::toNativeSeparators(dir) + QLatin1Char('.');
- return result;
-}
-
-void QtDocGenerator::writeAdditionalDocumentation()
-{
- QFile additionalDocumentationFile(m_additionalDocumentationList);
- if (!additionalDocumentationFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgCannotOpenForReading(additionalDocumentationFile)));
- return;
- }
-
- QDir outDir(outputDirectory());
- const QString rstSuffix = fileNameSuffix();
-
- QString errorMessage;
- int successCount = 0;
- int count = 0;
-
- QString targetDir = outDir.absolutePath();
-
- while (!additionalDocumentationFile.atEnd()) {
- const QByteArray lineBA = additionalDocumentationFile.readLine().trimmed();
- if (lineBA.isEmpty() || lineBA.startsWith('#'))
- continue;
- const QString line = QFile::decodeName(lineBA);
- // Parse "[directory]" specification
- if (line.size() > 2 && line.startsWith(QLatin1Char('[')) && line.endsWith(QLatin1Char(']'))) {
- const QString dir = line.mid(1, line.size() - 2);
- if (dir.isEmpty() || dir == QLatin1String(".")) {
- targetDir = outDir.absolutePath();
- } else {
- if (!outDir.exists(dir) && !outDir.mkdir(dir)) {
- qCWarning(lcShiboken, "Cannot create directory %s under %s",
- qPrintable(dir),
- qPrintable(QDir::toNativeSeparators(outputDirectory())));
- break;
- }
- targetDir = outDir.absoluteFilePath(dir);
- }
- } else {
- // Normal file entry
- QFileInfo fi(m_docDataDir + QLatin1Char('/') + line);
- if (fi.isFile()) {
- const QString rstFileName = fi.baseName() + rstSuffix;
- const QString rstFile = targetDir + QLatin1Char('/') + rstFileName;
- const QString context = targetDir.mid(targetDir.lastIndexOf(QLatin1Char('/')) + 1);
- if (QtXmlToSphinx::convertToRst(this, fi.absoluteFilePath(),
- rstFile, context, &errorMessage)) {
- ++successCount;
- qCDebug(lcShiboken).nospace().noquote() << __FUNCTION__
- << " converted " << fi.fileName()
- << ' ' << rstFileName;
- } else {
- qCWarning(lcShiboken, "%s", qPrintable(errorMessage));
- }
- } else {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgNonExistentAdditionalDocFile(m_docDataDir, line)));
- }
- ++count;
- }
- }
- additionalDocumentationFile.close();
-
- qCInfo(lcShiboken, "Created %d/%d additional documentation files.",
- successCount, count);
-}
-
-#ifdef __WIN32__
-# define PATH_SEP ';'
-#else
-# define PATH_SEP ':'
-#endif
-
-bool QtDocGenerator::doSetup()
-{
- if (m_codeSnippetDirs.isEmpty())
- m_codeSnippetDirs = m_libSourceDir.split(QLatin1Char(PATH_SEP));
-
- if (!m_docParser)
- m_docParser = new QtDocParser;
-
- if (m_libSourceDir.isEmpty() || m_docDataDir.isEmpty()) {
- qCWarning(lcShiboken) << "Documentation data dir and/or Qt source dir not informed, "
- "documentation will not be extracted from Qt sources.";
- return false;
- }
-
- m_docParser->setDocumentationDataDirectory(m_docDataDir);
- m_docParser->setLibrarySourceDirectory(m_libSourceDir);
- return true;
-}
-
-
-Generator::OptionDescriptions QtDocGenerator::options() const
-{
- return OptionDescriptions()
- << qMakePair(QLatin1String("doc-parser=<parser>"),
- QLatin1String("The documentation parser used to interpret the documentation\n"
- "input files (qdoc|doxygen)"))
- << qMakePair(QLatin1String("documentation-code-snippets-dir=<dir>"),
- QLatin1String("Directory used to search code snippets used by the documentation"))
- << qMakePair(QLatin1String("documentation-data-dir=<dir>"),
- QLatin1String("Directory with XML files generated by documentation tool"))
- << qMakePair(QLatin1String("documentation-extra-sections-dir=<dir>"),
- QLatin1String("Directory used to search for extra documentation sections"))
- << qMakePair(QLatin1String("library-source-dir=<dir>"),
- QLatin1String("Directory where library source code is located"))
- << qMakePair(additionalDocumentationOption() + QLatin1String("=<file>"),
- QLatin1String("List of additional XML files to be converted to .rst files\n"
- "(for example, tutorials)."));
-}
-
-bool QtDocGenerator::handleOption(const QString &key, const QString &value)
-{
- if (key == QLatin1String("library-source-dir")) {
- m_libSourceDir = value;
- return true;
- }
- if (key == QLatin1String("documentation-data-dir")) {
- m_docDataDir = value;
- return true;
- }
- if (key == QLatin1String("documentation-code-snippets-dir")) {
- m_codeSnippetDirs = value.split(QLatin1Char(PATH_SEP));
- return true;
- }
- if (key == QLatin1String("documentation-extra-sections-dir")) {
- m_extraSectionDir = value;
- return true;
- }
- if (key == QLatin1String("doc-parser")) {
- qCDebug(lcShiboken).noquote().nospace() << "doc-parser: " << value;
- if (value == QLatin1String("doxygen"))
- m_docParser = new DoxygenParser;
- return true;
- }
- if (key == additionalDocumentationOption()) {
- m_additionalDocumentationList = value;
- return true;
- }
- return false;
-}
diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.h b/sources/shiboken2/generator/qtdoc/qtdocgenerator.h
deleted file mode 100644
index 56cb9c4bb..000000000
--- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.h
+++ /dev/null
@@ -1,284 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#ifndef DOCGENERATOR_H
-#define DOCGENERATOR_H
-
-#include <QtCore/QStack>
-#include <QtCore/QHash>
-#include <QtCore/QScopedPointer>
-#include <QtCore/QTextStream>
-#include <QXmlStreamReader>
-#include "generator.h"
-#include "docparser.h"
-#include "typesystem_enums.h"
-#include "typesystem_typedefs.h"
-
-class QtDocParser;
-class AbstractMetaFunction;
-class AbstractMetaClass;
-QT_BEGIN_NAMESPACE
-class QXmlStreamReader;
-QT_END_NAMESPACE
-class QtDocGenerator;
-
-class QtXmlToSphinx
-{
-public:
- struct LinkContext;
-
- struct InlineImage
- {
- QString tag;
- QString href;
- };
-
- struct TableCell
- {
- short rowSpan = 0;
- short colSpan = 0;
- QString data;
-
- TableCell(const QString& text = QString()) : data(text) {}
- TableCell(const char* text) : data(QLatin1String(text)) {}
- };
-
- using TableRow = QVector<TableCell>;
-
- class Table
- {
- public:
- Table() = default;
-
- bool isEmpty() const { return m_rows.isEmpty(); }
-
- void setHeaderEnabled(bool enable)
- {
- m_hasHeader = enable;
- }
-
- bool hasHeader() const
- {
- return m_hasHeader;
- }
-
- void normalize();
-
- bool isNormalized() const
- {
- return m_normalized;
- }
-
- void clear() {
- m_normalized = false;
- m_rows.clear();
- }
-
- void appendRow(const TableRow &row) { m_rows.append(row); }
-
- const TableRow &constFirst() { return m_rows.constFirst(); }
- TableRow &first() { return m_rows.first(); }
- TableRow &last() { return m_rows.last(); }
-
- void format (QTextStream& s) const;
-
- private:
- QVector<TableRow> m_rows;
- bool m_hasHeader = false;
- bool m_normalized = false;
- };
-
- QtXmlToSphinx(QtDocGenerator* generator, const QString& doc, const QString& context = QString());
-
- static bool convertToRst(QtDocGenerator *generator,
- const QString &sourceFileName,
- const QString &targetFileName,
- const QString &context = QString(),
- QString *errorMessage = nullptr);
-
- QString result() const
- {
- return m_result;
- }
-
-private:
- QString resolveContextForMethod(const QString& methodName) const;
- QString expandFunction(const QString& function) const;
- 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 handleInlineImageTag(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 handlePageTag(QXmlStreamReader&);
- void handleTargetTag(QXmlStreamReader&);
-
- void handleIgnoredTag(QXmlStreamReader& reader);
- void handleUnknownTag(QXmlStreamReader& reader);
- void handleUselessTag(QXmlStreamReader& reader);
- void handleAnchorTag(QXmlStreamReader& reader);
- void handleRstPassTroughTag(QXmlStreamReader& reader);
-
- LinkContext *handleLinkStart(const QString &type, QString ref) const;
- void handleLinkText(LinkContext *linkContext, const QString &linktext) const;
- void handleLinkEnd(LinkContext *linkContext);
-
- 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;
- QScopedPointer<LinkContext> m_linkContext; // for <link>
- QScopedPointer<LinkContext> m_seeAlsoContext; // for <see-also>foo()</see-also>
- bool m_tableHasHeader;
- QString m_context;
- QtDocGenerator* m_generator;
- bool m_insideBold;
- bool m_insideItalic;
- QString m_lastTagName;
- QString m_opened_anchor;
- QVector<InlineImage> m_inlineImages;
-
- QString readFromLocations(const QStringList &locations, const QString &path,
- const QString &identifier, QString *errorMessage);
- QString readFromLocation(const QString &location, const QString &identifier,
- QString *errorMessage);
- void pushOutputBuffer();
- QString popOutputBuffer();
- void writeTable(Table& table);
- bool copyImage(const QString &href) const;
-};
-
-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;
- }
-
- QString docDataDir() const { return m_docDataDir; }
-
- bool doSetup() override;
-
- const char* name() const override
- {
- return "QtDocGenerator";
- }
-
- OptionDescriptions options() const override;
- bool handleOption(const QString &key, const QString &value) override;
-
- QStringList codeSnippetDirs() const
- {
- return m_codeSnippetDirs;
- }
-
-protected:
- bool shouldGenerate(const AbstractMetaClass *) const override;
- QString fileNameSuffix() const override;
- QString fileNameForContext(GeneratorContext &context) const override;
- void generateClass(QTextStream &s, GeneratorContext &classContext) override;
- bool finishGeneration() override;
-
- void writeFunctionArguments(QTextStream&, const AbstractMetaFunction*, Options) const override {}
- void writeArgumentNames(QTextStream&, const AbstractMetaFunction*, Options) const override {}
-
-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);
- QString functionSignature(const AbstractMetaClass* cppClass, const AbstractMetaFunction* func);
- void writeFunction(QTextStream& s, 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 writeParameterType(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaArgument *arg);
-
- void writeConstructors(QTextStream &s, const AbstractMetaClass *cppClass);
- void writeFormattedText(QTextStream &s, const Documentation &doc,
- const AbstractMetaClass *metaclass = nullptr);
- bool writeInjectDocumentation(QTextStream& s, TypeSystem::DocModificationMode mode, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func);
- void writeDocSnips(QTextStream &s, const CodeSnipList &codeSnips, TypeSystem::CodeSnipPosition position, TypeSystem::Language language);
-
- void writeModuleDocumentation();
- void writeAdditionalDocumentation();
-
- 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;
- QString m_additionalDocumentationList;
-};
-
-#endif // DOCGENERATOR_H
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
deleted file mode 100644
index eaa9fe8c4..000000000
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ /dev/null
@@ -1,6024 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <memory>
-
-#include "cppgenerator.h"
-#include "fileout.h"
-#include "overloaddata.h"
-#include <abstractmetalang.h>
-#include <messages.h>
-#include <reporthandler.h>
-#include <typedatabase.h>
-
-#include <QtCore/QDir>
-#include <QtCore/QMetaObject>
-#include <QtCore/QRegularExpression>
-#include <QtCore/QTextStream>
-#include <QtCore/QDebug>
-#include <QMetaType>
-
-#include <algorithm>
-
-#include <algorithm>
-
-static const char CPP_ARG0[] = "cppArg0";
-
-QHash<QString, QString> CppGenerator::m_nbFuncs = QHash<QString, QString>();
-QHash<QString, QString> CppGenerator::m_sqFuncs = QHash<QString, QString>();
-QHash<QString, QString> CppGenerator::m_mpFuncs = QHash<QString, QString>();
-QString CppGenerator::m_currentErrorCode(QLatin1String("{}"));
-
-static const char typeNameFunc[] = R"CPP(
-template <class T>
-static const char *typeNameOf(const T &t)
-{
- const char *typeName = typeid(t).name();
- auto size = std::strlen(typeName);
-#if defined(Q_CC_MSVC) // MSVC: "class QPaintDevice * __ptr64"
- if (auto lastStar = strchr(typeName, '*')) {
- // MSVC: "class QPaintDevice * __ptr64"
- while (*--lastStar == ' ') {
- }
- size = lastStar - typeName + 1;
- }
-#else // g++, Clang: "QPaintDevice *" -> "P12QPaintDevice"
- if (size > 2 && typeName[0] == 'P' && std::isdigit(typeName[1])) {
- ++typeName;
- --size;
- }
-#endif
- char *result = new char[size + 1];
- result[size] = '\0';
- memcpy(result, typeName, size);
- return result;
-}
-)CPP";
-
-// 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;
-}
-
-// A helper for writing C++ return statements for either void ("return;")
-// or some return value ("return value;")
-class returnStatement
-{
-public:
- explicit returnStatement(QString s) : m_returnValue(std::move(s)) {}
-
- friend QTextStream &operator<<(QTextStream &s, const returnStatement &r);
-
-private:
- const QString m_returnValue;
-};
-
-QTextStream &operator<<(QTextStream &s, const returnStatement &r)
-{
- s << "return";
- if (!r.m_returnValue.isEmpty())
- s << ' ' << r.m_returnValue;
- s << ';';
- return s;
-}
-
-CppGenerator::CppGenerator()
-{
- // Number protocol structure members names
- m_nbFuncs.insert(QLatin1String("__add__"), QLatin1String("nb_add"));
- m_nbFuncs.insert(QLatin1String("__sub__"), QLatin1String("nb_subtract"));
- m_nbFuncs.insert(QLatin1String("__mul__"), QLatin1String("nb_multiply"));
- m_nbFuncs.insert(QLatin1String("__div__"), QLatin1String("nb_divide"));
- m_nbFuncs.insert(QLatin1String("__mod__"), QLatin1String("nb_remainder"));
- m_nbFuncs.insert(QLatin1String("__neg__"), QLatin1String("nb_negative"));
- m_nbFuncs.insert(QLatin1String("__pos__"), QLatin1String("nb_positive"));
- m_nbFuncs.insert(QLatin1String("__invert__"), QLatin1String("nb_invert"));
- m_nbFuncs.insert(QLatin1String("__lshift__"), QLatin1String("nb_lshift"));
- m_nbFuncs.insert(QLatin1String("__rshift__"), QLatin1String("nb_rshift"));
- m_nbFuncs.insert(QLatin1String("__and__"), QLatin1String("nb_and"));
- m_nbFuncs.insert(QLatin1String("__xor__"), QLatin1String("nb_xor"));
- m_nbFuncs.insert(QLatin1String("__or__"), QLatin1String("nb_or"));
- m_nbFuncs.insert(QLatin1String("__iadd__"), QLatin1String("nb_inplace_add"));
- m_nbFuncs.insert(QLatin1String("__isub__"), QLatin1String("nb_inplace_subtract"));
- m_nbFuncs.insert(QLatin1String("__imul__"), QLatin1String("nb_inplace_multiply"));
- m_nbFuncs.insert(QLatin1String("__idiv__"), QLatin1String("nb_inplace_divide"));
- m_nbFuncs.insert(QLatin1String("__imod__"), QLatin1String("nb_inplace_remainder"));
- m_nbFuncs.insert(QLatin1String("__ilshift__"), QLatin1String("nb_inplace_lshift"));
- m_nbFuncs.insert(QLatin1String("__irshift__"), QLatin1String("nb_inplace_rshift"));
- m_nbFuncs.insert(QLatin1String("__iand__"), QLatin1String("nb_inplace_and"));
- m_nbFuncs.insert(QLatin1String("__ixor__"), QLatin1String("nb_inplace_xor"));
- m_nbFuncs.insert(QLatin1String("__ior__"), QLatin1String("nb_inplace_or"));
- m_nbFuncs.insert(QLatin1String("bool"), QLatin1String("nb_nonzero"));
-
- // sequence protocol functions
- m_sequenceProtocol.insert(QLatin1String("__len__"),
- {QLatin1String("PyObject *self"),
- QLatin1String("Py_ssize_t")});
- m_sequenceProtocol.insert(QLatin1String("__getitem__"),
- {QLatin1String("PyObject *self, Py_ssize_t _i"),
- QLatin1String("PyObject*")});
- m_sequenceProtocol.insert(QLatin1String("__setitem__"),
- {QLatin1String("PyObject *self, Py_ssize_t _i, PyObject *_value"),
- QLatin1String("int")});
- m_sequenceProtocol.insert(QLatin1String("__getslice__"),
- {QLatin1String("PyObject *self, Py_ssize_t _i1, Py_ssize_t _i2"),
- QLatin1String("PyObject*")});
- m_sequenceProtocol.insert(QLatin1String("__setslice__"),
- {QLatin1String("PyObject *self, Py_ssize_t _i1, Py_ssize_t _i2, PyObject *_value"),
- QLatin1String("int")});
- m_sequenceProtocol.insert(QLatin1String("__contains__"),
- {QLatin1String("PyObject *self, PyObject *_value"),
- QLatin1String("int")});
- m_sequenceProtocol.insert(QLatin1String("__concat__"),
- {QLatin1String("PyObject *self, PyObject *_other"),
- QLatin1String("PyObject*")});
-
- // Sequence protocol structure members names
- m_sqFuncs.insert(QLatin1String("__concat__"), QLatin1String("sq_concat"));
- m_sqFuncs.insert(QLatin1String("__contains__"), QLatin1String("sq_contains"));
- m_sqFuncs.insert(QLatin1String("__getitem__"), QLatin1String("sq_item"));
- m_sqFuncs.insert(QLatin1String("__getslice__"), QLatin1String("sq_slice"));
- m_sqFuncs.insert(QLatin1String("__len__"), QLatin1String("sq_length"));
- m_sqFuncs.insert(QLatin1String("__setitem__"), QLatin1String("sq_ass_item"));
- m_sqFuncs.insert(QLatin1String("__setslice__"), QLatin1String("sq_ass_slice"));
-
- // mapping protocol function
- m_mappingProtocol.insert(QLatin1String("__mlen__"),
- {QLatin1String("PyObject *self"),
- QLatin1String("Py_ssize_t")});
- m_mappingProtocol.insert(QLatin1String("__mgetitem__"),
- {QLatin1String("PyObject *self, PyObject *_key"),
- QLatin1String("PyObject*")});
- m_mappingProtocol.insert(QLatin1String("__msetitem__"),
- {QLatin1String("PyObject *self, PyObject *_key, PyObject *_value"),
- QLatin1String("int")});
-
- // Sequence protocol structure members names
- m_mpFuncs.insert(QLatin1String("__mlen__"), QLatin1String("mp_length"));
- m_mpFuncs.insert(QLatin1String("__mgetitem__"), QLatin1String("mp_subscript"));
- m_mpFuncs.insert(QLatin1String("__msetitem__"), QLatin1String("mp_ass_subscript"));
-}
-
-QString CppGenerator::fileNameSuffix() const
-{
- return QLatin1String("_wrapper.cpp");
-}
-
-QString CppGenerator::fileNameForContext(GeneratorContext &context) const
-{
- const AbstractMetaClass *metaClass = context.metaClass();
- if (!context.forSmartPointer()) {
- QString fileNameBase = metaClass->qualifiedCppName().toLower();
- fileNameBase.replace(QLatin1String("::"), QLatin1String("_"));
- return fileNameBase + fileNameSuffix();
- }
- const AbstractMetaType *smartPointerType = context.preciseType();
- QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass);
- return fileNameBase + fileNameSuffix();
-}
-
-QVector<AbstractMetaFunctionList> CppGenerator::filterGroupedOperatorFunctions(const AbstractMetaClass *metaClass,
- uint queryIn)
-{
- // ( func_name, num_args ) => func_list
- QMap<QPair<QString, int>, AbstractMetaFunctionList> results;
- const AbstractMetaClass::OperatorQueryOptions query(queryIn);
- const AbstractMetaFunctionList &funcs = metaClass->operatorOverloads(query);
- for (AbstractMetaFunction *func : funcs) {
- if (func->isModifiedRemoved()
- || func->usesRValueReferences()
- || func->name() == QLatin1String("operator[]")
- || func->name() == QLatin1String("operator->")
- || func->name() == QLatin1String("operator!")) {
- continue;
- }
- int args;
- if (func->isComparisonOperator()) {
- args = -1;
- } else {
- args = func->arguments().size();
- }
- QPair<QString, int > op(func->name(), args);
- results[op].append(func);
- }
- QVector<AbstractMetaFunctionList> result;
- result.reserve(results.size());
- for (auto it = results.cbegin(), end = results.cend(); it != end; ++it)
- result.append(it.value());
- return result;
-}
-
-const AbstractMetaFunction *CppGenerator::boolCast(const AbstractMetaClass *metaClass) const
-{
- if (!useIsNullAsNbNonZero())
- return nullptr;
- // TODO: This could be configurable someday
- const AbstractMetaFunction *func = metaClass->findFunction(QLatin1String("isNull"));
- if (!func || !func->type() || !func->type()->typeEntry()->isPrimitive() || !func->isPublic())
- return nullptr;
- auto pte = static_cast<const PrimitiveTypeEntry *>(func->type()->typeEntry());
- while (pte->referencedTypeEntry())
- pte = pte->referencedTypeEntry();
- return func && func->isConstant() && pte->name() == QLatin1String("bool")
- && func->arguments().isEmpty() ? func : nullptr;
-}
-
-using FunctionGroupMap = QMap<QString, AbstractMetaFunctionList>;
-
-// Prevent ELF symbol qt_version_tag from being generated into the source
-static const char includeQDebug[] =
-"#ifndef QT_NO_VERSION_TAGGING\n"
-"# define QT_NO_VERSION_TAGGING\n"
-"#endif\n"
-"#include <QDebug>\n";
-
-static QString chopType(QString s)
-{
- if (s.endsWith(QLatin1String("_Type")))
- s.chop(5);
- else if (s.endsWith(QLatin1String("_TypeF()")))
- s.chop(8);
- return s;
-}
-
-// Helper for field setters: Check for "const QWidget *" (settable field),
-// but not "int *const" (read-only field).
-static bool isPointerToConst(const AbstractMetaType *t)
-{
- const AbstractMetaType::Indirections &indirections = t->indirectionsV();
- return t->isConstant() && !indirections.isEmpty()
- && indirections.constLast() != Indirection::ConstPointer;
-}
-
-static inline bool canGenerateFieldSetter(const AbstractMetaField *field)
-{
- const AbstractMetaType *type = field->type();
- return !type->isConstant() || isPointerToConst(type);
-}
-
-/*!
- Function used to write the class generated binding code on the buffer
- \param s the output buffer
- \param metaClass the pointer to metaclass information
-*/
-void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
-{
- AbstractMetaClass *metaClass = classContext.metaClass();
- if (ReportHandler::isDebug(ReportHandler::SparseDebug))
- qCDebug(lcShiboken) << "Generating wrapper implementation for " << metaClass->fullName();
-
- // write license comment
- s << licenseComment() << Qt::endl;
-
- if (!avoidProtectedHack() && !metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) {
- s << "//workaround to access protected functions\n";
- s << "#define protected public\n\n";
- }
-
- // headers
- s << "// default includes\n";
- s << "#include <shiboken.h>\n";
- if (usePySideExtensions()) {
- s << includeQDebug;
- s << "#include <pysidesignal.h>\n"
- << "#include <pysideproperty.h>\n"
- << "#include <pyside.h>\n"
- << "#include <destroylistener.h>\n"
- << "#include <qapp_macro.h>\n\n"
- << "QT_WARNING_DISABLE_DEPRECATED\n\n";
- }
-
- s << "#include <typeinfo>\n";
- if (usePySideExtensions() && metaClass->isQObject()) {
- s << "#include <signalmanager.h>\n";
- s << "#include <pysidemetafunction.h>\n";
- }
-
- // The multiple inheritance initialization function
- // needs the 'set' class from C++ STL.
- if (getMultipleInheritingClass(metaClass) != nullptr)
- s << "#include <algorithm>\n#include <set>\n";
- if (metaClass->generateExceptionHandling())
- s << "#include <exception>\n";
-
- s << "\n// module include\n" << "#include \"" << getModuleHeaderFileName() << "\"\n";
-
- QString headerfile = fileNameForContext(classContext);
- headerfile.replace(QLatin1String(".cpp"), QLatin1String(".h"));
- s << "\n// main header\n" << "#include \"" << headerfile << "\"\n";
-
- s << Qt::endl << "// inner classes\n";
- const AbstractMetaClassList &innerClasses = metaClass->innerClasses();
- for (AbstractMetaClass *innerClass : innerClasses) {
- GeneratorContext innerClassContext(innerClass);
- if (shouldGenerate(innerClass) && !innerClass->typeEntry()->isSmartPointer()) {
- QString headerfile = fileNameForContext(innerClassContext);
- headerfile.replace(QLatin1String(".cpp"), QLatin1String(".h"));
- s << "#include \"" << headerfile << "\"\n";
- }
- }
-
- AbstractMetaEnumList classEnums = metaClass->enums();
- for (AbstractMetaClass *innerClass : innerClasses)
- lookForEnumsInClassesNotToBeGenerated(classEnums, innerClass);
-
- //Extra includes
- s << "\n// Extra includes\n";
- QVector<Include> includes = metaClass->typeEntry()->extraIncludes();
- for (AbstractMetaEnum *cppEnum : qAsConst(classEnums))
- includes.append(cppEnum->typeEntry()->extraIncludes());
- std::sort(includes.begin(), includes.end());
- for (const Include &inc : qAsConst(includes))
- s << inc.toString() << Qt::endl;
- s << Qt::endl;
-
- s << "\n#include <cctype>\n#include <cstring>\n";
-
- if (metaClass->typeEntry()->typeFlags() & ComplexTypeEntry::Deprecated)
- s << "#Deprecated\n";
-
- // Use class base namespace
- {
- const AbstractMetaClass *context = metaClass->enclosingClass();
- while (context) {
- if (context->isNamespace() && !context->enclosingClass()) {
- s << "using namespace " << context->qualifiedCppName() << ";\n";
- break;
- }
- context = context->enclosingClass();
- }
- }
-
- s << Qt::endl << Qt::endl << typeNameFunc << Qt::endl;
-
- // Create string literal for smart pointer getter method.
- if (classContext.forSmartPointer()) {
- const auto *typeEntry =
- static_cast<const SmartPointerTypeEntry *>(classContext.preciseType()
- ->typeEntry());
- QString rawGetter = typeEntry->getter();
- s << "static const char * " << SMART_POINTER_GETTER << " = \"" << rawGetter << "\";";
- }
-
- // class inject-code native/beginning
- if (!metaClass->typeEntry()->codeSnips().isEmpty()) {
- writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode, metaClass);
- s << Qt::endl;
- }
-
- // python conversion rules
- if (metaClass->typeEntry()->hasTargetConversionRule()) {
- s << "// Python Conversion\n";
- s << metaClass->typeEntry()->conversionRule() << Qt::endl;
- }
-
- if (shouldGenerateCppWrapper(metaClass)) {
- s << "// Native ---------------------------------------------------------\n\n";
-
- if (avoidProtectedHack() && usePySideExtensions()) {
- s << "void " << wrapperName(metaClass) << "::pysideInitQtMetaTypes()\n{\n";
- Indentation indent(INDENT);
- writeInitQtMetaTypeFunctionBody(s, classContext);
- s << "}\n\n";
- }
-
- const AbstractMetaFunctionList &funcs = filterFunctions(metaClass);
- for (const AbstractMetaFunction *func : funcs) {
- const bool notAbstract = !func->isAbstract();
- if ((func->isPrivate() && notAbstract && !visibilityModifiedToPrivate(func))
- || (func->isModifiedRemoved() && notAbstract))
- continue;
- if (func->functionType() == AbstractMetaFunction::ConstructorFunction && !func->isUserAdded()) {
- writeConstructorNative(s, func);
- } else if ((!avoidProtectedHack() || !metaClass->hasPrivateDestructor())
- && ((func->isVirtual() || func->isAbstract())
- && (func->attributes() & AbstractMetaAttributes::FinalCppMethod) == 0)) {
- 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);
- QString signaturesString;
- QTextStream signatureStream(&signaturesString);
-
- s << "\n// Target ---------------------------------------------------------\n\n"
- << "extern \"C\" {\n";
- const auto &functionGroups = getFunctionGroups(metaClass);
- for (auto it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
- AbstractMetaFunctionList overloads;
- QSet<QString> seenSignatures;
- bool staticEncountered = false;
- for (AbstractMetaFunction *func : it.value()) {
- if (!func->isAssignmentOperator()
- && !func->usesRValueReferences()
- && !func->isCastOperator()
- && !func->isModifiedRemoved()
- && (!func->isPrivate() || func->functionType() == AbstractMetaFunction::EmptyFunction)
- && func->ownerClass() == func->implementingClass()
- && (func->name() != QLatin1String("qt_metacall"))) {
- // PYSIDE-331: Inheritance works correctly when there are disjoint functions.
- // But when a function is both in a class and inherited in a subclass,
- // then we need to search through all subclasses and collect the new signatures.
- overloads << getFunctionAndInheritedOverloads(func, &seenSignatures);
- if (func->isStatic())
- staticEncountered = true;
- }
- }
- // PYSIDE-886: If the method does not have any static overloads declared
- // in the class in question, remove all inherited static methods as setting
- // METH_STATIC in that case can cause crashes for the instance methods.
- // Manifested as crash when calling QPlainTextEdit::find() (clash with
- // static QWidget::find(WId)).
- if (!staticEncountered) {
- for (int i = overloads.size() - 1; i >= 0; --i) {
- if (overloads.at(i)->isStatic())
- delete overloads.takeAt(i);
- }
- }
-
- if (overloads.isEmpty())
- continue;
-
- const AbstractMetaFunction *rfunc = overloads.constFirst();
- if (m_sequenceProtocol.contains(rfunc->name()) || m_mappingProtocol.contains(rfunc->name()))
- continue;
-
- if (rfunc->isConstructor()) {
- // @TODO: Implement constructor support for smart pointers, so that they can be
- // instantiated in python code.
- if (classContext.forSmartPointer())
- continue;
- writeConstructorWrapper(s, overloads, classContext);
- writeSignatureInfo(signatureStream, overloads);
- }
- // call operators
- else if (rfunc->name() == QLatin1String("operator()")) {
- writeMethodWrapper(s, overloads, classContext);
- writeSignatureInfo(signatureStream, overloads);
- }
- else if (!rfunc->isOperatorOverload()) {
-
- if (classContext.forSmartPointer()) {
- const auto *smartPointerTypeEntry =
- static_cast<const SmartPointerTypeEntry *>(
- classContext.preciseType()->typeEntry());
-
- if (smartPointerTypeEntry->getter() == rfunc->name()) {
- // Replace the return type of the raw pointer getter method with the actual
- // return type.
- QString innerTypeName =
- classContext.preciseType()->getSmartPointerInnerType()->cppSignature();
- QString pointerToInnerTypeName = innerTypeName + QLatin1Char('*');
- // @TODO: This possibly leaks, but there are a bunch of other places where this
- // is done, so this will be fixed in bulk with all the other cases, because the
- // ownership of the pointers is not clear at the moment.
- AbstractMetaType *pointerToInnerType =
- buildAbstractMetaTypeFromString(pointerToInnerTypeName);
-
- AbstractMetaFunction *mutableRfunc = overloads.constFirst();
- mutableRfunc->replaceType(pointerToInnerType);
- } else if (smartPointerTypeEntry->refCountMethodName().isEmpty()
- || smartPointerTypeEntry->refCountMethodName() != rfunc->name()) {
- // Skip all public methods of the smart pointer except for the raw getter and
- // the ref count method.
- continue;
- }
- }
-
- writeMethodWrapper(s, overloads, classContext);
- writeSignatureInfo(signatureStream, overloads);
- if (OverloadData::hasStaticAndInstanceFunctions(overloads)) {
- QString methDefName = cpythonMethodDefinitionName(rfunc);
- smd << "static PyMethodDef " << methDefName << " = {\n";
- smd << INDENT;
- writeMethodDefinitionEntry(smd, overloads);
- smd << "\n};\n\n";
- }
- writeMethodDefinition(md, overloads);
- }
- }
-
- const QString className = chopType(cpythonTypeName(metaClass));
-
- if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) {
- writeCopyFunction(s, classContext);
- signatureStream << fullPythonClassName(metaClass) << ".__copy__()\n";
- }
-
- // Write single method definitions
- s << singleMethodDefinitions;
-
- // Write methods definition
- s << "static PyMethodDef " << className << "_methods[] = {\n";
- s << methodsDefinitions << Qt::endl;
- if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) {
- s << INDENT << "{\"__copy__\", reinterpret_cast<PyCFunction>(" << className << "___copy__)"
- << ", METH_NOARGS},\n";
- }
- s << INDENT << '{' << NULL_PTR << ", " << NULL_PTR << "} // Sentinel\n";
- s << "};\n\n";
-
- // Write tp_getattro function
- if ((usePySideExtensions() && metaClass->qualifiedCppName() == QLatin1String("QObject"))) {
- writeGetattroFunction(s, classContext);
- s << Qt::endl;
- writeSetattroFunction(s, classContext);
- s << Qt::endl;
- } else {
- if (classNeedsGetattroFunction(metaClass)) {
- writeGetattroFunction(s, classContext);
- s << Qt::endl;
- }
- if (classNeedsSetattroFunction(metaClass)) {
- writeSetattroFunction(s, classContext);
- s << Qt::endl;
- }
- }
-
- if (const AbstractMetaFunction *f = boolCast(metaClass)) {
- ErrorCode errorCode(-1);
- s << "static int " << cpythonBaseName(metaClass) << "___nb_bool(PyObject *self)\n"
- << "{\n";
- writeCppSelfDefinition(s, classContext);
- if (f->allowThread()) {
- s << INDENT << "int result;\n";
- s << INDENT << BEGIN_ALLOW_THREADS << Qt::endl;
- s << INDENT << "result = !" << CPP_SELF_VAR << "->isNull();\n";
- s << INDENT << END_ALLOW_THREADS << Qt::endl;
- s << INDENT << "return result;\n";
- } else {
- s << INDENT << "return !" << CPP_SELF_VAR << "->isNull();\n";
- }
- s << "}\n\n";
- }
-
- if (supportsNumberProtocol(metaClass) && !metaClass->typeEntry()->isSmartPointer()) {
- const QVector<AbstractMetaFunctionList> opOverloads = filterGroupedOperatorFunctions(
- metaClass,
- AbstractMetaClass::ArithmeticOp
- | AbstractMetaClass::LogicalOp
- | AbstractMetaClass::BitwiseOp);
-
- for (const AbstractMetaFunctionList &allOverloads : opOverloads) {
- AbstractMetaFunctionList overloads;
- for (AbstractMetaFunction *func : allOverloads) {
- if (!func->isModifiedRemoved()
- && !func->isPrivate()
- && (func->ownerClass() == func->implementingClass() || func->isAbstract()))
- overloads.append(func);
- }
-
- if (overloads.isEmpty())
- continue;
-
- writeMethodWrapper(s, overloads, classContext);
- writeSignatureInfo(signatureStream, overloads);
- }
- }
-
- if (supportsSequenceProtocol(metaClass)) {
- writeSequenceMethods(s, metaClass, classContext);
- }
-
- if (supportsMappingProtocol(metaClass)) {
- writeMappingMethods(s, metaClass, classContext);
- }
-
- if (!metaClass->isNamespace() && metaClass->hasComparisonOperatorOverload()) {
- s << "// Rich comparison\n";
- writeRichCompareFunction(s, classContext);
- }
-
- if (shouldGenerateGetSetList(metaClass) && !classContext.forSmartPointer()) {
- const AbstractMetaFieldList &fields = metaClass->fields();
- for (const AbstractMetaField *metaField : fields) {
- if (metaField->isStatic())
- continue;
- writeGetterFunction(s, metaField, classContext);
- if (canGenerateFieldSetter(metaField))
- writeSetterFunction(s, metaField, classContext);
- s << Qt::endl;
- }
-
- s << "// Getters and Setters for " << metaClass->name() << Qt::endl;
- s << "static PyGetSetDef " << cpythonGettersSettersDefinitionName(metaClass) << "[] = {\n";
- for (const AbstractMetaField *metaField : fields) {
- if (metaField->isStatic())
- continue;
-
- s << INDENT << "{const_cast<char *>(\"" << metaField->name() << "\"), ";
- s << cpythonGetterFunctionName(metaField) << ", ";
- if (canGenerateFieldSetter(metaField))
- s << cpythonSetterFunctionName(metaField);
- else
- s << NULL_PTR;
- s << "},\n";
- }
- s << INDENT << '{' << NULL_PTR << "} // Sentinel\n";
- s << "};\n\n";
- }
-
- s << "} // extern \"C\"\n\n";
-
- if (!metaClass->typeEntry()->hashFunction().isEmpty())
- writeHashFunction(s, classContext);
-
- // Write tp_traverse and tp_clear functions.
- writeTpTraverseFunction(s, metaClass);
- writeTpClearFunction(s, metaClass);
-
- writeClassDefinition(s, metaClass, classContext);
- s << Qt::endl;
-
- if (metaClass->isPolymorphic() && metaClass->baseClass())
- writeTypeDiscoveryFunction(s, metaClass);
-
-
- for (AbstractMetaEnum *cppEnum : qAsConst(classEnums)) {
- if (cppEnum->isAnonymous() || cppEnum->isPrivate())
- continue;
-
- bool hasFlags = cppEnum->typeEntry()->flags();
- if (hasFlags) {
- writeFlagsMethods(s, cppEnum);
- writeFlagsNumberMethodsDefinition(s, cppEnum);
- s << Qt::endl;
- }
- }
- s << Qt::endl;
-
- writeConverterFunctions(s, metaClass, classContext);
- writeClassRegister(s, metaClass, classContext, signatureStream);
-
- // class inject-code native/end
- if (!metaClass->typeEntry()->codeSnips().isEmpty()) {
- writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode, metaClass);
- s << Qt::endl;
- }
-}
-
-void CppGenerator::writeConstructorNative(QTextStream &s, const AbstractMetaFunction *func)
-{
- Indentation indentation(INDENT);
- s << functionSignature(func, wrapperName(func->ownerClass()) + QLatin1String("::"), QString(),
- OriginalTypeDescription | SkipDefaultValues);
- s << " : ";
- writeFunctionCall(s, func);
- s << "\n{\n";
- const AbstractMetaArgument *lastArg = func->arguments().isEmpty() ? nullptr : func->arguments().constLast();
- writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode, func, lastArg);
- s << INDENT << "// ... middle\n";
- writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode, func, lastArg);
- s << "}\n\n";
-}
-
-void CppGenerator::writeDestructorNative(QTextStream &s, const AbstractMetaClass *metaClass)
-{
- Indentation indentation(INDENT);
- s << wrapperName(metaClass) << "::~" << wrapperName(metaClass) << "()\n{\n";
- // kill pyobject
- s << INDENT << "SbkObject *wrapper = Shiboken::BindingManager::instance().retrieveWrapper(this);\n";
- s << INDENT << "Shiboken::Object::destroy(wrapper, this);\n";
- s << "}\n";
-}
-
-static bool allArgumentsRemoved(const AbstractMetaFunction *func)
-{
- if (func->arguments().isEmpty())
- return false;
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (const AbstractMetaArgument *arg : arguments) {
- if (!func->argumentRemoved(arg->argumentIndex() + 1))
- return false;
- }
- return true;
-}
-
-QString CppGenerator::getVirtualFunctionReturnTypeName(const AbstractMetaFunction *func)
-{
- if (!func->type())
- return QLatin1String("\"\"");
-
- if (!func->typeReplaced(0).isEmpty())
- return QLatin1Char('"') + func->typeReplaced(0) + QLatin1Char('"');
-
- // SbkType would return null when the type is a container.
- if (func->type()->typeEntry()->isContainer()) {
- return QLatin1Char('"')
- + reinterpret_cast<const ContainerTypeEntry *>(func->type()->typeEntry())->typeName()
- + QLatin1Char('"');
- }
-
- if (avoidProtectedHack()) {
- const AbstractMetaEnum *metaEnum = findAbstractMetaEnum(func->type());
- if (metaEnum && metaEnum->isProtected())
- return QLatin1Char('"') + protectedEnumSurrogateName(metaEnum) + QLatin1Char('"');
- }
-
- if (func->type()->isPrimitive())
- return QLatin1Char('"') + func->type()->name() + QLatin1Char('"');
-
- return QString::fromLatin1("reinterpret_cast<PyTypeObject *>(Shiboken::SbkType< %1 >())->tp_name").arg(func->type()->typeEntry()->qualifiedCppName());
-}
-
-void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFunction *func)
-{
- //skip metaObject function, this will be written manually ahead
- if (usePySideExtensions() && func->ownerClass() && func->ownerClass()->isQObject() &&
- ((func->name() == QLatin1String("metaObject")) || (func->name() == QLatin1String("qt_metacall"))))
- return;
-
- const TypeEntry *retType = func->type() ? func->type()->typeEntry() : nullptr;
- const QString funcName = func->isOperatorOverload() ? pythonOperatorFunctionName(func) : func->name();
-
- QString prefix = wrapperName(func->ownerClass()) + QLatin1String("::");
- s << functionSignature(func, prefix, QString(), Generator::SkipDefaultValues|Generator::OriginalTypeDescription)
- << "\n{\n";
-
- Indentation indentation(INDENT);
-
- DefaultValue defaultReturnExpr;
- if (retType) {
- const FunctionModificationList &mods = func->modifications();
- for (const FunctionModification &mod : mods) {
- for (const ArgumentModification &argMod : mod.argument_mods) {
- if (argMod.index == 0 && !argMod.replacedDefaultExpression.isEmpty()) {
- static const QRegularExpression regex(QStringLiteral("%(\\d+)"));
- Q_ASSERT(regex.isValid());
- QString expr = argMod.replacedDefaultExpression;
- for (int offset = 0; ; ) {
- const QRegularExpressionMatch match = regex.match(expr, offset);
- if (!match.hasMatch())
- break;
- const int argId = match.capturedRef(1).toInt() - 1;
- if (argId < 0 || argId > func->arguments().count()) {
- qCWarning(lcShiboken) << "The expression used in return value contains an invalid index.";
- break;
- }
- expr.replace(match.captured(0), func->arguments().at(argId)->name());
- offset = match.capturedStart(1);
- }
- defaultReturnExpr.setType(DefaultValue::Custom);
- defaultReturnExpr.setValue(expr);
- }
- }
- }
- if (!defaultReturnExpr.isValid())
- defaultReturnExpr = minimalConstructor(func->type());
- if (!defaultReturnExpr.isValid()) {
- QString errorMsg = QLatin1String(__FUNCTION__) + QLatin1String(": ");
- if (const AbstractMetaClass *c = func->implementingClass())
- errorMsg += c->qualifiedCppName() + QLatin1String("::");
- errorMsg += func->signature();
- errorMsg = msgCouldNotFindMinimalConstructor(errorMsg, func->type()->cppSignature());
- qCWarning(lcShiboken).noquote().nospace() << errorMsg;
- s << Qt::endl << INDENT << "#error " << errorMsg << Qt::endl;
- }
- } else {
- defaultReturnExpr.setType(DefaultValue::Void);
- }
-
- if (func->isAbstract() && func->isModifiedRemoved()) {
- qCWarning(lcShiboken).noquote().nospace()
- << QString::fromLatin1("Pure virtual method '%1::%2' must be implement but was "\
- "completely removed on type system.")
- .arg(func->ownerClass()->name(), func->minimalSignature());
- s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << Qt::endl;
- s << "}\n\n";
- return;
- }
-
- //Write declaration/native injected code
- if (func->hasInjectedCode()) {
- CodeSnipList snips = func->injectedCodeSnips();
- const AbstractMetaArgument *lastArg = func->arguments().isEmpty() ? nullptr : func->arguments().constLast();
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionDeclaration, TypeSystem::NativeCode, func, lastArg);
- s << Qt::endl;
- }
-
- s << INDENT << "Shiboken::GilState gil;\n";
-
- // Get out of virtual method call if someone already threw an error.
- s << INDENT << "if (PyErr_Occurred())\n";
- {
- Indentation indentation(INDENT);
- s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << Qt::endl;
- }
-
- s << INDENT << "Shiboken::AutoDecRef " << PYTHON_OVERRIDE_VAR << "(Shiboken::BindingManager::instance().getOverride(this, \"";
- s << funcName << "\"));\n";
-
- s << INDENT << "if (" << PYTHON_OVERRIDE_VAR << ".isNull()) {\n";
- {
- Indentation indentation(INDENT);
- CodeSnipList snips;
- if (func->hasInjectedCode()) {
- snips = func->injectedCodeSnips();
- const AbstractMetaArgument *lastArg = func->arguments().isEmpty() ? nullptr : func->arguments().constLast();
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::ShellCode, func, lastArg);
- s << Qt::endl;
- }
-
- if (func->isAbstract()) {
- s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '";
- s << func->ownerClass()->name() << '.' << funcName;
- s << "()' not implemented.\");\n";
- s << INDENT << "return";
- if (retType)
- s << ' ' << defaultReturnExpr.returnValue();
- } else {
- s << INDENT << "gil.release();\n";
- s << INDENT;
- if (retType)
- s << "return ";
- s << "this->::" << func->implementingClass()->qualifiedCppName() << "::";
- writeFunctionCall(s, func, Generator::VirtualCall);
- if (!retType)
- s << ";\n" << INDENT << "return";
- }
- }
- s << ";\n";
- s << INDENT<< "}\n\n";
-
- writeConversionRule(s, func, TypeSystem::TargetLangCode);
-
- s << INDENT << "Shiboken::AutoDecRef " << PYTHON_ARGS << "(";
-
- if (func->arguments().isEmpty() || allArgumentsRemoved(func)) {
- s << "PyTuple_New(0));\n";
- } else {
- QStringList argConversions;
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (const AbstractMetaArgument *arg : arguments) {
- if (func->argumentRemoved(arg->argumentIndex() + 1))
- continue;
-
- QString argConv;
- QTextStream ac(&argConv);
- auto argType = static_cast<const PrimitiveTypeEntry *>(arg->type()->typeEntry());
- bool convert = argType->isObject()
- || argType->isValue()
- || arg->type()->isValuePointer()
- || arg->type()->isNativePointer()
- || argType->isFlags()
- || argType->isEnum()
- || argType->isContainer()
- || arg->type()->referenceType() == LValueReference;
-
- if (!convert && argType->isPrimitive()) {
- if (argType->basicReferencedTypeEntry())
- argType = argType->basicReferencedTypeEntry();
- convert = !m_formatUnits.contains(argType->name());
- }
-
- Indentation indentation(INDENT);
- ac << INDENT;
- if (!func->conversionRule(TypeSystem::TargetLangCode, arg->argumentIndex() + 1).isEmpty()) {
- // Has conversion rule.
- ac << arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX);
- } else {
- QString argName = arg->name();
- if (convert)
- writeToPythonConversion(ac, arg->type(), func->ownerClass(), argName);
- else
- ac << argName;
- }
-
- argConversions << argConv;
- }
-
- s << "Py_BuildValue(\"(" << getFormatUnitString(func, false) << ")\",\n";
- s << argConversions.join(QLatin1String(",\n")) << Qt::endl;
- s << INDENT << "));\n";
- }
-
- bool invalidateReturn = false;
- QSet<int> invalidateArgs;
- const FunctionModificationList &mods = func->modifications();
- for (const FunctionModification &funcMod : mods) {
- for (const ArgumentModification &argMod : funcMod.argument_mods) {
- if (argMod.resetAfterUse && !invalidateArgs.contains(argMod.index)) {
- invalidateArgs.insert(argMod.index);
- s << INDENT << "bool invalidateArg" << argMod.index;
- s << " = PyTuple_GET_ITEM(" << PYTHON_ARGS << ", " << argMod.index - 1 << ")->ob_refcnt == 1;\n";
- } else if (argMod.index == 0 && argMod.ownerships[TypeSystem::TargetLangCode] == TypeSystem::CppOwnership) {
- invalidateReturn = true;
- }
- }
- }
- s << Qt::endl;
-
- CodeSnipList snips;
- if (func->hasInjectedCode()) {
- snips = func->injectedCodeSnips();
-
- if (injectedCodeUsesPySelf(func))
- s << INDENT << "PyObject *pySelf = BindingManager::instance().retrieveWrapper(this);\n";
-
- const AbstractMetaArgument *lastArg = func->arguments().isEmpty() ? nullptr : func->arguments().constLast();
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode, func, lastArg);
- s << Qt::endl;
- }
-
- if (!injectedCodeCallsPythonOverride(func)) {
- s << INDENT;
- s << "Shiboken::AutoDecRef " << PYTHON_RETURN_VAR << "(PyObject_Call("
- << PYTHON_OVERRIDE_VAR << ", " << PYTHON_ARGS << ", nullptr));\n";
-
- s << INDENT << "// An error happened in python code!\n";
- s << INDENT << "if (" << PYTHON_RETURN_VAR << ".isNull()) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "PyErr_Print();\n";
- s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << Qt::endl;
- }
- s << INDENT << "}\n";
-
- if (retType) {
- if (invalidateReturn)
- s << INDENT << "bool invalidateArg0 = " << PYTHON_RETURN_VAR << "->ob_refcnt == 1;\n";
-
- if (func->typeReplaced(0) != QLatin1String("PyObject")) {
-
- s << INDENT << "// Check return type\n";
- s << INDENT;
- if (func->typeReplaced(0).isEmpty()) {
- s << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << " = " << cpythonIsConvertibleFunction(func->type());
- s << PYTHON_RETURN_VAR << ");\n";
- s << INDENT << "if (!" << PYTHON_TO_CPP_VAR << ") {\n";
- {
- 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 << ", Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);\n";
- s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << Qt::endl;
- }
- s << INDENT << "}\n";
-
- } else {
-
- s << INDENT << "// Check return type\n";
- s << INDENT << "bool typeIsValid = ";
- writeTypeCheck(s, func->type(), QLatin1String(PYTHON_RETURN_VAR),
- isNumber(func->type()->typeEntry()), func->typeReplaced(0));
- s << ";\n";
- s << INDENT << "if (!typeIsValid";
- if (isPointerToWrapperType(func->type()))
- s << " && " << PYTHON_RETURN_VAR << " != Py_None";
- s << ") {\n";
- {
- 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 << ", Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);\n";
- s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << Qt::endl;
- }
- s << INDENT << "}\n";
-
- }
- }
-
- if (!func->conversionRule(TypeSystem::NativeCode, 0).isEmpty()) {
- // Has conversion rule.
- writeConversionRule(s, func, TypeSystem::NativeCode, QLatin1String(CPP_RETURN_VAR));
- } else if (!injectedCodeHasReturnValueAttribution(func, TypeSystem::NativeCode)) {
- writePythonToCppTypeConversion(s, func->type(), QLatin1String(PYTHON_RETURN_VAR),
- QLatin1String(CPP_RETURN_VAR), func->implementingClass());
- }
- }
- }
-
- if (invalidateReturn) {
- s << INDENT << "if (invalidateArg0)\n";
- Indentation indentation(INDENT);
- s << INDENT << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR << ".object());\n";
- }
- for (int argIndex : qAsConst(invalidateArgs)) {
- s << INDENT << "if (invalidateArg" << argIndex << ")\n";
- Indentation indentation(INDENT);
- s << INDENT << "Shiboken::Object::invalidate(PyTuple_GET_ITEM(" << PYTHON_ARGS << ", ";
- s << (argIndex - 1) << "));\n";
- }
-
-
- const FunctionModificationList &funcMods = func->modifications();
- for (const FunctionModification &funcMod : funcMods) {
- for (const ArgumentModification &argMod : funcMod.argument_mods) {
- if (argMod.ownerships.contains(TypeSystem::NativeCode)
- && argMod.index == 0 && argMod.ownerships[TypeSystem::NativeCode] == TypeSystem::CppOwnership) {
- s << INDENT << "if (Shiboken::Object::checkType(" << PYTHON_RETURN_VAR << "))\n";
- Indentation indent(INDENT);
- s << INDENT << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR << ");\n";
- }
- }
- }
-
- if (func->hasInjectedCode()) {
- s << Qt::endl;
- const AbstractMetaArgument *lastArg = func->arguments().isEmpty() ? nullptr : func->arguments().constLast();
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode, func, lastArg);
- }
-
- if (retType) {
- s << INDENT << "return ";
- if (avoidProtectedHack() && retType->isEnum()) {
- const AbstractMetaEnum *metaEnum = findAbstractMetaEnum(retType);
- bool isProtectedEnum = metaEnum && metaEnum->isProtected();
- if (isProtectedEnum) {
- QString typeCast;
- if (metaEnum->enclosingClass())
- typeCast += QLatin1String("::") + metaEnum->enclosingClass()->qualifiedCppName();
- typeCast += QLatin1String("::") + metaEnum->name();
- s << '(' << typeCast << ')';
- }
- }
- if (func->type()->referenceType() == LValueReference && !isPointer(func->type()))
- s << " *";
- s << CPP_RETURN_VAR << ";\n";
- }
-
- s<< "}\n\n";
-}
-
-void CppGenerator::writeMetaObjectMethod(QTextStream &s, const AbstractMetaClass *metaClass)
-{
- Indentation indentation(INDENT);
- QString wrapperClassName = wrapperName(metaClass);
- s << "const QMetaObject *" << wrapperClassName << "::metaObject() const\n{\n";
- s << INDENT << "if (QObject::d_ptr->metaObject)\n"
- << INDENT << INDENT << "return QObject::d_ptr->dynamicMetaObject();\n";
- s << INDENT << "SbkObject *pySelf = Shiboken::BindingManager::instance().retrieveWrapper(this);\n";
- s << INDENT << "if (pySelf == nullptr)\n";
- s << INDENT << INDENT << "return " << metaClass->qualifiedCppName() << "::metaObject();\n";
- s << INDENT << "return PySide::SignalManager::retrieveMetaObject(reinterpret_cast<PyObject *>(pySelf));\n";
- s<< "}\n\n";
-
- // qt_metacall function
- s << "int " << wrapperClassName << "::qt_metacall(QMetaObject::Call call, int id, void **args)\n";
- s << "{\n";
-
- AbstractMetaFunction *func = nullptr;
- AbstractMetaFunctionList list = metaClass->queryFunctionsByName(QLatin1String("qt_metacall"));
- if (list.size() == 1)
- func = list[0];
-
- CodeSnipList snips;
- if (func) {
- snips = func->injectedCodeSnips();
- if (func->isUserAdded()) {
- CodeSnipList snips = func->injectedCodeSnips();
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::NativeCode, func);
- }
- }
-
- s << INDENT << "int result = " << metaClass->qualifiedCppName() << "::qt_metacall(call, id, args);\n";
- s << INDENT << "return result < 0 ? result : PySide::SignalManager::qt_metacall(this, call, id, args);\n";
- s << "}\n\n";
-
- // 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)\n{\n";
- s << INDENT << "if (!_clname) return {};\n";
- s << INDENT << "SbkObject *pySelf = Shiboken::BindingManager::instance().retrieveWrapper(this);\n";
- s << INDENT << "if (pySelf && PySide::inherits(Py_TYPE(pySelf), _clname))\n";
- s << INDENT << INDENT << "return static_cast<void *>(const_cast< " << wrapperClassName << " *>(this));\n";
- s << INDENT << "return " << metaClass->qualifiedCppName() << "::qt_metacast(_clname);\n";
- s << "}\n\n";
-}
-
-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 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 << "*reinterpret_cast<" << cppTypeName << " *>(cppOut) =\n"
- << INDENT << " ";
- if (enumType->isFlags())
- c << cppTypeName << "(QFlag(int(PySide::QFlags::getValue(reinterpret_cast<PySideQFlagsObject *>(pyIn)))))";
- else
- c << "static_cast<" << cppTypeName << ">(Shiboken::Enum::getValue(pyIn))";
- c << ";\n";
- writePythonToCppFunction(s, code, typeName, typeName);
-
- QString pyTypeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, %1)").arg(enumPythonType);
- writeIsPythonConvertibleToCppFunction(s, typeName, typeName, pyTypeCheck);
-
- code.clear();
-
- c << INDENT << "const int castCppIn = int(*reinterpret_cast<const "
- << cppTypeName << " *>(cppIn));\n";
- c << INDENT;
- c << "return ";
- if (enumType->isFlags()) {
- c << "reinterpret_cast<PyObject *>(PySide::QFlags::newObject(castCppIn, "
- << enumPythonType << "))";
- } else {
- c << "Shiboken::Enum::newItem(" << enumPythonType << ", castCppIn)";
- }
- c << ";\n";
- writeCppToPythonFunction(s, code, typeName, typeName);
- s << Qt::endl;
-
- if (enumType->isFlags())
- return;
-
- auto flags = reinterpret_cast<const EnumTypeEntry *>(enumType)->flags();
- if (!flags)
- return;
-
- // QFlags part.
-
- writeEnumConverterFunctions(s, flags);
-
- code.clear();
- cppTypeName = getFullTypeName(flags).trimmed();
- c << INDENT << "*reinterpret_cast<" << cppTypeName << " *>(cppOut) =\n"
- << INDENT << " " << cppTypeName
- << "(QFlag(int(Shiboken::Enum::getValue(pyIn))));\n";
-
- QString flagsTypeName = fixedCppTypeName(flags);
- writePythonToCppFunction(s, code, typeName, flagsTypeName);
- writeIsPythonConvertibleToCppFunction(s, typeName, flagsTypeName, pyTypeCheck);
-
- code.clear();
- c << INDENT << "Shiboken::AutoDecRef pyLong(PyNumber_Long(pyIn));\n";
- c << INDENT << "*reinterpret_cast<" << cppTypeName << " *>(cppOut) =\n"
- << INDENT << " " << cppTypeName
- << "(QFlag(int(PyLong_AsLong(pyLong.object()))));\n";
- // PYSIDE-898: Include an additional condition to detect if the type of the
- // enum corresponds to the object that is being evaluated.
- // Using only `PyNumber_Check(...)` is too permissive,
- // then we would have been unable to detect the difference between
- // a PolarOrientation and Qt::AlignmentFlag, which was the main
- // issue of the bug.
- const QString numberCondition = QStringLiteral("PyNumber_Check(pyIn) && ") + pyTypeCheck;
- writePythonToCppFunction(s, code, QLatin1String("number"), flagsTypeName);
- writeIsPythonConvertibleToCppFunction(s, QLatin1String("number"), flagsTypeName, numberCondition);
-
-
-}
-
-void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaClass *metaClass,
- GeneratorContext &classContext)
-{
- s << "// Type conversion functions.\n\n";
-
- AbstractMetaEnumList classEnums = metaClass->enums();
- const AbstractMetaClassList &innerClasses = metaClass->innerClasses();
- for (AbstractMetaClass *innerClass : innerClasses)
- lookForEnumsInClassesNotToBeGenerated(classEnums, innerClass);
- if (!classEnums.isEmpty())
- s << "// Python to C++ enum conversion.\n";
- for (const AbstractMetaEnum *metaEnum : qAsConst(classEnums))
- writeEnumConverterFunctions(s, metaEnum);
-
- if (metaClass->isNamespace())
- return;
-
- QString typeName;
- if (!classContext.forSmartPointer())
- typeName = getFullTypeName(metaClass);
- else
- typeName = getFullTypeName(classContext.preciseType());
-
- QString cpythonType = cpythonTypeName(metaClass);
-
- // Returns the C++ pointer of the Python wrapper.
- s << "// Python to C++ pointer conversion - returns the C++ object of the Python wrapper (keeps object identity).\n";
-
- QString sourceTypeName = metaClass->name();
- QString targetTypeName = metaClass->name() + QLatin1String("_PTR");
- QString code;
- QTextStream c(&code);
- c << INDENT << "Shiboken::Conversions::pythonToCppPointer(" << cpythonType << ", pyIn, cppOut);";
- writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
-
- // "Is convertible" function for the Python object to C++ pointer conversion.
- const QString pyTypeCheck = QLatin1String("PyObject_TypeCheck(pyIn, reinterpret_cast<PyTypeObject *>(")
- + cpythonType + QLatin1String("))");
- writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, pyTypeCheck, QString(), true);
- s << Qt::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).\n";
- code.clear();
- if (usePySideExtensions() && metaClass->isQObject())
- {
- c << INDENT << "return PySide::getWrapperForQObject(reinterpret_cast<"
- << typeName << " *>(const_cast<void *>(cppIn)), " << cpythonType << ");\n";
- } else {
- c << INDENT << "auto pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(cppIn));\n";
- c << INDENT << "if (pyOut) {\n";
- {
- Indentation indent(INDENT);
- c << INDENT << "Py_INCREF(pyOut);\n";
- c << INDENT << "return pyOut;\n";
- }
- c << INDENT << "}\n";
- c << INDENT << "bool changedTypeName = false;\n"
- << INDENT << "auto tCppIn = reinterpret_cast<const " << typeName << " *>(cppIn);\n"
- << INDENT << "const char *typeName = typeid(*tCppIn).name();\n"
- << INDENT << "auto sbkType = Shiboken::ObjectType::typeForTypeName(typeName);\n"
- << INDENT << "if (sbkType && Shiboken::ObjectType::hasSpecialCastFunction(sbkType)) {\n"
- << INDENT << " typeName = typeNameOf(tCppIn);\n"
- << INDENT << " changedTypeName = true;\n"
- << INDENT << " }\n"
- << INDENT << "PyObject *result = Shiboken::Object::newObject(" << cpythonType
- << ", const_cast<void *>(cppIn), false, /* exactType */ changedTypeName, typeName);\n"
- << INDENT << "if (changedTypeName)\n"
- << INDENT << " delete [] typeName;\n"
- << INDENT << "return result;";
- }
- std::swap(targetTypeName, sourceTypeName);
- writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName);
-
- // The conversions for an Object Type end here.
- if (!metaClass->typeEntry()->isValue() && !metaClass->typeEntry()->isSmartPointer()) {
- s << Qt::endl;
- return;
- }
-
- // Always copies C++ value (not pointer, and not reference) to a new Python wrapper.
- s << Qt::endl << "// C++ to Python copy conversion.\n";
- if (!classContext.forSmartPointer())
- targetTypeName = metaClass->name();
- else
- targetTypeName = classContext.preciseType()->name();
-
- sourceTypeName = targetTypeName + QLatin1String("_COPY");
-
- code.clear();
-
- QString computedWrapperName;
- if (!classContext.forSmartPointer())
- computedWrapperName = wrapperName(metaClass);
- else
- computedWrapperName = wrapperName(classContext.preciseType());
-
- c << INDENT << "return Shiboken::Object::newObject(" << cpythonType
- << ", new ::" << computedWrapperName << "(*reinterpret_cast<const "
- << typeName << " *>(cppIn)), true, true);";
- writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName);
- s << Qt::endl;
-
- // Python to C++ copy conversion.
- s << "// Python to C++ copy conversion.\n";
- if (!classContext.forSmartPointer())
- sourceTypeName = metaClass->name();
- else
- sourceTypeName = classContext.preciseType()->name();
-
- targetTypeName = QStringLiteral("%1_COPY").arg(sourceTypeName);
- code.clear();
-
- QString pyInVariable = QLatin1String("pyIn");
- QString wrappedCPtrExpression;
- if (!classContext.forSmartPointer())
- wrappedCPtrExpression = cpythonWrapperCPtr(metaClass->typeEntry(), pyInVariable);
- else
- wrappedCPtrExpression = cpythonWrapperCPtr(classContext.preciseType(), pyInVariable);
-
- c << INDENT << "*reinterpret_cast<" << typeName << " *>(cppOut) = *"
- << wrappedCPtrExpression << ';';
- writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
-
- // "Is convertible" function for the Python object to C++ value copy conversion.
- writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, pyTypeCheck);
- s << Qt::endl;
-
- // User provided implicit conversions.
- CustomConversion *customConversion = metaClass->typeEntry()->customConversion();
-
- // Implicit conversions.
- AbstractMetaFunctionList implicitConvs;
- if (!customConversion || !customConversion->replaceOriginalTargetToNativeConversions()) {
- const AbstractMetaFunctionList &allImplicitConvs = implicitConversions(metaClass->typeEntry());
- for (AbstractMetaFunction *func : allImplicitConvs) {
- if (!func->isUserAdded())
- implicitConvs << func;
- }
- }
-
- if (!implicitConvs.isEmpty())
- s << "// Implicit conversions.\n";
-
- AbstractMetaType *targetType = buildAbstractMetaTypeFromAbstractMetaClass(metaClass);
- for (const AbstractMetaFunction *conv : qAsConst(implicitConvs)) {
- if (conv->isModifiedRemoved())
- continue;
-
- QString typeCheck;
- QString toCppConv;
- QString toCppPreConv;
- if (conv->isConversionOperator()) {
- const AbstractMetaClass *sourceClass = conv->ownerClass();
- typeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, %1)").arg(cpythonTypeNameExt(sourceClass->typeEntry()));
- toCppConv = QLatin1Char('*') + cpythonWrapperCPtr(sourceClass->typeEntry(), QLatin1String("pyIn"));
- } else {
- // Constructor that does implicit conversion.
- if (!conv->typeReplaced(1).isEmpty() || conv->isModifiedToArray(1))
- continue;
- const AbstractMetaType *sourceType = conv->arguments().constFirst()->type();
- typeCheck = cpythonCheckFunction(sourceType);
- bool isUserPrimitiveWithoutTargetLangName = isUserPrimitive(sourceType)
- && sourceType->typeEntry()->targetLangApiName() == sourceType->typeEntry()->name();
- if (!isWrapperType(sourceType)
- && !isUserPrimitiveWithoutTargetLangName
- && !sourceType->typeEntry()->isEnum()
- && !sourceType->typeEntry()->isFlags()
- && !sourceType->typeEntry()->isContainer()) {
- typeCheck += QLatin1Char('(');
- }
- if (isWrapperType(sourceType)) {
- typeCheck += QLatin1String("pyIn)");
- toCppConv = (sourceType->referenceType() == LValueReference || !isPointerToWrapperType(sourceType))
- ? QLatin1String(" *") : QString();
- toCppConv += cpythonWrapperCPtr(sourceType->typeEntry(), QLatin1String("pyIn"));
- } else if (typeCheck.contains(QLatin1String("%in"))) {
- typeCheck.replace(QLatin1String("%in"), QLatin1String("pyIn"));
- typeCheck.append(QLatin1Char(')'));
- } else {
- typeCheck += QLatin1String("pyIn)");
- }
-
- if (isUserPrimitive(sourceType)
- || isCppPrimitive(sourceType)
- || sourceType->typeEntry()->isContainer()
- || sourceType->typeEntry()->isEnum()
- || sourceType->typeEntry()->isFlags()) {
- QTextStream pc(&toCppPreConv);
- pc << INDENT << getFullTypeNameWithoutModifiers(sourceType) << " cppIn";
- writeMinimalConstructorExpression(pc, sourceType);
- pc << ";\n";
- writeToCppConversion(pc, sourceType, nullptr, QLatin1String("pyIn"), QLatin1String("cppIn"));
- pc << ';';
- toCppConv.append(QLatin1String("cppIn"));
- } else if (!isWrapperType(sourceType)) {
- QTextStream tcc(&toCppConv);
- writeToCppConversion(tcc, sourceType, metaClass, QLatin1String("pyIn"), QLatin1String("/*BOZO-1061*/"));
- }
-
-
- }
- const AbstractMetaType *sourceType = conv->isConversionOperator()
- ? buildAbstractMetaTypeFromAbstractMetaClass(conv->ownerClass())
- : conv->arguments().constFirst()->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() << "'.\n";
- for (CustomConversion::TargetToNativeConversion *toNative : toCppConversions)
- writePythonToCppConversionFunctions(s, toNative, customConversion->ownerType());
- s << Qt::endl;
-}
-
-void CppGenerator::writeConverterRegister(QTextStream &s, const AbstractMetaClass *metaClass,
- GeneratorContext &classContext)
-{
- if (metaClass->isNamespace())
- return;
- s << INDENT << "// Register Converter\n";
- s << INDENT << "SbkConverter *converter = Shiboken::Conversions::createConverter(";
- s << cpythonTypeName(metaClass) << ',' << Qt::endl;
- {
- Indentation indent(INDENT);
- QString sourceTypeName = metaClass->name();
- QString targetTypeName = sourceTypeName + QLatin1String("_PTR");
- s << INDENT << pythonToCppFunctionName(sourceTypeName, targetTypeName) << ',' << Qt::endl;
- s << INDENT << convertibleToCppFunctionName(sourceTypeName, targetTypeName) << ',' << Qt::endl;
- std::swap(targetTypeName, sourceTypeName);
- s << INDENT << cppToPythonFunctionName(sourceTypeName, targetTypeName);
- if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) {
- s << ',' << Qt::endl;
- sourceTypeName = metaClass->name() + QLatin1String("_COPY");
- s << INDENT << cppToPythonFunctionName(sourceTypeName, targetTypeName);
- }
- }
- s << ");\n";
-
- s << Qt::endl;
-
- QStringList cppSignature;
- if (!classContext.forSmartPointer()) {
- cppSignature = metaClass->qualifiedCppName().split(QLatin1String("::"),
- QString::SkipEmptyParts);
- } else {
- cppSignature = classContext.preciseType()->cppSignature().split(QLatin1String("::"),
- QString::SkipEmptyParts);
- }
- while (!cppSignature.isEmpty()) {
- QString signature = cppSignature.join(QLatin1String("::"));
- s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "\");\n";
- s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "*\");\n";
- s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "&\");\n";
- cppSignature.removeFirst();
- }
-
- s << INDENT << "Shiboken::Conversions::registerConverterName(converter, typeid(::";
- QString qualifiedCppNameInvocation;
- if (!classContext.forSmartPointer())
- qualifiedCppNameInvocation = metaClass->qualifiedCppName();
- else
- qualifiedCppNameInvocation = classContext.preciseType()->cppSignature();
-
- s << qualifiedCppNameInvocation << ").name());\n";
-
- if (shouldGenerateCppWrapper(metaClass)) {
- s << INDENT << "Shiboken::Conversions::registerConverterName(converter, typeid(::";
- s << wrapperName(metaClass) << ").name());\n";
- }
-
- s << Qt::endl;
-
- if (!metaClass->typeEntry()->isValue() && !metaClass->typeEntry()->isSmartPointer())
- return;
-
- // Python to C++ copy (value, not pointer neither reference) conversion.
- s << INDENT << "// Add Python to C++ copy (value, not pointer neither reference) conversion to type converter.\n";
- QString sourceTypeName = metaClass->name();
- QString targetTypeName = sourceTypeName + QLatin1String("_COPY");
- QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName);
- QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName);
- writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
-
- // User provided implicit conversions.
- CustomConversion *customConversion = metaClass->typeEntry()->customConversion();
-
- // Add implicit conversions.
- AbstractMetaFunctionList implicitConvs;
- if (!customConversion || !customConversion->replaceOriginalTargetToNativeConversions()) {
- const AbstractMetaFunctionList &allImplicitConvs = implicitConversions(metaClass->typeEntry());
- for (AbstractMetaFunction *func : allImplicitConvs) {
- if (!func->isUserAdded())
- implicitConvs << func;
- }
- }
-
- if (!implicitConvs.isEmpty())
- s << INDENT << "// Add implicit conversions to type converter.\n";
-
- AbstractMetaType *targetType = buildAbstractMetaTypeFromAbstractMetaClass(metaClass);
- for (const AbstractMetaFunction *conv : qAsConst(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() || conv->isModifiedToArray(1))
- continue;
- sourceType = conv->arguments().constFirst()->type();
- }
- QString toCpp = pythonToCppFunctionName(sourceType, targetType);
- QString isConv = convertibleToCppFunctionName(sourceType, targetType);
- writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
- }
-
- writeCustomConverterRegister(s, customConversion, QLatin1String("converter"));
-}
-
-void CppGenerator::writeCustomConverterRegister(QTextStream &s, const CustomConversion *customConversion, const QString &converterVar)
-{
- if (!customConversion)
- return;
- const CustomConversion::TargetToNativeConversions &toCppConversions = customConversion->targetToNativeConversions();
- if (toCppConversions.isEmpty())
- return;
- s << INDENT << "// Add user defined implicit conversions to type converter.\n";
- for (CustomConversion::TargetToNativeConversion *toNative : toCppConversions) {
- QString toCpp = pythonToCppFunctionName(toNative, customConversion->ownerType());
- QString isConv = convertibleToCppFunctionName(toNative, customConversion->ownerType());
- writeAddPythonToCppConversion(s, converterVar, toCpp, isConv);
- }
-}
-
-void CppGenerator::writeContainerConverterFunctions(QTextStream &s, const AbstractMetaType *containerType)
-{
- writeCppToPythonFunction(s, containerType);
- writePythonToCppConversionFunctions(s, containerType);
-}
-
-void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &overloadData,
- GeneratorContext &context)
-{
- const AbstractMetaFunction *rfunc = overloadData.referenceFunction();
- const AbstractMetaClass *ownerClass = rfunc->ownerClass();
- int minArgs = overloadData.minArgs();
- int maxArgs = overloadData.maxArgs();
- bool initPythonArguments;
- bool usesNamedArguments;
-
- // If method is a constructor...
- if (rfunc->isConstructor()) {
- // Check if the right constructor was called.
- if (!ownerClass->hasPrivateDestructor()) {
- s << INDENT;
- s << "if (Shiboken::Object::isUserType(self) && !Shiboken::ObjectType::canCallConstructor(self->ob_type, Shiboken::SbkType< ::";
- QString qualifiedCppName;
- if (!context.forSmartPointer())
- qualifiedCppName = ownerClass->qualifiedCppName();
- else
- qualifiedCppName = context.preciseType()->cppSignature();
-
- s << qualifiedCppName << " >()))\n";
- Indentation indent(INDENT);
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl << Qt::endl;
- }
- // Declare pointer for the underlying C++ object.
- s << INDENT << "::";
- if (!context.forSmartPointer()) {
- s << (shouldGenerateCppWrapper(ownerClass) ? wrapperName(ownerClass)
- : ownerClass->qualifiedCppName());
- } else {
- s << context.preciseType()->cppSignature();
- }
- s << " *cptr{};\n";
-
- initPythonArguments = maxArgs > 0;
- usesNamedArguments = !ownerClass->isQObject() && overloadData.hasArgumentWithDefaultValue();
-
- } else {
- if (rfunc->implementingClass() &&
- (!rfunc->implementingClass()->isNamespace() && overloadData.hasInstanceFunction())) {
- writeCppSelfDefinition(s, rfunc, context, overloadData.hasStaticFunction());
- }
- if (!rfunc->isInplaceOperator() && overloadData.hasNonVoidReturnType())
- s << INDENT << "PyObject *" << PYTHON_RETURN_VAR << "{};\n";
-
- initPythonArguments = minArgs != maxArgs || maxArgs > 1;
- usesNamedArguments = rfunc->isCallOperator() || overloadData.hasArgumentWithDefaultValue();
- }
-
- if (maxArgs > 0) {
- s << INDENT << "int overloadId = -1;\n";
- s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR;
- if (pythonFunctionWrapperUsesListOfArguments(overloadData)) {
- s << "[] = { " << NULL_PTR;
- for (int i = 1; i < maxArgs; ++i)
- s << ", " << NULL_PTR;
- s << " };\n";
- } else {
- s << "{};\n";
- }
- writeUnusedVariableCast(s, QLatin1String(PYTHON_TO_CPP_VAR));
- }
-
- if (usesNamedArguments && !rfunc->isCallOperator())
- s << INDENT << "int numNamedArgs = (kwds ? PyDict_Size(kwds) : 0);\n";
-
- if (initPythonArguments) {
- s << INDENT << "int numArgs = ";
- if (minArgs == 0 && maxArgs == 1 && !rfunc->isConstructor() && !pythonFunctionWrapperUsesListOfArguments(overloadData))
- s << "(" << PYTHON_ARG << " == 0 ? 0 : 1);\n";
- else
- writeArgumentsInitializer(s, overloadData);
- }
-}
-
-void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFunctionList &overloads,
- GeneratorContext &classContext)
-{
- ErrorCode errorCode(-1);
- OverloadData overloadData(overloads, this);
-
- const AbstractMetaFunction *rfunc = overloadData.referenceFunction();
- const AbstractMetaClass *metaClass = rfunc->ownerClass();
-
- s << "static int\n";
- s << cpythonFunctionName(rfunc) << "(PyObject *self, PyObject *args, PyObject *kwds)\n{\n";
-
- QSet<QString> argNamesSet;
- if (usePySideExtensions() && metaClass->isQObject()) {
- // Write argNames variable with all known argument names.
- const OverloadData::MetaFunctionList &overloads = overloadData.overloads();
- for (const AbstractMetaFunction *func : overloads) {
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (const AbstractMetaArgument *arg : arguments) {
- if (arg->defaultValueExpression().isEmpty() || func->argumentRemoved(arg->argumentIndex() + 1))
- continue;
- argNamesSet << arg->name();
- }
- }
- QStringList argNamesList = argNamesSet.values();
- std::sort(argNamesList.begin(), argNamesList.end());
- if (argNamesList.isEmpty()) {
- s << INDENT << "const char **argNames{};\n";
- } else {
- s << INDENT << "const char *argNames[] = {\""
- << argNamesList.join(QLatin1String("\", \"")) << "\"};\n";
- }
- s << INDENT << "const QMetaObject *metaObject;\n";
- }
-
- s << INDENT << "SbkObject *sbkSelf = reinterpret_cast<SbkObject *>(self);\n";
-
- if (metaClass->isAbstract() || metaClass->baseClassNames().size() > 1) {
- s << INDENT << "SbkObjectType *type = reinterpret_cast<SbkObjectType *>(self->ob_type);\n";
- s << INDENT << "SbkObjectType *myType = reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(metaClass->typeEntry()) << ");\n";
- }
-
- if (metaClass->isAbstract()) {
- s << INDENT << "if (type == myType) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "PyErr_SetString(PyExc_NotImplementedError,\n";
- {
- Indentation indentation(INDENT);
- s << INDENT << "\"'" << metaClass->qualifiedCppName();
- }
- s << "' represents a C++ abstract class and cannot be instantiated\");\n";
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
- }
- s << INDENT<< "}\n\n";
- }
-
- if (metaClass->baseClassNames().size() > 1) {
- if (!metaClass->isAbstract()) {
- s << INDENT << "if (type != myType) {\n";
- }
- {
- Indentation indentation(INDENT);
- s << INDENT << "Shiboken::ObjectType::copyMultipleInheritance(type, myType);\n";
- }
- if (!metaClass->isAbstract())
- s << INDENT<< "}\n\n";
- }
-
- writeMethodWrapperPreamble(s, overloadData, classContext);
-
- s << Qt::endl;
-
- if (overloadData.maxArgs() > 0)
- writeOverloadedFunctionDecisor(s, overloadData);
-
- writeFunctionCalls(s, overloadData, classContext);
- s << Qt::endl;
-
- s << INDENT << "if (PyErr_Occurred() || !Shiboken::Object::setCppPointer(sbkSelf, Shiboken::SbkType< ::" << metaClass->qualifiedCppName() << " >(), cptr)) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "delete cptr;\n";
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
- }
- s << INDENT << "}\n";
- if (overloadData.maxArgs() > 0) {
- s << INDENT << "if (!cptr) goto " << cpythonFunctionName(rfunc) << "_TypeError;\n";
- s << Qt::endl;
- }
-
- s << INDENT << "Shiboken::Object::setValidCpp(sbkSelf, true);\n";
- // 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.constFirst()->ownerClass()))
- s << INDENT << "Shiboken::Object::setHasCppWrapper(sbkSelf, true);\n";
- // Need to check if a wrapper for same pointer is already registered
- // Caused by bug PYSIDE-217, where deleted objects' wrappers are not released
- s << INDENT << "if (Shiboken::BindingManager::instance().hasWrapper(cptr)) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "Shiboken::BindingManager::instance().releaseWrapper(Shiboken::BindingManager::instance().retrieveWrapper(cptr));\n";
- }
- s << INDENT << "}\n";
- s << INDENT << "Shiboken::BindingManager::instance().registerWrapper(sbkSelf, cptr);\n";
-
- // Create metaObject and register signal/slot
- if (metaClass->isQObject() && usePySideExtensions()) {
- s << Qt::endl << INDENT << "// QObject setup\n";
- s << INDENT << "PySide::Signal::updateSourceObject(self);\n";
- s << INDENT << "metaObject = cptr->metaObject(); // <- init python qt properties\n";
- s << INDENT << "if (kwds && !PySide::fillQtProperties(self, metaObject, kwds, argNames, " << argNamesSet.count() << "))\n";
- {
- Indentation indentation(INDENT);
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
- }
- }
-
- // Constructor code injections, position=end
- bool hasCodeInjectionsAtEnd = false;
- for (AbstractMetaFunction *func : overloads) {
- const CodeSnipList &injectedCodeSnips = func->injectedCodeSnips();
- for (const CodeSnip &cs : injectedCodeSnips) {
- if (cs.position == TypeSystem::CodeSnipPositionEnd) {
- hasCodeInjectionsAtEnd = true;
- break;
- }
- }
- }
- if (hasCodeInjectionsAtEnd) {
- // FIXME: C++ arguments are not available in code injection on constructor when position = end.
- s << INDENT << "switch (overloadId) {\n";
- for (AbstractMetaFunction *func : overloads) {
- Indentation indent(INDENT);
- const CodeSnipList &injectedCodeSnips = func->injectedCodeSnips();
- for (const CodeSnip &cs : injectedCodeSnips) {
- if (cs.position == TypeSystem::CodeSnipPositionEnd) {
- s << INDENT << "case " << metaClass->functions().indexOf(func) << ':' << Qt::endl;
- s << INDENT << "{\n";
- {
- Indentation indent(INDENT);
- writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode, func);
- }
- s << INDENT << "}\n";
- break;
- }
- }
- }
- s << "}\n";
- }
-
- s << Qt::endl;
- s << Qt::endl << INDENT << "return 1;\n";
- if (overloadData.maxArgs() > 0)
- writeErrorSection(s, overloadData);
- s<< "}\n\n";
-}
-
-void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunctionList &overloads,
- GeneratorContext &classContext)
-{
- OverloadData overloadData(overloads, this);
- const AbstractMetaFunction *rfunc = overloadData.referenceFunction();
-
- int maxArgs = overloadData.maxArgs();
-
- s << "static PyObject *";
- s << cpythonFunctionName(rfunc) << "(PyObject *self";
- if (maxArgs > 0) {
- s << ", PyObject *" << (pythonFunctionWrapperUsesListOfArguments(overloadData) ? "args" : PYTHON_ARG);
- if (overloadData.hasArgumentWithDefaultValue() || rfunc->isCallOperator())
- s << ", PyObject *kwds";
- }
- s << ")\n{\n";
-
- writeMethodWrapperPreamble(s, overloadData, classContext);
-
- s << Qt::endl;
-
- /*
- * This code is intended for shift operations only:
- * Make sure reverse <</>> operators defined in other classes (specially from other modules)
- * are called. A proper and generic solution would require an reengineering in the operator
- * system like the extended converters.
- *
- * Solves #119 - QDataStream <</>> operators not working for QPixmap
- * http://bugs.openbossa.org/show_bug.cgi?id=119
- */
- bool hasReturnValue = overloadData.hasNonVoidReturnType();
- bool callExtendedReverseOperator = hasReturnValue
- && !rfunc->isInplaceOperator()
- && !rfunc->isCallOperator()
- && rfunc->isOperatorOverload();
- if (callExtendedReverseOperator) {
- QString revOpName = ShibokenGenerator::pythonOperatorFunctionName(rfunc).insert(2, QLatin1Char('r'));
- // For custom classes, operations like __radd__ and __rmul__
- // will enter an infinite loop.
- if (rfunc->isBinaryOperator() && revOpName.contains(QLatin1String("shift"))) {
- s << INDENT << "Shiboken::AutoDecRef attrName(Py_BuildValue(\"s\", \"" << revOpName << "\"));\n";
- s << INDENT << "if (!isReverse\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "&& Shiboken::Object::checkType(" << PYTHON_ARG << ")\n";
- s << INDENT << "&& !PyObject_TypeCheck(" << PYTHON_ARG << ", self->ob_type)\n";
- s << INDENT << "&& PyObject_HasAttr(" << PYTHON_ARG << ", attrName)) {\n";
-
- // 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_GetAttr(" << PYTHON_ARG << ", attrName);\n";
- s << INDENT << "if (revOpMethod && PyCallable_Check(revOpMethod)) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << PYTHON_RETURN_VAR << " = PyObject_CallFunction(revOpMethod, const_cast<char *>(\"O\"), self);\n";
- s << INDENT << "if (PyErr_Occurred() && (PyErr_ExceptionMatches(PyExc_NotImplementedError)";
- s << " || PyErr_ExceptionMatches(PyExc_AttributeError))) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "PyErr_Clear();\n";
- s << INDENT << "Py_XDECREF(" << PYTHON_RETURN_VAR << ");\n";
- s << INDENT << PYTHON_RETURN_VAR << " = " << NULL_PTR << ";\n";
- }
- s << INDENT << "}\n";
- }
- s << INDENT << "}\n";
- s << INDENT << "Py_XDECREF(revOpMethod);\n\n";
- }
- s << INDENT << "}\n";
- }
- s << INDENT << "// Do not enter here if other object has implemented a reverse operator.\n";
- s << INDENT << "if (!" << PYTHON_RETURN_VAR << ") {\n\n";
- }
-
- if (maxArgs > 0)
- writeOverloadedFunctionDecisor(s, overloadData);
-
- writeFunctionCalls(s, overloadData, classContext);
-
- if (callExtendedReverseOperator)
- s << Qt::endl << INDENT << "} // End of \"if (!" << PYTHON_RETURN_VAR << ")\"\n";
-
- s << Qt::endl;
-
- writeFunctionReturnErrorCheckSection(s, hasReturnValue && !rfunc->isInplaceOperator());
-
- if (hasReturnValue) {
- if (rfunc->isInplaceOperator()) {
- s << INDENT << "Py_INCREF(self);\n";
- s << INDENT << "return self;\n";
- } else {
- s << INDENT << "return " << PYTHON_RETURN_VAR << ";\n";
- }
- } else {
- s << INDENT << "Py_RETURN_NONE;\n";
- }
-
- if (maxArgs > 0)
- writeErrorSection(s, overloadData);
-
- s<< "}\n\n";
-}
-
-void CppGenerator::writeArgumentsInitializer(QTextStream &s, OverloadData &overloadData)
-{
- const AbstractMetaFunction *rfunc = overloadData.referenceFunction();
- s << "PyTuple_GET_SIZE(args);\n";
- writeUnusedVariableCast(s, QLatin1String("numArgs"));
-
- int minArgs = overloadData.minArgs();
- int maxArgs = overloadData.maxArgs();
-
- s << INDENT << "PyObject *";
- s << PYTHON_ARGS << "[] = {"
- << QString(maxArgs, QLatin1Char('0')).split(QLatin1String(""), QString::SkipEmptyParts).join(QLatin1String(", "))
- << "};\n";
- s << Qt::endl;
-
- if (overloadData.hasVarargs()) {
- maxArgs--;
- if (minArgs > maxArgs)
- minArgs = maxArgs;
-
- s << INDENT << "PyObject *nonvarargs = PyTuple_GetSlice(args, 0, " << maxArgs << ");\n";
- s << INDENT << "Shiboken::AutoDecRef auto_nonvarargs(nonvarargs);\n";
- s << INDENT << PYTHON_ARGS << '[' << maxArgs << "] = PyTuple_GetSlice(args, " << maxArgs << ", numArgs);\n";
- s << INDENT << "Shiboken::AutoDecRef auto_varargs(" << PYTHON_ARGS << "[" << maxArgs << "]);\n";
- s << Qt::endl;
- }
-
- bool usesNamedArguments = overloadData.hasArgumentWithDefaultValue();
-
- s << INDENT << "// invalid argument lengths\n";
- bool ownerClassIsQObject = rfunc->ownerClass() && rfunc->ownerClass()->isQObject() && rfunc->isConstructor();
- if (usesNamedArguments) {
- if (!ownerClassIsQObject) {
- s << INDENT << "if (numArgs" << (overloadData.hasArgumentWithDefaultValue() ? " + numNamedArgs" : "") << " > " << maxArgs << ") {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): too many arguments\");\n";
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
- }
- s << INDENT << '}';
- }
- if (minArgs > 0) {
- if (ownerClassIsQObject)
- s << INDENT;
- else
- s << " else ";
- s << "if (numArgs < " << minArgs << ") {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): not enough arguments\");\n";
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
- }
- s << INDENT << '}';
- }
- }
- const QVector<int> invalidArgsLength = overloadData.invalidArgumentLengths();
- if (!invalidArgsLength.isEmpty()) {
- QStringList invArgsLen;
- for (int i : qAsConst(invalidArgsLength))
- invArgsLen << QStringLiteral("numArgs == %1").arg(i);
- if (usesNamedArguments && (!ownerClassIsQObject || minArgs > 0))
- s << " else ";
- else
- s << INDENT;
- s << "if (" << invArgsLen.join(QLatin1String(" || ")) << ")\n";
- Indentation indent(INDENT);
- s << INDENT << "goto " << cpythonFunctionName(rfunc) << "_TypeError;";
- }
- s << Qt::endl << Qt::endl;
-
- QString funcName;
- if (rfunc->isOperatorOverload())
- funcName = ShibokenGenerator::pythonOperatorFunctionName(rfunc);
- else
- funcName = rfunc->name();
-
- QString argsVar = overloadData.hasVarargs() ? QLatin1String("nonvarargs") : QLatin1String("args");
- s << INDENT << "if (!";
- if (usesNamedArguments)
- s << "PyArg_ParseTuple(" << argsVar << ", \"|" << QByteArray(maxArgs, 'O') << ':' << funcName << '"';
- else
- s << "PyArg_UnpackTuple(" << argsVar << ", \"" << funcName << "\", " << minArgs << ", " << maxArgs;
- for (int i = 0; i < maxArgs; i++)
- s << ", &(" << PYTHON_ARGS << '[' << i << "])";
- s << "))\n";
- {
- Indentation indent(INDENT);
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
- }
- s << Qt::endl;
-}
-
-void CppGenerator::writeCppSelfAssigment(QTextStream &s, const GeneratorContext &context,
- const QString &className, bool cppSelfAsReference,
- bool useWrapperClass)
-{
- static const QString pythonSelfVar = QLatin1String("self");
- if (cppSelfAsReference)
- s << className << " &";
- s << CPP_SELF_VAR << " = ";
- if (cppSelfAsReference)
- s << " *";
- if (useWrapperClass)
- s << "static_cast<" << className << " *>(";
- if (!context.forSmartPointer())
- s << cpythonWrapperCPtr(context.metaClass(), pythonSelfVar);
- else
- s << cpythonWrapperCPtr(context.preciseType(), pythonSelfVar);
- if (useWrapperClass)
- s << ')';
-}
-
-void CppGenerator::writeCppSelfDefinition(QTextStream &s,
- GeneratorContext &context,
- bool hasStaticOverload,
- bool cppSelfAsReference)
-{
- const AbstractMetaClass *metaClass = context.metaClass();
- bool useWrapperClass = avoidProtectedHack() && metaClass->hasProtectedMembers();
- QString className;
- if (!context.forSmartPointer()) {
- className = useWrapperClass
- ? wrapperName(metaClass)
- : (QLatin1String("::") + metaClass->qualifiedCppName());
- } else {
- className = context.preciseType()->cppSignature();
- }
-
- if (!cppSelfAsReference) {
- s << INDENT << className << " *" << CPP_SELF_VAR << " = nullptr;\n";
- writeUnusedVariableCast(s, QLatin1String(CPP_SELF_VAR));
- }
-
- // Checks if the underlying C++ object is valid.
- if (hasStaticOverload && !cppSelfAsReference) {
- s << INDENT << "if (self) {\n";
- {
- Indentation indent(INDENT);
- writeInvalidPyObjectCheck(s, QLatin1String("self"));
- s << INDENT;
- writeCppSelfAssigment(s, context, className, cppSelfAsReference, useWrapperClass);
- s << ";\n";
- }
- s << INDENT << "}\n";
- return;
- }
-
- writeInvalidPyObjectCheck(s, QLatin1String("self"));
- s << INDENT;
- writeCppSelfAssigment(s, context, className, cppSelfAsReference, useWrapperClass);
- s << ";\n";
-}
-
-void CppGenerator::writeCppSelfDefinition(QTextStream &s,
- const AbstractMetaFunction *func,
- GeneratorContext &context,
- bool hasStaticOverload)
-{
- if (!func->ownerClass() || func->isConstructor())
- return;
-
- if (func->isOperatorOverload() && func->isBinaryOperator()) {
- QString checkFunc = cpythonCheckFunction(func->ownerClass()->typeEntry());
- s << INDENT << "bool isReverse = " << checkFunc << PYTHON_ARG << ")\n";
- {
- Indentation indent1(INDENT, 4);
- s << INDENT << "&& !" << checkFunc << "self);\n";
- }
- s << INDENT << "if (isReverse)\n";
- Indentation indent(INDENT);
- s << INDENT << "std::swap(self, " << PYTHON_ARG << ");\n";
- }
-
- writeCppSelfDefinition(s, context, hasStaticOverload);
-}
-
-void CppGenerator::writeErrorSection(QTextStream &s, OverloadData &overloadData)
-{
- const AbstractMetaFunction *rfunc = overloadData.referenceFunction();
- s << Qt::endl << INDENT << cpythonFunctionName(rfunc) << "_TypeError:\n";
- Indentation indentation(INDENT);
- QString funcName = fullPythonFunctionName(rfunc);
-
- QString argsVar = pythonFunctionWrapperUsesListOfArguments(overloadData)
- ? QLatin1String("args") : QLatin1String(PYTHON_ARG);
- s << INDENT << "Shiboken::setErrorAboutWrongArguments(" << argsVar << ", \"" << funcName << "\");\n";
- s << INDENT << "return " << m_currentErrorCode << ";\n";
-}
-
-void CppGenerator::writeFunctionReturnErrorCheckSection(QTextStream &s, bool hasReturnValue)
-{
- s << INDENT << "if (PyErr_Occurred()";
- if (hasReturnValue)
- s << " || !" << PYTHON_RETURN_VAR;
- s << ") {\n";
- {
- Indentation indent(INDENT);
- if (hasReturnValue)
- s << INDENT << "Py_XDECREF(" << PYTHON_RETURN_VAR << ");\n";
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
- }
- s << INDENT << "}\n";
-}
-
-void CppGenerator::writeInvalidPyObjectCheck(QTextStream &s, const QString &pyObj)
-{
- s << INDENT << "if (!Shiboken::Object::isValid(" << pyObj << "))\n";
- Indentation indent(INDENT);
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
-}
-
-static QString pythonToCppConverterForArgumentName(const QString &argumentName)
-{
- static const QRegularExpression pyArgsRegex(QLatin1String(PYTHON_ARGS)
- + QLatin1String(R"((\[\d+[-]?\d*\]))"));
- Q_ASSERT(pyArgsRegex.isValid());
- const QRegularExpressionMatch match = pyArgsRegex.match(argumentName);
- QString result = QLatin1String(PYTHON_TO_CPP_VAR);
- if (match.hasMatch())
- result += match.captured(1);
- return result;
-}
-
-void CppGenerator::writeTypeCheck(QTextStream &s, const AbstractMetaType *argType,
- const QString &argumentName, bool isNumber,
- const QString &customType, bool rejectNull)
-{
- QString customCheck;
- if (!customType.isEmpty()) {
- AbstractMetaType *metaType;
- // PYSIDE-795: Note: XML-Overrides are handled in this shibokengenerator function!
- // This enables iterables for QMatrix4x4 for instance.
- customCheck = guessCPythonCheckFunction(customType, &metaType);
- if (metaType)
- argType = metaType;
- }
-
- // TODO-CONVERTER: merge this with the code below.
- QString typeCheck;
- if (customCheck.isEmpty())
- typeCheck = cpythonIsConvertibleFunction(argType, argType->isEnum() ? false : isNumber);
- else
- typeCheck = customCheck;
- typeCheck.append(QString::fromLatin1("(%1)").arg(argumentName));
-
- // TODO-CONVERTER -----------------------------------------------------------------------
- if (customCheck.isEmpty() && !argType->typeEntry()->isCustom()) {
- typeCheck = QString::fromLatin1("(%1 = %2))").arg(pythonToCppConverterForArgumentName(argumentName), typeCheck);
- if (!isNumber && argType->typeEntry()->isCppPrimitive())
- typeCheck.prepend(QString::fromLatin1("%1(%2) && ").arg(cpythonCheckFunction(argType), argumentName));
- }
- // TODO-CONVERTER -----------------------------------------------------------------------
-
- if (rejectNull)
- typeCheck = QString::fromLatin1("(%1 != Py_None && %2)").arg(argumentName, typeCheck);
-
- s << typeCheck;
-}
-
-static void checkTypeViability(const AbstractMetaFunction *func, const AbstractMetaType *type, int argIdx)
-{
- if (!type
- || !type->typeEntry()->isPrimitive()
- || type->indirections() == 0
- || (type->indirections() == 1 && type->typeUsagePattern() == AbstractMetaType::NativePointerAsArrayPattern)
- || ShibokenGenerator::isCString(type)
- || func->argumentRemoved(argIdx)
- || !func->typeReplaced(argIdx).isEmpty()
- || !func->conversionRule(TypeSystem::All, argIdx).isEmpty()
- || func->hasInjectedCode())
- return;
- QString message;
- QTextStream str(&message);
- str << "There's no user provided way (conversion rule, argument"
- " removal, custom code, etc) to handle the primitive ";
- if (argIdx == 0)
- str << "return type '" << type->cppSignature() << '\'';
- else
- str << "type '" << type->cppSignature() << "' of argument " << argIdx;
- str << " in function '";
- if (func->ownerClass())
- str << func->ownerClass()->qualifiedCppName() << "::";
- str << func->signature() << "'.";
- qCWarning(lcShiboken).noquote().nospace() << message;
-}
-
-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;
- const OverloadDataList &overloads = overloadData->previousOverloadData()->nextOverloadData();
- for (OverloadData *od : overloads) {
- const OverloadData::MetaFunctionList &odOverloads = od->overloads();
- for (const AbstractMetaFunction *func : odOverloads) {
- checkTypeViability(func);
- const AbstractMetaType *argType = od->argument(func)->type();
- if (!argType->isPrimitive())
- continue;
- if (ShibokenGenerator::isNumber(argType->typeEntry()))
- numericTypes << argType->typeEntry();
- }
- }
-
- // This condition trusts that the OverloadData object will arrange for
- // PyInt type to come after the more precise numeric types (e.g. float and bool)
- const AbstractMetaType *argType = overloadData->argType();
- bool numberType = numericTypes.count() == 1 || ShibokenGenerator::isPyInt(argType);
- QString customType = (overloadData->hasArgumentTypeReplace() ? overloadData->argumentTypeReplaced() : QString());
- bool rejectNull = shouldRejectNullPointerArgument(overloadData->referenceFunction(), overloadData->argPos());
- writeTypeCheck(s, argType, argumentName, numberType, customType, rejectNull);
-}
-
-void CppGenerator::writeArgumentConversion(QTextStream &s,
- const AbstractMetaType *argType,
- const QString &argName, const QString &pyArgName,
- const AbstractMetaClass *context,
- const QString &defaultValue,
- bool castArgumentAsUnused)
-{
- if (argType->typeEntry()->isCustom() || argType->typeEntry()->isVarargs())
- return;
- if (isWrapperType(argType))
- writeInvalidPyObjectCheck(s, pyArgName);
- writePythonToCppTypeConversion(s, argType, pyArgName, argName, context, defaultValue);
- if (castArgumentAsUnused)
- writeUnusedVariableCast(s, argName);
-}
-
-const AbstractMetaType *CppGenerator::getArgumentType(const AbstractMetaFunction *func, int argPos)
-{
- if (argPos < 0 || argPos > func->arguments().size()) {
- qCWarning(lcShiboken).noquote().nospace()
- << QStringLiteral("Argument index for function '%1' out of range.").arg(func->signature());
- return nullptr;
- }
-
- const AbstractMetaType *argType = nullptr;
- QString typeReplaced = func->typeReplaced(argPos);
- if (typeReplaced.isEmpty())
- argType = (argPos == 0) ? func->type() : func->arguments().at(argPos-1)->type();
- else
- argType = buildAbstractMetaTypeFromString(typeReplaced);
- if (!argType && !m_knownPythonTypes.contains(typeReplaced)) {
- qCWarning(lcShiboken).noquote().nospace()
- << QString::fromLatin1("Unknown type '%1' used as argument type replacement "\
- "in function '%2', the generated code may be broken.")
- .arg(typeReplaced, func->signature());
- }
- return argType;
-}
-
-static inline QString arrayHandleType(const AbstractMetaTypeCList &nestedArrayTypes)
-{
- switch (nestedArrayTypes.size()) {
- case 1:
- return QStringLiteral("Shiboken::Conversions::ArrayHandle<")
- + nestedArrayTypes.constLast()->minimalSignature()
- + QLatin1Char('>');
- case 2:
- return QStringLiteral("Shiboken::Conversions::Array2Handle<")
- + nestedArrayTypes.constLast()->minimalSignature()
- + QStringLiteral(", ")
- + QString::number(nestedArrayTypes.constFirst()->arrayElementCount())
- + QLatin1Char('>');
- }
- return QString();
-}
-
-void CppGenerator::writePythonToCppTypeConversion(QTextStream &s,
- const AbstractMetaType *type,
- const QString &pyIn,
- const QString &cppOut,
- const AbstractMetaClass * /* context */,
- const QString &defaultValue)
-{
- const TypeEntry *typeEntry = type->typeEntry();
- if (typeEntry->isCustom() || typeEntry->isVarargs())
- return;
-
- QString cppOutAux = cppOut + QLatin1String("_local");
-
- bool treatAsPointer = isValueTypeWithCopyConstructorOnly(type);
- bool isPointerOrObjectType = (isObjectType(type) || isPointer(type)) && !isUserPrimitive(type) && !isCppPrimitive(type);
- bool isNotContainerEnumOrFlags = !typeEntry->isContainer() && !typeEntry->isEnum() && !typeEntry->isFlags();
- bool mayHaveImplicitConversion = type->referenceType() == LValueReference
- && !isUserPrimitive(type)
- && !isCppPrimitive(type)
- && isNotContainerEnumOrFlags
- && !(treatAsPointer || isPointerOrObjectType);
-
- const AbstractMetaTypeCList nestedArrayTypes = type->nestedArrayTypes();
- const bool isCppPrimitiveArray = !nestedArrayTypes.isEmpty()
- && nestedArrayTypes.constLast()->isCppPrimitive();
- QString typeName = isCppPrimitiveArray
- ? arrayHandleType(nestedArrayTypes)
- : getFullTypeNameWithoutModifiers(type);
-
- bool isProtectedEnum = false;
-
- if (mayHaveImplicitConversion) {
- s << INDENT << typeName << ' ' << cppOutAux;
- writeMinimalConstructorExpression(s, type, defaultValue);
- s << ";\n";
- } else if (avoidProtectedHack() && type->typeEntry()->isEnum()) {
- const AbstractMetaEnum *metaEnum = findAbstractMetaEnum(type);
- if (metaEnum && metaEnum->isProtected()) {
- typeName = QLatin1String("long");
- isProtectedEnum = true;
- }
- }
-
- s << INDENT << typeName;
- if (isCppPrimitiveArray) {
- s << ' ' << cppOut;
- } else if (treatAsPointer || isPointerOrObjectType) {
- s << " *" << cppOut;
- if (!defaultValue.isEmpty())
- s << " = " << defaultValue;
- } else if (type->referenceType() == LValueReference && !typeEntry->isPrimitive() && isNotContainerEnumOrFlags) {
- s << " *" << cppOut << " = &" << cppOutAux;
- } else {
- s << ' ' << cppOut;
- if (isProtectedEnum && avoidProtectedHack()) {
- s << " = ";
- if (defaultValue.isEmpty())
- s << "0";
- else
- s << "(long)" << defaultValue;
- } else if (isUserPrimitive(type) || typeEntry->isEnum() || typeEntry->isFlags()) {
- writeMinimalConstructorExpression(s, typeEntry, defaultValue);
- } else if (!type->isContainer() && !type->isSmartPointer()) {
- writeMinimalConstructorExpression(s, type, defaultValue);
- }
- }
- s << ";\n";
-
- QString pythonToCppFunc = pythonToCppConverterForArgumentName(pyIn);
-
- s << INDENT;
- if (!defaultValue.isEmpty())
- s << "if (" << pythonToCppFunc << ") ";
-
- QString pythonToCppCall = QString::fromLatin1("%1(%2, &%3)").arg(pythonToCppFunc, pyIn, cppOut);
- if (!mayHaveImplicitConversion) {
- s << pythonToCppCall << ";\n";
- return;
- }
-
- if (!defaultValue.isEmpty())
- s << "{\n" << INDENT;
-
- s << "if (Shiboken::Conversions::isImplicitConversion(reinterpret_cast<SbkObjectType *>("
- << cpythonTypeNameExt(type) << "), " << pythonToCppFunc << "))\n";
- {
- Indentation indent(INDENT);
- s << INDENT << pythonToCppFunc << '(' << pyIn << ", &" << cppOutAux << ");\n";
- }
- s << INDENT << "else\n";
- {
- Indentation indent(INDENT);
- s << INDENT << pythonToCppCall << ";\n";
- }
-
- if (!defaultValue.isEmpty())
- s << INDENT << '}';
- s << Qt::endl;
-}
-
-static void addConversionRuleCodeSnippet(CodeSnipList &snippetList, QString &rule,
- TypeSystem::Language /* conversionLanguage */,
- TypeSystem::Language snippetLanguage,
- const QString &outputName = QString(),
- const QString &inputName = QString())
-{
- if (rule.isEmpty())
- return;
- if (snippetLanguage == TypeSystem::TargetLangCode) {
- rule.replace(QLatin1String("%in"), inputName);
- rule.replace(QLatin1String("%out"), outputName + QLatin1String("_out"));
- } else {
- rule.replace(QLatin1String("%out"), outputName);
- }
- CodeSnip snip(snippetLanguage);
- snip.position = (snippetLanguage == TypeSystem::NativeCode) ? TypeSystem::CodeSnipPositionAny : TypeSystem::CodeSnipPositionBeginning;
- snip.addCode(rule);
- snippetList << snip;
-}
-
-void CppGenerator::writeConversionRule(QTextStream &s, const AbstractMetaFunction *func, TypeSystem::Language language)
-{
- CodeSnipList snippets;
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (AbstractMetaArgument *arg : arguments) {
- QString rule = func->conversionRule(language, arg->argumentIndex() + 1);
- addConversionRuleCodeSnippet(snippets, rule, language, TypeSystem::TargetLangCode,
- arg->name(), arg->name());
- }
- writeCodeSnips(s, snippets, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode, func);
-}
-
-void CppGenerator::writeConversionRule(QTextStream &s, const AbstractMetaFunction *func, TypeSystem::Language language, const QString &outputVar)
-{
- CodeSnipList snippets;
- QString rule = func->conversionRule(language, 0);
- addConversionRuleCodeSnippet(snippets, rule, language, language, outputVar);
- writeCodeSnips(s, snippets, TypeSystem::CodeSnipPositionAny, language, func);
-}
-
-void CppGenerator::writeNoneReturn(QTextStream &s, const AbstractMetaFunction *func, bool thereIsReturnValue)
-{
- if (thereIsReturnValue && (!func->type() || func->argumentRemoved(0)) && !injectedCodeHasReturnValueAttribution(func)) {
- s << INDENT << PYTHON_RETURN_VAR << " = Py_None;\n";
- s << INDENT << "Py_INCREF(Py_None);\n";
- }
-}
-
-void CppGenerator::writeOverloadedFunctionDecisor(QTextStream &s, const OverloadData &overloadData)
-{
- s << INDENT << "// Overloaded function decisor\n";
- const AbstractMetaFunction *rfunc = overloadData.referenceFunction();
- const OverloadData::MetaFunctionList &functionOverloads = overloadData.overloadsWithoutRepetition();
- for (int i = 0; i < functionOverloads.count(); i++) {
- const auto func = functionOverloads.at(i);
- s << INDENT << "// " << i << ": ";
- if (func->isStatic())
- s << "static ";
- if (const auto *decl = func->declaringClass())
- s << decl->name() << "::";
- s << func->minimalSignature() << Qt::endl;
- }
- writeOverloadedFunctionDecisorEngine(s, &overloadData);
- s << Qt::endl;
-
- // Ensure that the direct overload that called this reverse
- // is called.
- if (rfunc->isOperatorOverload() && !rfunc->isCallOperator()) {
- s << INDENT << "if (isReverse && overloadId == -1) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"reverse operator not implemented.\");\n";
- s << INDENT << "return {};\n";
- }
- s << INDENT << "}\n\n";
- }
-
- s << INDENT << "// Function signature not found.\n";
- s << INDENT << "if (overloadId == -1) goto " << cpythonFunctionName(overloadData.referenceFunction()) << "_TypeError;\n";
- s << Qt::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) {
- const OverloadData::MetaFunctionList &overloads = parentOverloadData->overloads();
- for (const AbstractMetaFunction *func : 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() << Qt::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.
- 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() << Qt::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.
- const OverloadDataList &overloads = parentOverloadData->nextOverloadData();
- if (hasDefaultCall) {
- isFirst = false;
- int numArgs = parentOverloadData->argPos() + 1;
- s << INDENT << "if (numArgs == " << numArgs << ") {\n";
- {
- Indentation indent(INDENT);
- const AbstractMetaFunction *func = referenceFunction;
- for (OverloadData *overloadData : overloads) {
- const AbstractMetaFunction *defValFunc = overloadData->getFunctionWithDefaultValue();
- if (defValFunc) {
- func = defValFunc;
- break;
- }
- }
- s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(func);
- s << "; // " << func->minimalSignature() << Qt::endl;
- }
- s << INDENT << '}';
- }
-
- for (OverloadData *overloadData : overloads) {
- bool signatureFound = overloadData->overloads().size() == 1
- && !overloadData->getFunctionWithDefaultValue()
- && !overloadData->findNextArgWithDefault();
-
- const AbstractMetaFunction *refFunc = overloadData->referenceFunction();
-
- QStringList typeChecks;
-
- QString pyArgName = (usePyArgs && maxArgs > 1)
- ? pythonArgsAt(overloadData->argPos())
- : QLatin1String(PYTHON_ARG);
- OverloadData *od = overloadData;
- int startArg = od->argPos();
- int sequenceArgCount = 0;
- while (od && !od->argType()->isVarargs()) {
- bool typeReplacedByPyObject = od->argumentTypeReplaced() == QLatin1String("PyObject");
- if (!typeReplacedByPyObject) {
- if (usePyArgs)
- pyArgName = pythonArgsAt(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().constFirst()->type()->typeEntry() && isCopyable(ownerClass)) {
- tck << '!' << cpythonCheckFunction(ownerClass->typeEntry()) << pyArgName << ")\n";
- 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().constFirst()->overloads().size()) {
- overloadData = od;
- od = nullptr;
- } else {
- od = od->nextOverloadData().constFirst();
- }
- }
-
- if (usePyArgs && signatureFound) {
- AbstractMetaArgumentList args = refFunc->arguments();
- int lastArgIsVarargs = (int) (args.size() > 1 && args.constLast()->type()->isVarargs());
- int numArgs = args.size() - OverloadData::numberOfRemovedArguments(refFunc) - lastArgIsVarargs;
- typeChecks.prepend(QString::fromLatin1("numArgs %1 %2").arg(lastArgIsVarargs ? QLatin1String(">=") : QLatin1String("==")).arg(numArgs));
- } else if (sequenceArgCount > 1) {
- typeChecks.prepend(QString::fromLatin1("numArgs >= %1").arg(startArg + sequenceArgCount));
- } else if (refFunc->isOperatorOverload() && !refFunc->isCallOperator()) {
- typeChecks.prepend(QString::fromLatin1("%1isReverse").arg(refFunc->isReverseOperator() ? QString() : QLatin1String("!")));
- }
-
- if (isFirst) {
- isFirst = false;
- s << INDENT;
- } else {
- s << " else ";
- }
- s << "if (";
- if (typeChecks.isEmpty()) {
- s << "true";
- } else {
- Indentation indent(INDENT);
- QString separator;
- QTextStream sep(&separator);
- sep << Qt::endl << INDENT << "&& ";
- s << typeChecks.join(separator);
- }
- s << ") {\n";
- {
- Indentation indent(INDENT);
- writeOverloadedFunctionDecisorEngine(s, overloadData);
- }
- s << INDENT << "}";
- }
- s << Qt::endl;
-}
-
-void CppGenerator::writeFunctionCalls(QTextStream &s, const OverloadData &overloadData,
- GeneratorContext &context)
-{
- const OverloadData::MetaFunctionList &overloads = overloadData.overloadsWithoutRepetition();
- s << INDENT << "// Call function/method\n";
- s << INDENT << (overloads.count() > 1 ? "switch (overloadId) " : "") << "{\n";
- {
- Indentation indent(INDENT);
- if (overloads.count() == 1) {
- writeSingleFunctionCall(s, overloadData, overloads.constFirst(), context);
- } else {
- for (int i = 0; i < overloads.count(); i++) {
- const AbstractMetaFunction *func = overloads.at(i);
- s << INDENT << "case " << i << ": // " << func->signature() << Qt::endl;
- s << INDENT << "{\n";
- {
- Indentation indent(INDENT);
- writeSingleFunctionCall(s, overloadData, func, context);
- if (func->attributes().testFlag(AbstractMetaAttributes::Deprecated)) {
- s << INDENT << "PyErr_WarnEx(PyExc_DeprecationWarning, \"";
- if (auto cls = context.metaClass())
- s << cls->name() << '.';
- s << func->signature() << " is deprecated\", 1);\n";
- }
- s << INDENT << "break;\n";
- }
- s << INDENT << "}\n";
- }
- }
- }
- s << INDENT << "}\n";
-}
-
-void CppGenerator::writeSingleFunctionCall(QTextStream &s,
- const OverloadData &overloadData,
- const AbstractMetaFunction *func,
- GeneratorContext &context)
-{
- if (func->isDeprecated()) {
- s << INDENT << "Shiboken::warning(PyExc_DeprecationWarning, 1, \"Function: '"
- << func->signature().replace(QLatin1String("::"), QLatin1String("."))
- << "' is marked as deprecated, please check the documentation for more information.\");\n";
- }
-
- if (func->functionType() == AbstractMetaFunction::EmptyFunction) {
- s << INDENT << "PyErr_Format(PyExc_TypeError, \"%s is a private method.\", \""
- << func->signature().replace(QLatin1String("::"), QLatin1String("."))
- << "\");\n";
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::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()) {
- const QString cppArgRemoved = QLatin1String(CPP_ARG_REMOVED)
- + QString::number(argIdx);
- s << INDENT << getFullTypeName(arg->type()) << ' ' << cppArgRemoved;
- s << " = " << guessScopeForDefaultValue(func, arg) << ";\n";
- 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("No way to call '%s::%s' with the modifications described in the type system.",
- qPrintable(func->ownerClass()->name()), qPrintable(func->signature()));
- }
- 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 = QLatin1String(CPP_ARG) + QString::number(argPos);
- QString pyArgName = usePyArgs ? pythonArgsAt(argPos) : QLatin1String(PYTHON_ARG);
- QString defaultValue = guessScopeForDefaultValue(func, arg);
- writeArgumentConversion(s, argType, argName, pyArgName, func->implementingClass(), defaultValue, func->isUserAdded());
- }
-
- s << Qt::endl;
-
- int numRemovedArgs = OverloadData::numberOfRemovedArguments(func);
-
- s << INDENT << "if (!PyErr_Occurred()) {\n";
- {
- Indentation indentation(INDENT);
- writeMethodCall(s, func, context, func->arguments().size() - numRemovedArgs);
- if (!func->isConstructor())
- writeNoneReturn(s, func, overloadData.hasNonVoidReturnType());
- }
- s << INDENT << "}\n";
-}
-
-QString CppGenerator::cppToPythonFunctionName(const QString &sourceTypeName, QString targetTypeName)
-{
- if (targetTypeName.isEmpty())
- targetTypeName = sourceTypeName;
- return QString::fromLatin1("%1_CppToPython_%2").arg(sourceTypeName, targetTypeName);
-}
-
-QString CppGenerator::pythonToCppFunctionName(const QString &sourceTypeName, const QString &targetTypeName)
-{
- return QString::fromLatin1("%1_PythonToCpp_%2").arg(sourceTypeName, targetTypeName);
-}
-QString CppGenerator::pythonToCppFunctionName(const AbstractMetaType *sourceType, const AbstractMetaType *targetType)
-{
- return pythonToCppFunctionName(fixedCppTypeName(sourceType), fixedCppTypeName(targetType));
-}
-QString CppGenerator::pythonToCppFunctionName(const CustomConversion::TargetToNativeConversion *toNative,
- const TypeEntry *targetType)
-{
- return pythonToCppFunctionName(fixedCppTypeName(toNative), fixedCppTypeName(targetType));
-}
-
-QString CppGenerator::convertibleToCppFunctionName(const QString &sourceTypeName, const QString &targetTypeName)
-{
- return QString::fromLatin1("is_%1_PythonToCpp_%2_Convertible").arg(sourceTypeName, targetTypeName);
-}
-QString CppGenerator::convertibleToCppFunctionName(const AbstractMetaType *sourceType, const AbstractMetaType *targetType)
-{
- return convertibleToCppFunctionName(fixedCppTypeName(sourceType), fixedCppTypeName(targetType));
-}
-QString CppGenerator::convertibleToCppFunctionName(const CustomConversion::TargetToNativeConversion *toNative,
- const TypeEntry *targetType)
-{
- return convertibleToCppFunctionName(fixedCppTypeName(toNative), fixedCppTypeName(targetType));
-}
-
-void CppGenerator::writeCppToPythonFunction(QTextStream &s, const QString &code, const QString &sourceTypeName, QString targetTypeName)
-{
- QString prettyCode;
- QTextStream c(&prettyCode);
- formatCode(c, code, INDENT);
- processCodeSnip(prettyCode);
-
- s << "static PyObject *" << cppToPythonFunctionName(sourceTypeName, targetTypeName);
- s << "(const void *cppIn) {\n";
- s << prettyCode;
- s << "}\n";
-}
-
-static void replaceCppToPythonVariables(QString &code, const QString &typeName)
-{
- code.prepend(QLatin1String("auto &cppInRef = *reinterpret_cast<")
- + typeName + QLatin1String(" *>(const_cast<void *>(cppIn));\n"));
- code.replace(QLatin1String("%INTYPE"), typeName);
- code.replace(QLatin1String("%OUTTYPE"), QLatin1String("PyObject *"));
- code.replace(QLatin1String("%in"), QLatin1String("cppInRef"));
- code.replace(QLatin1String("%out"), QLatin1String("pyOut"));
-}
-void CppGenerator::writeCppToPythonFunction(QTextStream &s, const CustomConversion *customConversion)
-{
- QString code = customConversion->nativeToTargetConversion();
- replaceCppToPythonVariables(code, getFullTypeName(customConversion->ownerType()));
- writeCppToPythonFunction(s, code, fixedCppTypeName(customConversion->ownerType()));
-}
-void CppGenerator::writeCppToPythonFunction(QTextStream &s, const AbstractMetaType *containerType)
-{
- const CustomConversion *customConversion = containerType->typeEntry()->customConversion();
- if (!customConversion) {
- qFatal("Can't write the C++ to Python conversion function for container type '%s' - "\
- "no conversion rule was defined for it in the type system.",
- qPrintable(containerType->typeEntry()->qualifiedCppName()));
- }
- if (!containerType->typeEntry()->isContainer()) {
- writeCppToPythonFunction(s, customConversion);
- return;
- }
- QString code = customConversion->nativeToTargetConversion();
- for (int i = 0; i < containerType->instantiations().count(); ++i) {
- AbstractMetaType *type = containerType->instantiations().at(i);
- QString typeName = getFullTypeName(type);
- if (type->isConstant())
- typeName = QLatin1String("const ") + typeName;
- code.replace(QString::fromLatin1("%INTYPE_%1").arg(i), typeName);
- }
- replaceCppToPythonVariables(code, getFullTypeNameWithoutModifiers(containerType));
- processCodeSnip(code);
- writeCppToPythonFunction(s, code, fixedCppTypeName(containerType));
-}
-
-void CppGenerator::writePythonToCppFunction(QTextStream &s, const QString &code, const QString &sourceTypeName, const QString &targetTypeName)
-{
- QString prettyCode;
- QTextStream c(&prettyCode);
- formatCode(c, code, INDENT);
- processCodeSnip(prettyCode);
- s << "static void " << pythonToCppFunctionName(sourceTypeName, targetTypeName);
- s << "(PyObject *pyIn, void *cppOut) {\n";
- s << prettyCode;
- s << "}\n";
-}
-
-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) {\n";
- if (acceptNoneAsCppNull) {
- s << INDENT << "if (pyIn == Py_None)\n";
- Indentation indent(INDENT);
- s << INDENT << "return Shiboken::Conversions::nonePythonToCppNullPtr;\n";
- }
- s << INDENT << "if (" << condition << ")\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "return " << pythonToCppFuncName << ";\n";
- }
- s << INDENT << "return {};\n";
- s << "}\n";
-}
-
-void CppGenerator::writePythonToCppConversionFunctions(QTextStream &s,
- const AbstractMetaType *sourceType,
- const AbstractMetaType *targetType,
- QString typeCheck,
- QString conversion,
- const QString &preConversion)
-{
- QString sourcePyType = cpythonTypeNameExt(sourceType);
-
- // Python to C++ conversion function.
- QString code;
- QTextStream c(&code);
- if (conversion.isEmpty())
- conversion = QLatin1Char('*') + cpythonWrapperCPtr(sourceType->typeEntry(), QLatin1String("pyIn"));
- if (!preConversion.isEmpty())
- c << INDENT << preConversion << Qt::endl;
- const QString fullTypeName = getFullTypeName(targetType->typeEntry());
- c << INDENT << "*reinterpret_cast<" << fullTypeName << " *>(cppOut) = "
- << fullTypeName << '(' << conversion << ");";
- QString sourceTypeName = fixedCppTypeName(sourceType);
- QString targetTypeName = fixedCppTypeName(targetType);
- writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
-
- // Python to C++ convertible check function.
- if (typeCheck.isEmpty())
- typeCheck = QString::fromLatin1("PyObject_TypeCheck(pyIn, %1)").arg(sourcePyType);
- writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck);
- s << Qt::endl;
-}
-
-void CppGenerator::writePythonToCppConversionFunctions(QTextStream &s,
- const CustomConversion::TargetToNativeConversion *toNative,
- const TypeEntry *targetType)
-{
- // Python to C++ conversion function.
- QString code = toNative->conversion();
- QString inType;
- if (toNative->sourceType())
- inType = cpythonTypeNameExt(toNative->sourceType());
- else
- inType = QString::fromLatin1("(%1_TypeF())").arg(toNative->sourceTypeName());
- code.replace(QLatin1String("%INTYPE"), inType);
- code.replace(QLatin1String("%OUTTYPE"), targetType->qualifiedCppName());
- code.replace(QLatin1String("%in"), QLatin1String("pyIn"));
- code.replace(QLatin1String("%out"),
- QLatin1String("*reinterpret_cast<") + getFullTypeName(targetType) + QLatin1String(" *>(cppOut)"));
-
- QString sourceTypeName = fixedCppTypeName(toNative);
- QString targetTypeName = fixedCppTypeName(targetType);
- writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
-
- // Python to C++ convertible check function.
- QString typeCheck = toNative->sourceTypeCheck();
- if (typeCheck.isEmpty()) {
- QString pyTypeName = toNative->sourceTypeName();
- if (pyTypeName == QLatin1String("Py_None") || pyTypeName == QLatin1String("PyNone"))
- typeCheck = QLatin1String("%in == Py_None");
- else if (pyTypeName == QLatin1String("SbkEnumType"))
- typeCheck = QLatin1String("Shiboken::isShibokenEnum(%in)");
- else if (pyTypeName == QLatin1String("SbkObject"))
- typeCheck = QLatin1String("Shiboken::Object::checkType(%in)");
- else if (pyTypeName == QLatin1String("PyTypeObject"))
- typeCheck = QLatin1String("PyType_Check(%in)");
- else if (pyTypeName == QLatin1String("PyObject"))
- typeCheck = QLatin1String("PyObject_TypeCheck(%in, &PyBaseObject_Type)");
- // PYSIDE-795: We abuse PySequence for iterables
- else if (pyTypeName == QLatin1String("PySequence"))
- typeCheck = QLatin1String("Shiboken::String::checkIterable(%in)");
- else if (pyTypeName.startsWith(QLatin1String("Py")))
- typeCheck = pyTypeName + QLatin1String("_Check(%in)");
- }
- if (typeCheck.isEmpty()) {
- if (!toNative->sourceType() || toNative->sourceType()->isPrimitive()) {
- qFatal("User added implicit conversion for C++ type '%s' must provide either an input "\
- "type check function or a non primitive type entry.",
- qPrintable(targetType->qualifiedCppName()));
-
- }
- typeCheck = QString::fromLatin1("PyObject_TypeCheck(%in, %1)").arg(cpythonTypeNameExt(toNative->sourceType()));
- }
- typeCheck.replace(QLatin1String("%in"), QLatin1String("pyIn"));
- processCodeSnip(typeCheck);
- writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck);
-}
-
-void CppGenerator::writePythonToCppConversionFunctions(QTextStream &s, const AbstractMetaType *containerType)
-{
- const CustomConversion *customConversion = containerType->typeEntry()->customConversion();
- if (!customConversion) {
- //qFatal
- return;
- }
- const CustomConversion::TargetToNativeConversions &toCppConversions = customConversion->targetToNativeConversions();
- if (toCppConversions.isEmpty()) {
- //qFatal
- return;
- }
- // Python to C++ conversion function.
- QString cppTypeName = getFullTypeNameWithoutModifiers(containerType);
- QString code;
- QTextStream c(&code);
- c << INDENT << "auto &cppOutRef = *reinterpret_cast<"
- << cppTypeName << " *>(cppOut);\n";
- code.append(toCppConversions.constFirst()->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)) {
- for (int pos = 0; ; ) {
- const QRegularExpressionMatch match = convertToCppRegEx().match(code, pos);
- if (!match.hasMatch())
- break;
- pos = match.capturedEnd();
- const QString varName = match.captured(1);
- QString rightCode = code.mid(pos);
- rightCode.replace(varName, QLatin1Char('*') + varName);
- code.replace(pos, code.size() - pos, rightCode);
- }
- typeName.append(QLatin1String(" *"));
- }
- code.replace(QString::fromLatin1("%OUTTYPE_%1").arg(i), typeName);
- }
- code.replace(QLatin1String("%OUTTYPE"), cppTypeName);
- code.replace(QLatin1String("%in"), QLatin1String("pyIn"));
- code.replace(QLatin1String("%out"), QLatin1String("cppOutRef"));
- QString typeName = fixedCppTypeName(containerType);
- writePythonToCppFunction(s, code, typeName, typeName);
-
- // Python to C++ convertible check function.
- QString typeCheck = cpythonCheckFunction(containerType);
- if (typeCheck.isEmpty())
- typeCheck = QLatin1String("false");
- else
- typeCheck = QString::fromLatin1("%1pyIn)").arg(typeCheck);
- writeIsPythonConvertibleToCppFunction(s, typeName, typeName, typeCheck);
- s << Qt::endl;
-}
-
-void CppGenerator::writeAddPythonToCppConversion(QTextStream &s, const QString &converterVar, const QString &pythonToCppFunc, const QString &isConvertibleFunc)
-{
- s << INDENT << "Shiboken::Conversions::addPythonToCppValueConversion(" << converterVar << ',' << Qt::endl;
- {
- Indentation indent(INDENT);
- s << INDENT << pythonToCppFunc << ',' << Qt::endl;
- s << INDENT << isConvertibleFunc;
- }
- s << ");\n";
-}
-
-void CppGenerator::writeNamedArgumentResolution(QTextStream &s, const AbstractMetaFunction *func, bool usePyArgs)
-{
- const AbstractMetaArgumentList &args = OverloadData::getArgumentsWithDefaultValues(func);
- if (args.isEmpty())
- return;
-
- QString pyErrString(QLatin1String("PyErr_SetString(PyExc_TypeError, \"") + fullPythonFunctionName(func)
- + QLatin1String("(): got multiple values for keyword argument '%1'.\");"));
-
- s << INDENT << "if (kwds) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "PyObject *keyName = nullptr;\n";
- s << INDENT << "PyObject *value = nullptr;\n";
- for (const AbstractMetaArgument *arg : args) {
- int pyArgIndex = arg->argumentIndex() - OverloadData::numberOfRemovedArguments(func, arg->argumentIndex());
- QString pyArgName = usePyArgs ? pythonArgsAt(pyArgIndex) : QLatin1String(PYTHON_ARG);
- s << INDENT << "keyName = Py_BuildValue(\"s\",\"" << arg->name() << "\");\n";
- s << INDENT << "if (PyDict_Contains(kwds, keyName)) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "value = PyDict_GetItem(kwds, keyName);\n";
- s << INDENT << "if (value && " << pyArgName << ") {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << pyErrString.arg(arg->name()) << Qt::endl;
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
- }
- s << INDENT << "}\n";
- s << INDENT << "if (value) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << pyArgName << " = value;\n";
- s << INDENT << "if (!";
- writeTypeCheck(s, arg->type(), pyArgName, isNumber(arg->type()->typeEntry()), func->typeReplaced(arg->argumentIndex() + 1));
- s << ")\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "goto " << cpythonFunctionName(func) << "_TypeError;\n";
- }
- }
- s << INDENT << "}\n";
- }
- s << INDENT << "}\n";
- }
- }
- s << INDENT << "}\n";
-}
-
-QString CppGenerator::argumentNameFromIndex(const AbstractMetaFunction *func, int argIndex, const AbstractMetaClass **wrappedClass)
-{
- *wrappedClass = nullptr;
- QString pyArgName;
- if (argIndex == -1) {
- pyArgName = QLatin1String("self");
- *wrappedClass = func->implementingClass();
- } else if (argIndex == 0) {
- AbstractMetaType *funcType = func->type();
- AbstractMetaType *returnType = getTypeWithoutContainer(funcType);
- if (returnType) {
- pyArgName = QLatin1String(PYTHON_RETURN_VAR);
- *wrappedClass = AbstractMetaClass::findClass(classes(), returnType->typeEntry());
- } else {
- QString message = QLatin1String("Invalid Argument index (0, return value) on function modification: ")
- + (funcType ? funcType->name() : QLatin1String("void")) + QLatin1Char(' ');
- if (const AbstractMetaClass *declaringClass = func->declaringClass())
- message += declaringClass->name() + QLatin1String("::");
- message += func->name() + QLatin1String("()");
- qCWarning(lcShiboken).noquote().nospace() << message;
- }
- } else {
- int realIndex = argIndex - 1 - OverloadData::numberOfRemovedArguments(func, argIndex - 1);
- AbstractMetaType *argType = getTypeWithoutContainer(func->arguments().at(realIndex)->type());
-
- if (argType) {
- *wrappedClass = AbstractMetaClass::findClass(classes(), argType->typeEntry());
- if (argIndex == 1
- && !func->isConstructor()
- && OverloadData::isSingleArgument(getFunctionGroups(func->implementingClass())[func->name()]))
- pyArgName = QLatin1String(PYTHON_ARG);
- else
- pyArgName = pythonArgsAt(argIndex - 1);
- }
- }
- return pyArgName;
-}
-
-static QStringList defaultExceptionHandling()
-{
- static const QStringList result{
- QLatin1String("} catch (const std::exception &e) {"),
- QLatin1String(" PyErr_SetString(PyExc_RuntimeError, e.what());"),
- QLatin1String("} catch (...) {"),
- QLatin1String(" PyErr_SetString(PyExc_RuntimeError, \"An unknown exception was caught\");"),
- QLatin1String("}")};
- return result;
-}
-
-void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *func,
- GeneratorContext &context, int maxArgs)
-{
- s << INDENT << "// " << func->minimalSignature() << (func->isReverseOperator() ? " [reverse operator]": "") << Qt::endl;
- if (func->isConstructor()) {
- const CodeSnipList &snips = func->injectedCodeSnips();
- for (const CodeSnip &cs : snips) {
- if (cs.position == TypeSystem::CodeSnipPositionEnd) {
- s << INDENT << "overloadId = " << func->ownerClass()->functions().indexOf(const_cast<AbstractMetaFunction *const>(func)) << ";\n";
- break;
- }
- }
- }
-
- if (func->isAbstract()) {
- s << INDENT << "if (Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject *>(self))) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '";
- s << func->ownerClass()->name() << '.' << func->name() << "()' not implemented.\");\n";
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
- }
- s << INDENT << "}\n";
- }
-
- // Used to provide contextual information to custom code writer function.
- const AbstractMetaArgument *lastArg = nullptr;
-
- 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().constLast();
- }
-
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode, func, lastArg);
- s << Qt::endl;
- }
-
- writeConversionRule(s, func, TypeSystem::NativeCode);
-
- if (!func->isUserAdded()) {
- QStringList userArgs;
- if (func->functionType() != AbstractMetaFunction::CopyConstructorFunction) {
- int removedArgs = 0;
- for (int i = 0; i < maxArgs + removedArgs; i++) {
- const AbstractMetaArgument *arg = func->arguments().at(i);
- bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, arg->argumentIndex() + 1).isEmpty();
- if (func->argumentRemoved(i + 1)) {
- // If some argument with default value is removed from a
- // method signature, the said value must be explicitly
- // added to the method call.
- removedArgs++;
-
- // If have conversion rules I will use this for removed args
- if (hasConversionRule)
- userArgs << arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX);
- else if (!arg->defaultValueExpression().isEmpty())
- userArgs.append(QLatin1String(CPP_ARG_REMOVED) + QString::number(i));
- } else {
- int idx = arg->argumentIndex() - removedArgs;
- bool deRef = isValueTypeWithCopyConstructorOnly(arg->type())
- || isObjectTypeUsedAsValueType(arg->type())
- || (arg->type()->referenceType() == LValueReference && isWrapperType(arg->type()) && !isPointer(arg->type()));
- if (hasConversionRule) {
- userArgs.append(arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX));
- } else {
- QString argName;
- if (deRef)
- argName += QLatin1Char('*');
- argName += QLatin1String(CPP_ARG) + QString::number(idx);
- userArgs.append(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);
- const bool defValModified = arg->hasModifiedDefaultValueExpression();
- bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, arg->argumentIndex() + 1).isEmpty();
- if (argsClear && !defValModified && !hasConversionRule)
- continue;
- argsClear = false;
- otherArgsModified |= defValModified || hasConversionRule || func->argumentRemoved(i + 1);
- if (hasConversionRule)
- otherArgs.prepend(arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX));
- else
- otherArgs.prepend(QLatin1String(CPP_ARG_REMOVED) + QString::number(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(QLatin1Char('('));
- if (!func->isPointerOperator()) // no de-reference operator
- firstArg += QLatin1Char('*');
- firstArg += QLatin1String(CPP_SELF_VAR);
- firstArg += QLatin1Char(')');
- QString secondArg = QLatin1String(CPP_ARG0);
- if (!func->isUnaryOperator() && shouldDereferenceArgumentPointer(func->arguments().constFirst())) {
- secondArg.prepend(QLatin1String("(*"));
- secondArg.append(QLatin1Char(')'));
- }
-
- if (func->isUnaryOperator())
- std::swap(firstArg, secondArg);
-
- QString op = func->originalName();
- op = op.right(op.size() - (sizeof("operator")/sizeof(char)-1));
-
- if (func->isBinaryOperator()) {
- if (func->isReverseOperator())
- std::swap(firstArg, secondArg);
-
- if (((op == QLatin1String("++")) || (op == QLatin1String("--"))) && !func->isReverseOperator()) {
- s << Qt::endl << INDENT << "for (int i=0; i < " << secondArg << "; i++, " << firstArg << op << ");\n";
- mc << firstArg;
- } else {
- mc << firstArg << ' ' << op << ' ' << secondArg;
- }
- } else {
- mc << op << ' ' << secondArg;
- }
- } else if (!injectedCodeCallsCppFunction(func)) {
- if (func->isConstructor()) {
- isCtor = true;
- QString className = wrapperName(func->ownerClass());
-
- if (func->functionType() == AbstractMetaFunction::CopyConstructorFunction && maxArgs == 1) {
- mc << "new ::" << className << "(*" << CPP_ARG0 << ')';
- } else {
- QString ctorCall = className + QLatin1Char('(') + userArgs.join(QLatin1String(", ")) + QLatin1Char(')');
- if (usePySideExtensions() && func->ownerClass()->isQObject()) {
- s << INDENT << "void *addr = PySide::nextQObjectMemoryAddr();\n";
- uva << "if (addr) {\n";
- {
- Indentation indent(INDENT);
-
- uva << INDENT << "cptr = " << "new (addr) ::"
- << ctorCall << ";\n"
- << INDENT
- << "PySide::setNextQObjectMemoryAddr(0);"
- << Qt::endl;
- }
- uva << INDENT << "} else {\n";
- {
- Indentation indent(INDENT);
-
- uva << INDENT << "cptr = " << "new ::"
- << ctorCall << ";\n";
- }
- uva << INDENT << "}\n";
- } else {
- mc << "new ::" << ctorCall;
- }
- }
- } else {
- QString methodCallClassName;
- if (context.forSmartPointer())
- methodCallClassName = context.preciseType()->cppSignature();
- else if (func->ownerClass())
- methodCallClassName = func->ownerClass()->qualifiedCppName();
-
- if (func->ownerClass()) {
- if (!avoidProtectedHack() || !func->isProtected()) {
- if (func->isStatic()) {
- mc << "::" << methodCallClassName << "::";
- } else {
- const QString selfVarCast = func->ownerClass() == func->implementingClass()
- ? QLatin1String(CPP_SELF_VAR)
- : QLatin1String("reinterpret_cast<") + methodCallClassName
- + QLatin1String(" *>(") + QLatin1String(CPP_SELF_VAR) + QLatin1Char(')');
- if (func->isConstant()) {
- if (avoidProtectedHack()) {
- mc << "const_cast<const ::";
- if (func->ownerClass()->hasProtectedMembers()) {
- // PYSIDE-500: Need a special wrapper cast when inherited
- const QString selfWrapCast = func->ownerClass() == func->implementingClass()
- ? QLatin1String(CPP_SELF_VAR)
- : QLatin1String("reinterpret_cast<") + wrapperName(func->ownerClass())
- + QLatin1String(" *>(") + QLatin1String(CPP_SELF_VAR) + QLatin1Char(')');
- mc << wrapperName(func->ownerClass());
- mc << " *>(" << selfWrapCast << ")->";
- }
- else {
- mc << methodCallClassName;
- mc << " *>(" << selfVarCast << ")->";
- }
- } else {
- mc << "const_cast<const ::" << methodCallClassName;
- mc << " *>(" << selfVarCast << ")->";
- }
- } else {
- mc << selfVarCast << "->";
- }
- }
-
- if (!func->isAbstract() && func->isVirtual())
- mc << "::%CLASS_NAME::";
-
- mc << func->originalName();
- } else {
- if (!func->isStatic()) {
- const auto *owner = func->ownerClass();
- const bool directInheritance = context.metaClass() == owner;
- mc << (directInheritance ? "static_cast" : "reinterpret_cast")
- << "<::" << wrapperName(owner) << " *>(" << CPP_SELF_VAR << ")->";
- }
-
- if (!func->isAbstract())
- mc << (func->isProtected() ? wrapperName(func->ownerClass()) :
- QLatin1String("::")
- + methodCallClassName) << "::";
- mc << func->originalName() << "_protected";
- }
- } else {
- mc << func->originalName();
- }
- mc << '(' << userArgs.join(QLatin1String(", ")) << ')';
- if (!func->isAbstract() && func->isVirtual()) {
- mc.flush();
- if (!avoidProtectedHack() || !func->isProtected()) {
- QString virtualCall(methodCall);
- QString normalCall(methodCall);
- virtualCall = virtualCall.replace(QLatin1String("%CLASS_NAME"),
- methodCallClassName);
- normalCall.remove(QLatin1String("::%CLASS_NAME::"));
- methodCall.clear();
- mc << "Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject *>(self)) ? ";
- mc << virtualCall << " : " << normalCall;
- }
- }
- }
- }
-
- if (!injectedCodeCallsCppFunction(func)) {
- const bool allowThread = func->allowThread();
- const bool generateExceptionHandling = func->generateExceptionHandling();
- if (generateExceptionHandling) {
- s << INDENT << "try {\n";
- ++INDENT.indent;
- if (allowThread) {
- s << INDENT << "Shiboken::ThreadStateSaver threadSaver;\n"
- << INDENT << "threadSaver.save();\n";
- }
- } else if (allowThread) {
- s << INDENT << BEGIN_ALLOW_THREADS << Qt::endl;
- }
- s << INDENT;
- if (isCtor) {
- s << (useVAddr.isEmpty() ?
- QString::fromLatin1("cptr = %1;").arg(methodCall) : useVAddr) << Qt::endl;
- } else if (func->type() && !func->isInplaceOperator()) {
- bool writeReturnType = true;
- if (avoidProtectedHack()) {
- const AbstractMetaEnum *metaEnum = findAbstractMetaEnum(func->type());
- if (metaEnum) {
- QString enumName;
- if (metaEnum->isProtected())
- enumName = protectedEnumSurrogateName(metaEnum);
- else
- enumName = func->type()->cppSignature();
- methodCall.prepend(enumName + QLatin1Char('('));
- methodCall.append(QLatin1Char(')'));
- s << enumName;
- writeReturnType = false;
- }
- }
- if (writeReturnType) {
- s << func->type()->cppSignature();
- if (isObjectTypeUsedAsValueType(func->type())) {
- s << '*';
- methodCall.prepend(QString::fromLatin1("new %1(").arg(func->type()->typeEntry()->qualifiedCppName()));
- methodCall.append(QLatin1Char(')'));
- }
- }
- s << " " << CPP_RETURN_VAR << " = ";
- s << methodCall << ";\n";
- } else {
- s << methodCall << ";\n";
- }
-
- if (allowThread) {
- s << INDENT << (generateExceptionHandling
- ? "threadSaver.restore();" : END_ALLOW_THREADS) << '\n';
- }
-
- // Convert result
- if (!func->conversionRule(TypeSystem::TargetLangCode, 0).isEmpty()) {
- writeConversionRule(s, func, TypeSystem::TargetLangCode, QLatin1String(PYTHON_RETURN_VAR));
- } else if (!isCtor && !func->isInplaceOperator() && func->type()
- && !injectedCodeHasReturnValueAttribution(func, TypeSystem::TargetLangCode)) {
- s << INDENT << PYTHON_RETURN_VAR << " = ";
- if (isObjectTypeUsedAsValueType(func->type())) {
- s << "Shiboken::Object::newObject(reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(func->type()->typeEntry())
- << "), " << CPP_RETURN_VAR << ", true, true)";
- } else {
- writeToPythonConversion(s, func->type(), func->ownerClass(), QLatin1String(CPP_RETURN_VAR));
- }
- s << ";\n";
- }
-
- if (generateExceptionHandling) { // "catch" code
- --INDENT.indent;
- const QStringList handlingCode = defaultExceptionHandling();
- for (const auto &line : handlingCode)
- s << INDENT << line << '\n';
- }
- }
- }
-
- if (func->hasInjectedCode() && !func->isConstructor()) {
- s << Qt::endl;
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode, func, lastArg);
- }
-
- bool hasReturnPolicy = false;
-
- // Ownership transference between C++ and Python.
- QVector<ArgumentModification> ownership_mods;
- // Python object reference management.
- QVector<ArgumentModification> refcount_mods;
- const FunctionModificationList &funcMods = func->modifications();
- for (const FunctionModification &func_mod : funcMods) {
- for (const ArgumentModification &arg_mod : func_mod.argument_mods) {
- if (!arg_mod.ownerships.isEmpty() && arg_mod.ownerships.contains(TypeSystem::TargetLangCode))
- ownership_mods.append(arg_mod);
- else if (!arg_mod.referenceCounts.isEmpty())
- refcount_mods.append(arg_mod);
- }
- }
-
- // If there's already a setParent(return, me), don't use the return heuristic!
- if (func->argumentOwner(func->ownerClass(), -1).index == 0)
- hasReturnPolicy = true;
-
- if (!ownership_mods.isEmpty()) {
- s << Qt::endl << INDENT << "// Ownership transferences.\n";
- for (const ArgumentModification &arg_mod : qAsConst(ownership_mods)) {
- const AbstractMetaClass *wrappedClass = nullptr;
- QString pyArgName = argumentNameFromIndex(func, arg_mod.index, &wrappedClass);
- if (!wrappedClass) {
- s << "#error Invalid ownership modification for argument " << arg_mod.index << '(' << pyArgName << ")\n" << Qt::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 << Qt::endl;
- }
-
- } else if (!refcount_mods.isEmpty()) {
- for (const ArgumentModification &arg_mod : qAsConst(refcount_mods)) {
- ReferenceCount refCount = arg_mod.referenceCounts.constFirst();
- if (refCount.action != ReferenceCount::Set
- && refCount.action != ReferenceCount::Remove
- && refCount.action != ReferenceCount::Add) {
- qCWarning(lcShiboken) << "\"set\", \"add\" and \"remove\" are the only values supported by Shiboken for action attribute of reference-count tag.";
- continue;
- }
- const AbstractMetaClass *wrappedClass = nullptr;
-
- QString pyArgName;
- if (refCount.action == ReferenceCount::Remove) {
- pyArgName = QLatin1String("Py_None");
- } else {
- pyArgName = argumentNameFromIndex(func, arg_mod.index, &wrappedClass);
- if (pyArgName.isEmpty()) {
- s << "#error Invalid reference count modification for argument " << arg_mod.index << Qt::endl << Qt::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 *>(self), \"";
- QString varName = arg_mod.referenceCounts.constFirst().varName;
- if (varName.isEmpty())
- varName = func->minimalSignature() + QString::number(arg_mod.index);
-
- s << varName << "\", " << pyArgName
- << (refCount.action == ReferenceCount::Add ? ", true" : "")
- << ");\n";
-
- if (arg_mod.index == 0)
- hasReturnPolicy = true;
- }
- }
- writeParentChildManagement(s, func, !hasReturnPolicy);
-}
-
-QStringList CppGenerator::getAncestorMultipleInheritance(const AbstractMetaClass *metaClass)
-{
- QStringList result;
- const AbstractMetaClassList &baseClases = getBaseClasses(metaClass);
- if (!baseClases.isEmpty()) {
- for (const AbstractMetaClass *baseClass : baseClases) {
- QString offset;
- QTextStream(&offset) << "reinterpret_cast<uintptr_t>(static_cast<const "
- << baseClass->qualifiedCppName() << " *>(class_ptr)) - base";
- result.append(offset);
- offset.clear();
- QTextStream(&offset) << "reinterpret_cast<uintptr_t>(static_cast<const "
- << baseClass->qualifiedCppName() << " *>(static_cast<const "
- << metaClass->qualifiedCppName()
- << " *>(static_cast<const void *>(class_ptr)))) - base";
- result.append(offset);
- }
-
- for (const AbstractMetaClass *baseClass : baseClases)
- result.append(getAncestorMultipleInheritance(baseClass));
- }
- return result;
-}
-
-void CppGenerator::writeMultipleInheritanceInitializerFunction(QTextStream &s, const AbstractMetaClass *metaClass)
-{
- QString className = metaClass->qualifiedCppName();
- const QStringList ancestors = getAncestorMultipleInheritance(metaClass);
- s << "static int mi_offsets[] = { ";
- for (int i = 0; i < ancestors.size(); i++)
- s << "-1, ";
- s << "-1 };\n";
- s << "int *\n";
- s << multipleInheritanceInitializerFunctionName(metaClass) << "(const void *cptr)\n";
- s << "{\n";
- s << INDENT << "if (mi_offsets[0] == -1) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "std::set<int> offsets;\n";
- s << INDENT << "const auto *class_ptr = reinterpret_cast<const " << className << " *>(cptr);\n";
- s << INDENT << "const auto base = reinterpret_cast<uintptr_t>(class_ptr);\n";
-
- for (const QString &ancestor : ancestors)
- s << INDENT << "offsets.insert(int(" << ancestor << "));\n";
-
- s << Qt::endl;
- s << INDENT << "offsets.erase(0);\n";
- s << Qt::endl;
-
- s << INDENT << "std::copy(offsets.cbegin(), offsets.cend(), mi_offsets);\n";
- }
- s << INDENT << "}\n";
- s << INDENT << "return mi_offsets;\n";
- s << "}\n";
-}
-
-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 << "auto me = reinterpret_cast< ::" << className << " *>(obj);\n";
- bool firstClass = true;
- const AbstractMetaClassList &allAncestors = getAllAncestors(metaClass);
- for (const AbstractMetaClass *baseClass : allAncestors) {
- 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() << "'.\n";
- s << INDENT << converter << " = Shiboken::Conversions::createConverter(";
- if (type->targetLangApiName() == type->name())
- s << '0';
- else if (type->targetLangApiName() == QLatin1String("PyObject"))
- s << "&PyBaseObject_Type";
- else
- s << '&' << type->targetLangApiName() << "_Type";
- QString typeName = fixedCppTypeName(type);
- s << ", " << cppToPythonFunctionName(typeName, typeName) << ");\n";
- s << INDENT << "Shiboken::Conversions::registerConverterName(" << converter << ", \"" << type->qualifiedCppName() << "\");\n";
- writeCustomConverterRegister(s, customConversion, converter);
-}
-
-void CppGenerator::writeEnumConverterInitialization(QTextStream &s, const AbstractMetaEnum *metaEnum)
-{
- if (metaEnum->isPrivate() || metaEnum->isAnonymous())
- return;
- writeEnumConverterInitialization(s, metaEnum->typeEntry());
-}
-
-void CppGenerator::writeEnumConverterInitialization(QTextStream &s, const TypeEntry *enumType)
-{
- if (!enumType)
- return;
- QString enumFlagName = enumType->isFlags() ? QLatin1String("flag") : QLatin1String("enum");
- QString enumPythonType = cpythonTypeNameExt(enumType);
-
- const FlagsTypeEntry *flags = nullptr;
- if (enumType->isFlags())
- flags = static_cast<const FlagsTypeEntry *>(enumType);
-
- s << INDENT << "// Register converter for " << enumFlagName << " '" << enumType->qualifiedCppName() << "'.\n";
- s << INDENT << "{\n";
- {
- Indentation indent(INDENT);
- QString typeName = fixedCppTypeName(enumType);
- s << INDENT << "SbkConverter *converter = Shiboken::Conversions::createConverter(" << enumPythonType << ',' << Qt::endl;
- {
- Indentation indent(INDENT);
- s << INDENT << cppToPythonFunctionName(typeName, typeName) << ");\n";
- }
-
- if (flags) {
- QString enumTypeName = fixedCppTypeName(flags->originator());
- QString toCpp = pythonToCppFunctionName(enumTypeName, typeName);
- QString isConv = convertibleToCppFunctionName(enumTypeName, typeName);
- writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
- }
-
- QString toCpp = pythonToCppFunctionName(typeName, typeName);
- QString isConv = convertibleToCppFunctionName(typeName, typeName);
- writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
-
- if (flags) {
- QString toCpp = pythonToCppFunctionName(QLatin1String("number"), typeName);
- QString isConv = convertibleToCppFunctionName(QLatin1String("number"), typeName);
- writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
- }
-
- s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", converter);\n";
-
- QString signature = enumType->qualifiedCppName();
- // Replace "QFlags<Class::Option>" by "Class::Options"
- if (flags && signature.startsWith(QLatin1String("QFlags<")) && signature.endsWith(QLatin1Char('>'))) {
- signature.chop(1);
- signature.remove(0, 7);
- const int lastQualifierPos = signature.lastIndexOf(QLatin1String("::"));
- if (lastQualifierPos != -1) {
- signature.replace(lastQualifierPos + 2, signature.size() - lastQualifierPos - 2,
- flags->flagsName());
- } else {
- signature = flags->flagsName();
- }
- }
-
- while (true) {
- s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \""
- << signature << "\");\n";
- const int qualifierPos = signature.indexOf(QLatin1String("::"));
- if (qualifierPos != -1)
- signature.remove(0, qualifierPos + 2);
- else
- break;
- }
- }
- s << INDENT << "}\n";
-
- if (!flags)
- writeEnumConverterInitialization(s, static_cast<const EnumTypeEntry *>(enumType)->flags());
-}
-
-void CppGenerator::writeContainerConverterInitialization(QTextStream &s, const AbstractMetaType *type)
-{
- QByteArray cppSignature = QMetaObject::normalizedSignature(type->cppSignature().toUtf8());
- s << INDENT << "// Register converter for type '" << cppSignature << "'.\n";
- QString converter = converterObject(type);
- s << INDENT << converter << " = Shiboken::Conversions::createConverter(";
- if (type->typeEntry()->targetLangApiName() == QLatin1String("PyObject")) {
- s << "&PyBaseObject_Type";
- } else {
- QString baseName = cpythonBaseName(type->typeEntry());
- if (baseName == QLatin1String("PySequence"))
- baseName = QLatin1String("PyList");
- s << '&' << baseName << "_Type";
- }
- QString typeName = fixedCppTypeName(type);
- s << ", " << cppToPythonFunctionName(typeName, typeName) << ");\n";
- QString toCpp = pythonToCppFunctionName(typeName, typeName);
- QString isConv = convertibleToCppFunctionName(typeName, typeName);
- s << INDENT << "Shiboken::Conversions::registerConverterName(" << converter << ", \"" << cppSignature << "\");\n";
- 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 << "\");\n";
- }
- writeAddPythonToCppConversion(s, converterObject(type), toCpp, isConv);
-}
-
-void CppGenerator::writeExtendedConverterInitialization(QTextStream &s, const TypeEntry *externalType,
- const QVector<const AbstractMetaClass *>& conversions)
-{
- s << INDENT << "// Extended implicit conversions for " << externalType->qualifiedTargetLangName() << '.' << Qt::endl;
- for (const AbstractMetaClass *sourceClass : conversions) {
- const QString converterVar = QLatin1String("reinterpret_cast<SbkObjectType *>(")
- + cppApiVariableName(externalType->targetLangPackage()) + QLatin1Char('[')
- + getTypeIndexVariableName(externalType) + QLatin1String("])");
- QString sourceTypeName = fixedCppTypeName(sourceClass->typeEntry());
- QString targetTypeName = fixedCppTypeName(externalType);
- QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName);
- QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName);
- writeAddPythonToCppConversion(s, converterVar, toCpp, isConv);
- }
-}
-
-QString CppGenerator::multipleInheritanceInitializerFunctionName(const AbstractMetaClass *metaClass)
-{
- return cpythonBaseName(metaClass->typeEntry()) + QLatin1String("_mi_init");
-}
-
-bool CppGenerator::supportsMappingProtocol(const AbstractMetaClass *metaClass)
-{
- for (auto it = m_mappingProtocol.cbegin(), end = m_mappingProtocol.cend(); it != end; ++it) {
- if (metaClass->hasFunction(it.key()))
- return true;
- }
-
- return false;
-}
-
-bool CppGenerator::supportsNumberProtocol(const AbstractMetaClass *metaClass)
-{
- return metaClass->hasArithmeticOperatorOverload()
- || metaClass->hasLogicalOperatorOverload()
- || metaClass->hasBitwiseOperatorOverload()
- || hasBoolCast(metaClass);
-}
-
-bool CppGenerator::supportsSequenceProtocol(const AbstractMetaClass *metaClass)
-{
- for (auto it = m_sequenceProtocol.cbegin(), end = m_sequenceProtocol.cend(); it != end; ++it) {
- if (metaClass->hasFunction(it.key()))
- return true;
- }
-
- const ComplexTypeEntry *baseType = metaClass->typeEntry()->baseContainerType();
- return baseType && baseType->isContainer();
-}
-
-bool CppGenerator::shouldGenerateGetSetList(const AbstractMetaClass *metaClass)
-{
- const AbstractMetaFieldList &fields = metaClass->fields();
- for (const AbstractMetaField *f : fields) {
- if (!f->isStatic())
- return true;
- }
- return false;
-}
-
-struct pyTypeSlotEntry
-{
- explicit pyTypeSlotEntry(const char *name, const QString &function) :
- m_name(name), m_function(function) {}
-
- const char *m_name;
- const QString &m_function;
-};
-
-QTextStream &operator<<(QTextStream &str, const pyTypeSlotEntry &e)
-{
- str << '{' << e.m_name << ',';
- const int padding = qMax(0, 18 - int(strlen(e.m_name)));
- for (int p = 0; p < padding; ++p)
- str << ' ';
- if (e.m_function.isEmpty())
- str << NULL_PTR;
- else
- str << "reinterpret_cast<void *>(" << e.m_function << ')';
- str << "},\n";
- return str;
-}
-
-void CppGenerator::writeClassDefinition(QTextStream &s,
- const AbstractMetaClass *metaClass,
- GeneratorContext &classContext)
-{
- QString tp_flags;
- QString tp_init;
- QString tp_new;
- QString tp_dealloc;
- QString tp_hash;
- QString tp_call;
- QString cppClassName = metaClass->qualifiedCppName();
- const QString className = chopType(cpythonTypeName(metaClass));
- QString baseClassName;
- AbstractMetaFunctionList ctors;
- const AbstractMetaFunctionList &allCtors = metaClass->queryFunctions(AbstractMetaClass::Constructors);
- for (AbstractMetaFunction *f : allCtors) {
- if (!f->isPrivate() && !f->isModifiedRemoved() && !classContext.forSmartPointer())
- ctors.append(f);
- }
-
- if (!metaClass->baseClass())
- baseClassName = QLatin1String("reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())");
-
- bool onlyPrivCtor = !metaClass->hasNonPrivateConstructor();
-
- const AbstractMetaClass *qCoreApp = AbstractMetaClass::findClass(classes(), QLatin1String("QCoreApplication"));
- const bool isQApp = qCoreApp != Q_NULLPTR && metaClass->inheritsFrom(qCoreApp);
-
- tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES");
- if (metaClass->isNamespace() || metaClass->hasPrivateDestructor()) {
- tp_dealloc = metaClass->hasPrivateDestructor() ?
- QLatin1String("SbkDeallocWrapperWithPrivateDtor") :
- QLatin1String("Sbk_object_dealloc /* PYSIDE-832: Prevent replacement of \"0\" with subtype_dealloc. */");
- tp_init.clear();
- } else {
- QString deallocClassName;
- if (shouldGenerateCppWrapper(metaClass))
- deallocClassName = wrapperName(metaClass);
- else
- deallocClassName = cppClassName;
- if (isQApp)
- tp_dealloc = QLatin1String("&SbkDeallocQAppWrapper");
- else
- tp_dealloc = QLatin1String("&SbkDeallocWrapper");
- if (!onlyPrivCtor && !ctors.isEmpty())
- tp_init = cpythonFunctionName(ctors.constFirst());
- }
-
- QString tp_getattro;
- QString tp_setattro;
- if (usePySideExtensions() && (metaClass->qualifiedCppName() == QLatin1String("QObject"))) {
- tp_getattro = cpythonGetattroFunctionName(metaClass);
- tp_setattro = cpythonSetattroFunctionName(metaClass);
- } else {
- if (classNeedsGetattroFunction(metaClass))
- tp_getattro = cpythonGetattroFunctionName(metaClass);
- if (classNeedsSetattroFunction(metaClass))
- tp_setattro = cpythonSetattroFunctionName(metaClass);
- }
-
- if (metaClass->hasPrivateDestructor() || onlyPrivCtor) {
- // tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES");
- // This is not generally possible, because PySide does not care about
- // privacy the same way. This worked before the heap types were used,
- // because inheritance is not really checked for static types.
- // Instead, we check this at runtime, see SbkObjectTypeTpNew.
- if (metaClass->fullName().startsWith(QLatin1String("PySide2.Qt"))) {
- // PYSIDE-595: No idea how to do non-inheritance correctly.
- // Since that is only relevant in shiboken, I used a shortcut for
- // PySide.
- tp_new = QLatin1String("SbkObjectTpNew");
- }
- else {
- tp_new = QLatin1String("SbkDummyNew /* PYSIDE-595: Prevent replacement "
- "of \"0\" with base->tp_new. */");
- }
- tp_flags.append(QLatin1String("|Py_TPFLAGS_HAVE_GC"));
- }
- else if (isQApp) {
- tp_new = QLatin1String("SbkQAppTpNew"); // PYSIDE-571: need singleton app
- }
- else {
- tp_new = QLatin1String("SbkObjectTpNew");
- tp_flags.append(QLatin1String("|Py_TPFLAGS_HAVE_GC"));
- }
-
- QString tp_richcompare;
- if (!metaClass->isNamespace() && metaClass->hasComparisonOperatorOverload())
- tp_richcompare = cpythonBaseName(metaClass) + QLatin1String("_richcompare");
-
- QString tp_getset;
- if (shouldGenerateGetSetList(metaClass) && !classContext.forSmartPointer())
- tp_getset = cpythonGettersSettersDefinitionName(metaClass);
-
- // search for special functions
- ShibokenGenerator::clearTpFuncs();
- const AbstractMetaFunctionList &funcs = metaClass->functions();
- for (AbstractMetaFunction *func : funcs) {
- if (m_tpFuncs.contains(func->name()))
- m_tpFuncs[func->name()] = cpythonFunctionName(func);
- }
- if (m_tpFuncs.value(QLatin1String("__repr__")).isEmpty()
- && metaClass->hasToStringCapability()) {
- m_tpFuncs[QLatin1String("__repr__")] = writeReprFunction(s,
- classContext,
- metaClass->toStringCapabilityIndirections());
- }
-
- // class or some ancestor has multiple inheritance
- const AbstractMetaClass *miClass = getMultipleInheritingClass(metaClass);
- if (miClass) {
- if (metaClass == miClass)
- writeMultipleInheritanceInitializerFunction(s, metaClass);
- writeSpecialCastFunction(s, metaClass);
- s << Qt::endl;
- }
-
- s << "// Class Definition -----------------------------------------------\n";
- s << "extern \"C\" {\n";
-
- if (!metaClass->typeEntry()->hashFunction().isEmpty())
- tp_hash = QLatin1Char('&') + cpythonBaseName(metaClass) + QLatin1String("_HashFunc");
-
- const AbstractMetaFunction *callOp = metaClass->findFunction(QLatin1String("operator()"));
- if (callOp && !callOp->isModifiedRemoved())
- tp_call = QLatin1Char('&') + cpythonFunctionName(callOp);
-
- QString computedClassTargetFullName;
- if (!classContext.forSmartPointer())
- computedClassTargetFullName = getClassTargetFullName(metaClass);
- else
- computedClassTargetFullName = getClassTargetFullName(classContext.preciseType());
-
- QString suffix;
- if (isObjectType(metaClass))
- suffix = QLatin1String(" *");
- const QString typePtr = QLatin1String("_") + className
- + QLatin1String("_Type");
- s << "static SbkObjectType *" << typePtr << " = nullptr;\n";
- s << "static SbkObjectType *" << className << "_TypeF(void)\n";
- s << "{\n";
- s << INDENT << "return " << typePtr << ";\n";
- s << "}\n";
- s << Qt::endl;
- s << "static PyType_Slot " << className << "_slots[] = {\n";
- s << INDENT << "{Py_tp_base, nullptr}, // inserted by introduceWrapperType\n";
- s << INDENT << pyTypeSlotEntry("Py_tp_dealloc", tp_dealloc)
- << INDENT << pyTypeSlotEntry("Py_tp_repr", m_tpFuncs.value(QLatin1String("__repr__")))
- << INDENT << pyTypeSlotEntry("Py_tp_hash", tp_hash)
- << INDENT << pyTypeSlotEntry("Py_tp_call", tp_call)
- << INDENT << pyTypeSlotEntry("Py_tp_str", m_tpFuncs.value(QLatin1String("__str__")))
- << INDENT << pyTypeSlotEntry("Py_tp_getattro", tp_getattro)
- << INDENT << pyTypeSlotEntry("Py_tp_setattro", tp_setattro)
- << INDENT << pyTypeSlotEntry("Py_tp_traverse", className + QLatin1String("_traverse"))
- << INDENT << pyTypeSlotEntry("Py_tp_clear", className + QLatin1String("_clear"))
- << INDENT << pyTypeSlotEntry("Py_tp_richcompare", tp_richcompare)
- << INDENT << pyTypeSlotEntry("Py_tp_iter", m_tpFuncs.value(QLatin1String("__iter__")))
- << INDENT << pyTypeSlotEntry("Py_tp_iternext", m_tpFuncs.value(QLatin1String("__next__")))
- << INDENT << pyTypeSlotEntry("Py_tp_methods", className + QLatin1String("_methods"))
- << INDENT << pyTypeSlotEntry("Py_tp_getset", tp_getset)
- << INDENT << pyTypeSlotEntry("Py_tp_init", tp_init)
- << INDENT << pyTypeSlotEntry("Py_tp_new", tp_new);
- if (supportsSequenceProtocol(metaClass)) {
- s << INDENT << "// type supports sequence protocol\n";
- writeTypeAsSequenceDefinition(s, metaClass);
- }
- if (supportsMappingProtocol(metaClass)) {
- s << INDENT << "// type supports mapping protocol\n";
- writeTypeAsMappingDefinition(s, metaClass);
- }
- if (supportsNumberProtocol(metaClass)) {
- // This one must come last. See the function itself.
- s << INDENT << "// type supports number protocol\n";
- writeTypeAsNumberDefinition(s, metaClass);
- }
- s << INDENT << "{0, " << NULL_PTR << "}\n";
- s << "};\n";
- s << "static PyType_Spec " << className << "_spec = {\n";
- s << INDENT << "\"" << computedClassTargetFullName << "\",\n";
- s << INDENT << "sizeof(SbkObject),\n";
- s << INDENT << "0,\n";
- s << INDENT << tp_flags << ",\n";
- s << INDENT << className << "_slots\n";
- s << "};\n";
- s << Qt::endl;
- s << "} //extern \"C\"" << Qt::endl;
-}
-
-void CppGenerator::writeMappingMethods(QTextStream &s,
- const AbstractMetaClass *metaClass,
- GeneratorContext &context)
-{
- for (auto it = m_mappingProtocol.cbegin(), end = m_mappingProtocol.cend(); it != end; ++it) {
- const AbstractMetaFunction *func = metaClass->findFunction(it.key());
- if (!func)
- continue;
- QString funcName = cpythonFunctionName(func);
- QString funcArgs = it.value().first;
- QString funcRetVal = it.value().second;
-
- CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
- s << funcRetVal << ' ' << funcName << '(' << funcArgs << ")\n{\n";
- writeInvalidPyObjectCheck(s, QLatin1String("self"));
-
- writeCppSelfDefinition(s, func, context);
-
- const AbstractMetaArgument *lastArg = func->arguments().isEmpty() ? nullptr : func->arguments().constLast();
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, lastArg);
- s<< "}\n\n";
- }
-}
-
-void CppGenerator::writeSequenceMethods(QTextStream &s,
- const AbstractMetaClass *metaClass,
- GeneratorContext &context)
-{
- bool injectedCode = false;
-
- for (auto it = m_sequenceProtocol.cbegin(), end = m_sequenceProtocol.cend(); it != end; ++it) {
- const AbstractMetaFunction *func = metaClass->findFunction(it.key());
- if (!func)
- continue;
- injectedCode = true;
- QString funcName = cpythonFunctionName(func);
- QString funcArgs = it.value().first;
- QString funcRetVal = it.value().second;
-
- CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
- s << funcRetVal << ' ' << funcName << '(' << funcArgs << ")\n{\n";
- writeInvalidPyObjectCheck(s, QLatin1String("self"));
-
- writeCppSelfDefinition(s, func, context);
-
- const AbstractMetaArgument *lastArg = func->arguments().isEmpty() ? 0 : func->arguments().constLast();
- writeCodeSnips(s, snips,TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, lastArg);
- s<< "}\n\n";
- }
-
- if (!injectedCode)
- writeStdListWrapperMethods(s, context);
-}
-
-void CppGenerator::writeTypeAsSequenceDefinition(QTextStream &s, const AbstractMetaClass *metaClass)
-{
- bool hasFunctions = false;
- QMap<QString, QString> funcs;
- for (auto it = m_sequenceProtocol.cbegin(), end = m_sequenceProtocol.cend(); it != end; ++it) {
- const QString &funcName = it.key();
- const AbstractMetaFunction *func = metaClass->findFunction(funcName);
- funcs[funcName] = func ? cpythonFunctionName(func).prepend(QLatin1Char('&')) : QString();
- if (!hasFunctions && func)
- hasFunctions = true;
- }
-
- QString baseName = cpythonBaseName(metaClass);
-
- //use default implementation
- if (!hasFunctions) {
- funcs[QLatin1String("__len__")] = baseName + QLatin1String("__len__");
- funcs[QLatin1String("__getitem__")] = baseName + QLatin1String("__getitem__");
- funcs[QLatin1String("__setitem__")] = baseName + QLatin1String("__setitem__");
- }
-
- for (QHash<QString, QString>::const_iterator it = m_sqFuncs.cbegin(), end = m_sqFuncs.cend(); it != end; ++it) {
- const QString &sqName = it.key();
- if (funcs[sqName].isEmpty())
- continue;
- if (it.value() == QLatin1String("sq_slice"))
- s << "#ifndef IS_PY3K\n";
- s << INDENT << "{Py_" << it.value() << ", (void *)" << funcs[sqName] << "},\n";
- if (it.value() == QLatin1String("sq_slice"))
- s << "#endif\n";
- }
-}
-
-void CppGenerator::writeTypeAsMappingDefinition(QTextStream &s, const AbstractMetaClass *metaClass)
-{
- bool hasFunctions = false;
- QMap<QString, QString> funcs;
- for (auto it = m_mappingProtocol.cbegin(), end = m_mappingProtocol.cend(); it != end; ++it) {
- const QString &funcName = it.key();
- const AbstractMetaFunction *func = metaClass->findFunction(funcName);
- funcs[funcName] = func ? cpythonFunctionName(func).prepend(QLatin1Char('&')) : QLatin1String("0");
- if (!hasFunctions && func)
- hasFunctions = true;
- }
-
- //use default implementation
- if (!hasFunctions) {
- funcs.insert(QLatin1String("__mlen__"), QString());
- funcs.insert(QLatin1String("__mgetitem__"), QString());
- funcs.insert(QLatin1String("__msetitem__"), QString());
- }
-
- for (auto it = m_mpFuncs.cbegin(), end = m_mpFuncs.cend(); it != end; ++it) {
- const QString &mpName = it.key();
- if (funcs[mpName].isEmpty())
- continue;
- s << INDENT << "{Py_" << it.value() << ", (void *)" << funcs[mpName] << "},\n";
- }
-}
-
-void CppGenerator::writeTypeAsNumberDefinition(QTextStream &s, const AbstractMetaClass *metaClass)
-{
- QMap<QString, QString> nb;
-
- nb.insert(QLatin1String("__add__"), QString());
- nb.insert(QLatin1String("__sub__"), QString());
- nb.insert(QLatin1String("__mul__"), QString());
- nb.insert(QLatin1String("__div__"), QString());
- nb.insert(QLatin1String("__mod__"), QString());
- nb.insert(QLatin1String("__neg__"), QString());
- nb.insert(QLatin1String("__pos__"), QString());
- nb.insert(QLatin1String("__invert__"), QString());
- nb.insert(QLatin1String("__lshift__"), QString());
- nb.insert(QLatin1String("__rshift__"), QString());
- nb.insert(QLatin1String("__and__"), QString());
- nb.insert(QLatin1String("__xor__"), QString());
- nb.insert(QLatin1String("__or__"), QString());
- nb.insert(QLatin1String("__iadd__"), QString());
- nb.insert(QLatin1String("__isub__"), QString());
- nb.insert(QLatin1String("__imul__"), QString());
- nb.insert(QLatin1String("__idiv__"), QString());
- nb.insert(QLatin1String("__imod__"), QString());
- nb.insert(QLatin1String("__ilshift__"), QString());
- nb.insert(QLatin1String("__irshift__"), QString());
- nb.insert(QLatin1String("__iand__"), QString());
- nb.insert(QLatin1String("__ixor__"), QString());
- nb.insert(QLatin1String("__ior__"), QString());
-
- const QVector<AbstractMetaFunctionList> opOverloads =
- filterGroupedOperatorFunctions(metaClass,
- AbstractMetaClass::ArithmeticOp
- | AbstractMetaClass::LogicalOp
- | AbstractMetaClass::BitwiseOp);
-
- for (const AbstractMetaFunctionList &opOverload : opOverloads) {
- const AbstractMetaFunction *rfunc = opOverload.at(0);
- QString opName = ShibokenGenerator::pythonOperatorFunctionName(rfunc);
- nb[opName] = cpythonFunctionName(rfunc);
- }
-
- QString baseName = cpythonBaseName(metaClass);
-
- if (hasBoolCast(metaClass))
- nb.insert(QLatin1String("bool"), baseName + QLatin1String("___nb_bool"));
-
- for (QHash<QString, QString>::const_iterator it = m_nbFuncs.cbegin(), end = m_nbFuncs.cend(); it != end; ++it) {
- const QString &nbName = it.key();
- if (nb[nbName].isEmpty())
- continue;
-
- // bool is special because the field name differs on Python 2 and 3 (nb_nonzero vs nb_bool)
- // so a shiboken macro is used.
- if (nbName == QLatin1String("bool")) {
- s << "#ifdef IS_PY3K\n";
- s << INDENT << "{Py_nb_bool, (void *)" << nb[nbName] << "},\n";
- s << "#else\n";
- s << INDENT << "{Py_nb_nonzero, (void *)" << nb[nbName] << "},\n";
- s << "#endif\n";
- } else {
- bool excludeFromPy3K = nbName == QLatin1String("__div__") || nbName == QLatin1String("__idiv__");
- if (!excludeFromPy3K)
- s << INDENT << "{Py_" << it.value() << ", (void *)" << nb[nbName] << "},\n";
- }
- }
- if (!nb[QLatin1String("__div__")].isEmpty()) {
- s << INDENT << "{Py_nb_true_divide, (void *)" << nb[QLatin1String("__div__")] << "},\n";
- s << "#ifndef IS_PY3K\n";
- s << INDENT << "{Py_nb_divide, (void *)" << nb[QLatin1String("__div__")] << "},\n";
- s << "#endif\n";
- }
- if (!nb[QLatin1String("__idiv__")].isEmpty()) {
- s << INDENT << "// This function is unused in Python 3. We reference it here.\n";
- s << INDENT << "{0, (void *)" << nb[QLatin1String("__idiv__")] << "},\n";
- s << INDENT << "// This list is ending at the first 0 entry.\n";
- s << INDENT << "// Therefore, we need to put the unused functions at the very end.\n";
- }
-}
-
-void CppGenerator::writeTpTraverseFunction(QTextStream &s, const AbstractMetaClass *metaClass)
-{
- QString baseName = cpythonBaseName(metaClass);
- s << "static int ";
- s << baseName << "_traverse(PyObject *self, visitproc visit, void *arg)\n";
- s << "{\n";
- s << INDENT << "return reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())->tp_traverse(self, visit, arg);\n";
- s << "}\n";
-}
-
-void CppGenerator::writeTpClearFunction(QTextStream &s, const AbstractMetaClass *metaClass)
-{
- QString baseName = cpythonBaseName(metaClass);
- s << "static int ";
- s << baseName << "_clear(PyObject *self)\n";
- s << "{\n";
- s << INDENT << "return reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())->tp_clear(self);\n";
- s << "}\n";
-}
-
-void CppGenerator::writeCopyFunction(QTextStream &s, GeneratorContext &context)
-{
- const AbstractMetaClass *metaClass = context.metaClass();
- const QString className = chopType(cpythonTypeName(metaClass));
- s << "static PyObject *" << className << "___copy__(PyObject *self)\n";
- s << "{\n";
- writeCppSelfDefinition(s, context, false, true);
- QString conversionCode;
- if (!context.forSmartPointer())
- conversionCode = cpythonToPythonConversionFunction(metaClass);
- else
- conversionCode = cpythonToPythonConversionFunction(context.preciseType());
-
- s << INDENT << "PyObject *" << PYTHON_RETURN_VAR << " = " << conversionCode;
- s << CPP_SELF_VAR << ");\n";
- writeFunctionReturnErrorCheckSection(s);
- s << INDENT << "return " << PYTHON_RETURN_VAR << ";\n";
- s << "}\n";
- s << Qt::endl;
-}
-
-void CppGenerator::writeGetterFunction(QTextStream &s,
- const AbstractMetaField *metaField,
- GeneratorContext &context)
-{
- ErrorCode errorCode(QString::fromLatin1(NULL_PTR));
- s << "static PyObject *" << cpythonGetterFunctionName(metaField) << "(PyObject *self, void *)\n";
- s << "{\n";
-
- writeCppSelfDefinition(s, context);
-
- AbstractMetaType *fieldType = metaField->type();
- // Force use of pointer to return internal variable memory
- bool newWrapperSameObject = !fieldType->isConstant() && isWrapperType(fieldType) && !isPointer(fieldType);
-
- QString cppField;
- if (avoidProtectedHack() && metaField->isProtected()) {
- QTextStream(&cppField) << "static_cast<"
- << wrapperName(metaField->enclosingClass()) << " *>("
- << CPP_SELF_VAR << ")->" << protectedFieldGetterName(metaField) << "()";
- } else {
- cppField = QLatin1String(CPP_SELF_VAR) + QLatin1String("->") + metaField->name();
- if (newWrapperSameObject) {
- cppField.prepend(QLatin1String("&("));
- cppField.append(QLatin1Char(')'));
- }
- }
- if (isCppIntegralPrimitive(fieldType) || fieldType->isEnum()) {
- s << INDENT << getFullTypeNameWithoutModifiers(fieldType) << " cppOut_local = " << cppField << ";\n";
- cppField = QLatin1String("cppOut_local");
- } else if (avoidProtectedHack() && metaField->isProtected()) {
- s << INDENT << getFullTypeNameWithoutModifiers(fieldType);
- if (fieldType->isContainer() || fieldType->isFlags() || fieldType->isSmartPointer()) {
- s << " &";
- cppField.prepend(QLatin1Char('*'));
- } else if ((!fieldType->isConstant() && !fieldType->isEnum() && !fieldType->isPrimitive()) || fieldType->indirections() == 1) {
- s << " *";
- }
- s << " fieldValue = " << cppField << ";\n";
- cppField = QLatin1String("fieldValue");
- }
-
- s << INDENT << "PyObject *pyOut = {};\n";
- if (newWrapperSameObject) {
- // Special case colocated field with same address (first field in a struct)
- s << INDENT << "if (reinterpret_cast<void *>("
- << cppField
- << ") == reinterpret_cast<void *>("
- << CPP_SELF_VAR << ")) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "pyOut = reinterpret_cast<PyObject *>(Shiboken::Object::findColocatedChild("
- << "reinterpret_cast<SbkObject *>(self), reinterpret_cast<SbkObjectType *>("
- << cpythonTypeNameExt(fieldType)
- << ")));\n";
- s << INDENT << "if (pyOut) {Py_IncRef(pyOut); return pyOut;}\n";
- }
- s << INDENT << "}\n";
- // Check if field wrapper has already been created.
- s << INDENT << "else if (Shiboken::BindingManager::instance().hasWrapper(" << cppField << ")) {" << "\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper("
- << cppField << "));" << "\n";
- s << INDENT << "Py_IncRef(pyOut);" << "\n";
- s << INDENT << "return pyOut;" << "\n";
- }
- s << INDENT << "}\n";
- // Create and register new wrapper
- s << INDENT << "pyOut = ";
- s << "Shiboken::Object::newObject(reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(fieldType)
- << "), " << cppField << ", false, true);\n";
- s << INDENT << "Shiboken::Object::setParent(self, pyOut)";
- } else {
- s << INDENT << "pyOut = ";
- writeToPythonConversion(s, fieldType, metaField->enclosingClass(), cppField);
- }
- s << ";\n";
-
- s << INDENT << "return pyOut;\n";
- s << "}\n";
-}
-
-void CppGenerator::writeSetterFunction(QTextStream &s,
- const AbstractMetaField *metaField,
- GeneratorContext &context)
-{
- ErrorCode errorCode(0);
- s << "static int " << cpythonSetterFunctionName(metaField) << "(PyObject *self, PyObject *pyIn, void *)\n";
- s << "{\n";
-
- writeCppSelfDefinition(s, context);
-
- s << INDENT << "if (pyIn == " << NULL_PTR << ") {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "PyErr_SetString(PyExc_TypeError, \"'";
- s << metaField->name() << "' may not be deleted\");\n";
- s << INDENT << "return -1;\n";
- }
- s << INDENT << "}\n";
-
- AbstractMetaType *fieldType = metaField->type();
-
- s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << "{nullptr};\n";
- s << INDENT << "if (!";
- writeTypeCheck(s, fieldType, QLatin1String("pyIn"), isNumber(fieldType->typeEntry()));
- s << ") {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "PyErr_SetString(PyExc_TypeError, \"wrong type attributed to '";
- s << metaField->name() << "', '" << fieldType->name() << "' or convertible type expected\");\n";
- s << INDENT << "return -1;\n";
- }
- s << INDENT<< "}\n\n";
-
- QString cppField = QString::fromLatin1("%1->%2").arg(QLatin1String(CPP_SELF_VAR), metaField->name());
- s << INDENT;
- if (avoidProtectedHack() && metaField->isProtected()) {
- s << getFullTypeNameWithoutModifiers(fieldType);
- s << (fieldType->indirections() == 1 ? " *" : "") << " cppOut;\n";
- s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut);\n";
- s << INDENT << "static_cast<" << wrapperName(metaField->enclosingClass())
- << " *>(" << CPP_SELF_VAR << ")->" << protectedFieldSetterName(metaField)
- << "(cppOut)";
- } else if (isCppIntegralPrimitive(fieldType) || fieldType->typeEntry()->isEnum() || fieldType->typeEntry()->isFlags()) {
- s << getFullTypeNameWithoutModifiers(fieldType) << " cppOut_local = " << cppField << ";\n";
- s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut_local);\n";
- s << INDENT << cppField << " = cppOut_local";
- } else {
- if (isPointerToConst(fieldType))
- s << "const ";
- s << getFullTypeNameWithoutModifiers(fieldType);
- s << QString::fromLatin1(" *").repeated(fieldType->indirections()) << "& cppOut_ptr = ";
- s << cppField << ";\n";
- s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut_ptr)";
- }
- s << ";\n" << Qt::endl;
-
- if (isPointerToWrapperType(fieldType)) {
- s << INDENT << "Shiboken::Object::keepReference(reinterpret_cast<SbkObject *>(self), \"";
- s << metaField->name() << "\", pyIn);\n";
- }
-
- s << INDENT << "return 0;\n";
- s << "}\n";
-}
-
-void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &context)
-{
- const AbstractMetaClass *metaClass = context.metaClass();
- QString baseName = cpythonBaseName(metaClass);
- s << "static PyObject * ";
- s << baseName << "_richcompare(PyObject *self, PyObject *" << PYTHON_ARG
- << ", int op)\n{\n";
- writeCppSelfDefinition(s, context, false, true);
- writeUnusedVariableCast(s, QLatin1String(CPP_SELF_VAR));
- s << INDENT << "PyObject *" << PYTHON_RETURN_VAR << "{};\n";
- s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ";\n";
- writeUnusedVariableCast(s, QLatin1String(PYTHON_TO_CPP_VAR));
- s << Qt::endl;
-
- s << INDENT << "switch (op) {\n";
- {
- Indentation indent(INDENT);
- const QVector<AbstractMetaFunctionList> &groupedFuncs = filterGroupedOperatorFunctions(metaClass, AbstractMetaClass::ComparisonOp);
- for (const AbstractMetaFunctionList &overloads : groupedFuncs) {
- const AbstractMetaFunction *rfunc = overloads[0];
-
- QString operatorId = ShibokenGenerator::pythonRichCompareOperatorId(rfunc);
- s << INDENT << "case " << operatorId << ':' << Qt::endl;
-
- Indentation indent(INDENT);
-
- QString op = rfunc->originalName();
- op = op.right(op.size() - QLatin1String("operator").size());
-
- int alternativeNumericTypes = 0;
- for (const AbstractMetaFunction *func : overloads) {
- if (!func->isStatic() &&
- ShibokenGenerator::isNumber(func->arguments().at(0)->type()->typeEntry()))
- alternativeNumericTypes++;
- }
-
- bool first = true;
- OverloadData overloadData(overloads, this);
- const OverloadDataList &nextOverloads = overloadData.nextOverloadData();
- for (OverloadData *od : nextOverloads) {
- const AbstractMetaFunction *func = od->referenceFunction();
- if (func->isStatic())
- continue;
- const AbstractMetaType *argType = getArgumentType(func, 1);
- if (!argType)
- continue;
- if (!first) {
- s << " else ";
- } else {
- first = false;
- s << INDENT;
- }
- s << "if (";
- writeTypeCheck(s, argType, QLatin1String(PYTHON_ARG), alternativeNumericTypes == 1 || isPyInt(argType));
- s << ") {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "// " << func->signature() << Qt::endl;
- writeArgumentConversion(s, argType, QLatin1String(CPP_ARG0),
- QLatin1String(PYTHON_ARG), metaClass,
- QString(), func->isUserAdded());
-
- // If the function is user added, use the inject code
- if (func->isUserAdded()) {
- CodeSnipList snips = func->injectedCodeSnips();
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, func->arguments().constLast());
- } else {
- s << INDENT;
- if (func->type())
- s << func->type()->cppSignature() << " " << CPP_RETURN_VAR << " = ";
- // expression
- if (func->isPointerOperator())
- s << '&';
- s << CPP_SELF_VAR << ' ' << op << '(';
- if (shouldDereferenceAbstractMetaTypePointer(argType))
- s << '*';
- s << CPP_ARG0 << ");\n";
- s << INDENT << PYTHON_RETURN_VAR << " = ";
- if (func->type())
- writeToPythonConversion(s, func->type(), metaClass, QLatin1String(CPP_RETURN_VAR));
- else
- s << "Py_None;\n" << INDENT << "Py_INCREF(Py_None)";
- s << ";\n";
- }
- }
- s << INDENT << '}';
- }
-
- s << " else {\n";
- if (operatorId == QLatin1String("Py_EQ") || operatorId == QLatin1String("Py_NE")) {
- Indentation indent(INDENT);
- s << INDENT << PYTHON_RETURN_VAR << " = "
- << (operatorId == QLatin1String("Py_EQ") ? "Py_False" : "Py_True") << ";\n";
- s << INDENT << "Py_INCREF(" << PYTHON_RETURN_VAR << ");\n";
- } else {
- Indentation indent(INDENT);
- s << INDENT << "goto " << baseName << "_RichComparison_TypeError;\n";
- }
- s << INDENT<< "}\n\n";
-
- s << INDENT << "break;\n";
- }
- s << INDENT << "default:\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "goto " << baseName << "_RichComparison_TypeError;\n";
- }
- }
- s << INDENT<< "}\n\n";
-
- s << INDENT << "if (" << PYTHON_RETURN_VAR << " && !PyErr_Occurred())\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "return " << PYTHON_RETURN_VAR << ";\n";
- }
- s << INDENT << baseName << "_RichComparison_TypeError:\n";
- s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"operator not implemented.\");\n";
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl << Qt::endl;
- s<< "}\n\n";
-}
-
-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() << "\", reinterpret_cast<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.constFirst();
- if (m_tpFuncs.contains(func->name()))
- return;
-
- s << INDENT;
- if (OverloadData::hasStaticAndInstanceFunctions(overloads)) {
- s << cpythonMethodDefinitionName(func);
- } else {
- s << '{';
- writeMethodDefinitionEntry(s, overloads);
- s << '}';
- }
- s << ',' << Qt::endl;
-}
-
-void CppGenerator::writeSignatureInfo(QTextStream &s, const AbstractMetaFunctionList &overloads)
-{
- OverloadData overloadData(overloads, this);
- const AbstractMetaFunction *rfunc = overloadData.referenceFunction();
- QString funcName = fullPythonFunctionName(rfunc);
-
- int idx = overloads.length() - 1;
- bool multiple = idx > 0;
-
- for (const AbstractMetaFunction *f : overloads) {
- QStringList args;
- const AbstractMetaArgumentList &arguments = f->arguments();
- for (const AbstractMetaArgument *arg : arguments) {
- QString strArg = arg->type()->pythonSignature();
- if (!arg->defaultValueExpression().isEmpty()) {
- strArg += QLatin1Char('=');
- QString e = arg->defaultValueExpression();
- e.replace(QLatin1String("::"), QLatin1String("."));
- // the tests insert stuff like Str("<unknown>"):
- e.replace(QLatin1Char('"'), QLatin1String("\\\""));
- strArg += e;
- }
- args << arg->name() + QLatin1Char(':') + strArg;
- }
- // mark the multiple signatures as such, to make it easier to generate different code
- if (multiple)
- s << idx-- << ':';
- s << funcName << '(' << args.join(QLatin1Char(',')) << ')';
- if (f->type())
- s << "->" << f->type()->pythonSignature();
- s << Qt::endl;
- }
-}
-
-void CppGenerator::writeEnumsInitialization(QTextStream &s, AbstractMetaEnumList &enums)
-{
- if (enums.isEmpty())
- return;
- s << INDENT << "// Initialization of enums.\n\n";
- for (const AbstractMetaEnum *cppEnum : qAsConst(enums)) {
- if (cppEnum->isPrivate())
- continue;
- writeEnumInitialization(s, cppEnum);
- }
-}
-
-static QString mangleName(QString name)
-{
- if ( name == QLatin1String("None")
- || name == QLatin1String("False")
- || name == QLatin1String("True"))
- name += QLatin1Char('_');
- return name;
-}
-
-void CppGenerator::writeEnumInitialization(QTextStream &s, const AbstractMetaEnum *cppEnum)
-{
- const AbstractMetaClass *enclosingClass = cppEnum->targetLangEnclosingClass();
- bool hasUpperEnclosingClass = enclosingClass && enclosingClass->targetLangEnclosingClass() != nullptr;
- const EnumTypeEntry *enumTypeEntry = cppEnum->typeEntry();
- QString enclosingObjectVariable;
- if (enclosingClass)
- enclosingObjectVariable = cpythonTypeName(enclosingClass);
- else if (hasUpperEnclosingClass)
- enclosingObjectVariable = QLatin1String("enclosingClass");
- else
- enclosingObjectVariable = QLatin1String("module");
-
- s << INDENT << "// Initialization of ";
- s << (cppEnum->isAnonymous() ? "anonymous enum identified by enum value" : "enum");
- s << " '" << cppEnum->name() << "'.\n";
-
- QString enumVarTypeObj;
- if (!cppEnum->isAnonymous()) {
- FlagsTypeEntry *flags = enumTypeEntry->flags();
- if (flags) {
- // The following could probably be made nicer:
- // We need 'flags->flagsName()' with the full module/class path.
- QString fullPath = getClassTargetFullName(cppEnum);
- fullPath.truncate(fullPath.lastIndexOf(QLatin1Char('.')) + 1);
- s << INDENT << cpythonTypeNameExt(flags) << " = PySide::QFlags::create(\""
- << fullPath << flags->flagsName() << "\", "
- << cpythonEnumName(cppEnum) << "_number_slots);\n";
- }
-
- enumVarTypeObj = cpythonTypeNameExt(enumTypeEntry);
-
- s << INDENT << enumVarTypeObj << " = Shiboken::Enum::";
- s << ((enclosingClass || hasUpperEnclosingClass) ? "createScopedEnum" : "createGlobalEnum");
- s << '(' << enclosingObjectVariable << ',' << Qt::endl;
- {
- Indentation indent(INDENT);
- s << INDENT << '"' << cppEnum->name() << "\",\n";
- s << INDENT << '"' << getClassTargetFullName(cppEnum) << "\",\n";
- s << INDENT << '"' << (cppEnum->enclosingClass() ? (cppEnum->enclosingClass()->qualifiedCppName() + QLatin1String("::")) : QString());
- s << cppEnum->name() << '"';
- if (flags)
- s << ',' << Qt::endl << INDENT << cpythonTypeNameExt(flags);
- s << ");\n";
- }
- s << INDENT << "if (!" << cpythonTypeNameExt(cppEnum->typeEntry()) << ")\n";
- {
- Indentation indent(INDENT);
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl << Qt::endl;
- }
- }
-
- const AbstractMetaEnumValueList &enumValues = cppEnum->values();
- for (const AbstractMetaEnumValue *enumValue : enumValues) {
- if (enumTypeEntry->isEnumValueRejected(enumValue->name()))
- continue;
-
- QString enumValueText;
- if (!avoidProtectedHack() || !cppEnum->isProtected()) {
- enumValueText = QLatin1String("(long) ");
- if (cppEnum->enclosingClass())
- enumValueText += cppEnum->enclosingClass()->qualifiedCppName() + QLatin1String("::");
- // Fully qualify the value which is required for C++ 11 enum classes.
- if (!cppEnum->isAnonymous())
- enumValueText += cppEnum->name() + QLatin1String("::");
- enumValueText += enumValue->name();
- } else {
- enumValueText += enumValue->value().toString();
- }
-
- switch (cppEnum->enumKind()) {
- case AnonymousEnum:
- if (enclosingClass || hasUpperEnclosingClass) {
- s << INDENT << "{\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "PyObject *anonEnumItem = PyInt_FromLong(" << enumValueText << ");\n";
- s << INDENT << "if (PyDict_SetItemString(reinterpret_cast<PyTypeObject *>(reinterpret_cast<SbkObjectType *>(" << enclosingObjectVariable
- << "))->tp_dict, \"" << mangleName(enumValue->name()) << "\", anonEnumItem) < 0)\n";
- {
- Indentation indent(INDENT);
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
- }
- s << INDENT << "Py_DECREF(anonEnumItem);\n";
- }
- s << INDENT << "}\n";
- } else {
- s << INDENT << "if (PyModule_AddIntConstant(module, \"" << mangleName(enumValue->name()) << "\", ";
- s << enumValueText << ") < 0)\n";
- {
- Indentation indent(INDENT);
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
- }
- }
- break;
- case CEnum: {
- s << INDENT << "if (!Shiboken::Enum::";
- s << ((enclosingClass || hasUpperEnclosingClass) ? "createScopedEnumItem" : "createGlobalEnumItem");
- s << '(' << enumVarTypeObj << ',' << Qt::endl;
- Indentation indent(INDENT);
- s << INDENT << enclosingObjectVariable << ", \"" << mangleName(enumValue->name()) << "\", ";
- s << enumValueText << "))\n";
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
- }
- break;
- case EnumClass: {
- s << INDENT << "if (!Shiboken::Enum::createScopedEnumItem("
- << enumVarTypeObj << ',' << Qt::endl;
- Indentation indent(INDENT);
- s << INDENT << enumVarTypeObj<< ", \"" << mangleName(enumValue->name()) << "\", "
- << enumValueText << "))\n"
- << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
- }
- break;
- }
- }
-
- writeEnumConverterInitialization(s, cppEnum);
-
- s << INDENT << "// End of '" << cppEnum->name() << "' enum";
- if (cppEnum->typeEntry()->flags())
- s << "/flags";
- s << '.' << Qt::endl << Qt::endl;
-}
-
-void CppGenerator::writeSignalInitialization(QTextStream &s, const AbstractMetaClass *metaClass)
-{
- // Try to check something and print some warnings
- const AbstractMetaFunctionList &signalFuncs = metaClass->cppSignalFunctions();
- for (const AbstractMetaFunction *cppSignal : signalFuncs) {
- if (cppSignal->declaringClass() != metaClass)
- continue;
- const AbstractMetaArgumentList &arguments = cppSignal->arguments();
- for (AbstractMetaArgument *arg : arguments) {
- AbstractMetaType *metaType = arg->type();
- const QByteArray origType =
- QMetaObject::normalizedType(qPrintable(metaType->originalTypeDescription()));
- const QByteArray cppSig =
- QMetaObject::normalizedType(qPrintable(metaType->cppSignature()));
- if ((origType != cppSig) && (!metaType->isFlags())) {
- qCWarning(lcShiboken).noquote().nospace()
- << "Typedef used on signal " << metaClass->qualifiedCppName() << "::"
- << cppSignal->signature();
- }
- }
- }
-
- s << INDENT << "PySide::Signal::registerSignals(" << cpythonTypeName(metaClass) << ", &::"
- << metaClass->qualifiedCppName() << "::staticMetaObject);\n";
-}
-
-void CppGenerator::writeFlagsToLong(QTextStream &s, const AbstractMetaEnum *cppEnum)
-{
- FlagsTypeEntry *flagsEntry = cppEnum->typeEntry()->flags();
- if (!flagsEntry)
- return;
- s << "static PyObject *" << cpythonEnumName(cppEnum) << "_long(PyObject *self)\n";
- s << "{\n";
- s << INDENT << "int val;\n";
- AbstractMetaType *flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
- s << INDENT << cpythonToCppConversionFunction(flagsType) << "self, &val);\n";
- s << INDENT << "return Shiboken::Conversions::copyToPython(Shiboken::Conversions::PrimitiveTypeConverter<int>(), &val);\n";
- s << "}\n";
-}
-
-void CppGenerator::writeFlagsNonZero(QTextStream &s, const AbstractMetaEnum *cppEnum)
-{
- FlagsTypeEntry *flagsEntry = cppEnum->typeEntry()->flags();
- if (!flagsEntry)
- return;
- s << "static int " << cpythonEnumName(cppEnum) << "__nonzero(PyObject *self)\n";
- s << "{\n";
-
- s << INDENT << "int val;\n";
- AbstractMetaType *flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
- s << INDENT << cpythonToCppConversionFunction(flagsType) << "self, &val);\n";
- s << INDENT << "return val != 0;\n";
- s << "}\n";
-}
-
-void CppGenerator::writeFlagsMethods(QTextStream &s, const AbstractMetaEnum *cppEnum)
-{
- writeFlagsBinaryOperator(s, cppEnum, QLatin1String("and"), QLatin1String("&"));
- writeFlagsBinaryOperator(s, cppEnum, QLatin1String("or"), QLatin1String("|"));
- writeFlagsBinaryOperator(s, cppEnum, QLatin1String("xor"), QLatin1String("^"));
-
- writeFlagsUnaryOperator(s, cppEnum, QLatin1String("invert"), QLatin1String("~"));
- writeFlagsToLong(s, cppEnum);
- writeFlagsNonZero(s, cppEnum);
-
- s << Qt::endl;
-}
-
-void CppGenerator::writeFlagsNumberMethodsDefinition(QTextStream &s, const AbstractMetaEnum *cppEnum)
-{
- QString cpythonName = cpythonEnumName(cppEnum);
-
- s << "static PyType_Slot " << cpythonName << "_number_slots[] = {\n";
- s << "#ifdef IS_PY3K\n";
- s << INDENT << "{Py_nb_bool, (void *)" << cpythonName << "__nonzero},\n";
- s << "#else\n";
- s << INDENT << "{Py_nb_nonzero, (void *)" << cpythonName << "__nonzero},\n";
- s << INDENT << "{Py_nb_long, (void *)" << cpythonName << "_long},\n";
- s << "#endif\n";
- s << INDENT << "{Py_nb_invert, (void *)" << cpythonName << "___invert__},\n";
- s << INDENT << "{Py_nb_and, (void *)" << cpythonName << "___and__},\n";
- s << INDENT << "{Py_nb_xor, (void *)" << cpythonName << "___xor__},\n";
- s << INDENT << "{Py_nb_or, (void *)" << cpythonName << "___or__},\n";
- s << INDENT << "{Py_nb_int, (void *)" << cpythonName << "_long},\n";
- s << "#ifndef IS_PY3K\n";
- s << INDENT << "{Py_nb_long, (void *)" << cpythonName << "_long},\n";
- s << "#endif\n";
- s << INDENT << "{0, " << NULL_PTR << "} // sentinel\n";
- s << "};\n\n";
-}
-
-void CppGenerator::writeFlagsBinaryOperator(QTextStream &s, const AbstractMetaEnum *cppEnum,
- const QString &pyOpName, const QString &cppOpName)
-{
- FlagsTypeEntry *flagsEntry = cppEnum->typeEntry()->flags();
- Q_ASSERT(flagsEntry);
-
- s << "PyObject * " << cpythonEnumName(cppEnum) << "___" << pyOpName
- << "__(PyObject *self, PyObject *" << PYTHON_ARG << ")\n{\n";
-
- AbstractMetaType *flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
- s << INDENT << "::" << flagsEntry->originalName() << " cppResult, " << CPP_SELF_VAR << ", cppArg;\n";
- s << "#ifdef IS_PY3K\n";
- s << INDENT << CPP_SELF_VAR << " = static_cast<::" << flagsEntry->originalName()
- << ">(int(PyLong_AsLong(self)));\n";
- s << INDENT << "cppArg = static_cast<" << flagsEntry->originalName() << ">(int(PyLong_AsLong("
- << PYTHON_ARG << ")));\n";
- s << "#else\n";
- s << INDENT << CPP_SELF_VAR << " = static_cast<::" << flagsEntry->originalName()
- << ">(int(PyInt_AsLong(self)));\n";
- s << INDENT << "cppArg = static_cast<" << flagsEntry->originalName()
- << ">(int(PyInt_AsLong(" << PYTHON_ARG << ")));\n";
- s << "#endif\n\n";
- s << INDENT << "cppResult = " << CPP_SELF_VAR << " " << cppOpName << " cppArg;\n";
- s << INDENT << "return ";
- writeToPythonConversion(s, flagsType, nullptr, QLatin1String("cppResult"));
- s << ";\n";
- s<< "}\n\n";
-}
-
-void CppGenerator::writeFlagsUnaryOperator(QTextStream &s, const AbstractMetaEnum *cppEnum,
- const QString &pyOpName,
- const QString &cppOpName, bool boolResult)
-{
- FlagsTypeEntry *flagsEntry = cppEnum->typeEntry()->flags();
- Q_ASSERT(flagsEntry);
-
- s << "PyObject *" << cpythonEnumName(cppEnum) << "___" << pyOpName
- << "__(PyObject *self, PyObject *" << PYTHON_ARG << ")\n{\n";
-
- AbstractMetaType *flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
- s << INDENT << "::" << flagsEntry->originalName() << " " << CPP_SELF_VAR << ";\n";
- s << INDENT << cpythonToCppConversionFunction(flagsType) << "self, &" << CPP_SELF_VAR << ");\n";
- s << INDENT;
- if (boolResult)
- s << "bool";
- else
- s << "::" << flagsEntry->originalName();
- s << " cppResult = " << cppOpName << CPP_SELF_VAR << ";\n";
- s << INDENT << "return ";
- if (boolResult)
- s << "PyBool_FromLong(cppResult)";
- else
- writeToPythonConversion(s, flagsType, nullptr, QLatin1String("cppResult"));
- s << ";\n";
- s<< "}\n\n";
-}
-
-QString CppGenerator::getSimpleClassInitFunctionName(const AbstractMetaClass *metaClass) const
-{
- QString initFunctionName;
- // Disambiguate namespaces per module to allow for extending them.
- if (metaClass->isNamespace())
- initFunctionName += moduleName();
- initFunctionName += metaClass->qualifiedCppName();
- initFunctionName.replace(QLatin1String("::"), QLatin1String("_"));
- return initFunctionName;
-}
-
-QString CppGenerator::getInitFunctionName(GeneratorContext &context) const
-{
- return !context.forSmartPointer()
- ? getSimpleClassInitFunctionName(context.metaClass())
- : getFilteredCppSignatureString(context.preciseType()->cppSignature());
-}
-
-void CppGenerator::writeClassRegister(QTextStream &s,
- const AbstractMetaClass *metaClass,
- GeneratorContext &classContext,
- QTextStream &signatureStream)
-{
- const ComplexTypeEntry *classTypeEntry = metaClass->typeEntry();
-
- const AbstractMetaClass *enc = metaClass->targetLangEnclosingClass();
- QString enclosingObjectVariable = enc ? QLatin1String("enclosingClass") : QLatin1String("module");
-
- QString pyTypeName = cpythonTypeName(metaClass);
- QString initFunctionName = getInitFunctionName(classContext);
-
- // PYSIDE-510: Create a signatures string for the introspection feature.
- s << "// The signatures string for the functions.\n";
- s << "// Multiple signatures have their index \"n:\" in front.\n";
- s << "static const char *" << initFunctionName << "_SignatureStrings[] = {\n";
- QString line;
- while (signatureStream.readLineInto(&line))
- s << INDENT << '"' << line << "\",\n";
- s << INDENT << NULL_PTR << "}; // Sentinel\n\n";
- s << "void init_" << initFunctionName;
- s << "(PyObject *" << enclosingObjectVariable << ")\n{\n";
-
- // Multiple inheritance
- QString pyTypeBasesVariable = chopType(pyTypeName) + QLatin1String("_Type_bases");
- const AbstractMetaClassList baseClasses = getBaseClasses(metaClass);
- if (metaClass->baseClassNames().size() > 1) {
- s << INDENT << "PyObject *" << pyTypeBasesVariable
- << " = PyTuple_Pack(" << baseClasses.size() << ',' << Qt::endl;
- Indentation indent(INDENT);
- for (int i = 0, size = baseClasses.size(); i < size; ++i) {
- if (i)
- s << ",\n";
- s << INDENT << "reinterpret_cast<PyObject *>("
- << cpythonTypeNameExt(baseClasses.at(i)->typeEntry()) << ')';
- }
- s << ");\n\n";
- }
-
- // Create type and insert it in the module or enclosing class.
- const QString typePtr = QLatin1String("_") + chopType(pyTypeName)
- + QLatin1String("_Type");
-
- s << INDENT << typePtr << " = Shiboken::ObjectType::introduceWrapperType(\n";
- {
- Indentation indent(INDENT);
- // 1:enclosingObject
- s << INDENT << enclosingObjectVariable << ",\n";
- QString typeName;
- if (!classContext.forSmartPointer())
- typeName = metaClass->name();
- else
- typeName = classContext.preciseType()->cppSignature();
-
- // 2:typeName
- s << INDENT << "\"" << typeName << "\",\n";
-
- // 3:originalName
- s << INDENT << "\"";
- if (!classContext.forSmartPointer()) {
- s << metaClass->qualifiedCppName();
- if (isObjectType(classTypeEntry))
- s << '*';
- } else {
- s << classContext.preciseType()->cppSignature();
- }
-
- s << "\",\n";
- // 4:typeSpec
- s << INDENT << '&' << chopType(pyTypeName) << "_spec,\n";
-
- // 5:signatureStrings
- s << INDENT << initFunctionName << "_SignatureStrings,\n";
-
- // 6:cppObjDtor
- s << INDENT;
- if (!metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) {
- QString dtorClassName = metaClass->qualifiedCppName();
- if ((avoidProtectedHack() && metaClass->hasProtectedDestructor()) || classTypeEntry->isValue())
- dtorClassName = wrapperName(metaClass);
- if (classContext.forSmartPointer())
- dtorClassName = wrapperName(classContext.preciseType());
-
- s << "&Shiboken::callCppDestructor< ::" << dtorClassName << " >,\n";
- } else {
- s << "0,\n";
- }
-
- // 7:baseType
- const auto base = metaClass->isNamespace()
- ? metaClass->extendedNamespace() : metaClass->baseClass();
- if (base) {
- s << INDENT << "reinterpret_cast<SbkObjectType *>("
- << cpythonTypeNameExt(base->typeEntry()) << "),\n";
- } else {
- s << INDENT << "0,\n";
- }
-
- // 8:baseTypes
- if (metaClass->baseClassNames().size() > 1)
- s << INDENT << pyTypeBasesVariable << ',' << Qt::endl;
- else
- s << INDENT << "0,\n";
-
- // 9:wrapperflags
- QByteArrayList wrapperFlags;
- if (enc)
- wrapperFlags.append(QByteArrayLiteral("Shiboken::ObjectType::WrapperFlags::InnerClass"));
- if (metaClass->deleteInMainThread())
- wrapperFlags.append(QByteArrayLiteral("Shiboken::ObjectType::WrapperFlags::DeleteInMainThread"));
- if (wrapperFlags.isEmpty())
- s << INDENT << '0';
- else
- s << INDENT << wrapperFlags.join(" | ");
- }
- s << INDENT << ");\n";
- s << INDENT << Qt::endl;
-
- if (!classContext.forSmartPointer())
- s << INDENT << cpythonTypeNameExt(classTypeEntry) << Qt::endl;
- else
- s << INDENT << cpythonTypeNameExt(classContext.preciseType()) << Qt::endl;
- s << INDENT << " = reinterpret_cast<PyTypeObject *>(" << pyTypeName << ");\n";
- s << Qt::endl;
-
- // Register conversions for the type.
- writeConverterRegister(s, metaClass, classContext);
- s << Qt::endl;
-
- // class inject-code target/beginning
- if (!classTypeEntry->codeSnips().isEmpty()) {
- writeCodeSnips(s, classTypeEntry->codeSnips(), TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode, metaClass);
- s << Qt::endl;
- }
-
- // Fill multiple inheritance data, if needed.
- const AbstractMetaClass *miClass = getMultipleInheritingClass(metaClass);
- if (miClass) {
- s << INDENT << "MultipleInheritanceInitFunction func = ";
- if (miClass == metaClass) {
- s << multipleInheritanceInitializerFunctionName(miClass) << ";\n";
- } else {
- s << "Shiboken::ObjectType::getMultipleInheritanceFunction(reinterpret_cast<SbkObjectType *>(";
- s << cpythonTypeNameExt(miClass->typeEntry()) << "));\n";
- }
- s << INDENT << "Shiboken::ObjectType::setMultipleInheritanceFunction(";
- s << cpythonTypeName(metaClass) << ", func);\n";
- s << INDENT << "Shiboken::ObjectType::setCastFunction(" << cpythonTypeName(metaClass);
- s << ", &" << cpythonSpecialCastFunctionName(metaClass) << ");\n";
- }
-
- // 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);\n\n";
- }
-
- AbstractMetaEnumList classEnums = metaClass->enums();
- const AbstractMetaClassList &innerClasses = metaClass->innerClasses();
- for (AbstractMetaClass *innerClass : innerClasses)
- lookForEnumsInClassesNotToBeGenerated(classEnums, innerClass);
-
- ErrorCode errorCode(QString::fromLatin1(""));
- writeEnumsInitialization(s, classEnums);
-
- if (metaClass->hasSignals())
- writeSignalInitialization(s, metaClass);
-
- // Write static fields
- const AbstractMetaFieldList &fields = metaClass->fields();
- for (const AbstractMetaField *field : fields) {
- if (!field->isStatic())
- continue;
- s << INDENT << QLatin1String("PyDict_SetItemString(reinterpret_cast<PyTypeObject *>(") + cpythonTypeName(metaClass) + QLatin1String(")->tp_dict, \"");
- s << field->name() << "\", ";
- writeToPythonConversion(s, field->type(), metaClass, metaClass->qualifiedCppName() + QLatin1String("::") + field->name());
- s << ");\n";
- }
- s << Qt::endl;
-
- // class inject-code target/end
- if (!classTypeEntry->codeSnips().isEmpty()) {
- s << Qt::endl;
- writeCodeSnips(s, classTypeEntry->codeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode, metaClass);
- }
-
- if (usePySideExtensions()) {
- if (avoidProtectedHack() && shouldGenerateCppWrapper(metaClass))
- s << INDENT << wrapperName(metaClass) << "::pysideInitQtMetaTypes();\n";
- else
- writeInitQtMetaTypeFunctionBody(s, classContext);
- }
-
- if (usePySideExtensions() && metaClass->isQObject()) {
- s << INDENT << "Shiboken::ObjectType::setSubTypeInitHook(" << pyTypeName << ", &PySide::initQObjectSubType);\n";
- s << INDENT << "PySide::initDynamicMetaObject(" << pyTypeName << ", &::" << metaClass->qualifiedCppName()
- << "::staticMetaObject, sizeof(::" << metaClass->qualifiedCppName() << "));\n";
- }
-
- s << "}\n";
-}
-
-void CppGenerator::writeInitQtMetaTypeFunctionBody(QTextStream &s, GeneratorContext &context) const
-{
- const AbstractMetaClass *metaClass = context.metaClass();
- // Gets all class name variants used on different possible scopes
- QStringList nameVariants;
- if (!context.forSmartPointer())
- nameVariants << metaClass->name();
- else
- nameVariants << context.preciseType()->cppSignature();
-
- const AbstractMetaClass *enclosingClass = metaClass->enclosingClass();
- while (enclosingClass) {
- if (enclosingClass->typeEntry()->generateCode())
- nameVariants << (enclosingClass->name() + QLatin1String("::") + nameVariants.constLast());
- enclosingClass = enclosingClass->enclosingClass();
- }
-
- QString className;
- if (!context.forSmartPointer())
- className = metaClass->qualifiedCppName();
- else
- className = context.preciseType()->cppSignature();
-
- if (!metaClass->isNamespace() && !metaClass->isAbstract()) {
- // Qt metatypes are registered only on their first use, so we do this now.
- bool canBeValue = false;
- if (!isObjectType(metaClass)) {
- // check if there's a empty ctor
- const AbstractMetaFunctionList &funcs = metaClass->functions();
- for (AbstractMetaFunction *func : funcs) {
- if (func->isConstructor() && !func->arguments().count()) {
- canBeValue = true;
- break;
- }
- }
- }
-
- if (canBeValue) {
- for (const QString &name : qAsConst(nameVariants)) {
- if (name == QLatin1String("iterator")) {
- qCWarning(lcShiboken).noquote().nospace()
- << QString::fromLatin1("%1:%2 FIXME:\n"
- " The code tried to qRegisterMetaType the unqualified name "
- "'iterator'. This is currently fixed by a hack(ct) and needs improvement!")
- .arg(QFile::decodeName(__FILE__)).arg(__LINE__);
- continue;
- }
- s << INDENT << "qRegisterMetaType< ::" << className << " >(\"" << name << "\");\n";
- }
- }
- }
-
- const AbstractMetaEnumList &enums = metaClass->enums();
- for (AbstractMetaEnum *metaEnum : enums) {
- if (!metaEnum->isPrivate() && !metaEnum->isAnonymous()) {
- for (const QString &name : qAsConst(nameVariants))
- s << INDENT << "qRegisterMetaType< ::" << metaEnum->typeEntry()->qualifiedCppName() << " >(\"" << name << "::" << metaEnum->name() << "\");\n";
-
- if (metaEnum->typeEntry()->flags()) {
- QString n = metaEnum->typeEntry()->flags()->originalName();
- s << INDENT << "qRegisterMetaType< ::" << n << " >(\"" << n << "\");\n";
- }
- }
- }
-}
-
-void CppGenerator::writeTypeDiscoveryFunction(QTextStream &s, const AbstractMetaClass *metaClass)
-{
- QString polymorphicExpr = metaClass->typeEntry()->polymorphicIdValue();
-
- s << "static void *" << cpythonBaseName(metaClass) << "_typeDiscovery(void *cptr, SbkObjectType *instanceType)\n{\n";
-
- if (!polymorphicExpr.isEmpty()) {
- polymorphicExpr = polymorphicExpr.replace(QLatin1String("%1"),
- QLatin1String(" reinterpret_cast< ::")
- + metaClass->qualifiedCppName()
- + QLatin1String(" *>(cptr)"));
- s << INDENT << " if (" << polymorphicExpr << ")\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "return cptr;\n";
- }
- } else if (metaClass->isPolymorphic()) {
- const AbstractMetaClassList &ancestors = getAllAncestors(metaClass);
- for (AbstractMetaClass *ancestor : ancestors) {
- if (ancestor->baseClass())
- continue;
- if (ancestor->isPolymorphic()) {
- s << INDENT << "if (instanceType == reinterpret_cast<SbkObjectType *>(Shiboken::SbkType< ::"
- << ancestor->qualifiedCppName() << " >()))\n";
- Indentation indent(INDENT);
- s << INDENT << "return dynamic_cast< ::" << metaClass->qualifiedCppName()
- << " *>(reinterpret_cast< ::"<< ancestor->qualifiedCppName() << " *>(cptr));\n";
- } else {
- qCWarning(lcShiboken).noquote().nospace()
- << metaClass->qualifiedCppName() << " inherits from a non polymorphic type ("
- << ancestor->qualifiedCppName() << "), type discovery based on RTTI is "
- "impossible, write a polymorphic-id-expression for this type.";
- }
-
- }
- }
- s << INDENT << "return {};\n";
- s << "}\n\n";
-}
-
-QString CppGenerator::writeSmartPointerGetterCast()
-{
- return QLatin1String("const_cast<char *>(")
- + QLatin1String(SMART_POINTER_GETTER) + QLatin1Char(')');
-}
-
-void CppGenerator::writeSetattroFunction(QTextStream &s, GeneratorContext &context)
-{
- const AbstractMetaClass *metaClass = context.metaClass();
- s << "static int " << cpythonSetattroFunctionName(metaClass)
- << "(PyObject *self, PyObject *name, PyObject *value)\n{\n";
- if (usePySideExtensions()) {
- s << INDENT << "Shiboken::AutoDecRef pp(reinterpret_cast<PyObject *>(PySide::Property::getObject(self, name)));\n";
- s << INDENT << "if (!pp.isNull())\n";
- Indentation indent(INDENT);
- s << INDENT << "return PySide::Property::setValue(reinterpret_cast<PySideProperty *>(pp.object()), self, value);\n";
- }
-
- if (context.forSmartPointer()) {
- s << INDENT << "// Try to find the 'name' attribute, by retrieving the PyObject for the corresponding C++ object held by the smart pointer.\n";
- s << INDENT << "PyObject *rawObj = PyObject_CallMethod(self, "
- << writeSmartPointerGetterCast() << ", 0);\n";
- s << INDENT << "if (rawObj) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "int hasAttribute = PyObject_HasAttr(rawObj, name);\n";
- s << INDENT << "if (hasAttribute) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "return PyObject_GenericSetAttr(rawObj, name, value);\n";
- }
- s << INDENT << "}\n";
- s << INDENT << "Py_DECREF(rawObj);\n";
- }
- s << INDENT << "}\n";
-
- }
-
- s << INDENT << "return PyObject_GenericSetAttr(self, name, value);\n";
- s << "}\n";
-}
-
-static inline QString qObjectClassName() { return QStringLiteral("QObject"); }
-static inline QString qMetaObjectClassName() { return QStringLiteral("QMetaObject"); }
-
-void CppGenerator::writeGetattroFunction(QTextStream &s, GeneratorContext &context)
-{
- const AbstractMetaClass *metaClass = context.metaClass();
- s << "static PyObject *" << cpythonGetattroFunctionName(metaClass)
- << "(PyObject *self, PyObject *name)\n{\n";
- s << INDENT << "assert(self);\n";
-
- QString getattrFunc;
- if (usePySideExtensions() && metaClass->isQObject()) {
- AbstractMetaClass *qobjectClass = AbstractMetaClass::findClass(classes(), qObjectClassName());
- QTextStream(&getattrFunc) << "PySide::getMetaDataFromQObject("
- << cpythonWrapperCPtr(qobjectClass, QLatin1String("self"))
- << ", self, name)";
- } else {
- getattrFunc = QLatin1String("PyObject_GenericGetAttr(self, name)");
- }
-
- if (classNeedsGetattroFunction(metaClass)) {
- s << INDENT << "// Search the method in the instance dict\n";
- s << INDENT << "if (auto ob_dict = reinterpret_cast<SbkObject *>(self)->ob_dict) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "if (auto meth = PyDict_GetItem(ob_dict, name)) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "Py_INCREF(meth);\n";
- s << INDENT << "return meth;\n";
- }
- s << INDENT << "}\n";
- }
- s << INDENT << "}\n";
- s << INDENT << "// Search the method in the type dict\n";
- s << INDENT << "if (Shiboken::Object::isUserType(self)) {\n";
- {
- Indentation indent(INDENT);
- // PYSIDE-772: Perform optimized name mangling.
- s << INDENT << "Shiboken::AutoDecRef tmp(_Pep_PrivateMangle(self, name));\n";
- s << INDENT << "if (auto meth = PyDict_GetItem(Py_TYPE(self)->tp_dict, tmp))\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "return PyFunction_Check(meth) ? SBK_PyMethod_New(meth, self) : " << getattrFunc << ";\n";
- }
- }
- s << INDENT << "}\n";
-
- const AbstractMetaFunctionList &funcs = getMethodsWithBothStaticAndNonStaticMethods(metaClass);
- for (const AbstractMetaFunction *func : funcs) {
- QString defName = cpythonMethodDefinitionName(func);
- s << INDENT << "static PyMethodDef non_static_" << defName << " = {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << defName << ".ml_name,\n";
- s << INDENT << defName << ".ml_meth,\n";
- s << INDENT << defName << ".ml_flags & (~METH_STATIC),\n";
- s << INDENT << defName << ".ml_doc,\n";
- }
- s << INDENT << "};\n";
- s << INDENT << "if (Shiboken::String::compare(name, \"" << func->name() << "\") == 0)\n";
- Indentation indent(INDENT);
- s << INDENT << "return PyCFunction_NewEx(&non_static_" << defName << ", self, 0);\n";
- }
- }
-
- if (context.forSmartPointer()) {
- s << INDENT << "PyObject *tmp = " << getattrFunc << ";\n";
- s << INDENT << "if (tmp)\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "return tmp;\n";
- }
- s << INDENT << "if (!PyErr_ExceptionMatches(PyExc_AttributeError))\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "return nullptr;\n";
- }
- s << INDENT << "PyErr_Clear();\n";
-
- // This generates the code which dispatches access to member functions
- // and fields from the smart pointer to its pointee.
- s << INDENT << "// Try to find the 'name' attribute, by retrieving the PyObject for "
- "the corresponding C++ object held by the smart pointer.\n";
- s << INDENT << "if (auto rawObj = PyObject_CallMethod(self, "
- << writeSmartPointerGetterCast() << ", 0)) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "if (auto attribute = PyObject_GetAttr(rawObj, name))\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "tmp = attribute;\n";
- }
- s << INDENT << "Py_DECREF(rawObj);\n";
- }
- s << INDENT << "}\n";
- s << INDENT << "if (!tmp) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "PyTypeObject *tp = Py_TYPE(self);\n";
- s << INDENT << "PyErr_Format(PyExc_AttributeError,\n";
- s << INDENT << " \"'%.50s' object has no attribute '%.400s'\",\n";
- s << INDENT << " tp->tp_name, Shiboken::String::toCString(name));\n";
- }
- s << INDENT << "}\n";
- s << INDENT << "return tmp;\n";
- } else {
- s << INDENT << "return " << getattrFunc << ";\n";
- }
- s << "}\n";
-}
-
-// Write declaration and invocation of the init function for the module init
-// function.
-void CppGenerator::writeInitFunc(QTextStream &declStr, QTextStream &callStr,
- const Indentor &indent, const QString &initFunctionName,
- const TypeEntry *enclosingEntry)
-{
- const bool hasParent =
- enclosingEntry && enclosingEntry->type() != TypeEntry::TypeSystemType;
- declStr << "void init_" << initFunctionName << "(PyObject *"
- << (hasParent ? "enclosingClass" : "module") << ");\n";
- callStr << indent << "init_" << initFunctionName;
- if (hasParent) {
- callStr << "(reinterpret_cast<PyTypeObject *>("
- << cpythonTypeNameExt(enclosingEntry) << ")->tp_dict);\n";
- } else {
- callStr << "(module);\n";
- }
-}
-
-bool CppGenerator::finishGeneration()
-{
- //Generate CPython wrapper file
- QString classInitDecl;
- QTextStream s_classInitDecl(&classInitDecl);
- QString classPythonDefines;
- QTextStream s_classPythonDefines(&classPythonDefines);
-
- QSet<Include> includes;
- QString globalFunctionImpl;
- QTextStream s_globalFunctionImpl(&globalFunctionImpl);
- QString globalFunctionDecl;
- QTextStream s_globalFunctionDef(&globalFunctionDecl);
- QString signaturesString;
- QTextStream signatureStream(&signaturesString);
-
- Indentation indent(INDENT);
-
- const auto functionGroups = getGlobalFunctionGroups();
- for (auto it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
- AbstractMetaFunctionList overloads;
- for (AbstractMetaFunction *func : it.value()) {
- if (!func->isModifiedRemoved()) {
- overloads.append(func);
- if (func->typeEntry())
- includes << func->typeEntry()->include();
- }
- }
-
- if (overloads.isEmpty())
- continue;
-
- // Dummy context to satisfy the API.
- GeneratorContext classContext;
- writeMethodWrapper(s_globalFunctionImpl, overloads, classContext);
- writeSignatureInfo(signatureStream, overloads);
- writeMethodDefinition(s_globalFunctionDef, overloads);
- }
-
- //this is a temporary solution before new type revison implementation
- //We need move QMetaObject register before QObject
- Dependencies additionalDependencies;
- const AbstractMetaClassList &allClasses = classes();
- if (auto qObjectClass = AbstractMetaClass::findClass(allClasses, qObjectClassName())) {
- if (auto qMetaObjectClass = AbstractMetaClass::findClass(allClasses, qMetaObjectClassName())) {
- Dependency dependency;
- dependency.parent = qMetaObjectClass;
- dependency.child = qObjectClass;
- additionalDependencies.append(dependency);
- }
- }
- const AbstractMetaClassList lst = classesTopologicalSorted(additionalDependencies);
-
- for (const AbstractMetaClass *cls : lst){
- if (shouldGenerate(cls)) {
- writeInitFunc(s_classInitDecl, s_classPythonDefines, INDENT,
- getSimpleClassInitFunctionName(cls),
- cls->typeEntry()->targetLangEnclosingEntry());
- }
- }
-
- // Initialize smart pointer types.
- const QVector<const AbstractMetaType *> &smartPtrs = instantiatedSmartPointers();
- for (const AbstractMetaType *metaType : smartPtrs) {
- GeneratorContext context(nullptr, metaType, true);
- writeInitFunc(s_classInitDecl, s_classPythonDefines, INDENT,
- getInitFunctionName(context),
- metaType->typeEntry()->targetLangEnclosingEntry());
- }
-
- QString moduleFileName(outputDirectory() + QLatin1Char('/') + subDirectoryForPackage(packageName()));
- moduleFileName += QLatin1Char('/') + moduleName().toLower() + QLatin1String("_module_wrapper.cpp");
-
-
- verifyDirectoryFor(moduleFileName);
- FileOut file(moduleFileName);
-
- QTextStream &s = file.stream;
-
- // write license comment
- s << licenseComment() << Qt::endl;
-
- s << "#include <sbkpython.h>\n";
- s << "#include <shiboken.h>\n";
- s << "#include <algorithm>\n";
- s << "#include <signature.h>\n";
- if (usePySideExtensions()) {
- s << includeQDebug;
- s << "#include <pyside.h>\n";
- s << "#include <qapp_macro.h>\n";
- }
-
- s << "#include \"" << getModuleHeaderFileName() << '"' << Qt::endl << Qt::endl;
- for (const Include &include : qAsConst(includes))
- s << include;
- s << Qt::endl;
-
- // Global enums
- AbstractMetaEnumList globalEnums = this->globalEnums();
- const AbstractMetaClassList &classList = classes();
- for (const AbstractMetaClass *metaClass : classList) {
- const AbstractMetaClass *encClass = metaClass->enclosingClass();
- if (!encClass || !NamespaceTypeEntry::isVisibleScope(encClass->typeEntry()))
- lookForEnumsInClassesNotToBeGenerated(globalEnums, metaClass);
- }
-
- TypeDatabase *typeDb = TypeDatabase::instance();
- const TypeSystemTypeEntry *moduleEntry = typeDb->defaultTypeSystemType();
- Q_ASSERT(moduleEntry);
-
- //Extra includes
- s << Qt::endl << "// Extra includes\n";
- QVector<Include> extraIncludes = moduleEntry->extraIncludes();
- for (AbstractMetaEnum *cppEnum : qAsConst(globalEnums))
- extraIncludes.append(cppEnum->typeEntry()->extraIncludes());
- std::sort(extraIncludes.begin(), extraIncludes.end());
- for (const Include &inc : qAsConst(extraIncludes))
- s << inc;
- s << Qt::endl;
-
- s << "// Current module's type array.\n";
- s << "PyTypeObject **" << cppApiVariableName() << " = nullptr;\n";
-
- s << "// Current module's PyObject pointer.\n";
- s << "PyObject *" << pythonModuleObjectName() << " = nullptr;\n";
-
- s << "// Current module's converter array.\n";
- s << "SbkConverter **" << convertersVariableName() << " = nullptr;\n";
-
- const CodeSnipList snips = moduleEntry->codeSnips();
-
- // module inject-code native/beginning
- if (!snips.isEmpty()) {
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode);
- s << Qt::endl;
- }
-
- // cleanup staticMetaObject attribute
- if (usePySideExtensions()) {
- s << "void cleanTypesAttributes(void) {\n";
- s << INDENT << "if (PY_VERSION_HEX >= 0x03000000 && PY_VERSION_HEX < 0x03060000)\n";
- s << INDENT << " return; // PYSIDE-953: testbinding crashes in Python 3.5 when hasattr touches types!\n";
- s << INDENT << "for (int i = 0, imax = SBK_" << moduleName() << "_IDX_COUNT; i < imax; i++) {\n";
- {
- Indentation indentation(INDENT);
- s << INDENT << "PyObject *pyType = reinterpret_cast<PyObject *>(" << cppApiVariableName() << "[i]);\n";
- s << INDENT << "Shiboken::AutoDecRef attrName(Py_BuildValue(\"s\", \"staticMetaObject\"));\n";
- s << INDENT << "if (pyType && PyObject_HasAttr(pyType, attrName))\n";
- {
- Indentation indentation(INDENT);
- s << INDENT << "PyObject_SetAttr(pyType, attrName, Py_None);\n";
- }
- }
- s << INDENT << "}\n";
- s << "}\n";
- }
-
- s << "// Global functions ";
- s << "------------------------------------------------------------\n";
- s << globalFunctionImpl << Qt::endl;
-
- s << "static PyMethodDef " << moduleName() << "_methods[] = {\n";
- s << globalFunctionDecl;
- s << INDENT << "{0} // Sentinel\n" << "};\n\n";
-
- s << "// Classes initialization functions ";
- s << "------------------------------------------------------------\n";
- s << classInitDecl << Qt::endl;
-
- if (!globalEnums.isEmpty()) {
- QString converterImpl;
- QTextStream convImpl(&converterImpl);
-
- s << "// Enum definitions ";
- s << "------------------------------------------------------------\n";
- for (const AbstractMetaEnum *cppEnum : qAsConst(globalEnums)) {
- if (cppEnum->isAnonymous() || cppEnum->isPrivate())
- continue;
- writeEnumConverterFunctions(s, cppEnum);
- s << Qt::endl;
- }
-
- if (!converterImpl.isEmpty()) {
- s << "// Enum converters ";
- s << "------------------------------------------------------------\n";
- s << "namespace Shiboken\n{\n";
- s << converterImpl << Qt::endl;
- s << "} // namespace Shiboken\n\n";
- }
- }
-
- const QStringList &requiredModules = typeDb->requiredTargetImports();
- if (!requiredModules.isEmpty())
- s << "// Required modules' type and converter arrays.\n";
- for (const QString &requiredModule : requiredModules) {
- s << "PyTypeObject **" << cppApiVariableName(requiredModule) << ";\n";
- s << "SbkConverter **" << convertersVariableName(requiredModule) << ";\n";
- }
- s << Qt::endl;
-
- s << "// Module initialization ";
- s << "------------------------------------------------------------\n";
- ExtendedConverterData extendedConverters = getExtendedConverters();
- if (!extendedConverters.isEmpty()) {
- s << Qt::endl << "// Extended Converters.\n\n";
- for (ExtendedConverterData::const_iterator it = extendedConverters.cbegin(), end = extendedConverters.cend(); it != end; ++it) {
- const TypeEntry *externalType = it.key();
- s << "// Extended implicit conversions for " << externalType->qualifiedTargetLangName() << '.' << Qt::endl;
- for (const AbstractMetaClass *sourceClass : it.value()) {
- AbstractMetaType *sourceType = buildAbstractMetaTypeFromAbstractMetaClass(sourceClass);
- AbstractMetaType *targetType = buildAbstractMetaTypeFromTypeEntry(externalType);
- writePythonToCppConversionFunctions(s, sourceType, targetType);
- }
- }
- }
-
- const QVector<const CustomConversion *> &typeConversions = getPrimitiveCustomConversions();
- if (!typeConversions.isEmpty()) {
- s << Qt::endl << "// Primitive Type converters.\n\n";
- for (const CustomConversion *conversion : typeConversions) {
- s << "// C++ to Python conversion for type '" << conversion->ownerType()->qualifiedCppName() << "'.\n";
- writeCppToPythonFunction(s, conversion);
- writeCustomConverterFunctions(s, conversion);
- }
- s << Qt::endl;
- }
-
- const QVector<const AbstractMetaType *> &containers = instantiatedContainers();
- if (!containers.isEmpty()) {
- s << "// Container Type converters.\n\n";
- for (const AbstractMetaType *container : containers) {
- s << "// C++ to Python conversion for type '" << container->cppSignature() << "'.\n";
- writeContainerConverterFunctions(s, container);
- }
- s << Qt::endl;
- }
-
- s << "#if defined _WIN32 || defined __CYGWIN__\n";
- s << " #define SBK_EXPORT_MODULE __declspec(dllexport)\n";
- s << "#elif __GNUC__ >= 4\n";
- s << " #define SBK_EXPORT_MODULE __attribute__ ((visibility(\"default\")))\n";
- s << "#else\n";
- s << " #define SBK_EXPORT_MODULE\n";
- s << "#endif\n\n";
-
- s << "#ifdef IS_PY3K\n";
- s << "static struct PyModuleDef moduledef = {\n";
- s << " /* m_base */ PyModuleDef_HEAD_INIT,\n";
- s << " /* m_name */ \"" << moduleName() << "\",\n";
- s << " /* m_doc */ nullptr,\n";
- s << " /* m_size */ -1,\n";
- s << " /* m_methods */ " << moduleName() << "_methods,\n";
- s << " /* m_reload */ nullptr,\n";
- s << " /* m_traverse */ nullptr,\n";
- s << " /* m_clear */ nullptr,\n";
- s << " /* m_free */ nullptr\n";
- s << "};\n\n";
- s << "#endif\n\n";
-
- // PYSIDE-510: Create a signatures string for the introspection feature.
- s << "// The signatures string for the global functions.\n";
- s << "// Multiple signatures have their index \"n:\" in front.\n";
- s << "static const char *" << moduleName() << "_SignatureStrings[] = {\n";
- QString line;
- while (signatureStream.readLineInto(&line))
- s << INDENT << '"' << line << "\",\n";
- s << INDENT << NULL_PTR << "}; // Sentinel\n\n";
-
- s << "SBK_MODULE_INIT_FUNCTION_BEGIN(" << moduleName() << ")\n";
-
- ErrorCode errorCode(QLatin1String("SBK_MODULE_INIT_ERROR"));
- // module inject-code target/beginning
- if (!snips.isEmpty()) {
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode);
- s << Qt::endl;
- }
-
- for (const QString &requiredModule : requiredModules) {
- s << INDENT << "{\n";
- {
- Indentation indentation(INDENT);
- s << INDENT << "Shiboken::AutoDecRef requiredModule(Shiboken::Module::import(\"" << requiredModule << "\"));\n";
- s << INDENT << "if (requiredModule.isNull())\n";
- {
- Indentation indentation(INDENT);
- s << INDENT << "return SBK_MODULE_INIT_ERROR;\n";
- }
- s << INDENT << cppApiVariableName(requiredModule) << " = Shiboken::Module::getTypes(requiredModule);\n";
- s << INDENT << convertersVariableName(requiredModule) << " = Shiboken::Module::getTypeConverters(requiredModule);\n";
- }
- s << INDENT << "}\n\n";
- }
-
- int maxTypeIndex = getMaxTypeIndex() + instantiatedSmartPointers().size();
- if (maxTypeIndex) {
- s << INDENT << "// Create an array of wrapper types for the current module.\n";
- s << INDENT << "static PyTypeObject *cppApi[SBK_" << moduleName() << "_IDX_COUNT];\n";
- s << INDENT << cppApiVariableName() << " = cppApi;\n\n";
- }
-
- s << INDENT << "// Create an array of primitive type converters for the current module.\n";
- s << INDENT << "static SbkConverter *sbkConverters[SBK_" << moduleName() << "_CONVERTERS_IDX_COUNT" << "];\n";
- s << INDENT << convertersVariableName() << " = sbkConverters;\n\n";
-
- s << "#ifdef IS_PY3K\n";
- s << INDENT << "PyObject *module = Shiboken::Module::create(\"" << moduleName() << "\", &moduledef);\n";
- s << "#else\n";
- s << INDENT << "PyObject *module = Shiboken::Module::create(\"" << moduleName() << "\", ";
- s << moduleName() << "_methods);\n";
- s << "#endif\n\n";
-
- s << INDENT << "// Make module available from global scope\n";
- s << INDENT << pythonModuleObjectName() << " = module;\n\n";
-
- //s << INDENT << "// Initialize converters for primitive types.\n";
- //s << INDENT << "initConverters();\n\n";
-
- s << INDENT << "// Initialize classes in the type system\n";
- s << classPythonDefines;
-
- if (!typeConversions.isEmpty()) {
- s << Qt::endl;
- for (const CustomConversion *conversion : typeConversions) {
- writePrimitiveConverterInitialization(s, conversion);
- s << Qt::endl;
- }
- }
-
- if (!containers.isEmpty()) {
- s << Qt::endl;
- for (const AbstractMetaType *container : containers) {
- writeContainerConverterInitialization(s, container);
- s << Qt::endl;
- }
- }
-
- if (!extendedConverters.isEmpty()) {
- s << Qt::endl;
- for (ExtendedConverterData::const_iterator it = extendedConverters.cbegin(), end = extendedConverters.cend(); it != end; ++it) {
- writeExtendedConverterInitialization(s, it.key(), it.value());
- s << Qt::endl;
- }
- }
-
- writeEnumsInitialization(s, globalEnums);
-
- s << INDENT << "// Register primitive types converters.\n";
- const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes();
- for (const PrimitiveTypeEntry *pte : primitiveTypeList) {
- if (!pte->generateCode() || !pte->isCppPrimitive())
- continue;
- const TypeEntry *referencedType = pte->basicReferencedTypeEntry();
- if (!referencedType)
- continue;
- QString converter = converterObject(referencedType);
- QStringList cppSignature = pte->qualifiedCppName().split(QLatin1String("::"), QString::SkipEmptyParts);
- while (!cppSignature.isEmpty()) {
- QString signature = cppSignature.join(QLatin1String("::"));
- s << INDENT << "Shiboken::Conversions::registerConverterName(" << converter << ", \"" << signature << "\");\n";
- cppSignature.removeFirst();
- }
- }
-
- s << Qt::endl;
- if (maxTypeIndex)
- s << INDENT << "Shiboken::Module::registerTypes(module, " << cppApiVariableName() << ");\n";
- s << INDENT << "Shiboken::Module::registerTypeConverters(module, " << convertersVariableName() << ");\n";
-
- s << Qt::endl << INDENT << "if (PyErr_Occurred()) {\n";
- {
- Indentation indentation(INDENT);
- s << INDENT << "PyErr_Print();\n";
- s << INDENT << "Py_FatalError(\"can't initialize module " << moduleName() << "\");\n";
- }
- s << INDENT << "}\n";
-
- // module inject-code target/end
- if (!snips.isEmpty()) {
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode);
- s << Qt::endl;
- }
-
- // module inject-code native/end
- if (!snips.isEmpty()) {
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode);
- s << Qt::endl;
- }
-
- if (usePySideExtensions()) {
- for (AbstractMetaEnum *metaEnum : qAsConst(globalEnums))
- if (!metaEnum->isAnonymous()) {
- s << INDENT << "qRegisterMetaType< ::" << metaEnum->typeEntry()->qualifiedCppName() << " >(\"" << metaEnum->name() << "\");\n";
- }
-
- // cleanup staticMetaObject attribute
- s << INDENT << "PySide::registerCleanupFunction(cleanTypesAttributes);\n\n";
- }
-
- // finish the rest of __signature__ initialization.
- s << INDENT << "FinishSignatureInitialization(module, " << moduleName()
- << "_SignatureStrings);\n";
-
- if (usePySideExtensions()) {
- // initialize the qApp module.
- s << INDENT << "NotifyModuleForQApp(module, qApp);\n";
- }
- s << Qt::endl;
- s << "SBK_MODULE_INIT_FUNCTION_END\n";
-
- return file.done() != FileOut::Failure;
-}
-
-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;
-
- const auto &groups = func->implementingClass()
- ? getFunctionGroups(func->implementingClass())
- : getGlobalFunctionGroups();
- bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(OverloadData(groups[func->name()], this));
-
- ArgumentOwner argOwner = getArgumentOwner(func, argIndex);
- ArgumentOwner::Action action = argOwner.action;
- int parentIndex = argOwner.index;
- int childIndex = argIndex;
- if (ctorHeuristicEnabled && argIndex > 0 && numArgs) {
- AbstractMetaArgument *arg = func->arguments().at(argIndex-1);
- if (arg->name() == QLatin1String("parent") && isObjectType(arg->type())) {
- action = ArgumentOwner::Add;
- parentIndex = argIndex;
- childIndex = -1;
- }
- }
-
- QString parentVariable;
- QString childVariable;
- if (action != ArgumentOwner::Invalid) {
- if (!usePyArgs && argIndex > 1)
- qCWarning(lcShiboken).noquote().nospace()
- << "Argument index for parent tag out of bounds: " << func->signature();
-
- if (action == ArgumentOwner::Remove) {
- parentVariable = QLatin1String("Py_None");
- } else {
- if (parentIndex == 0) {
- parentVariable = QLatin1String(PYTHON_RETURN_VAR);
- } else if (parentIndex == -1) {
- parentVariable = QLatin1String("self");
- } else {
- parentVariable = usePyArgs
- ? pythonArgsAt(parentIndex - 1) : QLatin1String(PYTHON_ARG);
- }
- }
-
- if (childIndex == 0) {
- childVariable = QLatin1String(PYTHON_RETURN_VAR);
- } else if (childIndex == -1) {
- childVariable = QLatin1String("self");
- } else {
- childVariable = usePyArgs
- ? pythonArgsAt(childIndex - 1) : QLatin1String(PYTHON_ARG);
- }
-
- s << INDENT << "Shiboken::Object::setParent(" << parentVariable << ", " << childVariable << ");\n";
- return true;
- }
-
- return false;
-}
-
-void CppGenerator::writeParentChildManagement(QTextStream &s, const AbstractMetaFunction *func, bool useHeuristicForReturn)
-{
- const int numArgs = func->arguments().count();
-
- // -1 = return value
- // 0 = self
- // 1..n = func. args.
- for (int i = -1; i <= numArgs; ++i)
- writeParentChildManagement(s, func, i, useHeuristicForReturn);
-
- if (useHeuristicForReturn)
- writeReturnValueHeuristics(s, func);
-}
-
-void CppGenerator::writeReturnValueHeuristics(QTextStream &s, const AbstractMetaFunction *func, const QString &self)
-{
- AbstractMetaType *type = func->type();
- if (!useReturnValueHeuristic()
- || !func->ownerClass()
- || !type
- || func->isStatic()
- || func->isConstructor()
- || !func->typeReplaced(0).isEmpty()) {
- return;
- }
-
- ArgumentOwner argOwner = getArgumentOwner(func, ArgumentOwner::ReturnIndex);
- if (argOwner.action == ArgumentOwner::Invalid || argOwner.index != ArgumentOwner::ThisIndex) {
- if (isPointerToWrapperType(type))
- s << INDENT << "Shiboken::Object::setParent(self, " << PYTHON_RETURN_VAR << ");\n";
- }
-}
-
-void CppGenerator::writeHashFunction(QTextStream &s, GeneratorContext &context)
-{
- const AbstractMetaClass *metaClass = context.metaClass();
- s << "static Py_hash_t " << cpythonBaseName(metaClass) << "_HashFunc(PyObject *self) {\n";
- writeCppSelfDefinition(s, context);
- s << INDENT << "return " << metaClass->typeEntry()->hashFunction() << '(';
- s << (isObjectType(metaClass) ? "" : "*") << CPP_SELF_VAR << ");\n";
- s<< "}\n\n";
-}
-
-void CppGenerator::writeStdListWrapperMethods(QTextStream &s, GeneratorContext &context)
-{
- const AbstractMetaClass *metaClass = context.metaClass();
- ErrorCode errorCode(0);
-
- // __len__
- s << "Py_ssize_t " << cpythonBaseName(metaClass->typeEntry())
- << "__len__(PyObject *self)\n{\n";
- writeCppSelfDefinition(s, context);
- s << INDENT << "return " << CPP_SELF_VAR << "->size();\n";
- s << "}\n";
-
- // __getitem__
- s << "PyObject *" << cpythonBaseName(metaClass->typeEntry())
- << "__getitem__(PyObject *self, Py_ssize_t _i)\n{\n";
- writeCppSelfDefinition(s, context);
- writeIndexError(s, QLatin1String("index out of bounds"));
-
- s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = " << CPP_SELF_VAR << "->begin();\n";
- s << INDENT << "for (Py_ssize_t pos = 0; pos < _i; pos++) _item++;\n";
-
- const AbstractMetaType *itemType = metaClass->templateBaseClassInstantiations().constFirst();
-
- s << INDENT << "return ";
- writeToPythonConversion(s, itemType, metaClass, QLatin1String("*_item"));
- s << ";\n";
- s << "}\n";
-
- // __setitem__
- ErrorCode errorCode2(-1);
- s << "int " << cpythonBaseName(metaClass->typeEntry())
- << "__setitem__(PyObject *self, Py_ssize_t _i, PyObject *pyArg)\n{\n";
- writeCppSelfDefinition(s, context);
- writeIndexError(s, QLatin1String("list assignment index out of range"));
-
- s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ";\n";
- s << INDENT << "if (!";
- writeTypeCheck(s, itemType, QLatin1String("pyArg"), isNumber(itemType->typeEntry()));
- s << ") {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "PyErr_SetString(PyExc_TypeError, \"attributed value with wrong type, '";
- s << itemType->name() << "' or other convertible type expected\");\n";
- s << INDENT << "return -1;\n";
- }
- s << INDENT << "}\n";
- writeArgumentConversion(s, itemType, QLatin1String("cppValue"), QLatin1String("pyArg"), metaClass);
-
- s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = " << CPP_SELF_VAR << "->begin();\n";
- s << INDENT << "for (Py_ssize_t pos = 0; pos < _i; pos++) _item++;\n";
- s << INDENT << "*_item = cppValue;\n";
- s << INDENT << "return {};\n";
- s << "}\n";
-}
-void CppGenerator::writeIndexError(QTextStream &s, const QString &errorMsg)
-{
- s << INDENT << "if (_i < 0 || _i >= (Py_ssize_t) " << CPP_SELF_VAR << "->size()) {\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "PyErr_SetString(PyExc_IndexError, \"" << errorMsg << "\");\n";
- s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl;
- }
- s << INDENT << "}\n";
-}
-
-QString CppGenerator::writeReprFunction(QTextStream &s,
- GeneratorContext &context,
- uint indirections)
-{
- const AbstractMetaClass *metaClass = context.metaClass();
- QString funcName = cpythonBaseName(metaClass) + QLatin1String("__repr__");
- s << "extern \"C\"\n{\n";
- s << "static PyObject *" << funcName << "(PyObject *self)\n{\n";
- writeCppSelfDefinition(s, context);
- s << INDENT << "QBuffer buffer;\n";
- s << INDENT << "buffer.open(QBuffer::ReadWrite);\n";
- s << INDENT << "QDebug dbg(&buffer);\n";
- s << INDENT << "dbg << ";
- if (metaClass->typeEntry()->isValue() || indirections == 0)
- s << '*';
- s << CPP_SELF_VAR << ";\n";
- s << INDENT << "buffer.close();\n";
- s << INDENT << "QByteArray str = buffer.data();\n";
- s << INDENT << "int idx = str.indexOf('(');\n";
- s << INDENT << "if (idx >= 0)\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "str.replace(0, idx, Py_TYPE(self)->tp_name);\n";
- }
- s << INDENT << "str = str.trimmed();\n";
- s << INDENT << "PyObject *mod = PyDict_GetItem(Py_TYPE(self)->tp_dict, Shiboken::PyMagicName::module());\n";
- // PYSIDE-595: The introduction of heap types has the side effect that the module name
- // is always prepended to the type name. Therefore the strchr check:
- s << INDENT << "if (mod && !strchr(str, '.'))\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "return Shiboken::String::fromFormat(\"<%s.%s at %p>\", Shiboken::String::toCString(mod), str.constData(), self);\n";
- }
- s << INDENT << "else\n";
- {
- Indentation indent(INDENT);
- s << INDENT << "return Shiboken::String::fromFormat(\"<%s at %p>\", str.constData(), self);\n";
- }
- s << "}\n";
- s << "} // extern C\n\n";
- return funcName;
-}
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h
deleted file mode 100644
index fd272eaad..000000000
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.h
+++ /dev/null
@@ -1,384 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef CPPGENERATOR_H
-#define CPPGENERATOR_H
-
-#include "shibokengenerator.h"
-
-/**
- * The CppGenerator generate the implementations of C++ bindings classes.
- */
-class CppGenerator : public ShibokenGenerator
-{
-public:
- CppGenerator();
-
- const char *name() const override { return "Source generator"; }
-
-protected:
- QString fileNameSuffix() const override;
- QString fileNameForContext(GeneratorContext &context) const override;
- QVector<AbstractMetaFunctionList> filterGroupedOperatorFunctions(const AbstractMetaClass *metaClass,
- uint query);
- void generateClass(QTextStream &s, GeneratorContext &classContext) override;
- bool finishGeneration() override;
-
-private:
- void writeInitFunc(QTextStream &declStr, QTextStream &callStr,
- const Indentor &indent, const QString &initFunctionName,
- const TypeEntry *enclosingEntry = nullptr);
- void writeConstructorNative(QTextStream &s, const AbstractMetaFunction *func);
- void writeDestructorNative(QTextStream &s, const AbstractMetaClass *metaClass);
-
- QString getVirtualFunctionReturnTypeName(const AbstractMetaFunction *func);
- void writeVirtualMethodNative(QTextStream &s, const AbstractMetaFunction *func);
-
- void writeMetaObjectMethod(QTextStream &s, const AbstractMetaClass *metaClass);
- void writeMetaCast(QTextStream &s, const AbstractMetaClass *metaClass);
-
- void writeEnumConverterFunctions(QTextStream &s, const TypeEntry *enumType);
- void writeEnumConverterFunctions(QTextStream &s, const AbstractMetaEnum *metaEnum);
- void writeConverterFunctions(QTextStream &s, const AbstractMetaClass *metaClass,
- GeneratorContext &classContext);
- void writeCustomConverterFunctions(QTextStream &s, const CustomConversion *customConversion);
- void writeConverterRegister(QTextStream &s, const AbstractMetaClass *metaClass,
- GeneratorContext &classContext);
- void writeCustomConverterRegister(QTextStream &s, const CustomConversion *customConversion, const QString &converterVar);
-
- void writeContainerConverterFunctions(QTextStream &s, const AbstractMetaType *containerType);
-
- void writeMethodWrapperPreamble(QTextStream &s, OverloadData &overloadData,
- GeneratorContext &context);
- void writeConstructorWrapper(QTextStream &s, const AbstractMetaFunctionList &overloads,
- GeneratorContext &classContext);
- void writeMethodWrapper(QTextStream &s, const AbstractMetaFunctionList &overloads,
- GeneratorContext &classContext);
- void writeArgumentsInitializer(QTextStream &s, OverloadData &overloadData);
- void writeCppSelfAssigment(QTextStream &s, const GeneratorContext &context,
- const QString &className, bool cppSelfAsReference,
- bool useWrapperClass);
- void writeCppSelfDefinition(QTextStream &s,
- const AbstractMetaFunction *func,
- GeneratorContext &context,
- bool hasStaticOverload = false);
- void writeCppSelfDefinition(QTextStream &s,
- GeneratorContext &context,
- bool hasStaticOverload = false,
- bool cppSelfAsReference = false);
-
- void writeErrorSection(QTextStream &s, OverloadData &overloadData);
- void writeFunctionReturnErrorCheckSection(QTextStream &s, bool hasReturnValue = true);
-
- /// Writes the check section for the validity of wrapped C++ objects.
- void writeInvalidPyObjectCheck(QTextStream &s, const QString &pyObj);
-
- void writeTypeCheck(QTextStream &s, const AbstractMetaType *argType, const QString &argumentName,
- bool isNumber = false, const QString &customType = QString(),
- bool rejectNull = false);
- void writeTypeCheck(QTextStream& s, const OverloadData *overloadData, QString argumentName);
-
- void writeTypeDiscoveryFunction(QTextStream &s, const AbstractMetaClass *metaClass);
-
- void writeSetattroFunction(QTextStream &s, GeneratorContext &context);
- void writeGetattroFunction(QTextStream &s, GeneratorContext &context);
- QString writeSmartPointerGetterCast();
-
- /**
- * Writes Python to C++ conversions for arguments on Python wrappers.
- * If implicit conversions, and thus new object allocation, are needed,
- * code to deallocate a possible new instance is also generated.
- * \param s text stream to write
- * \param argType a pointer to the argument type to be converted
- * \param argName C++ argument name
- * \param pyArgName Python argument name
- * \param context the current meta class
- * \param defaultValue an optional default value to be used instead of the conversion result
- * \param castArgumentAsUnused if true the converted argument is cast as unused to avoid compiler warnings
- */
- void writeArgumentConversion(QTextStream &s, const AbstractMetaType *argType,
- const QString &argName, const QString &pyArgName,
- const AbstractMetaClass *context = nullptr,
- 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 = nullptr,
- const QString &defaultValue = QString());
-
- /// Writes the conversion rule for arguments of regular and virtual methods.
- void writeConversionRule(QTextStream &s, const AbstractMetaFunction *func, TypeSystem::Language language);
- /// Writes the conversion rule for the return value of a method.
- void writeConversionRule(QTextStream &s, const AbstractMetaFunction *func, TypeSystem::Language language, const QString &outputVar);
-
- /**
- * Set the Python method wrapper return value variable to Py_None if
- * there are return types different from void in any of the other overloads
- * for the function passed as parameter.
- * \param s text stream to write
- * \param func a pointer to the function that will possibly return Py_None
- * \param thereIsReturnValue indicates if the return type of any of the other overloads
- * for this function is different from 'void'
- */
- void writeNoneReturn(QTextStream &s, const AbstractMetaFunction *func, bool thereIsReturnValue);
-
- /**
- * Writes the Python function wrapper overload decisor that selects which C++
- * method/function to call with the received Python arguments.
- * \param s text stream to write
- * \param overloadData the overload data describing all the possible overloads for the function/method
- */
- void writeOverloadedFunctionDecisor(QTextStream &s, const OverloadData &overloadData);
- /// Recursive auxiliar method to the other writeOverloadedFunctionDecisor.
- void writeOverloadedFunctionDecisorEngine(QTextStream &s, const OverloadData *parentOverloadData);
-
- /// Writes calls to all the possible method/function overloads.
- void writeFunctionCalls(QTextStream &s,
- const OverloadData &overloadData,
- GeneratorContext &context);
-
- /// Writes the call to a single function usually from a collection of overloads.
- void writeSingleFunctionCall(QTextStream &s,
- const OverloadData &overloadData,
- const AbstractMetaFunction *func,
- GeneratorContext &context);
-
- /// Returns the name of a C++ to Python conversion function.
- static QString cppToPythonFunctionName(const QString &sourceTypeName, QString targetTypeName = QString());
-
- /// Returns the name of a Python to C++ conversion function.
- static QString pythonToCppFunctionName(const QString &sourceTypeName, const QString &targetTypeName);
- static QString pythonToCppFunctionName(const AbstractMetaType *sourceType, const AbstractMetaType *targetType);
- static QString pythonToCppFunctionName(const CustomConversion::TargetToNativeConversion *toNative, const TypeEntry *targetType);
-
- /// Returns the name of a Python to C++ convertible check function.
- static QString convertibleToCppFunctionName(const QString &sourceTypeName, const QString &targetTypeName);
- static QString convertibleToCppFunctionName(const AbstractMetaType *sourceType, const AbstractMetaType *targetType);
- static QString convertibleToCppFunctionName(const CustomConversion::TargetToNativeConversion *toNative, const TypeEntry *targetType);
-
- /// Writes a C++ to Python conversion function.
- void writeCppToPythonFunction(QTextStream &s, const QString &code, const QString &sourceTypeName, QString targetTypeName = QString());
- void writeCppToPythonFunction(QTextStream &s, const CustomConversion *customConversion);
- void writeCppToPythonFunction(QTextStream &s, const AbstractMetaType *containerType);
-
- /// Writes a Python to C++ conversion function.
- void writePythonToCppFunction(QTextStream &s, const QString &code, const QString &sourceTypeName, const QString &targetTypeName);
-
- /// Writes a Python to C++ convertible check function.
- void writeIsPythonConvertibleToCppFunction(QTextStream &s,
- const QString &sourceTypeName,
- const QString &targetTypeName,
- const QString &condition,
- QString pythonToCppFuncName = QString(),
- bool acceptNoneAsCppNull = false);
-
- /// Writes a pair of Python to C++ conversion and check functions.
- void writePythonToCppConversionFunctions(QTextStream &s,
- const AbstractMetaType *sourceType,
- const AbstractMetaType *targetType,
- QString typeCheck = QString(),
- QString conversion = QString(),
- const QString &preConversion = QString());
- /// Writes a pair of Python to C++ conversion and check functions for implicit conversions.
- void writePythonToCppConversionFunctions(QTextStream &s,
- const CustomConversion::TargetToNativeConversion *toNative,
- const TypeEntry *targetType);
-
- /// Writes a pair of Python to C++ conversion and check functions for instantiated container types.
- void writePythonToCppConversionFunctions(QTextStream &s, const AbstractMetaType *containerType);
-
- void writeAddPythonToCppConversion(QTextStream &s, const QString &converterVar, const QString &pythonToCppFunc, const QString &isConvertibleFunc);
-
- void writeNamedArgumentResolution(QTextStream &s, const AbstractMetaFunction *func, bool usePyArgs);
-
- /// Returns a string containing the name of an argument for the given function and argument index.
- QString argumentNameFromIndex(const AbstractMetaFunction *func, int argIndex, const AbstractMetaClass **wrappedClass);
- void writeMethodCall(QTextStream &s, const AbstractMetaFunction *func,
- GeneratorContext &context, int maxArgs = 0);
-
- QString getInitFunctionName(GeneratorContext &context) const;
- QString getSimpleClassInitFunctionName(const AbstractMetaClass *metaClass) const;
-
- void writeClassRegister(QTextStream &s,
- const AbstractMetaClass *metaClass,
- GeneratorContext &classContext,
- QTextStream &signatureStream);
- void writeClassDefinition(QTextStream &s,
- const AbstractMetaClass *metaClass,
- GeneratorContext &classContext);
- void writeMethodDefinitionEntry(QTextStream &s, const AbstractMetaFunctionList &overloads);
- void writeMethodDefinition(QTextStream &s, const AbstractMetaFunctionList &overloads);
- void writeSignatureInfo(QTextStream &s, const AbstractMetaFunctionList &overloads);
- /// Writes the implementation of all methods part of python sequence protocol
- void writeSequenceMethods(QTextStream &s,
- const AbstractMetaClass *metaClass,
- GeneratorContext &context);
- void writeTypeAsSequenceDefinition(QTextStream &s, const AbstractMetaClass *metaClass);
-
- /// Writes the PyMappingMethods structure for types that supports the python mapping protocol.
- void writeTypeAsMappingDefinition(QTextStream &s, const AbstractMetaClass *metaClass);
- void writeMappingMethods(QTextStream &s,
- const AbstractMetaClass *metaClass,
- GeneratorContext &context);
-
- void writeTypeAsNumberDefinition(QTextStream &s, const AbstractMetaClass *metaClass);
-
- void writeTpTraverseFunction(QTextStream &s, const AbstractMetaClass *metaClass);
- void writeTpClearFunction(QTextStream &s, const AbstractMetaClass *metaClass);
-
- void writeCopyFunction(QTextStream &s, GeneratorContext &context);
-
- void writeGetterFunction(QTextStream &s,
- const AbstractMetaField *metaField,
- GeneratorContext &context);
- void writeSetterFunction(QTextStream &s,
- const AbstractMetaField *metaField,
- GeneratorContext &context);
-
- void writeRichCompareFunction(QTextStream &s, GeneratorContext &context);
-
- void 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,
- const QString &pyOpName, const QString &cppOpName);
- void writeFlagsUnaryOperator(QTextStream &s, const AbstractMetaEnum *cppEnum,
- const QString &pyOpName, const 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 QVector<const AbstractMetaClass *>& conversions);
-
- void writeParentChildManagement(QTextStream &s, const AbstractMetaFunction *func, bool userHeuristicForReturn);
- bool writeParentChildManagement(QTextStream &s, const AbstractMetaFunction *func, int argIndex, bool userHeuristicPolicy);
- void writeReturnValueHeuristics(QTextStream &s, const AbstractMetaFunction *func, const QString &self = QLatin1String("self"));
- void writeInitQtMetaTypeFunctionBody(QTextStream &s, GeneratorContext &context) const;
-
- /**
- * Returns the multiple inheritance initializer function for the given class.
- * \param metaClass the class for whom the function name must be generated.
- * \return name of the multiple inheritance information initializer function or
- * an empty string if there is no multiple inheritance in its ancestry.
- */
- QString multipleInheritanceInitializerFunctionName(const AbstractMetaClass *metaClass);
-
- /// Returns a list of all classes to which the given class could be cast.
- QStringList getAncestorMultipleInheritance(const AbstractMetaClass *metaClass);
-
- /// Returns true if the given class supports the python number protocol
- bool supportsNumberProtocol(const AbstractMetaClass *metaClass);
-
- /// Returns true if the given class supports the python sequence protocol
- bool supportsSequenceProtocol(const AbstractMetaClass *metaClass);
-
- /// Returns true if the given class supports the python mapping protocol
- bool supportsMappingProtocol(const AbstractMetaClass *metaClass);
-
- /// Returns true if generator should produce getters and setters for the given class.
- bool shouldGenerateGetSetList(const AbstractMetaClass *metaClass);
-
- void writeHashFunction(QTextStream &s, GeneratorContext &context);
-
- /// Write default implementations for sequence protocol
- void writeStdListWrapperMethods(QTextStream &s, GeneratorContext &context);
- /// Helper function for writeStdListWrapperMethods.
- void writeIndexError(QTextStream &s, const QString &errorMsg);
-
- QString writeReprFunction(QTextStream &s, GeneratorContext &context, uint indirections);
-
- const AbstractMetaFunction *boolCast(const AbstractMetaClass *metaClass) const;
- bool hasBoolCast(const AbstractMetaClass *metaClass) const
- { return boolCast(metaClass) != nullptr; }
-
- // Number protocol structure members names.
- static QHash<QString, QString> m_nbFuncs;
-
- // Maps special function names to function parameters and return types
- // used by CPython API in the sequence protocol.
- QHash<QString, QPair<QString, QString> > m_sequenceProtocol;
- // Sequence protocol structure members names.
- static QHash<QString, QString> m_sqFuncs;
-
- // Maps special function names to function parameters and return types
- // used by CPython API in the mapping protocol.
- QHash<QString, QPair<QString, QString> > m_mappingProtocol;
- // Mapping protocol structure members names.
- static QHash<QString, QString> m_mpFuncs;
-
- static QString m_currentErrorCode;
-
- /// Helper class to set and restore the current error code.
- class ErrorCode {
- public:
- explicit ErrorCode(QString errorCode) {
- m_savedErrorCode = CppGenerator::m_currentErrorCode;
- CppGenerator::m_currentErrorCode = errorCode;
- }
- explicit ErrorCode(int errorCode) {
- m_savedErrorCode = CppGenerator::m_currentErrorCode;
- CppGenerator::m_currentErrorCode = QString::number(errorCode);
- }
- ~ErrorCode() {
- CppGenerator::m_currentErrorCode = m_savedErrorCode;
- }
- private:
- QString m_savedErrorCode;
- };
-};
-
-#endif // CPPGENERATOR_H
diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.cpp b/sources/shiboken2/generator/shiboken2/headergenerator.cpp
deleted file mode 100644
index a565659de..000000000
--- a/sources/shiboken2/generator/shiboken2/headergenerator.cpp
+++ /dev/null
@@ -1,639 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "headergenerator.h"
-#include <abstractmetalang.h>
-#include <typedatabase.h>
-#include <reporthandler.h>
-#include <fileout.h>
-#include "parser/codemodel.h"
-
-#include <algorithm>
-
-#include <QtCore/QDir>
-#include <QtCore/QTextStream>
-#include <QtCore/QVariant>
-#include <QtCore/QDebug>
-
-QString HeaderGenerator::fileNameSuffix() const
-{
- return QLatin1String("_wrapper.h");
-}
-
-QString HeaderGenerator::fileNameForContext(GeneratorContext &context) const
-{
- const AbstractMetaClass *metaClass = context.metaClass();
- if (!context.forSmartPointer()) {
- QString fileNameBase = metaClass->qualifiedCppName().toLower();
- fileNameBase.replace(QLatin1String("::"), QLatin1String("_"));
- return fileNameBase + fileNameSuffix();
- }
- const AbstractMetaType *smartPointerType = context.preciseType();
- QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass);
- return fileNameBase + fileNameSuffix();
-}
-
-void HeaderGenerator::writeCopyCtor(QTextStream &s, const AbstractMetaClass *metaClass) const
-{
- s << INDENT << wrapperName(metaClass) << "(const " << metaClass->qualifiedCppName() << "& self)";
- s << " : " << metaClass->qualifiedCppName() << "(self)\n";
- s << INDENT << "{\n";
- s << INDENT << "}\n\n";
-}
-
-void HeaderGenerator::writeProtectedFieldAccessors(QTextStream &s, const AbstractMetaField *field) const
-{
- AbstractMetaType *metaType = field->type();
- QString fieldType = metaType->cppSignature();
- QString fieldName = field->enclosingClass()->qualifiedCppName() + QLatin1String("::") + field->name();
-
- // Force use of pointer to return internal variable memory
- bool useReference = (!metaType->isConstant() &&
- !metaType->isEnum() &&
- !metaType->isPrimitive() &&
- metaType->indirections() == 0);
-
-
- // Get function
- s << INDENT << "inline " << fieldType
- << (useReference ? " *" : " ")
- << ' ' << protectedFieldGetterName(field) << "()"
- << " { return "
- << (useReference ? " &" : " ") << "this->" << fieldName << "; }\n";
-
- // Set function
- s << INDENT << "inline void " << protectedFieldSetterName(field) << '(' << fieldType << " value)"
- << " { " << fieldName << " = value; }\n";
-}
-
-void HeaderGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
-{
- AbstractMetaClass *metaClass = classContext.metaClass();
- if (ReportHandler::isDebug(ReportHandler::SparseDebug))
- qCDebug(lcShiboken) << "Generating header for " << metaClass->fullName();
- m_inheritedOverloads.clear();
- Indentation indent(INDENT);
-
- // write license comment
- s << licenseComment();
-
- QString wrapperName;
- if (!classContext.forSmartPointer()) {
- wrapperName = HeaderGenerator::wrapperName(metaClass);
- } else {
- wrapperName = HeaderGenerator::wrapperName(classContext.preciseType());
- }
- QString outerHeaderGuard = getFilteredCppSignatureString(wrapperName).toUpper();
- QString innerHeaderGuard;
-
- // Header
- s << "#ifndef SBK_" << outerHeaderGuard << "_H\n";
- s << "#define SBK_" << outerHeaderGuard << "_H\n\n";
-
- if (!avoidProtectedHack())
- s << "#define protected public\n\n";
-
- //Includes
- s << metaClass->typeEntry()->include() << Qt::endl;
-
- if (shouldGenerateCppWrapper(metaClass) &&
- usePySideExtensions() && metaClass->isQObject())
- s << "namespace PySide { class DynamicQMetaObject; }\n\n";
-
- while (shouldGenerateCppWrapper(metaClass)) {
- if (!innerHeaderGuard.isEmpty()) {
- s << "# ifndef SBK_" << innerHeaderGuard << "_H\n";
- s << "# define SBK_" << innerHeaderGuard << "_H\n\n";
- s << "// Inherited base class:\n";
- }
-
- // Class
- s << "class " << wrapperName;
- s << " : public " << metaClass->qualifiedCppName();
-
- s << "\n{\npublic:\n";
-
- const AbstractMetaFunctionList &funcs = filterFunctions(metaClass);
- for (AbstractMetaFunction *func : funcs) {
- if ((func->attributes() & AbstractMetaAttributes::FinalCppMethod) == 0)
- writeFunction(s, func);
- }
-
- if (avoidProtectedHack() && metaClass->hasProtectedFields()) {
- const AbstractMetaFieldList &fields = metaClass->fields();
- for (AbstractMetaField *field : fields) {
- if (!field->isProtected())
- continue;
- writeProtectedFieldAccessors(s, field);
- }
- }
-
- //destructor
- // PYSIDE-504: When C++ 11 is used, then the destructor must always be written.
- // See generator.h for further reference.
- if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor() || alwaysGenerateDestructor) {
- s << INDENT;
- if (avoidProtectedHack() && metaClass->hasPrivateDestructor())
- s << "// C++11: need to declare (unimplemented) destructor because "
- "the base class destructor is private.\n";
- s << '~' << wrapperName << "();\n";
- }
-
- writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), TypeSystem::CodeSnipPositionDeclaration, TypeSystem::NativeCode);
-
- if ((!avoidProtectedHack() || !metaClass->hasPrivateDestructor())
- && usePySideExtensions() && metaClass->isQObject()) {
- s << "public:\n";
- s << INDENT << "int qt_metacall(QMetaObject::Call call, int id, void **args) override;\n";
- s << INDENT << "void *qt_metacast(const char *_clname) override;\n";
- }
-
- if (!m_inheritedOverloads.isEmpty()) {
- s << INDENT << "// Inherited overloads, because the using keyword sux\n";
- writeInheritedOverloads(s);
- m_inheritedOverloads.clear();
- }
-
- if (usePySideExtensions())
- s << INDENT << "static void pysideInitQtMetaTypes();\n";
-
- s << "};\n\n";
- if (!innerHeaderGuard.isEmpty())
- s << "# endif // SBK_" << innerHeaderGuard << "_H\n\n";
-
- // PYSIDE-500: Use also includes for inherited wrapper classes, because
- // without the protected hack, we sometimes need to cast inherited wrappers.
- // But we don't use multiple include files. Instead, they are inserted as recursive
- // headers. This keeps the file structure as simple as before the enhanced inheritance.
- metaClass = metaClass->baseClass();
- if (!metaClass || !avoidProtectedHack())
- break;
- classContext = GeneratorContext(metaClass);
- if (!classContext.forSmartPointer()) {
- wrapperName = HeaderGenerator::wrapperName(metaClass);
- } else {
- wrapperName = HeaderGenerator::wrapperName(classContext.preciseType());
- }
- innerHeaderGuard = getFilteredCppSignatureString(wrapperName).toUpper();
- }
-
- s << "#endif // SBK_" << outerHeaderGuard << "_H\n\n";
-}
-
-void HeaderGenerator::writeFunction(QTextStream &s, const AbstractMetaFunction *func)
-{
-
- // do not write copy ctors here.
- if (!func->isPrivate() && func->functionType() == AbstractMetaFunction::CopyConstructorFunction) {
- writeCopyCtor(s, func->ownerClass());
- return;
- }
- if (func->isUserAdded())
- return;
-
- if (avoidProtectedHack() && func->isProtected() && !func->isConstructor() && !func->isOperatorOverload()) {
- s << INDENT << "inline " << (func->isStatic() ? "static " : "");
- s << functionSignature(func, QString(), QLatin1String("_protected"), Generator::EnumAsInts|Generator::OriginalTypeDescription)
- << " { ";
- s << (func->type() ? "return " : "");
- if (!func->isAbstract())
- s << func->ownerClass()->qualifiedCppName() << "::";
- s << func->originalName() << '(';
- QStringList args;
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (const AbstractMetaArgument *arg : arguments) {
- QString argName = arg->name();
- const TypeEntry *enumTypeEntry = nullptr;
- if (arg->type()->isFlags())
- enumTypeEntry = static_cast<const FlagsTypeEntry *>(arg->type()->typeEntry())->originator();
- else if (arg->type()->isEnum())
- enumTypeEntry = arg->type()->typeEntry();
- if (enumTypeEntry)
- argName = QString::fromLatin1("%1(%2)").arg(arg->type()->cppSignature(), argName);
- args << argName;
- }
- s << args.join(QLatin1String(", ")) << ')';
- s << "; }\n";
- }
-
- // pure virtual functions need a default implementation
- const bool notAbstract = !func->isAbstract();
- if ((func->isPrivate() && notAbstract && !visibilityModifiedToPrivate(func))
- || (func->isModifiedRemoved() && notAbstract))
- return;
-
- if (avoidProtectedHack() && func->ownerClass()->hasPrivateDestructor()
- && (func->isAbstract() || func->isVirtual()))
- return;
-
- if (func->isConstructor() || func->isAbstract() || func->isVirtual()) {
- s << INDENT;
- Options virtualOption = Generator::OriginalTypeDescription;
-
- const bool virtualFunc = func->isVirtual() || func->isAbstract();
- if (!virtualFunc && !func->hasSignatureModifications())
- virtualOption = Generator::NoOption;
-
- s << functionSignature(func, QString(), QString(), virtualOption);
-
- if (virtualFunc)
- s << " override";
- s << ";\n";
- // Check if this method hide other methods in base classes
- const AbstractMetaFunctionList &ownerFuncs = func->ownerClass()->functions();
- for (const AbstractMetaFunction *f : ownerFuncs) {
- if (f != func
- && !f->isConstructor()
- && !f->isPrivate()
- && !f->isVirtual()
- && !f->isAbstract()
- && !f->isStatic()
- && f->name() == func->name()) {
- m_inheritedOverloads << f;
- }
- }
-
- // TODO: when modified an abstract method ceases to be virtual but stays abstract
- //if (func->isModifiedRemoved() && func->isAbstract()) {
- //}
- }
-}
-
-static void _writeTypeIndexValue(QTextStream &s, const QString &variableName,
- int typeIndex)
-{
- s << " ";
- s.setFieldWidth(56);
- s << variableName;
- s.setFieldWidth(0);
- s << " = " << typeIndex;
-}
-
-static inline void _writeTypeIndexValueLine(QTextStream &s,
- const QString &variableName,
- int typeIndex)
-{
- _writeTypeIndexValue(s, variableName, typeIndex);
- s << ",\n";
-}
-
-void HeaderGenerator::writeTypeIndexValueLine(QTextStream &s, const TypeEntry *typeEntry)
-{
- if (!typeEntry || !typeEntry->generateCode())
- return;
- s.setFieldAlignment(QTextStream::AlignLeft);
- const int typeIndex = typeEntry->sbkIndex();
- _writeTypeIndexValueLine(s, getTypeIndexVariableName(typeEntry), typeIndex);
- if (typeEntry->isComplex()) {
- const auto *cType = static_cast<const ComplexTypeEntry *>(typeEntry);
- if (cType->baseContainerType()) {
- const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes(), cType);
- if (metaClass->templateBaseClass())
- _writeTypeIndexValueLine(s, getTypeIndexVariableName(metaClass, true), typeIndex);
- }
- }
- if (typeEntry->isEnum()) {
- auto ete = static_cast<const EnumTypeEntry *>(typeEntry);
- if (ete->flags())
- writeTypeIndexValueLine(s, ete->flags());
- }
-}
-
-void HeaderGenerator::writeTypeIndexValueLines(QTextStream &s, const AbstractMetaClass *metaClass)
-{
- auto typeEntry = metaClass->typeEntry();
- if (!typeEntry->generateCode() || !NamespaceTypeEntry::isVisibleScope(typeEntry))
- return;
- writeTypeIndexValueLine(s, metaClass->typeEntry());
- const AbstractMetaEnumList &enums = metaClass->enums();
- for (const AbstractMetaEnum *metaEnum : enums) {
- if (metaEnum->isPrivate())
- continue;
- writeTypeIndexValueLine(s, metaEnum->typeEntry());
- }
-}
-
-// Format the typedefs for the typedef entries to be generated
-static void formatTypeDefEntries(QTextStream &s)
-{
- QVector<const TypedefEntry *> entries;
- const auto typeDbEntries = TypeDatabase::instance()->typedefEntries();
- for (auto it = typeDbEntries.cbegin(), end = typeDbEntries.cend(); it != end; ++it) {
- if (it.value()->generateCode() != 0)
- entries.append(it.value());
- }
- if (entries.isEmpty())
- return;
- s << "\n// typedef entries\n";
- for (const auto e : entries) {
- const QString name = e->qualifiedCppName();
- // Fixme: simplify by using nested namespaces in C++ 17.
- const auto components = name.splitRef(QLatin1String("::"));
- const int nameSpaceCount = components.size() - 1;
- for (int n = 0; n < nameSpaceCount; ++n)
- s << "namespace " << components.at(n) << " {\n";
- s << "using " << components.constLast() << " = " << e->sourceType() << ";\n";
- for (int n = 0; n < nameSpaceCount; ++n)
- s << "}\n";
- }
- s << '\n';
-}
-
-
-bool HeaderGenerator::finishGeneration()
-{
- // Generate the main header for this module.
- // This header should be included by binding modules
- // extendind on top of this one.
- QSet<Include> includes;
- QString macros;
- QTextStream macrosStream(&macros);
- QString sbkTypeFunctions;
- QTextStream typeFunctions(&sbkTypeFunctions);
- QString protectedEnumSurrogates;
- QTextStream protEnumsSurrogates(&protectedEnumSurrogates);
-
- Indentation indent(INDENT);
-
- macrosStream << "// Type indices\nenum : int {\n";
- AbstractMetaEnumList globalEnums = this->globalEnums();
- AbstractMetaClassList classList = classes();
-
- std::sort(classList.begin(), classList.end(), [](AbstractMetaClass *a, AbstractMetaClass *b) {
- return a->typeEntry()->sbkIndex() < b->typeEntry()->sbkIndex();
- });
-
- for (const AbstractMetaClass *metaClass : classList) {
- writeTypeIndexValueLines(macrosStream, metaClass);
- lookForEnumsInClassesNotToBeGenerated(globalEnums, metaClass);
- }
-
- for (const AbstractMetaEnum *metaEnum : qAsConst(globalEnums))
- writeTypeIndexValueLine(macrosStream, metaEnum->typeEntry());
-
- // Write the smart pointer define indexes.
- int smartPointerCountIndex = getMaxTypeIndex();
- int smartPointerCount = 0;
- const QVector<const AbstractMetaType *> &instantiatedSmartPtrs = instantiatedSmartPointers();
- for (const AbstractMetaType *metaType : instantiatedSmartPtrs) {
- QString indexName = getTypeIndexVariableName(metaType);
- _writeTypeIndexValue(macrosStream, indexName, smartPointerCountIndex);
- macrosStream << ", // " << metaType->cppSignature() << Qt::endl;
- // Add a the same value for const pointees (shared_ptr<const Foo>).
- const auto ptrName = metaType->typeEntry()->entryName();
- int pos = indexName.indexOf(ptrName, 0, Qt::CaseInsensitive);
- if (pos >= 0) {
- indexName.insert(pos + ptrName.size() + 1, QLatin1String("CONST"));
- _writeTypeIndexValue(macrosStream, indexName, smartPointerCountIndex);
- macrosStream << ", // (const)\n";
- }
- ++smartPointerCountIndex;
- ++smartPointerCount;
- }
-
- _writeTypeIndexValue(macrosStream,
- QLatin1String("SBK_") + moduleName() + QLatin1String("_IDX_COUNT"),
- getMaxTypeIndex() + smartPointerCount);
- macrosStream << "\n};\n";
-
- macrosStream << "// This variable stores all Python types exported by this module.\n";
- macrosStream << "extern PyTypeObject **" << cppApiVariableName() << ";\n\n";
- macrosStream << "// This variable stores the Python module object exported by this module.\n";
- macrosStream << "extern PyObject *" << pythonModuleObjectName() << ";\n\n";
- macrosStream << "// This variable stores all type converters exported by this module.\n";
- macrosStream << "extern SbkConverter **" << convertersVariableName() << ";\n\n";
-
- // TODO-CONVERTER ------------------------------------------------------------------------------
- // Using a counter would not do, a fix must be made to APIExtractor's getTypeIndex().
- macrosStream << "// Converter indices\nenum : int {\n";
- const PrimitiveTypeEntryList &primitives = primitiveTypes();
- int pCount = 0;
- for (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;
-
- _writeTypeIndexValueLine(macrosStream, getTypeIndexVariableName(ptype), pCount++);
- }
-
- const QVector<const AbstractMetaType *> &containers = instantiatedContainers();
- for (const AbstractMetaType *container : containers) {
- _writeTypeIndexValue(macrosStream, getTypeIndexVariableName(container), pCount);
- macrosStream << ", // " << container->cppSignature() << Qt::endl;
- pCount++;
- }
-
- // Because on win32 the compiler will not accept a zero length array.
- if (pCount == 0)
- pCount++;
- _writeTypeIndexValue(macrosStream, QStringLiteral("SBK_%1_CONVERTERS_IDX_COUNT")
- .arg(moduleName()), pCount);
- macrosStream << "\n};\n";
-
- formatTypeDefEntries(macrosStream);
-
- // TODO-CONVERTER ------------------------------------------------------------------------------
-
- macrosStream << "// Macros for type check\n";
-
- if (usePySideExtensions()) {
- typeFunctions << "QT_WARNING_PUSH\n";
- typeFunctions << "QT_WARNING_DISABLE_DEPRECATED\n";
- }
- for (const AbstractMetaEnum *cppEnum : qAsConst(globalEnums)) {
- if (cppEnum->isAnonymous() || cppEnum->isPrivate())
- continue;
- includes << cppEnum->typeEntry()->include();
- writeProtectedEnumSurrogate(protEnumsSurrogates, cppEnum);
- writeSbkTypeFunction(typeFunctions, cppEnum);
- }
-
- for (AbstractMetaClass *metaClass : classList) {
- if (!shouldGenerate(metaClass))
- continue;
-
- //Includes
- const TypeEntry *classType = metaClass->typeEntry();
- includes << classType->include();
-
- const AbstractMetaEnumList &enums = metaClass->enums();
- for (const AbstractMetaEnum *cppEnum : 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);
- }
-
- for (const AbstractMetaType *metaType : instantiatedSmartPtrs) {
- const TypeEntry *classType = metaType->typeEntry();
- includes << classType->include();
- writeSbkTypeFunction(typeFunctions, metaType);
- }
- if (usePySideExtensions())
- typeFunctions << "QT_WARNING_POP\n";
-
- QString moduleHeaderFileName(outputDirectory()
- + QDir::separator() + subDirectoryForPackage(packageName())
- + QDir::separator() + getModuleHeaderFileName());
-
- QString includeShield(QLatin1String("SBK_") + moduleName().toUpper() + QLatin1String("_PYTHON_H"));
-
- FileOut file(moduleHeaderFileName);
- QTextStream &s = file.stream;
- // write license comment
- s << licenseComment() << Qt::endl << Qt::endl;
-
- s << "#ifndef " << includeShield << Qt::endl;
- s << "#define " << includeShield << Qt::endl << Qt::endl;
- if (!avoidProtectedHack()) {
- s << "//workaround to access protected functions\n";
- s << "#define protected public\n\n";
- }
-
- s << "#include <sbkpython.h>\n";
- s << "#include <sbkconverter.h>\n";
-
- QStringList requiredTargetImports = TypeDatabase::instance()->requiredTargetImports();
- if (!requiredTargetImports.isEmpty()) {
- s << "// Module Includes\n";
- for (const QString &requiredModule : qAsConst(requiredTargetImports))
- s << "#include <" << getModuleHeaderFileName(requiredModule) << ">\n";
- s << Qt::endl;
- }
-
- s << "// Bound library includes\n";
- for (const Include &include : qAsConst(includes))
- s << include;
-
- if (!primitiveTypes().isEmpty()) {
- s << "// Conversion Includes - Primitive Types\n";
- const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes();
- for (const PrimitiveTypeEntry *ptype : primitiveTypeList)
- s << ptype->include();
- s << Qt::endl;
- }
-
- if (!containerTypes().isEmpty()) {
- s << "// Conversion Includes - Container Types\n";
- const ContainerTypeEntryList &containerTypeList = containerTypes();
- for (const ContainerTypeEntry *ctype : containerTypeList)
- s << ctype->include();
- s << Qt::endl;
- }
-
- s << macros << Qt::endl;
-
- if (!protectedEnumSurrogates.isEmpty()) {
- s << "// Protected enum surrogates\n";
- s << protectedEnumSurrogates << Qt::endl;
- }
-
- s << "namespace Shiboken\n{\n\n";
-
- s << "// PyType functions, to get the PyObjectType for a type T\n";
- s << sbkTypeFunctions << Qt::endl;
-
- s << "} // namespace Shiboken\n\n";
-
- s << "#endif // " << includeShield << Qt::endl << Qt::endl;
-
- return file.done() != FileOut::Failure;
-}
-
-void HeaderGenerator::writeProtectedEnumSurrogate(QTextStream &s, const AbstractMetaEnum *cppEnum)
-{
- if (avoidProtectedHack() && cppEnum->isProtected())
- s << "enum " << protectedEnumSurrogateName(cppEnum) << " {};\n";
-}
-
-void HeaderGenerator::writeSbkTypeFunction(QTextStream &s, const AbstractMetaEnum *cppEnum)
-{
- QString enumName;
- if (avoidProtectedHack() && cppEnum->isProtected()) {
- enumName = protectedEnumSurrogateName(cppEnum);
- } else {
- enumName = cppEnum->name();
- if (cppEnum->enclosingClass())
- enumName = cppEnum->enclosingClass()->qualifiedCppName() + QLatin1String("::") + enumName;
- }
-
- s << "template<> inline PyTypeObject *SbkType< ::" << enumName << " >() ";
- s << "{ return " << cpythonTypeNameExt(cppEnum->typeEntry()) << "; }\n";
-
- FlagsTypeEntry *flag = cppEnum->typeEntry()->flags();
- if (flag) {
- s << "template<> inline PyTypeObject *SbkType< ::" << flag->name() << " >() "
- << "{ return " << cpythonTypeNameExt(flag) << "; }\n";
- }
-}
-
-void HeaderGenerator::writeSbkTypeFunction(QTextStream &s, const AbstractMetaClass *cppClass)
-{
- s << "template<> inline PyTypeObject *SbkType< ::" << cppClass->qualifiedCppName() << " >() "
- << "{ return reinterpret_cast<PyTypeObject *>(" << cpythonTypeNameExt(cppClass->typeEntry()) << "); }\n";
-}
-
-void HeaderGenerator::writeSbkTypeFunction(QTextStream &s, const AbstractMetaType *metaType)
-{
- s << "template<> inline PyTypeObject *SbkType< ::" << metaType->cppSignature() << " >() "
- << "{ return reinterpret_cast<PyTypeObject *>(" << cpythonTypeNameExt(metaType) << "); }\n";
-}
-
-void HeaderGenerator::writeInheritedOverloads(QTextStream &s)
-{
- for (const AbstractMetaFunction *func : qAsConst(m_inheritedOverloads)) {
- s << INDENT << "inline ";
- s << functionSignature(func, QString(), QString(), Generator::EnumAsInts|Generator::OriginalTypeDescription) << " { ";
- s << (func->type() ? "return " : "");
- s << func->ownerClass()->qualifiedCppName() << "::" << func->originalName() << '(';
- QStringList args;
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (const AbstractMetaArgument *arg : arguments) {
- QString argName = arg->name();
- const TypeEntry *enumTypeEntry = nullptr;
- if (arg->type()->isFlags())
- enumTypeEntry = static_cast<const FlagsTypeEntry *>(arg->type()->typeEntry())->originator();
- else if (arg->type()->isEnum())
- enumTypeEntry = arg->type()->typeEntry();
- if (enumTypeEntry)
- argName = arg->type()->cppSignature() + QLatin1Char('(') + argName + QLatin1Char(')');
- args << argName;
- }
- s << args.join(QLatin1String(", ")) << ')';
- s << "; }\n";
- }
-}
diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.h b/sources/shiboken2/generator/shiboken2/headergenerator.h
deleted file mode 100644
index 5f59dd13a..000000000
--- a/sources/shiboken2/generator/shiboken2/headergenerator.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef HEADERGENERATOR_H
-#define HEADERGENERATOR_H
-
-#include "shibokengenerator.h"
-
-#include <QtCore/QSet>
-
-class AbstractMetaFunction;
-
-/**
- * The HeaderGenerator generate the declarations of C++ bindings classes.
- */
-class HeaderGenerator : public ShibokenGenerator
-{
-public:
- OptionDescriptions options() const override { return OptionDescriptions(); }
-
- const char *name() const override { return "Header generator"; }
-
-protected:
- QString fileNameSuffix() const override;
- QString fileNameForContext(GeneratorContext &context) const override;
- void generateClass(QTextStream &s, GeneratorContext &classContext) override;
- bool finishGeneration() override;
-
-private:
- void writeCopyCtor(QTextStream &s, const AbstractMetaClass *metaClass) const;
- void writeProtectedFieldAccessors(QTextStream &s, const AbstractMetaField *field) const;
- void writeFunction(QTextStream &s, const AbstractMetaFunction *func);
- void writeSbkTypeFunction(QTextStream &s, const AbstractMetaEnum *cppEnum);
- void writeSbkTypeFunction(QTextStream &s, const AbstractMetaClass *cppClass);
- void writeSbkTypeFunction(QTextStream &s, const AbstractMetaType *metaType);
- void writeTypeIndexValueLine(QTextStream &s, const TypeEntry *typeEntry);
- void writeTypeIndexValueLines(QTextStream &s, const AbstractMetaClass *metaClass);
- void writeProtectedEnumSurrogate(QTextStream &s, const AbstractMetaEnum *cppEnum);
- void writeInheritedOverloads(QTextStream &s);
-
- QSet<const AbstractMetaFunction *> m_inheritedOverloads;
-};
-
-#endif // HEADERGENERATOR_H
-
diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.cpp b/sources/shiboken2/generator/shiboken2/overloaddata.cpp
deleted file mode 100644
index 56b64bbd5..000000000
--- a/sources/shiboken2/generator/shiboken2/overloaddata.cpp
+++ /dev/null
@@ -1,1091 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <abstractmetalang.h>
-#include <reporthandler.h>
-#include <graph.h>
-#include "overloaddata.h"
-#include "indentor.h"
-#include "shibokengenerator.h"
-
-#include <QtCore/QDir>
-#include <QtCore/QFile>
-#include <QtCore/QTemporaryFile>
-
-static const TypeEntry *getReferencedTypeEntry(const TypeEntry *typeEntry)
-{
- if (typeEntry->isPrimitive()) {
- auto pte = dynamic_cast<const PrimitiveTypeEntry *>(typeEntry);
- while (pte->referencedTypeEntry())
- pte = pte->referencedTypeEntry();
- typeEntry = pte;
- }
- return typeEntry;
-}
-
-static QString getTypeName(const AbstractMetaType *type)
-{
- const TypeEntry *typeEntry = getReferencedTypeEntry(type->typeEntry());
- QString typeName = typeEntry->name();
- if (typeEntry->isContainer()) {
- QStringList types;
- const AbstractMetaTypeList &instantiations = type->instantiations();
- for (const AbstractMetaType *cType : instantiations) {
- const TypeEntry *typeEntry = getReferencedTypeEntry(cType->typeEntry());
- types << typeEntry->name();
- }
- typeName += QLatin1Char('<') + types.join(QLatin1Char(',')) + QLatin1String(" >");
- }
- return typeName;
-}
-
-static QString getTypeName(const OverloadData *ov)
-{
- return ov->hasArgumentTypeReplace() ? ov->argumentTypeReplaced() : getTypeName(ov->argType());
-}
-
-static bool typesAreEqual(const AbstractMetaType *typeA, const AbstractMetaType *typeB)
-{
- if (typeA->typeEntry() == typeB->typeEntry()) {
- if (typeA->isContainer() || typeA->isSmartPointer()) {
- if (typeA->instantiations().size() != typeB->instantiations().size())
- return false;
-
- for (int i = 0; i < typeA->instantiations().size(); ++i) {
- if (!typesAreEqual(typeA->instantiations().at(i), typeB->instantiations().at(i)))
- return false;
- }
- return true;
- }
-
- return !(ShibokenGenerator::isCString(typeA) ^ ShibokenGenerator::isCString(typeB));
- }
- return false;
-}
-
-
-/**
- * OverloadSortData just helps writing clearer code in the
- * OverloadData::sortNextOverloads method.
- */
-struct OverloadSortData
-{
- /**
- * 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 = 0;
- 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().constFirst()->type());
-
- QStringList types;
- const AbstractMetaTypeList &instantiations = containerType->instantiations();
- for (const AbstractMetaType *otherType : instantiations)
- types << (otherType == instantiation ? impConv : getTypeName(otherType));
-
- return containerType->typeEntry()->qualifiedCppName() + QLatin1Char('<')
- + types.join(QLatin1String(", ")) + QLatin1String(" >");
-}
-
-// overloaddata.cpp
-static QString msgCyclicDependency(const QString &funcName, const QString &graphName,
- const OverloadData::MetaFunctionList &involvedConversions)
-{
- QString result;
- QTextStream str(&result);
- str << "Cyclic dependency found on overloaddata for \"" << funcName
- << "\" method! The graph boy saved the graph at \"" << QDir::toNativeSeparators(graphName)
- << "\".";
- if (const int count = involvedConversions.size()) {
- str << " Implicit conversions (" << count << "): ";
- for (int i = 0; i < count; ++i) {
- if (i)
- str << ", \"";
- str << involvedConversions.at(i)->signature() << '"';
- if (const AbstractMetaClass *c = involvedConversions.at(i)->implementingClass())
- str << '(' << c->name() << ')';
- }
- }
- return result;
-}
-
-/**
- * Topologically sort the overloads by implicit convertion order
- *
- * This avoids using an implicit conversion if there's an explicit
- * overload for the convertible type. So, if there's an implicit convert
- * like TargetType(ConvertibleType foo) and both are in the overload list,
- * ConvertibleType is checked before TargetType.
- *
- * Side effects: Modifies m_nextOverloadData
- */
-void OverloadData::sortNextOverloads()
-{
- OverloadSortData sortData;
- bool checkPyObject = false;
- int pyobjectIndex = 0;
- bool checkPySequence = false;
- int pySeqIndex = 0;
- bool checkQString = false;
- int qstringIndex = 0;
- bool checkQVariant = false;
- int qvariantIndex = 0;
- bool checkPyBuffer = false;
- int pyBufferIndex = 0;
-
- // Primitive types that are not int, long, short,
- // char and their respective unsigned counterparts.
- QStringList nonIntegerPrimitives;
- nonIntegerPrimitives << QLatin1String("float") << QLatin1String("double")
- << QLatin1String("bool");
-
- // Signed integer primitive types.
- QStringList signedIntegerPrimitives;
- signedIntegerPrimitives << QLatin1String("int") << QLatin1String("short")
- << QLatin1String("long");
-
- // sort the children overloads
- for (OverloadData *ov : qAsConst(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.
- for (OverloadData *ov : qAsConst(m_nextOverloadData)) {
- sortData.mapType(ov);
-
- const QString typeName(getTypeName(ov));
-
- if (!checkPyObject && typeName.contains(QLatin1String("PyObject"))) {
- checkPyObject = true;
- pyobjectIndex = sortData.lastProcessedItemId();
- } else if (!checkPySequence && typeName == QLatin1String("PySequence")) {
- checkPySequence = true;
- pySeqIndex = sortData.lastProcessedItemId();
- } else if (!checkPyBuffer && typeName == QLatin1String("PyBuffer")) {
- checkPyBuffer = true;
- pyBufferIndex = sortData.lastProcessedItemId();
- } else if (!checkQVariant && typeName == QLatin1String("QVariant")) {
- checkQVariant = true;
- qvariantIndex = sortData.lastProcessedItemId();
- } else if (!checkQString && typeName == QLatin1String("QString")) {
- checkQString = true;
- qstringIndex = sortData.lastProcessedItemId();
- }
-
- const AbstractMetaTypeList &instantiations = ov->argType()->instantiations();
- for (const AbstractMetaType *instantiation : 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()))) {
- for (const QString &primitive : qAsConst(nonIntegerPrimitives))
- sortData.mapType(getImplicitConversionTypeName(ov->argType(), instantiation, nullptr, primitive));
- } else {
- const AbstractMetaFunctionList &funcs = m_generator->implicitConversions(instantiation);
- for (const AbstractMetaFunction *function : funcs)
- sortData.mapType(getImplicitConversionTypeName(ov->argType(), instantiation, function));
- }
- }
- }
-
-
- // Create the graph of type dependencies based on implicit conversions.
- Graph graph(sortData.reverseMap.count());
- // All C++ primitive types, add any forgotten type AT THE END OF THIS LIST!
- const char *primitiveTypes[] = {"int",
- "unsigned int",
- "long",
- "unsigned long",
- "short",
- "unsigned short",
- "bool",
- "unsigned char",
- "char",
- "float",
- "double",
- "const char*"
- };
- const int numPrimitives = sizeof(primitiveTypes)/sizeof(const char *);
- bool hasPrimitive[numPrimitives];
- for (int i = 0; i < numPrimitives; ++i)
- hasPrimitive[i] = sortData.map.contains(QLatin1String(primitiveTypes[i]));
-
- if (checkPySequence && checkPyObject)
- graph.addEdge(pySeqIndex, pyobjectIndex);
-
- QStringList classesWithIntegerImplicitConversion;
-
- MetaFunctionList involvedConversions;
-
- for (OverloadData *ov : qAsConst(m_nextOverloadData)) {
- const AbstractMetaType *targetType = ov->argType();
- const QString targetTypeEntryName(getTypeName(ov));
- int targetTypeId = sortData.map[targetTypeEntryName];
-
- // Process implicit conversions
- const AbstractMetaFunctionList &functions = m_generator->implicitConversions(targetType);
- for (AbstractMetaFunction *function : functions) {
- QString convertibleType;
- if (function->isConversionOperator())
- convertibleType = function->ownerClass()->typeEntry()->name();
- else
- convertibleType = getTypeName(function->arguments().constFirst()->type());
-
- if (convertibleType == QLatin1String("int") || convertibleType == QLatin1String("unsigned int"))
- classesWithIntegerImplicitConversion << targetTypeEntryName;
-
- if (!sortData.map.contains(convertibleType))
- continue;
-
- int convertibleTypeId = sortData.map[convertibleType];
-
- // If a reverse pair already exists, remove it. Probably due to the
- // container check (This happened to QVariant and QHash)
- graph.removeEdge(targetTypeId, convertibleTypeId);
- graph.addEdge(convertibleTypeId, targetTypeId);
- involvedConversions.append(function);
- }
-
- // Process inheritance relationships
- if (targetType->isValue() || targetType->isObject()) {
- const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_generator->classes(), targetType->typeEntry());
- const AbstractMetaClassList &ancestors = m_generator->getAllAncestors(metaClass);
- for (const AbstractMetaClass *ancestor : ancestors) {
- 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
- const AbstractMetaTypeList &instantiations = targetType->instantiations();
- for (const AbstractMetaType *instantiation : 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()))) {
- for (const QString &primitive : qAsConst(nonIntegerPrimitives)) {
- QString convertibleTypeName = getImplicitConversionTypeName(ov->argType(), instantiation, nullptr, primitive);
- if (!graph.containsEdge(targetTypeId, sortData.map[convertibleTypeName])) // Avoid cyclic dependency.
- graph.addEdge(sortData.map[convertibleTypeName], targetTypeId);
- }
-
- } else {
- const AbstractMetaFunctionList &funcs = m_generator->implicitConversions(instantiation);
- for (const AbstractMetaFunction *function : funcs) {
- QString convertibleTypeName = getImplicitConversionTypeName(ov->argType(), instantiation, function);
- if (!graph.containsEdge(targetTypeId, sortData.map[convertibleTypeName])) { // Avoid cyclic dependency.
- graph.addEdge(sortData.map[convertibleTypeName], targetTypeId);
- involvedConversions.append(function);
- }
- }
- }
- }
- }
-
-
- if ((checkPySequence || checkPyObject || checkPyBuffer)
- && !targetTypeEntryName.contains(QLatin1String("PyObject"))
- && !targetTypeEntryName.contains(QLatin1String("PyBuffer"))
- && !targetTypeEntryName.contains(QLatin1String("PySequence"))) {
- if (checkPySequence) {
- // PySequence will be checked after all more specific types, but before PyObject.
- graph.addEdge(targetTypeId, pySeqIndex);
- } else if (checkPyBuffer) {
- // PySequence will be checked after all more specific types, but before PyObject.
- graph.addEdge(targetTypeId, pyBufferIndex);
- } else {
- // Add dependency on PyObject, so its check is the last one (too generic).
- graph.addEdge(targetTypeId, pyobjectIndex);
- }
- } else if (checkQVariant && targetTypeEntryName != QLatin1String("QVariant")) {
- if (!graph.containsEdge(qvariantIndex, targetTypeId)) // Avoid cyclic dependency.
- graph.addEdge(targetTypeId, qvariantIndex);
- } else if (checkQString && ShibokenGenerator::isPointer(ov->argType())
- && targetTypeEntryName != QLatin1String("QString")
- && targetTypeEntryName != QLatin1String("QByteArray")
- && (!checkPyObject || targetTypeId != pyobjectIndex)) {
- if (!graph.containsEdge(qstringIndex, targetTypeId)) // Avoid cyclic dependency.
- graph.addEdge(targetTypeId, qstringIndex);
- }
-
- if (targetType->isEnum()) {
- // Enum values must precede primitive types.
- for (int i = 0; i < numPrimitives; ++i) {
- if (hasPrimitive[i])
- graph.addEdge(targetTypeId, sortData.map[QLatin1String(primitiveTypes[i])]);
- }
- }
- }
-
- // QByteArray args need to be checked after QString args
- if (sortData.map.contains(QLatin1String("QString")) && sortData.map.contains(QLatin1String("QByteArray")))
- graph.addEdge(sortData.map[QLatin1String("QString")], sortData.map[QLatin1String("QByteArray")]);
-
- for (OverloadData *ov : qAsConst(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".
- for (const QString &implicitFromInt : qAsConst(classesWithIntegerImplicitConversion))
- graph.addEdge(sortData.map[targetTypeEntryName], sortData.map[implicitFromInt]);
- }
-
-
- // Special case for double(int i) (not tracked by m_generator->implicitConversions
- for (const QString &signedIntegerName : qAsConst(signedIntegerPrimitives)) {
- if (sortData.map.contains(signedIntegerName)) {
- for (const QString &nonIntegerName : qAsConst(nonIntegerPrimitives)) {
- if (sortData.map.contains(nonIntegerName))
- graph.addEdge(sortData.map[nonIntegerName], sortData.map[signedIntegerName]);
- }
- }
- }
-
- // sort the overloads topologically based on the dependency graph.
- const auto unmappedResult = graph.topologicalSort();
- if (unmappedResult.isEmpty()) {
- QString funcName = referenceFunction()->name();
- if (referenceFunction()->ownerClass())
- funcName.prepend(referenceFunction()->ownerClass()->name() + QLatin1Char('.'));
-
- // Dump overload graph
- QString graphName = QDir::tempPath() + QLatin1Char('/') + funcName + QLatin1String(".dot");
- QHash<int, QString> nodeNames;
- for (auto it = sortData.map.cbegin(), end = sortData.map.cend(); it != end; ++it)
- nodeNames.insert(it.value(), it.key());
- graph.dumpDot(nodeNames, graphName);
- qCWarning(lcShiboken).noquote() << qPrintable(msgCyclicDependency(funcName, graphName, involvedConversions));
- }
-
- m_nextOverloadData.clear();
- for (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(nullptr),
- m_headOverloadData(this), m_previousOverloadData(nullptr), m_generator(generator)
-{
- for (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;
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (const AbstractMetaArgument *arg : 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(nullptr),
- m_generator(nullptr)
-{
- 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 (func->arguments().at(i)->hasDefaultValueExpression()) {
- 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 = nullptr;
- if (!func->isOperatorOverload()) {
- for (OverloadData *tmp : qAsConst(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;
- for (const AbstractMetaFunction *func : m_overloads) {
- if (!func->typeReplaced(0).isEmpty())
- retTypes << func->typeReplaced(0);
- else if (func->type() && !func->argumentRemoved(0))
- retTypes << func->type()->cppSignature();
- else
- retTypes << QLatin1String("void");
- }
- return retTypes.values();
-}
-
-bool OverloadData::hasNonVoidReturnType() const
-{
- QStringList retTypes = returnTypes();
- return !retTypes.contains(QLatin1String("void")) || retTypes.size() > 1;
-}
-
-bool OverloadData::hasVarargs() const
-{
- for (const AbstractMetaFunction *func : m_overloads) {
- AbstractMetaArgumentList args = func->arguments();
- if (args.size() > 1 && args.constLast()->type()->isVarargs())
- return true;
- }
- return false;
-}
-
-bool OverloadData::hasAllowThread() const
-{
- for (const AbstractMetaFunction *func : m_overloads) {
- if (func->allowThread())
- return true;
- }
- return false;
-}
-
-bool OverloadData::hasStaticFunction(const AbstractMetaFunctionList &overloads)
-{
- for (const AbstractMetaFunction *func : qAsConst(overloads)) {
- if (func->isStatic())
- return true;
- }
- return false;
-}
-
-bool OverloadData::hasStaticFunction() const
-{
- for (const AbstractMetaFunction *func : m_overloads) {
- if (func->isStatic())
- return true;
- }
- return false;
-}
-
-bool OverloadData::hasInstanceFunction(const AbstractMetaFunctionList &overloads)
-{
- for (const AbstractMetaFunction *func : qAsConst(overloads)) {
- if (!func->isStatic())
- return true;
- }
- return false;
-}
-
-bool OverloadData::hasInstanceFunction() const
-{
- for (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.constFirst();
-}
-
-const AbstractMetaArgument *OverloadData::argument(const AbstractMetaFunction *func) const
-{
- if (isHeadOverloadData() || !m_overloads.contains(func))
- return nullptr;
-
- 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().at(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) {
- const OverloadDataList &data = overloadData->nextOverloadData();
- for (OverloadData *pd : data)
- 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
-{
- for (OverloadData *overloadData : m_nextOverloadData) {
- if (overloadData->getFunctionWithDefaultValue())
- return true;
- }
- return false;
-}
-
-static OverloadData *_findNextArgWithDefault(OverloadData *overloadData)
-{
- if (overloadData->getFunctionWithDefaultValue())
- return overloadData;
-
- OverloadData *result = nullptr;
- const OverloadDataList &data = overloadData->nextOverloadData();
- for (OverloadData *odata : data) {
- 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
-{
- for (const OverloadData *pd : m_nextOverloadData) {
- if (pd->overloads().contains(func))
- return false;
- }
- return true;
-}
-
-OverloadData::MetaFunctionList OverloadData::overloadsWithoutRepetition() const
-{
- MetaFunctionList overloads = m_overloads;
- for (const AbstractMetaFunction *func : m_overloads) {
- if (func->minimalSignature().endsWith(QLatin1String("const")))
- continue;
- for (const AbstractMetaFunction *f : qAsConst(overloads)) {
- if ((func->minimalSignature() + QLatin1String("const")) == f->minimalSignature()) {
- overloads.removeOne(f);
- break;
- }
- }
- }
- return overloads;
-}
-
-const AbstractMetaFunction *OverloadData::getFunctionWithDefaultValue() const
-{
- for (const AbstractMetaFunction *func : m_overloads) {
- int removedArgs = 0;
- for (int i = 0; i <= m_argPos + removedArgs; i++) {
- if (func->argumentRemoved(i + 1))
- removedArgs++;
- }
- if (func->arguments().at(m_argPos + removedArgs)->hasDefaultValueExpression())
- return func;
- }
- return nullptr;
-}
-
-QVector<int> OverloadData::invalidArgumentLengths() const
-{
- QSet<int> validArgLengths;
-
- for (const AbstractMetaFunction *func : qAsConst(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 (args.at(i)->hasDefaultValueExpression())
- validArgLengths << i-offset;
- }
- }
- validArgLengths << args.size() - offset;
- }
-
- QVector<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 (const AbstractMetaFunction *func : overloads) {
- 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 && func->arguments().at(j)->hasDefaultValueExpression())
- minArgs = fixedArgIndex;
- }
- }
- return {minArgs, maxArgs};
-}
-
-bool OverloadData::isSingleArgument(const AbstractMetaFunctionList &overloads)
-{
- bool singleArgument = true;
- for (const AbstractMetaFunction *func : overloads) {
- if (func->arguments().size() - numberOfRemovedArguments(func) != 1) {
- singleArgument = false;
- break;
- }
- }
- return singleArgument;
-}
-
-void OverloadData::dumpGraph(const QString &filename) const
-{
- QFile file(filename);
- if (file.open(QFile::WriteOnly)) {
- QTextStream s(&file);
- s << m_headOverloadData->dumpGraph();
- }
-}
-
-static inline QString toHtml(QString s)
-{
- s.replace(QLatin1Char('<'), QLatin1String("&lt;"));
- s.replace(QLatin1Char('>'), QLatin1String("&gt;"));
- s.replace(QLatin1Char('&'), QLatin1String("&amp;"));
- return s;
-}
-
-QString OverloadData::dumpGraph() const
-{
- Indentor INDENT;
- Indentation indent(INDENT);
- QString result;
- QTextStream s(&result);
- if (m_argPos == -1) {
- const AbstractMetaFunction *rfunc = referenceFunction();
- s << "digraph OverloadedFunction {\n";
- s << INDENT << "graph [fontsize=12 fontname=freemono labelloc=t splines=true overlap=false rankdir=LR];\n";
-
- // Shows all function signatures
- s << "legend [fontsize=9 fontname=freemono shape=rect label=\"";
- for (const AbstractMetaFunction *func : m_overloads) {
- s << "f" << functionNumber(func) << " : ";
- if (func->type())
- s << toHtml(func->type()->cppSignature());
- else
- s << "void";
- s << ' ' << toHtml(func->minimalSignature()) << "\\l";
- }
- s << "\"];\n";
-
- // Function box title
- s << INDENT << '"' << rfunc->name() << "\" [shape=plaintext style=\"filled,bold\" margin=0 fontname=freemono fillcolor=white penwidth=1 ";
- s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">";
- s << "<tr><td bgcolor=\"black\" align=\"center\" cellpadding=\"6\" colspan=\"2\"><font color=\"white\">";
- if (rfunc->ownerClass())
- s << rfunc->ownerClass()->name() << "::";
- s << toHtml(rfunc->name()) << "</font>";
- if (rfunc->isVirtual()) {
- s << "<br/><font color=\"white\" point-size=\"10\">&lt;&lt;";
- if (rfunc->isAbstract())
- s << "pure ";
- s << "virtual&gt;&gt;</font>";
- }
- s << "</td></tr>";
-
- // Function return type
- s << "<tr><td bgcolor=\"gray\" align=\"right\">original type</td><td bgcolor=\"gray\" align=\"left\">";
- if (rfunc->type())
- s << toHtml(rfunc->type()->cppSignature());
- else
- s << "void";
- s << "</td></tr>";
-
- // Shows type changes for all function signatures
- for (const AbstractMetaFunction *func : m_overloads) {
- if (func->typeReplaced(0).isEmpty())
- continue;
- s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func);
- s << "-type</td><td bgcolor=\"gray\" align=\"left\">";
- s << toHtml(func->typeReplaced(0)) << "</td></tr>";
- }
-
- // Minimum and maximum number of arguments
- s << "<tr><td bgcolor=\"gray\" align=\"right\">minArgs</td><td bgcolor=\"gray\" align=\"left\">";
- s << minArgs() << "</td></tr>";
- s << "<tr><td bgcolor=\"gray\" align=\"right\">maxArgs</td><td bgcolor=\"gray\" align=\"left\">";
- s << maxArgs() << "</td></tr>";
-
- if (rfunc->ownerClass()) {
- if (rfunc->implementingClass() != rfunc->ownerClass())
- s << "<tr><td align=\"right\">implementor</td><td align=\"left\">" << rfunc->implementingClass()->name() << "</td></tr>";
- if (rfunc->declaringClass() != rfunc->ownerClass() && rfunc->declaringClass() != rfunc->implementingClass())
- s << "<tr><td align=\"right\">declarator</td><td align=\"left\">" << rfunc->declaringClass()->name() << "</td></tr>";
- }
-
- // Overloads for the signature to present point
- s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">";
- for (const AbstractMetaFunction *func : m_overloads)
- s << 'f' << functionNumber(func) << ' ';
- s << "</td></tr>";
-
- s << "</table>> ];\n";
-
- for (const OverloadData *pd : m_nextOverloadData)
- s << INDENT << '"' << rfunc->name() << "\" -> " << pd->dumpGraph();
-
- s << "}\n";
- } else {
- QString argId = QLatin1String("arg_") + QString::number(quintptr(this));
- s << argId << ";\n";
-
- s << INDENT << '"' << argId << "\" [shape=\"plaintext\" style=\"filled,bold\" margin=\"0\" fontname=\"freemono\" fillcolor=\"white\" penwidth=1 ";
- s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">";
-
- // Argument box title
- s << "<tr><td bgcolor=\"black\" align=\"left\" cellpadding=\"2\" colspan=\"2\">";
- s << "<font color=\"white\" point-size=\"11\">arg #" << argPos() << "</font></td></tr>";
-
- // Argument type information
- QString type = hasArgumentTypeReplace() ? argumentTypeReplaced() : argType()->cppSignature();
- s << "<tr><td bgcolor=\"gray\" align=\"right\">type</td><td bgcolor=\"gray\" align=\"left\">";
- s << toHtml(type) << "</td></tr>";
- if (hasArgumentTypeReplace()) {
- s << "<tr><td bgcolor=\"gray\" align=\"right\">orig. type</td><td bgcolor=\"gray\" align=\"left\">";
- s << toHtml(argType()->cppSignature()) << "</td></tr>";
- }
-
- // Overloads for the signature to present point
- s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">";
- for (const AbstractMetaFunction *func : m_overloads)
- s << 'f' << functionNumber(func) << ' ';
- s << "</td></tr>";
-
- // Show default values (original and modified) for various functions
- for (const AbstractMetaFunction *func : m_overloads) {
- const AbstractMetaArgument *arg = argument(func);
- if (!arg)
- continue;
- QString argDefault = arg->defaultValueExpression();
- 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>>];\n";
-
- for (const OverloadData *pd : m_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;
- for (const AbstractMetaFunction *func : overloads) {
- if (hasArgumentWithDefaultValue(func))
- return true;
- }
- return false;
-}
-
-bool OverloadData::hasArgumentWithDefaultValue() const
-{
- if (maxArgs() == 0)
- return false;
- for (const AbstractMetaFunction *func : m_overloads) {
- if (hasArgumentWithDefaultValue(func))
- return true;
- }
- return false;
-}
-
-bool OverloadData::hasArgumentWithDefaultValue(const AbstractMetaFunction *func)
-{
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (const AbstractMetaArgument *arg : arguments) {
- if (func->argumentRemoved(arg->argumentIndex() + 1))
- continue;
- if (arg->hasDefaultValueExpression())
- return true;
- }
- return false;
-}
-
-AbstractMetaArgumentList OverloadData::getArgumentsWithDefaultValues(const AbstractMetaFunction *func)
-{
- AbstractMetaArgumentList args;
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (AbstractMetaArgument *arg : arguments) {
- if (!arg->hasDefaultValueExpression()
- || func->argumentRemoved(arg->argumentIndex() + 1))
- continue;
- args << arg;
- }
- return args;
-}
-
-#ifndef QT_NO_DEBUG_STREAM
-void OverloadData::formatDebug(QDebug &d) const
-{
- const int count = m_overloads.size();
- d << "argType=" << m_argType << ", minArgs=" << m_minArgs << ", maxArgs=" << m_maxArgs
- << ", argPos=" << m_argPos << ", argTypeReplaced=\"" << m_argTypeReplaced
- << "\", overloads[" << count << "]=(";
- const int oldVerbosity = d.verbosity();
- d.setVerbosity(3);
- for (int i = 0; i < count; ++i) {
- if (i)
- d << '\n';
- d << m_overloads.at(i);
- }
- d << ')';
- d.setVerbosity(oldVerbosity);
-}
-
-QDebug operator<<(QDebug d, const OverloadData *od)
-{
- QDebugStateSaver saver(d);
- d.noquote();
- d.nospace();
- d << "OverloadData(";
- if (od)
- od->formatDebug(d);
- else
- d << '0';
- d << ')';
- return d;
-}
-#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.h b/sources/shiboken2/generator/shiboken2/overloaddata.h
deleted file mode 100644
index 4fd4199e5..000000000
--- a/sources/shiboken2/generator/shiboken2/overloaddata.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef OVERLOADDATA_H
-#define OVERLOADDATA_H
-
-#include <abstractmetalang_typedefs.h>
-#include <QtCore/QBitArray>
-#include <QtCore/QVector>
-
-QT_FORWARD_DECLARE_CLASS(QDebug)
-
-class ShibokenGenerator;
-
-class OverloadData;
-using OverloadDataList = QVector<OverloadData *>;
-
-class OverloadData
-{
-public:
- using MetaFunctionList = QVector<const AbstractMetaFunction *>;
-
- 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).
- MetaFunctionList overloadsWithoutRepetition() const;
- const MetaFunctionList &overloads() const { return m_overloads; }
- OverloadDataList nextOverloadData() const { return m_nextOverloadData; }
- OverloadData *previousOverloadData() const { return m_previousOverloadData; }
-
- QVector<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(const QString &filename) const;
- QString dumpGraph() const;
-
- bool hasArgumentTypeReplace() const;
- QString argumentTypeReplaced() const;
-
- bool hasArgumentWithDefaultValue() const;
- static bool hasArgumentWithDefaultValue(const AbstractMetaFunctionList &overloads);
- static bool hasArgumentWithDefaultValue(const AbstractMetaFunction *func);
-
- /// Returns a list of function arguments which have default values and were not removed.
- static AbstractMetaArgumentList getArgumentsWithDefaultValues(const AbstractMetaFunction *func);
-
-#ifndef QT_NO_DEBUG_STREAM
- void formatDebug(QDebug &) const;
-#endif
-
-private:
- OverloadData(OverloadData *headOverloadData, const AbstractMetaFunction *func,
- const AbstractMetaType *argType, int argPos);
-
- void addOverload(const AbstractMetaFunction *func);
- OverloadData *addOverloadData(const AbstractMetaFunction *func, const AbstractMetaArgument *arg);
-
- void sortNextOverloads();
-
- int functionNumber(const AbstractMetaFunction *func) const;
- OverloadDataList overloadDataOnPosition(OverloadData *overloadData, int argPos) const;
-
- int m_minArgs;
- int m_maxArgs;
- int m_argPos;
- const AbstractMetaType *m_argType;
- QString m_argTypeReplaced;
- MetaFunctionList m_overloads;
-
- OverloadData *m_headOverloadData;
- OverloadDataList m_nextOverloadData;
- OverloadData *m_previousOverloadData;
- const ShibokenGenerator *m_generator;
-};
-
-#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug, const OverloadData *);
-#endif
-
-#endif // OVERLOADDATA_H
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
deleted file mode 100644
index 35bd363b5..000000000
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
+++ /dev/null
@@ -1,2756 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "shibokengenerator.h"
-#include <abstractmetalang.h>
-#include <messages.h>
-#include "overloaddata.h"
-#include <reporthandler.h>
-#include <typedatabase.h>
-#include <abstractmetabuilder.h>
-#include <iostream>
-
-#include <QtCore/QDir>
-#include <QtCore/QDebug>
-#include <QtCore/QRegularExpression>
-#include <limits>
-#include <memory>
-
-static const char AVOID_PROTECTED_HACK[] = "avoid-protected-hack";
-static const char PARENT_CTOR_HEURISTIC[] = "enable-parent-ctor-heuristic";
-static const char RETURN_VALUE_HEURISTIC[] = "enable-return-value-heuristic";
-static const char ENABLE_PYSIDE_EXTENSIONS[] = "enable-pyside-extensions";
-static const char DISABLE_VERBOSE_ERROR_MESSAGES[] = "disable-verbose-error-messages";
-static const char USE_ISNULL_AS_NB_NONZERO[] = "use-isnull-as-nb_nonzero";
-
-const char *CPP_ARG = "cppArg";
-const char *CPP_ARG_REMOVED = "removed_cppArg";
-const char *CPP_RETURN_VAR = "cppResult";
-const char *CPP_SELF_VAR = "cppSelf";
-const char *NULL_PTR = "nullptr";
-const char *PYTHON_ARG = "pyArg";
-const char *PYTHON_ARGS = "pyArgs";
-const char *PYTHON_OVERRIDE_VAR = "pyOverride";
-const char *PYTHON_RETURN_VAR = "pyResult";
-const char *PYTHON_TO_CPP_VAR = "pythonToCpp";
-const char *SMART_POINTER_GETTER = "kSmartPointerGetter";
-
-const char *CONV_RULE_OUT_VAR_SUFFIX = "_out";
-const char *BEGIN_ALLOW_THREADS =
- "PyThreadState *_save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS";
-const char *END_ALLOW_THREADS = "PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS";
-
-//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 QRegularExpression placeHolderRegex(int index)
-{
- return QRegularExpression(QLatin1Char('%') + QString::number(index) + QStringLiteral("\\b"));
-}
-
-// Return a prefix to fully qualify value, eg:
-// resolveScopePrefix("Class::NestedClass::Enum::Value1", "Enum::Value1")
-// -> "Class::NestedClass::")
-static QString resolveScopePrefix(const QStringList &scopeList, const QString &value)
-{
- QString name;
- for (int i = scopeList.size() - 1 ; i >= 0; --i) {
- const QString prefix = scopeList.at(i) + QLatin1String("::");
- if (value.startsWith(prefix))
- name.clear();
- else
- name.prepend(prefix);
- }
- return name;
-}
-
-static inline QStringList splitClassScope(const AbstractMetaClass *scope)
-{
- return scope->qualifiedCppName().split(QLatin1String("::"), QString::SkipEmptyParts);
-}
-
-static QString resolveScopePrefix(const AbstractMetaClass *scope, const QString &value)
-{
- return scope
- ? resolveScopePrefix(splitClassScope(scope), value)
- : QString();
-}
-
-static QString resolveScopePrefix(const AbstractMetaEnum *metaEnum,
- const QString &value)
-{
- QStringList parts;
- if (const AbstractMetaClass *scope = metaEnum->enclosingClass())
- parts.append(splitClassScope(scope));
- // Fully qualify the value which is required for C++ 11 enum classes.
- if (!metaEnum->isAnonymous())
- parts.append(metaEnum->name());
- return resolveScopePrefix(parts, value);
-}
-
-struct GeneratorClassInfoCacheEntry
-{
- ShibokenGenerator::FunctionGroups functionGroups;
- bool needsGetattroFunction = false;
-};
-
-using GeneratorClassInfoCache = QHash<const AbstractMetaClass *, GeneratorClassInfoCacheEntry>;
-
-Q_GLOBAL_STATIC(GeneratorClassInfoCache, generatorClassInfoCache)
-
-ShibokenGenerator::ShibokenGenerator()
-{
- if (m_pythonPrimitiveTypeName.isEmpty())
- ShibokenGenerator::initPrimitiveTypesCorrespondences();
-
- if (m_tpFuncs.isEmpty())
- ShibokenGenerator::clearTpFuncs();
-
- if (m_knownPythonTypes.isEmpty())
- ShibokenGenerator::initKnownPythonTypes();
-
- m_metaTypeFromStringCache = AbstractMetaTypeCache();
-
- m_typeSystemConvName[TypeSystemCheckFunction] = QLatin1String("checkType");
- m_typeSystemConvName[TypeSystemIsConvertibleFunction] = QLatin1String("isConvertible");
- m_typeSystemConvName[TypeSystemToCppFunction] = QLatin1String("toCpp");
- m_typeSystemConvName[TypeSystemToPythonFunction] = QLatin1String("toPython");
-
- const char CHECKTYPE_REGEX[] = R"(%CHECKTYPE\[([^\[]*)\]\()";
- const char ISCONVERTIBLE_REGEX[] = R"(%ISCONVERTIBLE\[([^\[]*)\]\()";
- const char CONVERTTOPYTHON_REGEX[] = R"(%CONVERTTOPYTHON\[([^\[]*)\]\()";
- // Capture a '*' leading the variable name into the target
- // so that "*valuePtr = %CONVERTTOCPP..." works as expected.
- const char CONVERTTOCPP_REGEX[] =
- R"((\*?%?[a-zA-Z_][\w\.]*(?:\[[^\[^<^>]+\])*)(?:\s+)=(?:\s+)%CONVERTTOCPP\[([^\[]*)\]\()";
- m_typeSystemConvRegEx[TypeSystemCheckFunction] = QRegularExpression(QLatin1String(CHECKTYPE_REGEX));
- m_typeSystemConvRegEx[TypeSystemIsConvertibleFunction] = QRegularExpression(QLatin1String(ISCONVERTIBLE_REGEX));
- m_typeSystemConvRegEx[TypeSystemToPythonFunction] = QRegularExpression(QLatin1String(CONVERTTOPYTHON_REGEX));
- m_typeSystemConvRegEx[TypeSystemToCppFunction] = QRegularExpression(QLatin1String(CONVERTTOCPP_REGEX));
-}
-
-ShibokenGenerator::~ShibokenGenerator() = default;
-
-void ShibokenGenerator::clearTpFuncs()
-{
- m_tpFuncs.insert(QLatin1String("__str__"), QString());
- m_tpFuncs.insert(QLatin1String("__repr__"), QString());
- m_tpFuncs.insert(QLatin1String("__iter__"), QString());
- m_tpFuncs.insert(QLatin1String("__next__"), QString());
-}
-
-void ShibokenGenerator::initPrimitiveTypesCorrespondences()
-{
- // Python primitive types names
- m_pythonPrimitiveTypeName.clear();
-
- // PyBool
- m_pythonPrimitiveTypeName.insert(QLatin1String("bool"), QLatin1String("PyBool"));
-
- const char *charTypes[] = {
- "char", "signed char", "unsigned char"
- };
- for (const char *charType : charTypes)
- m_pythonPrimitiveTypeName.insert(QLatin1String(charType), QStringLiteral("SbkChar"));
-
- // PyInt
- const char *intTypes[] = {
- "int", "signed int", "uint", "unsigned int",
- "short", "ushort", "signed short", "signed short int",
- "unsigned short", "unsigned short", "unsigned short int",
- "long"
- };
- for (const char *intType : intTypes)
- m_pythonPrimitiveTypeName.insert(QLatin1String(intType), QStringLiteral("PyInt"));
-
- // PyFloat
- m_pythonPrimitiveTypeName.insert(QLatin1String("double"), QLatin1String("PyFloat"));
- m_pythonPrimitiveTypeName.insert(QLatin1String("float"), QLatin1String("PyFloat"));
-
- // PyLong
- const char *longTypes[] = {
- "unsigned long", "signed long", "ulong", "unsigned long int",
- "long long", "__int64",
- "unsigned long long", "unsigned __int64", "size_t"
- };
- for (const char *longType : longTypes)
- m_pythonPrimitiveTypeName.insert(QLatin1String(longType), QStringLiteral("PyLong"));
-
- // Python operators
- m_pythonOperators.clear();
-
- // call operator
- m_pythonOperators.insert(QLatin1String("operator()"), QLatin1String("call"));
-
- // Arithmetic operators
- m_pythonOperators.insert(QLatin1String("operator+"), QLatin1String("add"));
- m_pythonOperators.insert(QLatin1String("operator-"), QLatin1String("sub"));
- m_pythonOperators.insert(QLatin1String("operator*"), QLatin1String("mul"));
- m_pythonOperators.insert(QLatin1String("operator/"), QLatin1String("div"));
- m_pythonOperators.insert(QLatin1String("operator%"), QLatin1String("mod"));
-
- // Inplace arithmetic operators
- m_pythonOperators.insert(QLatin1String("operator+="), QLatin1String("iadd"));
- m_pythonOperators.insert(QLatin1String("operator-="), QLatin1String("isub"));
- m_pythonOperators.insert(QLatin1String("operator++"), QLatin1String("iadd"));
- m_pythonOperators.insert(QLatin1String("operator--"), QLatin1String("isub"));
- m_pythonOperators.insert(QLatin1String("operator*="), QLatin1String("imul"));
- m_pythonOperators.insert(QLatin1String("operator/="), QLatin1String("idiv"));
- m_pythonOperators.insert(QLatin1String("operator%="), QLatin1String("imod"));
-
- // Bitwise operators
- m_pythonOperators.insert(QLatin1String("operator&"), QLatin1String("and"));
- m_pythonOperators.insert(QLatin1String("operator^"), QLatin1String("xor"));
- m_pythonOperators.insert(QLatin1String("operator|"), QLatin1String("or"));
- m_pythonOperators.insert(QLatin1String("operator<<"), QLatin1String("lshift"));
- m_pythonOperators.insert(QLatin1String("operator>>"), QLatin1String("rshift"));
- m_pythonOperators.insert(QLatin1String("operator~"), QLatin1String("invert"));
-
- // Inplace bitwise operators
- m_pythonOperators.insert(QLatin1String("operator&="), QLatin1String("iand"));
- m_pythonOperators.insert(QLatin1String("operator^="), QLatin1String("ixor"));
- m_pythonOperators.insert(QLatin1String("operator|="), QLatin1String("ior"));
- m_pythonOperators.insert(QLatin1String("operator<<="), QLatin1String("ilshift"));
- m_pythonOperators.insert(QLatin1String("operator>>="), QLatin1String("irshift"));
-
- // Comparison operators
- m_pythonOperators.insert(QLatin1String("operator=="), QLatin1String("eq"));
- m_pythonOperators.insert(QLatin1String("operator!="), QLatin1String("ne"));
- m_pythonOperators.insert(QLatin1String("operator<"), QLatin1String("lt"));
- m_pythonOperators.insert(QLatin1String("operator>"), QLatin1String("gt"));
- m_pythonOperators.insert(QLatin1String("operator<="), QLatin1String("le"));
- m_pythonOperators.insert(QLatin1String("operator>="), QLatin1String("ge"));
-
- // Initialize format units for C++->Python->C++ conversion
- m_formatUnits.clear();
- m_formatUnits.insert(QLatin1String("char"), QLatin1String("b"));
- m_formatUnits.insert(QLatin1String("unsigned char"), QLatin1String("B"));
- m_formatUnits.insert(QLatin1String("int"), QLatin1String("i"));
- m_formatUnits.insert(QLatin1String("unsigned int"), QLatin1String("I"));
- m_formatUnits.insert(QLatin1String("short"), QLatin1String("h"));
- m_formatUnits.insert(QLatin1String("unsigned short"), QLatin1String("H"));
- m_formatUnits.insert(QLatin1String("long"), QLatin1String("l"));
- m_formatUnits.insert(QLatin1String("unsigned long"), QLatin1String("k"));
- m_formatUnits.insert(QLatin1String("long long"), QLatin1String("L"));
- m_formatUnits.insert(QLatin1String("__int64"), QLatin1String("L"));
- m_formatUnits.insert(QLatin1String("unsigned long long"), QLatin1String("K"));
- m_formatUnits.insert(QLatin1String("unsigned __int64"), QLatin1String("K"));
- m_formatUnits.insert(QLatin1String("double"), QLatin1String("d"));
- m_formatUnits.insert(QLatin1String("float"), QLatin1String("f"));
-}
-
-void ShibokenGenerator::initKnownPythonTypes()
-{
- m_knownPythonTypes.clear();
- m_knownPythonTypes << QLatin1String("PyBool") << QLatin1String("PyInt")
- << QLatin1String("PyFloat") << QLatin1String("PyLong") << QLatin1String("PyObject")
- << QLatin1String("PyString") << QLatin1String("PyBuffer") << QLatin1String("PySequence")
- << QLatin1String("PyTuple") << QLatin1String("PyList") << QLatin1String("PyDict")
- << QLatin1String("PyObject*") << QLatin1String("PyObject *") << QLatin1String("PyTupleObject*");
-}
-
-QString ShibokenGenerator::translateTypeForWrapperMethod(const AbstractMetaType *cType,
- const AbstractMetaClass *context,
- Options options) const
-{
- if (cType->isArray())
- return translateTypeForWrapperMethod(cType->arrayElementType(), context, options) + QLatin1String("[]");
-
- if (avoidProtectedHack() && cType->isEnum()) {
- const AbstractMetaEnum *metaEnum = findAbstractMetaEnum(cType);
- if (metaEnum && metaEnum->isProtected())
- return protectedEnumSurrogateName(metaEnum);
- }
-
- return translateType(cType, context, options);
-}
-
-bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass *metaClass) const
-{
- if (metaClass->isNamespace() || (metaClass->attributes() & AbstractMetaAttributes::FinalCppClass))
- return false;
- bool result = metaClass->isPolymorphic() || metaClass->hasVirtualDestructor();
- if (avoidProtectedHack()) {
- result = result || metaClass->hasProtectedFields() || metaClass->hasProtectedDestructor();
- if (!result && metaClass->hasProtectedFunctions()) {
- int protectedFunctions = 0;
- int protectedOperators = 0;
- const AbstractMetaFunctionList &funcs = metaClass->functions();
- for (const AbstractMetaFunction *func : funcs) {
- if (!func->isProtected() || func->isSignal() || func->isModifiedRemoved())
- continue;
- if (func->isOperatorOverload())
- protectedOperators++;
- else
- protectedFunctions++;
- }
- result = result || (protectedFunctions > protectedOperators);
- }
- } else {
- result = result && !metaClass->hasPrivateDestructor();
- }
- return result;
-}
-
-void ShibokenGenerator::lookForEnumsInClassesNotToBeGenerated(AbstractMetaEnumList &enumList, const AbstractMetaClass *metaClass)
-{
- Q_ASSERT(metaClass);
- // if a scope is not to be generated, collect its enums into the parent scope
- if (!NamespaceTypeEntry::isVisibleScope(metaClass->typeEntry())) {
- const AbstractMetaEnumList &enums = metaClass->enums();
- for (AbstractMetaEnum *metaEnum : enums) {
- if (!metaEnum->isPrivate() && metaEnum->typeEntry()->generateCode()
- && !enumList.contains(metaEnum)) {
- enumList.append(metaEnum);
- }
- }
- }
-}
-
-QString ShibokenGenerator::wrapperName(const AbstractMetaClass *metaClass) const
-{
- if (shouldGenerateCppWrapper(metaClass)) {
- QString result = metaClass->name();
- if (metaClass->enclosingClass()) // is a inner class
- result.replace(QLatin1String("::"), QLatin1String("_"));
-
- result += QLatin1String("Wrapper");
- return result;
- }
- return metaClass->qualifiedCppName();
-}
-
-QString ShibokenGenerator::wrapperName(const AbstractMetaType *metaType) const
-{
- return metaType->cppSignature();
-}
-
-QString ShibokenGenerator::fullPythonClassName(const AbstractMetaClass *metaClass)
-{
- QString fullClassName = metaClass->name();
- const AbstractMetaClass *enclosing = metaClass->enclosingClass();
- while (enclosing) {
- if (NamespaceTypeEntry::isVisibleScope(enclosing->typeEntry()))
- fullClassName.prepend(enclosing->name() + QLatin1Char('.'));
- enclosing = enclosing->enclosingClass();
- }
- fullClassName.prepend(packageName() + QLatin1Char('.'));
- return fullClassName;
-}
-
-QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction *func)
-{
- QString funcName;
- if (func->isOperatorOverload())
- funcName = ShibokenGenerator::pythonOperatorFunctionName(func);
- else
- funcName = func->name();
- if (func->ownerClass()) {
- QString fullClassName = fullPythonClassName(func->ownerClass());
- if (func->isConstructor())
- funcName = fullClassName;
- else
- funcName.prepend(fullClassName + QLatin1Char('.'));
- }
- else {
- funcName = packageName() + QLatin1Char('.') + func->name();
- }
- return funcName;
-}
-
-QString ShibokenGenerator::protectedEnumSurrogateName(const AbstractMetaEnum *metaEnum)
-{
- return metaEnum->fullName().replace(QLatin1Char('.'), QLatin1Char('_')).replace(QLatin1String("::"), QLatin1String("_")) + QLatin1String("_Surrogate");
-}
-
-QString ShibokenGenerator::protectedFieldGetterName(const AbstractMetaField *field)
-{
- return QStringLiteral("protected_%1_getter").arg(field->name());
-}
-
-QString ShibokenGenerator::protectedFieldSetterName(const AbstractMetaField *field)
-{
- return QStringLiteral("protected_%1_setter").arg(field->name());
-}
-
-QString ShibokenGenerator::cpythonFunctionName(const AbstractMetaFunction *func)
-{
- QString result;
-
- // PYSIDE-331: For inherited functions, we need to find the same labels.
- // Therefore we use the implementing class.
- if (func->implementingClass()) {
- result = cpythonBaseName(func->implementingClass()->typeEntry());
- if (func->isConstructor()) {
- result += QLatin1String("_Init");
- } else {
- result += QLatin1String("Func_");
- if (func->isOperatorOverload())
- result += ShibokenGenerator::pythonOperatorFunctionName(func);
- else
- result += func->name();
- }
- } else {
- result = QLatin1String("Sbk") + moduleName() + QLatin1String("Module_") + func->name();
- }
-
- return result;
-}
-
-QString ShibokenGenerator::cpythonMethodDefinitionName(const AbstractMetaFunction *func)
-{
- if (!func->ownerClass())
- return QString();
- return QStringLiteral("%1Method_%2").arg(cpythonBaseName(func->ownerClass()->typeEntry()), func->name());
-}
-
-QString ShibokenGenerator::cpythonGettersSettersDefinitionName(const AbstractMetaClass *metaClass)
-{
- return cpythonBaseName(metaClass) + QLatin1String("_getsetlist");
-}
-
-QString ShibokenGenerator::cpythonSetattroFunctionName(const AbstractMetaClass *metaClass)
-{
- return cpythonBaseName(metaClass) + QLatin1String("_setattro");
-}
-
-
-QString ShibokenGenerator::cpythonGetattroFunctionName(const AbstractMetaClass *metaClass)
-{
- return cpythonBaseName(metaClass) + QLatin1String("_getattro");
-}
-
-QString ShibokenGenerator::cpythonGetterFunctionName(const AbstractMetaField *metaField)
-{
- return QStringLiteral("%1_get_%2").arg(cpythonBaseName(metaField->enclosingClass()), metaField->name());
-}
-
-QString ShibokenGenerator::cpythonSetterFunctionName(const AbstractMetaField *metaField)
-{
- return QStringLiteral("%1_set_%2").arg(cpythonBaseName(metaField->enclosingClass()), metaField->name());
-}
-
-static QString cpythonEnumFlagsName(const QString &moduleName,
- const QString &qualifiedCppName)
-{
- QString result = QStringLiteral("Sbk%1_%2").arg(moduleName, qualifiedCppName);
- result.replace(QLatin1String("::"), QLatin1String("_"));
- return result;
-}
-
-// Return the scope for fully qualifying the enumeration including trailing "::".
-static QString searchForEnumScope(const AbstractMetaClass *metaClass, const QString &value)
-{
- if (!metaClass)
- return QString();
- const AbstractMetaEnumList &enums = metaClass->enums();
- for (const AbstractMetaEnum *metaEnum : enums) {
- if (metaEnum->findEnumValue(value))
- return resolveScopePrefix(metaEnum, value);
- }
- // PYSIDE-331: We need to also search the base classes.
- QString ret = searchForEnumScope(metaClass->enclosingClass(), value);
- if (ret.isEmpty())
- ret = searchForEnumScope(metaClass->baseClass(), value);
- return ret;
-}
-
-// Handle QFlags<> for guessScopeForDefaultValue()
-QString ShibokenGenerator::guessScopeForDefaultFlagsValue(const AbstractMetaFunction *func,
- const AbstractMetaArgument *arg,
- const QString &value) const
-{
- // Numeric values -> "Options(42)"
- static const QRegularExpression numberRegEx(QStringLiteral("^\\d+$")); // Numbers to flags
- Q_ASSERT(numberRegEx.isValid());
- if (numberRegEx.match(value).hasMatch()) {
- QString typeName = translateTypeForWrapperMethod(arg->type(), func->implementingClass());
- if (arg->type()->isConstant())
- typeName.remove(0, sizeof("const ") / sizeof(char) - 1);
- switch (arg->type()->referenceType()) {
- case NoReference:
- break;
- case LValueReference:
- typeName.chop(1);
- break;
- case RValueReference:
- typeName.chop(2);
- break;
- }
- return typeName + QLatin1Char('(') + value + QLatin1Char(')');
- }
-
- // "Options(Option1 | Option2)" -> "Options(Class::Enum::Option1 | Class::Enum::Option2)"
- static const QRegularExpression enumCombinationRegEx(QStringLiteral("^([A-Za-z_][\\w:]*)\\(([^,\\(\\)]*)\\)$")); // FlagName(EnumItem|EnumItem|...)
- Q_ASSERT(enumCombinationRegEx.isValid());
- const QRegularExpressionMatch match = enumCombinationRegEx.match(value);
- if (match.hasMatch()) {
- const QString expression = match.captured(2).trimmed();
- if (expression.isEmpty())
- return value;
- const QStringList enumItems = expression.split(QLatin1Char('|'));
- const QString scope = searchForEnumScope(func->implementingClass(),
- enumItems.constFirst().trimmed());
- if (scope.isEmpty())
- return value;
- QString result;
- QTextStream str(&result);
- str << match.captured(1) << '('; // Flag name
- for (int i = 0, size = enumItems.size(); i < size; ++i) {
- if (i)
- str << '|';
- str << scope << enumItems.at(i).trimmed();
- }
- str << ')';
- return result;
- }
- // A single flag "Option1" -> "Class::Enum::Option1"
- return searchForEnumScope(func->implementingClass(), value) + value;
-}
-
-/*
- * This function uses some heuristics to find out the scope for a given
- * argument default value since they must be fully qualified when used outside the class:
- * class A {
- * enum Enum { e1, e1 };
- * void foo(Enum e = e1);
- * }
- * should be qualified to:
- * A::Enum cppArg0 = A::Enum::e1;
- *
- * 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) const
-{
- QString value = arg->defaultValueExpression();
-
- if (value.isEmpty()
- || arg->hasModifiedDefaultValueExpression()
- || isPointer(arg->type())) {
- return value;
- }
-
- static const QRegularExpression enumValueRegEx(QStringLiteral("^([A-Za-z_]\\w*)?$"));
- Q_ASSERT(enumValueRegEx.isValid());
- // Do not qualify macros by class name, eg QSGGeometry(..., int t = GL_UNSIGNED_SHORT);
- static const QRegularExpression macroRegEx(QStringLiteral("^[A-Z_][A-Z0-9_]*$"));
- Q_ASSERT(macroRegEx.isValid());
- if (arg->type()->isPrimitive() && macroRegEx.match(value).hasMatch())
- return value;
-
- QString prefix;
- if (arg->type()->isEnum()) {
- if (const AbstractMetaEnum *metaEnum = findAbstractMetaEnum(arg->type()))
- prefix = resolveScopePrefix(metaEnum, value);
- } else if (arg->type()->isFlags()) {
- value = guessScopeForDefaultFlagsValue(func, arg, value);
- } else if (arg->type()->typeEntry()->isValue()) {
- const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes(), arg->type()->typeEntry());
- if (enumValueRegEx.match(value).hasMatch() && value != QLatin1String("NULL"))
- prefix = resolveScopePrefix(metaClass, value);
- } else if (arg->type()->isPrimitive() && arg->type()->name() == QLatin1String("int")) {
- if (enumValueRegEx.match(value).hasMatch() && func->implementingClass())
- prefix = resolveScopePrefix(func->implementingClass(), value);
- } else if(arg->type()->isPrimitive()) {
- static const QRegularExpression unknowArgumentRegEx(QStringLiteral("^(?:[A-Za-z_][\\w:]*\\()?([A-Za-z_]\\w*)(?:\\))?$")); // [PrimitiveType(] DESIREDNAME [)]
- Q_ASSERT(unknowArgumentRegEx.isValid());
- const QRegularExpressionMatch match = unknowArgumentRegEx.match(value);
- if (match.hasMatch() && func->implementingClass()) {
- const AbstractMetaFieldList &fields = func->implementingClass()->fields();
- for (const AbstractMetaField *field : fields) {
- if (match.captured(1).trimmed() == field->name()) {
- QString fieldName = field->name();
- if (field->isStatic()) {
- prefix = resolveScopePrefix(func->implementingClass(), value);
- fieldName.prepend(prefix);
- prefix.clear();
- } else {
- fieldName.prepend(QLatin1String(CPP_SELF_VAR) + QLatin1String("->"));
- }
- value.replace(match.captured(1), fieldName);
- break;
- }
- }
- }
- }
-
- if (!prefix.isEmpty())
- value.prepend(prefix);
- return value;
-}
-
-QString ShibokenGenerator::cpythonEnumName(const EnumTypeEntry *enumEntry)
-{
- QString p = enumEntry->targetLangPackage();
- p.replace(QLatin1Char('.'), QLatin1Char('_'));
- return cpythonEnumFlagsName(p, enumEntry->qualifiedCppName());
-}
-
-QString ShibokenGenerator::cpythonEnumName(const AbstractMetaEnum *metaEnum)
-{
- return cpythonEnumName(metaEnum->typeEntry());
-}
-
-QString ShibokenGenerator::cpythonFlagsName(const FlagsTypeEntry *flagsEntry)
-{
- QString p = flagsEntry->targetLangPackage();
- p.replace(QLatin1Char('.'), QLatin1Char('_'));
- return cpythonEnumFlagsName(p, flagsEntry->originalName());
-}
-
-QString ShibokenGenerator::cpythonFlagsName(const AbstractMetaEnum *metaEnum)
-{
- const FlagsTypeEntry *flags = metaEnum->typeEntry()->flags();
- if (!flags)
- return QString();
- return cpythonFlagsName(flags);
-}
-
-QString ShibokenGenerator::cpythonSpecialCastFunctionName(const AbstractMetaClass *metaClass)
-{
- return cpythonBaseName(metaClass->typeEntry()) + QLatin1String("SpecialCastFunction");
-}
-
-QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClass *metaClass,
- const QString &argName)
-{
- return cpythonWrapperCPtr(metaClass->typeEntry(), argName);
-}
-
-QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType *metaType,
- const QString &argName)
-{
- if (!ShibokenGenerator::isWrapperType(metaType->typeEntry()))
- return QString();
- return QLatin1String("reinterpret_cast< ::") + metaType->cppSignature()
- + QLatin1String(" *>(Shiboken::Conversions::cppPointer(") + cpythonTypeNameExt(metaType)
- + QLatin1String(", reinterpret_cast<SbkObject *>(") + argName + QLatin1String(")))");
-}
-
-QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntry *type,
- const QString &argName)
-{
- if (!ShibokenGenerator::isWrapperType(type))
- return QString();
- return QLatin1String("reinterpret_cast< ::") + type->qualifiedCppName()
- + QLatin1String(" *>(Shiboken::Conversions::cppPointer(") + cpythonTypeNameExt(type)
- + QLatin1String(", reinterpret_cast<SbkObject *>(") + argName + QLatin1String(")))");
-}
-
-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;
- const FunctionModificationList &mods = func->modifications();
- for (const FunctionModification &funcMod : mods) {
- for (const ArgumentModification &argMod : funcMod.argument_mods) {
- if (argMod.index == argIndex + 1 && argMod.noNullPointers)
- return true;
- }
- }
- return false;
-}
-
-QString ShibokenGenerator::getFormatUnitString(const AbstractMetaFunction *func, bool incRef) const
-{
- QString result;
- const char objType = (incRef ? 'O' : 'N');
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (const AbstractMetaArgument *arg : arguments) {
- if (func->argumentRemoved(arg->argumentIndex() + 1))
- continue;
-
- if (!func->typeReplaced(arg->argumentIndex() + 1).isEmpty()) {
- result += QLatin1Char(objType);
- } else if (arg->type()->isObject()
- || arg->type()->isValue()
- || arg->type()->isValuePointer()
- || arg->type()->isNativePointer()
- || arg->type()->isEnum()
- || arg->type()->isFlags()
- || arg->type()->isContainer()
- || arg->type()->isSmartPointer()
- || arg->type()->referenceType() == LValueReference) {
- result += QLatin1Char(objType);
- } else if (arg->type()->isPrimitive()) {
- const auto *ptype =
- static_cast<const PrimitiveTypeEntry *>(arg->type()->typeEntry());
- if (ptype->basicReferencedTypeEntry())
- ptype = ptype->basicReferencedTypeEntry();
- if (m_formatUnits.contains(ptype->name()))
- result += m_formatUnits[ptype->name()];
- else
- result += QLatin1Char(objType);
- } else if (isCString(arg->type())) {
- result += QLatin1Char('z');
- } else {
- qCWarning(lcShiboken).noquote().nospace()
- << "Method: " << func->ownerClass()->qualifiedCppName()
- << "::" << func->signature() << " => Arg:"
- << arg->name() << "index: " << arg->argumentIndex()
- << " - cannot be handled properly. Use an inject-code to fix it!";
- result += QLatin1Char('?');
- }
- }
- return result;
-}
-
-QString ShibokenGenerator::cpythonBaseName(const AbstractMetaType *type)
-{
- if (isCString(type))
- return QLatin1String("PyString");
- return cpythonBaseName(type->typeEntry());
-}
-
-QString ShibokenGenerator::cpythonBaseName(const AbstractMetaClass *metaClass)
-{
- return cpythonBaseName(metaClass->typeEntry());
-}
-
-QString ShibokenGenerator::cpythonBaseName(const TypeEntry *type)
-{
- QString baseName;
- if (ShibokenGenerator::isWrapperType(type) || type->isNamespace()) { // && type->referenceType() == NoReference) {
- baseName = QLatin1String("Sbk_") + type->name();
- } else if (type->isPrimitive()) {
- const auto *ptype = static_cast<const PrimitiveTypeEntry *>(type);
- while (ptype->basicReferencedTypeEntry())
- ptype = ptype->basicReferencedTypeEntry();
- if (ptype->targetLangApiName() == ptype->name())
- baseName = pythonPrimitiveTypeName(ptype->name());
- else
- baseName = ptype->targetLangApiName();
- } else if (type->isEnum()) {
- baseName = cpythonEnumName(static_cast<const EnumTypeEntry *>(type));
- } else if (type->isFlags()) {
- baseName = cpythonFlagsName(static_cast<const FlagsTypeEntry *>(type));
- } else if (type->isContainer()) {
- const auto *ctype = static_cast<const ContainerTypeEntry *>(type);
- switch (ctype->type()) {
- case ContainerTypeEntry::ListContainer:
- case ContainerTypeEntry::StringListContainer:
- case ContainerTypeEntry::LinkedListContainer:
- case ContainerTypeEntry::VectorContainer:
- case ContainerTypeEntry::StackContainer:
- case ContainerTypeEntry::QueueContainer:
- //baseName = "PyList";
- //break;
- case ContainerTypeEntry::PairContainer:
- //baseName = "PyTuple";
- baseName = QLatin1String("PySequence");
- break;
- case ContainerTypeEntry::SetContainer:
- baseName = QLatin1String("PySet");
- break;
- case ContainerTypeEntry::MapContainer:
- case ContainerTypeEntry::MultiMapContainer:
- case ContainerTypeEntry::HashContainer:
- case ContainerTypeEntry::MultiHashContainer:
- baseName = QLatin1String("PyDict");
- break;
- default:
- Q_ASSERT(false);
- }
- } else {
- baseName = QLatin1String("PyObject");
- }
- return baseName.replace(QLatin1String("::"), QLatin1String("_"));
-}
-
-QString ShibokenGenerator::cpythonTypeName(const AbstractMetaClass *metaClass)
-{
- return cpythonTypeName(metaClass->typeEntry());
-}
-
-QString ShibokenGenerator::cpythonTypeName(const TypeEntry *type)
-{
- return cpythonBaseName(type) + QLatin1String("_TypeF()");
-}
-
-QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntry *type)
-{
- return cppApiVariableName(type->targetLangPackage()) + QLatin1Char('[')
- + getTypeIndexVariableName(type) + QLatin1Char(']');
-}
-
-QString ShibokenGenerator::converterObject(const AbstractMetaType *type)
-{
- if (isCString(type))
- return QLatin1String("Shiboken::Conversions::PrimitiveTypeConverter<const char *>()");
- if (isVoidPointer(type))
- return QLatin1String("Shiboken::Conversions::PrimitiveTypeConverter<void *>()");
- const AbstractMetaTypeCList nestedArrayTypes = type->nestedArrayTypes();
- if (!nestedArrayTypes.isEmpty() && nestedArrayTypes.constLast()->isCppPrimitive()) {
- return QStringLiteral("Shiboken::Conversions::ArrayTypeConverter<")
- + nestedArrayTypes.constLast()->minimalSignature()
- + QLatin1String(">(") + QString::number(nestedArrayTypes.size())
- + QLatin1Char(')');
- }
- if (type->typeEntry()->isContainer()) {
- return convertersVariableName(type->typeEntry()->targetLangPackage())
- + QLatin1Char('[') + getTypeIndexVariableName(type) + QLatin1Char(']');
- }
- return converterObject(type->typeEntry());
-}
-
-QString ShibokenGenerator::converterObject(const TypeEntry *type)
-{
- if (isCppPrimitive(type))
- return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(type->qualifiedCppName());
- if (isWrapperType(type) || type->isEnum() || type->isFlags())
- return QString::fromLatin1("*PepType_SGTP(%1)->converter").arg(cpythonTypeNameExt(type));
-
- if (type->isArray()) {
- qDebug() << "Warning: no idea how to handle the Qt5 type " << type->qualifiedCppName();
- return QString();
- }
-
- /* the typedef'd primitive types case */
- const auto *pte = dynamic_cast<const PrimitiveTypeEntry *>(type);
- if (!pte) {
- qDebug() << "Warning: the Qt5 primitive type is unknown" << type->qualifiedCppName();
- return QString();
- }
- if (pte->basicReferencedTypeEntry())
- pte = pte->basicReferencedTypeEntry();
- if (pte->isPrimitive() && !pte->isCppPrimitive() && !pte->customConversion())
- return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(pte->qualifiedCppName());
-
- return convertersVariableName(type->targetLangPackage())
- + QLatin1Char('[') + getTypeIndexVariableName(type) + QLatin1Char(']');
-}
-
-QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType *type)
-{
- return cppApiVariableName(type->typeEntry()->targetLangPackage()) + QLatin1Char('[')
- + getTypeIndexVariableName(type) + QLatin1Char(']');
-}
-
-static inline QString unknownOperator() { return QStringLiteral("__UNKNOWN_OPERATOR__"); }
-
-QString ShibokenGenerator::fixedCppTypeName(const CustomConversion::TargetToNativeConversion *toNative)
-{
- if (toNative->sourceType())
- return fixedCppTypeName(toNative->sourceType());
- return toNative->sourceTypeName();
-}
-QString ShibokenGenerator::fixedCppTypeName(const AbstractMetaType *type)
-{
- return fixedCppTypeName(type->typeEntry(), type->cppSignature());
-}
-
-static QString _fixedCppTypeName(QString typeName)
-{
- typeName.remove(QLatin1Char(' '));
- typeName.replace(QLatin1Char('.'), QLatin1Char('_'));
- typeName.replace(QLatin1Char(','), QLatin1Char('_'));
- typeName.replace(QLatin1Char('<'), QLatin1Char('_'));
- typeName.replace(QLatin1Char('>'), QLatin1Char('_'));
- typeName.replace(QLatin1String("::"), QLatin1String("_"));
- typeName.replace(QLatin1String("*"), QLatin1String("PTR"));
- typeName.replace(QLatin1String("&"), QLatin1String("REF"));
- return typeName;
-}
-QString ShibokenGenerator::fixedCppTypeName(const TypeEntry *type, QString typeName)
-{
- if (typeName.isEmpty())
- typeName = type->qualifiedCppName();
- if (!(type->codeGeneration() & TypeEntry::GenerateTargetLang)) {
- typeName.prepend(QLatin1Char('_'));
- typeName.prepend(type->targetLangPackage());
- }
- return _fixedCppTypeName(typeName);
-}
-
-QString ShibokenGenerator::pythonPrimitiveTypeName(const QString &cppTypeName)
-{
- QString rv = ShibokenGenerator::m_pythonPrimitiveTypeName.value(cppTypeName, QString());
- if (rv.isEmpty()) {
- // activate this when some primitive types are missing,
- // i.e. when shiboken itself fails to build.
- // In general, this is valid while just called by isNumeric()
- // used on Qt5, 2015-09-20
- if (false) {
- std::cerr << "primitive type not found: " << qPrintable(cppTypeName) << std::endl;
- abort();
- }
- }
- return rv;
-}
-
-QString ShibokenGenerator::pythonPrimitiveTypeName(const PrimitiveTypeEntry *type)
-{
- while (type->basicReferencedTypeEntry())
- type = type->basicReferencedTypeEntry();
- return pythonPrimitiveTypeName(type->name());
-}
-
-QString ShibokenGenerator::pythonOperatorFunctionName(const QString &cppOpFuncName)
-{
- QString value = m_pythonOperators.value(cppOpFuncName);
- if (value.isEmpty())
- return unknownOperator();
- value.prepend(QLatin1String("__"));
- value.append(QLatin1String("__"));
- return value;
-}
-
-QString ShibokenGenerator::pythonOperatorFunctionName(const AbstractMetaFunction *func)
-{
- QString op = pythonOperatorFunctionName(func->originalName());
- if (op == unknownOperator())
- qCWarning(lcShiboken).noquote().nospace() << msgUnknownOperator(func);
- if (func->arguments().isEmpty()) {
- if (op == QLatin1String("__sub__"))
- op = QLatin1String("__neg__");
- else if (op == QLatin1String("__add__"))
- op = QLatin1String("__pos__");
- } else if (func->isStatic() && func->arguments().size() == 2) {
- // If a operator overload function has 2 arguments and
- // is static we assume that it is a reverse operator.
- op = op.insert(2, QLatin1Char('r'));
- }
- return op;
-}
-
-QString ShibokenGenerator::pythonRichCompareOperatorId(const QString &cppOpFuncName)
-{
- return QLatin1String("Py_") + m_pythonOperators.value(cppOpFuncName).toUpper();
-}
-
-QString ShibokenGenerator::pythonRichCompareOperatorId(const AbstractMetaFunction *func)
-{
- return pythonRichCompareOperatorId(func->originalName());
-}
-
-bool ShibokenGenerator::isNumber(const QString &cpythonApiName)
-{
- return cpythonApiName == QLatin1String("PyInt")
- || cpythonApiName == QLatin1String("PyFloat")
- || cpythonApiName == QLatin1String("PyLong")
- || cpythonApiName == QLatin1String("PyBool");
-}
-
-bool ShibokenGenerator::isNumber(const TypeEntry *type)
-{
- if (!type->isPrimitive())
- return false;
- return isNumber(pythonPrimitiveTypeName(static_cast<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(static_cast<const PrimitiveTypeEntry *>(type))
- == QLatin1String("PyInt");
-}
-
-bool ShibokenGenerator::isPyInt(const AbstractMetaType *type)
-{
- return isPyInt(type->typeEntry());
-}
-
-bool ShibokenGenerator::isWrapperType(const TypeEntry *type)
-{
- if (type->isComplex())
- return ShibokenGenerator::isWrapperType(static_cast<const ComplexTypeEntry *>(type));
- return type->isObject() || type->isValue() || type->isSmartPointer();
-}
-bool ShibokenGenerator::isWrapperType(const ComplexTypeEntry *type)
-{
- return isObjectType(type) || type->isValue() || type->isSmartPointer();
-}
-bool ShibokenGenerator::isWrapperType(const AbstractMetaType *metaType)
-{
- return isObjectType(metaType)
- || metaType->typeEntry()->isValue()
- || metaType->typeEntry()->isSmartPointer();
-}
-
-bool ShibokenGenerator::isPointerToWrapperType(const AbstractMetaType *type)
-{
- return (isObjectType(type) && type->indirections() == 1) || type->isValuePointer();
-}
-
-bool ShibokenGenerator::isObjectTypeUsedAsValueType(const AbstractMetaType *type)
-{
- return type->typeEntry()->isObject() && type->referenceType() == NoReference && type->indirections() == 0;
-}
-
-bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const AbstractMetaClass *metaClass)
-{
- if (!metaClass || !metaClass->typeEntry()->isValue())
- return false;
- if (metaClass->attributes().testFlag(AbstractMetaAttributes::HasRejectedDefaultConstructor))
- return false;
- const AbstractMetaFunctionList ctors =
- metaClass->queryFunctions(AbstractMetaClass::Constructors);
- bool copyConstructorFound = false;
- for (auto ctor : ctors) {
- switch (ctor->functionType()) {
- case AbstractMetaFunction::ConstructorFunction:
- return false;
- case AbstractMetaFunction::CopyConstructorFunction:
- copyConstructorFound = true;
- break;
- case AbstractMetaFunction::MoveConstructorFunction:
- break;
- default:
- Q_ASSERT(false);
- break;
- }
- }
- return copyConstructorFound;
-}
-
-bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const TypeEntry *type) const
-{
- if (!type || !type->isValue())
- return false;
- return isValueTypeWithCopyConstructorOnly(AbstractMetaClass::findClass(classes(), type));
-}
-
-bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const AbstractMetaType *type) const
-{
- if (!type || !type->typeEntry()->isValue())
- return false;
- return isValueTypeWithCopyConstructorOnly(type->typeEntry());
-}
-
-bool ShibokenGenerator::isUserPrimitive(const TypeEntry *type)
-{
- if (!type->isPrimitive())
- return false;
- const auto *trueType = static_cast<const PrimitiveTypeEntry *>(type);
- if (trueType->basicReferencedTypeEntry())
- trueType = trueType->basicReferencedTypeEntry();
- return trueType->isPrimitive() && !trueType->isCppPrimitive()
- && trueType->qualifiedCppName() != QLatin1String("std::string");
-}
-
-bool ShibokenGenerator::isUserPrimitive(const AbstractMetaType *type)
-{
- if (type->indirections() != 0)
- return false;
- return isUserPrimitive(type->typeEntry());
-}
-
-bool ShibokenGenerator::isCppPrimitive(const TypeEntry *type)
-{
- if (type->isCppPrimitive())
- return true;
- if (!type->isPrimitive())
- return false;
- const auto *trueType = static_cast<const PrimitiveTypeEntry *>(type);
- if (trueType->basicReferencedTypeEntry())
- trueType = trueType->basicReferencedTypeEntry();
- return trueType->qualifiedCppName() == QLatin1String("std::string");
-}
-
-bool ShibokenGenerator::isCppPrimitive(const AbstractMetaType *type)
-{
- if (isCString(type) || isVoidPointer(type))
- return true;
- if (type->indirections() != 0)
- return false;
- return isCppPrimitive(type->typeEntry());
-}
-
-bool ShibokenGenerator::shouldDereferenceArgumentPointer(const AbstractMetaArgument *arg)
-{
- return shouldDereferenceAbstractMetaTypePointer(arg->type());
-}
-
-bool ShibokenGenerator::shouldDereferenceAbstractMetaTypePointer(const AbstractMetaType *metaType)
-{
- return metaType->referenceType() == LValueReference && isWrapperType(metaType) && !isPointer(metaType);
-}
-
-bool ShibokenGenerator::visibilityModifiedToPrivate(const AbstractMetaFunction *func)
-{
- const FunctionModificationList &mods = func->modifications();
- for (const FunctionModification &mod : mods) {
- if (mod.modifiers & Modification::Private)
- return true;
- }
- return false;
-}
-
-QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType *metaType, bool genericNumberType)
-{
- QString customCheck;
- if (metaType->typeEntry()->isCustom()) {
- AbstractMetaType *type;
- customCheck = guessCPythonCheckFunction(metaType->typeEntry()->name(), &type);
- if (type)
- metaType = type;
- if (!customCheck.isEmpty())
- return customCheck;
- }
-
- if (isCppPrimitive(metaType)) {
- if (isCString(metaType))
- return QLatin1String("Shiboken::String::check");
- if (isVoidPointer(metaType))
- return QLatin1String("PyObject_Check");
- return cpythonCheckFunction(metaType->typeEntry(), genericNumberType);
- }
- if (metaType->typeEntry()->isContainer()) {
- QString typeCheck = QLatin1String("Shiboken::Conversions::");
- ContainerTypeEntry::Type type =
- static_cast<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().constFirst();
- if (isPointerToWrapperType(type)) {
- typeCheck += QString::fromLatin1("checkSequenceTypes(%1, ").arg(cpythonTypeNameExt(type));
- } else if (isWrapperType(type)) {
- typeCheck += QLatin1String("convertibleSequenceTypes(reinterpret_cast<SbkObjectType *>(");
- typeCheck += cpythonTypeNameExt(type);
- typeCheck += QLatin1String("), ");
- } else {
- typeCheck += QString::fromLatin1("convertibleSequenceTypes(%1, ").arg(converterObject(type));
- }
- } else if (type == ContainerTypeEntry::MapContainer
- || type == ContainerTypeEntry::MultiMapContainer
- || type == ContainerTypeEntry::HashContainer
- || type == ContainerTypeEntry::MultiHashContainer
- || type == ContainerTypeEntry::PairContainer) {
- QString pyType = (type == ContainerTypeEntry::PairContainer) ? QLatin1String("Pair") : QLatin1String("Dict");
- const AbstractMetaType *firstType = metaType->instantiations().constFirst();
- const AbstractMetaType *secondType = metaType->instantiations().constLast();
- if (isPointerToWrapperType(firstType) && isPointerToWrapperType(secondType)) {
- typeCheck += QString::fromLatin1("check%1Types(%2, %3, ")
- .arg(pyType, cpythonTypeNameExt(firstType), cpythonTypeNameExt(secondType));
- } else {
- typeCheck += QString::fromLatin1("convertible%1Types(%2, %3, %4, %5, ")
- .arg(pyType, converterObject(firstType),
- isPointerToWrapperType(firstType) ? QLatin1String("true") : QLatin1String("false"),
- converterObject(secondType),
- isPointerToWrapperType(secondType) ? QLatin1String("true") : QLatin1String("false"));
- }
- }
- return typeCheck;
- }
- return cpythonCheckFunction(metaType->typeEntry(), genericNumberType);
-}
-
-QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry *type, bool genericNumberType)
-{
- QString customCheck;
- if (type->isCustom()) {
- AbstractMetaType *metaType;
- customCheck = guessCPythonCheckFunction(type->name(), &metaType);
- if (metaType)
- return cpythonCheckFunction(metaType, genericNumberType);
- return customCheck;
- }
-
- if (type->isEnum() || type->isFlags() || isWrapperType(type))
- return QString::fromLatin1("SbkObject_TypeCheck(%1, ").arg(cpythonTypeNameExt(type));
- if (isCppPrimitive(type)) {
- return pythonPrimitiveTypeName(static_cast<const PrimitiveTypeEntry *>(type))
- + QLatin1String("_Check");
- }
- QString typeCheck;
- if (type->targetLangApiName() == type->name())
- typeCheck = cpythonIsConvertibleFunction(type);
- else if (type->targetLangApiName() == QLatin1String("PyUnicode"))
- typeCheck = QLatin1String("Shiboken::String::check");
- else
- typeCheck = type->targetLangApiName() + QLatin1String("_Check");
- return typeCheck;
-}
-
-QString ShibokenGenerator::guessCPythonCheckFunction(const QString &type, AbstractMetaType **metaType)
-{
- *metaType = nullptr;
- // PYSIDE-795: We abuse PySequence for iterables.
- // This part handles the overrides in the XML files.
- if (type == QLatin1String("PySequence"))
- return QLatin1String("Shiboken::String::checkIterable");
-
- if (type == QLatin1String("PyTypeObject"))
- return QLatin1String("PyType_Check");
-
- if (type == QLatin1String("PyBuffer"))
- return QLatin1String("Shiboken::Buffer::checkType");
-
- if (type == QLatin1String("str"))
- return QLatin1String("Shiboken::String::check");
-
- *metaType = buildAbstractMetaTypeFromString(type);
- if (*metaType && !(*metaType)->typeEntry()->isCustom())
- return QString();
-
- return type + QLatin1String("_Check");
-}
-
-QString ShibokenGenerator::cpythonIsConvertibleFunction(const TypeEntry *type,
- bool /* genericNumberType */,
- bool /* checkExact */)
-{
- if (isWrapperType(type)) {
- QString result = QLatin1String("Shiboken::Conversions::");
- result += (type->isValue() && !isValueTypeWithCopyConstructorOnly(type))
- ? QLatin1String("isPythonToCppValueConvertible")
- : QLatin1String("isPythonToCppPointerConvertible");
- result += QLatin1String("(reinterpret_cast<SbkObjectType *>(")
- + cpythonTypeNameExt(type) + QLatin1String("), ");
- return result;
- }
- return QString::fromLatin1("Shiboken::Conversions::isPythonToCppConvertible(%1, ")
- .arg(converterObject(type));
-}
-QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType *metaType,
- bool /* genericNumberType */)
-{
- QString customCheck;
- if (metaType->typeEntry()->isCustom()) {
- AbstractMetaType *type;
- customCheck = guessCPythonCheckFunction(metaType->typeEntry()->name(), &type);
- if (type)
- metaType = type;
- if (!customCheck.isEmpty())
- return customCheck;
- }
-
- QString result = QLatin1String("Shiboken::Conversions::");
- if (isWrapperType(metaType)) {
- if (isPointer(metaType) || isValueTypeWithCopyConstructorOnly(metaType))
- result += QLatin1String("isPythonToCppPointerConvertible");
- else if (metaType->referenceType() == LValueReference)
- result += QLatin1String("isPythonToCppReferenceConvertible");
- else
- result += QLatin1String("isPythonToCppValueConvertible");
- result += QLatin1String("(reinterpret_cast<SbkObjectType *>(")
- + cpythonTypeNameExt(metaType) + QLatin1String("), ");
- return result;
- }
- result += QLatin1String("isPythonToCppConvertible(") + converterObject(metaType);
- // Write out array sizes if known
- const AbstractMetaTypeCList nestedArrayTypes = metaType->nestedArrayTypes();
- if (!nestedArrayTypes.isEmpty() && nestedArrayTypes.constLast()->isCppPrimitive()) {
- const int dim1 = metaType->arrayElementCount();
- const int dim2 = nestedArrayTypes.constFirst()->isArray()
- ? nestedArrayTypes.constFirst()->arrayElementCount() : -1;
- result += QLatin1String(", ") + QString::number(dim1)
- + QLatin1String(", ") + QString::number(dim2);
- }
- result += QLatin1String(", ");
- return result;
-}
-
-QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaArgument *metaArg, bool genericNumberType)
-{
- return cpythonIsConvertibleFunction(metaArg->type(), genericNumberType);
-}
-
-QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaClass *metaClass)
-{
- return QLatin1String("Shiboken::Conversions::pythonToCppPointer(reinterpret_cast<SbkObjectType *>(")
- + cpythonTypeNameExt(metaClass->typeEntry()) + QLatin1String("), ");
-}
-
-QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaType *type,
- const AbstractMetaClass * /* context */)
-{
- if (isWrapperType(type)) {
- return QLatin1String("Shiboken::Conversions::pythonToCpp")
- + (isPointer(type) ? QLatin1String("Pointer") : QLatin1String("Copy"))
- + QLatin1String("(reinterpret_cast<SbkObjectType *>(")
- + cpythonTypeNameExt(type) + QLatin1String("), ");
- }
- return QStringLiteral("Shiboken::Conversions::pythonToCppCopy(%1, ")
- .arg(converterObject(type));
-}
-
-QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaType *type,
- const AbstractMetaClass * /* context */)
-{
- if (isWrapperType(type)) {
- QString conversion;
- if (type->referenceType() == LValueReference && !(type->isValue() && type->isConstant()) && !isPointer(type))
- conversion = QLatin1String("reference");
- else if (type->isValue() || type->isSmartPointer())
- conversion = QLatin1String("copy");
- else
- conversion = QLatin1String("pointer");
- QString result = QLatin1String("Shiboken::Conversions::") + conversion
- + QLatin1String("ToPython(reinterpret_cast<SbkObjectType *>(")
- + cpythonTypeNameExt(type) + QLatin1String("), ");
- if (conversion != QLatin1String("pointer"))
- result += QLatin1Char('&');
- return result;
- }
- return QStringLiteral("Shiboken::Conversions::copyToPython(%1, %2")
- .arg(converterObject(type),
- (isCString(type) || isVoidPointer(type)) ? QString() : QLatin1String("&"));
-}
-
-QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaClass *metaClass)
-{
- return cpythonToPythonConversionFunction(metaClass->typeEntry());
-}
-
-QString ShibokenGenerator::cpythonToPythonConversionFunction(const TypeEntry *type)
-{
- if (isWrapperType(type)) {
- const QString conversion = type->isValue() ? QLatin1String("copy") : QLatin1String("pointer");
- QString result = QLatin1String("Shiboken::Conversions::") + conversion
- + QLatin1String("ToPython(reinterpret_cast<SbkObjectType *>(") + cpythonTypeNameExt(type)
- + QLatin1String("), ");
- if (conversion != QLatin1String("pointer"))
- result += QLatin1Char('&');
- return result;
- }
-
- return QStringLiteral("Shiboken::Conversions::copyToPython(%1, &").arg(converterObject(type));
-}
-
-QString ShibokenGenerator::argumentString(const AbstractMetaFunction *func,
- const AbstractMetaArgument *argument,
- Options options) const
-{
- QString modified_type;
- if (!(options & OriginalTypeDescription))
- modified_type = func->typeReplaced(argument->argumentIndex() + 1);
- QString arg;
-
- if (modified_type.isEmpty())
- arg = translateType(argument->type(), func->implementingClass(), options);
- else
- arg = modified_type.replace(QLatin1Char('$'), QLatin1Char('.'));
-
- if (!(options & Generator::SkipName)) {
- // "int a", "int a[]"
- const int arrayPos = arg.indexOf(QLatin1Char('['));
- if (arrayPos != -1)
- arg.insert(arrayPos, QLatin1Char(' ') + argument->name());
- else
- arg.append(QLatin1Char(' ') + argument->name());
- }
-
- if ((options & Generator::SkipDefaultValues) != Generator::SkipDefaultValues &&
- !argument->originalDefaultValueExpression().isEmpty())
- {
- QString default_value = argument->originalDefaultValueExpression();
- if (default_value == QLatin1String("NULL"))
- default_value = QLatin1String(NULL_PTR);
-
- //WORKAROUND: fix this please
- if (default_value.startsWith(QLatin1String("new ")))
- default_value.remove(0, 4);
-
- arg += QLatin1String(" = ") + default_value;
- }
-
- return arg;
-}
-
-void ShibokenGenerator::writeArgument(QTextStream &s,
- const AbstractMetaFunction *func,
- const AbstractMetaArgument *argument,
- Options options) const
-{
- s << argumentString(func, argument, options);
-}
-
-void ShibokenGenerator::writeFunctionArguments(QTextStream &s,
- const AbstractMetaFunction *func,
- Options options) const
-{
- AbstractMetaArgumentList arguments = func->arguments();
-
- if (options & Generator::WriteSelf) {
- s << func->implementingClass()->name() << '&';
- if (!(options & SkipName))
- s << " self";
- }
-
- 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.isEmpty() && !(options & OriginalTypeDescription))
- return modifiedReturnType;
- return translateType(func->type(), func->implementingClass(), options);
-}
-
-QString ShibokenGenerator::functionSignature(const AbstractMetaFunction *func,
- const QString &prepend,
- const 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";
-
- if (func->exceptionSpecification() == ExceptionSpecification::NoExcept)
- s << " noexcept";
-
- return result;
-}
-
-void ShibokenGenerator::writeArgumentNames(QTextStream &s,
- const AbstractMetaFunction *func,
- Options options) const
-{
- const AbstractMetaArgumentList arguments = func->arguments();
- int argCount = 0;
- for (auto argument : arguments) {
- const int index = argument->argumentIndex() + 1;
- if ((options & Generator::SkipRemovedArguments) && (func->argumentRemoved(index)))
- continue;
-
- s << ((argCount > 0) ? ", " : "") << argument->name();
-
- if (((options & Generator::VirtualCall) == 0)
- && (!func->conversionRule(TypeSystem::NativeCode, index).isEmpty()
- || !func->conversionRule(TypeSystem::TargetLangCode, index).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<< ")\n";
-}
-
-AbstractMetaFunctionList ShibokenGenerator::filterFunctions(const AbstractMetaClass *metaClass)
-{
- AbstractMetaFunctionList result;
- const AbstractMetaFunctionList &funcs = metaClass->functions();
- for (AbstractMetaFunction *func : funcs) {
- if (func->isSignal() || func->isDestructor() || func->usesRValueReferences()
- || (func->isModifiedRemoved() && !func->isAbstract()
- && (!avoidProtectedHack() || !func->isProtected())))
- continue;
- result << func;
- }
- return result;
-}
-
-ShibokenGenerator::ExtendedConverterData ShibokenGenerator::getExtendedConverters() const
-{
- ExtendedConverterData extConvs;
- const AbstractMetaClassList &classList = classes();
- for (const AbstractMetaClass *metaClass : classList) {
- // Use only the classes for the current module.
- if (!shouldGenerate(metaClass))
- continue;
- const AbstractMetaFunctionList &overloads = metaClass->operatorOverloads(AbstractMetaClass::ConversionOp);
- for (AbstractMetaFunction *convOp : overloads) {
- // 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;
-}
-
-QVector<const CustomConversion *> ShibokenGenerator::getPrimitiveCustomConversions()
-{
- QVector<const CustomConversion *> conversions;
- const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes();
- for (const PrimitiveTypeEntry *type : primitiveTypeList) {
- if (!shouldGenerateTypeEntry(type) || !isUserPrimitive(type) || !type->customConversion())
- continue;
-
- conversions << type->customConversion();
- }
- return conversions;
-}
-
-static QString getArgumentsFromMethodCall(const QString &str)
-{
- // It would be way nicer to be able to use a Perl like
- // regular expression that accepts temporary variables
- // to count the parenthesis.
- // For more information check this:
- // http://perl.plover.com/yak/regex/samples/slide083.html
- static QLatin1String funcCall("%CPPSELF.%FUNCTION_NAME");
- int pos = str.indexOf(funcCall);
- if (pos == -1)
- return QString();
- pos = pos + funcCall.size();
- while (str.at(pos) == QLatin1Char(' ') || str.at(pos) == QLatin1Char('\t'))
- ++pos;
- if (str.at(pos) == QLatin1Char('('))
- ++pos;
- int begin = pos;
- int counter = 1;
- while (counter != 0) {
- if (str.at(pos) == QLatin1Char('('))
- ++counter;
- else if (str.at(pos) == QLatin1Char(')'))
- --counter;
- ++pos;
- }
- return str.mid(begin, pos-begin-1);
-}
-
-QString ShibokenGenerator::getCodeSnippets(const CodeSnipList &codeSnips,
- TypeSystem::CodeSnipPosition position,
- TypeSystem::Language language)
-{
- QString code;
- QTextStream c(&code);
- for (const CodeSnip &snip : codeSnips) {
- if ((position != TypeSystem::CodeSnipPositionAny && snip.position != position) || !(snip.language & language))
- continue;
- QString snipCode;
- QTextStream sc(&snipCode);
- formatCode(sc, snip.code(), INDENT);
- c << snipCode;
- }
- return code;
-}
-void ShibokenGenerator::processCodeSnip(QString &code, const AbstractMetaClass *context)
-{
- if (context) {
- // Replace template variable by the Python Type object
- // for the class context in which the variable is used.
- code.replace(QLatin1String("%PYTHONTYPEOBJECT"),
- cpythonTypeName(context) + QLatin1String("->type"));
- code.replace(QLatin1String("%TYPE"), wrapperName(context));
- code.replace(QLatin1String("%CPPTYPE"), context->name());
- }
-
- // replace "toPython" converters
- replaceConvertToPythonTypeSystemVariable(code);
-
- // replace "toCpp" converters
- replaceConvertToCppTypeSystemVariable(code);
-
- // replace "isConvertible" check
- replaceIsConvertibleToCppTypeSystemVariable(code);
-
- // replace "checkType" check
- replaceTypeCheckTypeSystemVariable(code);
-}
-
-ShibokenGenerator::ArgumentVarReplacementList ShibokenGenerator::getArgumentReplacement(const AbstractMetaFunction *func,
- bool usePyArgs, TypeSystem::Language language,
- const AbstractMetaArgument *lastArg)
-{
- ArgumentVarReplacementList argReplacements;
- TypeSystem::Language convLang = (language == TypeSystem::TargetLangCode)
- ? TypeSystem::NativeCode : TypeSystem::TargetLangCode;
- int removed = 0;
- for (int i = 0; i < func->arguments().size(); ++i) {
- const AbstractMetaArgument *arg = func->arguments().at(i);
- QString argValue;
- if (language == TypeSystem::TargetLangCode) {
- bool hasConversionRule = !func->conversionRule(convLang, i+1).isEmpty();
- const bool argRemoved = func->argumentRemoved(i+1);
- if (argRemoved)
- ++removed;
- if (argRemoved && hasConversionRule)
- argValue = arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX);
- else if (argRemoved || (lastArg && arg->argumentIndex() > lastArg->argumentIndex()))
- argValue = QLatin1String(CPP_ARG_REMOVED) + QString::number(i);
- if (!argRemoved && argValue.isEmpty()) {
- int argPos = i - removed;
- const AbstractMetaType *type = arg->type();
- QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1);
- if (!typeReplaced.isEmpty()) {
- AbstractMetaType *builtType = buildAbstractMetaTypeFromString(typeReplaced);
- if (builtType)
- type = builtType;
- }
- if (type->typeEntry()->isCustom()) {
- argValue = usePyArgs
- ? pythonArgsAt(argPos) : QLatin1String(PYTHON_ARG);
- } else {
- argValue = hasConversionRule
- ? arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX)
- : QLatin1String(CPP_ARG) + QString::number(argPos);
- if (isWrapperType(type)) {
- if (type->referenceType() == LValueReference && !isPointer(type))
- argValue.prepend(QLatin1Char('*'));
- }
- }
- }
- } else {
- argValue = arg->name();
- }
- if (!argValue.isEmpty())
- argReplacements << ArgumentVarReplacementPair(arg, argValue);
-
- }
- return argReplacements;
-}
-
-void ShibokenGenerator::writeCodeSnips(QTextStream &s,
- const CodeSnipList &codeSnips,
- TypeSystem::CodeSnipPosition position,
- TypeSystem::Language language,
- const AbstractMetaClass *context)
-{
- QString code = getCodeSnippets(codeSnips, position, language);
- if (code.isEmpty())
- return;
- processCodeSnip(code, context);
- s << INDENT << "// Begin code injection\n";
- s << code;
- s << INDENT << "// End of code injection\n";
-}
-
-void ShibokenGenerator::writeCodeSnips(QTextStream &s,
- const CodeSnipList &codeSnips,
- TypeSystem::CodeSnipPosition position,
- TypeSystem::Language language,
- const AbstractMetaFunction *func,
- const AbstractMetaArgument *lastArg)
-{
- QString code = getCodeSnippets(codeSnips, position, language);
- if (code.isEmpty())
- return;
-
- // Calculate the real number of arguments.
- int argsRemoved = 0;
- for (int i = 0; i < func->arguments().size(); i++) {
- if (func->argumentRemoved(i+1))
- argsRemoved++;
- }
-
- const auto &groups = func->implementingClass()
- ? getFunctionGroups(func->implementingClass())
- : getGlobalFunctionGroups();
- OverloadData od(groups[func->name()], this);
- bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(od);
-
- // Replace %PYARG_# variables.
- code.replace(QLatin1String("%PYARG_0"), QLatin1String(PYTHON_RETURN_VAR));
-
- static const QRegularExpression pyArgsRegex(QStringLiteral("%PYARG_(\\d+)"));
- Q_ASSERT(pyArgsRegex.isValid());
- if (language == TypeSystem::TargetLangCode) {
- if (usePyArgs) {
- code.replace(pyArgsRegex, QLatin1String(PYTHON_ARGS) + QLatin1String("[\\1-1]"));
- } else {
- static const QRegularExpression pyArgsRegexCheck(QStringLiteral("%PYARG_([2-9]+)"));
- Q_ASSERT(pyArgsRegexCheck.isValid());
- const QRegularExpressionMatch match = pyArgsRegexCheck.match(code);
- if (match.hasMatch()) {
- qCWarning(lcShiboken).noquote().nospace()
- << msgWrongIndex("%PYARG", match.captured(1), func);
- return;
- }
- code.replace(QLatin1String("%PYARG_1"), QLatin1String(PYTHON_ARG));
- }
- } else {
- // Replaces the simplest case of attribution to a
- // Python argument on the binding virtual method.
- static const QRegularExpression pyArgsAttributionRegex(QStringLiteral("%PYARG_(\\d+)\\s*=[^=]\\s*([^;]+)"));
- Q_ASSERT(pyArgsAttributionRegex.isValid());
- code.replace(pyArgsAttributionRegex, QLatin1String("PyTuple_SET_ITEM(")
- + QLatin1String(PYTHON_ARGS) + QLatin1String(", \\1-1, \\2)"));
- code.replace(pyArgsRegex, QLatin1String("PyTuple_GET_ITEM(")
- + QLatin1String(PYTHON_ARGS) + QLatin1String(", \\1-1)"));
- }
-
- // Replace %ARG#_TYPE variables.
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (const AbstractMetaArgument *arg : arguments) {
- QString argTypeVar = QStringLiteral("%ARG%1_TYPE").arg(arg->argumentIndex() + 1);
- QString argTypeVal = arg->type()->cppSignature();
- code.replace(argTypeVar, argTypeVal);
- }
-
- static const QRegularExpression cppArgTypeRegexCheck(QStringLiteral("%ARG(\\d+)_TYPE"));
- Q_ASSERT(cppArgTypeRegexCheck.isValid());
- QRegularExpressionMatchIterator rit = cppArgTypeRegexCheck.globalMatch(code);
- while (rit.hasNext()) {
- QRegularExpressionMatch match = rit.next();
- qCWarning(lcShiboken).noquote().nospace()
- << msgWrongIndex("%ARG#_TYPE", match.captured(1), func);
- }
-
- // Replace template variable for return variable name.
- if (func->isConstructor()) {
- code.replace(QLatin1String("%0."), QLatin1String("cptr->"));
- code.replace(QLatin1String("%0"), QLatin1String("cptr"));
- } else if (func->type()) {
- QString returnValueOp = isPointerToWrapperType(func->type())
- ? QLatin1String("%1->") : QLatin1String("%1.");
- if (ShibokenGenerator::isWrapperType(func->type()))
- code.replace(QLatin1String("%0."), returnValueOp.arg(QLatin1String(CPP_RETURN_VAR)));
- code.replace(QLatin1String("%0"), QLatin1String(CPP_RETURN_VAR));
- }
-
- // Replace template variable for self Python object.
- QString pySelf = language == TypeSystem::NativeCode
- ? QLatin1String("pySelf") : QLatin1String("self");
- code.replace(QLatin1String("%PYSELF"), pySelf);
-
- // Replace template variable for a pointer to C++ of this object.
- if (func->implementingClass()) {
- QString replacement = func->isStatic() ? QLatin1String("%1::") : QLatin1String("%1->");
- QString cppSelf;
- if (func->isStatic())
- cppSelf = func->ownerClass()->qualifiedCppName();
- else if (language == TypeSystem::NativeCode)
- cppSelf = QLatin1String("this");
- else
- cppSelf = QLatin1String(CPP_SELF_VAR);
-
- // On comparison operator CPP_SELF_VAR is always a reference.
- if (func->isComparisonOperator())
- replacement = QLatin1String("%1.");
-
- if (func->isVirtual() && !func->isAbstract() && (!avoidProtectedHack() || !func->isProtected())) {
- QString methodCallArgs = getArgumentsFromMethodCall(code);
- if (!methodCallArgs.isEmpty()) {
- const QString pattern = QStringLiteral("%CPPSELF.%FUNCTION_NAME(%1)").arg(methodCallArgs);
- if (func->name() == QLatin1String("metaObject")) {
- QString wrapperClassName = wrapperName(func->ownerClass());
- QString cppSelfVar = avoidProtectedHack()
- ? QLatin1String("%CPPSELF")
- : QStringLiteral("reinterpret_cast<%1 *>(%CPPSELF)").arg(wrapperClassName);
- code.replace(pattern,
- QString::fromLatin1("(Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject *>(%1))"
- " ? %2->::%3::%FUNCTION_NAME(%4)"
- " : %CPPSELF.%FUNCTION_NAME(%4))").arg(pySelf, cppSelfVar, wrapperClassName, methodCallArgs));
- } else {
- code.replace(pattern,
- QString::fromLatin1("(Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject *>(%1))"
- " ? %CPPSELF->::%TYPE::%FUNCTION_NAME(%2)"
- " : %CPPSELF.%FUNCTION_NAME(%2))").arg(pySelf, methodCallArgs));
- }
- }
- }
-
- code.replace(QLatin1String("%CPPSELF."), replacement.arg(cppSelf));
- code.replace(QLatin1String("%CPPSELF"), cppSelf);
-
- if (code.indexOf(QLatin1String("%BEGIN_ALLOW_THREADS")) > -1) {
- if (code.count(QLatin1String("%BEGIN_ALLOW_THREADS")) == code.count(QLatin1String("%END_ALLOW_THREADS"))) {
- code.replace(QLatin1String("%BEGIN_ALLOW_THREADS"), QLatin1String(BEGIN_ALLOW_THREADS));
- code.replace(QLatin1String("%END_ALLOW_THREADS"), QLatin1String(END_ALLOW_THREADS));
- } else {
- qCWarning(lcShiboken) << "%BEGIN_ALLOW_THREADS and %END_ALLOW_THREADS mismatch";
- }
- }
-
- // replace template variable for the Python Type object for the
- // class implementing the method in which the code snip is written
- if (func->isStatic()) {
- code.replace(QLatin1String("%PYTHONTYPEOBJECT"),
- cpythonTypeName(func->implementingClass()) + QLatin1String("->type"));
- } else {
- code.replace(QLatin1String("%PYTHONTYPEOBJECT."), pySelf + QLatin1String("->ob_type->"));
- code.replace(QLatin1String("%PYTHONTYPEOBJECT"), pySelf + QLatin1String("->ob_type"));
- }
- }
-
- // Replaces template %ARGUMENT_NAMES and %# variables by argument variables and values.
- // Replaces template variables %# for individual arguments.
- const ArgumentVarReplacementList &argReplacements = getArgumentReplacement(func, usePyArgs, language, lastArg);
-
- QStringList args;
- for (const ArgumentVarReplacementPair &pair : argReplacements) {
- if (pair.second.startsWith(QLatin1String(CPP_ARG_REMOVED)))
- continue;
- args << pair.second;
- }
- code.replace(QLatin1String("%ARGUMENT_NAMES"), args.join(QLatin1String(", ")));
-
- for (const ArgumentVarReplacementPair &pair : argReplacements) {
- const AbstractMetaArgument *arg = pair.first;
- int idx = arg->argumentIndex() + 1;
- AbstractMetaType *type = arg->type();
- QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1);
- if (!typeReplaced.isEmpty()) {
- AbstractMetaType *builtType = buildAbstractMetaTypeFromString(typeReplaced);
- if (builtType)
- type = builtType;
- }
- if (isWrapperType(type)) {
- QString replacement = pair.second;
- if (type->referenceType() == LValueReference && !isPointer(type))
- replacement.remove(0, 1);
- if (type->referenceType() == LValueReference || isPointer(type))
- code.replace(QString::fromLatin1("%%1.").arg(idx), replacement + QLatin1String("->"));
- }
- code.replace(placeHolderRegex(idx), pair.second);
- }
-
- if (language == TypeSystem::NativeCode) {
- // Replaces template %PYTHON_ARGUMENTS variable with a pointer to the Python tuple
- // containing the converted virtual method arguments received from C++ to be passed
- // to the Python override.
- code.replace(QLatin1String("%PYTHON_ARGUMENTS"), QLatin1String(PYTHON_ARGS));
-
- // replace variable %PYTHON_METHOD_OVERRIDE for a pointer to the Python method
- // override for the C++ virtual method in which this piece of code was inserted
- code.replace(QLatin1String("%PYTHON_METHOD_OVERRIDE"), QLatin1String(PYTHON_OVERRIDE_VAR));
- }
-
- if (avoidProtectedHack()) {
- // If the function being processed was added by the user via type system,
- // Shiboken needs to find out if there are other overloads for the same method
- // name and if any of them is of the protected visibility. This is used to replace
- // calls to %FUNCTION_NAME on user written custom code for calls to the protected
- // dispatcher.
- bool hasProtectedOverload = false;
- if (func->isUserAdded()) {
- const AbstractMetaFunctionList &funcs = getFunctionOverloads(func->ownerClass(), func->name());
- for (const AbstractMetaFunction *f : funcs)
- hasProtectedOverload |= f->isProtected();
- }
-
- if (func->isProtected() || hasProtectedOverload) {
- code.replace(QLatin1String("%TYPE::%FUNCTION_NAME"),
- QStringLiteral("%1::%2_protected")
- .arg(wrapperName(func->ownerClass()), func->originalName()));
- code.replace(QLatin1String("%FUNCTION_NAME"),
- func->originalName() + QLatin1String("_protected"));
- }
- }
-
- if (func->isConstructor() && shouldGenerateCppWrapper(func->ownerClass()))
- code.replace(QLatin1String("%TYPE"), wrapperName(func->ownerClass()));
-
- if (func->ownerClass())
- code.replace(QLatin1String("%CPPTYPE"), func->ownerClass()->name());
-
- replaceTemplateVariables(code, func);
-
- processCodeSnip(code);
- s << INDENT << "// Begin code injection\n";
- s << code;
- s << INDENT << "// End of code injection\n";
-}
-
-// Returns true if the string is an expression,
-// and false if it is a variable.
-static bool isVariable(const QString &code)
-{
- static const QRegularExpression expr(QStringLiteral("^\\s*\\*?\\s*[A-Za-z_][A-Za-z_0-9.]*\\s*(?:\\[[^\\[]+\\])*$"));
- Q_ASSERT(expr.isValid());
- return expr.match(code.trimmed()).hasMatch();
-}
-
-// A miniature normalizer that puts a type string into a format
-// suitable for comparison with AbstractMetaType::cppSignature()
-// result.
-static QString miniNormalizer(const QString &varType)
-{
- QString normalized = varType.trimmed();
- if (normalized.isEmpty())
- return normalized;
- if (normalized.startsWith(QLatin1String("::")))
- normalized.remove(0, 2);
- QString suffix;
- while (normalized.endsWith(QLatin1Char('*')) || normalized.endsWith(QLatin1Char('&'))) {
- suffix.prepend(normalized.at(normalized.count() - 1));
- normalized.chop(1);
- normalized = normalized.trimmed();
- }
- const QString result = normalized + QLatin1Char(' ') + suffix;
- return result.trimmed();
-}
-// The position must indicate the first character after the opening '('.
-// ATTENTION: do not modify this function to trim any resulting string!
-// This must be done elsewhere.
-static QString getConverterTypeSystemVariableArgument(const QString &code, int pos)
-{
- QString arg;
- int parenthesisDepth = 0;
- int count = 0;
- while (pos + count < code.count()) {
- char c = code.at(pos+count).toLatin1(); // toAscii is gone
- if (c == '(') {
- ++parenthesisDepth;
- } else if (c == ')') {
- if (parenthesisDepth == 0) {
- arg = code.mid(pos, count).trimmed();
- break;
- }
- --parenthesisDepth;
- }
- ++count;
- }
- if (parenthesisDepth != 0)
- qFatal("Unbalanced parenthesis on type system converter variable call.");
- return arg;
-}
-using StringPair = QPair<QString, QString>;
-
-void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString &code)
-{
- QVector<StringPair> replacements;
- QRegularExpressionMatchIterator rit = m_typeSystemConvRegEx[converterVariable].globalMatch(code);
- while (rit.hasNext()) {
- const QRegularExpressionMatch match = rit.next();
- const QStringList list = match.capturedTexts();
- QString conversionString = list.constFirst();
- const QString &conversionTypeName = list.constLast();
- QString message;
- const AbstractMetaType *conversionType = buildAbstractMetaTypeFromString(conversionTypeName, &message);
- if (!conversionType) {
- qFatal("%s", qPrintable(msgCannotFindType(conversionTypeName,
- m_typeSystemConvName[converterVariable],
- message)));
- }
- QString conversion;
- QTextStream c(&conversion);
- switch (converterVariable) {
- case TypeSystemToCppFunction: {
- int end = match.capturedStart();
- int start = end;
- while (start > 0 && code.at(start) != QLatin1Char('\n'))
- --start;
- while (code.at(start).isSpace())
- ++start;
- QString varType = code.mid(start, end - start);
- conversionString = varType + list.constFirst();
- varType = miniNormalizer(varType);
- QString varName = list.at(1).trimmed();
- if (!varType.isEmpty()) {
- const QString conversionSignature = conversionType->cppSignature();
- if (varType != QLatin1String("auto") && varType != conversionSignature)
- qFatal("%s", qPrintable(msgConversionTypesDiffer(varType, conversionSignature)));
- c << getFullTypeName(conversionType) << ' ' << varName;
- writeMinimalConstructorExpression(c, conversionType);
- c << ";\n";
- Indentation indent(INDENT);
- c << INDENT;
- }
- c << cpythonToCppConversionFunction(conversionType);
- QString prefix;
- if (varName.startsWith(QLatin1Char('*'))) {
- varName.remove(0, 1);
- varName = varName.trimmed();
- } else {
- prefix = QLatin1Char('&');
- }
- QString arg = getConverterTypeSystemVariableArgument(code, match.capturedEnd());
- conversionString += arg;
- c << arg << ", " << prefix << '(' << varName << ')';
- break;
- }
- case TypeSystemCheckFunction:
- conversion = cpythonCheckFunction(conversionType);
- if (conversionType->typeEntry()->isPrimitive()
- && (conversionType->typeEntry()->name() == QLatin1String("PyObject")
- || !conversion.endsWith(QLatin1Char(' ')))) {
- c << '(';
- break;
- }
- Q_FALLTHROUGH();
- case TypeSystemIsConvertibleFunction:
- if (conversion.isEmpty())
- conversion = cpythonIsConvertibleFunction(conversionType);
- Q_FALLTHROUGH();
- case TypeSystemToPythonFunction:
- if (conversion.isEmpty())
- conversion = cpythonToPythonConversionFunction(conversionType);
- Q_FALLTHROUGH();
- default: {
- QString arg = getConverterTypeSystemVariableArgument(code, match.capturedEnd());
- conversionString += arg;
- if (converterVariable == TypeSystemToPythonFunction && !isVariable(arg)) {
- qFatal("Only variables are acceptable as argument to %%CONVERTTOPYTHON type system variable on code snippet: '%s'",
- qPrintable(code));
- }
- if (conversion.contains(QLatin1String("%in"))) {
- conversion.prepend(QLatin1Char('('));
- conversion.replace(QLatin1String("%in"), arg);
- } else {
- c << arg;
- }
- }
- }
- replacements.append(qMakePair(conversionString, conversion));
- }
- for (const StringPair &rep : qAsConst(replacements))
- code.replace(rep.first, rep.second);
-}
-
-bool ShibokenGenerator::injectedCodeUsesPySelf(const AbstractMetaFunction *func)
-{
- CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::NativeCode);
- for (const CodeSnip &snip : qAsConst(snips)) {
- if (snip.code().contains(QLatin1String("%PYSELF")))
- return true;
- }
- return false;
-}
-
-bool ShibokenGenerator::injectedCodeCallsCppFunction(const AbstractMetaFunction *func)
-{
- QString funcCall = func->originalName() + QLatin1Char('(');
- QString wrappedCtorCall;
- if (func->isConstructor()) {
- funcCall.prepend(QLatin1String("new "));
- wrappedCtorCall = QStringLiteral("new %1(").arg(wrapperName(func->ownerClass()));
- }
- CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
- for (const CodeSnip &snip : qAsConst(snips)) {
- if (snip.code().contains(QLatin1String("%FUNCTION_NAME(")) || snip.code().contains(funcCall)
- || (func->isConstructor()
- && ((func->ownerClass()->isPolymorphic() && snip.code().contains(wrappedCtorCall))
- || snip.code().contains(QLatin1String("new %TYPE("))))
- )
- return true;
- }
- return false;
-}
-
-bool ShibokenGenerator::injectedCodeCallsPythonOverride(const AbstractMetaFunction *func)
-{
- static const QRegularExpression overrideCallRegexCheck(QStringLiteral("PyObject_Call\\s*\\(\\s*%PYTHON_METHOD_OVERRIDE\\s*,"));
- Q_ASSERT(overrideCallRegexCheck.isValid());
- CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::NativeCode);
- for (const CodeSnip &snip : qAsConst(snips)) {
- if (snip.code().contains(overrideCallRegexCheck))
- return true;
- }
- return false;
-}
-
-bool ShibokenGenerator::injectedCodeHasReturnValueAttribution(const AbstractMetaFunction *func, TypeSystem::Language language)
-{
- static const QRegularExpression retValAttributionRegexCheck_native(QStringLiteral("%0\\s*=[^=]\\s*.+"));
- Q_ASSERT(retValAttributionRegexCheck_native.isValid());
- static const QRegularExpression retValAttributionRegexCheck_target(QStringLiteral("%PYARG_0\\s*=[^=]\\s*.+"));
- Q_ASSERT(retValAttributionRegexCheck_target.isValid());
- CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, language);
- for (const CodeSnip &snip : qAsConst(snips)) {
- if (language == TypeSystem::TargetLangCode) {
- if (snip.code().contains(retValAttributionRegexCheck_target))
- return true;
- } else {
- if (snip.code().contains(retValAttributionRegexCheck_native))
- return true;
- }
- }
- return false;
-}
-
-bool ShibokenGenerator::injectedCodeUsesArgument(const AbstractMetaFunction *func, int argumentIndex)
-{
- CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny);
- const QRegularExpression argRegEx = placeHolderRegex(argumentIndex + 1);
- for (const CodeSnip &snip : qAsConst(snips)) {
- QString code = snip.code();
- if (code.contains(QLatin1String("%ARGUMENT_NAMES")) || code.contains(argRegEx))
- return true;
- }
- return false;
-}
-
-bool ShibokenGenerator::classNeedsGetattroFunction(const AbstractMetaClass *metaClass)
-{
- return getGeneratorClassInfo(metaClass).needsGetattroFunction;
-}
-
-bool ShibokenGenerator::classNeedsGetattroFunctionImpl(const AbstractMetaClass *metaClass)
-{
- if (!metaClass)
- return false;
- if (metaClass->typeEntry()->isSmartPointer())
- return true;
- const auto &functionGroup = getFunctionGroups(metaClass);
- for (auto it = functionGroup.cbegin(), end = functionGroup.cend(); it != end; ++it) {
- AbstractMetaFunctionList overloads;
- for (AbstractMetaFunction *func : qAsConst(it.value())) {
- if (func->isAssignmentOperator() || func->isCastOperator() || func->isModifiedRemoved()
- || func->isPrivate() || func->ownerClass() != func->implementingClass()
- || func->isConstructor() || func->isOperatorOverload())
- continue;
- overloads.append(func);
- }
- if (overloads.isEmpty())
- continue;
- if (OverloadData::hasStaticAndInstanceFunctions(overloads))
- return true;
- }
- return false;
-}
-
-bool ShibokenGenerator::classNeedsSetattroFunction(const AbstractMetaClass *metaClass)
-{
- if (!metaClass)
- return false;
- return metaClass->typeEntry()->isSmartPointer();
-}
-
-AbstractMetaFunctionList ShibokenGenerator::getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass *metaClass)
-{
- AbstractMetaFunctionList methods;
- if (metaClass) {
- const auto &functionGroups = getFunctionGroups(metaClass);
- for (auto it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
- AbstractMetaFunctionList overloads;
- for (AbstractMetaFunction *func : qAsConst(it.value())) {
- if (func->isAssignmentOperator() || func->isCastOperator() || func->isModifiedRemoved()
- || func->isPrivate() || func->ownerClass() != func->implementingClass()
- || func->isConstructor() || func->isOperatorOverload())
- continue;
- overloads.append(func);
- }
- if (overloads.isEmpty())
- continue;
- if (OverloadData::hasStaticAndInstanceFunctions(overloads))
- methods.append(overloads.constFirst());
- }
- }
- return methods;
-}
-
-AbstractMetaClassList ShibokenGenerator::getBaseClasses(const AbstractMetaClass *metaClass) const
-{
- AbstractMetaClassList baseClasses;
- if (metaClass) {
- QStringList baseClassNames(metaClass->baseClassNames());
- const QString defaultSuperclass = metaClass->typeEntry()->defaultSuperclass();
- if (!defaultSuperclass.isEmpty()) {
- int index = baseClassNames.indexOf(defaultSuperclass);
- if (index >= 0)
- baseClassNames.move(index, 0);
- }
- for (const QString &parent : baseClassNames) {
- AbstractMetaClass *clazz = AbstractMetaClass::findClass(classes(), parent);
- if (clazz)
- baseClasses << clazz;
- }
- }
- return baseClasses;
-}
-
-const AbstractMetaClass *ShibokenGenerator::getMultipleInheritingClass(const AbstractMetaClass *metaClass)
-{
- if (!metaClass || metaClass->baseClassNames().isEmpty())
- return nullptr;
- 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);
- for (AbstractMetaClass *base : qAsConst(baseClasses)) {
- result.append(base);
- result.append(getAllAncestors(base));
- }
- }
- return result;
-}
-
-QString ShibokenGenerator::getModuleHeaderFileName(const QString &moduleName) const
-{
- return moduleCppPrefix(moduleName).toLower() + QLatin1String("_python.h");
-}
-
-bool ShibokenGenerator::isCopyable(const AbstractMetaClass *metaClass)
-
-{
- if (metaClass->isNamespace() || isObjectType(metaClass))
- return false;
- if (metaClass->typeEntry()->copyable() == ComplexTypeEntry::Unknown)
- return metaClass->hasCloneOperator();
-
- return metaClass->typeEntry()->copyable() == ComplexTypeEntry::CopyableSet;
-}
-
-AbstractMetaType *ShibokenGenerator::buildAbstractMetaTypeFromString(QString typeSignature,
- QString *errorMessage)
-{
- typeSignature = typeSignature.trimmed();
- if (typeSignature.startsWith(QLatin1String("::")))
- typeSignature.remove(0, 2);
-
- auto it = m_metaTypeFromStringCache.find(typeSignature);
- if (it == m_metaTypeFromStringCache.end()) {
- AbstractMetaType *metaType =
- AbstractMetaBuilder::translateType(typeSignature, nullptr, {}, errorMessage);
- if (Q_UNLIKELY(!metaType)) {
- if (errorMessage)
- errorMessage->prepend(msgCannotBuildMetaType(typeSignature));
- return nullptr;
- }
- it = m_metaTypeFromStringCache.insert(typeSignature, metaType);
- }
- return it.value();
-}
-
-AbstractMetaType *ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(const TypeEntry *typeEntry)
-{
- QString typeName = typeEntry->qualifiedCppName();
- if (typeName.startsWith(QLatin1String("::")))
- typeName.remove(0, 2);
- if (m_metaTypeFromStringCache.contains(typeName))
- return m_metaTypeFromStringCache.value(typeName);
- auto *metaType = new AbstractMetaType;
- metaType->setTypeEntry(typeEntry);
- metaType->clearIndirections();
- metaType->setReferenceType(NoReference);
- metaType->setConstant(false);
- metaType->decideUsagePattern();
- m_metaTypeFromStringCache.insert(typeName, metaType);
- return metaType;
-}
-AbstractMetaType *ShibokenGenerator::buildAbstractMetaTypeFromAbstractMetaClass(const AbstractMetaClass *metaClass)
-{
- return ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(metaClass->typeEntry());
-}
-
-/*
-static void dumpFunction(AbstractMetaFunctionList lst)
-{
- qDebug() << "DUMP FUNCTIONS: ";
- for (AbstractMetaFunction *func : qAsConst(lst))
- qDebug() << "*" << func->ownerClass()->name()
- << func->signature()
- << "Private: " << func->isPrivate()
- << "Empty: " << func->isEmptyFunction()
- << "Static:" << func->isStatic()
- << "Signal:" << func->isSignal()
- << "ClassImplements: " << (func->ownerClass() != func->implementingClass())
- << "is operator:" << func->isOperatorOverload()
- << "is global:" << func->isInGlobalScope();
-}
-*/
-
-static bool isGroupable(const AbstractMetaFunction *func)
-{
- if (func->isSignal() || func->isDestructor() || (func->isModifiedRemoved() && !func->isAbstract()))
- return false;
- // weird operator overloads
- if (func->name() == QLatin1String("operator[]") || func->name() == QLatin1String("operator->")) // FIXME: what about cast operators?
- return false;;
- return true;
-}
-
-ShibokenGenerator::FunctionGroups ShibokenGenerator::getGlobalFunctionGroups() const
-{
- const AbstractMetaFunctionList &lst = globalFunctions();
- FunctionGroups results;
- for (AbstractMetaFunction *func : lst) {
- if (isGroupable(func))
- results[func->name()].append(func);
- }
- return results;
-}
-
-const GeneratorClassInfoCacheEntry &ShibokenGenerator::getGeneratorClassInfo(const AbstractMetaClass *scope)
-{
- auto cache = generatorClassInfoCache();
- auto it = cache->find(scope);
- if (it == cache->end()) {
- it = cache->insert(scope, {});
- it.value().functionGroups = getFunctionGroupsImpl(scope);
- it.value().needsGetattroFunction = classNeedsGetattroFunctionImpl(scope);
- }
- return it.value();
-}
-
-ShibokenGenerator::FunctionGroups ShibokenGenerator::getFunctionGroups(const AbstractMetaClass *scope)
-{
- Q_ASSERT(scope);
- return getGeneratorClassInfo(scope).functionGroups;
-}
-
-ShibokenGenerator::FunctionGroups ShibokenGenerator::getFunctionGroupsImpl(const AbstractMetaClass *scope)
-{
- const AbstractMetaFunctionList &lst = scope->functions();
-
- FunctionGroups results;
- for (AbstractMetaFunction *func : lst) {
- if (isGroupable(func)) {
- auto it = results.find(func->name());
- if (it == results.end()) {
- results.insert(func->name(), AbstractMetaFunctionList(1, func));
- } else {
- // If there are virtuals methods in the mix (PYSIDE-570,
- // QFileSystemModel::index(QString,int) and
- // QFileSystemModel::index(int,int,QModelIndex)) override, make sure
- // the overriding method of the most-derived class is seen first
- // and inserted into the "seenSignatures" set.
- if (func->isVirtual())
- it.value().prepend(func);
- else
- it.value().append(func);
- }
- }
- }
- return results;
-}
-
-AbstractMetaFunctionList ShibokenGenerator::getInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen)
-{
- AbstractMetaFunctionList results;
- AbstractMetaClass *basis;
- if (func->ownerClass() && (basis = func->ownerClass()->baseClass())) {
- for (; basis; basis = basis->baseClass()) {
- const AbstractMetaFunction *inFunc = basis->findFunction(func->name());
- if (inFunc && !seen->contains(inFunc->minimalSignature())) {
- seen->insert(inFunc->minimalSignature());
- AbstractMetaFunction *newFunc = inFunc->copy();
- newFunc->setImplementingClass(func->implementingClass());
- results << newFunc;
- }
- }
- }
- return results;
-}
-
-AbstractMetaFunctionList ShibokenGenerator::getFunctionAndInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen)
-{
- AbstractMetaFunctionList results;
- seen->insert(func->minimalSignature());
- results << const_cast<AbstractMetaFunction *>(func) << getInheritedOverloads(func, seen);
- return results;
-}
-
-AbstractMetaFunctionList ShibokenGenerator::getFunctionOverloads(const AbstractMetaClass *scope, const QString &functionName)
-{
- AbstractMetaFunctionList lst = scope ? scope->functions() : globalFunctions();
-
- AbstractMetaFunctionList results;
- QSet<QString> seenSignatures;
- for (AbstractMetaFunction *func : qAsConst(lst)) {
- if (func->name() != functionName)
- continue;
- if (isGroupable(func)) {
- // PYSIDE-331: look also into base classes.
- results << getFunctionAndInheritedOverloads(func, &seenSignatures);
- }
- }
- return results;
-}
-
-Generator::OptionDescriptions ShibokenGenerator::options() const
-{
- return OptionDescriptions()
- << qMakePair(QLatin1String(AVOID_PROTECTED_HACK),
- QLatin1String("Avoid the use of the '#define protected public' hack."))
- << qMakePair(QLatin1String(DISABLE_VERBOSE_ERROR_MESSAGES),
- QLatin1String("Disable verbose error messages. Turn the python code hard to debug\n"
- "but safe few kB on the generated bindings."))
- << qMakePair(QLatin1String(PARENT_CTOR_HEURISTIC),
- QLatin1String("Enable heuristics to detect parent relationship on constructors."))
- << qMakePair(QLatin1String(ENABLE_PYSIDE_EXTENSIONS),
- QLatin1String("Enable PySide extensions, such as support for signal/slots,\n"
- "use this if you are creating a binding for a Qt-based library."))
- << qMakePair(QLatin1String(RETURN_VALUE_HEURISTIC),
- QLatin1String("Enable heuristics to detect parent relationship on return values\n"
- "(USE WITH CAUTION!)"))
- << qMakePair(QLatin1String(USE_ISNULL_AS_NB_NONZERO),
- QLatin1String("If a class have an isNull() const method, it will be used to compute\n"
- "the value of boolean casts"));
-}
-
-bool ShibokenGenerator::handleOption(const QString &key, const QString & /* value */)
-{
- if (key == QLatin1String(PARENT_CTOR_HEURISTIC))
- return (m_useCtorHeuristic = true);
- if (key == QLatin1String(ENABLE_PYSIDE_EXTENSIONS))
- return (m_usePySideExtensions = true);
- if (key == QLatin1String(RETURN_VALUE_HEURISTIC))
- return (m_userReturnValueHeuristic = true);
- if (key == QLatin1String(DISABLE_VERBOSE_ERROR_MESSAGES))
- return (m_verboseErrorMessagesDisabled = true);
- if (key == QLatin1String(USE_ISNULL_AS_NB_NONZERO))
- return (m_useIsNullAsNbNonZero = true);
- if (key == QLatin1String(AVOID_PROTECTED_HACK))
- return (m_avoidProtectedHack = true);
- return false;
-}
-
-static void getCode(QStringList &code, const CodeSnipList &codeSnips)
-{
- for (const CodeSnip &snip : qAsConst(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;
-
- for (CustomConversion::TargetToNativeConversion *toNative : qAsConst(toCppConversions))
- code.append(toNative->conversion());
-}
-
-bool ShibokenGenerator::doSetup()
-{
- QStringList snips;
- const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes();
- for (const PrimitiveTypeEntry *type : primitiveTypeList)
- getCode(snips, type);
- const ContainerTypeEntryList &containerTypeList = containerTypes();
- for (const ContainerTypeEntry *type : containerTypeList)
- getCode(snips, type);
- const AbstractMetaClassList &classList = classes();
- for (const AbstractMetaClass *metaClass : classList)
- getCode(snips, metaClass->typeEntry());
-
- const TypeSystemTypeEntry *moduleEntry = TypeDatabase::instance()->defaultTypeSystemType();
- Q_ASSERT(moduleEntry);
- getCode(snips, moduleEntry);
-
- const auto &functionGroups = getGlobalFunctionGroups();
- for (auto it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
- for (AbstractMetaFunction *func : it.value())
- getCode(snips, func->injectedCodeSnips());
- }
-
- for (const QString &code : qAsConst(snips)) {
- collectContainerTypesFromConverterMacros(code, true);
- collectContainerTypesFromConverterMacros(code, false);
- }
-
- return true;
-}
-
-void ShibokenGenerator::collectContainerTypesFromConverterMacros(const QString &code, bool toPythonMacro)
-{
- QString convMacro = toPythonMacro ? QLatin1String("%CONVERTTOPYTHON[") : QLatin1String("%CONVERTTOCPP[");
- int offset = toPythonMacro ? sizeof("%CONVERTTOPYTHON") : sizeof("%CONVERTTOCPP");
- int start = 0;
- while ((start = code.indexOf(convMacro, start)) != -1) {
- int end = code.indexOf(QLatin1Char(']'), start);
- start += offset;
- if (code.at(start) != QLatin1Char('%')) {
- QString typeString = code.mid(start, end - start);
- AbstractMetaType *type = buildAbstractMetaTypeFromString(typeString);
- addInstantiatedContainersAndSmartPointers(type, type->originalTypeDescription());
- }
- start = end;
- }
-}
-
-bool ShibokenGenerator::useCtorHeuristic() const
-{
- return m_useCtorHeuristic;
-}
-
-bool ShibokenGenerator::useReturnValueHeuristic() const
-{
- return m_userReturnValueHeuristic;
-}
-
-bool ShibokenGenerator::usePySideExtensions() const
-{
- return m_usePySideExtensions;
-}
-
-bool ShibokenGenerator::useIsNullAsNbNonZero() const
-{
- return m_useIsNullAsNbNonZero;
-}
-
-bool ShibokenGenerator::avoidProtectedHack() const
-{
- return m_avoidProtectedHack;
-}
-
-QString ShibokenGenerator::moduleCppPrefix(const QString &moduleName) const
- {
- QString result = moduleName.isEmpty() ? packageName() : moduleName;
- result.replace(QLatin1Char('.'), QLatin1Char('_'));
- return result;
-}
-
-QString ShibokenGenerator::cppApiVariableName(const QString &moduleName) const
-{
- return QLatin1String("Sbk") + moduleCppPrefix(moduleName)
- + QLatin1String("Types");
-}
-
-QString ShibokenGenerator::pythonModuleObjectName(const QString &moduleName) const
-{
- return QLatin1String("Sbk") + moduleCppPrefix(moduleName)
- + QLatin1String("ModuleObject");
-}
-
-QString ShibokenGenerator::convertersVariableName(const QString &moduleName) const
-{
- QString result = cppApiVariableName(moduleName);
- result.chop(1);
- result.append(QLatin1String("Converters"));
- return result;
-}
-
-static QString processInstantiationsVariableName(const AbstractMetaType *type)
-{
- QString res = QLatin1Char('_') + _fixedCppTypeName(type->typeEntry()->qualifiedCppName()).toUpper();
- const AbstractMetaTypeList &instantiations = type->instantiations();
- for (const AbstractMetaType *instantiation : instantiations) {
- res += instantiation->isContainer()
- ? processInstantiationsVariableName(instantiation)
- : QLatin1Char('_') + _fixedCppTypeName(instantiation->cppSignature()).toUpper();
- }
- return res;
-}
-
-static void appendIndexSuffix(QString *s)
-{
- if (!s->endsWith(QLatin1Char('_')))
- s->append(QLatin1Char('_'));
- s->append(QStringLiteral("IDX"));
-}
-
-QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClass *metaClass, bool alternativeTemplateName)
-{
- if (alternativeTemplateName) {
- const AbstractMetaClass *templateBaseClass = metaClass->templateBaseClass();
- if (!templateBaseClass)
- return QString();
- QString result = QLatin1String("SBK_")
- + _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper();
- const AbstractMetaTypeList &templateBaseClassInstantiations = metaClass->templateBaseClassInstantiations();
- for (const AbstractMetaType *instantiation : templateBaseClassInstantiations)
- result += processInstantiationsVariableName(instantiation);
- appendIndexSuffix(&result);
- return result;
- }
- return getTypeIndexVariableName(metaClass->typeEntry());
-}
-QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry *type)
-{
- if (type->isCppPrimitive()) {
- const auto *trueType = static_cast<const PrimitiveTypeEntry *>(type);
- if (trueType->basicReferencedTypeEntry())
- type = trueType->basicReferencedTypeEntry();
- }
- QString result = QLatin1String("SBK_");
- // Disambiguate namespaces per module to allow for extending them.
- if (type->isNamespace()) {
- QString package = type->targetLangPackage();
- const int dot = package.lastIndexOf(QLatin1Char('.'));
- result += package.rightRef(package.size() - (dot + 1));
- }
- result += _fixedCppTypeName(type->qualifiedCppName()).toUpper();
- appendIndexSuffix(&result);
- return result;
-}
-QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType *type)
-{
- QString result = QLatin1String("SBK");
- if (type->typeEntry()->isContainer())
- result += QLatin1Char('_') + moduleName().toUpper();
- result += processInstantiationsVariableName(type);
- appendIndexSuffix(&result);
- return result;
-}
-
-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();
-}
-
-void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream &s, const AbstractMetaType *type, const QString &defaultCtor)
-{
- if (!defaultCtor.isEmpty()) {
- s << " = " << defaultCtor;
- return;
- }
- if (isCppPrimitive(type) || type->isSmartPointer())
- return;
- const auto ctor = minimalConstructor(type);
- if (ctor.isValid()) {
- s << ctor.initialization();
- } else {
- const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->cppSignature());
- qCWarning(lcShiboken()).noquote() << message;
- s << ";\n#error " << message << '\n';
- }
-}
-
-void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream &s, const TypeEntry *type, const QString &defaultCtor)
-{
- if (!defaultCtor.isEmpty()) {
- s << " = " << defaultCtor;
- return;
- }
- if (isCppPrimitive(type))
- return;
- const auto ctor = minimalConstructor(type);
- if (ctor.isValid()) {
- s << ctor.initialization();
- } else {
- const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->qualifiedCppName());
- qCWarning(lcShiboken()).noquote() << message;
- s << ";\n#error " << message << Qt::endl;
- }
-}
-
-bool ShibokenGenerator::isCppIntegralPrimitive(const TypeEntry *type)
-{
- if (!type->isCppPrimitive())
- return false;
- const auto *trueType = static_cast<const PrimitiveTypeEntry *>(type);
- if (trueType->basicReferencedTypeEntry())
- trueType = trueType->basicReferencedTypeEntry();
- QString typeName = trueType->qualifiedCppName();
- return !typeName.contains(QLatin1String("double"))
- && !typeName.contains(QLatin1String("float"))
- && !typeName.contains(QLatin1String("wchar"));
-}
-bool ShibokenGenerator::isCppIntegralPrimitive(const AbstractMetaType *type)
-{
- return isCppIntegralPrimitive(type->typeEntry());
-}
-
-QString ShibokenGenerator::pythonArgsAt(int i)
-{
- return QLatin1String(PYTHON_ARGS) + QLatin1Char('[')
- + QString::number(i) + QLatin1Char(']');
-}
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
deleted file mode 100644
index 4501b902d..000000000
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.h
+++ /dev/null
@@ -1,546 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef SHIBOKENGENERATOR_H
-#define SHIBOKENGENERATOR_H
-
-extern const char *CPP_ARG;
-extern const char *CPP_ARG_REMOVED;
-extern const char *CPP_RETURN_VAR;
-extern const char *CPP_SELF_VAR;
-extern const char *NULL_PTR;
-extern const char *PYTHON_ARG;
-extern const char *PYTHON_ARGS;
-extern const char *PYTHON_OVERRIDE_VAR;
-extern const char *PYTHON_RETURN_VAR;
-extern const char *PYTHON_TO_CPP_VAR;
-extern const char *SMART_POINTER_GETTER;
-
-extern const char *CONV_RULE_OUT_VAR_SUFFIX;
-extern const char *BEGIN_ALLOW_THREADS;
-extern const char *END_ALLOW_THREADS;
-
-#include <generator.h>
-
-#include "typesystem.h"
-
-#include <QtCore/QRegularExpression>
-
-class DocParser;
-class CodeSnip;
-class OverloadData;
-struct GeneratorClassInfoCacheEntry;
-
-QT_FORWARD_DECLARE_CLASS(QTextStream)
-
-/**
- * Abstract generator that contains common methods used in CppGenerator and HeaderGenerator.
- */
-class ShibokenGenerator : public Generator
-{
-public:
- using FunctionGroups = QMap<QString, AbstractMetaFunctionList>; // Sorted
-
- ShibokenGenerator();
- ~ShibokenGenerator() override;
-
- const char *name() const override { return "Shiboken"; }
-
- /// Returns a list of all ancestor classes for the given class.
- AbstractMetaClassList getAllAncestors(const AbstractMetaClass *metaClass) const;
-
-protected:
- bool doSetup() override;
-
- void writeArgumentNames(QTextStream &s,
- const AbstractMetaFunction *func,
- Options options = NoOption) const override;
-
- /**
- * 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 override;
-
- /**
- * Returns a map with all functions grouped, the function name is used as key.
- * Example of return value: { "foo" -> ["foo(int)", "foo(int, long)], "bar" -> "bar(double)"}
- * \param scope Where to search for functions, null means all global functions.
- */
- FunctionGroups getGlobalFunctionGroups() const;
- static FunctionGroups getFunctionGroups(const AbstractMetaClass *scope);
-
- /**
- * Returns all different inherited overloads of func, and includes func as well.
- * The function can be called multiple times without duplication.
- * \param func the metafunction to be searched in subclasses.
- * \param seen the function's minimal signatures already seen.
- */
- AbstractMetaFunctionList getFunctionAndInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen);
-
- /// Write user's custom code snippets at class or module level.
- void writeCodeSnips(QTextStream &s,
- const QVector<CodeSnip> & codeSnips,
- TypeSystem::CodeSnipPosition position,
- TypeSystem::Language language,
- const AbstractMetaClass *context = nullptr);
- /// Write user's custom code snippets at function level.
- void writeCodeSnips(QTextStream &s,
- const QVector<CodeSnip> & codeSnips,
- TypeSystem::CodeSnipPosition position,
- TypeSystem::Language language,
- const AbstractMetaFunction *func,
- const AbstractMetaArgument *lastArg = nullptr);
-
- /// Replaces variables for the user's custom code at global or class level.
- void processCodeSnip(QString &code, const AbstractMetaClass *context = nullptr);
-
- /**
- * 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,
- const QString &prepend = QString(),
- const QString &append = QString(),
- Options options = NoOption,
- int arg_count = -1) const;
-
- /// Returns the top-most class that has multiple inheritance in the ancestry.
- static const AbstractMetaClass *getMultipleInheritingClass(const AbstractMetaClass *metaClass);
-
- /// Returns true if the class needs to have a getattro function.
- bool classNeedsGetattroFunction(const AbstractMetaClass *metaClass);
-
- /// Returns true if the class needs to have a setattro function.
- bool classNeedsSetattroFunction(const AbstractMetaClass *metaClass);
-
- /// Returns a list of methods of the given class where each one is part of a different overload with both static and non-static method.
- AbstractMetaFunctionList getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass *metaClass);
-
- /// Returns a list of parent classes for a given class.
- AbstractMetaClassList getBaseClasses(const AbstractMetaClass *metaClass) const;
-
- 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 nullptr 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);
-
- QString wrapperName(const AbstractMetaClass *metaClass) const;
- QString wrapperName(const AbstractMetaType *metaType) const;
-
- QString fullPythonClassName(const AbstractMetaClass *metaClass);
- 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(const QString &cppOpFuncName);
- static QString pythonOperatorFunctionName(const AbstractMetaFunction *func);
- static QString pythonRichCompareOperatorId(const QString &cppOpFuncName);
- static QString pythonRichCompareOperatorId(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(const 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);
-
- /**
- * 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 nullptr, is \p type is a Python type.
- * \return A custom check if \p type is a custom type, or an empty string if \p metaType
- * receives an existing type object.
- */
- QString guessCPythonCheckFunction(const QString &type, AbstractMetaType **metaType);
- QString cpythonIsConvertibleFunction(const TypeEntry *type, bool genericNumberType = false, bool checkExact = false);
- QString cpythonIsConvertibleFunction(const AbstractMetaType *metaType, bool genericNumberType = false);
- QString cpythonIsConvertibleFunction(const AbstractMetaArgument *metaArg, bool genericNumberType = false);
-
- QString cpythonToCppConversionFunction(const AbstractMetaClass *metaClass);
- QString cpythonToCppConversionFunction(const AbstractMetaType *type, const AbstractMetaClass *context = nullptr);
- QString cpythonToPythonConversionFunction(const AbstractMetaType *type, const AbstractMetaClass *context = nullptr);
- 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,
- const QString &argName = QLatin1String("self"));
- QString cpythonWrapperCPtr(const AbstractMetaType *metaType, const QString &argName);
- QString cpythonWrapperCPtr(const TypeEntry *type, const QString &argName);
-
- /// Guesses the scope to where belongs an argument's default value.
- QString guessScopeForDefaultValue(const AbstractMetaFunction *func,
- const AbstractMetaArgument *arg) const;
- QString guessScopeForDefaultFlagsValue(const AbstractMetaFunction *func,
- const AbstractMetaArgument *arg,
- const QString &value) const;
-
- QString cpythonEnumName(const EnumTypeEntry *enumEntry);
- QString cpythonEnumName(const AbstractMetaEnum *metaEnum);
-
- QString cpythonFlagsName(const FlagsTypeEntry *flagsEntry);
- QString cpythonFlagsName(const AbstractMetaEnum *metaEnum);
- /// Returns the special cast function name, the function used to proper cast class with multiple inheritance.
- QString cpythonSpecialCastFunctionName(const AbstractMetaClass *metaClass);
-
- QString 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;
-
- OptionDescriptions options() const override;
- bool handleOption(const QString &key, const QString &value) override;
-
- /// 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 pythonModuleObjectName(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 nullptr 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 nullptr pointer in case of failure.
- */
- AbstractMetaType *buildAbstractMetaTypeFromString(QString typeSignature,
- QString *errorMessage = nullptr);
-
- /// 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());
-
- void collectContainerTypesFromConverterMacros(const QString &code, bool toPythonMacro);
- // verify whether the class is copyable
- bool isCopyable(const AbstractMetaClass *metaClass);
-
- void clearTpFuncs();
-
-
- /// 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.
- using ExtendedConverterData = QHash<const TypeEntry *, QVector<const AbstractMetaClass *> >;
- /// 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.
- QVector<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;
-
- const QRegularExpression &convertToCppRegEx() const
- { return m_typeSystemConvRegEx[TypeSystemToCppFunction]; }
-
- static QString pythonArgsAt(int i);
-
- 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;
-
-private:
- static const GeneratorClassInfoCacheEntry &getGeneratorClassInfo(const AbstractMetaClass *scope);
- static FunctionGroups getFunctionGroupsImpl(const AbstractMetaClass *scope);
- static bool classNeedsGetattroFunctionImpl(const AbstractMetaClass *metaClass);
-
- QString translateTypeForWrapperMethod(const AbstractMetaType *cType,
- const AbstractMetaClass *context,
- Options opt = NoOption) const;
-
- /**
- * Returns all different inherited overloads of func.
- * The function can be called multiple times without duplication.
- * \param func the metafunction to be searched in subclasses.
- * \param seen the function's minimal signatures already seen.
- */
- AbstractMetaFunctionList getInheritedOverloads(const AbstractMetaFunction *func,
- QSet<QString> *seen);
-
- /**
- * Returns all 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);
- /**
- * 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;
-
- QString functionReturnType(const AbstractMetaFunction *func, Options options = NoOption) const;
-
- /// Utility function for writeCodeSnips.
- using ArgumentVarReplacementPair = QPair<const AbstractMetaArgument *, QString>;
- using ArgumentVarReplacementList = QVector<ArgumentVarReplacementPair>;
- ArgumentVarReplacementList getArgumentReplacement(const AbstractMetaFunction* func,
- bool usePyArgs, TypeSystem::Language language,
- const AbstractMetaArgument *lastArg);
-
- /// Returns a string with the user's custom code snippets that comply with \p position and \p language.
- QString getCodeSnippets(const QVector<CodeSnip> & codeSnips,
- TypeSystem::CodeSnipPosition position,
- TypeSystem::Language language);
-
- enum TypeSystemConverterVariable {
- TypeSystemCheckFunction = 0,
- TypeSystemIsConvertibleFunction,
- TypeSystemToCppFunction,
- TypeSystemToPythonFunction,
- TypeSystemConverterVariables
- };
- void replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString &code);
-
- /// 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);
- }
-
- /// Return a prefix with '_' suitable for names in C++
- QString moduleCppPrefix(const QString &moduleName = QString()) const;
-
- bool m_useCtorHeuristic = false;
- bool m_userReturnValueHeuristic = false;
- bool m_usePySideExtensions = false;
- bool m_verboseErrorMessagesDisabled = false;
- bool m_useIsNullAsNbNonZero = false;
- bool m_avoidProtectedHack = false;
-
- using AbstractMetaTypeCache = QHash<QString, AbstractMetaType *>;
- AbstractMetaTypeCache m_metaTypeFromStringCache;
-
- /// Type system converter variable replacement names and regular expressions.
- QString m_typeSystemConvName[TypeSystemConverterVariables];
- QRegularExpression m_typeSystemConvRegEx[TypeSystemConverterVariables];
-};
-
-#endif // SHIBOKENGENERATOR_H
diff --git a/sources/shiboken2/generator/shibokenconfig.h.in b/sources/shiboken2/generator/shibokenconfig.h.in
deleted file mode 100644
index 2c86a4a3c..000000000
--- a/sources/shiboken2/generator/shibokenconfig.h.in
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef SHIBOKENCONFIG_H
-#define SHIBOKENCONFIG_H
-
-#define SHIBOKEN_VERSION "@shiboken2_VERSION@"
-
-#endif