diff options
Diffstat (limited to 'sources/shiboken2/generator')
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(¤tColData); - 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(¯os); - 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("<")); - s.replace(QLatin1Char('>'), QLatin1String(">")); - s.replace(QLatin1Char('&'), QLatin1String("&")); - 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\"><<"; - if (rfunc->isAbstract()) - s << "pure "; - s << "virtual>></font>"; - } - s << "</td></tr>"; - - // Function return type - s << "<tr><td bgcolor=\"gray\" align=\"right\">original type</td><td bgcolor=\"gray\" align=\"left\">"; - if (rfunc->type()) - s << 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 |