aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/generator
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6/generator')
-rw-r--r--sources/shiboken6/generator/CMakeLists.txt78
-rw-r--r--sources/shiboken6/generator/_config.py.in1
-rw-r--r--sources/shiboken6/generator/defaultvalue.cpp120
-rw-r--r--sources/shiboken6/generator/defaultvalue.h46
-rw-r--r--sources/shiboken6/generator/generator.cpp657
-rw-r--r--sources/shiboken6/generator/generator.h256
-rw-r--r--sources/shiboken6/generator/generatorcontext.cpp38
-rw-r--r--sources/shiboken6/generator/generatorcontext.h56
-rw-r--r--sources/shiboken6/generator/main.cpp883
-rw-r--r--sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp1513
-rw-r--r--sources/shiboken6/generator/qtdoc/qtdocgenerator.h123
-rw-r--r--sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp984
-rw-r--r--sources/shiboken6/generator/qtdoc/qtxmltosphinx.h108
-rw-r--r--sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h62
-rw-r--r--sources/shiboken6/generator/qtdoc/rstformat.h55
-rw-r--r--sources/shiboken6/generator/shiboken/configurablescope.h33
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator.cpp6675
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator.h552
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator_container.cpp272
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp476
-rw-r--r--sources/shiboken6/generator/shiboken/ctypenames.h69
-rw-r--r--sources/shiboken6/generator/shiboken/generatorargument.cpp110
-rw-r--r--sources/shiboken6/generator/shiboken/generatorargument.h60
-rw-r--r--sources/shiboken6/generator/shiboken/generatorstrings.h39
-rw-r--r--sources/shiboken6/generator/shiboken/headergenerator.cpp962
-rw-r--r--sources/shiboken6/generator/shiboken/headergenerator.h84
-rw-r--r--sources/shiboken6/generator/shiboken/overloaddata.cpp879
-rw-r--r--sources/shiboken6/generator/shiboken/overloaddata.h214
-rw-r--r--sources/shiboken6/generator/shiboken/pytypenames.h56
-rw-r--r--sources/shiboken6/generator/shiboken/shibokengenerator.cpp2540
-rw-r--r--sources/shiboken6/generator/shiboken/shibokengenerator.h402
31 files changed, 10093 insertions, 8310 deletions
diff --git a/sources/shiboken6/generator/CMakeLists.txt b/sources/shiboken6/generator/CMakeLists.txt
index 0296138e5..aebe2cd5e 100644
--- a/sources/shiboken6/generator/CMakeLists.txt
+++ b/sources/shiboken6/generator/CMakeLists.txt
@@ -1,17 +1,46 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
project(shibokengenerator)
+set(package_name "Shiboken6Tools")
+
+set(CMAKE_AUTOMOC ON)
+
+if(NOT (Qt${QT_MAJOR_VERSION}Core_FOUND AND Python_Interpreter_FOUND))
+ message(WARNING "Some dependencies were not found: shiboken6 generator compilation disabled!")
+ return()
+endif()
set(shiboken6_SRC
-generator.cpp
-shiboken/cppgenerator.cpp
-shiboken/headergenerator.cpp
-shiboken/overloaddata.cpp
-shiboken/shibokengenerator.cpp
+defaultvalue.cpp defaultvalue.h
+generator.cpp generator.h
+generatorcontext.cpp generatorcontext.h
main.cpp
+shiboken/configurablescope.h
+shiboken/cppgenerator.cpp shiboken/cppgenerator.h
+shiboken/cppgenerator_container.cpp
+shiboken/cppgenerator_smartpointer.cpp
+shiboken/ctypenames.h
+shiboken/generatorargument.cpp shiboken/generatorargument.h shiboken/generatorstrings.h
+shiboken/headergenerator.cpp shiboken/headergenerator.h
+shiboken/overloaddata.cpp shiboken/overloaddata.h
+shiboken/pytypenames.h
+shiboken/shibokengenerator.cpp shiboken/shibokengenerator.h
)
+find_libclang()
+
+if(${STANDALONE})
+ list(APPEND CMAKE_INSTALL_RPATH ${base}/Qt/lib)
+else()
+ list(APPEND CMAKE_INSTALL_RPATH ${QT6_INSTALL_PREFIX}/${QT6_INSTALL_LIBS}
+ ${libclang_lib_dir})
+endif()
+
add_executable(shiboken6 ${shiboken6_SRC})
add_executable(Shiboken6::shiboken6 ALIAS shiboken6)
add_dependencies(shiboken6 apiextractor)
+
set_target_properties(shiboken6 PROPERTIES OUTPUT_NAME shiboken6${shiboken6_SUFFIX})
target_include_directories(shiboken6 PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/shiboken
@@ -20,17 +49,24 @@ target_include_directories(shiboken6 PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
${apiextractor_SOURCE_DIR}
)
-target_link_libraries(shiboken6 apiextractor Qt${QT_MAJOR_VERSION}::Core)
+target_link_libraries(shiboken6 apiextractor Qt::Core)
if (NOT DISABLE_DOCSTRINGS)
- target_sources(shiboken6 PRIVATE qtdoc/qtxmltosphinx.cpp qtdoc/qtdocgenerator.cpp)
- target_compile_definitions(shiboken6 PUBLIC DOCSTRINGS_ENABLED)
+ target_sources(shiboken6 PRIVATE
+ qtdoc/qtdocgenerator.cpp qtdoc/qtdocgenerator.h
+ qtdoc/qtxmltosphinx.cpp qtdoc/qtxmltosphinx.h
+ qtdoc/qtxmltosphinxinterface.h
+ qtdoc/rstformat.h)
+ target_compile_definitions(shiboken6 PUBLIC DOCSTRINGS_ENABLED QT_LEAN_HEADERS=1)
endif()
configure_file(shibokenconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/shibokenconfig.h" @ONLY)
install(TARGETS shiboken6
- EXPORT Shiboken6Targets
- DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
+ EXPORT "${package_name}Targets"
+ DESTINATION "bin")
+install(EXPORT "${package_name}Targets"
+ NAMESPACE "Shiboken6::"
+ DESTINATION ${LIB_INSTALL_DIR}/cmake/${package_name})
set(shiboken_generator_package_name "shiboken6_generator")
@@ -61,3 +97,25 @@ configure_file("${shiboken_version_path}"
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_git_shiboken_generator_version.py"
DESTINATION "${PYTHON_SITE_PACKAGES}/${shiboken_generator_package_name}")
+
+include(CMakePackageConfigHelpers)
+
+# Single build-tree and install-tree Config file. There's no need for separate ones because we
+# don't specify any PATH_VARS, so the relative path of PACKAGE_PREFIX_DIR does not really matter.
+configure_package_config_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/../data/${package_name}Config.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/${package_name}Config.cmake"
+ INSTALL_DESTINATION "${LIB_INSTALL_DIR}/cmake/${package_name}"
+)
+write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/${package_name}ConfigVersion.cmake"
+ VERSION "${shiboken6_VERSION}"
+ COMPATIBILITY AnyNewerVersion
+ ARCH_INDEPENDENT
+)
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${package_name}Config.cmake"
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/${package_name}")
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${package_name}ConfigVersion.cmake"
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/${package_name}")
diff --git a/sources/shiboken6/generator/_config.py.in b/sources/shiboken6/generator/_config.py.in
index 985735fa4..ed7e67098 100644
--- a/sources/shiboken6/generator/_config.py.in
+++ b/sources/shiboken6/generator/_config.py.in
@@ -7,3 +7,4 @@ version_info = (@shiboken_MAJOR_VERSION@, @shiboken_MINOR_VERSION@, @shiboken_MI
@PACKAGE_BUILD_COMMIT_HASH_DESCRIBED@
@PACKAGE_SETUP_PY_PACKAGE_TIMESTAMP_ASSIGNMENT@
@PACKAGE_SETUP_PY_PACKAGE_VERSION_ASSIGNMENT@
+@QT_MACOS_DEPLOYMENT_TARGET@
diff --git a/sources/shiboken6/generator/defaultvalue.cpp b/sources/shiboken6/generator/defaultvalue.cpp
new file mode 100644
index 000000000..89cc9fa77
--- /dev/null
+++ b/sources/shiboken6/generator/defaultvalue.cpp
@@ -0,0 +1,120 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "defaultvalue.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
+
+using namespace Qt::StringLiterals;
+
+// 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::Boolean:
+ return u"false"_s;
+ case DefaultValue::CppScalar:
+ return u"0"_s;
+ case DefaultValue::Custom:
+ case DefaultValue::Enum:
+ return m_value;
+ case DefaultValue::Pointer:
+ return u"nullptr"_s;
+ case DefaultValue::Void:
+ return {};
+ case DefaultValue::DefaultConstructorWithDefaultValues:
+ return m_value + u"()"_s;
+ case DefaultValue::DefaultConstructor:
+ break;
+ }
+ return u"{}"_s;
+}
+
+QString DefaultValue::initialization() const
+{
+ switch (m_type) {
+ case DefaultValue::Boolean:
+ return u"{false}"_s;
+ case DefaultValue::CppScalar:
+ return u"{0}"_s;
+ case DefaultValue::Custom:
+ return u" = "_s + m_value;
+ case DefaultValue::Enum:
+ return u'{' + m_value + u'}';
+ case DefaultValue::Pointer:
+ return u"{nullptr}"_s;
+ case DefaultValue::Void:
+ Q_ASSERT(false);
+ break;
+ case DefaultValue::DefaultConstructor:
+ case DefaultValue::DefaultConstructorWithDefaultValues:
+ break;
+ }
+ return {};
+}
+
+QString DefaultValue::constructorParameter() const
+{
+ switch (m_type) {
+ case DefaultValue::Boolean:
+ return u"false"_s;
+ case DefaultValue::CppScalar: {
+ // PYSIDE-846: Use static_cast in case of "unsigned long" and similar
+ const QString cast = m_value.contains(u' ')
+ ? u"static_cast<"_s + m_value + u'>'
+ : m_value;
+ return cast + u"(0)"_s;
+ }
+ 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 u"static_cast<"_s + m_value + u"*>(nullptr)"_s;
+ case DefaultValue::Void:
+ Q_ASSERT(false);
+ break;
+ case DefaultValue::DefaultConstructor:
+ case DefaultValue::DefaultConstructorWithDefaultValues:
+ break;
+ }
+ return m_value + u"()"_s;
+}
+
+QDebug operator<<(QDebug debug, const DefaultValue &v)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "DefaultValue(" << v.type() << ", \"" << v.value() << "\")";
+ return debug;
+}
diff --git a/sources/shiboken6/generator/defaultvalue.h b/sources/shiboken6/generator/defaultvalue.h
new file mode 100644
index 000000000..d518d134f
--- /dev/null
+++ b/sources/shiboken6/generator/defaultvalue.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef DEFAULTVALUE_H
+#define DEFAULTVALUE_H
+
+#include <QtCore/QString>
+
+QT_FORWARD_DECLARE_CLASS(QDebug);
+
+class DefaultValue
+{
+public:
+ enum Type
+ {
+ 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, QString value = QString());
+ explicit DefaultValue(QString customValue);
+
+ 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;
+};
+
+QDebug operator<<(QDebug debug, const DefaultValue &v);
+
+#endif // DEFAULTVALUE_H
diff --git a/sources/shiboken6/generator/generator.cpp b/sources/shiboken6/generator/generator.cpp
index a50666252..a01326530 100644
--- a/sources/shiboken6/generator/generator.cpp
+++ b/sources/shiboken6/generator/generator.cpp
@@ -1,171 +1,43 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "generator.h"
+#include "defaultvalue.h"
+#include "generatorcontext.h"
#include "apiextractorresult.h"
-#include "ctypenames.h"
+#include "abstractmetaargument.h"
#include "abstractmetaenum.h"
-#include "abstractmetafield.h"
#include "abstractmetafunction.h"
#include "abstractmetalang.h"
-#include "parser/codemodel.h"
#include "messages.h"
+#include <optionsparser.h>
#include "reporthandler.h"
#include "fileout.h"
-#include "apiextractor.h"
-#include "typesystem.h"
+#include "arraytypeentry.h"
+#include "enumtypeentry.h"
+#include "enumvaluetypeentry.h"
+#include "namespacetypeentry.h"
+#include "primitivetypeentry.h"
+#include "typesystemtypeentry.h"
+#include <typedatabase.h>
+
+#include "qtcompat.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::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::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::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("()");
-}
+using namespace Qt::StringLiterals;
-#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug debug, const DefaultValue &v)
-{
- QDebugStateSaver saver(debug);
- debug.noquote();
- debug.nospace();
- debug << "DefaultValue(" << v.type() << ", \"" << v.value() << "\")";
- return debug;
-}
-#endif // !QT_NO_DEBUG_STREAM
+static constexpr auto ENABLE_PYSIDE_EXTENSIONS = "enable-pyside-extensions"_L1;
+static constexpr auto AVOID_PROTECTED_HACK = "avoid-protected-hack"_L1;
-QString GeneratorContext::smartPointerWrapperName() const
+struct GeneratorOptions
{
- Q_ASSERT(m_type == SmartPointer);
- return m_preciseClassType.cppSignature();
-}
+ bool usePySideExtensions = false;
+ bool avoidProtectedHack = false;
+};
struct Generator::GeneratorPrivate
{
@@ -173,13 +45,16 @@ struct Generator::GeneratorPrivate
QString outDir;
// License comment
QString licenseComment;
- QStringList instantiatedContainersNames;
- AbstractMetaTypeList instantiatedContainers;
- AbstractMetaTypeList instantiatedSmartPointers;
AbstractMetaClassCList m_invisibleTopNamespaces;
bool m_hasPrivateClasses = false;
+ static GeneratorOptions m_options;
};
+GeneratorOptions Generator::GeneratorPrivate::m_options;
+
+// Kept as a variable for a potential Qt-in-namespace support
+QString Generator::m_gsp = "::"_L1;
+
Generator::Generator() : m_d(new GeneratorPrivate)
{
}
@@ -193,17 +68,19 @@ bool Generator::setup(const ApiExtractorResult &api)
{
m_d->api = api;
const auto moduleEntry = TypeDatabase::instance()->defaultTypeSystemType();
- if (!moduleEntry || !moduleEntry->generateCode()) {
- qCWarning(lcShiboken) << "Couldn't find the package name!!";
+ if (!moduleEntry) {
+ qCWarning(lcShiboken,"Couldn't find the package name!!");
+ return false;
+ }
+ if (!moduleEntry->generateCode()) {
+ qCWarning(lcShiboken, "Code generation of root typesystem is disabled!!");
return false;
}
- collectInstantiatedContainersAndSmartPointers();
-
- for (auto c : api.classes()) {
+ for (const auto &c : api.classes()) {
if (c->enclosingClass() == nullptr && c->isInvisibleNamespace()) {
m_d->m_invisibleTopNamespaces.append(c);
- c->invisibleNamespaceRecursion([&](AbstractMetaClass *ic) {
+ c->invisibleNamespaceRecursion([&](const AbstractMetaClassCPtr &ic) {
m_d->m_invisibleTopNamespaces.append(ic);
});
}
@@ -212,150 +89,65 @@ bool Generator::setup(const ApiExtractorResult &api)
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)
-AbstractMetaType canonicalSmartPtrInstantiation(const AbstractMetaType &type)
-{
- const 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;
- fixedType.setReferenceType(NoReference);
- fixedType.setConstant(false);
- if (pointeeNeedsFix) {
- auto fixedPointeeType = instantiations.constFirst();
- fixedPointeeType.setConstant(false);
- fixedType.setInstantiations(AbstractMetaTypeList(1, fixedPointeeType));
- }
- return fixedType;
-}
-
-static inline const TypeEntry *pointeeTypeEntry(const AbstractMetaType &smartPtrType)
+QList<OptionDescription> Generator::options()
{
- return smartPtrType.instantiations().constFirst().typeEntry();
+ return {
+ {AVOID_PROTECTED_HACK,
+ u"Avoid the use of the '#define protected public' hack."_s},
+ {ENABLE_PYSIDE_EXTENSIONS,
+ u"Enable PySide extensions, such as support for signal/slots,\n"
+ "use this if you are creating a binding for a Qt-based library."_s}
+ };
}
-void Generator::addInstantiatedContainersAndSmartPointers(const AbstractMetaType &type,
- const QString &context)
+class GeneratorOptionsParser : public OptionsParser
{
- for (const auto &t : type.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: ") + context);
-
- qCWarning(lcShiboken).noquote().nospace() << warning;
- return;
-
- }
- if (isContainer) {
- const QString typeName = getSimplifiedContainerTypeName(type);
- if (!m_d->instantiatedContainersNames.contains(typeName)) {
- m_d->instantiatedContainersNames.append(typeName);
- auto simplifiedType = type;
- simplifiedType.setIndirections(0);
- simplifiedType.setConstant(false);
- simplifiedType.setReferenceType(NoReference);
- simplifiedType.decideUsagePattern();
- m_d->instantiatedContainers.append(simplifiedType);
- }
- return;
- }
+public:
+ explicit GeneratorOptionsParser(GeneratorOptions *o) : m_options(o) {}
- // Is smart pointer. Check if the (const?) pointee is already known for the given
- // smart pointer type entry.
- auto pt = pointeeTypeEntry(type);
- const bool present =
- std::any_of(m_d->instantiatedSmartPointers.cbegin(), m_d->instantiatedSmartPointers.cend(),
- [typeEntry, pt] (const AbstractMetaType &t) {
- return t.typeEntry() == typeEntry && pointeeTypeEntry(t) == pt;
- });
- if (!present)
- m_d->instantiatedSmartPointers.append(canonicalSmartPtrInstantiation(type));
-}
-
-void Generator::collectInstantiatedContainersAndSmartPointers(const AbstractMetaFunctionCPtr &func)
-{
- addInstantiatedContainersAndSmartPointers(func->type(), func->signature());
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (const AbstractMetaArgument &arg : arguments)
- addInstantiatedContainersAndSmartPointers(arg.type(), func->signature());
-}
+ bool handleBoolOption(const QString &key, OptionSource source) override;
-void Generator::collectInstantiatedContainersAndSmartPointers(const AbstractMetaClass *metaClass)
-{
- if (!metaClass->typeEntry()->generateCode())
- return;
- for (const auto &func : metaClass->functions())
- collectInstantiatedContainersAndSmartPointers(func);
- for (const AbstractMetaField &field : metaClass->fields())
- addInstantiatedContainersAndSmartPointers(field.type(), field.name());
- const AbstractMetaClassList &innerClasses = metaClass->innerClasses();
- for (AbstractMetaClass *innerClass : innerClasses)
- collectInstantiatedContainersAndSmartPointers(innerClass);
-}
+private:
+ GeneratorOptions *m_options;
+};
-void Generator::collectInstantiatedContainersAndSmartPointers()
+bool GeneratorOptionsParser::handleBoolOption(const QString & key, OptionSource source)
{
- for (const auto &func : m_d->api.globalFunctions())
- collectInstantiatedContainersAndSmartPointers(func);
- for (auto metaClass : m_d->api.classes())
- collectInstantiatedContainersAndSmartPointers(metaClass);
+ if (source == OptionSource::CommandLineSingleDash)
+ return false;
+ if (key == ENABLE_PYSIDE_EXTENSIONS)
+ return ( m_options->usePySideExtensions = true);
+ if (key == AVOID_PROTECTED_HACK)
+ return ( m_options->avoidProtectedHack = true);
+ return false;
}
-AbstractMetaTypeList Generator::instantiatedContainers() const
+std::shared_ptr<OptionsParser> Generator::createOptionsParser()
{
- return m_d->instantiatedContainers;
+ return std::make_shared<GeneratorOptionsParser>(&GeneratorPrivate::m_options);
}
-AbstractMetaTypeList Generator::instantiatedSmartPointers() const
-{
- return m_d->instantiatedSmartPointers;
-}
+QString Generator::fileNameForContextHelper(const GeneratorContext &context,
+ const QString &suffix,
+ FileNameFlags flags)
-Generator::OptionDescriptions Generator::options() const
{
- return OptionDescriptions();
-}
+ if (!context.forSmartPointer()) {
+ const auto metaClass = context.metaClass();
+ QString fileNameBase = flags.testFlag(FileNameFlag::UnqualifiedName)
+ ? metaClass->name() : metaClass->qualifiedCppName();
+ if (!flags.testFlag(FileNameFlag::KeepCase))
+ fileNameBase = fileNameBase.toLower();
+ fileNameBase.replace(u"::"_s, u"_"_s);
+ return fileNameBase + suffix;
+ }
-bool Generator::handleOption(const QString & /* key */, const QString & /* value */)
-{
- return false;
+ // FIXME: PYSIDE7: Use the above code path for all types. Note the file
+ // names will then change to reflect the namespaces of the pointee
+ // (smart/integer2).
+ const AbstractMetaType &smartPointerType = context.preciseType();
+ QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType);
+ return fileNameBase + suffix;
}
const AbstractMetaClassCList &Generator::invisibleTopNamespaces() const
@@ -363,12 +155,12 @@ const AbstractMetaClassCList &Generator::invisibleTopNamespaces() const
return m_d->m_invisibleTopNamespaces;
}
-PrimitiveTypeEntryList Generator::primitiveTypes()
+PrimitiveTypeEntryCList Generator::primitiveTypes()
{
return TypeDatabase::instance()->primitiveTypes();
}
-ContainerTypeEntryList Generator::containerTypes()
+ContainerTypeEntryCList Generator::containerTypes()
{
return TypeDatabase::instance()->containerTypes();
}
@@ -391,7 +183,7 @@ QString Generator::packageName()
static QString getModuleName()
{
QString result = TypeDatabase::instance()->defaultPackageName();
- result.remove(0, result.lastIndexOf(QLatin1Char('.')) + 1);
+ result.remove(0, result.lastIndexOf(u'.') + 1);
return result;
}
@@ -413,17 +205,19 @@ void Generator::setOutputDirectory(const QString &outDir)
bool Generator::generateFileForContext(const GeneratorContext &context)
{
- const AbstractMetaClass *cls = context.metaClass();
+ const auto cls = context.metaClass();
+ auto typeEntry = cls->typeEntry();
- if (!shouldGenerate(cls))
+ if (!shouldGenerate(typeEntry))
return true;
const QString fileName = fileNameForContext(context);
if (fileName.isEmpty())
return true;
- QString filePath = outputDirectory() + QLatin1Char('/') + subDirectoryForClass(cls)
- + QLatin1Char('/') + fileName;
+ QString filePath = outputDirectory() + u'/'
+ + subDirectoryForPackage(typeEntry->targetLangPackage())
+ + u'/' + fileName;
FileOut fileOut(filePath);
generateClass(fileOut.stream, context);
@@ -432,109 +226,101 @@ bool Generator::generateFileForContext(const GeneratorContext &context)
return true;
}
-QString Generator::getFileNameBaseForSmartPointer(const AbstractMetaType &smartPointerType,
- const AbstractMetaClass *smartPointerClass)
+QString Generator::getFileNameBaseForSmartPointer(const AbstractMetaType &smartPointerType)
{
const AbstractMetaType innerType = smartPointerType.getSmartPointerInnerType();
- QString fileName = smartPointerClass->qualifiedCppName().toLower();
- fileName.replace(QLatin1String("::"), QLatin1String("_"));
- fileName.append(QLatin1String("_"));
+ smartPointerType.typeEntry()->qualifiedCppName();
+ QString fileName = smartPointerType.typeEntry()->qualifiedCppName().toLower();
+ fileName.append(u'_');
fileName.append(innerType.name().toLower());
-
+ fileName.replace(u"::"_s, u"_"_s); // std::shared_ptr<std::string>
return fileName;
}
-GeneratorContext Generator::contextForClass(const AbstractMetaClass *c) const
+GeneratorContext Generator::contextForClass(const AbstractMetaClassCPtr &c) const
{
GeneratorContext result;
result.m_metaClass = c;
return result;
}
-GeneratorContext Generator::contextForSmartPointer(const AbstractMetaClass *c,
- const AbstractMetaType &t)
+GeneratorContext
+ Generator::contextForSmartPointer(const AbstractMetaClassCPtr &c,
+ const AbstractMetaType &t,
+ const AbstractMetaClassCPtr &pointeeClass)
{
GeneratorContext result;
result.m_metaClass = c;
result.m_preciseClassType = t;
result.m_type = GeneratorContext::SmartPointer;
+ result.m_pointeeClass = pointeeClass;
return result;
}
bool Generator::generate()
{
- for (auto cls : m_d->api.classes()) {
+ for (const auto &cls : m_d->api.classes()) {
if (!generateFileForContext(contextForClass(cls)))
return false;
- if (shouldGenerate(cls) && cls->typeEntry()->isPrivate())
+ auto te = cls->typeEntry();
+ if (shouldGenerate(te) && te->isPrivate())
m_d->m_hasPrivateClasses = true;
}
- const auto smartPointers = m_d->api.smartPointers();
- for (const AbstractMetaType &type : qAsConst(m_d->instantiatedSmartPointers)) {
- const AbstractMetaClass *smartPointerClass =
- AbstractMetaClass::findClass(smartPointers, type.typeEntry());
- if (!smartPointerClass) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgCannotFindSmartPointer(type.cppSignature(),
- smartPointers)));
+ for (const auto &smp: m_d->api.instantiatedSmartPointers()) {
+ AbstractMetaClassCPtr pointeeClass;
+ const auto instantiatedType = smp.type.instantiations().constFirst().typeEntry();
+ if (instantiatedType->isComplex()) // not a C++ primitive
+ pointeeClass = AbstractMetaClass::findClass(m_d->api.classes(), instantiatedType);
+ if (!generateFileForContext(contextForSmartPointer(smp.specialized, smp.type,
+ pointeeClass))) {
return false;
}
- if (!generateFileForContext(contextForSmartPointer(smartPointerClass, type)))
- return false;
}
return finishGeneration();
}
-bool Generator::shouldGenerateTypeEntry(const TypeEntry *type)
+bool Generator::shouldGenerate(const TypeEntryCPtr &typeEntry) const
{
- return type->generateCode() && NamespaceTypeEntry::isVisibleScope(type);
+ return typeEntry->shouldGenerate();
}
-bool Generator::shouldGenerate(const AbstractMetaClass *metaClass) const
+const ApiExtractorResult &Generator::api() const
{
- return shouldGenerateTypeEntry(metaClass->typeEntry());
+ return m_d->api;
}
-void verifyDirectoryFor(const QString &file)
+bool Generator::hasPrivateClasses() const
{
- QDir dir = QFileInfo(file).absoluteDir();
- if (!dir.exists()) {
- if (!dir.mkpath(dir.absolutePath())) {
- qCWarning(lcShiboken, "Unable to create directory '%s'",
- qPrintable(QDir::toNativeSeparators(dir.absolutePath())));
- }
- }
+ return m_d->m_hasPrivateClasses;
}
-const ApiExtractorResult &Generator::api() const
+bool Generator::usePySideExtensions()
{
- return m_d->api;
+ return GeneratorPrivate::m_options.usePySideExtensions;
}
-bool Generator::hasPrivateClasses() const
+bool Generator::avoidProtectedHack()
{
- return m_d->m_hasPrivateClasses;
+ return GeneratorPrivate::m_options.avoidProtectedHack;
}
-QString Generator::getFullTypeName(const TypeEntry *type)
+QString Generator::getFullTypeName(TypeEntryCPtr type)
{
QString result = type->qualifiedCppName();
if (type->isArray())
- type = static_cast<const ArrayTypeEntry *>(type)->nestedTypeEntry();
- if (!type->isCppPrimitive())
- result.prepend(QLatin1String("::"));
- return result;
+ type = std::static_pointer_cast<const ArrayTypeEntry>(type)->nestedTypeEntry();
+ return isCppPrimitive(type) ? result : addGlobalScopePrefix(result);
}
QString Generator::getFullTypeName(const AbstractMetaType &type)
{
if (type.isCString())
- return QLatin1String("const char*");
+ return u"const char*"_s;
if (type.isVoidPointer())
- return QLatin1String("void*");
+ return u"void*"_s;
if (type.typeEntry()->isContainer())
- return QLatin1String("::") + type.cppSignature();
+ return addGlobalScopePrefix(type.cppSignature());
QString typeName;
if (type.typeEntry()->isComplex() && type.hasInstantiations())
typeName = getFullTypeNameWithoutModifiers(type);
@@ -543,17 +329,19 @@ QString Generator::getFullTypeName(const AbstractMetaType &type)
return typeName + QString::fromLatin1("*").repeated(type.indirections());
}
-QString Generator::getFullTypeName(const AbstractMetaClass *metaClass)
+QString Generator::getFullTypeName(const AbstractMetaClassCPtr &metaClass)
{
- return QLatin1String("::") + metaClass->qualifiedCppName();
+ const QString &qualName = metaClass->qualifiedCppName();
+ // Typedefs are generated into the global namespace
+ return metaClass->isTypeDef() ? qualName : addGlobalScopePrefix(qualName);
}
QString Generator::getFullTypeNameWithoutModifiers(const AbstractMetaType &type)
{
if (type.isCString())
- return QLatin1String("const char*");
+ return u"const char*"_s;
if (type.isVoidPointer())
- return QLatin1String("void*");
+ return u"void*"_s;
if (!type.hasInstantiations())
return getFullTypeName(type.typeEntry());
QString typeName = type.cppSignature();
@@ -569,9 +357,9 @@ QString Generator::getFullTypeNameWithoutModifiers(const AbstractMetaType &type)
typeName.chop(2);
break;
}
- while (typeName.endsWith(QLatin1Char('*')) || typeName.endsWith(QLatin1Char(' ')))
+ while (typeName.endsWith(u'*') || typeName.endsWith(u' '))
typeName.chop(1);
- return QLatin1String("::") + typeName;
+ return addGlobalScopePrefix(typeName);
}
std::optional<DefaultValue>
@@ -584,29 +372,29 @@ std::optional<DefaultValue>
if (type.isContainer()) {
QString ctor = type.cppSignature();
- if (ctor.endsWith(QLatin1Char('*'))) {
+ if (ctor.endsWith(u'*')) {
ctor.chop(1);
return DefaultValue(DefaultValue::Pointer, ctor.trimmed());
}
- if (ctor.startsWith(QLatin1String("const ")))
+ if (ctor.startsWith(u"const "))
ctor.remove(0, sizeof("const ") / sizeof(char) - 1);
- if (ctor.endsWith(QLatin1Char('&'))) {
+ if (ctor.endsWith(u'&')) {
ctor.chop(1);
ctor = ctor.trimmed();
}
- return DefaultValue(DefaultValue::DefaultConstructor, QLatin1String("::") + ctor);
+ return DefaultValue(DefaultValue::DefaultConstructor, u"::"_s + ctor);
}
if (type.isNativePointer())
return DefaultValue(DefaultValue::Pointer, type.typeEntry()->qualifiedCppName());
if (type.isPointer())
- return DefaultValue(DefaultValue::Pointer, QLatin1String("::") + type.typeEntry()->qualifiedCppName());
+ return DefaultValue(DefaultValue::Pointer, getFullTypeName(type.typeEntry()));
if (type.typeEntry()->isSmartPointer())
return minimalConstructor(api, type.typeEntry());
if (type.typeEntry()->isComplex()) {
- auto cType = static_cast<const ComplexTypeEntry *>(type.typeEntry());
+ auto cType = std::static_pointer_cast<const ComplexTypeEntry>(type.typeEntry());
if (cType->hasDefaultConstructor())
return DefaultValue(DefaultValue::Custom, cType->defaultConstructor());
auto klass = AbstractMetaClass::findClass(api.classes(), cType);
@@ -631,41 +419,40 @@ std::optional<DefaultValue>
std::optional<DefaultValue>
Generator::minimalConstructor(const ApiExtractorResult &api,
- const TypeEntry *type,
+ const TypeEntryCPtr &type,
QString *errorString)
{
if (!type)
return {};
- if (type->isCppPrimitive()) {
+ if (isCppPrimitive(type)) {
const QString &name = type->qualifiedCppName();
- return name == QLatin1String("bool")
+ return name == u"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())
+ const auto enumEntry = std::static_pointer_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)"));
+ "static_cast< "_L1 + getFullTypeName(type) + ">(0)"_L1);
}
if (type->isFlags()) {
return DefaultValue(DefaultValue::Custom,
- type->qualifiedCppName() + QLatin1String("(0)"));
+ type->qualifiedCppName() + u"(0)"_s);
}
if (type->isPrimitive()) {
- QString ctor = static_cast<const PrimitiveTypeEntry *>(type)->defaultConstructor();
+ QString ctor = std::static_pointer_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("::")
+ ? DefaultValue(DefaultValue::DefaultConstructorWithDefaultValues, u"::"_s
+ type->qualifiedCppName())
: DefaultValue(DefaultValue::Custom, ctor);
}
@@ -684,25 +471,25 @@ std::optional<DefaultValue>
}
if (errorString != nullptr)
- *errorString = QLatin1String("No default value could be determined.");
+ *errorString = u"No default value could be determined."_s;
return {};
}
static QString constructorCall(const QString &qualifiedCppName, const QStringList &args)
{
- return QLatin1String("::") + qualifiedCppName + QLatin1Char('(')
- + args.join(QLatin1String(", ")) + QLatin1Char(')');
+ return u"::"_s + qualifiedCppName + u'('
+ + args.join(u", "_s) + u')';
}
std::optional<DefaultValue>
Generator::minimalConstructor(const ApiExtractorResult &api,
- const AbstractMetaClass *metaClass,
+ const AbstractMetaClassCPtr &metaClass,
QString *errorString)
{
if (!metaClass)
return {};
- auto cType = static_cast<const ComplexTypeEntry *>(metaClass->typeEntry());
+ auto cType = std::static_pointer_cast<const ComplexTypeEntry>(metaClass->typeEntry());
if (cType->hasDefaultConstructor())
return DefaultValue(DefaultValue::Custom, cType->defaultConstructor());
@@ -712,27 +499,27 @@ std::optional<DefaultValue>
const auto &constructors = metaClass->queryFunctions(FunctionQueryOption::Constructors);
for (const auto &ctor : constructors) {
if (!ctor->isUserAdded() && !ctor->isPrivate()
- && ctor->functionType() == AbstractMetaFunction::ConstructorFunction) {
+ && (ctor->isPublic() || !api.flags().testFlag(ApiExtractorFlag::AvoidProtectedHack))) {
// No arguments: Default constructible
const auto &arguments = ctor->arguments();
if (arguments.isEmpty()) {
return DefaultValue(DefaultValue::DefaultConstructor,
- QLatin1String("::") + qualifiedCppName);
+ u"::"_s + qualifiedCppName);
}
// First argument has unmodified default: Default constructible with values
if (arguments.constFirst().hasUnmodifiedDefaultValueExpression()) {
return DefaultValue(DefaultValue::DefaultConstructorWithDefaultValues,
- QLatin1String("::") + qualifiedCppName);
+ u"::"_s + qualifiedCppName);
}
// Examine arguments, exclude functions taking a self parameter
bool simple = true;
bool suitable = true;
- for (int i = 0, size = arguments.size();
+ for (qsizetype 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();
+ TypeEntryCPtr aType = arg.type().typeEntry();
suitable &= aType != cType;
- simple &= aType->isCppPrimitive() || aType->isEnum() || arg.type().isPointer();
+ simple &= isCppPrimitive(aType) || aType->isEnum() || arg.type().isPointer();
}
if (suitable)
candidates.insert(arguments.size() + (simple ? 0 : 100), ctor);
@@ -742,8 +529,7 @@ std::optional<DefaultValue>
for (auto it = candidates.cbegin(), end = candidates.cend(); it != end; ++it) {
const AbstractMetaArgumentList &arguments = it.value()->arguments();
QStringList args;
- for (int i = 0, size = arguments.size(); i < size; ++i) {
- const AbstractMetaArgument &arg = arguments.at(i);
+ for (const auto &arg : arguments) {
if (arg.hasModifiedDefaultValueExpression()) {
args << arg.defaultValueExpression(); // Spell out modified values
break;
@@ -762,7 +548,7 @@ std::optional<DefaultValue>
}
QString Generator::translateType(AbstractMetaType cType,
- const AbstractMetaClass *context,
+ const AbstractMetaClassCPtr &context,
Options options) const
{
QString s;
@@ -774,94 +560,141 @@ QString Generator::translateType(AbstractMetaType cType,
}
if (cType.isVoid()) {
- s = QLatin1String("void");
+ s = u"void"_s;
} else if (cType.isArray()) {
- s = translateType(*cType.arrayElementType(), context, options) + QLatin1String("[]");
+ s = translateType(*cType.arrayElementType(), context, options) + u"[]"_s;
} else {
+ AbstractMetaType copyType = cType;
if (options & Generator::ExcludeConst || options & Generator::ExcludeReference) {
- AbstractMetaType copyType = cType;
-
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("::"));
- } else {
- s = cType.cppSignature();
+ s = copyType.cppSignature();
+ const auto te = copyType.typeEntry();
+ if (!te->isVoid() && !isCppPrimitive(te)) { // Add scope resolution
+ const auto pos = s.indexOf(te->qualifiedCppName()); // Skip const/volatile
+ Q_ASSERT(pos >= 0);
+ s.insert(pos, u"::"_s);
}
}
return s;
}
+static const QHash<QString, QString> &pythonOperators()
+{
+ static const QHash<QString, QString> result = {
+ // call operator
+ {u"operator()"_s, u"__call__"_s},
+ // Arithmetic operators
+ {u"operator+"_s, u"__add__"_s},
+ {u"operator-"_s, u"__sub__"_s},
+ {u"operator*"_s, u"__mul__"_s},
+ {u"operator/"_s, u"__div__"_s},
+ {u"operator%"_s, u"__mod__"_s},
+ // Inplace arithmetic operators
+ {u"operator+="_s, u"__iadd__"_s},
+ {u"operator-="_s, u"__isub__"_s},
+ {u"operator++"_s, u"__iadd__"_s},
+ {u"operator--"_s, u"__isub__"_s},
+ {u"operator*="_s, u"__imul__"_s},
+ {u"operator%="_s, u"__imod__"_s},
+ // Bitwise operators
+ {u"operator&"_s, u"__and__"_s},
+ {u"operator^"_s, u"__xor__"_s},
+ {u"operator|"_s, u"__or__"_s},
+ {u"operator<<"_s, u"__lshift__"_s},
+ {u"operator>>"_s, u"__rshift__"_s},
+ {u"operator~"_s, u"__invert__"_s},
+ // Inplace bitwise operators
+ {u"operator&="_s, u"__iand__"_s},
+ {u"operator^="_s, u"__ixor__"_s},
+ {u"operator|="_s, u"__ior__"_s},
+ {u"operator<<="_s, u"__ilshift__"_s},
+ {u"operator>>="_s, u"__irshift__"_s},
+ // Comparison operators
+ {u"operator=="_s, u"__eq__"_s},
+ {u"operator!="_s, u"__ne__"_s},
+ {u"operator<"_s, u"__lt__"_s},
+ {u"operator>"_s, u"__gt__"_s},
+ {u"operator<="_s, u"__le__"_s},
+ {u"operator>="_s, u"__ge__"_s},
+ // Conversion (note bool has special handling with heuristics)
+ {u"operator int"_s, u"__int__"_s},
+ {u"operator double"_s, u"__float__"_s}
+ };
+ return result;
+}
+
+QString Generator::pythonOperatorFunctionName(const QString &cppOpFuncName)
+{
+ return pythonOperators().value(cppOpFuncName);
+}
-QString Generator::subDirectoryForClass(const AbstractMetaClass *clazz) const
+bool Generator::isPythonOperatorFunctionName(const QString &cppOpFuncName)
{
- return subDirectoryForPackage(clazz->package());
+ return pythonOperators().contains(cppOpFuncName);
}
QString Generator::subDirectoryForPackage(QString packageNameIn) const
{
if (packageNameIn.isEmpty())
packageNameIn = packageName();
- packageNameIn.replace(QLatin1Char('.'), QDir::separator());
+ packageNameIn.replace(u'.', QDir::separator());
return packageNameIn;
}
+QString Generator::addGlobalScopePrefix(const QString &t)
+{
+ return t.startsWith("std::"_L1) ? t : m_gsp + t;
+}
+
+QString Generator::globalScopePrefix(const GeneratorContext &classContext)
+{
+ return classContext.useWrapper() ? QString{} : m_gsp;
+}
+
template<typename T>
-static QString getClassTargetFullName_(const T *t, bool includePackageName)
+static QString getClassTargetFullName_(T t, bool includePackageName)
{
QString name = t->name();
- const AbstractMetaClass *context = t->enclosingClass();
+ AbstractMetaClassCPtr 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(u'.');
name.prepend(context->name());
}
context = context->enclosingClass();
}
if (includePackageName) {
- name.prepend(QLatin1Char('.'));
+ name.prepend(u'.');
name.prepend(t->package());
}
return name;
}
-QString getClassTargetFullName(const AbstractMetaClass *metaClass, bool includePackageName)
+QString getClassTargetFullName(const AbstractMetaClassCPtr &metaClass,
+ bool includePackageName)
{
return getClassTargetFullName_(metaClass, includePackageName);
}
-QString getClassTargetFullName(const AbstractMetaEnum &metaEnum, bool 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('_'));
+ signature.replace(u"::"_s, u"_"_s);
+ signature.replace(u'<', u'_');
+ signature.replace(u'>', u'_');
+ signature.replace(u' ', u'_');
return signature;
}
diff --git a/sources/shiboken6/generator/generator.h b/sources/shiboken6/generator/generator.h
index 48ce9edca..5b051b599 100644
--- a/sources/shiboken6/generator/generator.h
+++ b/sources/shiboken6/generator/generator.h
@@ -1,191 +1,40 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef GENERATOR_H
#define GENERATOR_H
-#include <abstractmetatype.h>
+#include <abstractmetalang_typedefs.h>
#include <typedatabase_typedefs.h>
-#include <QtCore/QObject>
-#include <QtCore/QSharedPointer>
-#include <QtCore/QTextStream>
#include <QtCore/QList>
+#include <memory>
#include <optional>
+
class ApiExtractorResult;
-class AbstractMetaFunction;
-class AbstractMetaClass;
-class AbstractMetaEnum;
-class TypeEntry;
-class ComplexTypeEntry;
-class AbstractMetaType;
-class EnumTypeEntry;
-class FlagsTypeEntry;
+class GeneratorContext;
+class DefaultValue;
+struct OptionDescription;
+class OptionsParser;
class TextStream;
-QT_BEGIN_NAMESPACE
-class QFile;
-class QDebug;
-QT_END_NAMESPACE
-
-class PrimitiveTypeEntry;
-class ContainerTypeEntry;
-
-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 getClassTargetFullName(const AbstractMetaClassCPtr &metaClass,
+ bool includePackageName = true);
+QString getClassTargetFullName(const AbstractMetaEnum &metaEnum,
+ 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
- {
- 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, QString value = QString());
- explicit DefaultValue(QString customValue);
-
- 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;
-};
-
-#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug debug, const DefaultValue &v);
-#endif
-
-/**
- * A GeneratorContext object contains a pointer to an AbstractMetaClass and/or a specialized
- * AbstractMetaType, for which code is currently being generated.
- *
- * The main case is when the context contains only an AbstractMetaClass pointer, which is used
- * by different methods to generate appropriate expressions, functions, type names, etc.
- *
- * The second case is for generation of code for smart pointers. In this case the m_metaClass member
- * contains the generic template class of the smart pointer, and the m_preciseClassType member
- * contains the instantiated template type, e.g. a concrete shared_ptr<int>. To
- * distinguish this case, the member m_forSmartPointer is set to true.
- *
- * In the future the second case might be generalized for all template type instantiations.
- */
-class GeneratorContext {
- friend class ShibokenGenerator;
- friend class Generator;
-public:
- enum Type { Class, WrappedClass, SmartPointer };
-
- GeneratorContext() = default;
-
- const AbstractMetaClass *metaClass() const { return m_metaClass; }
- const AbstractMetaType &preciseType() const { return m_preciseClassType; }
-
- bool forSmartPointer() const { return m_type == SmartPointer; }
- bool useWrapper() const { return m_type == WrappedClass; }
-
- QString wrapperName() const
- {
- Q_ASSERT(m_type == WrappedClass);
- return m_wrappername;
- }
-
- QString smartPointerWrapperName() const;
-
-private:
- const AbstractMetaClass *m_metaClass = nullptr;
- AbstractMetaType m_preciseClassType;
- QString m_wrappername;
- Type m_type = Class;
-};
-
-/**
* 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 = QList<OptionDescription>;
+ Q_DISABLE_COPY_MOVE(Generator)
- /// Optiosn used around the generator code
+ /// Options used around the generator code
enum Option {
NoOption = 0x00000000,
ExcludeConst = 0x00000001,
@@ -200,13 +49,19 @@ public:
};
Q_DECLARE_FLAGS(Options, Option)
+ enum FileNameFlag {
+ UnqualifiedName = 0x1,
+ KeepCase = 0x2
+ };
+ Q_DECLARE_FLAGS(FileNameFlags, FileNameFlag)
+
Generator();
virtual ~Generator();
bool setup(const ApiExtractorResult &api);
- virtual OptionDescriptions options() const;
- virtual bool handleOption(const QString &key, const QString &value);
+ static QList<OptionDescription> options();
+ static std::shared_ptr<OptionsParser> createOptionsParser();
/// Returns the top namespace made invisible
const AbstractMetaClassCList &invisibleTopNamespaces() const;
@@ -239,6 +94,12 @@ public:
bool hasPrivateClasses() const;
+ /// Returns true if the user enabled PySide extensions (command line option)
+ static bool usePySideExtensions();
+ /// Returns true if the generated code should not use the
+ /// "#define protected public" hack.
+ static bool avoidProtectedHack();
+
/**
* Retrieves the name of the currently processed module.
* While package name is a complete package idetification, e.g. 'PySide.QtCore',
@@ -249,32 +110,34 @@ public:
*/
static QString moduleName();
+ static QString pythonOperatorFunctionName(const QString &cppOpFuncName);
+ static bool isPythonOperatorFunctionName(const QString &cppOpFuncName);
+
protected:
+ /// Helper for determining the file name
+ static QString fileNameForContextHelper(const GeneratorContext &context,
+ const QString &suffix,
+ FileNameFlags flags = {});
+
/// Returns all primitive types found by APIExtractor
- static PrimitiveTypeEntryList primitiveTypes();
+ static PrimitiveTypeEntryCList primitiveTypes();
/// Returns all container types found by APIExtractor
- static ContainerTypeEntryList containerTypes();
+ static ContainerTypeEntryCList containerTypes();
- virtual GeneratorContext contextForClass(const AbstractMetaClass *c) const;
- static GeneratorContext contextForSmartPointer(const AbstractMetaClass *c,
- const AbstractMetaType &t);
+ virtual GeneratorContext contextForClass(const AbstractMetaClassCPtr &c) const;
+ static GeneratorContext
+ contextForSmartPointer(const AbstractMetaClassCPtr &c, const AbstractMetaType &t,
+ const AbstractMetaClassCPtr &pointeeClass = {});
/// Generates a file for given AbstractMetaClass or AbstractMetaType (smart pointer case).
bool generateFileForContext(const GeneratorContext &context);
/// Returns the file base name for a smart pointer.
- static QString getFileNameBaseForSmartPointer(const AbstractMetaType &smartPointerType,
- const AbstractMetaClass *smartPointer);
-
- /// Returns true if the generator should generate any code for the TypeEntry.
- static bool shouldGenerateTypeEntry(const TypeEntry *) ;
+ static QString getFileNameBaseForSmartPointer(const AbstractMetaType &smartPointerType);
/// 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;
+ virtual bool shouldGenerate(const TypeEntryCPtr &t) const;
/**
* Translate metatypes to binding source format.
@@ -284,7 +147,7 @@ protected:
* \return the metatype translated to binding source format
*/
QString translateType(AbstractMetaType metatype,
- const AbstractMetaClass *context,
+ const AbstractMetaClassCPtr &context,
Options options = NoOption) const;
/**
@@ -293,9 +156,9 @@ protected:
static QString packageName();
// Returns the full name of the type.
- static QString getFullTypeName(const TypeEntry *type);
+ static QString getFullTypeName(TypeEntryCPtr type);
static QString getFullTypeName(const AbstractMetaType &type);
- static QString getFullTypeName(const AbstractMetaClass *metaClass);
+ static QString getFullTypeName(const AbstractMetaClassCPtr &metaClass);
/**
* Returns the full qualified C++ name for an AbstractMetaType, but removing modifiers
@@ -310,14 +173,14 @@ protected:
* Returns a null string if it fails.
*/
static std::optional<DefaultValue>
- minimalConstructor(const ApiExtractorResult &api, const TypeEntry *type,
+ minimalConstructor(const ApiExtractorResult &api, const TypeEntryCPtr &type,
QString *errorString = nullptr);
static std::optional<DefaultValue>
minimalConstructor(const ApiExtractorResult &api, const AbstractMetaType &type,
QString *errorString = nullptr);
static std::optional<DefaultValue>
minimalConstructor(const ApiExtractorResult &api,
- const AbstractMetaClass *metaClass,
+ const AbstractMetaClassCPtr &metaClass,
QString *errorString = nullptr);
/**
@@ -326,7 +189,6 @@ protected:
* 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(const GeneratorContext &context) const = 0;
@@ -352,24 +214,20 @@ protected:
*/
virtual QString subDirectoryForPackage(QString packageName = QString()) const;
- AbstractMetaTypeList instantiatedContainers() const;
- AbstractMetaTypeList instantiatedSmartPointers() const;
+ static QString addGlobalScopePrefix(const QString &t);
+ static QString globalScopePrefix(const GeneratorContext &classContext);
- static QString getSimplifiedContainerTypeName(const AbstractMetaType &type);
- void addInstantiatedContainersAndSmartPointers(const AbstractMetaType &type,
- const QString &context);
+ static QString m_gsp;
private:
struct GeneratorPrivate;
GeneratorPrivate *m_d;
- void collectInstantiatedContainersAndSmartPointers(const AbstractMetaFunctionCPtr &func);
- void collectInstantiatedContainersAndSmartPointers(const AbstractMetaClass *metaClass);
- void collectInstantiatedContainersAndSmartPointers();
};
Q_DECLARE_OPERATORS_FOR_FLAGS(Generator::Options)
-using GeneratorPtr = QSharedPointer<Generator>;
+Q_DECLARE_OPERATORS_FOR_FLAGS(Generator::FileNameFlags)
+
+using GeneratorPtr = std::shared_ptr<Generator>;
using Generators = QList<GeneratorPtr>;
#endif // GENERATOR_H
-
diff --git a/sources/shiboken6/generator/generatorcontext.cpp b/sources/shiboken6/generator/generatorcontext.cpp
new file mode 100644
index 000000000..b50c2effb
--- /dev/null
+++ b/sources/shiboken6/generator/generatorcontext.cpp
@@ -0,0 +1,38 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "generatorcontext.h"
+#include <abstractmetalang.h>
+
+#include <QtCore/QDebug>
+
+using namespace Qt::StringLiterals;
+
+QString GeneratorContext::wrapperName() const
+{
+ Q_ASSERT(m_type == WrappedClass);
+ return m_wrappername;
+}
+
+QString GeneratorContext::effectiveClassName() const
+{
+ if (m_type == SmartPointer)
+ return m_preciseClassType.cppSignature();
+ return m_type == WrappedClass ? m_wrappername : m_metaClass->qualifiedCppName();
+}
+
+QDebug operator<<(QDebug debug, const GeneratorContext &c)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "GeneratorContext(\"" << c.metaClass()->name() << "\" ";
+ if (c.useWrapper())
+ debug << "[wrapper]";
+ else if (c.forSmartPointer())
+ debug << "[smart pointer] \"" << c.preciseType().cppSignature() << '"';
+ else
+ debug << "[class]";
+ debug << ')';
+ return debug;
+}
diff --git a/sources/shiboken6/generator/generatorcontext.h b/sources/shiboken6/generator/generatorcontext.h
new file mode 100644
index 000000000..2e58d4346
--- /dev/null
+++ b/sources/shiboken6/generator/generatorcontext.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef GENERATORCONTEXT_H
+#define GENERATORCONTEXT_H
+
+#include <abstractmetalang_typedefs.h>
+#include <abstractmetatype.h>
+#include <QtCore/QList>
+
+QT_FORWARD_DECLARE_CLASS(QDebug);
+
+// 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 {
+ friend class ShibokenGenerator;
+ friend class Generator;
+public:
+ enum Type { Class, WrappedClass, SmartPointer };
+
+ GeneratorContext() = default;
+
+ AbstractMetaClassCPtr metaClass() const { return m_metaClass; }
+ const AbstractMetaType &preciseType() const { return m_preciseClassType; }
+ AbstractMetaClassCPtr pointeeClass() const { return m_pointeeClass; }
+
+ bool forSmartPointer() const { return m_type == SmartPointer; }
+ bool useWrapper() const { return m_type == WrappedClass; }
+
+ QString wrapperName() const;
+ /// Returns the wrapper name in case of useWrapper(), the qualified class
+ /// name or the smart pointer specialization.
+ QString effectiveClassName() const;
+
+private:
+ AbstractMetaClassCPtr m_metaClass;
+ AbstractMetaClassCPtr m_pointeeClass;
+ AbstractMetaType m_preciseClassType;
+ QString m_wrappername;
+ Type m_type = Class;
+};
+
+QDebug operator<<(QDebug debug, const GeneratorContext &c);
+
+#endif // GENERATORCONTEXT_H
diff --git a/sources/shiboken6/generator/main.cpp b/sources/shiboken6/generator/main.cpp
index 315e963c4..9871df206 100644
--- a/sources/shiboken6/generator/main.cpp
+++ b/sources/shiboken6/generator/main.cpp
@@ -1,701 +1,369 @@
-/****************************************************************************
-**
-** 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 <QtCore/QVariant>
-#include <iostream>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "shibokenconfig.h"
+#include "cppgenerator.h"
+#include "generator.h"
+#include "headergenerator.h"
+#include "qtdocgenerator.h"
+
#include <apiextractor.h>
#include <apiextractorresult.h>
+#include <exception.h>
#include <fileout.h>
+#include <messages.h>
+#include <optionsparser.h>
#include <reporthandler.h>
#include <typedatabase.h>
-#include <messages.h>
-#include "generator.h"
-#include "shibokenconfig.h"
-#include "cppgenerator.h"
-#include "headergenerator.h"
-#include "qtdocgenerator.h"
-#include <exception>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QLibrary>
+#include <QtCore/QVariant>
-static const QChar clangOptionsSplitter = u',';
-static const QChar keywordsSplitter = u',';
-static const QChar dropTypeEntriesSplitter = u';';
-static const QChar apiVersionSplitter = u'|';
-
-static inline QString keywordsOption() { return QStringLiteral("keywords"); }
-static inline QString clangOptionOption() { return QStringLiteral("clang-option"); }
-static inline QString clangOptionsOption() { return QStringLiteral("clang-options"); }
-static inline QString apiVersionOption() { return QStringLiteral("api-version"); }
-static inline QString dropTypeEntriesOption() { return QStringLiteral("drop-type-entries"); }
-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 useGlobalHeaderOption() { return QStringLiteral("use-global-header"); }
-static inline QString dryrunOption() { return QStringLiteral("dry-run"); }
-static inline QString skipDeprecatedOption() { return QStringLiteral("skip-deprecated"); }
+#include "qtcompat.h"
-static const char helpHint[] = "Note: use --help or -h for more information.\n";
-
-using OptionDescriptions = Generator::OptionDescriptions;
+#include <exception>
+#include <iostream>
-struct CommandLineArguments
-{
- void addToOptionsList(const QString &option,
- const QString &value);
- void addToOptionsList(const QString &option,
- const QStringList &value);
- void addToOptionsList(const QString &option,
- const QString &listValue,
- QChar separator);
- void addToOptionsPathList(const QString &option,
- const QString &pathListValue)
- {
- addToOptionsList(option, pathListValue, QDir::listSeparator());
- }
+using namespace Qt::StringLiterals;
- QVariantMap options; // string,stringlist for path lists, etc.
- QStringList positionalArguments;
-};
+static const char helpHint[] = "Note: use --help or -h for more information.\n";
+static const char appName[] = "shiboken";
-void CommandLineArguments::addToOptionsList(const QString &option,
- const QString &value)
+static inline Generators docGenerators()
{
- auto it = options.find(option);
- if (it == options.end()) {
- options.insert(option, QVariant(QStringList(value)));
- } else {
- auto list = it.value().toStringList();
- list += value;
- options[option] = QVariant(list);
- }
+ Generators result;
+#ifdef DOCSTRINGS_ENABLED
+ result.append(GeneratorPtr(new QtDocGenerator));
+#endif
+ return result;
}
-void CommandLineArguments::addToOptionsList(const QString &option,
- const QStringList &value)
+static inline Generators shibokenGenerators()
{
- auto it = options.find(option);
- if (it == options.end()) {
- options.insert(option, QVariant(value));
- } else {
- auto list = it.value().toStringList();
- list += value;
- options[option] = QVariant(list);
- }
+ Generators result;
+ result << GeneratorPtr(new CppGenerator) << GeneratorPtr(new HeaderGenerator);
+ return result;
}
-void CommandLineArguments::addToOptionsList(const QString &option,
- const QString &listValue,
- QChar separator)
+struct CommonOptions
{
- const auto newValues = listValue.split(separator, Qt::SkipEmptyParts);
- addToOptionsList(option, newValues);
-}
+ QString generatorSet;
+ QString licenseComment;
+ QString outputDirectory = u"out"_s;
+ QStringList headers;
+ QString typeSystemFileName;
+ bool help = false;
+ bool version = false;
+ bool diff = false;
+ bool dryRun = false;
+ bool logUnmatched = false;
+ bool printBuiltinTypes = false;
+};
-static void printOptions(QTextStream &s, const OptionDescriptions &options)
+class CommonOptionsParser : public OptionsParser
{
- 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 = QStringView{od.second}.split(QLatin1Char('\n'));
- for (const auto &line : lines)
- s << " " << line << Qt::endl;
- s << Qt::endl;
- }
- }
-}
+public:
+ explicit CommonOptionsParser(CommonOptions *o) : m_options(o) {}
-static std::optional<CommandLineArguments>
- processProjectFile(const QString &appName, QFile &projectFile)
-{
- QByteArray line = projectFile.readLine().trimmed();
- if (line.isEmpty() || line != "[generator-project]") {
- std::cerr << qPrintable(appName) << ": first line of project file \""
- << qPrintable(projectFile.fileName())
- << "\" must be the string \"[generator-project]\"\n";
- return {};
- }
+ bool handleBoolOption(const QString &key, OptionSource source) override;
+ bool handleOption(const QString &key, const QString &value, OptionSource source) override;
- CommandLineArguments args;
-
- 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).trimmed();
- value = QString::fromUtf8(line.mid(split + 1).trimmed());
- } else {
- key = line;
- }
+ static OptionDescriptions optionDescriptions();
- if (key == "include-path") {
- args.addToOptionsList(includePathOption(),
- QDir::toNativeSeparators(value));
- } else if (key == "framework-include-path") {
- args.addToOptionsList(frameworkIncludePathOption(),
- QDir::toNativeSeparators(value));
- } else if (key == "system-include-paths") {
- args.addToOptionsList(systemIncludePathOption(),
- QDir::toNativeSeparators(value));
- } else if (key == "typesystem-path") {
- args.addToOptionsList(typesystemPathOption(),
- QDir::toNativeSeparators(value));
- } else if (key == "language-level") {
- args.options.insert(languageLevelOption(), value);
- } else if (key == "clang-option") {
- args.addToOptionsList(clangOptionsOption(), value);
- } else if (key == "clang-options") {
- args.addToOptionsList(clangOptionsOption(),
- value, clangOptionsSplitter);
- } else if (key == "api-version") {
- args.addToOptionsList(apiVersionOption(),
- value, apiVersionSplitter);
- } else if (key == "keywords") {
- args.addToOptionsList(keywordsOption(),
- value, keywordsSplitter);
- } else if (key == "drop-type-entries") {
- args.addToOptionsList(dropTypeEntriesOption(),
- value, dropTypeEntriesSplitter);
- } else if (key == "header-file") {
- args.positionalArguments.prepend(value);
- } else if (key == "typesystem-file") {
- args.positionalArguments.append(value);
- } else {
- args.options.insert(QString::fromUtf8(key), value);
- }
- }
+private:
+ CommonOptions *m_options;
+};
- return args;
+OptionDescriptions CommonOptionsParser::optionDescriptions()
+{
+ return {
+ {u"debug-level=[sparse|medium|full]"_s,
+ u"Set the debug level"_s},
+ {u"documentation-only"_s,
+ u"Do not generates any code, just the documentation"_s},
+ {u"compiler=<type>"_s,
+ u"Emulated compiler type (g++, msvc, clang)"_s},
+ {u"platform=<name>"_s,
+ u"Emulated platform (windows, darwin, unix)"_s},
+ {u"compiler-path=<file>"_s,
+ u"Path to the compiler for determining builtin include paths"_s},
+ {u"generator-set=<\"generator module\">"_s,
+ u"generator-set to be used. e.g. qtdoc"_s},
+ {u"diff"_s, u"Print a diff of wrapper files"_s},
+ {u"dry-run"_s, u"Dry run, do not generate wrapper files"_s},
+ {u"-h"_s, {} },
+ {u"help"_s, u"Display this help and exit"_s},
+ {u"-I<path>"_s, {} },
+ {u"include-paths="_s + OptionsParser::pathSyntax(),
+ u"Include paths used by the C++ parser"_s},
+ {u"license-file=<license-file>"_s,
+ u"File used for copyright headers of generated files"_s},
+ {u"no-suppress-warnings"_s,
+ u"Show all warnings"_s},
+ {u"output-directory=<path>"_s,
+ u"The directory where the generated files will be written"_s},
+ {u"project-file=<file>"_s,
+ u"text file containing a description of the binding project.\n"
+ "Replaces and overrides command line arguments"_s},
+ {u"silent"_s, u"Avoid printing any message"_s},
+ {u"print-builtin-types"_s,
+ u"Print information about builtin types"_s},
+ {u"version"_s,
+ u"Output version information and exit"_s}
+ };
}
-static std::optional<CommandLineArguments> getProjectFileArguments()
+bool CommonOptionsParser::handleBoolOption(const QString &key, OptionSource source)
{
- 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 (source == OptionSource::CommandLineSingleDash) {
+ if (key == u"h") {
+ m_options->help = true;
+ return true;
}
+ return false;
}
- if (projectFileName.isEmpty())
- return CommandLineArguments{};
-
- if (!QFile::exists(projectFileName)) {
- std::cerr << qPrintable(appName) << ": Project file \""
- << qPrintable(projectFileName) << "\" not found.\n";
- return {};
+ if (key == u"version") {
+ m_options->version = true;
+ return true;
}
-
- QFile projectFile(projectFileName);
- if (!projectFile.open(QIODevice::ReadOnly)) {
- std::cerr << qPrintable(appName) << ": Cannot open project file \""
- << qPrintable(projectFileName) << "\" : " << qPrintable(projectFile.errorString())
- << '\n';
- return {};
+ if (key == u"help") {
+ m_options->help = true;
+ return true;
}
- return processProjectFile(appName, projectFile);
-}
-
-static void getCommandLineArg(QString arg, int &argNum, CommandLineArguments &args)
-{
- if (arg.startsWith(QLatin1String("--"))) {
- arg.remove(0, 2);
- const int split = arg.indexOf(QLatin1Char('='));
- if (split < 0) {
- args.options.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()) {
- args.addToOptionsPathList(option, value);
- } else if (option == apiVersionOption()) {
- args.addToOptionsList(apiVersionOption(), value, apiVersionSplitter);
- } else if (option == dropTypeEntriesOption()) {
- args.addToOptionsList(dropTypeEntriesOption(), value, dropTypeEntriesSplitter);
- } else if (option == clangOptionOption()) {
- args.addToOptionsList(clangOptionsOption(), value);
- } else if (option == clangOptionsOption()) {
- args.addToOptionsList(clangOptionsOption(), value, clangOptionsSplitter);
- } else if (option == keywordsOption()) {
- args.addToOptionsList(keywordsOption(), value, keywordsSplitter);
- } else {
- args.options.insert(option, value);
- }
- return;
+ if (key == u"diff") {
+ FileOut::setDiff(true);
+ return true;
}
- if (arg.startsWith(QLatin1Char('-'))) {
- arg.remove(0, 1);
- if (arg.startsWith(QLatin1Char('I'))) // Shorthand path arguments -I/usr/include...
- args.addToOptionsPathList(includePathOption(), arg.mid(1));
- else if (arg.startsWith(QLatin1Char('F')))
- args.addToOptionsPathList(frameworkIncludePathOption(), arg.mid(1));
- else if (arg.startsWith(QLatin1String("isystem")))
- args.addToOptionsPathList(systemIncludePathOption(), arg.mid(7));
- else if (arg.startsWith(QLatin1Char('T')))
- args.addToOptionsPathList(typesystemPathOption(), arg.mid(1));
- else if (arg == QLatin1String("h"))
- args.options.insert(helpOption(), QString());
- else if (arg.startsWith(QLatin1String("std=")))
- args.options.insert(languageLevelOption(), arg.mid(4));
- else
- args.options.insert(arg, QString());
- return;
+ if (key == u"dry-run") {
+ FileOut::setDryRun(true);
+ return true;
+ }
+ if (key == u"silent") {
+ ReportHandler::setSilent(true);
+ return true;
+ }
+ if (key == u"log-unmatched") {
+ m_options->logUnmatched = true;
+ return true;
+ }
+ if (key == u"print-builtin-types") {
+ m_options->printBuiltinTypes = true;
+ return true;
}
- if (argNum < args.positionalArguments.size())
- args.positionalArguments[argNum] = arg;
- else
- args.positionalArguments.append(arg);
- ++argNum;
-}
-
-static void getCommandLineArgs(CommandLineArguments &args)
-{
- const QStringList arguments = QCoreApplication::arguments();
- int argNum = 0;
- for (int i = 1, size = arguments.size(); i < size; ++i)
- getCommandLineArg(arguments.at(i).trimmed(), argNum, args);
-}
-static inline Generators docGenerators()
-{
- Generators result;
-#ifdef DOCSTRINGS_ENABLED
- result.append(GeneratorPtr(new QtDocGenerator));
-#endif
- return result;
+ return false;
}
-static inline Generators shibokenGenerators()
+bool CommonOptionsParser::handleOption(const QString &key, const QString &value,
+ OptionSource source)
{
- Generators result;
- result << GeneratorPtr(new CppGenerator) << GeneratorPtr(new HeaderGenerator);
- return result;
-}
+ if (source == OptionSource::CommandLineSingleDash)
+ return false;
+
+ if (key == u"generator-set" || key == u"generatorSet" /* legacy */) {
+ m_options->generatorSet = value;
+ return true;
+ }
+ if (key == u"license-file") {
+ QFile licenseFile(value);
+ if (!licenseFile.open(QIODevice::ReadOnly))
+ throw Exception(msgCannotOpenForReading(licenseFile));
+ m_options->licenseComment = QString::fromUtf8(licenseFile.readAll());
+ return true;
+ }
+ if (key == u"debug-level") {
+ if (!ReportHandler::setDebugLevelFromArg(value))
+ throw Exception(u"Invalid debug level: "_s + value);
+ return true;
+ }
+ if (key == u"output-directory") {
+ m_options->outputDirectory = value;
+ return true;
+ }
+ if (key == u"compiler") {
+ if (!clang::setCompiler(value))
+ throw Exception(u"Invalid value \""_s + value + u"\" passed to --compiler"_s);
+ return true;
+ }
+ if (key == u"compiler-path") {
+ clang::setCompilerPath(value);
+ return true;
+ }
+ if (key == u"platform") {
+ if (!clang::setPlatform(value))
+ throw Exception(u"Invalid value \""_s + value + u"\" passed to --platform"_s);
+ return true;
+ }
+
+ if (source == OptionSource::ProjectFile) {
+ if (key == u"header-file") {
+ m_options->headers.append(value);
+ return true;
+ }
+ if (key == u"typesystem-file") {
+ m_options->typeSystemFileName = value;
+ return true;
+ }
+ }
-static inline QString languageLevelDescription()
-{
- return QLatin1String("C++ Language level (c++11..c++17, default=")
- + QLatin1String(clang::languageLevelOption(clang::emulatedCompilerLanguageLevel()))
- + QLatin1Char(')');
+ return false;
}
void printUsage()
{
- const QChar pathSplitter = QDir::listSeparator();
+ const auto generatorOptions = Generator::options();
+
QTextStream s(stdout);
s << "Usage:\n "
- << "shiboken [options] header-file(s) typesystem-file\n\n"
- << "General options:\n";
- QString pathSyntax;
- QTextStream(&pathSyntax) << "<path>[" << pathSplitter << "<path>"
- << pathSplitter << "...]";
- OptionDescriptions generalOptions = {
- {QLatin1String("api-version=<\"package mask\">,<\"version\">"),
- QLatin1String("Specify the supported api version used to generate the bindings")},
- {QLatin1String("debug-level=[sparse|medium|full]"),
- QLatin1String("Set the debug level")},
- {QLatin1String("documentation-only"),
- QLatin1String("Do not generates any code, just the documentation")},
- {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.")},
- {keywordsOption() + QStringLiteral("=keyword1[,keyword2,...]"),
- QLatin1String("A comma-separated list of keywords for conditional typesystem parsing")},
- {clangOptionOption(),
- QLatin1String("Option to be passed to clang")},
- {clangOptionsOption(),
- QLatin1String("A comma-separated list of options to be passed to clang")},
- {QLatin1String("-F<path>"), {} },
- {QLatin1String("framework-include-paths=") + pathSyntax,
- QLatin1String("Framework include paths used by the C++ parser")},
- {QLatin1String("-isystem<path>"), {} },
- {QLatin1String("system-include-paths=") + pathSyntax,
- QLatin1String("System include paths used by the C++ parser")},
- {useGlobalHeaderOption(),
- QLatin1String("Use the global headers in generated code.")},
- {QLatin1String("generator-set=<\"generator module\">"),
- QLatin1String("generator-set to be used. e.g. qtdoc")},
- {skipDeprecatedOption(),
- QLatin1String("Skip deprecated functions")},
- {diffOption(), QLatin1String("Print a diff of wrapper files")},
- {dryrunOption(), QLatin1String("Dry run, do not generate wrapper files")},
- {QLatin1String("-h"), {} },
- {helpOption(), QLatin1String("Display this help and exit")},
- {QLatin1String("-I<path>"), {} },
- {QLatin1String("include-paths=") + pathSyntax,
- QLatin1String("Include paths used by the C++ parser")},
- {languageLevelOption() + QLatin1String("=, -std=<level>"),
- languageLevelDescription()},
- {QLatin1String("license-file=<license-file>"),
- QLatin1String("File used for copyright headers of generated files")},
- {QLatin1String("no-suppress-warnings"),
- QLatin1String("Show all warnings")},
- {QLatin1String("output-directory=<path>"),
- QLatin1String("The directory where the generated files will be written")},
- {QLatin1String("project-file=<file>"),
- QLatin1String("text file containing a description of the binding project.\n"
- "Replaces and overrides command line arguments")},
- {QLatin1String("silent"), QLatin1String("Avoid printing any message")},
- {QLatin1String("-T<path>"), {} },
- {QLatin1String("typesystem-paths=") + pathSyntax,
- QLatin1String("Paths used when searching for typesystems")},
- {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());
- }
- }
+ << "shiboken [options] header-file(s) typesystem-file\n\n"
+ << "General options:\n"
+ << CommonOptionsParser::optionDescriptions()
+ << ApiExtractor::options()
+ << TypeDatabase::options()
+ << "\nSource generator options:\n\n" << generatorOptions
+ << ShibokenGenerator::options();
+
+#ifdef DOCSTRINGS_ENABLED
+ s << "\nDocumentation Generator options:\n\n"
+ << generatorOptions << QtDocGenerator::options();
+#endif
}
static inline void printVerAndBanner()
{
- std::cout << "shiboken v" SHIBOKEN_VERSION << std::endl;
+ std::cout << appName << " v" << SHIBOKEN_VERSION << std::endl;
std::cout << "Copyright (C) 2016 The Qt Company Ltd." << std::endl;
}
-static inline void errorPrint(const QString &s)
+static inline void errorPrint(const QString &s, const QStringList &arguments)
{
- QStringList arguments = QCoreApplication::arguments();
- arguments.pop_front();
- std::cerr << "shiboken: " << qPrintable(s) << "\nCommand line:\n";
+ std::cerr << appName << ": " << qPrintable(s) << "\nCommand line:\n";
for (const auto &argument : arguments)
std::cerr << " \"" << qPrintable(argument) << "\"\n";
}
-static void parseIncludePathOption(const QString &option, HeaderType headerType,
- CommandLineArguments &args,
- ApiExtractor &extractor)
-{
- const auto it = args.options.find(option);
- if (it != args.options.end()) {
- const auto includePathListList = it.value().toStringList();
- args.options.erase(it);
- for (const QString &s : includePathListList) {
- auto path = QFile::encodeName(QDir::cleanPath(s));
- extractor.addIncludePath(HeaderPath{path, headerType});
- }
- }
-}
-
-int shibokenMain(int argc, char *argv[])
+int shibokenMain(const QStringList &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);
+ QHashSeed::setDeterministicGlobalSeed();
+
ReportHandler::install();
if (ReportHandler::isDebug(ReportHandler::SparseDebug))
- qCInfo(lcShiboken()).noquote().nospace() << QCoreApplication::arguments().join(QLatin1Char(' '));
+ qCInfo(lcShiboken()).noquote().nospace() << appName << ' ' << argV.join(u' ');
- // Store command arguments in a map
- const auto projectFileArgumentsOptional = getProjectFileArguments();
- if (!projectFileArgumentsOptional.has_value())
- return EXIT_FAILURE;
-
- const CommandLineArguments projectFileArguments = projectFileArgumentsOptional.value();
- CommandLineArguments args = projectFileArguments;
- getCommandLineArgs(args);
- Generators generators;
+ Options options;
+ options.setOptions(argV);
- auto ait = args.options.find(QLatin1String("version"));
- if (ait != args.options.end()) {
- args.options.erase(ait);
+ CommonOptions commonOptions;
+ {
+ CommonOptionsParser parser(&commonOptions);
+ parser.process(&options);
+ }
+ if (commonOptions.version) {
printVerAndBanner();
return EXIT_SUCCESS;
}
-
- QString generatorSet;
- ait = args.options.find(QLatin1String("generator-set"));
- if (ait == args.options.end()) // Also check QLatin1String("generatorSet") command line argument for backward compatibility.
- ait = args.options.find(QLatin1String("generatorSet"));
- if (ait != args.options.end()) {
- generatorSet = ait.value().toString();
- args.options.erase(ait);
+ if (commonOptions.help) {
+ printUsage();
+ return EXIT_SUCCESS;
}
+ Generators generators;
+
+ OptionsParserList optionParser;
+ optionParser.append(Generator::createOptionsParser());
+ optionParser.append(TypeDatabase::instance()->createOptionsParser());
+ ApiExtractor extractor;
+ optionParser.append(extractor.createOptionsParser());
+
// Pre-defined generator sets.
- if (generatorSet == QLatin1String("qtdoc")) {
+ if (commonOptions.generatorSet == u"qtdoc") {
generators = docGenerators();
if (generators.isEmpty()) {
- errorPrint(QLatin1String("Doc strings extractions was not enabled in this shiboken build."));
+ errorPrint(u"Doc strings extractions was not enabled in this shiboken build."_s, argV);
return EXIT_FAILURE;
}
- } else if (generatorSet.isEmpty() || generatorSet == QLatin1String("shiboken")) {
+#ifdef DOCSTRINGS_ENABLED
+ optionParser.append(QtDocGenerator::createOptionsParser());
+#endif
+ } else if (commonOptions.generatorSet.isEmpty() || commonOptions.generatorSet == u"shiboken") {
generators = shibokenGenerators();
+ optionParser.append(ShibokenGenerator::createOptionsParser());
} else {
- errorPrint(QLatin1String("Unknown generator set, try \"shiboken\" or \"qtdoc\"."));
+ errorPrint(u"Unknown generator set, try \"shiboken\" or \"qtdoc\"."_s, argV);
return EXIT_FAILURE;
}
- ait = args.options.find(QLatin1String("help"));
- if (ait != args.options.end()) {
- args.options.erase(ait);
- printUsage();
- return EXIT_SUCCESS;
- }
-
- ait = args.options.find(diffOption());
- if (ait != args.options.end()) {
- args.options.erase(ait);
- FileOut::setDiff(true);
- }
-
- ait = args.options.find(useGlobalHeaderOption());
- if (ait != args.options.end()) {
- args.options.erase(ait);
- ApiExtractor::setUseGlobalHeader(true);
- }
-
- ait = args.options.find(dryrunOption());
- if (ait != args.options.end()) {
- args.options.erase(ait);
- FileOut::setDryRun(true);
- }
-
- QString licenseComment;
- ait = args.options.find(QLatin1String("license-file"));
- if (ait != args.options.end()) {
- QFile licenseFile(ait.value().toString());
- args.options.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.options.find(QLatin1String("output-directory"));
- if (ait != args.options.end()) {
- outputDirectory = ait.value().toString();
- args.options.erase(ait);
- }
-
- if (!QDir(outputDirectory).exists()) {
- if (!QDir().mkpath(outputDirectory)) {
+ if (!QDir(commonOptions.outputDirectory).exists()) {
+ if (!QDir().mkpath(commonOptions.outputDirectory)) {
qCWarning(lcShiboken).noquote().nospace()
- << "Can't create output directory: " << QDir::toNativeSeparators(outputDirectory);
+ << "Can't create output directory: "
+ << QDir::toNativeSeparators(commonOptions.outputDirectory);
return EXIT_FAILURE;
}
}
// Create and set-up API Extractor
- ApiExtractor extractor;
- extractor.setLogDirectory(outputDirectory);
- ait = args.options.find(skipDeprecatedOption());
- if (ait != args.options.end()) {
- extractor.setSkipDeprecated(true);
- args.options.erase(ait);
- }
-
- ait = args.options.find(QLatin1String("silent"));
- if (ait != args.options.end()) {
- extractor.setSilent(true);
- args.options.erase(ait);
- } else {
- ait = args.options.find(QLatin1String("debug-level"));
- if (ait != args.options.end()) {
- const QString value = ait.value().toString();
- if (!ReportHandler::setDebugLevelFromArg(value)) {
- errorPrint(QLatin1String("Invalid debug level: ") + value);
- return EXIT_FAILURE;
- }
- args.options.erase(ait);
- }
- }
- ait = args.options.find(QLatin1String("no-suppress-warnings"));
- if (ait != args.options.end()) {
- args.options.erase(ait);
- extractor.setSuppressWarnings(false);
- }
- ait = args.options.find(apiVersionOption());
- if (ait != args.options.end()) {
- const QStringList &versions = ait.value().toStringList();
- args.options.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;
- }
+ extractor.setLogDirectory(commonOptions.outputDirectory);
+
+ if (commonOptions.typeSystemFileName.isEmpty() && commonOptions.headers.isEmpty()) {
+ if (options.positionalArguments.size() < 2) {
+ errorPrint(u"Insufficient positional arguments, specify header-file and typesystem-file."_s,
+ argV);
+ std::cout << '\n';
+ printUsage();
+ return EXIT_FAILURE;
}
- }
-
- ait = args.options.find(dropTypeEntriesOption());
- if (ait != args.options.end()) {
- extractor.setDropTypeEntries(ait.value().toStringList());
- args.options.erase(ait);
- }
- ait = args.options.find(keywordsOption());
- if (ait != args.options.end()) {
- extractor.setTypesystemKeywords(ait.value().toStringList());
- args.options.erase(ait);
+ commonOptions.typeSystemFileName = options.positionalArguments.takeLast();
+ commonOptions.headers = options.positionalArguments;
}
- ait = args.options.find(typesystemPathOption());
- if (ait != args.options.end()) {
- extractor.addTypesystemSearchPath(ait.value().toStringList());
- args.options.erase(ait);
- }
-
- ait = args.options.find(clangOptionsOption());
- if (ait != args.options.end()) {
- extractor.setClangOptions(ait.value().toStringList());
- args.options.erase(ait);
- }
-
- parseIncludePathOption(includePathOption(), HeaderType::Standard,
- args, extractor);
- parseIncludePathOption(frameworkIncludePathOption(), HeaderType::Framework,
- args, extractor);
- parseIncludePathOption(systemIncludePathOption(), HeaderType::System,
- args, extractor);
-
- if (args.positionalArguments.size() < 2) {
- errorPrint(QLatin1String("Insufficient positional arguments, specify header-file and typesystem-file."));
- std::cout << '\n';
- printUsage();
- return EXIT_FAILURE;
- }
-
- const QString typeSystemFileName = args.positionalArguments.takeLast();
- QString messagePrefix = QFileInfo(typeSystemFileName).baseName();
- if (messagePrefix.startsWith(QLatin1String("typesystem_")))
+ QString messagePrefix = QFileInfo(commonOptions.typeSystemFileName).baseName();
+ if (messagePrefix.startsWith(u"typesystem_"))
messagePrefix.remove(0, 11);
- ReportHandler::setPrefix(QLatin1Char('(') + messagePrefix + QLatin1Char(')'));
+ ReportHandler::setPrefix(u'(' + messagePrefix + u')');
QFileInfoList cppFileNames;
- for (const QString &cppFileName : qAsConst(args.positionalArguments)) {
+ for (const QString &cppFileName : std::as_const(commonOptions.headers)) {
const QFileInfo cppFileNameFi(cppFileName);
if (!cppFileNameFi.isFile() && !cppFileNameFi.isSymLink()) {
- errorPrint(QLatin1Char('"') + cppFileName + QLatin1String("\" does not exist."));
+ errorPrint(u'"' + cppFileName + u"\" does not exist."_s, argV);
return EXIT_FAILURE;
}
cppFileNames.append(cppFileNameFi);
}
- // Pass option to all generators (Cpp/Header generator have the same options)
- for (ait = args.options.begin(); ait != args.options.end(); ) {
- bool found = false;
- for (const GeneratorPtr &generator : qAsConst(generators))
- found |= generator->handleOption(ait.key(), ait.value().toString());
- if (found)
- ait = args.options.erase(ait);
- else
- ++ait;
- }
-
- ait = args.options.find(languageLevelOption());
- if (ait != args.options.end()) {
- const QByteArray languageLevelBA = ait.value().toString().toLatin1();
- args.options.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);
- }
+ optionParser.process(&options);
+ optionParser.clear();
- /* 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.options.remove(QLatin1String("project-file"));
- for (auto it = projectFileArguments.options.cbegin(), end = projectFileArguments.options.cend();
- it != end; ++it) {
- args.options.remove(it.key());
- }
-
- if (!args.options.isEmpty()) {
- errorPrint(msgLeftOverArguments(args.options));
+ if (!options.boolOptions.isEmpty() || !options.valueOptions.isEmpty()) {
+ errorPrint(msgLeftOverArguments(options.msgUnprocessedOptions(), argV), argV);
std::cout << helpHint;
return EXIT_FAILURE;
}
- if (typeSystemFileName.isEmpty()) {
+ if (commonOptions.typeSystemFileName.isEmpty()) {
std::cout << "You must specify a Type System file." << std::endl << helpHint;
return EXIT_FAILURE;
}
extractor.setCppFileNames(cppFileNames);
- extractor.setTypeSystem(typeSystemFileName);
-
- auto shibokenGenerator = dynamic_cast<const ShibokenGenerator *>(generators.constFirst().data());
- const bool usePySideExtensions = shibokenGenerator && shibokenGenerator->usePySideExtensions();
+ extractor.setTypeSystem(commonOptions.typeSystemFileName);
- const std::optional<ApiExtractorResult> apiOpt = extractor.run(usePySideExtensions);
+ ApiExtractorFlags apiExtractorFlags;
+ if (generators.constFirst()->usePySideExtensions())
+ apiExtractorFlags.setFlag(ApiExtractorFlag::UsePySideExtensions);
+ if (generators.constFirst()->avoidProtectedHack())
+ apiExtractorFlags.setFlag(ApiExtractorFlag::AvoidProtectedHack);
+ const std::optional<ApiExtractorResult> apiOpt = extractor.run(apiExtractorFlags);
if (!apiOpt.has_value()) {
- errorPrint(QLatin1String("Error running ApiExtractor."));
+ errorPrint(u"Error running ApiExtractor."_s, argV);
return EXIT_FAILURE;
}
@@ -708,32 +376,59 @@ int shibokenMain(int argc, char *argv[])
<< "\n\nType datase:\n" << *TypeDatabase::instance();
}
- for (const GeneratorPtr &g : qAsConst(generators)) {
- g->setOutputDirectory(outputDirectory);
- g->setLicenseComment(licenseComment);
- ReportHandler::startProgress(QByteArray("Running ") + g->name() + "...");
+ if (commonOptions.printBuiltinTypes)
+ TypeDatabase::instance()->formatBuiltinTypes(qInfo());
+
+ for (const GeneratorPtr &g : std::as_const(generators)) {
+ g->setOutputDirectory(commonOptions.outputDirectory);
+ g->setLicenseComment(commonOptions.licenseComment);
+ ReportHandler::startProgress("Ran "_ba + g->name() + '.');
const bool ok = g->setup(apiOpt.value()) && g->generate();
ReportHandler::endProgress();
if (!ok) {
- errorPrint(QLatin1String("Error running generator: ")
- + QLatin1String(g->name()) + QLatin1Char('.'));
+ errorPrint(u"Error running generator: "_s
+ + QLatin1StringView(g->name()) + u'.', argV);
return EXIT_FAILURE;
}
}
+ if (commonOptions.logUnmatched)
+ TypeDatabase::instance()->logUnmatched();
+
const QByteArray doneMessage = ReportHandler::doneMessage();
std::cout << doneMessage.constData() << std::endl;
return EXIT_SUCCESS;
}
+#ifndef Q_OS_WIN
+
+static inline QString argvToString(const char *arg)
+{
+ return QString::fromLocal8Bit(arg);
+}
+
int main(int argc, char *argv[])
+#else
+
+static inline QString argvToString(const wchar_t *arg)
+{
+ return QString::fromWCharArray(arg);
+}
+
+int wmain(int argc, wchar_t *argv[])
+#endif
{
int ex = EXIT_SUCCESS;
+
+ QStringList argV;
+ argV.reserve(argc - 1);
+ std::transform(argv + 1, argv + argc, std::back_inserter(argV), argvToString);
+
try {
- ex = shibokenMain(argc, argv);
+ ex = shibokenMain(argV);
} catch (const std::exception &e) {
- std::cerr << e.what() << std::endl;
+ std::cerr << appName << " error: " << e.what() << std::endl;
ex = EXIT_FAILURE;
}
return ex;
diff --git a/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp
index 401441d1b..1634a7e83 100644
--- a/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp
+++ b/sources/shiboken6/generator/qtdoc/qtdocgenerator.cpp
@@ -1,33 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qtdocgenerator.h"
+#include "generatorcontext.h"
+#include "codesnip.h"
#include "exception.h"
+#include "abstractmetaargument.h"
#include "apiextractorresult.h"
#include "qtxmltosphinx.h"
#include "rstformat.h"
@@ -37,6 +15,7 @@
#include <abstractmetafield.h>
#include <abstractmetafunction.h>
#include <abstractmetalang.h>
+#include "abstractmetalang_helpers.h"
#include <fileout.h>
#include <messages.h>
#include <modifications.h>
@@ -44,25 +23,97 @@
#include <reporthandler.h>
#include <textstream.h>
#include <typedatabase.h>
-#include <typesystem.h>
+#include <functiontypeentry.h>
+#include <enumtypeentry.h>
+#include <complextypeentry.h>
+#include <flagstypeentry.h>
+#include <primitivetypeentry.h>
#include <qtdocparser.h>
#include <doxygenparser.h>
+#include "qtcompat.h"
+
#include <QtCore/QTextStream>
#include <QtCore/QFile>
#include <QtCore/QDir>
+#include <QtCore/QJsonArray>
+#include <QtCore/QJsonDocument>
+#include <QtCore/QJsonObject>
+#include <QtCore/QSet>
#include <algorithm>
#include <limits>
-static inline QString additionalDocumentationOption() { return QStringLiteral("additional-documentation"); }
+using namespace Qt::StringLiterals;
+
+static inline QString classScope(const AbstractMetaClassCPtr &metaClass)
+{
+ return metaClass->fullName();
+}
+
+struct DocPackage
+{
+ QStringList classPages;
+ QStringList decoratorPages;
+ AbstractMetaFunctionCList globalFunctions;
+ AbstractMetaEnumList globalEnums;
+};
+
+struct DocGeneratorOptions
+{
+ QtXmlToSphinxParameters parameters;
+ QString extraSectionDir;
+ QString additionalDocumentationList;
+ QString inheritanceFile;
+ bool doxygen = false;
+ bool inheritanceDiagram = true;
+};
+
+struct GeneratorDocumentation
+{
+ struct Property
+ {
+ QString name;
+ Documentation documentation;
+ AbstractMetaType type;
+ AbstractMetaFunctionCPtr getter;
+ AbstractMetaFunctionCPtr setter;
+ AbstractMetaFunctionCPtr reset;
+ AbstractMetaFunctionCPtr notify;
+ };
+
+ AbstractMetaFunctionCList allFunctions;
+ AbstractMetaFunctionCList tocNormalFunctions; // Index lists
+ AbstractMetaFunctionCList tocVirtuals;
+ AbstractMetaFunctionCList tocSignalFunctions;
+ AbstractMetaFunctionCList tocSlotFunctions;
+ AbstractMetaFunctionCList tocStaticFunctions;
+
+ QList<Property> properties;
+};
+
+static bool operator<(const GeneratorDocumentation::Property &lhs,
+ const GeneratorDocumentation::Property &rhs)
+{
+ return lhs.name < rhs.name;
+}
-static inline QString none() { return QStringLiteral("None"); }
+static QString propertyRefTarget(const QString &name)
+{
+ QString result = name;
+ // For sphinx referencing, disambiguate the target from the getter name
+ // by appending an invisible "Hangul choseong filler" character.
+ result.append(QChar(0x115F));
+ return result;
+}
+
+constexpr auto additionalDocumentationOption = "additional-documentation"_L1;
+
+constexpr auto none = "None"_L1;
static bool shouldSkip(const AbstractMetaFunctionCPtr &func)
{
- // Constructors go to separate section
- if (DocParser::skipForQuery(func) || func->isConstructor())
+ if (DocParser::skipForQuery(func))
return true;
// Search a const clone (QImage::bits() vs QImage::bits() const)
@@ -75,12 +126,12 @@ static bool shouldSkip(const AbstractMetaFunctionCPtr &func)
if (f != func
&& f->isConstant()
&& f->name() == func->name()
- && f->arguments().count() == funcArgs.count()) {
+ && f->arguments().size() == funcArgs.size()) {
// Compare each argument
bool cloneFound = true;
const AbstractMetaArgumentList fargs = f->arguments();
- for (int i = 0, max = funcArgs.count(); i < max; ++i) {
+ for (qsizetype i = 0, max = funcArgs.size(); i < max; ++i) {
if (funcArgs.at(i).type().typeEntry() != fargs.at(i).type().typeEntry()) {
cloneFound = false;
break;
@@ -95,116 +146,205 @@ static bool shouldSkip(const AbstractMetaFunctionCPtr &func)
static bool functionSort(const AbstractMetaFunctionCPtr &func1, const AbstractMetaFunctionCPtr &func2)
{
- return func1->name() < func2->name();
+ const bool ctor1 = func1->isConstructor();
+ if (ctor1 != func2->isConstructor())
+ return ctor1;
+ const QString &name1 = func1->name();
+ const QString &name2 = func2->name();
+ if (name1 != name2)
+ return name1 < name2;
+ return func1->arguments().size() < func2->arguments().size();
}
-static inline QVersionNumber versionOf(const TypeEntry *te)
+static inline QVersionNumber versionOf(const TypeEntryCPtr &te)
{
if (te) {
const auto version = te->version();
if (!version.isNull() && version > QVersionNumber(0, 0))
return version;
}
- return QVersionNumber();
-}
-
-static const QHash<QString, QString> &operatorMapping()
-{
- static const QHash<QString, QString> result = {
- {QLatin1String("operator+"), QLatin1String("__add__")},
- {QLatin1String("operator+="), QLatin1String("__iadd__")},
- {QLatin1String("operator-"), QLatin1String("__sub__")},
- {QLatin1String("operator-="), QLatin1String("__isub__")},
- {QLatin1String("operator*"), QLatin1String("__mul__")},
- {QLatin1String("operator*="), QLatin1String("__imul__")},
- {QLatin1String("operator/"), QLatin1String("__div__")},
- {QLatin1String("operator/="), QLatin1String("__idiv__")},
- {QLatin1String("operator%"), QLatin1String("__mod__")},
- {QLatin1String("operator%="), QLatin1String("__imod__")},
- {QLatin1String("operator<<"), QLatin1String("__lshift__")},
- {QLatin1String("operator<<="), QLatin1String("__ilshift__")},
- {QLatin1String("operator>>"), QLatin1String("__rshift__")},
- {QLatin1String("operator>>="), QLatin1String("__irshift__")},
- {QLatin1String("operator&"), QLatin1String("__and__")},
- {QLatin1String("operator&="), QLatin1String("__iand__")},
- {QLatin1String("operator|"), QLatin1String("__or__")},
- {QLatin1String("operator|="), QLatin1String("__ior__")},
- {QLatin1String("operator^"), QLatin1String("__xor__")},
- {QLatin1String("operator^="), QLatin1String("__ixor__")},
- {QLatin1String("operator=="), QLatin1String("__eq__")},
- {QLatin1String("operator!="), QLatin1String("__ne__")},
- {QLatin1String("operator<"), QLatin1String("__lt__")},
- {QLatin1String("operator<="), QLatin1String("__le__")},
- {QLatin1String("operator>"), QLatin1String("__gt__")},
- {QLatin1String("operator>="), QLatin1String("__ge__")},
- };
- return result;
+ return {};
+}
+
+struct docRef
+{
+ explicit docRef(const char *kind, QAnyStringView name) :
+ m_kind(kind), m_name(name) {}
+
+ const char *m_kind;
+ QAnyStringView m_name;
+};
+
+static TextStream &operator<<(TextStream &s, const docRef &dr)
+{
+ s << ':' << dr.m_kind << ":`" << dr.m_name << '`';
+ return s;
}
-static QString getFuncName(const AbstractMetaFunctionCPtr& cppFunc)
+static QString fileNameToTocEntry(const QString &fileName)
{
- const auto it = operatorMapping().constFind(cppFunc->name());
- QString result = it != operatorMapping().cend() ? it.value() : cppFunc->name();
- result.replace(QLatin1String("::"), QLatin1String("."));
+ constexpr auto rstSuffix = ".rst"_L1;
+
+ QString result = fileName;
+ if (result.endsWith(rstSuffix))
+ result.chop(rstSuffix.size()); // Remove the .rst extension
+ // skip namespace if necessary
+ auto lastDot = result.lastIndexOf(u'.');
+ if (lastDot != -1)
+ result.remove(0, lastDot + 1);
return result;
}
+static void readExtraDoc(const QFileInfo &fi,
+ const QString &moduleName,
+ const QString &outputDir,
+ DocPackage *docPackage, QStringList *extraTocEntries)
+{
+ // Strip to "Property.rst" in output directory
+ const QString newFileName = fi.fileName().mid(moduleName.size() + 1);
+ QFile sourceFile(fi.absoluteFilePath());
+ if (!sourceFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
+ qCWarning(lcShibokenDoc, "%s", qPrintable(msgCannotOpenForReading(sourceFile)));
+ return;
+ }
+ const QByteArray contents = sourceFile.readAll();
+ sourceFile.close();
+ QFile targetFile(outputDir + u'/' + newFileName);
+ if (!targetFile.open(QIODevice::WriteOnly|QIODevice::Text)) {
+ qCWarning(lcShibokenDoc, "%s", qPrintable(msgCannotOpenForWriting(targetFile)));
+ return;
+ }
+ targetFile.write(contents);
+ if (contents.contains("decorator::"))
+ docPackage->decoratorPages.append(newFileName);
+ else
+ docPackage->classPages.append(newFileName);
+ extraTocEntries->append(fileNameToTocEntry(newFileName));
+}
+
+// Format a short documentation reference (automatically dropping the prefix
+// by using '~'), usable for property/attributes ("attr").
+struct shortDocRef
+{
+ explicit shortDocRef(const char *kind, QAnyStringView name) :
+ m_kind(kind), m_name(name) {}
+
+ const char *m_kind;
+ QAnyStringView m_name;
+};
+
+static TextStream &operator<<(TextStream &s, const shortDocRef &sdr)
+{
+ s << ':' << sdr.m_kind << ":`~" << sdr.m_name << '`';
+ return s;
+}
+
+struct functionRef : public docRef
+{
+ explicit functionRef(QAnyStringView name) : docRef("meth", name) {}
+};
+
+struct classRef : public shortDocRef
+{
+ explicit classRef(QAnyStringView name) : shortDocRef("class", name) {}
+};
+
+struct propRef : public shortDocRef // Attribute/property (short) reference
+{
+ explicit propRef(const QString &target) :
+ shortDocRef("attr", target) {}
+};
+
+struct headline
+{
+ explicit headline(QAnyStringView title, char underLineChar = '-') :
+ m_title(title), m_underLineChar(underLineChar) {}
+
+ QAnyStringView m_title;
+ char m_underLineChar;
+};
+
+static TextStream &operator<<(TextStream &s, const headline &h)
+{
+ s << h.m_title << '\n' << Pad(h.m_underLineChar, h.m_title.size()) << "\n\n";
+ return s;
+}
+
+struct pyClass
+{
+ explicit pyClass(QAnyStringView name) : m_name(name) {}
+
+ QAnyStringView m_name;
+};
+
+static TextStream &operator<<(TextStream &s, pyClass c)
+{
+ s << ".. py:class:: " << c.m_name << "\n\n";
+ return s;
+}
+
+struct currentModule
+{
+ explicit currentModule(QAnyStringView module) : m_module(module) {}
+
+ QAnyStringView m_module;
+};
+
+static TextStream &operator<<(TextStream &s, const currentModule &m)
+{
+ s << ".. currentmodule:: " << m.m_module << "\n\n\n";
+ return s;
+}
+
+DocGeneratorOptions QtDocGenerator::m_options;
+
QtDocGenerator::QtDocGenerator()
{
- m_parameters.snippetComparison =
+ m_options.parameters.snippetComparison =
ReportHandler::debugLevel() >= ReportHandler::FullDebug;
}
QtDocGenerator::~QtDocGenerator() = default;
-QString QtDocGenerator::fileNameSuffix() const
+QString QtDocGenerator::fileNameSuffix()
{
- return QLatin1String(".rst");
+ return u".rst"_s;
}
-bool QtDocGenerator::shouldGenerate(const AbstractMetaClass *cls) const
+bool QtDocGenerator::shouldGenerate(const TypeEntryCPtr &te) const
{
- return Generator::shouldGenerate(cls)
- && cls->typeEntry()->type() != TypeEntry::SmartPointerType;
+ return Generator::shouldGenerate(te)
+ && te->type() != TypeEntry::SmartPointerType;
}
QString QtDocGenerator::fileNameForContext(const GeneratorContext &context) const
{
- const AbstractMetaClass *metaClass = context.metaClass();
- if (!context.forSmartPointer()) {
- return metaClass->name() + fileNameSuffix();
- }
- const AbstractMetaType &smartPointerType = context.preciseType();
- QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass);
- return fileNameBase + fileNameSuffix();
+ return fileNameForContextHelper(context, fileNameSuffix(),
+ FileNameFlag::UnqualifiedName
+ | FileNameFlag::KeepCase);
}
void QtDocGenerator::writeFormattedBriefText(TextStream &s, const Documentation &doc,
- const AbstractMetaClass *metaclass) const
+ const QString &scope) const
{
- writeFormattedText(s, doc.brief(), doc.format(), metaclass);
+ writeFormattedText(s, doc.brief(), doc.format(), scope);
}
void QtDocGenerator::writeFormattedDetailedText(TextStream &s, const Documentation &doc,
- const AbstractMetaClass *metaclass) const
+ const QString &scope) const
{
- writeFormattedText(s, doc.detailed(), doc.format(), metaclass);
+ writeFormattedText(s, doc.detailed(), doc.format(), scope);
}
void QtDocGenerator::writeFormattedText(TextStream &s, const QString &doc,
Documentation::Format format,
- const AbstractMetaClass *metaClass) const
+ const QString &scope) const
{
- QString metaClassName;
-
- if (metaClass)
- metaClassName = metaClass->fullName();
-
if (format == Documentation::Native) {
- QtXmlToSphinx x(this, m_parameters, doc, metaClassName);
+ QtXmlToSphinx x(this, m_options.parameters, doc, scope);
s << x;
} else {
- const auto lines = QStringView{doc}.split(QLatin1Char('\n'));
+ const auto lines = QStringView{doc}.split(u'\n');
int typesystemIndentation = std::numeric_limits<int>::max();
// check how many spaces must be removed from the beginning of each line
for (const auto &line : lines) {
@@ -225,50 +365,71 @@ void QtDocGenerator::writeFormattedText(TextStream &s, const QString &doc,
s << '\n';
}
-static void writeInheritedByList(TextStream& s, const AbstractMetaClass* metaClass,
+static void writeInheritanceList(TextStream &s, const AbstractMetaClassCList& classes,
+ const char *label)
+{
+ s << "**" << label << ":** ";
+ for (qsizetype i = 0, size = classes.size(); i < size; ++i) {
+ if (i > 0)
+ s << ", ";
+ s << classRef(classes.at(i)->fullName());
+ }
+ s << "\n\n";
+}
+
+static void writeInheritedByList(TextStream &s, const AbstractMetaClassCPtr &metaClass,
const AbstractMetaClassCList& allClasses)
{
AbstractMetaClassCList res;
- for (auto c : allClasses) {
- if (c != metaClass && c->inheritsFrom(metaClass))
+ for (const auto &c : allClasses) {
+ if (c != metaClass && inheritsFrom(c, metaClass))
res << c;
}
- if (res.isEmpty())
- return;
+ if (!res.isEmpty())
+ writeInheritanceList(s, res, "Inherited by");
+}
+
+static void writeInheritedFromList(TextStream &s, const AbstractMetaClassCPtr &metaClass)
+{
+ AbstractMetaClassCList res;
+
+ recurseClassHierarchy(metaClass, [&res, metaClass](const AbstractMetaClassCPtr &c) {
+ if (c.get() != metaClass.get())
+ res.append(c);
+ return false;
+ });
- s << "**Inherited by:** ";
- QStringList classes;
- for (auto c : qAsConst(res))
- classes << QLatin1String(":ref:`") + c->name() + QLatin1Char('`');
- s << classes.join(QLatin1String(", ")) << "\n\n";
+ if (!res.isEmpty())
+ writeInheritanceList(s, res, "Inherits from");
}
void QtDocGenerator::generateClass(TextStream &s, const GeneratorContext &classContext)
{
- const AbstractMetaClass *metaClass = classContext.metaClass();
+ AbstractMetaClassCPtr metaClass = classContext.metaClass();
qCDebug(lcShibokenDoc).noquote().nospace() << "Generating Documentation for " << metaClass->fullName();
- m_packages[metaClass->package()] << fileNameForContext(classContext);
+ m_packages[metaClass->package()].classPages << fileNameForContext(classContext);
m_docParser->setPackageName(metaClass->package());
- m_docParser->fillDocumentation(const_cast<AbstractMetaClass*>(metaClass));
-
- QString className = metaClass->name();
- s << ".. _" << className << ":" << "\n\n";
- s << ".. currentmodule:: " << metaClass->package() << "\n\n\n";
+ m_docParser->fillDocumentation(std::const_pointer_cast<AbstractMetaClass>(metaClass));
- s << className << '\n';
- s << Pad('*', className.count()) << "\n\n";
+ s << currentModule(metaClass->package()) << pyClass(metaClass->name());
+ Indentation indent(s);
auto documentation = metaClass->documentation();
+ const QString scope = classScope(metaClass);
if (documentation.hasBrief())
- writeFormattedBriefText(s, documentation, metaClass);
-
- s << ".. inheritance-diagram:: " << metaClass->fullName()<< '\n'
- << " :parts: 2\n\n";
- // TODO: This would be a parameter in the future...
+ writeFormattedBriefText(s, documentation, scope);
+ if (!metaClass->baseClasses().isEmpty()) {
+ if (m_options.inheritanceDiagram) {
+ s << ".. inheritance-diagram:: " << metaClass->fullName()<< '\n'
+ << " :parts: 2\n\n";
+ } else {
+ writeInheritedFromList(s, metaClass);
+ }
+ }
writeInheritedByList(s, metaClass, api().classes());
@@ -278,123 +439,113 @@ void QtDocGenerator::generateClass(TextStream &s, const GeneratorContext &classC
if (metaClass->attributes().testFlag(AbstractMetaClass::Deprecated))
s << rstDeprecationNote("class");
- writeFunctionList(s, metaClass);
-
- //Function list
- auto functionList = metaClass->functions();
- std::sort(functionList.begin(), functionList.end(), functionSort);
+ const GeneratorDocumentation doc = generatorDocumentation(metaClass);
- s << "\nDetailed Description\n"
- "--------------------\n\n"
- << ".. _More:\n";
+ if (!doc.allFunctions.isEmpty() || !doc.properties.isEmpty()) {
+ s << '\n' << headline("Synopsis");
+ writePropertyToc(s, doc);
+ writeFunctionToc(s, u"Methods"_s, doc.tocNormalFunctions);
+ writeFunctionToc(s, u"Virtual methods"_s, doc.tocVirtuals);
+ writeFunctionToc(s, u"Slots"_s, doc.tocSlotFunctions);
+ writeFunctionToc(s, u"Signals"_s, doc.tocSignalFunctions);
+ writeFunctionToc(s, u"Static functions"_s, doc.tocStaticFunctions);
+ }
- writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, metaClass, nullptr);
- if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, metaClass, nullptr))
- writeFormattedDetailedText(s, documentation, metaClass);
+ s << "\n.. note::\n"
+ " This documentation may contain snippets that were automatically\n"
+ " translated from C++ to Python. We always welcome contributions\n"
+ " to the snippet translation. If you see an issue with the\n"
+ " translation, you can also let us know by creating a ticket on\n"
+ " https:/bugreports.qt.io/projects/PYSIDE\n\n";
- if (!metaClass->isNamespace())
- writeConstructors(s, metaClass);
- writeEnums(s, metaClass);
- if (!metaClass->isNamespace())
- writeFields(s, metaClass);
+ s << '\n' << headline("Detailed Description") << ".. _More:\n";
+ writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, metaClass);
+ if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, metaClass))
+ writeFormattedDetailedText(s, documentation, scope);
+ writeInjectDocumentation(s, TypeSystem::DocModificationAppend, metaClass);
- QStringList uniqueFunctions;
- for (const auto &func : qAsConst(functionList)) {
- if (shouldSkip(func))
- continue;
+ writeEnums(s, metaClass->enums(), scope);
- if (func->isStatic())
- s << ".. staticmethod:: ";
- else
- s << ".. method:: ";
+ if (!doc.properties.isEmpty())
+ writeProperties(s, doc, metaClass);
- writeFunction(s, metaClass, func, !uniqueFunctions.contains(func->name()));
- uniqueFunctions.append(func->name());
- }
+ if (!metaClass->isNamespace())
+ writeFields(s, metaClass);
- writeInjectDocumentation(s, TypeSystem::DocModificationAppend, metaClass, nullptr);
+ writeFunctions(s, doc.allFunctions, metaClass, scope);
}
-void QtDocGenerator::writeFunctionList(TextStream& s, const AbstractMetaClass* cppClass)
+void QtDocGenerator::writeFunctionToc(TextStream &s, const QString &title,
+ const AbstractMetaFunctionCList &functions)
{
- QStringList functionList;
- QStringList virtualList;
- QStringList signalList;
- QStringList slotList;
- QStringList staticFunctionList;
-
- const auto &classFunctions = cppClass->functions();
- for (const auto &func : classFunctions) {
- if (shouldSkip(func))
- continue;
-
- QString className;
- if (!func->isConstructor())
- className = cppClass->fullName() + QLatin1Char('.');
- else if (func->implementingClass() && func->implementingClass()->enclosingClass())
- className = func->implementingClass()->enclosingClass()->fullName() + 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 (!functions.isEmpty()) {
+ s << headline(title, '^')
+ << ".. container:: function_list\n\n" << indent;
+ // Functions are sorted by the Metabuilder; erase overloads
+ QStringList toc;
+ toc.reserve(functions.size());
+ std::transform(functions.cbegin(), functions.end(),
+ std::back_inserter(toc), getFuncName);
+ toc.erase(std::unique(toc.begin(), toc.end()), toc.end());
+ for (const auto &func : toc)
+ s << "* def " << functionRef(func) << '\n';
+ s << outdent << "\n\n";
}
+}
- if (!functionList.isEmpty() || !staticFunctionList.isEmpty()) {
- QtXmlToSphinx::Table functionTable;
-
- s << "\nSynopsis\n--------\n\n";
+void QtDocGenerator::writePropertyToc(TextStream &s,
+ const GeneratorDocumentation &doc)
+{
+ if (doc.properties.isEmpty())
+ return;
- 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);
+ s << headline("Properties", '^')
+ << ".. container:: function_list\n\n" << indent;
+ for (const auto &prop : doc.properties) {
+ s << "* " << propRef(propertyRefTarget(prop.name));
+ if (prop.documentation.hasBrief())
+ s << " - " << prop.documentation.brief();
+ s << '\n';
}
+ s << outdent << "\n\n";
}
-void QtDocGenerator::writeFunctionBlock(TextStream& s, const QString& title, QStringList& functions)
+void QtDocGenerator::writeProperties(TextStream &s,
+ const GeneratorDocumentation &doc,
+ const AbstractMetaClassCPtr &cppClass) const
{
- if (!functions.isEmpty()) {
- s << title << '\n'
- << Pad('^', title.size()) << '\n';
-
- std::sort(functions.begin(), functions.end());
-
- s << ".. container:: function_list\n\n";
- Indentation indentation(s);
- for (const QString &func : qAsConst(functions))
- s << "* " << func << '\n';
- s << "\n\n";
+ s << "\n.. note:: Properties can be used directly when "
+ << "``from __feature__ import true_property`` is used or via accessor "
+ << "functions otherwise.\n\n";
+
+ const QString scope = classScope(cppClass);
+ for (const auto &prop : doc.properties) {
+ const QString type = translateToPythonType(prop.type, cppClass, /* createRef */ false);
+ s << ".. py:property:: " << propertyRefTarget(prop.name)
+ << "\n :type: " << type << "\n\n\n";
+ if (!prop.documentation.isEmpty())
+ writeFormattedText(s, prop.documentation.detailed(), Documentation::Native, scope);
+ s << "**Access functions:**\n";
+ if (prop.getter)
+ s << " * " << functionRef(prop.getter->name()) << '\n';
+ if (prop.setter)
+ s << " * " << functionRef(prop.setter->name()) << '\n';
+ if (prop.reset)
+ s << " * " << functionRef(prop.reset->name()) << '\n';
+ if (prop.notify)
+ s << " * Signal " << functionRef(prop.notify->name()) << '\n';
+ s << '\n';
}
}
-void QtDocGenerator::writeEnums(TextStream& s, const AbstractMetaClass* cppClass) const
+void QtDocGenerator::writeEnums(TextStream &s, const AbstractMetaEnumList &enums,
+ const QString &scope) const
{
- static const QString section_title = QLatin1String(".. attribute:: ");
-
- for (const AbstractMetaEnum &en : cppClass->enums()) {
- s << section_title << cppClass->fullName() << '.' << en.name() << "\n\n";
- writeFormattedDetailedText(s, en.documentation(), cppClass);
+ for (const AbstractMetaEnum &en : enums) {
+ s << pyClass(en.name());
+ Indentation indent(s);
+ writeFormattedDetailedText(s, en.documentation(), scope);
const auto version = versionOf(en.typeEntry());
if (!version.isNull())
s << rstVersionAdded(version);
@@ -402,116 +553,61 @@ void QtDocGenerator::writeEnums(TextStream& s, const AbstractMetaClass* cppClass
}
-void QtDocGenerator::writeFields(TextStream& s, const AbstractMetaClass* cppClass) const
+void QtDocGenerator::writeFields(TextStream &s, const AbstractMetaClassCPtr &cppClass) const
{
- static const QString section_title = QLatin1String(".. attribute:: ");
+ constexpr auto section_title = ".. attribute:: "_L1;
+ const QString scope = classScope(cppClass);
for (const AbstractMetaField &field : cppClass->fields()) {
s << section_title << cppClass->fullName() << "." << field.name() << "\n\n";
- writeFormattedDetailedText(s, field.documentation(), cppClass);
- }
-}
-
-void QtDocGenerator::writeConstructors(TextStream& s, const AbstractMetaClass* cppClass) const
-{
- static const QString sectionTitle = QLatin1String(".. class:: ");
-
- auto lst = cppClass->queryFunctions(FunctionQueryOption::Constructors | FunctionQueryOption::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;
-
- if (lst.isEmpty()) {
- s << sectionTitle << cppClass->fullName();
- } else {
- QByteArray pad;
- for (const auto &func : qAsConst(lst)) {
- s << pad;
- if (first) {
- first = false;
- s << sectionTitle;
- pad = QByteArray(sectionTitle.size(), ' ');
- }
- s << functionSignature(cppClass, func) << "\n\n";
-
- const auto version = versionOf(func->typeEntry());
- if (!version.isNull())
- s << pad << rstVersionAdded(version);
- if (func->attributes().testFlag(AbstractMetaFunction::Deprecated))
- s << pad << rstDeprecationNote("constructor");
-
- const AbstractMetaArgumentList &arguments = func->arguments();
- for (const AbstractMetaArgument &arg : arguments) {
- if (!arg_map.contains(arg.name())) {
- arg_map.insert(arg.name(), arg);
- }
- }
- }
- }
-
- s << '\n';
-
- for (auto it = arg_map.cbegin(), end = arg_map.cend(); it != end; ++it) {
- s.indent(2);
- writeParameterType(s, cppClass, it.value());
- s.outdent(2);
+ writeFormattedDetailedText(s, field.documentation(), scope);
}
-
- s << '\n';
-
- for (const auto &func : qAsConst(lst))
- writeFormattedDetailedText(s, func->documentation(), cppClass);
}
-QString QtDocGenerator::parseArgDocStyle(const AbstractMetaClass* /* cppClass */,
- const AbstractMetaFunctionCPtr &func)
+QString QtDocGenerator::formatArgs(const AbstractMetaFunctionCPtr &func)
{
- QString ret;
+ QString ret = u"("_s;
int optArgs = 0;
const AbstractMetaArgumentList &arguments = func->arguments();
for (const AbstractMetaArgument &arg : arguments) {
- if (func->argumentRemoved(arg.argumentIndex() + 1))
+ if (arg.isModifiedRemoved())
continue;
bool thisIsoptional = !arg.defaultValueExpression().isEmpty();
if (optArgs || thisIsoptional) {
- ret += QLatin1Char('[');
+ ret += u'[';
optArgs++;
}
if (arg.argumentIndex() > 0)
- ret += QLatin1String(", ");
+ ret += u", "_s;
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();
+ if (defValue == u"QString()") {
+ defValue = u"\"\""_s;
+ } else if (defValue == u"QStringList()"
+ || defValue.startsWith(u"QVector")
+ || defValue.startsWith(u"QList")) {
+ defValue = u"list()"_s;
+ } else if (defValue == u"QVariant()") {
+ defValue = none;
} else {
- defValue.replace(QLatin1String("::"), QLatin1String("."));
- if (defValue == QLatin1String("nullptr"))
- defValue = none();
- else if (defValue == QLatin1String("0") && arg.type().isObject())
- defValue = none();
+ defValue.replace(u"::"_s, u"."_s);
+ if (defValue == u"nullptr")
+ defValue = none;
+ else if (defValue == u"0" && arg.type().isObject())
+ defValue = none;
}
- ret += QLatin1Char('=') + defValue;
+ ret += u'=' + defValue;
}
}
- ret += QString(optArgs, QLatin1Char(']'));
+ ret += QString(optArgs, u']') + u')';
return ret;
}
@@ -521,11 +617,9 @@ void QtDocGenerator::writeDocSnips(TextStream &s,
TypeSystem::Language language)
{
Indentation indentation(s);
- QStringList invalidStrings;
- const static QString startMarkup = QLatin1String("[sphinx-begin]");
- const static QString endMarkup = QLatin1String("[sphinx-end]");
-
- invalidStrings << QLatin1String("*") << QLatin1String("//") << QLatin1String("/*") << QLatin1String("*/");
+ static const QStringList invalidStrings{u"*"_s, u"//"_s, u"/*"_s, u"*/"_s};
+ const static QString startMarkup = u"[sphinx-begin]"_s;
+ const static QString endMarkup = u"[sphinx-end]"_s;
for (const CodeSnip &snip : codeSnips) {
if ((snip.position != position) ||
@@ -534,19 +628,19 @@ void QtDocGenerator::writeDocSnips(TextStream &s,
QString code = snip.code();
while (code.contains(startMarkup) && code.contains(endMarkup)) {
- int startBlock = code.indexOf(startMarkup) + startMarkup.size();
- int endBlock = code.indexOf(endMarkup);
+ const auto startBlock = code.indexOf(startMarkup) + startMarkup.size();
+ const auto endBlock = code.indexOf(endMarkup);
if ((startBlock == -1) || (endBlock == -1))
break;
QString codeBlock = code.mid(startBlock, endBlock - startBlock);
- const QStringList rows = codeBlock.split(QLatin1Char('\n'));
+ const QStringList rows = codeBlock.split(u'\n');
int currentRow = 0;
- int offset = 0;
+ qsizetype offset = 0;
for (QString row : rows) {
- for (const QString &invalidString : qAsConst(invalidStrings))
+ for (const QString &invalidString : std::as_const(invalidStrings))
row.remove(invalidString);
if (row.trimmed().size() == 0) {
@@ -558,9 +652,9 @@ void QtDocGenerator::writeDocSnips(TextStream &s,
if (currentRow == 0) {
//find offset
for (auto c : row) {
- if (c == QLatin1Char(' '))
+ if (c == u' ')
offset++;
- else if (c == QLatin1Char('\n'))
+ else if (c == u'\n')
offset = 0;
else
break;
@@ -575,304 +669,472 @@ void QtDocGenerator::writeDocSnips(TextStream &s,
}
}
-bool QtDocGenerator::writeInjectDocumentation(TextStream& s,
- TypeSystem::DocModificationMode mode,
- const AbstractMetaClass* cppClass,
- const AbstractMetaFunctionCPtr &func)
+bool QtDocGenerator::writeDocModifications(TextStream &s,
+ const DocModificationList &mods,
+ TypeSystem::DocModificationMode mode,
+ const QString &scope) const
{
- Indentation indentation(s);
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::Format fmt;
-
- if (mod.format() == TypeSystem::NativeCode)
- fmt = Documentation::Native;
- else if (mod.format() == TypeSystem::TargetLangCode)
- fmt = Documentation::Target;
- else
- continue;
-
- writeFormattedText(s, mod.code(), fmt, cppClass);
+ switch (mod.format()) {
+ case TypeSystem::NativeCode:
+ writeFormattedText(s, mod.code(), Documentation::Native, scope);
didSomething = true;
+ break;
+ case TypeSystem::TargetLangCode:
+ writeFormattedText(s, mod.code(), Documentation::Target, scope);
+ didSomething = true;
+ break;
+ default:
+ break;
}
}
}
+ return didSomething;
+}
+bool QtDocGenerator::writeInjectDocumentation(TextStream &s,
+ TypeSystem::DocModificationMode mode,
+ const AbstractMetaClassCPtr &cppClass) const
+{
+ const bool didSomething =
+ writeDocModifications(s, DocParser::getDocModifications(cppClass),
+ mode, classScope(cppClass));
s << '\n';
- // TODO: Deprecate the use of doc string on glue code.
+ // FIXME PYSIDE-7: 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);
+ writeDocSnips(s, cppClass->typeEntry()->codeSnips(), pos, TypeSystem::TargetLangCode);
return didSomething;
}
-QString QtDocGenerator::functionSignature(const AbstractMetaClass* cppClass,
- const AbstractMetaFunctionCPtr &func)
+bool QtDocGenerator::writeInjectDocumentation(TextStream &s,
+ TypeSystem::DocModificationMode mode,
+ const DocModificationList &modifications,
+ const AbstractMetaFunctionCPtr &func,
+ const QString &scope) const
{
- QString funcName;
+ const bool didSomething = writeDocModifications(s, modifications, mode, scope);
+ s << '\n';
- funcName = cppClass->fullName();
- if (!func->isConstructor())
- funcName += QLatin1Char('.') + getFuncName(func);
+ // FIXME PYSIDE-7: 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;
+ writeDocSnips(s, func->injectedCodeSnips(), pos, TypeSystem::TargetLangCode);
+ return didSomething;
+}
- return funcName + QLatin1Char('(') + parseArgDocStyle(cppClass, func)
- + QLatin1Char(')');
+static QString inline toRef(const QString &t)
+{
+ return ":class:`~"_L1 + t + u'`';
}
QString QtDocGenerator::translateToPythonType(const AbstractMetaType &type,
- const AbstractMetaClass* cppClass) const
+ const AbstractMetaClassCPtr &cppClass,
+ bool createRef) const
{
static const QStringList nativeTypes =
- {boolT(), floatT(), intT(), pyObjectT(), pyStrT()};
+ {boolT, floatT, intT, pyObjectT, pyStrT};
- const QString name = type.name();
+ QString name = type.name();
if (nativeTypes.contains(name))
return name;
- static const QMap<QString, QString> typeMap = {
- { cPyObjectT(), pyObjectT() },
- { qStringT(), pyStrT() },
- { QLatin1String("uchar"), pyStrT() },
- { QLatin1String("QStringList"), QLatin1String("list of strings") },
- { qVariantT(), pyObjectT() },
- { QLatin1String("quint32"), intT() },
- { QLatin1String("uint32_t"), intT() },
- { QLatin1String("quint64"), intT() },
- { QLatin1String("qint64"), intT() },
- { QLatin1String("size_t"), intT() },
- { QLatin1String("int64_t"), intT() },
- { QLatin1String("qreal"), floatT() }
+ if (type.typeUsagePattern() == AbstractMetaType::PrimitivePattern) {
+ const auto &basicName = basicReferencedTypeEntry(type.typeEntry())->name();
+ if (AbstractMetaType::cppSignedIntTypes().contains(basicName)
+ || AbstractMetaType::cppUnsignedIntTypes().contains(basicName)) {
+ return intT;
+ }
+ if (AbstractMetaType::cppFloatTypes().contains(basicName))
+ return floatT;
+ }
+
+ static const QSet<QString> stringTypes = {
+ u"uchar"_s, u"std::string"_s, u"std::wstring"_s,
+ u"std::stringview"_s, u"std::wstringview"_s,
+ qStringT, u"QStringView"_s, u"QAnyStringView"_s, u"QUtf8StringView"_s
+ };
+ if (stringTypes.contains(name))
+ return pyStrT;
+
+ static const QHash<QString, QString> typeMap = {
+ { cPyObjectT, pyObjectT },
+ { u"QStringList"_s, u"list of strings"_s },
+ { qVariantT, pyObjectT }
};
- const auto found = typeMap.find(name);
- if (found != typeMap.end())
+ const auto found = typeMap.constFind(name);
+ if (found != typeMap.cend())
return found.value();
- QString strType;
- if (type.isConstant() && name == QLatin1String("char") && type.indirections() == 1) {
- strType = QLatin1String("str");
- } else if (name.startsWith(unsignedShortT())) {
- strType = intT();
- } else if (name.startsWith(unsignedT())) { // uint and ulong
- strType = intT();
- } else if (type.isContainer()) {
+ if (type.isFlags()) {
+ const auto fte = std::static_pointer_cast<const FlagsTypeEntry>(type.typeEntry());
+ auto enumTypeEntry = fte->originator();
+ auto enumName = enumTypeEntry->targetLangName();
+ if (createRef)
+ enumName.prepend(enumTypeEntry->targetLangPackage() + u'.');
+ return "Combination of "_L1 + (createRef ? toRef(enumName) : enumName);
+ } else if (type.isEnum()) {
+ auto enumTypeEntry = std::static_pointer_cast<const EnumTypeEntry>(type.typeEntry());
+ auto enumName = enumTypeEntry->targetLangName();
+ if (createRef)
+ enumName.prepend(enumTypeEntry->targetLangPackage() + u'.');
+ return createRef ? toRef(enumName) : enumName;
+ }
+
+ if (type.isConstant() && name == "char"_L1 && type.indirections() == 1)
+ return "str"_L1;
+
+ 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.remove(u'*');
+ strType.remove(u'>');
+ strType.remove(u'<');
+ strType.replace(u"::"_s, u"."_s);
+ if (strType.contains(u"QList") || strType.contains(u"QVector")) {
+ strType.replace(u"QList"_s, u"list of "_s);
+ strType.replace(u"QVector"_s, u"list of "_s);
+ } else if (strType.contains(u"QHash") || strType.contains(u"QMap")) {
+ strType.remove(u"QHash"_s);
+ strType.remove(u"QMap"_s);
+ QStringList types = strType.split(u',');
strType = QString::fromLatin1("Dictionary with keys of type %1 and values of type %2.")
.arg(types[0], types[1]);
}
- } else {
- auto k = AbstractMetaClass::findClass(api().classes(), type.typeEntry());
- strType = k ? k->fullName() : type.name();
- strType = QStringLiteral(":any:`") + strType + QLatin1Char('`');
+ return strType;
}
- return strType;
+
+ if (auto k = AbstractMetaClass::findClass(api().classes(), type.typeEntry()))
+ return createRef ? toRef(k->fullName()) : k->name();
+
+ return createRef ? toRef(name) : name;
}
-void QtDocGenerator::writeParameterType(TextStream& s, const AbstractMetaClass* cppClass,
+QString QtDocGenerator::getFuncName(const AbstractMetaFunctionCPtr &cppFunc)
+{
+ if (cppFunc->isConstructor())
+ return "__init__"_L1;
+ QString result = cppFunc->name();
+ if (cppFunc->isOperatorOverload()) {
+ const QString pythonOperator = Generator::pythonOperatorFunctionName(result);
+ if (!pythonOperator.isEmpty())
+ return pythonOperator;
+ }
+ result.replace(u"::"_s, u"."_s);
+ return result;
+}
+
+void QtDocGenerator::writeParameterType(TextStream &s,
+ const AbstractMetaClassCPtr &cppClass,
const AbstractMetaArgument &arg) const
{
s << ":param " << arg.name() << ": "
<< translateToPythonType(arg.type(), cppClass) << '\n';
}
-void QtDocGenerator::writeFunctionParametersType(TextStream &s, const AbstractMetaClass *cppClass,
+void QtDocGenerator::writeFunctionParametersType(TextStream &s,
+ const AbstractMetaClassCPtr &cppClass,
const AbstractMetaFunctionCPtr &func) const
{
s << '\n';
const AbstractMetaArgumentList &funcArgs = func->arguments();
for (const AbstractMetaArgument &arg : funcArgs) {
-
- if (func->argumentRemoved(arg.argumentIndex() + 1))
- continue;
-
- writeParameterType(s, cppClass, arg);
+ if (!arg.isModifiedRemoved())
+ writeParameterType(s, cppClass, arg);
}
- if (!func->isConstructor() && !func->isVoid()) {
-
- QString retType;
+ QString retType;
+ if (!func->isConstructor()) {
// check if the return type was modified
- for (const auto &mod : func->modifications()) {
- for (const ArgumentModification &argMod : mod.argument_mods()) {
- if (argMod.index() == 0) {
- retType = argMod.modifiedType();
- break;
- }
- }
- }
-
- if (retType.isEmpty())
+ retType = func->modifiedTypeName();
+ if (retType.isEmpty() && !func->isVoid())
retType = translateToPythonType(func->type(), cppClass);
- s << ":rtype: " << retType << '\n';
}
+
+ if (!retType.isEmpty())
+ s << ":rtype: " << retType << '\n';
+
s << '\n';
}
-void QtDocGenerator::writeFunction(TextStream& s, const AbstractMetaClass* cppClass,
- const AbstractMetaFunctionCPtr &func, bool indexed)
+static bool containsFunctionDirective(const DocModification &dm)
{
- s << functionSignature(cppClass, func);
+ return dm.mode() != TypeSystem::DocModificationXPathReplace
+ && dm.code().contains(".. py:"_L1);
+}
- {
+void QtDocGenerator::writeFunctions(TextStream &s, const AbstractMetaFunctionCList &funcs,
+ const AbstractMetaClassCPtr &cppClass, const QString &scope)
+{
+ QString lastName;
+ for (const auto &func : funcs) {
+ const bool indexed = func->name() != lastName;
+ lastName = func->name();
+ writeFunction(s, func, cppClass, scope, indexed);
+ }
+}
+
+void QtDocGenerator::writeFunction(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaClassCPtr &cppClass,
+ const QString &scope, bool indexed)
+{
+ const auto modifications = DocParser::getDocModifications(func, cppClass);
+
+ // Enable injecting parameter documentation by adding a complete function directive.
+ if (std::none_of(modifications.cbegin(), modifications.cend(), containsFunctionDirective)) {
+ if (func->ownerClass() == nullptr)
+ s << ".. py:function:: ";
+ else
+ s << (func->isStatic() ? ".. py:staticmethod:: " : ".. py:method:: ");
+ s << getFuncName(func) << formatArgs(func);
Indentation indentation(s);
if (!indexed)
s << "\n:noindex:";
+ if (func->cppAttributes().testFlag(FunctionAttribute::Final))
+ s << "\n:final:";
+ else if (func->isAbstract())
+ s << "\n:abstractmethod:";
s << "\n\n";
writeFunctionParametersType(s, cppClass, func);
const auto version = versionOf(func->typeEntry());
if (!version.isNull())
s << rstVersionAdded(version);
- if (func->attributes().testFlag(AbstractMetaFunction::Deprecated))
+ if (func->isDeprecated())
s << rstDeprecationNote("function");
}
- writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, cppClass, func);
- if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, cppClass, func)) {
- writeFormattedBriefText(s, func->documentation(), cppClass);
- writeFormattedDetailedText(s, func->documentation(), cppClass);
+
+ writeFunctionDocumentation(s, func, modifications, scope);
+
+ if (auto propIndex = func->propertySpecIndex(); propIndex >= 0) {
+ const QString name = cppClass->propertySpecs().at(propIndex).name();
+ const QString target = propertyRefTarget(name);
+ if (func->isPropertyReader())
+ s << "\nGetter of property " << propRef(target) << " .\n\n";
+ else if (func->isPropertyWriter())
+ s << "\nSetter of property " << propRef(target) << " .\n\n";
+ else if (func->isPropertyResetter())
+ s << "\nReset function of property " << propRef(target) << " .\n\n";
+ else if (func->attributes().testFlag(AbstractMetaFunction::Attribute::PropertyNotify))
+ s << "\nNotification signal of property " << propRef(target) << " .\n\n";
+ }
+}
+
+void QtDocGenerator::writeFunctionDocumentation(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ const DocModificationList &modifications,
+ const QString &scope) const
+
+{
+ writeInjectDocumentation(s, TypeSystem::DocModificationPrepend, modifications, func, scope);
+ if (!writeInjectDocumentation(s, TypeSystem::DocModificationReplace, modifications, func, scope)) {
+ writeFormattedBriefText(s, func->documentation(), scope);
+ writeFormattedDetailedText(s, func->documentation(), scope);
+ }
+ writeInjectDocumentation(s, TypeSystem::DocModificationAppend, modifications, func, scope);
+}
+
+static QStringList fileListToToc(const QStringList &items)
+{
+ QStringList result;
+ result.reserve(items.size());
+ std::transform(items.cbegin(), items.cend(), std::back_inserter(result),
+ fileNameToTocEntry);
+ return result;
+}
+
+static QStringList functionListToToc(const AbstractMetaFunctionCList &functions)
+{
+ QStringList result;
+ result.reserve(functions.size());
+ for (const auto &f : functions)
+ result.append(f->name());
+ // Functions are sorted by the Metabuilder; erase overloads
+ result.erase(std::unique(result.begin(), result.end()), result.end());
+ return result;
+}
+
+static QStringList enumListToToc(const AbstractMetaEnumList &enums)
+{
+ QStringList result;
+ result.reserve(enums.size());
+ for (const auto &e : enums)
+ result.append(e.name());
+ return result;
+}
+
+// Sort entries for a TOC by first character, dropping the
+// leading common Qt prefixes like 'Q'.
+static QChar sortKey(const QString &key)
+{
+ const auto size = key.size();
+ if (size >= 2 && (key.at(0) == u'Q' || key.at(0) == u'q')
+ && (key.at(1).isUpper() || key.at(1).isDigit())) {
+ return key.at(1); // "QClass" -> 'C', "qSin()" -> 'S', 'Q3DSurfaceWidget' -> '3'
}
- writeInjectDocumentation(s, TypeSystem::DocModificationAppend, cppClass, func);
+ if (size >= 3 && key.startsWith("Q_"_L1))
+ return key.at(2).toUpper(); // "Q_ARG" -> 'A'
+ if (size >= 4 && key.startsWith("QT_"_L1))
+ return key.at(3).toUpper(); // "QT_TR" -> 'T'
+ auto idx = 0;
+ for (; idx < size && key.at(idx) == u'_'; ++idx) {
+ } // "__init__" -> 'I'
+ return idx < size ? key.at(idx).toUpper() : u'A';
}
-static void writeFancyToc(TextStream& s, const QStringList& items)
+static void writeFancyToc(TextStream& s, QAnyStringView title,
+ const QStringList& items,
+ QLatin1StringView referenceType)
{
using TocMap = QMap<QChar, QStringList>;
+
+ if (items.isEmpty())
+ return;
+
TocMap tocMap;
- QChar Q = QLatin1Char('Q');
- QChar idx;
- for (QString item : items) {
- if (item.isEmpty())
- continue;
- item.chop(4); // Remove the .rst extension
- // skip namespace if necessary
- const QString className = item.split(QLatin1Char('.')).last();
- if (className.startsWith(Q) && className.length() > 1)
- idx = className[1];
- else
- idx = className[0];
- tocMap[idx] << item;
- }
+ for (const QString &item : items)
+ tocMap[sortKey(item)] << item;
static const qsizetype numColumns = 4;
QtXmlToSphinx::Table table;
for (auto it = tocMap.cbegin(), end = tocMap.cend(); it != end; ++it) {
QtXmlToSphinx::TableRow row;
- const QString charEntry = QLatin1String("**") + it.key() + QLatin1String("**");
+ const QString charEntry = u"**"_s + it.key() + u"**"_s;
row << QtXmlToSphinx::TableCell(charEntry);
- for (const QString &item : qAsConst(it.value())) {
+ for (const QString &item : std::as_const(it.value())) {
if (row.size() >= numColumns) {
table.appendRow(row);
row.clear();
row << QtXmlToSphinx::TableCell(QString{});
}
- const QString entry = QLatin1String("* :doc:`") + item + QLatin1Char('`');
+ const QString entry = "* :"_L1 + referenceType + ":`"_L1 + item + u'`';
row << QtXmlToSphinx::TableCell(entry);
}
- if (!row.isEmpty())
+ if (row.size() > 1)
table.appendRow(row);
}
table.normalize();
- s << ".. container:: pysidetoc\n\n";
+ s << '\n' << headline(title) << ".. container:: pysidetoc\n\n";
table.format(s);
}
bool QtDocGenerator::finishGeneration()
{
- if (!api().classes().isEmpty())
+ for (const auto &f : api().globalFunctions()) {
+ auto ncf = std::const_pointer_cast<AbstractMetaFunction>(f);
+ m_docParser->fillGlobalFunctionDocumentation(ncf);
+ m_packages[f->targetLangPackage()].globalFunctions.append(f);
+ }
+
+ for (auto e : api().globalEnums()) {
+ m_docParser->fillGlobalEnumDocumentation(e);
+ m_packages[e.typeEntry()->targetLangPackage()].globalEnums.append(e);
+ }
+
+ if (!m_packages.isEmpty())
writeModuleDocumentation();
- if (!m_additionalDocumentationList.isEmpty())
+ if (!m_options.additionalDocumentationList.isEmpty())
writeAdditionalDocumentation();
+ if (!m_options.inheritanceFile.isEmpty() && !writeInheritanceFile())
+ return false;
+ return true;
+}
+
+bool QtDocGenerator::writeInheritanceFile()
+{
+ QFile inheritanceFile(m_options.inheritanceFile);
+ if (!inheritanceFile.open(QIODevice::WriteOnly | QIODevice::Text))
+ throw Exception(msgCannotOpenForWriting(m_options.inheritanceFile));
+
+ QJsonObject dict;
+ for (const auto &c : api().classes()) {
+ const auto &bases = c->baseClasses();
+ if (!bases.isEmpty()) {
+ QJsonArray list;
+ for (const auto &base : bases)
+ list.append(QJsonValue(base->fullName()));
+ dict[c->fullName()] = list;
+ }
+ }
+ QJsonDocument document;
+ document.setObject(dict);
+ inheritanceFile.write(document.toJson(QJsonDocument::Compact));
return true;
}
+// Remove function entries that have extra documentation pages
+static inline void removeExtraDocs(const QStringList &extraTocEntries,
+ AbstractMetaFunctionCList *functions)
+{
+ auto predicate = [&extraTocEntries](const AbstractMetaFunctionCPtr &f) {
+ return extraTocEntries.contains(f->name());
+ };
+ functions->erase(std::remove_if(functions->begin(),functions->end(), predicate),
+ functions->end());
+}
+
void QtDocGenerator::writeModuleDocumentation()
{
- QMap<QString, QStringList>::iterator it = m_packages.begin();
- for (; it != m_packages.end(); ++it) {
- std::sort(it.value().begin(), it.value().end());
+ for (auto it = m_packages.begin(), end = m_packages.end(); it != end; ++it) {
+ auto &docPackage = it.value();
+ std::sort(docPackage.classPages.begin(), docPackage.classPages.end());
QString key = it.key();
- key.replace(QLatin1Char('.'), QLatin1Char('/'));
- QString outputDir = outputDirectory() + QLatin1Char('/') + key;
- FileOut output(outputDir + QLatin1String("/index.rst"));
+ key.replace(u'.', u'/');
+ QString outputDir = outputDirectory() + u'/' + key;
+ FileOut output(outputDir + u"/index.rst"_s);
TextStream& s = output.stream;
const QString &title = it.key();
- s << ".. module:: " << title << "\n\n"
- << title << '\n'
- << Pad('*', title.length()) << "\n\n";
+ s << ".. module:: " << title << "\n\n" << headline(title, '*');
// 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.
QString moduleName = it.key();
- const int lastIndex = moduleName.lastIndexOf(QLatin1Char('.'));
+ const int lastIndex = moduleName.lastIndexOf(u'.');
if (lastIndex >= 0)
moduleName.remove(0, lastIndex + 1);
// Search for extra-sections
- if (!m_extraSectionDir.isEmpty()) {
- QDir extraSectionDir(m_extraSectionDir);
+ QStringList extraTocEntries;
+ if (!m_options.extraSectionDir.isEmpty()) {
+ QDir extraSectionDir(m_options.extraSectionDir);
if (!extraSectionDir.exists()) {
- const QString m = QStringLiteral("Extra sections directory ") +
- m_extraSectionDir + QStringLiteral(" doesn't exist");
+ const QString m = u"Extra sections directory "_s +
+ m_options.extraSectionDir + u" doesn't exist"_s;
throw Exception(m);
}
// Filter for "QtCore.Property.rst", skipping module doc "QtCore.rst"
- const QString filter = moduleName + QLatin1String(".?*.rst");
+ const QString filter = moduleName + u".?*.rst"_s;
const auto fileList =
extraSectionDir.entryInfoList({filter}, QDir::Files, QDir::Name);
- for (const auto &fi : fileList) {
- // Strip to "Property.rst" in output directory
- const QString newFileName = fi.fileName().mid(moduleName.size() + 1);
- it.value().append(newFileName);
- const QString newFilePath = outputDir + QLatin1Char('/') + newFileName;
- if (QFile::exists(newFilePath))
- QFile::remove(newFilePath);
- if (!QFile::copy(fi.absoluteFilePath(), newFilePath)) {
- qCDebug(lcShibokenDoc).noquote().nospace() << "Error copying extra doc "
- << QDir::toNativeSeparators(fi.absoluteFilePath())
- << " to " << QDir::toNativeSeparators(newFilePath);
- }
- }
+ for (const auto &fi : fileList)
+ readExtraDoc(fi, moduleName, outputDir, &docPackage, &extraTocEntries);
}
- writeFancyToc(s, it.value());
+ removeExtraDocs(extraTocEntries, &docPackage.globalFunctions);
+ const bool hasGlobals = !docPackage.globalFunctions.isEmpty()
+ || !docPackage.globalEnums.isEmpty();
+ const QString globalsPage = moduleName + "_globals.rst"_L1;
s << ".. container:: hide\n\n" << indent
<< ".. toctree::\n" << indent
<< ":maxdepth: 1\n\n";
- for (const QString &className : qAsConst(it.value()))
+ if (hasGlobals)
+ s << globalsPage << '\n';
+ for (const QString &className : std::as_const(docPackage.classPages))
s << className << '\n';
- s << "\n\n" << outdent << outdent
- << "Detailed Description\n--------------------\n\n";
+ s << "\n\n" << outdent << outdent << headline("Detailed Description");
// module doc is always wrong and C++istic, so go straight to the extra directory!
- QFile moduleDoc(m_extraSectionDir + QLatin1Char('/') + moduleName
- + QLatin1String(".rst"));
+ QFile moduleDoc(m_options.extraSectionDir + u'/' + moduleName
+ + u".rst"_s);
if (moduleDoc.open(QIODevice::ReadOnly | QIODevice::Text)) {
s << moduleDoc.readAll();
moduleDoc.close();
@@ -882,16 +1144,50 @@ void QtDocGenerator::writeModuleDocumentation()
if (moduleDoc.format() == Documentation::Native) {
QString context = it.key();
QtXmlToSphinx::stripPythonQualifiers(&context);
- QtXmlToSphinx x(this, m_parameters, moduleDoc.detailed(), context);
+ QtXmlToSphinx x(this, m_options.parameters, moduleDoc.detailed(), context);
s << x;
} else {
s << moduleDoc.detailed();
}
}
+
+ writeFancyToc(s, "List of Classes", fileListToToc(docPackage.classPages),
+ "class"_L1);
+ writeFancyToc(s, "List of Decorators", fileListToToc(docPackage.decoratorPages),
+ "deco"_L1);
+ writeFancyToc(s, "List of Functions", functionListToToc(docPackage.globalFunctions),
+ "py:func"_L1);
+ writeFancyToc(s, "List of Enumerations", enumListToToc(docPackage.globalEnums),
+ "any"_L1);
+
output.done();
+
+ if (hasGlobals)
+ writeGlobals(it.key(), outputDir + u'/' + globalsPage, docPackage);
}
}
+void QtDocGenerator::writeGlobals(const QString &package,
+ const QString &fileName,
+ const DocPackage &docPackage)
+{
+ FileOut output(fileName);
+ TextStream &s = output.stream;
+
+ // Write out functions with injected documentation
+ if (!docPackage.globalFunctions.isEmpty()) {
+ s << currentModule(package) << headline("Functions");
+ writeFunctions(s, docPackage.globalFunctions, {}, {});
+ }
+
+ if (!docPackage.globalEnums.isEmpty()) {
+ s << headline("Enumerations");
+ writeEnums(s, docPackage.globalEnums, package);
+ }
+
+ output.done();
+}
+
static inline QString msgNonExistentAdditionalDocFile(const QString &dir,
const QString &fileName)
{
@@ -904,7 +1200,7 @@ static inline QString msgNonExistentAdditionalDocFile(const QString &dir,
void QtDocGenerator::writeAdditionalDocumentation() const
{
- QFile additionalDocumentationFile(m_additionalDocumentationList);
+ QFile additionalDocumentationFile(m_options.additionalDocumentationList);
if (!additionalDocumentationFile.open(QIODevice::ReadOnly | QIODevice::Text))
throw Exception(msgCannotOpenForReading(additionalDocumentationFile));
@@ -923,14 +1219,14 @@ void QtDocGenerator::writeAdditionalDocumentation() const
continue;
const QString line = QFile::decodeName(lineBA);
// Parse "[directory]" specification
- if (line.size() > 2 && line.startsWith(QLatin1Char('[')) && line.endsWith(QLatin1Char(']'))) {
+ if (line.size() > 2 && line.startsWith(u'[') && line.endsWith(u']')) {
const QString dir = line.mid(1, line.size() - 2);
- if (dir.isEmpty() || dir == QLatin1String(".")) {
+ if (dir.isEmpty() || dir == u".") {
targetDir = outDir.absolutePath();
} else {
if (!outDir.exists(dir) && !outDir.mkdir(dir)) {
- const QString m = QStringLiteral("Cannot create directory ")
- + dir + QStringLiteral(" under ")
+ const QString m = "Cannot create directory "_L1
+ + dir + " under "_L1
+ QDir::toNativeSeparators(outputDirectory());
throw Exception(m);
}
@@ -938,11 +1234,11 @@ void QtDocGenerator::writeAdditionalDocumentation() const
}
} else {
// Normal file entry
- QFileInfo fi(m_parameters.docDataDir + QLatin1Char('/') + line);
+ QFileInfo fi(m_options.parameters.docDataDir + u'/' + 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);
+ const QString rstFile = targetDir + u'/' + rstFileName;
+ const QString context = targetDir.mid(targetDir.lastIndexOf(u'/') + 1);
if (convertToRst(fi.absoluteFilePath(),
rstFile, context, &errorMessage)) {
++successCount;
@@ -956,7 +1252,7 @@ void QtDocGenerator::writeAdditionalDocumentation() const
// FIXME: This should be an exception, in principle, but it
// requires building all modules.
qCWarning(lcShibokenDoc, "%s",
- qPrintable(msgNonExistentAdditionalDocFile(m_parameters.docDataDir, line)));
+ qPrintable(msgNonExistentAdditionalDocFile(m_options.parameters.docDataDir, line)));
}
++count;
}
@@ -975,79 +1271,133 @@ void QtDocGenerator::writeAdditionalDocumentation() const
bool QtDocGenerator::doSetup()
{
- if (m_parameters.codeSnippetDirs.isEmpty()) {
- m_parameters.codeSnippetDirs =
- m_parameters.libSourceDir.split(QLatin1Char(PATH_SEP));
+ if (m_options.parameters.codeSnippetDirs.isEmpty()) {
+ m_options.parameters.codeSnippetDirs =
+ m_options.parameters.libSourceDir.split(QLatin1Char(PATH_SEP));
}
- if (m_docParser.isNull())
- m_docParser.reset(new QtDocParser);
+ if (m_docParser.isNull()) {
+ if (m_options.doxygen)
+ m_docParser.reset(new DoxygenParser);
+ else
+ m_docParser.reset(new QtDocParser);
+ }
- if (m_parameters.libSourceDir.isEmpty()
- || m_parameters.docDataDir.isEmpty()) {
+ if (m_options.parameters.libSourceDir.isEmpty()
+ || m_options.parameters.docDataDir.isEmpty()) {
qCWarning(lcShibokenDoc) << "Documentation data dir and/or Qt source dir not informed, "
"documentation will not be extracted from Qt sources.";
return false;
}
- m_docParser->setDocumentationDataDirectory(m_parameters.docDataDir);
- m_docParser->setLibrarySourceDirectory(m_parameters.libSourceDir);
- m_parameters.outputDirectory = outputDirectory();
+ m_docParser->setDocumentationDataDirectory(m_options.parameters.docDataDir);
+ m_docParser->setLibrarySourceDirectory(m_options.parameters.libSourceDir);
+ m_options.parameters.outputDirectory = outputDirectory();
return true;
}
-
-Generator::OptionDescriptions QtDocGenerator::options() const
+QList<OptionDescription> QtDocGenerator::options()
{
return {
- {QLatin1String("doc-parser=<parser>"),
- QLatin1String("The documentation parser used to interpret the documentation\n"
- "input files (qdoc|doxygen)")},
- {QLatin1String("documentation-code-snippets-dir=<dir>"),
- QLatin1String("Directory used to search code snippets used by the documentation")},
- {QLatin1String("documentation-data-dir=<dir>"),
- QLatin1String("Directory with XML files generated by documentation tool")},
- {QLatin1String("documentation-extra-sections-dir=<dir>"),
- QLatin1String("Directory used to search for extra documentation sections")},
- {QLatin1String("library-source-dir=<dir>"),
- QLatin1String("Directory where library source code is located")},
- {additionalDocumentationOption() + QLatin1String("=<file>"),
- QLatin1String("List of additional XML files to be converted to .rst files\n"
- "(for example, tutorials).")}
+ {u"doc-parser=<parser>"_s,
+ u"The documentation parser used to interpret the documentation\n"
+ "input files (qdoc|doxygen)"_s},
+ {u"documentation-code-snippets-dir=<dir>"_s,
+ u"Directory used to search code snippets used by the documentation"_s},
+ {u"snippets-path-rewrite=old:new"_s,
+ u"Replacements in code snippet path to find .cpp/.h snippets converted to Python"_s},
+ {u"documentation-data-dir=<dir>"_s,
+ u"Directory with XML files generated by documentation tool"_s},
+ {u"documentation-extra-sections-dir=<dir>"_s,
+ u"Directory used to search for extra documentation sections"_s},
+ {u"library-source-dir=<dir>"_s,
+ u"Directory where library source code is located"_s},
+ {additionalDocumentationOption + u"=<file>"_s,
+ u"List of additional XML files to be converted to .rst files\n"
+ "(for example, tutorials)."_s},
+ {u"inheritance-file=<file>"_s,
+ u"Generate a JSON file containing the class inheritance."_s},
+ {u"disable-inheritance-diagram"_s,
+ u"Disable the generation of the inheritance diagram."_s}
};
}
-bool QtDocGenerator::handleOption(const QString &key, const QString &value)
+class QtDocGeneratorOptionsParser : public OptionsParser
{
- if (key == QLatin1String("library-source-dir")) {
- m_parameters.libSourceDir = value;
+public:
+ explicit QtDocGeneratorOptionsParser(DocGeneratorOptions *o) : m_options(o) {}
+
+ bool handleBoolOption(const QString &key, OptionSource source) override;
+ bool handleOption(const QString &key, const QString &value, OptionSource source) override;
+
+private:
+ DocGeneratorOptions *m_options;
+};
+
+bool QtDocGeneratorOptionsParser::handleBoolOption(const QString &key, OptionSource)
+{
+ if (key == "disable-inheritance-diagram"_L1) {
+ m_options->inheritanceDiagram = false;
return true;
}
- if (key == QLatin1String("documentation-data-dir")) {
- m_parameters.docDataDir = value;
+ return false;
+}
+
+bool QtDocGeneratorOptionsParser::handleOption(const QString &key, const QString &value,
+ OptionSource source)
+{
+ if (source == OptionSource::CommandLineSingleDash)
+ return false;
+ if (key == u"library-source-dir") {
+ m_options->parameters.libSourceDir = value;
return true;
}
- if (key == QLatin1String("documentation-code-snippets-dir")) {
- m_parameters.codeSnippetDirs = value.split(QLatin1Char(PATH_SEP));
+ if (key == u"documentation-data-dir") {
+ m_options->parameters.docDataDir = value;
return true;
}
- if (key == QLatin1String("documentation-extra-sections-dir")) {
- m_extraSectionDir = value;
+ if (key == u"documentation-code-snippets-dir") {
+ m_options->parameters.codeSnippetDirs = value.split(QLatin1Char(PATH_SEP));
return true;
}
- if (key == QLatin1String("doc-parser")) {
+
+ if (key == u"snippets-path-rewrite") {
+ const auto pos = value.indexOf(u':');
+ if (pos == -1)
+ return false;
+ m_options->parameters.codeSnippetRewriteOld= value.left(pos);
+ m_options->parameters.codeSnippetRewriteNew = value.mid(pos + 1);
+ return true;
+ }
+
+ if (key == u"documentation-extra-sections-dir") {
+ m_options->extraSectionDir = value;
+ return true;
+ }
+ if (key == u"doc-parser") {
qCDebug(lcShibokenDoc).noquote().nospace() << "doc-parser: " << value;
- if (value == QLatin1String("doxygen"))
- m_docParser.reset(new DoxygenParser);
+ if (value == u"doxygen")
+ m_options->doxygen = true;
return true;
}
- if (key == additionalDocumentationOption()) {
- m_additionalDocumentationList = value;
+ if (key == additionalDocumentationOption) {
+ m_options->additionalDocumentationList = value;
return true;
}
+
+ if (key == u"inheritance-file") {
+ m_options->inheritanceFile = value;
+ return true;
+ }
+
return false;
}
+std::shared_ptr<OptionsParser> QtDocGenerator::createOptionsParser()
+{
+ return std::make_shared<QtDocGeneratorOptionsParser>(&m_options);
+}
+
bool QtDocGenerator::convertToRst(const QString &sourceFileName,
const QString &targetFileName,
const QString &context,
@@ -1063,20 +1413,65 @@ bool QtDocGenerator::convertToRst(const QString &sourceFileName,
sourceFile.close();
FileOut targetFile(targetFileName);
- QtXmlToSphinx x(this, m_parameters, doc, context);
+ QtXmlToSphinx x(this, m_options.parameters, doc, context);
targetFile.stream << x;
targetFile.done();
return true;
}
+GeneratorDocumentation
+ QtDocGenerator::generatorDocumentation(const AbstractMetaClassCPtr &cppClass)
+{
+ GeneratorDocumentation result;
+ const auto allFunctions = cppClass->functions();
+ result.allFunctions.reserve(allFunctions.size());
+ std::remove_copy_if(allFunctions.cbegin(), allFunctions.cend(),
+ std::back_inserter(result.allFunctions), shouldSkip);
+
+ std::stable_sort(result.allFunctions.begin(), result.allFunctions.end(), functionSort);
+
+ for (const auto &func : std::as_const(result.allFunctions)) {
+ if (func->isStatic())
+ result.tocStaticFunctions.append(func);
+ else if (func->isVirtual())
+ result.tocVirtuals.append(func);
+ else if (func->isSignal())
+ result.tocSignalFunctions.append(func);
+ else if (func->isSlot())
+ result.tocSlotFunctions.append(func);
+ else
+ result.tocNormalFunctions.append(func);
+ }
+
+ // Find the property getters/setters
+ for (const auto &spec: cppClass->propertySpecs()) {
+ GeneratorDocumentation::Property property;
+ property.name = spec.name();
+ property.type = spec.type();
+ property.documentation = spec.documentation();
+ if (!spec.read().isEmpty())
+ property.getter = AbstractMetaFunction::find(result.allFunctions, spec.read());
+ if (!spec.write().isEmpty())
+ property.setter = AbstractMetaFunction::find(result.allFunctions, spec.write());
+ if (!spec.reset().isEmpty())
+ property.reset = AbstractMetaFunction::find(result.allFunctions, spec.reset());
+ if (!spec.notify().isEmpty())
+ property.notify = AbstractMetaFunction::find(result.tocSignalFunctions, spec.notify());
+ result.properties.append(property);
+ }
+ std::sort(result.properties.begin(), result.properties.end());
+
+ return result;
+}
+
// QtXmlToSphinxDocGeneratorInterface
QString QtDocGenerator::expandFunction(const QString &function) const
{
- const int firstDot = function.indexOf(QLatin1Char('.'));
- const AbstractMetaClass *metaClass = nullptr;
+ const auto firstDot = function.indexOf(u'.');
+ AbstractMetaClassCPtr metaClass;
if (firstDot != -1) {
const auto className = QStringView{function}.left(firstDot);
- for (auto cls : api().classes()) {
+ for (const auto &cls : api().classes()) {
if (cls->name() == className) {
metaClass = cls;
break;
@@ -1097,12 +1492,11 @@ QString QtDocGenerator::expandClass(const QString &context,
return typeEntry->qualifiedTargetLangName();
// fall back to the old heuristic if the type wasn't found.
QString result = name;
- const auto rawlinklist = QStringView{name}.split(QLatin1Char('.'));
- QStringList splittedContext = context.split(QLatin1Char('.'));
+ const auto rawlinklist = QStringView{name}.split(u'.');
+ QStringList splittedContext = context.split(u'.');
if (rawlinklist.size() == 1 || rawlinklist.constFirst() == splittedContext.constLast()) {
splittedContext.removeLast();
- result.prepend(QLatin1Char('~') + splittedContext.join(QLatin1Char('.'))
- + QLatin1Char('.'));
+ result.prepend(u'~' + splittedContext.join(u'.') + u'.');
}
return result;
}
@@ -1110,10 +1504,10 @@ QString QtDocGenerator::expandClass(const QString &context,
QString QtDocGenerator::resolveContextForMethod(const QString &context,
const QString &methodName) const
{
- const auto currentClass = QStringView{context}.split(QLatin1Char('.')).constLast();
+ const auto currentClass = QStringView{context}.split(u'.').constLast();
- const AbstractMetaClass *metaClass = nullptr;
- for (auto cls : api().classes()) {
+ AbstractMetaClassCPtr metaClass;
+ for (const auto &cls : api().classes()) {
if (cls->name() == currentClass) {
metaClass = cls;
break;
@@ -1128,8 +1522,8 @@ QString QtDocGenerator::resolveContextForMethod(const QString &context,
funcList.append(func);
}
- const AbstractMetaClass *implementingClass = nullptr;
- for (const auto &func : qAsConst(funcList)) {
+ AbstractMetaClassCPtr implementingClass;
+ for (const auto &func : std::as_const(funcList)) {
implementingClass = func->implementingClass();
if (implementingClass->name() == currentClass)
break;
@@ -1139,10 +1533,59 @@ QString QtDocGenerator::resolveContextForMethod(const QString &context,
return implementingClass->typeEntry()->qualifiedTargetLangName();
}
- return QLatin1Char('~') + context;
+ return u'~' + context;
}
const QLoggingCategory &QtDocGenerator::loggingCategory() const
{
return lcShibokenDoc();
}
+
+static bool isRelativeHtmlFile(const QString &linkRef)
+{
+ return !linkRef.startsWith(u"http")
+ && (linkRef.endsWith(u".html") || linkRef.contains(u".html#"));
+}
+
+// Resolve relative, local .html documents links to doc.qt.io as they
+// otherwise will not work and neither be found in the HTML tree.
+QtXmlToSphinxLink QtDocGenerator::resolveLink(const QtXmlToSphinxLink &link) const
+{
+ if (link.type != QtXmlToSphinxLink::Reference || !isRelativeHtmlFile(link.linkRef))
+ return link;
+ static const QString prefix = "https://doc.qt.io/qt-"_L1
+ + QString::number(QT_VERSION_MAJOR) + u'/';
+ QtXmlToSphinxLink resolved = link;
+ resolved.type = QtXmlToSphinxLink::External;
+ resolved.linkRef = prefix + link.linkRef;
+ if (resolved.linkText.isEmpty()) {
+ resolved.linkText = link.linkRef;
+ const qsizetype anchor = resolved.linkText.lastIndexOf(u'#');
+ if (anchor != -1)
+ resolved.linkText.truncate(anchor);
+ }
+ return resolved;
+}
+
+QtXmlToSphinxDocGeneratorInterface::Image
+ QtDocGenerator::resolveImage(const QString &href, const QString &context) const
+{
+ QString relativeSourceDir = href;
+ const QString source = m_options.parameters.docDataDir + u'/' + relativeSourceDir;
+ if (!QFileInfo::exists(source))
+ throw Exception(msgCannotFindImage(href, context,source));
+
+ // Determine target 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 auto lastDot = relativeTargetDir.lastIndexOf(u'.');
+ if (lastDot != -1)
+ relativeTargetDir.truncate(lastDot);
+ relativeTargetDir.replace(u'.', u'/');
+ if (!relativeTargetDir.isEmpty())
+ relativeTargetDir += u'/';
+ relativeTargetDir += href;
+
+ return {relativeSourceDir, relativeTargetDir};
+}
diff --git a/sources/shiboken6/generator/qtdoc/qtdocgenerator.h b/sources/shiboken6/generator/qtdoc/qtdocgenerator.h
index 2b18d1edd..56e15e2a1 100644
--- a/sources/shiboken6/generator/qtdoc/qtdocgenerator.h
+++ b/sources/shiboken6/generator/qtdoc/qtdocgenerator.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef DOCGENERATOR_H
#define DOCGENERATOR_H
@@ -34,11 +9,15 @@
#include "generator.h"
#include "documentation.h"
+#include <optionsparser.h>
#include "typesystem_enums.h"
-#include "typesystem_typedefs.h"
+#include "modifications_typedefs.h"
#include "qtxmltosphinxinterface.h"
class DocParser;
+struct DocGeneratorOptions;
+struct GeneratorDocumentation;
+struct DocPackage;
/**
* The DocGenerator generates documentation from library being binded.
@@ -46,6 +25,8 @@ class DocParser;
class QtDocGenerator : public Generator, public QtXmlToSphinxDocGeneratorInterface
{
public:
+ Q_DISABLE_COPY_MOVE(QtDocGenerator)
+
QtDocGenerator();
~QtDocGenerator();
@@ -56,8 +37,8 @@ public:
return "QtDocGenerator";
}
- OptionDescriptions options() const override;
- bool handleOption(const QString &key, const QString &value) override;
+ static QList<OptionDescription> options();
+ static std::shared_ptr<OptionsParser> createOptionsParser();
// QtXmlToSphinxDocGeneratorInterface
QString expandFunction(const QString &function) const override;
@@ -66,64 +47,84 @@ public:
QString resolveContextForMethod(const QString &context,
const QString &methodName) const override;
const QLoggingCategory &loggingCategory() const override;
+ QtXmlToSphinxLink resolveLink(const QtXmlToSphinxLink &) const override;
+ Image resolveImage(const QString &href, const QString &context) const override;
+
+ static QString getFuncName(const AbstractMetaFunctionCPtr &cppFunc);
+ static QString formatArgs(const AbstractMetaFunctionCPtr &func);
protected:
- bool shouldGenerate(const AbstractMetaClass *) const override;
- QString fileNameSuffix() const override;
+ bool shouldGenerate(const TypeEntryCPtr &) const override;
+ static QString fileNameSuffix();
QString fileNameForContext(const GeneratorContext &context) const override;
void generateClass(TextStream &ts, const GeneratorContext &classContext) override;
bool finishGeneration() override;
private:
- void writeEnums(TextStream& s, const AbstractMetaClass* cppClass) const;
-
- void writeFields(TextStream &s, const AbstractMetaClass *cppClass) const;
- static QString functionSignature(const AbstractMetaClass* cppClass,
- const AbstractMetaFunctionCPtr &func);
- void writeFunction(TextStream& s, const AbstractMetaClass* cppClass,
- const AbstractMetaFunctionCPtr &func, bool indexed = true);
- void writeFunctionParametersType(TextStream &s, const AbstractMetaClass *cppClass,
+ void writeEnums(TextStream &s, const AbstractMetaEnumList &enums,
+ const QString &scope) const;
+
+ void writeFields(TextStream &s, const AbstractMetaClassCPtr &cppClass) const;
+ void writeFunctions(TextStream &s, const AbstractMetaFunctionCList &funcs,
+ const AbstractMetaClassCPtr &cppClass, const QString &scope);
+ void writeFunction(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaClassCPtr &cppClass = {},
+ const QString &scope = {}, bool indexed = true);
+ void writeFunctionDocumentation(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ const DocModificationList &modifications,
+ const QString &scope) const;
+ void writeFunctionParametersType(TextStream &s, const AbstractMetaClassCPtr &cppClass,
const AbstractMetaFunctionCPtr &func) const;
- static void writeFunctionList(TextStream& s, const AbstractMetaClass* cppClass);
- static void writeFunctionBlock(TextStream& s, const QString& title,
- QStringList& functions);
- void writeParameterType(TextStream &s, const AbstractMetaClass *cppClass,
+ static void writeFunctionToc(TextStream &s, const QString &title,
+ const AbstractMetaFunctionCList &functions);
+ static void writePropertyToc(TextStream &s,
+ const GeneratorDocumentation &doc);
+ void writeProperties(TextStream &s,
+ const GeneratorDocumentation &doc,
+ const AbstractMetaClassCPtr &cppClass) const;
+ void writeParameterType(TextStream &s, const AbstractMetaClassCPtr &cppClass,
const AbstractMetaArgument &arg) const;
-
- void writeConstructors(TextStream &s, const AbstractMetaClass *cppClass) const;
-
void writeFormattedText(TextStream &s, const QString &doc,
Documentation::Format format,
- const AbstractMetaClass *metaClass = nullptr) const;
+ const QString &scope = {}) const;
void writeFormattedBriefText(TextStream &s, const Documentation &doc,
- const AbstractMetaClass *metaclass = nullptr) const;
+ const QString &scope = {}) const;
void writeFormattedDetailedText(TextStream &s, const Documentation &doc,
- const AbstractMetaClass *metaclass = nullptr) const;
-
- bool writeInjectDocumentation(TextStream& s, TypeSystem::DocModificationMode mode,
- const AbstractMetaClass* cppClass,
- const AbstractMetaFunctionCPtr &func);
+ const QString &scope = {}) const;
+
+ bool writeInjectDocumentation(TextStream &s, TypeSystem::DocModificationMode mode,
+ const AbstractMetaClassCPtr &cppClass) const;
+ bool writeInjectDocumentation(TextStream &s, TypeSystem::DocModificationMode mode,
+ const DocModificationList &modifications,
+ const AbstractMetaFunctionCPtr &func,
+ const QString &scope = {}) const;
+ bool writeDocModifications(TextStream &s, const DocModificationList &mods,
+ TypeSystem::DocModificationMode mode,
+ const QString &scope = {}) const;
static void writeDocSnips(TextStream &s, const CodeSnipList &codeSnips,
TypeSystem::CodeSnipPosition position, TypeSystem::Language language);
void writeModuleDocumentation();
+ void writeGlobals(const QString &package, const QString &fileName,
+ const DocPackage &docPackage);
void writeAdditionalDocumentation() const;
+ bool writeInheritanceFile();
- static QString parseArgDocStyle(const AbstractMetaClass *cppClass,
- const AbstractMetaFunctionCPtr &func);
- QString translateToPythonType(const AbstractMetaType &type, const AbstractMetaClass *cppClass) const;
+ QString translateToPythonType(const AbstractMetaType &type,
+ const AbstractMetaClassCPtr &cppClass,
+ bool createRef = true) const;
bool convertToRst(const QString &sourceFileName,
const QString &targetFileName,
const QString &context = QString(),
QString *errorMessage = nullptr) const;
- QString m_extraSectionDir;
+ static GeneratorDocumentation generatorDocumentation(const AbstractMetaClassCPtr &cppClass);
+
QStringList m_functionList;
- QMap<QString, QStringList> m_packages;
+ QMap<QString, DocPackage> m_packages;
QScopedPointer<DocParser> m_docParser;
- QtXmlToSphinxParameters m_parameters;
- QString m_additionalDocumentationList;
+ static DocGeneratorOptions m_options;
};
#endif // DOCGENERATOR_H
diff --git a/sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp b/sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp
index 4a362ac54..b8fec836c 100644
--- a/sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp
+++ b/sources/shiboken6/generator/qtdoc/qtxmltosphinx.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qtxmltosphinx.h"
#include "exception.h"
@@ -32,16 +7,17 @@
#include <codesniphelpers.h>
#include "rstformat.h"
+#include "qtcompat.h"
+
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
+#include <QtCore/QHash>
#include <QtCore/QLoggingCategory>
#include <QtCore/QRegularExpression>
#include <QtCore/QXmlStreamReader>
-static inline QString nameAttribute() { return QStringLiteral("name"); }
-static inline QString titleAttribute() { return QStringLiteral("title"); }
-static inline QString fullTitleAttribute() { return QStringLiteral("fulltitle"); }
+using namespace Qt::StringLiterals;
QString msgTagWarning(const QXmlStreamReader &reader, const QString &context,
const QString &tag, const QString &message)
@@ -59,16 +35,23 @@ QString msgTagWarning(const QXmlStreamReader &reader, const QString &context,
return result;
}
-QString msgFallbackWarning(const QXmlStreamReader &reader, const QString &context,
- const QString &tag, const QString &location,
- const QString &identifier, const QString &fallback)
+QString msgFallbackWarning(const QString &location, const QString &identifier,
+ const QString &fallback)
{
- QString message = QLatin1String("Falling back to \"")
- + QDir::toNativeSeparators(fallback) + QLatin1String("\" for \"")
- + location + QLatin1Char('"');
+ QString message = u"Falling back to \""_s
+ + QDir::toNativeSeparators(fallback) + u"\" for \""_s
+ + location + u'"';
if (!identifier.isEmpty())
- message += QLatin1String(" [") + identifier + QLatin1Char(']');
- return msgTagWarning(reader, context, tag, message);
+ message += u" ["_s + identifier + u']';
+ return message;
+}
+
+QString msgSnippetsResolveError(const QString &path, const QStringList &locations)
+{
+ QString result;
+ QTextStream(&result) << "Could not resolve \"" << path << R"(" in ")"
+ << locations.join(uR"(", ")"_s);
+ return result;
}
static bool isHttpLink(const QString &ref)
@@ -76,66 +59,106 @@ static bool isHttpLink(const QString &ref)
return ref.startsWith(u"http://") || ref.startsWith(u"https://");
}
-struct QtXmlToSphinx::LinkContext
+static QString trimRight(QString s)
{
- enum Type
- {
- Method = 0x1, Function = 0x2,
- FunctionMask = Method | Function,
- Class = 0x4, Attribute = 0x8, Module = 0x10,
- Reference = 0x20, External= 0x40
+ while (!s.isEmpty() && s.crbegin()->isSpace())
+ s.chop(1);
+ return s;
+}
+
+static QString trimLeadingNewlines(QString s)
+{
+ while (!s.isEmpty() && s.at(0) == u'\n')
+ s.remove(0, 1);
+ return s;
+}
+
+QDebug operator<<(QDebug d, const QtXmlToSphinxLink &l)
+{
+ static const QHash<QtXmlToSphinxLink::Type, const char *> typeName = {
+ {QtXmlToSphinxLink::Method, "Method"},
+ {QtXmlToSphinxLink::Function, "Function"},
+ {QtXmlToSphinxLink::Class, "Class"},
+ {QtXmlToSphinxLink::Attribute, "Attribute"},
+ {QtXmlToSphinxLink::Module, "Module"},
+ {QtXmlToSphinxLink::Reference, "Reference"},
+ {QtXmlToSphinxLink::External, "External"},
};
- enum Flags { InsideBold = 0x1, InsideItalic = 0x2 };
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "QtXmlToSphinxLinkContext(" << typeName.value(l.type, "") << ", ref=\""
+ << l.linkRef << '"';
+ if (!l.linkText.isEmpty())
+ d << ", text=\"" << l.linkText << '"';
+ d << ')';
+ return d;
+}
- explicit LinkContext(const QString &ref) : linkRef(ref) {}
+QDebug operator<<(QDebug debug, const QtXmlToSphinx::TableCell &c)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "Cell(\"" << c.data << '"';
+ if (c.colSpan != 0)
+ debug << ", colSpan=" << c.colSpan;
+ if (c.rowSpan != 0)
+ debug << ", rowSpan=" << c.rowSpan;
+ debug << ')';
+ return debug;
+}
- QString linkRef;
- QString linkText;
- Type type = Reference;
- int flags = 0;
-};
+QDebug operator<<(QDebug debug, const QtXmlToSphinx::Table &t)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ t.formatDebug(debug);
+ return debug;
+}
-static const char *linkKeyWord(QtXmlToSphinx::LinkContext::Type type)
+static const char *linkKeyWord(QtXmlToSphinxLink::Type type)
{
switch (type) {
- case QtXmlToSphinx::LinkContext::Method:
+ case QtXmlToSphinxLink::Method:
return ":meth:";
- case QtXmlToSphinx::LinkContext::Function:
+ case QtXmlToSphinxLink::Function:
return ":func:";
- case QtXmlToSphinx::LinkContext::Class:
+ case QtXmlToSphinxLink::Class:
return ":class:";
- case QtXmlToSphinx::LinkContext::Attribute:
+ case QtXmlToSphinxLink::Attribute:
return ":attr:";
- case QtXmlToSphinx::LinkContext::Module:
+ case QtXmlToSphinxLink::Module:
return ":mod:";
- case QtXmlToSphinx::LinkContext::Reference:
+ case QtXmlToSphinxLink::Reference:
return ":ref:";
- case QtXmlToSphinx::LinkContext::External:
+ case QtXmlToSphinxLink::External:
break;
- case QtXmlToSphinx::LinkContext::FunctionMask:
+ case QtXmlToSphinxLink::FunctionMask:
break;
}
return "";
}
-TextStream &operator<<(TextStream &str, const QtXmlToSphinx::LinkContext &linkContext)
+TextStream &operator<<(TextStream &str, const QtXmlToSphinxLink &linkContext)
{
// Temporarily turn off bold/italic since links do not work within
- if (linkContext.flags & QtXmlToSphinx::LinkContext::InsideBold)
+ if (linkContext.flags & QtXmlToSphinxLink::InsideBold)
str << "**";
- else if (linkContext.flags & QtXmlToSphinx::LinkContext::InsideItalic)
+ else if (linkContext.flags & QtXmlToSphinxLink::InsideItalic)
str << '*';
str << ' ' << linkKeyWord(linkContext.type) << '`';
- const bool isExternal = linkContext.type == QtXmlToSphinx::LinkContext::External;
+ const bool isExternal = linkContext.type == QtXmlToSphinxLink::External;
if (!linkContext.linkText.isEmpty()) {
writeEscapedRstText(str, linkContext.linkText);
- if (isExternal && !linkContext.linkText.endsWith(QLatin1Char(' ')))
+ if (isExternal && !linkContext.linkText.endsWith(u' '))
str << ' ';
str << '<';
}
// Convert page titles to RST labels
- str << (linkContext.type == QtXmlToSphinx::LinkContext::Reference
+ str << (linkContext.type == QtXmlToSphinxLink::Reference
? toRstLabel(linkContext.linkRef) : linkContext.linkRef);
if (!linkContext.linkText.isEmpty())
str << '>';
@@ -143,9 +166,9 @@ TextStream &operator<<(TextStream &str, const QtXmlToSphinx::LinkContext &linkCo
if (isExternal)
str << '_';
str << ' ';
- if (linkContext.flags & QtXmlToSphinx::LinkContext::InsideBold)
+ if (linkContext.flags & QtXmlToSphinxLink::InsideBold)
str << "**";
- else if (linkContext.flags & QtXmlToSphinx::LinkContext::InsideItalic)
+ else if (linkContext.flags & QtXmlToSphinxLink::InsideItalic)
str << '*';
return str;
}
@@ -244,9 +267,8 @@ QtXmlToSphinx::QtXmlToSphinx(const QtXmlToSphinxDocGeneratorInterface *docGenera
const QtXmlToSphinxParameters &parameters,
const QString& doc, const QString& context)
: m_output(static_cast<QString *>(nullptr)),
- m_tableHasHeader(false), m_context(context),
- m_generator(docGenerator), m_parameters(parameters),
- m_insideBold(false), m_insideItalic(false)
+ m_context(context),
+ m_generator(docGenerator), m_parameters(parameters)
{
m_result = transform(doc);
}
@@ -283,7 +305,7 @@ void QtXmlToSphinx::callHandler(WebXmlTag t, QXmlStreamReader &r)
handleTableTag(r);
break;
case WebXmlTag::header:
- handleRowTag(r);
+ handleHeaderTag(r);
break;
case WebXmlTag::row:
handleRowTag(r);
@@ -395,35 +417,49 @@ void QtXmlToSphinx::callHandler(WebXmlTag t, QXmlStreamReader &r)
void QtXmlToSphinx::formatCurrentTable()
{
- if (m_currentTable.isEmpty())
+ Q_ASSERT(!m_tables.isEmpty());
+ auto &table = m_tables.back();
+ if (table.isEmpty())
return;
- m_currentTable.setHeaderEnabled(m_tableHasHeader);
- m_currentTable.normalize();
+ table.normalize();
m_output << '\n';
- m_currentTable.format(m_output);
+ table.format(m_output);
}
void QtXmlToSphinx::pushOutputBuffer()
{
- auto *buffer = new QString();
- m_buffers << buffer;
- m_output.setString(buffer);
+ m_buffers.append(std::make_shared<QString>());
+ m_output.setString(m_buffers.top().get());
}
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 result(*m_buffers.top());
+ m_buffers.pop();
+ m_output.setString(m_buffers.isEmpty() ? nullptr : m_buffers.top().get());
+ return result;
+}
+
+constexpr auto autoTranslatedPlaceholder = "AUTO_GENERATED\n"_L1;
+constexpr auto autoTranslatedNote =
+R"(.. warning::
+ This section contains snippets that were automatically
+ translated from C++ to Python and may contain errors.
+
+)"_L1;
+
+void QtXmlToSphinx::setAutoTranslatedNote(QString *str) const
+{
+ if (m_containsAutoTranslations)
+ str->replace(autoTranslatedPlaceholder, autoTranslatedNote);
+ else
+ str->remove(autoTranslatedPlaceholder);
}
QString QtXmlToSphinx::transform(const QString& doc)
{
Q_ASSERT(m_buffers.isEmpty());
- Indentation indentation(m_output);
if (doc.trimmed().isEmpty())
return doc;
@@ -431,6 +467,9 @@ QString QtXmlToSphinx::transform(const QString& doc)
QXmlStreamReader reader(doc);
+ m_output << autoTranslatedPlaceholder;
+ Indentation indentation(m_output);
+
while (!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (reader.hasError()) {
@@ -462,7 +501,7 @@ QString QtXmlToSphinx::transform(const QString& doc)
if (!m_inlineImages.isEmpty()) {
// Write out inline image definitions stored in handleInlineImageTag().
m_output << '\n' << disableIndent;
- for (const InlineImage &img : qAsConst(m_inlineImages))
+ for (const InlineImage &img : std::as_const(m_inlineImages))
m_output << ".. |" << img.tag << "| image:: " << img.href << '\n';
m_output << '\n' << enableIndent;
m_inlineImages.clear();
@@ -471,13 +510,14 @@ QString QtXmlToSphinx::transform(const QString& doc)
m_output.flush();
QString retval = popOutputBuffer();
Q_ASSERT(m_buffers.isEmpty());
+ setAutoTranslatedNote(&retval);
return retval;
}
static QString resolveFile(const QStringList &locations, const QString &path)
{
for (QString location : locations) {
- location.append(QLatin1Char('/'));
+ location.append(u'/');
location.append(path);
if (QFileInfo::exists(location))
return location;
@@ -485,25 +525,170 @@ static QString resolveFile(const QStringList &locations, const QString &path)
return QString();
}
-QString QtXmlToSphinx::readFromLocations(const QStringList &locations, const QString &path,
- const QString &identifier, QString *errorMessage)
+enum class SnippetType
{
+ Other, // .qdoc, .qml,...
+ CppSource, CppHeader // Potentially converted to Python
+};
+
+SnippetType snippetType(const QString &path)
+{
+ if (path.endsWith(u".cpp"))
+ return SnippetType::CppSource;
+ if (path.endsWith(u".h"))
+ return SnippetType::CppHeader;
+ return SnippetType::Other;
+}
+
+// Return the name of a .cpp/.h snippet converted to Python by snippets-translate
+static QString pySnippetName(const QString &path, SnippetType type)
+{
+ switch (type) {
+ case SnippetType::CppSource:
+ return path.left(path.size() - 3) + u"py"_s;
+ break;
+ case SnippetType::CppHeader:
+ return path + u".py"_s;
+ break;
+ default:
+ break;
+ }
+ return {};
+}
+
+QtXmlToSphinx::Snippet QtXmlToSphinx::readSnippetFromLocations(const QString &path,
+ const QString &identifier,
+ const QString &fallbackPath,
+ QString *errorMessage)
+{
+ // For anything else but C++ header/sources (no conversion to Python),
+ // use existing fallback paths first.
+ const auto type = snippetType(path);
+ if (type == SnippetType::Other && !fallbackPath.isEmpty()) {
+ const QString code = readFromLocation(fallbackPath, identifier, errorMessage);
+ return {code, code.isNull() ? Snippet::Error : Snippet::Fallback};
+ }
+
+ // For C++ header/sources, try snippets converted to Python first.
QString resolvedPath;
- if (path.endsWith(QLatin1String(".cpp"))) {
- const QString pySnippet = path.left(path.size() - 3) + QLatin1String("py");
- resolvedPath = resolveFile(locations, pySnippet);
+ const auto &locations = m_parameters.codeSnippetDirs;
+
+ if (type != SnippetType::Other) {
+ if (!fallbackPath.isEmpty() && !m_parameters.codeSnippetRewriteOld.isEmpty()) {
+ // Try looking up Python converted snippets by rewriting snippets paths
+ QString rewrittenPath = pySnippetName(fallbackPath, type);
+ if (!rewrittenPath.isEmpty()) {
+ rewrittenPath.replace(m_parameters.codeSnippetRewriteOld,
+ m_parameters.codeSnippetRewriteNew);
+ const QString code = readFromLocation(rewrittenPath, identifier, errorMessage);
+ m_containsAutoTranslations = true;
+ return {code, code.isNull() ? Snippet::Error : Snippet::Converted};
+ }
+ }
+
+ resolvedPath = resolveFile(locations, pySnippetName(path, type));
+ if (!resolvedPath.isEmpty()) {
+ const QString code = readFromLocation(resolvedPath, identifier, errorMessage);
+ return {code, code.isNull() ? Snippet::Error : Snippet::Converted};
+ }
+ }
+
+ resolvedPath = resolveFile(locations, path);
+ if (!resolvedPath.isEmpty()) {
+ const QString code = readFromLocation(resolvedPath, identifier, errorMessage);
+ return {code, code.isNull() ? Snippet::Error : Snippet::Resolved};
+ }
+
+ if (!fallbackPath.isEmpty()) {
+ *errorMessage = msgFallbackWarning(path, identifier, fallbackPath);
+ const QString code = readFromLocation(fallbackPath, identifier, errorMessage);
+ return {code, code.isNull() ? Snippet::Error : Snippet::Fallback};
+ }
+
+ *errorMessage = msgSnippetsResolveError(path, locations);
+ return {{}, Snippet::Error};
+}
+
+// Helpers for extracting qdoc snippets "#/// [id]"
+static QString fileNameOfDevice(const QIODevice *inputFile)
+{
+ const auto *file = qobject_cast<const QFile *>(inputFile);
+ return file ? QDir::toNativeSeparators(file->fileName()) : u"<stdin>"_s;
+}
+
+static QString msgSnippetNotFound(const QIODevice &inputFile,
+ const QString &identifier)
+{
+ return u"Code snippet file found ("_s + fileNameOfDevice(&inputFile)
+ + u"), but snippet ["_s + identifier + u"] not found."_s;
+}
+
+static QString msgEmptySnippet(const QIODevice &inputFile, int lineNo,
+ const QString &identifier)
+{
+ return u"Empty code snippet ["_s + identifier + u"] at "_s
+ + fileNameOfDevice(&inputFile) + u':' + QString::number(lineNo);
+}
+
+// Pattern to match qdoc snippet IDs with "#/// [id]" comments and helper to find ID
+static const QRegularExpression &snippetIdPattern()
+{
+ static const QRegularExpression result(uR"RX((//|#) *! *\[([^]]+)\])RX"_s);
+ Q_ASSERT(result.isValid());
+ return result;
+}
+
+static bool matchesSnippetId(QRegularExpressionMatchIterator it,
+ const QString &identifier)
+{
+ while (it.hasNext()) {
+ if (it.next().captured(2) == identifier)
+ return true;
+ }
+ return false;
+}
+
+QString QtXmlToSphinx::readSnippet(QIODevice &inputFile, const QString &identifier,
+ QString *errorMessage)
+{
+ const QByteArray identifierBA = identifier.toUtf8();
+ // Lambda that matches the snippet id
+ const auto snippetIdPred = [&identifierBA, &identifier](const QByteArray &lineBA)
+ {
+ const bool isComment = lineBA.contains('/') || lineBA.contains('#');
+ if (!isComment || !lineBA.contains(identifierBA))
+ return false;
+ const QString line = QString::fromUtf8(lineBA);
+ return matchesSnippetId(snippetIdPattern().globalMatch(line), identifier);
+ };
+
+ // Find beginning, skip over
+ int lineNo = 1;
+ for (; !inputFile.atEnd() && !snippetIdPred(inputFile.readLine());
+ ++lineNo) {
}
- if (resolvedPath.isEmpty())
- resolvedPath = resolveFile(locations, path);
- if (resolvedPath.isEmpty()) {
- QTextStream(errorMessage) << "Could not resolve \"" << path << "\" in \""
- << locations.join(QLatin1String("\", \""));
- return QString(); // null
+
+ if (inputFile.atEnd()) {
+ *errorMessage = msgSnippetNotFound(inputFile, identifier);
+ return {};
+ }
+
+ QString code;
+ for (; !inputFile.atEnd(); ++lineNo) {
+ const QString line = QString::fromUtf8(inputFile.readLine());
+ auto it = snippetIdPattern().globalMatch(line);
+ if (it.hasNext()) { // Skip snippet id lines
+ if (matchesSnippetId(it, identifier))
+ break;
+ } else {
+ code += line;
+ }
}
- qCDebug(m_generator->loggingCategory()).noquote().nospace()
- << "snippet file " << path
- << " [" << identifier << ']' << " resolved to " << resolvedPath;
- return readFromLocation(resolvedPath, identifier, errorMessage);
+
+ if (code.isEmpty())
+ *errorMessage = msgEmptySnippet(inputFile, lineNo, identifier);
+
+ return code;
}
QString QtXmlToSphinx::readFromLocation(const QString &location, const QString &identifier,
@@ -515,44 +700,18 @@ QString QtXmlToSphinx::readFromLocation(const QString &location, const QString &
QTextStream(errorMessage) << "Could not read code snippet file: "
<< QDir::toNativeSeparators(inputFile.fileName())
<< ": " << inputFile.errorString();
- return QString(); // null
+ return {}; // null
}
- QString code = QLatin1String(""); // non-null
+ QString code = u""_s; // non-null
if (identifier.isEmpty()) {
while (!inputFile.atEnd())
code += QString::fromUtf8(inputFile.readLine());
return CodeSnipHelpers::fixSpaces(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 CodeSnipHelpers::fixSpaces(code);
+ code = readSnippet(inputFile, identifier, errorMessage);
+ return code.isEmpty() ? QString{} : CodeSnipHelpers::fixSpaces(code); // maintain isNull()
}
void QtXmlToSphinx::handleHeadingTag(QXmlStreamReader& reader)
@@ -562,7 +721,7 @@ void QtXmlToSphinx::handleHeadingTag(QXmlStreamReader& reader)
static char types[] = { '-', '^' };
QXmlStreamReader::TokenType token = reader.tokenType();
if (token == QXmlStreamReader::StartElement) {
- uint typeIdx = reader.attributes().value(QLatin1String("level")).toUInt();
+ uint typeIdx = reader.attributes().value(u"level"_s).toUInt();
if (typeIdx >= sizeof(types))
type = types[sizeof(types)-1];
else
@@ -579,80 +738,133 @@ void QtXmlToSphinx::handleHeadingTag(QXmlStreamReader& reader)
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:: "));
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ handleParaTagStart();
+ break;
+ case QXmlStreamReader::EndElement:
+ handleParaTagEnd();
+ break;
+ case QXmlStreamReader::Characters:
+ handleParaTagText(reader);
+ break;
+ default:
+ break;
+ }
+}
- m_output << result << "\n\n";
- } else if (token == QXmlStreamReader::Characters) {
- const auto text = reader.text();
- const QChar end = m_output.lastChar();
- if (!text.isEmpty() && m_output.indentation() == 0 && !end.isNull()) {
- QChar start = text[0];
- if ((end == QLatin1Char('*') || end == QLatin1Char('`')) && start != QLatin1Char(' ') && !start.isPunct())
- m_output << '\\';
- }
- m_output << escape(text);
+void QtXmlToSphinx::handleParaTagStart()
+{
+ pushOutputBuffer();
+}
+
+void QtXmlToSphinx::handleParaTagText(QXmlStreamReader& reader)
+{
+ const auto text = reader.text();
+ const QChar end = m_output.lastChar();
+ if (!text.isEmpty() && m_output.indentation() == 0 && !end.isNull()) {
+ QChar start = text[0];
+ if ((end == u'*' || end == u'`') && start != u' ' && !start.isPunct())
+ m_output << '\\';
}
+ m_output << escape(text);
+}
+
+void QtXmlToSphinx::handleParaTagEnd()
+{
+ QString result = popOutputBuffer().simplified();
+ if (result.startsWith(u"**Warning:**"))
+ result.replace(0, 12, ".. warning:: "_L1);
+ else if (result.startsWith(u"**Note:**"))
+ result.replace(0, 9, ".. note:: "_L1);
+ m_output << result << "\n\n";
}
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) {
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ if (m_formattingDepth++ == 0) {
+ m_insideItalic = true;
+ m_output << rstItalic;
+ }
+ break;
+ case QXmlStreamReader::EndElement:
+ if (--m_formattingDepth == 0) {
+ m_insideItalic = false;
+ m_output << rstItalicOff;
+ }
+ break;
+ case QXmlStreamReader::Characters:
m_output << escape(reader.text().trimmed());
+ break;
+ default:
+ break;
}
}
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) {
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ if (m_formattingDepth++ == 0) {
+ m_insideBold = true;
+ m_output << rstBold;
+ }
+ break;
+ case QXmlStreamReader::EndElement:
+ if (--m_formattingDepth == 0) {
+ m_insideBold = false;
+ m_output << rstBoldOff;
+ }
+ break;
+ case QXmlStreamReader::Characters:
m_output << escape(reader.text().trimmed());
+ break;
+ default:
+ break;
}
}
void QtXmlToSphinx::handleArgumentTag(QXmlStreamReader& reader)
{
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement || token == QXmlStreamReader::EndElement)
- m_output << "``";
- else if (token == QXmlStreamReader::Characters)
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ if (m_formattingDepth++ == 0)
+ m_output << rstCode;
+ break;
+ case QXmlStreamReader::EndElement:
+ if (--m_formattingDepth == 0)
+ m_output << rstCodeOff;
+ break;
+ case QXmlStreamReader::Characters:
m_output << reader.text().trimmed();
+ break;
+ default:
+ break;
+ }
}
-static inline QString functionLinkType() { return QStringLiteral("function"); }
-static inline QString classLinkType() { return QStringLiteral("class"); }
+constexpr auto functionLinkType = "function"_L1;
+constexpr auto classLinkType = "class"_L1;
static inline QString fixLinkType(QStringView 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();
+ if (type == u"property")
+ return functionLinkType;
+ if (type == u"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");
+ if (type == functionLinkType || type == classLinkType)
+ return u"raw"_s;
+ return type == u"enum" || type == u"page"
+ ? type : u"href"_s;
}
// "See also" links may appear as nested links:
@@ -674,8 +886,8 @@ void QtXmlToSphinx::handleSeeAlsoTag(QXmlStreamReader& reader)
if (!textR.isEmpty()) {
const QString text = textR.toString();
if (m_seeAlsoContext.isNull()) {
- const QString type = text.endsWith(QLatin1String("()"))
- ? functionLinkType() : classLinkType();
+ const QString type = text.endsWith(u"()")
+ ? functionLinkType : classLinkType;
m_seeAlsoContext.reset(handleLinkStart(type, text));
}
handleLinkText(m_seeAlsoContext.data(), text);
@@ -694,12 +906,12 @@ void QtXmlToSphinx::handleSeeAlsoTag(QXmlStreamReader& reader)
}
}
-static inline QString fallbackPathAttribute() { return QStringLiteral("path"); }
+constexpr auto fallbackPathAttribute = "path"_L1;
template <class Indent> // const char*/class Indentor
void formatSnippet(TextStream &str, Indent indent, const QString &snippet)
{
- const auto lines = QStringView{snippet}.split(QLatin1Char('\n'));
+ const auto lines = QStringView{snippet}.split(u'\n');
for (const auto &line : lines) {
if (!line.trimmed().isEmpty())
str << indent << line;
@@ -725,55 +937,48 @@ 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");
+ const bool consecutiveSnippet = m_lastTagName == u"snippet"
+ || m_lastTagName == u"dots" || m_lastTagName == u"codeline";
if (consecutiveSnippet) {
m_output.flush();
- m_output.string()->chop(2);
+ m_output.string()->chop(1); // Strip newline from previous snippet
}
- QString location = reader.attributes().value(QLatin1String("location")).toString();
- QString identifier = reader.attributes().value(QLatin1String("identifier")).toString();
+ QString location = reader.attributes().value(u"location"_s).toString();
+ QString identifier = reader.attributes().value(u"identifier"_s).toString();
+ QString fallbackPath;
+ if (reader.attributes().hasAttribute(fallbackPathAttribute))
+ fallbackPath = reader.attributes().value(fallbackPathAttribute).toString();
QString errorMessage;
- const QString pythonCode =
- readFromLocations(m_parameters.codeSnippetDirs, location, identifier, &errorMessage);
+
+ const Snippet snippet = readSnippetFromLocations(location, identifier,
+ fallbackPath, &errorMessage);
if (!errorMessage.isEmpty())
warn(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() || m_parameters.snippetComparison)
- && reader.attributes().hasAttribute(fallbackPathAttribute())) {
- const QString fallback = reader.attributes().value(fallbackPathAttribute()).toString();
- if (QFileInfo::exists(fallback)) {
- if (pythonCode.isEmpty())
- warn(msgFallbackWarning(reader, m_context, m_lastTagName, location, identifier, fallback));
- fallbackCode = readFromLocation(fallback, identifier, &errorMessage);
- if (!errorMessage.isEmpty())
- warn(msgTagWarning(reader, m_context, m_lastTagName, errorMessage));
- }
- }
- if (!pythonCode.isEmpty() && !fallbackCode.isEmpty() && m_parameters.snippetComparison)
- debug(msgSnippetComparison(location, identifier, pythonCode, fallbackCode));
+ if (m_parameters.snippetComparison && snippet.result == Snippet::Converted
+ && !fallbackPath.isEmpty()) {
+ const QString fallbackCode = readFromLocation(fallbackPath, identifier, &errorMessage);
+ debug(msgSnippetComparison(location, identifier, snippet.code, fallbackCode));
+ }
if (!consecutiveSnippet)
m_output << "::\n\n";
Indentation indentation(m_output);
- const QString code = pythonCode.isEmpty() ? fallbackCode : pythonCode;
- if (code.isEmpty())
+ if (snippet.result == Snippet::Error)
m_output << "<Code snippet \"" << location << ':' << identifier << "\" not found>\n";
else
- m_output << code << ensureEndl;
+ m_output << snippet.code << ensureEndl;
m_output << '\n';
}
}
+
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");
+ const bool consecutiveSnippet = m_lastTagName == u"snippet"
+ || m_lastTagName == u"dots" || m_lastTagName == u"codeline";
if (consecutiveSnippet) {
m_output.flush();
m_output.string()->chop(2);
@@ -781,7 +986,7 @@ void QtXmlToSphinx::handleDotsTag(QXmlStreamReader& reader)
m_output << "::\n\n";
}
pushOutputBuffer();
- int indent = reader.attributes().value(QLatin1String("indent")).toInt()
+ int indent = reader.attributes().value(u"indent"_s).toInt()
+ m_output.indentation() * m_output.tabWidth();
for (int i = 0; i < indent; ++i)
m_output << ' ';
@@ -796,12 +1001,15 @@ void QtXmlToSphinx::handleTableTag(QXmlStreamReader& reader)
{
QXmlStreamReader::TokenType token = reader.tokenType();
if (token == QXmlStreamReader::StartElement) {
- m_currentTable.clear();
- m_tableHasHeader = false;
+ if (parentTag() == WebXmlTag::para)
+ handleParaTagEnd(); // End <para> to prevent the table from being rst-escaped
+ m_tables.push({});
} else if (token == QXmlStreamReader::EndElement) {
// write the table on m_output
formatCurrentTable();
- m_currentTable.clear();
+ m_tables.pop();
+ if (parentTag() == WebXmlTag::para)
+ handleParaTagStart();
}
}
@@ -811,11 +1019,11 @@ void QtXmlToSphinx::handleTermTag(QXmlStreamReader& reader)
if (token == QXmlStreamReader::StartElement) {
pushOutputBuffer();
} else if (token == QXmlStreamReader::Characters) {
- m_output << reader.text().toString().replace(QLatin1String("::"), QLatin1String("."));
+ m_output << reader.text().toString().replace(u"::"_s, u"."_s);
} else if (token == QXmlStreamReader::EndElement) {
TableCell cell;
cell.data = popOutputBuffer().trimmed();
- m_currentTable.appendRow(TableRow(1, cell));
+ m_tables.back().appendRow(TableRow(1, cell));
}
}
@@ -824,70 +1032,83 @@ 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();
+ auto &table = m_tables.back();
+ if (table.isEmpty())
+ table.appendRow({});
+ TableRow& row = table.last();
TableCell cell;
- cell.colSpan = reader.attributes().value(QLatin1String("colspan")).toShort();
- cell.rowSpan = reader.attributes().value(QLatin1String("rowspan")).toShort();
+ cell.colSpan = reader.attributes().value(u"colspan"_s).toShort();
+ cell.rowSpan = reader.attributes().value(u"rowspan"_s).toShort();
row << cell;
pushOutputBuffer();
} else if (token == QXmlStreamReader::EndElement) {
- QString data = popOutputBuffer().trimmed();
- if (!m_currentTable.isEmpty()) {
- TableRow& row = m_currentTable.last();
+ QString data = trimLeadingNewlines(trimRight(popOutputBuffer()));
+ auto &table = m_tables.back();
+ if (!table.isEmpty()) {
+ TableRow& row = table.last();
if (!row.isEmpty())
row.last().data = data;
}
}
}
-void QtXmlToSphinx::handleRowTag(QXmlStreamReader& reader)
+void QtXmlToSphinx::handleHeaderTag(QXmlStreamReader &reader)
{
- QXmlStreamReader::TokenType token = reader.tokenType();
- if (token == QXmlStreamReader::StartElement) {
- m_tableHasHeader = reader.name() == QLatin1String("header");
- m_currentTable.appendRow({});
+ // <header> in WebXML is either a table header or a description of a
+ // C++ header with "name"/"href" attributes.
+ if (reader.tokenType() == QXmlStreamReader::StartElement
+ && !reader.attributes().hasAttribute(u"name"_s)) {
+ auto &table = m_tables.back();
+ table.setHeaderEnabled(true);
+ table.appendRow({});
}
}
+void QtXmlToSphinx::handleRowTag(QXmlStreamReader& reader)
+{
+ if (reader.tokenType() == QXmlStreamReader::StartElement)
+ m_tables.back().appendRow({});
+}
+
enum ListType { BulletList, OrderedList, EnumeratedList };
static inline ListType webXmlListType(QStringView t)
{
- if (t == QLatin1String("enum"))
+ if (t == u"enum")
return EnumeratedList;
- if (t == QLatin1String("ordered"))
+ if (t == u"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")));
+ m_tables.push({});
+ auto &table = m_tables.back();
+ listType = webXmlListType(reader.attributes().value(u"type"_s));
if (listType == EnumeratedList) {
- m_currentTable.appendRow(TableRow{TableCell(QLatin1String("Constant")),
- TableCell(QLatin1String("Description"))});
- m_tableHasHeader = true;
+ table.appendRow(TableRow{TableCell(u"Constant"_s),
+ TableCell(u"Description"_s)});
+ table.setHeaderEnabled(true);
}
m_output.indent();
} else if (token == QXmlStreamReader::EndElement) {
m_output.outdent();
- if (!m_currentTable.isEmpty()) {
+ const auto &table = m_tables.back();
+ if (!table.isEmpty()) {
switch (listType) {
case BulletList:
case OrderedList: {
m_output << '\n';
const char *separator = listType == BulletList ? "* " : "#. ";
const char *indentLine = listType == BulletList ? " " : " ";
- for (const TableCell &cell : m_currentTable.constFirst()) {
- const auto itemLines = QStringView{cell.data}.split(QLatin1Char('\n'));
+ for (const TableCell &cell : table.constFirst()) {
+ const auto itemLines = QStringView{cell.data}.split(u'\n');
m_output << separator << itemLines.constFirst() << '\n';
- for (int i = 1, max = itemLines.count(); i < max; ++i)
+ for (qsizetype i = 1, max = itemLines.size(); i < max; ++i)
m_output << indentLine << itemLines[i] << '\n';
}
m_output << '\n';
@@ -898,7 +1119,7 @@ void QtXmlToSphinx::handleListTag(QXmlStreamReader& reader)
break;
}
}
- m_currentTable.clear();
+ m_tables.pop();
}
}
@@ -908,7 +1129,7 @@ void QtXmlToSphinx::handleLinkTag(QXmlStreamReader& reader)
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 type = fixLinkType(reader.attributes().value(u"type"_s));
const QString ref = reader.attributes().value(linkSourceAttribute(type)).toString();
m_linkContext.reset(handleLinkStart(type, ref));
}
@@ -927,122 +1148,109 @@ void QtXmlToSphinx::handleLinkTag(QXmlStreamReader& reader)
}
}
-QtXmlToSphinx::LinkContext *QtXmlToSphinx::handleLinkStart(const QString &type, QString ref) const
+QtXmlToSphinxLink *QtXmlToSphinx::handleLinkStart(const QString &type, QString ref) const
{
- ref.replace(QLatin1String("::"), QLatin1String("."));
- ref.remove(QLatin1String("()"));
- auto *result = new LinkContext(ref);
+ ref.replace(u"::"_s, u"."_s);
+ ref.remove(u"()"_s);
+ auto *result = new QtXmlToSphinxLink(ref);
if (m_insideBold)
- result->flags |= LinkContext::InsideBold;
+ result->flags |= QtXmlToSphinxLink::InsideBold;
else if (m_insideItalic)
- result->flags |= LinkContext::InsideItalic;
+ result->flags |= QtXmlToSphinxLink::InsideItalic;
if (type == u"external" || isHttpLink(ref)) {
- result->type = LinkContext::External;
- } else if (type == functionLinkType() && !m_context.isEmpty()) {
- result->type = LinkContext::Method;
- const auto rawlinklist = QStringView{result->linkRef}.split(QLatin1Char('.'));
+ result->type = QtXmlToSphinxLink::External;
+ } else if (type == functionLinkType && !m_context.isEmpty()) {
+ result->type = QtXmlToSphinxLink::Method;
+ const auto rawlinklist = QStringView{result->linkRef}.split(u'.');
if (rawlinklist.size() == 1 || rawlinklist.constFirst() == m_context) {
const auto lastRawLink = rawlinklist.constLast().toString();
QString context = m_generator->resolveContextForMethod(m_context, lastRawLink);
if (!result->linkRef.startsWith(context))
- result->linkRef.prepend(context + QLatin1Char('.'));
+ result->linkRef.prepend(context + u'.');
} else {
result->linkRef = m_generator->expandFunction(result->linkRef);
}
- } else if (type == functionLinkType() && m_context.isEmpty()) {
- result->type = LinkContext::Function;
- } else if (type == classLinkType()) {
- result->type = LinkContext::Class;
+ } else if (type == functionLinkType && m_context.isEmpty()) {
+ result->type = QtXmlToSphinxLink::Function;
+ } else if (type == classLinkType) {
+ result->type = QtXmlToSphinxLink::Class;
result->linkRef = m_generator->expandClass(m_context, result->linkRef);
- } else if (type == QLatin1String("enum")) {
- result->type = LinkContext::Attribute;
- } else if (type == QLatin1String("page")) {
+ } else if (type == u"enum") {
+ result->type = QtXmlToSphinxLink::Attribute;
+ } else if (type == u"page") {
// Module, external web page or reference
if (result->linkRef == m_parameters.moduleName)
- result->type = LinkContext::Module;
+ result->type = QtXmlToSphinxLink::Module;
else
- result->type = LinkContext::Reference;
+ result->type = QtXmlToSphinxLink::Reference;
} else {
- result->type = LinkContext::Reference;
+ result->type = QtXmlToSphinxLink::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 type="page" page="https://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,
+static QString fixLinkText(const QtXmlToSphinxLink *linkContext,
QString linktext)
{
- if (linkContext->type == QtXmlToSphinx::LinkContext::External
- || linkContext->type == QtXmlToSphinx::LinkContext::Reference) {
+ if (linkContext->type == QtXmlToSphinxLink::External
+ || linkContext->type == QtXmlToSphinxLink::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("::"));
+ const int lastSep = linktext.lastIndexOf(u"::");
if (lastSep != -1)
linktext.remove(0, lastSep + 2);
else
QtXmlToSphinx::stripPythonQualifiers(&linktext);
if (linkContext->linkRef == linktext)
- return QString();
- if ((linkContext->type & QtXmlToSphinx::LinkContext::FunctionMask) != 0
- && (linkContext->linkRef + QLatin1String("()")) == linktext) {
- return QString();
+ return {};
+ if ((linkContext->type & QtXmlToSphinxLink::FunctionMask) != 0
+ && (linkContext->linkRef + u"()"_s) == linktext) {
+ return {};
}
return linktext;
}
-void QtXmlToSphinx::handleLinkText(LinkContext *linkContext, const QString &linktext)
+void QtXmlToSphinx::handleLinkText(QtXmlToSphinxLink *linkContext, const QString &linktext)
{
linkContext->linkText = fixLinkText(linkContext, linktext);
}
-void QtXmlToSphinx::handleLinkEnd(LinkContext *linkContext)
+void QtXmlToSphinx::handleLinkEnd(QtXmlToSphinxLink *linkContext)
{
- m_output << *linkContext;
+ m_output << m_generator->resolveLink(*linkContext);
+}
+
+WebXmlTag QtXmlToSphinx::parentTag() const
+{
+ const auto index = m_tagStack.size() - 2;
+ return index >= 0 ? m_tagStack.at(index) : WebXmlTag::Unknown;
}
// Copy images that are placed in a subdirectory "images" under the webxml files
// by qdoc to a matching subdirectory under the "rst/PySide6/<module>" directory
-static bool copyImage(const QString &href, const QString &docDataDir,
- const QString &context, const QString &outputDir,
+static bool copyImage(const QString &docDataDir, const QString &relativeSourceFile,
+ const QString &outputDir, const QString &relativeTargetFile,
const QLoggingCategory &lc, 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;
+ QString targetFileName = outputDir + u'/' + relativeTargetFile;
if (QFileInfo::exists(targetFileName))
return true;
- if (!QFileInfo::exists(targetDir)) {
+
+ QString relativeTargetDir = relativeTargetFile;
+ relativeTargetDir.truncate(qMax(relativeTargetDir.lastIndexOf(u'/'), qsizetype(0)));
+ if (!relativeTargetDir.isEmpty() && !QFileInfo::exists(outputDir + u'/' + relativeTargetDir)) {
const QDir outDir(outputDir);
if (!outDir.mkpath(relativeTargetDir)) {
QTextStream(errorMessage) << "Cannot create " << QDir::toNativeSeparators(relativeTargetDir)
@@ -1051,28 +1259,29 @@ static bool copyImage(const QString &href, const QString &docDataDir,
}
}
- QFile source(imageSource.absoluteFilePath());
+ QFile source(docDataDir + u'/' + relativeSourceFile);
if (!source.copy(targetFileName)) {
QTextStream(errorMessage) << "Cannot copy " << QDir::toNativeSeparators(source.fileName())
<< " to " << QDir::toNativeSeparators(targetFileName) << ": "
<< source.errorString();
return false;
}
- qCDebug(lc).noquote().nospace() << __FUNCTION__ << " href=\""
- << href << "\", context=\"" << context << "\", docDataDir=\""
- << docDataDir << "\", outputDir=\"" << outputDir << "\", copied \""
- << source.fileName() << "\"->\"" << targetFileName << '"';
+
+ qCDebug(lc).noquote().nospace() << __FUNCTION__ << " \"" << relativeSourceFile
+ << "\"->\"" << relativeTargetFile << '"';
return true;
}
bool QtXmlToSphinx::copyImage(const QString &href) const
{
QString errorMessage;
- const bool result =
- ::copyImage(href, m_parameters.docDataDir, m_context,
- m_parameters.outputDirectory,
- m_generator->loggingCategory(),
- &errorMessage);
+ const auto imagePaths = m_generator->resolveImage(href, m_context);
+ const bool result = ::copyImage(m_parameters.docDataDir,
+ imagePaths.source,
+ m_parameters.outputDirectory,
+ imagePaths.target,
+ m_generator->loggingCategory(),
+ &errorMessage);
if (!result)
throw Exception(errorMessage);
return result;
@@ -1082,7 +1291,7 @@ void QtXmlToSphinx::handleImageTag(QXmlStreamReader& reader)
{
if (reader.tokenType() != QXmlStreamReader::StartElement)
return;
- const QString href = reader.attributes().value(QLatin1String("href")).toString();
+ const QString href = reader.attributes().value(u"href"_s).toString();
if (copyImage(href))
m_output << ".. image:: " << href << "\n\n";
}
@@ -1091,17 +1300,17 @@ void QtXmlToSphinx::handleInlineImageTag(QXmlStreamReader& reader)
{
if (reader.tokenType() != QXmlStreamReader::StartElement)
return;
- const QString href = reader.attributes().value(QLatin1String("href")).toString();
+ const QString href = reader.attributes().value(u"href"_s).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('/'));
+ auto pos = tag.lastIndexOf(u'/');
if (pos != -1)
tag.remove(0, pos + 1);
- pos = tag.indexOf(QLatin1Char('.'));
+ pos = tag.indexOf(u'.');
if (pos != -1)
tag.truncate(pos);
tag += QString::number(m_inlineImages.size() + 1);
@@ -1113,7 +1322,7 @@ void QtXmlToSphinx::handleRawTag(QXmlStreamReader& reader)
{
QXmlStreamReader::TokenType token = reader.tokenType();
if (token == QXmlStreamReader::StartElement) {
- QString format = reader.attributes().value(QLatin1String("format")).toString();
+ QString format = reader.attributes().value(u"format"_s).toString();
m_output << ".. raw:: " << format.toLower() << "\n\n";
} else if (token == QXmlStreamReader::Characters) {
Indentation indent(m_output);
@@ -1166,11 +1375,11 @@ void QtXmlToSphinx::handlePageTag(QXmlStreamReader &reader)
m_output << disableIndent;
- const auto title = reader.attributes().value(titleAttribute());
+ const auto title = reader.attributes().value("title");
if (!title.isEmpty())
m_output << rstLabel(title.toString());
- const auto fullTitle = reader.attributes().value(fullTitleAttribute());
+ const auto fullTitle = reader.attributes().value("fulltitle");
const int size = fullTitle.isEmpty()
? writeEscapedRstText(m_output, title)
: writeEscapedRstText(m_output, fullTitle);
@@ -1183,7 +1392,7 @@ void QtXmlToSphinx::handleTargetTag(QXmlStreamReader &reader)
{
if (reader.tokenType() != QXmlStreamReader::StartElement)
return;
- const auto name = reader.attributes().value(nameAttribute());
+ const auto name = reader.attributes().value("name");
if (!name.isEmpty())
m_output << rstLabel(name.toString());
}
@@ -1203,14 +1412,14 @@ 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 (reader.attributes().hasAttribute(u"id"_s))
+ anchor = reader.attributes().value(u"id"_s).toString();
+ else if (reader.attributes().hasAttribute(u"name"_s))
+ anchor = reader.attributes().value(u"name"_s).toString();
if (!anchor.isEmpty() && m_opened_anchor != anchor) {
m_opened_anchor = anchor;
if (!m_context.isEmpty())
- anchor.prepend(m_context + QLatin1Char('_'));
+ anchor.prepend(m_context + u'_');
m_output << rstLabel(anchor);
}
} else if (token == QXmlStreamReader::EndElement) {
@@ -1229,7 +1438,7 @@ void QtXmlToSphinx::handleQuoteFileTag(QXmlStreamReader& reader)
QXmlStreamReader::TokenType token = reader.tokenType();
if (token == QXmlStreamReader::Characters) {
QString location = reader.text().toString();
- location.prepend(m_parameters.libSourceDir + QLatin1Char('/'));
+ location.prepend(m_parameters.libSourceDir + u'/');
QString errorMessage;
QString code = readFromLocation(location, QString(), &errorMessage);
if (!errorMessage.isEmpty())
@@ -1244,51 +1453,72 @@ void QtXmlToSphinx::handleQuoteFileTag(QXmlStreamReader& reader)
}
}
+bool QtXmlToSphinx::Table::hasEmptyLeadingRow() const
+{
+ return !m_rows.isEmpty() && m_rows.constFirst().isEmpty();
+}
+
+bool QtXmlToSphinx::Table::hasEmptyTrailingRow() const
+{
+ return !m_rows.isEmpty() && m_rows.constLast().isEmpty();
+}
+
void QtXmlToSphinx::Table::normalize()
{
- if (m_normalized || isEmpty())
+ if (m_normalized)
+ return;
+
+ // Empty leading/trailing rows have been observed with nested tables
+ if (hasEmptyLeadingRow() || hasEmptyLeadingRow()) {
+ qWarning() << "QtXmlToSphinx: Table with leading/trailing empty columns found: " << *this;
+ while (hasEmptyTrailingRow())
+ m_rows.pop_back();
+ while (hasEmptyLeadingRow())
+ m_rows.pop_front();
+ }
+
+ if (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();
+ qsizetype maxCols = -1;
+ for (const auto &row : std::as_const(m_rows)) {
+ if (row.size() > maxCols)
+ maxCols = row.size();
}
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) {
+ for (qsizetype row = 0; row < m_rows.size(); ++row) {
+ for (qsizetype col = 0; col < m_rows.at(row).size(); ++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) {
+ 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;
+ m_rows[row][maxCols - 1].data += u' ' + 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()) {
+ const qsizetype numCols = m_rows.constFirst().size();
+ for (qsizetype col = 0; col < numCols; ++col) {
+ for (qsizetype row = 0; row < m_rows.size(); ++row) {
+ if (col < m_rows[row].size()) {
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, int(m_rows.count()));
+ qsizetype targetRow = row + 1;
+ const qsizetype targetEndRow =
+ std::min(targetRow + cell.rowSpan - 1, m_rows.size());
cell.rowSpan = 0;
for ( ; targetRow < targetEndRow; ++targetRow)
m_rows[targetRow].insert(col, newCell);
@@ -1308,16 +1538,17 @@ void QtXmlToSphinx::Table::format(TextStream& s) const
Q_ASSERT(isNormalized());
// calc width and height of each column and row
- const int headerColumnCount = m_rows.constFirst().count();
- QList<int> colWidths(headerColumnCount, 0);
- QList<int> rowHeights(m_rows.count(), 0);
- for (int i = 0, maxI = m_rows.count(); i < maxI; ++i) {
+ const qsizetype headerColumnCount = m_rows.constFirst().size();
+ QList<qsizetype> colWidths(headerColumnCount, 0);
+ QList<qsizetype> rowHeights(m_rows.size(), 0);
+ for (qsizetype i = 0, maxI = m_rows.size(); 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 auto rowLines = QStringView{row[j].data}.split(QLatin1Char('\n')); // cache this would be a good idea
+ for (qsizetype j = 0, maxJ = std::min(row.size(), colWidths.size()); j < maxJ; ++j) {
+ // cache this would be a good idea
+ const auto rowLines = QStringView{row[j].data}.split(u'\n');
for (const auto &str : rowLines)
- colWidths[j] = std::max(colWidths[j], int(str.size()));
- rowHeights[i] = std::max(rowHeights[i], int(rowLines.size()));
+ colWidths[j] = std::max(colWidths[j], str.size());
+ rowHeights[i] = std::max(rowHeights[i], rowLines.size());
}
}
@@ -1325,44 +1556,41 @@ void QtXmlToSphinx::Table::format(TextStream& s) const
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('+');
- }
+ QString horizontalLine = u"+"_s;
+ for (auto colWidth : colWidths)
+ horizontalLine += QString(colWidth, u'-') + u'+';
// write table rows
- for (int i = 0, maxI = m_rows.count(); i < maxI; ++i) { // for each row
+ for (qsizetype i = 0, maxI = m_rows.size(); i < maxI; ++i) { // for each row
const QtXmlToSphinx::TableRow& row = m_rows.at(i);
// print line
s << '+';
- for (int col = 0; col < headerColumnCount; ++col) {
- char c;
- if (col >= row.length() || row[col].rowSpan == -1)
+ for (qsizetype col = 0; col < headerColumnCount; ++col) {
+ char c = '-';
+ if (col >= row.size() || row[col].rowSpan == -1)
c = ' ';
else if (i == 1 && hasHeader())
c = '=';
- else
- c = '-';
s << Pad(c, colWidths.at(col)) << '+';
}
s << '\n';
// 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(int(row.count()), headerColumnCount); j < maxJ; ++j) { // for each column
+ for (qsizetype rowLine = 0; rowLine < rowHeights.at(i); ++rowLine) { // for each line in a row
+ qsizetype j = 0;
+ for (qsizetype maxJ = std::min(row.size(), headerColumnCount); j < maxJ; ++j) { // for each column
const QtXmlToSphinx::TableCell& cell = row[j];
- const auto rowLines = QStringView{cell.data}.split(QLatin1Char('\n')); // FIXME: Cache this!!!
+ // FIXME: Cache this!!!
+ const auto rowLines = QStringView{cell.data}.split(u'\n');
if (!j || !cell.colSpan)
s << '|';
else
s << ' ';
- const int width = colWidths.at(j);
- if (rowLine < rowLines.count())
+ const auto width = int(colWidths.at(j));
+ if (rowLine < rowLines.size())
s << AlignedField(rowLines.at(rowLine), width);
else
s << Pad(' ', width);
@@ -1375,9 +1603,31 @@ void QtXmlToSphinx::Table::format(TextStream& s) const
s << horizontalLine << "\n\n";
}
+void QtXmlToSphinx::Table::formatDebug(QDebug &debug) const
+{
+ const auto rowCount = m_rows.size();
+ debug << "Table(" <<rowCount << " rows";
+ if (m_hasHeader)
+ debug << ", [header]";
+ if (m_normalized)
+ debug << ", [normalized]";
+ for (qsizetype r = 0; r < rowCount; ++r) {
+ const auto &row = m_rows.at(r);
+ const auto &colCount = row.size();
+ debug << ", row " << r << " [" << colCount << "]={";
+ for (qsizetype c = 0; c < colCount; ++c) {
+ if (c > 0)
+ debug << ", ";
+ debug << row.at(c);
+ }
+ debug << '}';
+ }
+ debug << ')';
+}
+
void QtXmlToSphinx::stripPythonQualifiers(QString *s)
{
- const int lastSep = s->lastIndexOf(QLatin1Char('.'));
+ const int lastSep = s->lastIndexOf(u'.');
if (lastSep != -1)
s->remove(0, lastSep + 1);
}
diff --git a/sources/shiboken6/generator/qtdoc/qtxmltosphinx.h b/sources/shiboken6/generator/qtdoc/qtxmltosphinx.h
index 5c3a90be5..398c5bc97 100644
--- a/sources/shiboken6/generator/qtdoc/qtxmltosphinx.h
+++ b/sources/shiboken6/generator/qtdoc/qtxmltosphinx.h
@@ -1,48 +1,25 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QTXMLTOSPHINX_H
#define QTXMLTOSPHINX_H
#include <textstream.h>
-#include <QtCore/QHash>
#include <QtCore/QList>
#include <QtCore/QScopedPointer>
#include <QtCore/QStack>
-#include <QtCore/QTextStream>
+
+#include <memory>
QT_BEGIN_NAMESPACE
+class QDebug;
class QXmlStreamReader;
QT_END_NAMESPACE
class QtXmlToSphinxDocGeneratorInterface;
struct QtXmlToSphinxParameters;
+struct QtXmlToSphinxLink;
enum class WebXmlTag;
@@ -51,8 +28,6 @@ class QtXmlToSphinx
public:
Q_DISABLE_COPY_MOVE(QtXmlToSphinx)
- struct LinkContext;
-
struct InlineImage
{
QString tag;
@@ -66,7 +41,7 @@ public:
QString data;
TableCell(const QString& text = QString()) : data(text) {}
- TableCell(const char* text) : data(QLatin1String(text)) {}
+ TableCell(const char* text) : data(QString::fromLatin1(text)) {}
};
using TableRow = QList<TableCell>;
@@ -95,20 +70,19 @@ public:
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(); }
+ const TableRow &constFirst() const { return m_rows.constFirst(); }
TableRow &first() { return m_rows.first(); }
TableRow &last() { return m_rows.last(); }
void format(TextStream& s) const;
+ void formatDebug(QDebug &debug) const;
private:
+ bool hasEmptyLeadingRow() const;
+ bool hasEmptyTrailingRow() const;
+
QList<TableRow> m_rows;
bool m_hasHeader = false;
bool m_normalized = false;
@@ -127,11 +101,20 @@ public:
static void stripPythonQualifiers(QString *s);
+ // For testing
+ static QString readSnippet(QIODevice &inputFile, const QString &identifier,
+ QString *errorMessage);
+
private:
+ using StringSharedPtr = std::shared_ptr<QString>;
+
QString transform(const QString& doc);
void handleHeadingTag(QXmlStreamReader& reader);
void handleParaTag(QXmlStreamReader& reader);
+ void handleParaTagStart();
+ void handleParaTagText(QXmlStreamReader &reader);
+ void handleParaTagEnd();
void handleItalicTag(QXmlStreamReader& reader);
void handleBoldTag(QXmlStreamReader& reader);
void handleArgumentTag(QXmlStreamReader& reader);
@@ -149,6 +132,7 @@ private:
// table tagsvoid QtXmlToSphinx::handleValueTag(QXmlStreamReader& reader)
void handleTableTag(QXmlStreamReader& reader);
+ void handleHeaderTag(QXmlStreamReader& reader);
void handleRowTag(QXmlStreamReader& reader);
void handleItemTag(QXmlStreamReader& reader);
void handleRawTag(QXmlStreamReader& reader);
@@ -162,9 +146,10 @@ private:
void handleAnchorTag(QXmlStreamReader& reader);
void handleRstPassTroughTag(QXmlStreamReader& reader);
- LinkContext *handleLinkStart(const QString &type, QString ref) const;
- static void handleLinkText(LinkContext *linkContext, const QString &linktext) ;
- void handleLinkEnd(LinkContext *linkContext);
+ QtXmlToSphinxLink *handleLinkStart(const QString &type, QString ref) const;
+ static void handleLinkText(QtXmlToSphinxLink *linkContext, const QString &linktext) ;
+ void handleLinkEnd(QtXmlToSphinxLink *linkContext);
+ WebXmlTag parentTag() const;
void warn(const QString &message) const;
void debug(const QString &message) const;
@@ -173,23 +158,42 @@ private:
TextStream m_output;
QString m_result;
- QStack<QString*> m_buffers;
+ QStack<StringSharedPtr> m_buffers; // Maintain address stability since it used in TextStream
- Table m_currentTable;
- QScopedPointer<LinkContext> m_linkContext; // for <link>
- QScopedPointer<LinkContext> m_seeAlsoContext; // for <see-also>foo()</see-also>
- bool m_tableHasHeader;
+ QStack<Table> m_tables; // Stack of tables, used for <table><list> with nested <item>
+ QScopedPointer<QtXmlToSphinxLink> m_linkContext; // for <link>
+ QScopedPointer<QtXmlToSphinxLink> m_seeAlsoContext; // for <see-also>foo()</see-also>
QString m_context;
const QtXmlToSphinxDocGeneratorInterface *m_generator;
const QtXmlToSphinxParameters &m_parameters;
- bool m_insideBold;
- bool m_insideItalic;
+ int m_formattingDepth = 0;
+ bool m_insideBold = false;
+ bool m_insideItalic = false;
QString m_lastTagName;
QString m_opened_anchor;
QList<InlineImage> m_inlineImages;
- QString readFromLocations(const QStringList &locations, const QString &path,
- const QString &identifier, QString *errorMessage);
+ bool m_containsAutoTranslations = false;
+
+ struct Snippet
+ {
+ enum Result {
+ Converted, // C++ converted to Python
+ Resolved, // Otherwise resolved in snippet paths
+ Fallback, // Fallback from XML
+ Error
+ };
+
+ QString code;
+ Result result;
+ };
+
+ void setAutoTranslatedNote(QString *str) const;
+
+ Snippet readSnippetFromLocations(const QString &path,
+ const QString &identifier,
+ const QString &fallbackPath,
+ QString *errorMessage);
static QString readFromLocation(const QString &location, const QString &identifier,
QString *errorMessage);
void pushOutputBuffer();
@@ -205,4 +209,8 @@ inline TextStream& operator<<(TextStream& s, const QtXmlToSphinx& xmlToSphinx)
return s << xmlToSphinx.result();
}
+QDebug operator<<(QDebug d, const QtXmlToSphinxLink &l);
+QDebug operator<<(QDebug debug, const QtXmlToSphinx::Table &t);
+QDebug operator<<(QDebug debug, const QtXmlToSphinx::TableCell &c);
+
#endif // QTXMLTOSPHINX_H
diff --git a/sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h b/sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h
index c4bdedd21..d4a098a12 100644
--- a/sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h
+++ b/sources/shiboken6/generator/qtdoc/qtxmltosphinxinterface.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QTXMLTOSPHINXINTERFACE_H
#define QTXMLTOSPHINXINTERFACE_H
@@ -40,9 +15,31 @@ struct QtXmlToSphinxParameters
QString outputDirectory;
QString libSourceDir;
QStringList codeSnippetDirs;
+ QString codeSnippetRewriteOld;
+ QString codeSnippetRewriteNew;
bool snippetComparison = false;
};
+struct QtXmlToSphinxLink
+{
+ 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 QtXmlToSphinxLink(const QString &ref) : linkRef(ref) {}
+
+ QString linkRef;
+ QString linkText;
+ Type type = Reference;
+ int flags = 0;
+};
+
class QtXmlToSphinxDocGeneratorInterface
{
public:
@@ -54,6 +51,17 @@ public:
virtual const QLoggingCategory &loggingCategory() const = 0;
+ virtual QtXmlToSphinxLink resolveLink(const QtXmlToSphinxLink &) const = 0;
+
+ // Resolve images paths relative to doc data directory/output directory.
+ struct Image
+ {
+ QString source;
+ QString target;
+ };
+
+ virtual Image resolveImage(const QString &href, const QString &context) const = 0;
+
virtual ~QtXmlToSphinxDocGeneratorInterface() = default;
};
diff --git a/sources/shiboken6/generator/qtdoc/rstformat.h b/sources/shiboken6/generator/qtdoc/rstformat.h
index d14ecc55d..8af7671fb 100644
--- a/sources/shiboken6/generator/qtdoc/rstformat.h
+++ b/sources/shiboken6/generator/qtdoc/rstformat.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef RSTFORMAT_H
#define RSTFORMAT_H
@@ -55,28 +30,6 @@ inline QByteArray rstDeprecationNote(const char *what)
+ what + QByteArrayLiteral(" is deprecated.\n\n");
}
-class Pad
-{
-public:
- explicit Pad(char c, int count) : m_char(c), m_count(count) {}
-
- void write(TextStream &str) const
- {
- for (int i = 0; i < m_count; ++i)
- str << m_char;
- }
-
-private:
- const char m_char;
- const int m_count;
-};
-
-inline TextStream &operator<<(TextStream &str, const Pad &pad)
-{
- pad.write(str);
- return str;
-}
-
template <class String>
inline int writeEscapedRstText(TextStream &str, const String &s)
{
@@ -116,14 +69,14 @@ inline TextStream &operator<<(TextStream &str, const escape &e)
// RST anchor string: Anything else but letters, numbers, '_' or '.' replaced by '-'
inline bool isValidRstLabelChar(QChar c)
{
- return c.isLetterOrNumber() || c == QLatin1Char('_') || c == QLatin1Char('.');
+ return c.isLetterOrNumber() || c == u'_' || c == u'.';
}
inline QString toRstLabel(QString s)
{
for (int i = 0, size = s.size(); i < size; ++i) {
if (!isValidRstLabelChar(s.at(i)))
- s[i] = QLatin1Char('-');
+ s[i] = u'-';
}
return s;
}
diff --git a/sources/shiboken6/generator/shiboken/configurablescope.h b/sources/shiboken6/generator/shiboken/configurablescope.h
new file mode 100644
index 000000000..9040c7ad9
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/configurablescope.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef CONFIGURABLESCOPE_H
+#define CONFIGURABLESCOPE_H
+
+#include <textstream.h>
+#include <configurabletypeentry.h>
+
+/// Enclose a scope within preprocessor conditions for configurable entries
+class ConfigurableScope
+{
+public:
+ explicit ConfigurableScope(TextStream &s, const ConfigurableTypeEntryCPtr &t) :
+ m_stream(s),
+ m_hasConfigCondition(t->hasConfigCondition())
+ {
+ if (m_hasConfigCondition)
+ m_stream << t->configCondition() << '\n';
+ }
+
+ ~ConfigurableScope()
+ {
+ if (m_hasConfigCondition)
+ m_stream << "#endif\n";
+ }
+
+private:
+ TextStream &m_stream;
+ const bool m_hasConfigCondition;
+};
+
+#endif // CONFIGURABLESCOPE_H
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
index 182e3a112..97a38a08d 100644
--- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
@@ -1,44 +1,27 @@
-/****************************************************************************
-**
-** 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>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "cppgenerator.h"
+#include "configurablescope.h"
+#include "generatorargument.h"
+#include "generatorstrings.h"
+#include "defaultvalue.h"
+#include "generatorcontext.h"
+#include "codesnip.h"
+#include "customconversion.h"
+#include "headergenerator.h"
#include "apiextractorresult.h"
#include "ctypenames.h"
#include <exception.h>
#include "pytypenames.h"
#include "fileout.h"
#include "overloaddata.h"
+#include "pymethoddefentry.h"
#include <abstractmetaenum.h>
#include <abstractmetafield.h>
#include <abstractmetafunction.h>
#include <abstractmetalang.h>
+#include <abstractmetalang_helpers.h>
#include <messages.h>
#include <modifications.h>
#include <propertyspec.h>
@@ -46,80 +29,115 @@
#include <sourcelocation.h>
#include <textstream.h>
#include <typedatabase.h>
+#include <containertypeentry.h>
+#include <enumtypeentry.h>
+#include <flagstypeentry.h>
+#include <functiontypeentry.h>
+#include <namespacetypeentry.h>
+#include <primitivetypeentry.h>
+#include <smartpointertypeentry.h>
+#include <typesystemtypeentry.h>
+#include <valuetypeentry.h>
#include <parser/enumvalue.h>
+#include "qtcompat.h"
+
+#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QMetaObject>
+#include <QtCore/QMetaType>
#include <QtCore/QRegularExpression>
#include <QtCore/QTextStream>
-#include <QtCore/QDebug>
-#include <QMetaType>
#include <algorithm>
#include <cstring>
+#include <memory>
+#include <set>
+
+using namespace Qt::StringLiterals;
-static const char CPP_ARG0[] = "cppArg0";
+static const char shibokenErrorsOccurred[] = "Shiboken::Errors::occurred() != nullptr";
-static inline QString reprFunction() { return QStringLiteral("__repr__"); }
+static constexpr auto virtualMethodStaticReturnVar = "result"_L1;
+static constexpr auto initFuncPrefix = "init_"_L1;
-QString CppGenerator::m_currentErrorCode(QLatin1String("{}"));
+static constexpr auto sbkObjectTypeF = "SbkObject_TypeF()"_L1;
+static const char initInheritanceFunction[] = "initInheritance";
-static const char typeNameFunc[] = R"CPP(
-template <class T>
-static const char *typeNameOf(const T &t)
+static QString mangleName(QString name)
{
- 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;
+ if (name == u"None" || name == u"False" || name == u"True" || name == u"from")
+ name += u'_';
+ return name;
}
-)CPP";
-// utility functions
-inline AbstractMetaType getTypeWithoutContainer(const AbstractMetaType &arg)
+struct sbkUnusedVariableCast
{
- if (arg.typeEntry()->isContainer()) {
- // only support containers with 1 type
- if (arg.instantiations().size() == 1)
- return arg.instantiations().constFirst();
- }
- return arg;
-}
+ explicit sbkUnusedVariableCast(QAnyStringView name) : m_name(name) {}
-// A helper for writing C++ return statements for either void ("return;")
-// or some return value ("return value;")
-class returnStatement
+ const QAnyStringView m_name;
+};
+
+TextStream &operator<<(TextStream &str, const sbkUnusedVariableCast &c)
{
-public:
- explicit returnStatement(QString s) : m_returnValue(std::move(s)) {}
+ str << "SBK_UNUSED(" << c.m_name << ")\n";
+ return str;
+}
- friend TextStream &operator<<(TextStream &s, const returnStatement &r);
+struct pyTypeGetSlot
+{
+ explicit pyTypeGetSlot(QAnyStringView funcType, QAnyStringView typeObject,
+ QAnyStringView aSlot) :
+ m_funcType(funcType), m_typeObject(typeObject), m_slot(aSlot) {}
-private:
- const QString m_returnValue;
+ const QAnyStringView m_funcType;
+ const QAnyStringView m_typeObject;
+ const QAnyStringView m_slot;
};
-TextStream &operator<<(TextStream &s, const returnStatement &r)
+TextStream &operator<<(TextStream &str, const pyTypeGetSlot &p)
+{
+ str << "reinterpret_cast<" << p.m_funcType << ">(PepType_GetSlot("
+ << p.m_typeObject << ", " << p.m_slot << "));\n";
+ return str;
+}
+
+TextStream &operator<<(TextStream &s, CppGenerator::ErrorReturn r)
{
s << "return";
- if (!r.m_returnValue.isEmpty())
- s << ' ' << r.m_returnValue;
- s << ';';
+ switch (r) {
+ case CppGenerator::ErrorReturn::Default:
+ s << " {}";
+ break;
+ case CppGenerator::ErrorReturn::Zero:
+ s << " 0";
+ break;
+ case CppGenerator::ErrorReturn::MinusOne:
+ s << " -1";
+ break;
+ case CppGenerator::ErrorReturn::Void:
+ break;
+ }
+ s << ";\n";
+ return s;
+}
+
+static constexpr auto converterVar = "converter"_L1;
+
+struct registerConverterName
+{
+ explicit registerConverterName(QAnyStringView typeName,
+ QAnyStringView varName = converterVar) :
+ m_typeName(typeName), m_varName(varName) {}
+
+ QAnyStringView m_typeName;
+ QAnyStringView m_varName;
+};
+
+TextStream &operator<<(TextStream &s, const registerConverterName &r)
+{
+ s << "Shiboken::Conversions::registerConverterName(" << r.m_varName
+ << ", \"" << r.m_typeName << "\");\n";
return s;
}
@@ -147,15 +165,15 @@ static bool contains(const ProtocolEntries &l, const QString &needle)
const ProtocolEntries &mappingProtocols()
{
static const ProtocolEntries result = {
- {QLatin1String("__mlen__"),
- QLatin1String("PyObject *self"),
- QLatin1String("Py_ssize_t")},
- {QLatin1String("__mgetitem__"),
- QLatin1String("PyObject *self, PyObject *_key"),
- QLatin1String("PyObject*")},
- {QLatin1String("__msetitem__"),
- QLatin1String("PyObject *self, PyObject *_key, PyObject *_value"),
- intT()}};
+ {u"__mlen__"_s,
+ u"PyObject *self"_s,
+ u"Py_ssize_t"_s},
+ {u"__mgetitem__"_s,
+ u"PyObject *self, PyObject *_key"_s,
+ u"PyObject*"_s},
+ {u"__msetitem__"_s,
+ u"PyObject *self, PyObject *_key, PyObject *_value"_s,
+ intT}};
return result;
}
@@ -164,153 +182,71 @@ const ProtocolEntries &mappingProtocols()
const ProtocolEntries &sequenceProtocols()
{
static const ProtocolEntries result = {
- {QLatin1String("__len__"),
- QLatin1String("PyObject *self"),
- QLatin1String("Py_ssize_t")},
- {QLatin1String("__getitem__"),
- QLatin1String("PyObject *self, Py_ssize_t _i"),
- QLatin1String("PyObject*")},
- {QLatin1String("__setitem__"),
- QLatin1String("PyObject *self, Py_ssize_t _i, PyObject *_value"),
- intT()},
- {QLatin1String("__getslice__"),
- QLatin1String("PyObject *self, Py_ssize_t _i1, Py_ssize_t _i2"),
- QLatin1String("PyObject*")},
- {QLatin1String("__setslice__"),
- QLatin1String("PyObject *self, Py_ssize_t _i1, Py_ssize_t _i2, PyObject *_value"),
- intT()},
- {QLatin1String("__contains__"),
- QLatin1String("PyObject *self, PyObject *_value"),
- intT()},
- {QLatin1String("__concat__"),
- QLatin1String("PyObject *self, PyObject *_other"),
- QLatin1String("PyObject*")}
+ {u"__len__"_s,
+ u"PyObject *self"_s,
+ u"Py_ssize_t"_s},
+ {u"__getitem__"_s,
+ u"PyObject *self, Py_ssize_t _i"_s,
+ u"PyObject*"_s},
+ {u"__setitem__"_s,
+ u"PyObject *self, Py_ssize_t _i, PyObject *_value"_s,
+ intT},
+ {u"__getslice__"_s,
+ u"PyObject *self, Py_ssize_t _i1, Py_ssize_t _i2"_s,
+ u"PyObject*"_s},
+ {u"__setslice__"_s,
+ u"PyObject *self, Py_ssize_t _i1, Py_ssize_t _i2, PyObject *_value"_s,
+ intT},
+ {u"__contains__"_s,
+ u"PyObject *self, PyObject *_value"_s,
+ intT},
+ {u"__concat__"_s,
+ u"PyObject *self, PyObject *_other"_s,
+ u"PyObject*"_s}
};
return result;
}
-CppGenerator::CppGenerator() = default;
-
-QString CppGenerator::fileNameSuffix() const
-{
- return QLatin1String("_wrapper.cpp");
-}
-
-QString CppGenerator::fileNameForContext(const 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();
-}
-
-static bool isInplaceAdd(const AbstractMetaFunctionCPtr &func)
-{
- return func->name() == u"operator+=";
-}
-
-static bool isIncrementOperator(const AbstractMetaFunctionCPtr &func)
-{
- return func->functionType() == AbstractMetaFunction::IncrementOperator;
-}
-
-static bool isDecrementOperator(const AbstractMetaFunctionCPtr &func)
+// Return name of function to create PyObject wrapping a container
+static QString opaqueContainerCreationFunc(const AbstractMetaType &type)
{
- return func->functionType() == AbstractMetaFunction::DecrementOperator;
-}
-
-// Filter predicate for operator functions
-static bool skipOperatorFunc(const AbstractMetaFunctionCPtr &func)
-{
- if (func->isModifiedRemoved() || func->usesRValueReferences())
- return true;
- const auto &name = func->name();
- return name == u"operator[]" || name == u"operator->" || name == u"operator!";
-}
-
-QList<AbstractMetaFunctionCList>
- CppGenerator::filterGroupedOperatorFunctions(const AbstractMetaClass *metaClass,
- OperatorQueryOptions query)
-{
- // ( func_name, num_args ) => func_list
- QMap<QPair<QString, int>, AbstractMetaFunctionCList> results;
-
- auto funcs = metaClass->operatorOverloads(query);
- auto end = std::remove_if(funcs.begin(), funcs.end(), skipOperatorFunc);
- funcs.erase(end, funcs.end());
-
- // If we have operator+=, we remove the operator++/-- which would
- // otherwise be used for emulating __iadd__, __isub__.
- if (std::any_of(funcs.cbegin(), funcs.cend(), isInplaceAdd)) {
- end = std::remove_if(funcs.begin(), funcs.end(),
- [] (const AbstractMetaFunctionCPtr &func) {
- return func->isIncDecrementOperator();
- });
- funcs.erase(end, funcs.end());
- } else {
- // If both prefix/postfix ++/-- are present, remove one
- if (std::count_if(funcs.begin(), funcs.end(), isIncrementOperator) > 1)
- funcs.erase(std::find_if(funcs.begin(), funcs.end(), isIncrementOperator));
- if (std::count_if(funcs.begin(), funcs.end(), isDecrementOperator) > 1)
- funcs.erase(std::find_if(funcs.begin(), funcs.end(), isDecrementOperator));
- }
-
- for (const auto &func : funcs) {
- int args;
- if (func->isComparisonOperator()) {
- args = -1;
- } else {
- args = func->arguments().size();
- }
- QPair<QString, int > op(func->name(), args);
- results[op].append(func);
- }
- QList<AbstractMetaFunctionCList> result;
- result.reserve(results.size());
- for (auto it = results.cbegin(), end = results.cend(); it != end; ++it)
- result.append(it.value());
+ const auto containerTypeEntry =
+ std::static_pointer_cast<const ContainerTypeEntry>(type.typeEntry());
+ const auto instantiationTypeEntry =
+ type.instantiations().constFirst().typeEntry();
+ QString result = u"create"_s;
+ if (type.isConstant())
+ result += u"Const"_s;
+ result += containerTypeEntry->opaqueContainerName(type.instantiationCppSignatures());
return result;
}
-AbstractMetaFunctionCPtr CppGenerator::boolCast(const AbstractMetaClass *metaClass) const
+// Write declaration of the function to create PyObject wrapping a container
+static void writeOpaqueContainerCreationFuncDecl(TextStream &s, const QString &name,
+ AbstractMetaType type)
{
- if (!useIsNullAsNbNonZero())
- return {};
- // TODO: This could be configurable someday
- const auto func = metaClass->findFunction(QLatin1String("isNull"));
- if (func.isNull() || func->isVoid() || !func->type().typeEntry()->isPrimitive()
- || !func->isPublic()) {
- return {};
- }
- auto pte = static_cast<const PrimitiveTypeEntry *>(func->type().typeEntry());
- while (pte->referencedTypeEntry())
- pte = pte->referencedTypeEntry();
- return func->isConstant() && pte->name() == QLatin1String("bool")
- && func->arguments().isEmpty() ? func : AbstractMetaFunctionCPtr{};
+ type.setReferenceType(NoReference);
+ // Maintain const
+ s << "PyObject *" << name << '(' << type.cppSignature() << "*);\n";
}
-std::optional<AbstractMetaType>
- CppGenerator::findSmartPointerInstantiation(const TypeEntry *entry) const
+CppGenerator::CppGenerator() = default;
+
+QString CppGenerator::fileNameForContext(const GeneratorContext &context) const
{
- for (const auto &i : instantiatedSmartPointers()) {
- if (i.instantiations().at(0).typeEntry() == entry)
- return i;
- }
- return {};
+ return fileNameForContextHelper(context, u"_wrapper.cpp"_s);
}
void CppGenerator::clearTpFuncs()
{
+ // Functions that should not be registered under a name in PyMethodDef,
+ // but under a special constant under slots.
m_tpFuncs = {
- {QLatin1String("__str__"), {}}, {QLatin1String("__str__"), {}},
- {reprFunction(), {}}, {QLatin1String("__iter__"), {}},
- {QLatin1String("__next__"), {}}
+ {u"__str__"_s, {}}, {u"__str__"_s, {}},
+ {REPR_FUNCTION, {}}, {u"__iter__"_s, {}},
+ {u"__next__"_s, {}}
};
+ m_nbFuncs = { {u"__abs__"_s, {}}, {u"__pow__"_s, {} }};
}
// Prevent ELF symbol qt_version_tag from being generated into the source
@@ -318,13 +254,13 @@ static const char includeQDebug[] =
"#ifndef QT_NO_VERSION_TAGGING\n"
"# define QT_NO_VERSION_TAGGING\n"
"#endif\n"
-"#include <QDebug>\n";
+"#include <QtCore/QDebug>\n";
-static QString chopType(QString s)
+QString CppGenerator::chopType(QString s)
{
- if (s.endsWith(QLatin1String("_Type")))
+ if (s.endsWith(u"_Type"))
s.chop(5);
- else if (s.endsWith(QLatin1String("_TypeF()")))
+ else if (s.endsWith(u"_TypeF()"))
s.chop(8);
return s;
}
@@ -332,133 +268,314 @@ static QString chopType(QString s)
static bool isStdSetterName(QString setterName, QString propertyName)
{
return setterName.size() == propertyName.size() + 3
- && setterName.startsWith(QLatin1String("set"))
+ && setterName.startsWith(u"set")
&& setterName.endsWith(QStringView{propertyName}.right(propertyName.size() - 1))
&& setterName.at(3) == propertyName.at(0).toUpper();
}
static QString buildPropertyString(const QPropertySpec &spec)
{
- QString text;
- text += QLatin1Char('"');
- text += spec.name();
- text += QLatin1Char(':');
+ QString text = u'"' + spec.name() + u':';
if (spec.read() != spec.name())
text += spec.read();
if (!spec.write().isEmpty()) {
- text += QLatin1Char(':');
+ text += u':';
if (!isStdSetterName(spec.write(), spec.name()))
text += spec.write();
}
- text += QLatin1Char('"');
+ text += u'"';
return text;
}
+static QString _plainName(const QString &s)
+{
+ auto cutPos = s.lastIndexOf(u"::"_s);
+ return cutPos < 0 ? s : s.right(s.length() - (cutPos + 2));
+}
+
+/**********************************************************************
+ *
+ * Decision whether to use an IntEnum/IntFlag
+ * ------------------------------------------
+ *
+ * Unfortunately, all attempts to drive this decision automagically
+ * did not work out. We therefore compile a list in with known
+ * IntEnum and IntFlag.
+ */
+
+/*
+ * This function is now unused and replaced by TypeSystem::PythonEnumType
+ */
+#if 0
+static QSet<QString> useIntSet()
+{
+ static const QSet<QString> result{
+ /* IntEnum */ u"PySide6.QtCore.QDataStream.Version"_s,
+ /* IntEnum */ u"PySide6.QtCore.QEvent.Type"_s,
+ /* IntEnum */ u"PySide6.QtCore.QLocale.FloatingPointPrecisionOption"_s,
+ /* IntFlag */ u"PySide6.QtCore.QLocale.LanguageCodeType"_s,
+ /* IntFlag */ u"PySide6.QtCore.QUrl.ComponentFormattingOption"_s,
+ // note: "QUrl::UrlFormattingOption" is set as IntFlag without flags
+ /* IntFlag */ u"PySide6.QtCore.QUrl.UrlFormattingOption"_s,
+ /* IntFlag */ u"PySide6.QtCore.Qt.AlignmentFlag"_s,
+ /* IntFlag */ u"PySide6.QtCore.Qt.FocusPolicy"_s,
+ /* IntEnum */ u"PySide6.QtCore.Qt.GestureType"_s,
+ /* IntEnum */ u"PySide6.QtCore.Qt.ItemDataRole"_s,
+ /* IntEnum */ u"PySide6.QtCore.Qt.Key"_s,
+ /* Flag */ u"PySide6.QtCore.Qt.Modifier"_s,
+ // note: "Qt::TextFlag" is set as IntFlag without flags
+ /* IntFlag */ u"PySide6.QtCore.Qt.TextFlag"_s,
+ /* IntFlag */ u"PySide6.QtCore.Qt.WindowType"_s,
+ // This is found in QtWidgets but should be in QtGui.
+ /* IntEnum */ u"PySide6.QtGui.QFileSystemModel.Roles"_s,
+ /* IntEnum */ u"PySide6.QtGui.QFont.Stretch"_s,
+ /* IntEnum */ u"PySide6.QtGui.QFont.Weight"_s,
+ /* IntEnum */ u"PySide6.QtGui.QTextDocument.ResourceType"_s,
+ /* IntEnum */ u"PySide6.QtGui.QTextFormat.FormatType"_s,
+ /* IntEnum */ u"PySide6.QtGui.QTextFormat.ObjectTypes"_s,
+ /* IntEnum */ u"PySide6.QtGui.QTextFormat.Property"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QDialog.DialogCode"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QFrame.Shadow"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QFrame.Shape"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QListWidgetItem.ItemType"_s,
+ /* IntFlag */ u"PySide6.QtWidgets.QMessageBox.StandardButton"_s,
+ // note: "QSizePolicy::PolicyFlag" is set as IntFlag without flags
+ /* IntFlag */ u"PySide6.QtWidgets.QSizePolicy.PolicyFlag"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.ComplexControl"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.ContentsType"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.ControlElement"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.PixelMetric"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.PrimitiveElement"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.StandardPixmap"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.StyleHint"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QStyle.SubElement"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QTableWidgetItem.ItemType"_s,
+ /* IntEnum */ u"PySide6.QtWidgets.QTreeWidgetItem.ItemType"_s,
+ /* IntEnum */ u"PySide6.QtCharts.QBoxSet.ValuePositions"_s,
+ /* IntEnum */ u"PySide6.QtMultimedia.QMediaPlayer.Loops"_s,
+ /* IntEnum */ u"PySide6.QtQuick.QSGGeometry.DrawingMode"_s,
+ /* IntEnum */ u"PySide6.QtWebEngineCore.QWebEngineScript.ScriptWorldId"_s,
+ // Added because it should really be used as number
+ /* IntEnum */ u"PySide6.QtCore.QMetaType.Type"_s,
+ /* IntEnum */ u"PySide6.QtSerialPort.QSerialPort.BaudRate"_s,
+ };
+ return result;
+}
+#endif
+
+static bool _shouldInheritInt(const AbstractMetaEnum &cppEnum)
+{
+ return !cppEnum.fullName().startsWith(u"PySide6."_s);
+}
+
+static QString BuildEnumFlagInfo(const AbstractMetaEnum &cppEnum)
+{
+ auto enumType = cppEnum.typeEntry();
+ QString result = _plainName(enumType->name());
+ auto flags = enumType->flags();
+ auto decision = enumType->pythonEnumType();
+ bool _int = _shouldInheritInt(cppEnum);
+ bool _flag = bool(flags);
+
+ if (decision != TypeSystem::PythonEnumType::Unspecified) {
+ _int = decision == TypeSystem::PythonEnumType::IntEnum ||
+ decision == TypeSystem::PythonEnumType::IntFlag;
+ _flag = decision == TypeSystem::PythonEnumType::Flag ||
+ decision == TypeSystem::PythonEnumType::IntFlag;
+ }
+ result += _flag ? (_int ? u":IntFlag"_s : u":Flag"_s)
+ : (_int ? u":IntEnum"_s : u":Enum"_s);
+ if (flags)
+ result += u':' + _plainName(flags->flagsName());
+ return u'"' + result + u'"';
+}
+
static void writePyGetSetDefEntry(TextStream &s, const QString &name,
const QString &getFunc, const QString &setFunc)
{
- s << "{const_cast<char *>(\"" << name << "\"), " << getFunc << ", "
- << (setFunc.isEmpty() ? QLatin1String(NULL_PTR) : setFunc) << "},\n";
+ s << "{const_cast<char *>(\"" << mangleName(name) << "\"), " << getFunc << ", "
+ << (setFunc.isEmpty() ? NULL_PTR : setFunc) << ", nullptr, nullptr},\n";
}
-/*!
- Function used to write the class generated binding code on the buffer
- \param s the output buffer
- \param metaClass the pointer to metaclass information
-*/
-void CppGenerator::generateClass(TextStream &s, const GeneratorContext &classContext)
+static bool generateRichComparison(const GeneratorContext &c)
{
- s.setLanguage(TextStream::Language::Cpp);
- const AbstractMetaClass *metaClass = classContext.metaClass();
+ const auto metaClass = c.metaClass();
+ if (c.forSmartPointer()) {
+ auto te = std::static_pointer_cast<const SmartPointerTypeEntry>(metaClass->typeEntry());
+ return te->smartPointerType() == TypeSystem::SmartPointerType::Shared;
+ }
+
+ return !metaClass->isNamespace() && metaClass->hasComparisonOperatorOverload();
+}
+
+void CppGenerator::generateIncludes(TextStream &s, const GeneratorContext &classContext,
+ const IncludeGroupList &includes,
+ const AbstractMetaClassCList &innerClasses) const
+{
+ const auto metaClass = classContext.metaClass();
// write license comment
s << licenseComment() << '\n';
- if (!avoidProtectedHack() && !metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) {
- s << "//workaround to access protected functions\n";
- s << "#define protected public\n\n";
- }
+ const bool normalClass = !classContext.forSmartPointer();
+ // Normally only required for classes for which we want to generate protected API,
+ // but it needs to be generated into all files to ensure ODR for Unity builds.
+ if (!avoidProtectedHack())
+ s << HeaderGenerator::protectedHackDefine;
+ QByteArrayList cppIncludes{"typeinfo", "iterator", // for containers
+ "cctype", "cstring"};
// headers
s << "// default includes\n";
s << "#include <shiboken.h>\n";
- if (usePySideExtensions()) {
+ if (wrapperDiagnostics()) {
+ s << "#include <helper.h>\n";
+ cppIncludes << "iostream";
+ }
+
+ if (normalClass && usePySideExtensions()) {
s << includeQDebug;
- s << "#include <pysidesignal.h>\n"
- << "#include <pysideproperty.h>\n"
- << "#include <pyside.h>\n"
- << "#include <pysideqenum.h>\n"
+ if (metaClass->hasToStringCapability())
+ s << "#include <QtCore/QBuffer>\n";
+ if (isQObject(metaClass)) {
+ s << "#include <pysideqobject.h>\n"
+ << "#include <pysidesignal.h>\n"
+ << "#include <pysideproperty.h>\n"
+ << "#include <signalmanager.h>\n"
+ << "#include <pysidemetafunction.h>\n";
+ }
+ s << "#include <pysideqenum.h>\n"
+ << "#include <pysideqmetatype.h>\n"
+ << "#include <pysideutils.h>\n"
<< "#include <feature_select.h>\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 << "#include <iterator>\n"; // For containers
-
- if (wrapperDiagnostics())
- s << "#include <helper.h>\n#include <iostream>\n";
+ if (normalClass && getMultipleInheritingClass(metaClass) != nullptr)
+ cppIncludes << "algorithm" << "set";
+ if (normalClass && metaClass->generateExceptionHandling())
+ cppIncludes << "exception";
s << "\n// module include\n" << "#include \"" << getModuleHeaderFileName() << "\"\n";
if (hasPrivateClasses())
s << "#include \"" << getPrivateModuleHeaderFileName() << "\"\n";
- QString headerfile = fileNameForContext(classContext);
- headerfile.replace(QLatin1String(".cpp"), QLatin1String(".h"));
- s << "\n// main header\n" << "#include \"" << headerfile << "\"\n";
-
- s << '\n' << "// inner classes\n";
- const AbstractMetaClassList &innerClasses = metaClass->innerClasses();
- for (AbstractMetaClass *innerClass : innerClasses) {
- GeneratorContext innerClassContext = contextForClass(innerClass);
- if (shouldGenerate(innerClass) && !innerClass->typeEntry()->isSmartPointer()) {
- QString headerfile = fileNameForContext(innerClassContext);
- headerfile.replace(QLatin1String(".cpp"), QLatin1String(".h"));
- s << "#include \"" << headerfile << "\"\n";
+ s << "\n// main header\n" << "#include \""
+ << HeaderGenerator::headerFileNameForContext(classContext) << "\"\n";
+
+ if (!innerClasses.isEmpty()) {
+ s << "\n// inner classes\n";
+ for (const auto &innerClass : innerClasses) {
+ GeneratorContext innerClassContext = contextForClass(innerClass);
+ s << "#include \""
+ << HeaderGenerator::headerFileNameForContext(innerClassContext) << "\"\n";
}
}
- AbstractMetaEnumList classEnums = metaClass->enums();
- metaClass->getEnumsFromInvisibleNamespacesToBeGenerated(&classEnums);
+ if (avoidProtectedHack())
+ s << baseWrapperIncludes(classContext);
- //Extra includes
- QList<Include> includes;
- if (!classContext.useWrapper())
- includes += metaClass->typeEntry()->extraIncludes();
- for (const AbstractMetaEnum &cppEnum : qAsConst(classEnums))
- includes.append(cppEnum.typeEntry()->extraIncludes());
- if (!includes.isEmpty()) {
- s << "\n// Extra includes\n";
- std::sort(includes.begin(), includes.end());
- for (const Include &inc : qAsConst(includes))
- s << inc.toString() << '\n';
- s << '\n';
+ for (const auto &g : includes)
+ s << g;
+
+ // C++ includes
+ std::sort(cppIncludes.begin(), cppIncludes.end());
+ s << '\n';
+ for (const auto &i : std::as_const(cppIncludes))
+ s << "#include <" << i << ">\n";
+}
+
+// Write methods definition
+void CppGenerator::writePyMethodDefs(TextStream &s, const QString &className,
+ const QString &methodsDefinitions)
+{
+ s << "static PyMethodDef " << className << "_methods[] = {\n" << indent
+ << methodsDefinitions << METHOD_DEF_SENTINEL << outdent << "};\n\n";
+}
+
+void CppGenerator::writeModuleCodeSnips(TextStream &s, const CodeSnipList &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language) const
+{
+ if (!codeSnips.isEmpty()) {
+ try {
+ writeCodeSnips(s, codeSnips, position, language);
+ } catch (const std::exception &e) {
+ throw Exception(msgSnippetError("module source of "_L1 + moduleName(), e.what()));
+ }
+ }
+}
+
+bool CppGenerator::hasHashFunction(const AbstractMetaClassCPtr &c)
+{
+ return !c->typeEntry()->hashFunction().isEmpty()
+ || c->hasHashFunction();
+}
+
+static bool needsTypeDiscoveryFunction(const AbstractMetaClassCPtr &c)
+{
+ return c->baseClass() != nullptr
+ && (c->isPolymorphic() || !c->typeEntry()->polymorphicIdValue().isEmpty());
+}
+
+static void writeAddedTypeSignatures(TextStream &s, const ComplexTypeEntryCPtr &te)
+{
+ for (const auto &e : te->addedPyMethodDefEntrys()) {
+ if (auto count = e.signatures.size()) {
+ for (qsizetype i = 0; i < count; ++i) {
+ if (count > 1)
+ s << i << ':';
+ s << e.signatures.at(i) << '\n';
+ }
+ }
}
+}
- s << "\n#include <cctype>\n#include <cstring>\n";
+/// Function used to write the class generated binding code on the buffer
+/// \param s the output buffer
+/// \param classContext the pointer to metaclass information
+void CppGenerator::generateClass(TextStream &s, const GeneratorContext &classContext)
+{
+ if (classContext.forSmartPointer()) {
+ generateSmartPointerClass(s, classContext);
+ return;
+ }
- if (metaClass->typeEntry()->typeFlags() & ComplexTypeEntry::Deprecated)
+ s.setLanguage(TextStream::Language::Cpp);
+ AbstractMetaClassCPtr metaClass = classContext.metaClass();
+ const auto typeEntry = metaClass->typeEntry();
+
+ auto innerClasses = metaClass->innerClasses();
+ for (auto it = innerClasses.begin(); it != innerClasses.end(); ) {
+ auto innerTypeEntry = (*it)->typeEntry();
+ if (shouldGenerate(innerTypeEntry) && !innerTypeEntry->isSmartPointer())
+ ++it;
+ else
+ it = innerClasses.erase(it);
+ }
+
+ AbstractMetaEnumList classEnums = metaClass->enums();
+ metaClass->getEnumsFromInvisibleNamespacesToBeGenerated(&classEnums);
+
+ IncludeGroupList includeGroups;
+ if (!classContext.useWrapper() || !avoidProtectedHack())
+ includeGroups.append(classIncludes(metaClass));
+ generateIncludes(s, classContext, includeGroups, innerClasses);
+
+ if (typeEntry->typeFlags().testFlag(ComplexTypeEntry::Deprecated))
s << "#Deprecated\n";
// Use class base namespace
{
- const AbstractMetaClass *context = metaClass->enclosingClass();
+ AbstractMetaClassCPtr context = metaClass->enclosingClass();
while (context) {
if (context->isNamespace() && !context->enclosingClass()
- && static_cast<const NamespaceTypeEntry *>(context->typeEntry())->generateUsing()) {
+ && std::static_pointer_cast<const NamespaceTypeEntry>(context->typeEntry())->generateUsing()) {
s << "\nusing namespace " << context->qualifiedCppName() << ";\n";
break;
}
@@ -466,177 +583,109 @@ void CppGenerator::generateClass(TextStream &s, const GeneratorContext &classCon
}
}
- s << "\n\n" << typeNameFunc << '\n';
-
- // 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 << "\";";
- }
+ s << '\n';
// class inject-code native/beginning
- if (!metaClass->typeEntry()->codeSnips().isEmpty()) {
- writeClassCodeSnips(s, metaClass->typeEntry()->codeSnips(),
+ if (!typeEntry->codeSnips().isEmpty()) {
+ writeClassCodeSnips(s, typeEntry->codeSnips(),
TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode,
classContext);
s << '\n';
}
// python conversion rules
- if (metaClass->typeEntry()->hasTargetConversionRule()) {
- s << "// Python Conversion\n";
- s << metaClass->typeEntry()->targetConversionRule() << '\n';
+ if (typeEntry->isValue()) {
+ auto vte = std::static_pointer_cast<const ValueTypeEntry>(typeEntry);
+ if (vte->hasTargetConversionRule()) {
+ s << "// Python Conversion\n";
+ s << vte->targetConversionRule() << '\n';
+ }
}
if (classContext.useWrapper()) {
s << "// Native ---------------------------------------------------------\n\n";
if (avoidProtectedHack() && usePySideExtensions()) {
- s << "void " << classContext.wrapperName() << "::pysideInitQtMetaTypes()\n{\n";
- Indentation indent(s);
+ s << "void " << classContext.wrapperName() << "::pysideInitQtMetaTypes()\n{\n"
+ << indent;
writeInitQtMetaTypeFunctionBody(s, classContext);
- s << "}\n\n";
+ s << outdent << "}\n\n";
}
- const auto &funcs = filterFunctions(metaClass);
int maxOverrides = 0;
writeCacheResetNative(s, classContext);
- for (const auto &func : funcs) {
- const bool notAbstract = !func->isAbstract();
- if ((func->isPrivate() && notAbstract && !func->isVisibilityModifiedToPrivate())
- || (func->isModifiedRemoved() && notAbstract))
- continue;
- if (func->functionType() == AbstractMetaFunction::ConstructorFunction && !func->isUserAdded())
+ for (const auto &func : metaClass->functions()) {
+ const auto generation = functionGeneration(func);
+ if (generation.testFlag(FunctionGenerationFlag::WrapperConstructor))
writeConstructorNative(s, classContext, func);
- else if (shouldWriteVirtualMethodNative(func))
+ else if (generation.testFlag(FunctionGenerationFlag::VirtualMethod))
writeVirtualMethodNative(s, func, maxOverrides++);
}
- if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor()) {
- if (usePySideExtensions() && metaClass->isQObject())
- writeMetaObjectMethod(s, classContext);
+ if (shouldGenerateMetaObjectFunctions(metaClass))
+ writeMetaObjectMethod(s, classContext);
+ if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor())
writeDestructorNative(s, classContext);
- }
}
+ for (const auto &f : metaClass->userAddedPythonOverrides())
+ writeUserAddedPythonOverride(s, f);
+
StringStream smd(TextStream::Language::Cpp);
StringStream md(TextStream::Language::Cpp);
StringStream signatureStream(TextStream::Language::Cpp);
- s << "\n// Target ---------------------------------------------------------\n\n"
- << "extern \"C\" {\n";
+ s << openTargetExternC;
+
const auto &functionGroups = getFunctionGroups(metaClass);
for (auto it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
- AbstractMetaFunctionCList overloads;
- QSet<QString> seenSignatures;
- bool staticEncountered = false;
- for (const auto &func : it.value()) {
- if (!func->isAssignmentOperator()
- && !func->usesRValueReferences()
- && !func->isConversionOperator()
- && !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 (qsizetype i = overloads.size() - 1; i >= 0; --i) {
- if (overloads.at(i)->isStatic())
- overloads.removeAt(i);
- }
- }
-
+ if (contains(sequenceProtocols(), it.key()) || contains(mappingProtocols(), it.key()))
+ continue;
+ const AbstractMetaFunctionCList &overloads = it.value();
if (overloads.isEmpty())
continue;
const auto rfunc = overloads.constFirst();
- if (contains(sequenceProtocols(), rfunc->name())
- || contains(mappingProtocols(), rfunc->name())) {
- continue;
- }
+ OverloadData overloadData(overloads, api());
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);
+ writeConstructorWrapper(s, overloadData, classContext);
+ writeSignatureInfo(signatureStream, overloadData);
}
// call operators
- else if (rfunc->name() == QLatin1String("operator()")) {
- writeMethodWrapper(s, overloads, classContext);
- writeSignatureInfo(signatureStream, overloads);
+ else if (rfunc->name() == u"operator()") {
+ writeMethodWrapper(s, overloadData, classContext);
+ writeSignatureInfo(signatureStream, overloadData);
}
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.
- auto pointerToInnerType =
- buildAbstractMetaTypeFromString(pointerToInnerTypeName);
- Q_ASSERT(pointerToInnerType.has_value());
- auto mutableRfunc = overloads.constFirst();
- qSharedPointerConstCast<AbstractMetaFunction>(mutableRfunc)->setType(pointerToInnerType.value());
- } 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);
+ writeMethodWrapper(s, overloadData, classContext);
+ writeSignatureInfo(signatureStream, overloadData);
// For a mixture of static and member function overloads,
// a separate PyMethodDef entry is written which is referenced
// in the PyMethodDef list and later in getattro() for handling
// the non-static case.
+ const auto defEntries = methodDefinitionEntries(overloadData);
if (OverloadData::hasStaticAndInstanceFunctions(overloads)) {
QString methDefName = cpythonMethodDefinitionName(rfunc);
- smd << "static PyMethodDef " << methDefName << " = " << indent;
- writeMethodDefinitionEntries(smd, overloads, 1);
- smd << outdent << ";\n\n";
+ smd << "static PyMethodDef " << methDefName << " = " << indent
+ << defEntries.constFirst() << outdent << ";\n\n";
}
- writeMethodDefinition(md, overloads);
+ const auto &fname = rfunc->name();
+ if (!m_tpFuncs.contains(fname) && !m_nbFuncs.contains(fname))
+ md << defEntries;
}
}
+ for (const auto &pyMethodDef : typeEntry->addedPyMethodDefEntrys())
+ md << pyMethodDef << ",\n";
+
+ if (typeEntry->isValue())
+ writeCopyFunction(s, md, signatureStream, classContext);
+
const QString methodsDefinitions = md.toString();
const QString singleMethodDefinitions = smd.toString();
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;
@@ -652,74 +701,44 @@ void CppGenerator::generateClass(TextStream &s, const GeneratorContext &classCon
s << '\n';
s << "static const char *" << className << "_PropertyStrings[] = {\n" << indent;
- for (const auto &entry : qAsConst(sorter))
+ for (const auto &entry : std::as_const(sorter))
+ s << entry << ",\n";
+ s << NULL_PTR << " // Sentinel\n"
+ << outdent << "};\n\n";
+
+ }
+ // PYSIDE-1735: Write an EnumFlagInfo structure
+ QStringList sorter;
+ for (const auto &entry : std::as_const(classEnums))
+ sorter.append(BuildEnumFlagInfo(entry));
+ sorter.sort();
+ if (!sorter.empty()) {
+ s << "static const char *" << className << "_EnumFlagInfo[] = {\n" << indent;
+ for (const auto &entry : std::as_const(sorter))
s << entry << ",\n";
s << NULL_PTR << " // Sentinel\n"
<< outdent << "};\n\n";
}
// Write methods definition
- s << "static PyMethodDef " << className << "_methods[] = {\n" << indent
- << methodsDefinitions << '\n';
- if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) {
- s << "{\"__copy__\", reinterpret_cast<PyCFunction>(" << className << "___copy__)"
- << ", METH_NOARGS},\n";
- }
- s << '{' << NULL_PTR << ", " << NULL_PTR << "} // Sentinel\n" << outdent
- << "};\n\n";
+ writePyMethodDefs(s, className, methodsDefinitions);
// Write tp_s/getattro function
const AttroCheck attroCheck = checkAttroFunctionNeeds(metaClass);
- if (attroCheck.testFlag(AttroCheckFlag::GetattroSmartPointer)) {
- writeSmartPointerGetattroFunction(s, classContext);
- writeSmartPointerSetattroFunction(s, classContext);
- } else {
- if ((attroCheck & AttroCheckFlag::GetattroMask) != 0)
- writeGetattroFunction(s, attroCheck, classContext);
- if ((attroCheck & AttroCheckFlag::SetattroMask) != 0)
- writeSetattroFunction(s, attroCheck, classContext);
- }
-
- const auto f = boolCast(metaClass);
- if (!f.isNull()) {
- ErrorCode errorCode(-1);
- s << "static int " << cpythonBaseName(metaClass) << "___nb_bool(PyObject *self)\n"
- << "{\n" << indent;
- writeCppSelfDefinition(s, classContext);
- if (f->allowThread()) {
- s << "int result;\n"
- << BEGIN_ALLOW_THREADS << '\n'
- << "result = !" << CPP_SELF_VAR << "->isNull();\n"
- << END_ALLOW_THREADS << '\n'
- << "return result;\n";
- } else {
- s << "return !" << CPP_SELF_VAR << "->isNull();\n";
- }
- s << outdent << "}\n\n";
- }
+ if ((attroCheck & AttroCheckFlag::GetattroMask) != 0)
+ writeGetattroFunction(s, attroCheck, classContext);
+ if ((attroCheck & AttroCheckFlag::SetattroMask) != 0)
+ writeSetattroFunction(s, attroCheck, classContext);
- if (supportsNumberProtocol(metaClass) && !metaClass->typeEntry()->isSmartPointer()) {
- const QList<AbstractMetaFunctionCList> opOverloads = filterGroupedOperatorFunctions(
- metaClass,
- OperatorQueryOption::ArithmeticOp
- | OperatorQueryOption::IncDecrementOp
- | OperatorQueryOption::LogicalOp
- | OperatorQueryOption::BitwiseOp);
-
- for (const AbstractMetaFunctionCList &allOverloads : opOverloads) {
- AbstractMetaFunctionCList overloads;
- for (const auto &func : allOverloads) {
- if (!func->isModifiedRemoved()
- && !func->isPrivate()
- && (func->ownerClass() == func->implementingClass() || func->isAbstract()))
- overloads.append(func);
- }
-
- if (overloads.isEmpty())
- continue;
+ if (const auto f = boolCast(metaClass) ; f.has_value())
+ writeNbBoolFunction(classContext, f.value(), s);
- writeMethodWrapper(s, overloads, classContext);
- writeSignatureInfo(signatureStream, overloads);
+ if (supportsNumberProtocol(metaClass)) {
+ const auto numberProtocolOps = numberProtocolOperators(metaClass);
+ for (const auto &overloads : numberProtocolOps) {
+ OverloadData overloadData(overloads, api());
+ writeMethodWrapper(s, overloadData, classContext);
+ writeSignatureInfo(signatureStream, overloadData);
}
}
@@ -731,12 +750,12 @@ void CppGenerator::generateClass(TextStream &s, const GeneratorContext &classCon
writeMappingMethods(s, metaClass, classContext);
}
- if (!metaClass->isNamespace() && metaClass->hasComparisonOperatorOverload()) {
+ if (generateRichComparison(classContext)) {
s << "// Rich comparison\n";
writeRichCompareFunction(s, classContext);
}
- if (shouldGenerateGetSetList(metaClass) && !classContext.forSmartPointer()) {
+ if (shouldGenerateGetSetList(metaClass)) {
const AbstractMetaFieldList &fields = metaClass->fields();
for (const AbstractMetaField &metaField : fields) {
if (metaField.canGenerateGetter())
@@ -779,13 +798,13 @@ void CppGenerator::generateClass(TextStream &s, const GeneratorContext &classCon
cpythonGetterFunctionName(property, metaClass), setter);
}
}
- s << '{' << NULL_PTR << "} // Sentinel\n"
+ s << "{nullptr, nullptr, nullptr, nullptr, nullptr} // Sentinel\n"
<< outdent << "};\n\n";
}
- s << "} // extern \"C\"\n\n";
+ s << closeExternC;
- if (!metaClass->typeEntry()->hashFunction().isEmpty())
+ if (hasHashFunction(metaClass))
writeHashFunction(s, classContext);
// Write tp_traverse and tp_clear functions.
@@ -795,27 +814,38 @@ void CppGenerator::generateClass(TextStream &s, const GeneratorContext &classCon
writeClassDefinition(s, metaClass, classContext);
s << '\n';
- if (metaClass->isPolymorphic() && metaClass->baseClass())
+ if (needsTypeDiscoveryFunction(metaClass)) {
writeTypeDiscoveryFunction(s, metaClass);
-
- writeFlagsNumberMethodsDefinitions(s, classEnums);
- s << '\n';
+ s << '\n';
+ }
writeConverterFunctions(s, metaClass, classContext);
+ writeAddedTypeSignatures(signatureStream, typeEntry);
writeClassRegister(s, metaClass, classContext, signatureStream);
if (metaClass->hasStaticFields())
writeStaticFieldInitialization(s, metaClass);
// class inject-code native/end
- if (!metaClass->typeEntry()->codeSnips().isEmpty()) {
- writeClassCodeSnips(s, metaClass->typeEntry()->codeSnips(),
+ if (!typeEntry->codeSnips().isEmpty()) {
+ writeClassCodeSnips(s, typeEntry->codeSnips(),
TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode,
classContext);
s << '\n';
}
}
+void CppGenerator::writeMethodWrapper(TextStream &s, TextStream &definitionStream,
+ TextStream &signatureStream,
+ const AbstractMetaFunctionCList &overloads,
+ const GeneratorContext &classContext) const
+{
+ OverloadData overloadData(overloads, api());
+ writeMethodWrapper(s, overloadData, classContext);
+ writeSignatureInfo(signatureStream, overloadData);
+ definitionStream << methodDefinitionEntries(overloadData);
+}
+
void CppGenerator::writeCacheResetNative(TextStream &s, const GeneratorContext &classContext)
{
s << "void " << classContext.wrapperName()
@@ -827,7 +857,7 @@ void CppGenerator::writeCacheResetNative(TextStream &s, const GeneratorContext &
void CppGenerator::writeConstructorNative(TextStream &s, const GeneratorContext &classContext,
const AbstractMetaFunctionCPtr &func) const
{
- const QString qualifiedName = classContext.wrapperName() + QLatin1String("::");
+ const QString qualifiedName = classContext.wrapperName() + u"::"_s;
s << functionSignature(func, qualifiedName, QString(),
OriginalTypeDescription | SkipDefaultValues);
s << " : ";
@@ -837,14 +867,16 @@ void CppGenerator::writeConstructorNative(TextStream &s, const GeneratorContext
s << R"(std::cerr << __FUNCTION__ << ' ' << this << '\n';)" << '\n';
const AbstractMetaArgument *lastArg = func->arguments().isEmpty() ? nullptr : &func->arguments().constLast();
s << "resetPyMethodCache();\n";
- writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode, func, lastArg);
+ writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionBeginning,
+ TypeSystem::NativeCode, func, false, lastArg);
s << "// ... middle\n";
- writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode, func, lastArg);
+ writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionEnd,
+ TypeSystem::NativeCode, func, false, lastArg);
s << outdent << "}\n\n";
}
void CppGenerator::writeDestructorNative(TextStream &s,
- const GeneratorContext &classContext) const
+ const GeneratorContext &classContext)
{
s << classContext.wrapperName() << "::~"
<< classContext.wrapperName() << "()\n{\n" << indent;
@@ -856,49 +888,51 @@ Shiboken::Object::destroy(wrapper, this);
)" << outdent << "}\n";
}
-static bool allArgumentsRemoved(const AbstractMetaFunctionCPtr& 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;
-}
-
+// Return type for error messages when getting invalid types from virtual
+// methods implemented in Python in C++ wrappers
QString CppGenerator::getVirtualFunctionReturnTypeName(const AbstractMetaFunctionCPtr &func) const
{
if (func->type().isVoid())
- return QLatin1String("\"\"");
+ return u"\"\""_s;
- if (!func->typeReplaced(0).isEmpty())
- return QLatin1Char('"') + func->typeReplaced(0) + QLatin1Char('"');
+ if (func->isTypeModified())
+ return u'"' + func->modifiedTypeName() + u'"';
// SbkType would return null when the type is a container.
auto typeEntry = func->type().typeEntry();
if (typeEntry->isContainer()) {
- return QLatin1Char('"')
- + reinterpret_cast<const ContainerTypeEntry *>(typeEntry)->typeName()
- + QLatin1Char('"');
+ const auto cte = std::static_pointer_cast<const ContainerTypeEntry>(typeEntry);
+ switch (cte->containerKind()) {
+ case ContainerTypeEntry::ListContainer:
+ case ContainerTypeEntry::SpanContainer:
+ break;
+ case ContainerTypeEntry::SetContainer:
+ return uR"("set")"_s;
+ break;
+ case ContainerTypeEntry::MapContainer:
+ case ContainerTypeEntry::MultiMapContainer:
+ return uR"("dict")"_s;
+ break;
+ case ContainerTypeEntry::PairContainer:
+ return uR"("tuple")"_s;
+ break;
+ }
+ return uR"("list")"_s;
}
if (typeEntry->isSmartPointer())
- return QLatin1Char('"') + typeEntry->qualifiedCppName() + QLatin1Char('"');
+ return u'"' + typeEntry->qualifiedCppName() + u'"';
if (avoidProtectedHack()) {
auto metaEnum = api().findAbstractMetaEnum(func->type().typeEntry());
- if (metaEnum.has_value() && metaEnum->isProtected()) {
- return QLatin1Char('"') + protectedEnumSurrogateName(metaEnum.value())
- + QLatin1Char('"');
- }
+ if (metaEnum.has_value() && metaEnum->isProtected())
+ return u'"' + protectedEnumSurrogateName(metaEnum.value()) + u'"';
}
if (func->type().isPrimitive())
- return QLatin1Char('"') + func->type().name() + QLatin1Char('"');
+ return u'"' + func->type().name() + u'"';
- return QLatin1String("reinterpret_cast<PyTypeObject *>(Shiboken::SbkType< ")
- + typeEntry->qualifiedCppName() + QLatin1String(" >())->tp_name");
+ return u"Shiboken::SbkType< "_s
+ + typeEntry->qualifiedCppName() + u" >()->tp_name"_s;
}
// When writing an overridden method of a wrapper class, write the part
@@ -908,22 +942,26 @@ void CppGenerator::writeVirtualMethodCppCall(TextStream &s,
const QString &funcName,
const CodeSnipList &snips,
const AbstractMetaArgument *lastArg,
- const TypeEntry *retType,
- const QString &returnStatement) const
+ const TypeEntryCPtr &retType,
+ const QString &returnStatement, bool hasGil) const
{
if (!snips.isEmpty()) {
writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning,
- TypeSystem::ShellCode, func, lastArg);
+ TypeSystem::ShellCode, func, false, lastArg);
}
if (func->isAbstract()) {
- s << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '"
- << func->ownerClass()->name() << '.' << funcName
- << "()' not implemented.\");\n"
+ if (!hasGil)
+ s << "Shiboken::GilState gil;\n";
+ s << "Shiboken::Errors::setPureVirtualMethodError(\""
+ << func->ownerClass()->name() << '.' << funcName << "\");\n"
<< returnStatement << '\n';
return;
}
+ if (hasGil)
+ s << "gil.release();\n";
+
if (retType)
s << "return ";
s << "this->::" << func->implementingClass()->qualifiedCppName() << "::";
@@ -933,23 +971,30 @@ void CppGenerator::writeVirtualMethodCppCall(TextStream &s,
return;
if (!snips.isEmpty()) {
writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd,
- TypeSystem::ShellCode, func, lastArg);
+ TypeSystem::ShellCode, func, false, lastArg);
}
s << "return;\n";
}
// Determine the return statement (void or a result value).
-QString CppGenerator::virtualMethodReturn(TextStream &s, const ApiExtractorResult &api,
- const AbstractMetaFunctionCPtr &func,
- const FunctionModificationList &functionModifications)
+
+CppGenerator::VirtualMethodReturn
+ CppGenerator::virtualMethodReturn(const ApiExtractorResult &api,
+ const AbstractMetaFunctionCPtr &func,
+ const FunctionModificationList &functionModifications)
{
- if (func->isVoid())
- return QLatin1String("return;");
+ VirtualMethodReturn result;
+ if (func->isVoid()) {
+ result.statement = "return;"_L1;
+ return result;
+ }
+
+ result.statement = "return "_L1;
const AbstractMetaType &returnType = func->type();
for (const FunctionModification &mod : functionModifications) {
for (const ArgumentModification &argMod : mod.argument_mods()) {
if (argMod.index() == 0 && !argMod.replacedDefaultExpression().isEmpty()) {
- static const QRegularExpression regex(QStringLiteral("%(\\d+)"));
+ static const QRegularExpression regex("%(\\d+)"_L1);
Q_ASSERT(regex.isValid());
QString expr = argMod.replacedDefaultExpression();
for (int offset = 0; ; ) {
@@ -957,7 +1002,7 @@ QString CppGenerator::virtualMethodReturn(TextStream &s, const ApiExtractorResul
if (!match.hasMatch())
break;
const int argId = match.capturedView(1).toInt() - 1;
- if (argId < 0 || argId > func->arguments().count()) {
+ if (argId < 0 || argId > func->arguments().size()) {
qCWarning(lcShiboken, "The expression used in return value contains an invalid index.");
break;
}
@@ -965,57 +1010,178 @@ QString CppGenerator::virtualMethodReturn(TextStream &s, const ApiExtractorResul
offset = match.capturedStart(1);
}
DefaultValue defaultReturnExpr(DefaultValue::Custom, expr);
- return QLatin1String("return ") + defaultReturnExpr.returnValue()
- + QLatin1Char(';');
+ result.statement += defaultReturnExpr.returnValue() + u';';
+ return result;
}
}
}
QString errorMessage;
const auto defaultReturnExpr = minimalConstructor(api, returnType, &errorMessage);
if (!defaultReturnExpr.has_value()) {
- QString errorMsg = QLatin1String(__FUNCTION__) + QLatin1String(": ");
- if (const AbstractMetaClass *c = func->implementingClass())
- errorMsg += c->qualifiedCppName() + QLatin1String("::");
- errorMsg += func->signature();
+ QString errorMsg = QLatin1StringView(__FUNCTION__) + u": "_s
+ + func->classQualifiedSignature();
errorMsg = msgCouldNotFindMinimalConstructor(errorMsg,
func->type().cppSignature(),
errorMessage);
- qCWarning(lcShiboken).noquote().nospace() << errorMsg;
- s << "\n#error " << errorMsg << '\n';
+ throw Exception(errorMsg);
+ }
+
+ result.needsReference = returnType.referenceType() == LValueReference;
+ result.statement += (result.needsReference
+ ? virtualMethodStaticReturnVar : defaultReturnExpr->returnValue()) + u';';
+ return result;
+}
+
+// Create an argument for Py_BuildValue() when writing virtual methods.
+// Return a pair of (argument, format-char).
+std::pair<QString, QChar> CppGenerator::virtualMethodNativeArg(const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgument &arg)
+{
+ if (func->hasConversionRule(TypeSystem::TargetLangCode, arg.argumentIndex() + 1))
+ return {arg.name() + CONV_RULE_OUT_VAR_SUFFIX, u'N'};
+
+ const auto &type = arg.type();
+ auto argTypeEntry = type.typeEntry();
+ // Check for primitive types convertible by Py_BuildValue()
+ if (argTypeEntry->isPrimitive() && !type.isCString()) {
+ const auto pte = basicReferencedTypeEntry(argTypeEntry);
+ auto it = formatUnits().constFind(pte->name());
+ if (it != formatUnits().constEnd())
+ return {arg.name(), it.value()};
+ }
+
+ // Rest: convert
+ StringStream ac(TextStream::Language::Cpp);
+ writeToPythonConversion(ac, type, func->ownerClass(), arg.name());
+ return {ac.toString(), u'N'};
+}
+
+static const char PYTHON_ARGS_ARRAY[] = "pyArgArray";
+
+void CppGenerator::writeVirtualMethodNativeVectorCallArgs(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgumentList &arguments,
+ const QList<int> &invalidateArgs)
+{
+ Q_ASSERT(!arguments.isEmpty());
+ s << "PyObject *" << PYTHON_ARGS_ARRAY <<'[' << arguments.size() << "] = {\n" << indent;
+ const qsizetype last = arguments.size() - 1;
+ for (qsizetype i = 0; i <= last; ++i) {
+ const AbstractMetaArgument &arg = arguments.at(i);
+ if (func->hasConversionRule(TypeSystem::TargetLangCode, arg.argumentIndex() + 1)) {
+ s << arg.name() + CONV_RULE_OUT_VAR_SUFFIX;
+ } else {
+ writeToPythonConversion(s, arg.type(), func->ownerClass(), arg.name());
+ }
+ if (i < last)
+ s << ',';
+ s << '\n';
+ }
+ s << outdent << "};\n";
+
+ if (!invalidateArgs.isEmpty())
+ s << '\n';
+ for (int index : invalidateArgs) {
+ s << "const bool invalidateArg" << index << " = Py_REFCNT(" << PYTHON_ARGS_ARRAY <<
+ '[' << index - 1 << "]) == 1;\n";
}
- if (returnType.referenceType() == LValueReference) {
- s << "static " << returnType.typeEntry()->qualifiedCppName()
- << " result;\n";
- return QLatin1String("return result;");
+}
+
+void CppGenerator::writeVirtualMethodNativeArgs(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgumentList &arguments,
+ const QList<int> &invalidateArgs)
+{
+ s << "Shiboken::AutoDecRef " << PYTHON_ARGS << '(';
+ if (arguments.isEmpty()) {
+ s << "PyTuple_New(0));\n";
+ return;
}
- return QLatin1String("return ") + defaultReturnExpr->returnValue()
- + QLatin1Char(';');
+
+ QString format;
+ QStringList argConversions;
+ for (const AbstractMetaArgument &arg : arguments) {
+ auto argPair = virtualMethodNativeArg(func, arg);
+ argConversions.append(argPair.first);
+ format += argPair.second;
+ }
+
+ s << "Py_BuildValue(\"(" << format << ")\",\n"
+ << indent << argConversions.join(u",\n"_s) << outdent << "\n));\n";
+
+ for (int index : std::as_const(invalidateArgs)) {
+ s << "bool invalidateArg" << index << " = Py_REFCNT(PyTuple_GET_ITEM(" << PYTHON_ARGS
+ << ", " << index - 1 << ")) == 1;\n";
+ }
+}
+
+static bool isArgumentNotRemoved(const AbstractMetaArgument &a)
+{
+ return !a.isModifiedRemoved();
+}
+
+// PyObject_Vectorcall(): since 3.9
+static const char vectorCallCondition[] =
+ "#if !defined(PYPY_VERSION) && !defined(Py_LIMITED_API)\n";
+
+// PyObject_CallNoArgs(): since 3.9, stable API since 3.10
+static const char noArgsCallCondition[] =
+ "#if !defined(PYPY_VERSION) && ((defined(Py_LIMITED_API) && Py_LIMITED_API >= 0x030A0000) || !defined(Py_LIMITED_API))\n";
+static const char inverseNoArgsCallCondition[] =
+ "#if defined(PYPY_VERSION) || (defined(Py_LIMITED_API) && Py_LIMITED_API < 0x030A0000)\n";
+
+static inline void writeVirtualMethodStaticReturnVar(TextStream &s, const AbstractMetaFunctionCPtr &func)
+{
+ s << "static " << func->type().typeEntry()->qualifiedCppName() << ' '
+ << virtualMethodStaticReturnVar << ";\n";
+}
+
+static void writeFuncNameVar(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ const QString &funcName)
+{
+ // PYSIDE-1019: Add info about properties
+ int propFlag = 0;
+ if (func->isPropertyReader())
+ propFlag |= 1;
+ if (func->isPropertyWriter())
+ propFlag |= 2;
+ if (propFlag && func->isStatic())
+ propFlag |= 4;
+ QString propStr;
+ if (propFlag != 90)
+ propStr = QString::number(propFlag) + u':';
+
+ if (propFlag != 0)
+ s << "// This method belongs to a property.\n";
+ s << "static const char *funcName = \"";
+ if (propFlag != 0)
+ s << propFlag << ':';
+ s << funcName << "\";\n";
}
void CppGenerator::writeVirtualMethodNative(TextStream &s,
const AbstractMetaFunctionCPtr &func,
int cacheIndex) const
{
- //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().typeEntry();
+ TypeEntryCPtr retType = func->type().typeEntry();
const QString funcName = func->isOperatorOverload()
? pythonOperatorFunctionName(func) : func->definitionNames().constFirst();
- QString prefix = wrapperName(func->ownerClass()) + QLatin1String("::");
- s << functionSignature(func, prefix, QString(), Generator::SkipDefaultValues|Generator::OriginalTypeDescription)
+ QString prefix = wrapperName(func->ownerClass()) + u"::"_s;
+ s << functionSignature(func, prefix, QString(), Generator::SkipDefaultValues |
+ Generator::OriginalTypeDescription)
<< "\n{\n" << indent;
- const FunctionModificationList &functionModifications = func->modifications();
+ const auto returnStatement = virtualMethodReturn(api(), func,
+ func->modifications());
- const QString returnStatement = virtualMethodReturn(s, api(), func, functionModifications);
+ if (returnStatement.needsReference)
+ writeVirtualMethodStaticReturnVar(s, func);
- if (func->isAbstract() && func->isModifiedRemoved()) {
- qCWarning(lcShiboken, "%s", qPrintable(msgPureVirtualFunctionRemoved(func.data())));
- s << returnStatement << '\n' << outdent << "}\n\n";
+ const bool isAbstract = func->isAbstract();
+ if (isAbstract && func->isModifiedRemoved()) {
+ qCWarning(lcShiboken, "%s", qPrintable(msgPureVirtualFunctionRemoved(func.get())));
+ s << returnStatement.statement << '\n' << outdent << "}\n\n";
return;
}
@@ -1024,10 +1190,10 @@ void CppGenerator::writeVirtualMethodNative(TextStream &s,
const AbstractMetaArgument *lastArg = func->arguments().isEmpty()
? nullptr : &func->arguments().constLast();
- //Write declaration/native injected code
+ // Write declaration/native injected code.
if (!snips.isEmpty()) {
writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionDeclaration,
- TypeSystem::ShellCode, func, lastArg);
+ TypeSystem::ShellCode, func, false, lastArg);
}
if (wrapperDiagnostics()) {
@@ -1039,240 +1205,270 @@ void CppGenerator::writeVirtualMethodNative(TextStream &s,
<< cacheIndex << R"( << "]=" << m_PyMethodCache[)" << cacheIndex
<< R"(] << '\n';)" << '\n';
}
- // PYSIDE-803: Build a boolean cache for unused overrides.
- const bool multi_line = func->isVoid() || !snips.isEmpty() || func->isAbstract();
- s << "if (m_PyMethodCache[" << cacheIndex << "])" << (multi_line ? " {\n" : "\n");
- {
- Indentation indentation(s);
- writeVirtualMethodCppCall(s, func, funcName, snips, lastArg, retType,
- returnStatement);
- }
+ // PYSIDE-803: Build a boolean cache for unused overrides
+ const bool multi_line = func->isVoid() || !snips.isEmpty() || isAbstract;
+ s << "if (m_PyMethodCache[" << cacheIndex << "])" << (multi_line ? " {\n" : "\n")
+ << indent;
+ writeVirtualMethodCppCall(s, func, funcName, snips, lastArg, retType,
+ returnStatement.statement, false);
+ s << outdent;
if (multi_line)
s << "}\n";
s << "Shiboken::GilState gil;\n";
// Get out of virtual method call if someone already threw an error.
- s << "if (PyErr_Occurred())\n" << indent
- << returnStatement << '\n' << outdent;
-
- //PYSIDE-1019: Add info about properties.
- int propFlag = 0;
- if (func->isPropertyReader())
- propFlag |= 1;
- if (func->isPropertyWriter())
- propFlag |= 2;
- if (propFlag && func->isStatic())
- propFlag |= 4;
- QString propStr;
- if (propFlag)
- propStr = QString::number(propFlag) + QLatin1Char(':');
+ s << "if (" << shibokenErrorsOccurred << ")\n" << indent
+ << returnStatement.statement << '\n' << outdent;
s << "static PyObject *nameCache[2] = {};\n";
- if (propFlag)
- s << "// This method belongs to a property.\n";
- s << "static const char *funcName = \"" << propStr << funcName << "\";\n"
- << "Shiboken::AutoDecRef " << PYTHON_OVERRIDE_VAR
+ writeFuncNameVar(s, func, funcName);
+ s << "Shiboken::AutoDecRef " << PYTHON_OVERRIDE_VAR
<< "(Shiboken::BindingManager::instance().getOverride(this, nameCache, funcName));\n"
- << "if (" << PYTHON_OVERRIDE_VAR << ".isNull()) {\n"
- << indent << "gil.release();\n";
+ << "if (" << PYTHON_OVERRIDE_VAR << ".isNull()) {\n" << indent;
if (useOverrideCaching(func->ownerClass()))
s << "m_PyMethodCache[" << cacheIndex << "] = true;\n";
writeVirtualMethodCppCall(s, func, funcName, snips, lastArg, retType,
- returnStatement);
+ returnStatement.statement, true);
s << outdent << "}\n\n"; //WS
- writeConversionRule(s, func, TypeSystem::TargetLangCode);
-
- s << "Shiboken::AutoDecRef " << PYTHON_ARGS << "(";
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionPyOverride,
+ TypeSystem::ShellCode, func, false, lastArg);
+ }
- 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;
+ writeVirtualMethodPythonOverride(s, func, snips, returnStatement);
+}
- const auto &argType = arg.type();
- auto argTypeEntry = static_cast<const PrimitiveTypeEntry *>(argType.typeEntry());
- bool convert = argTypeEntry->isObject()
- || argTypeEntry->isValue()
- || argType.isValuePointer()
- || argType.isNativePointer()
- || argTypeEntry->isFlags()
- || argTypeEntry->isEnum()
- || argTypeEntry->isContainer()
- || argType.referenceType() == LValueReference;
-
- if (!convert && argTypeEntry->isPrimitive()) {
- if (argTypeEntry->basicReferencedTypeEntry())
- argTypeEntry = argTypeEntry->basicReferencedTypeEntry();
- convert = !formatUnits().contains(argTypeEntry->name());
- }
+void CppGenerator::writeVirtualMethodPythonOverride(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const CodeSnipList &snips,
+ const VirtualMethodReturn &returnStatement) const
+{
+ writeConversionRule(s, func, TypeSystem::TargetLangCode, false);
- StringStream ac(TextStream::Language::Cpp);
- if (!func->conversionRule(TypeSystem::TargetLangCode, arg.argumentIndex() + 1).isEmpty()) {
- // Has conversion rule.
- ac << arg.name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX);
+ bool invalidateReturn = false;
+ QList<int> invalidateArgs;
+ for (const FunctionModification &funcMod : func->modifications()) {
+ for (const ArgumentModification &argMod : funcMod.argument_mods()) {
+ const int index = argMod.index();
+ if (index == 0) {
+ if (argMod.targetOwnerShip() == TypeSystem::CppOwnership)
+ invalidateReturn = true;
} else {
- QString argName = arg.name();
- if (convert)
- writeToPythonConversion(ac, arg.type(), func->ownerClass(), argName);
- else
- ac << argName;
+ const int actualIndex = func->actualArgumentIndex(index - 1) + 1;
+ if (argMod.resetAfterUse() && !invalidateArgs.contains(actualIndex))
+ invalidateArgs.append(actualIndex);
}
-
- argConversions << ac.toString();
}
+ }
+ std::sort(invalidateArgs.begin(), invalidateArgs.end());
- s << "Py_BuildValue(\"(" << getFormatUnitString(func, false) << ")\",\n"
- << argConversions.join(QLatin1String(",\n")) << "\n));\n";
+ auto arguments = func->arguments();
+ auto removedEnd = std::stable_partition(arguments.begin(), arguments.end(),
+ isArgumentNotRemoved);
+ if (func->isAbstract()) { // Base function is not called, indicate unused arguments.
+ for (auto it = removedEnd; it != arguments.end(); ++it)
+ s << sbkUnusedVariableCast(it->name());
}
+ arguments.erase(removedEnd, arguments.end());
- bool invalidateReturn = false;
- QSet<int> invalidateArgs;
- for (const FunctionModification &funcMod : functionModifications) {
- for (const ArgumentModification &argMod : funcMod.argument_mods()) {
- const int index = argMod.index();
- if (argMod.resetAfterUse() && !invalidateArgs.contains(index)) {
- invalidateArgs.insert(index);
- s << "bool invalidateArg" << index
- << " = PyTuple_GET_ITEM(" << PYTHON_ARGS << ", "
- << index - 1 << ")->ob_refcnt == 1;\n";
- } else if (index == 0 &&
- argMod.targetOwnerShip() == TypeSystem::CppOwnership) {
- invalidateReturn = true;
- }
+ // FIXME PYSIDE-7: new functions PyObject_Vectorcall() (since 3.9) and
+ // PyObject_CallNoArgs() (since 3.9, stable API since 3.10) might have
+ // become part of the stable API?
+
+ // Code snips might expect the args tuple, don't generate new code
+ const bool generateNewCall = snips.isEmpty();
+ const qsizetype argCount = arguments.size();
+ const char *newCallCondition = argCount == 0 ? noArgsCallCondition : vectorCallCondition;
+ if (generateNewCall) {
+ if (argCount > 0) {
+ s << newCallCondition;
+ writeVirtualMethodNativeVectorCallArgs(s, func, arguments, invalidateArgs);
+ s << "#else\n";
+ } else {
+ s << inverseNoArgsCallCondition;
}
}
+ writeVirtualMethodNativeArgs(s, func, arguments, invalidateArgs);
+ if (generateNewCall)
+ s << "#endif\n";
s << '\n';
if (!snips.isEmpty()) {
if (func->injectedCodeUsesPySelf())
s << "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);
+ const AbstractMetaArgument *lastArg = func->arguments().isEmpty()
+ ? nullptr : &func->arguments().constLast();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning,
+ TypeSystem::NativeCode, func, false, lastArg);
}
+ qsizetype returnIndirections = 0;
+
if (!func->injectedCodeCallsPythonOverride()) {
+ if (generateNewCall) {
+ s << newCallCondition << "Shiboken::AutoDecRef " << PYTHON_RETURN_VAR << '(';
+ if (argCount > 0) {
+ s << "PyObject_Vectorcall(" << PYTHON_OVERRIDE_VAR << ", "
+ << PYTHON_ARGS_ARRAY << ", " << argCount << ", nullptr));\n";
+ for (int argIndex : std::as_const(invalidateArgs)) {
+ s << "if (invalidateArg" << argIndex << ")\n" << indent
+ << "Shiboken::Object::invalidate(" << PYTHON_ARGS_ARRAY
+ << '[' << (argIndex - 1) << "]);\n" << outdent;
+ }
+ for (qsizetype i = 0, size = arguments.size(); i < size; ++i)
+ s << "Py_DECREF(" << PYTHON_ARGS_ARRAY << '[' << i << "]);\n";
+ } else {
+ s << "PyObject_CallNoArgs(" << PYTHON_OVERRIDE_VAR << "));\n";
+ }
+ s << "#else\n";
+ }
s << "Shiboken::AutoDecRef " << PYTHON_RETURN_VAR << "(PyObject_Call("
- << PYTHON_OVERRIDE_VAR << ", " << PYTHON_ARGS << ", nullptr));\n"
+ << PYTHON_OVERRIDE_VAR << ", " << PYTHON_ARGS << ", nullptr));\n";
+
+ for (int argIndex : std::as_const(invalidateArgs)) {
+ s << "if (invalidateArg" << argIndex << ")\n" << indent
+ << "Shiboken::Object::invalidate(PyTuple_GET_ITEM(" << PYTHON_ARGS
+ << ", " << (argIndex - 1) << "));\n" << outdent;
+ }
+ if (generateNewCall)
+ s << "#endif\n";
+
+ s << "if (" << PYTHON_RETURN_VAR << ".isNull()) {\n" << indent
<< "// An error happened in python code!\n"
- << "if (" << PYTHON_RETURN_VAR << ".isNull()) {\n" << indent
- << "PyErr_Print();\n" << returnStatement << '\n' << outdent
- << "}\n";
+ << "Shiboken::Errors::storePythonOverrideErrorOrPrint(\""
+ << func->ownerClass()->name() << "\", funcName);\n"
+ << returnStatement.statement << "\n" << outdent
+ << "}\n";
+
+ if (invalidateReturn) {
+ s << "bool invalidateArg0 = Py_REFCNT(" << PYTHON_RETURN_VAR << ") == 1;\n"
+ << "if (invalidateArg0)\n" << indent
+ << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR
+ << ".object());\n" << outdent;
+ }
if (!func->isVoid()) {
- if (invalidateReturn)
- s << "bool invalidateArg0 = " << PYTHON_RETURN_VAR << "->ob_refcnt == 1;\n";
- if (func->typeReplaced(0) != cPyObjectT()) {
+ if (func->modifiedTypeName() != cPyObjectT) {
s << "// Check return type\n";
- if (func->typeReplaced(0).isEmpty()) {
- s << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << " = "
+
+ if (!func->isTypeModified()) {
+
+ s << PYTHON_TO_CPPCONVERSION_STRUCT << ' '
+ << PYTHON_TO_CPP_VAR << " =\n" << indent
<< cpythonIsConvertibleFunction(func->type())
- << PYTHON_RETURN_VAR << ");\n"
- << "if (!" << PYTHON_TO_CPP_VAR << ") {\n";
- {
- Indentation indent(s);
- s << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\
- "\"Invalid return value in function %s, expected %s, got %s.\", \""
- << func->ownerClass()->name() << '.' << funcName << "\", "
- << getVirtualFunctionReturnTypeName(func)
- << ", Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);\n"
- << returnStatement << '\n';
- }
- s << "}\n";
+ << PYTHON_RETURN_VAR << ");\n" << outdent
+ << "if (!" << PYTHON_TO_CPP_VAR << ") {\n" << indent
+ << "Shiboken::Warnings::warnInvalidReturnValue(\""
+ << func->ownerClass()->name() << "\", funcName, "
+ << getVirtualFunctionReturnTypeName(func) << ", "
+ << "Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);\n"
+ << returnStatement.statement << '\n' << outdent
+ << "}\n";
} else {
- s << "// Check return type\n"
- << "bool typeIsValid = ";
- writeTypeCheck(s, func->type(), QLatin1String(PYTHON_RETURN_VAR),
- isNumber(func->type().typeEntry()), func->typeReplaced(0));
+ s << "bool typeIsValid = ";
+ if (func->isTypeModified()) {
+ writeTypeCheck(s, func->modifiedTypeName(), PYTHON_RETURN_VAR);
+ } else {
+ const bool numberType = isNumber(func->type().typeEntry());
+ writeTypeCheck(s, func->type(), PYTHON_RETURN_VAR, numberType);
+ }
+
s << ";\n";
s << "if (!typeIsValid";
if (func->type().isPointerToWrapperType())
s << " && " << PYTHON_RETURN_VAR << " != Py_None";
- s << ") {\n";
- {
- Indentation indent(s);
- s << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\
- "\"Invalid return value in function %s, expected %s, got %s.\", \""
- << func->ownerClass()->name() << '.' << funcName << "\", "
- << getVirtualFunctionReturnTypeName(func)
- << ", Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);\n"
- << returnStatement << '\n';
- }
- s << "}\n";
+ s << ") {\n" << indent
+ << "Shiboken::Warnings::warnInvalidReturnValue(\""
+ << func->ownerClass()->name() << "\", funcName, "
+ << getVirtualFunctionReturnTypeName(func) << ", "
+ << "Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);\n"
+ << returnStatement.statement << '\n' << outdent
+ << "}\n";
}
}
- if (!func->conversionRule(TypeSystem::NativeCode, 0).isEmpty()) {
- // Has conversion rule.
- writeConversionRule(s, func, TypeSystem::NativeCode, QLatin1String(CPP_RETURN_VAR));
+ if (func->hasConversionRule(TypeSystem::NativeCode, 0)) {
+ writeConversionRule(s, func, TypeSystem::NativeCode, CPP_RETURN_VAR);
} else if (!func->injectedCodeHasReturnValueAttribution(TypeSystem::NativeCode)) {
- writePythonToCppTypeConversion(s, func->type(), QLatin1String(PYTHON_RETURN_VAR),
- QLatin1String(CPP_RETURN_VAR), func->implementingClass());
+ returnIndirections = writePythonToCppTypeConversion(
+ s, func->type(), PYTHON_RETURN_VAR,
+ CPP_RETURN_VAR, func->implementingClass(), {});
}
}
}
- if (invalidateReturn) {
- s << "if (invalidateArg0)\n" << indent
- << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR
- << ".object());\n" << outdent;
- }
- for (int argIndex : qAsConst(invalidateArgs)) {
- s << "if (invalidateArg" << argIndex << ")\n" << indent
- << "Shiboken::Object::invalidate(PyTuple_GET_ITEM(" << PYTHON_ARGS
- << ", " << (argIndex - 1) << "));\n" << outdent;
- }
-
-
- for (const FunctionModification &funcMod : functionModifications) {
+ for (const FunctionModification &funcMod : func->modifications()) {
for (const ArgumentModification &argMod : funcMod.argument_mods()) {
if (argMod.index() == 0
&& argMod.nativeOwnership() == TypeSystem::CppOwnership) {
- s << "if (Shiboken::Object::checkType(" << PYTHON_RETURN_VAR << "))\n";
- Indentation indent(s);
- s << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR << ");\n";
+ s << "if (Shiboken::Object::checkType(" << PYTHON_RETURN_VAR << "))\n" << indent
+ << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR << ");\n"
+ << outdent;
}
}
}
if (func->hasInjectedCode()) {
s << '\n';
- const AbstractMetaArgument *lastArg = func->arguments().isEmpty() ? nullptr : &func->arguments().constLast();
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode, func, lastArg);
+ const AbstractMetaArgument *lastArg = func->arguments().isEmpty()
+ ? nullptr : &func->arguments().constLast();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd,
+ TypeSystem::NativeCode, func, false, lastArg);
}
if (!func->isVoid()) {
s << "return ";
+ TypeEntryCPtr retType = func->type().typeEntry();
if (avoidProtectedHack() && retType->isEnum()) {
auto metaEnum = api().findAbstractMetaEnum(retType);
bool isProtectedEnum = metaEnum.has_value() && metaEnum->isProtected();
if (isProtectedEnum) {
QString typeCast;
if (metaEnum->enclosingClass())
- typeCast += QLatin1String("::") + metaEnum->enclosingClass()->qualifiedCppName();
- typeCast += QLatin1String("::") + metaEnum->name();
+ typeCast += getFullTypeName(metaEnum->enclosingClass());
+ typeCast += u"::"_s + metaEnum->name();
s << '(' << typeCast << ')';
}
}
- if (func->type().referenceType() == LValueReference && !func->type().isPointer())
- s << " *";
+
+ if (returnIndirections > 0)
+ s << QByteArray(returnIndirections, '*');
s << CPP_RETURN_VAR << ";\n";
}
s << outdent << "}\n\n";
}
+void CppGenerator::writeUserAddedPythonOverride(TextStream &s,
+ const AbstractMetaFunctionCPtr &func) const
+{
+ TypeEntryCPtr retType = func->type().typeEntry();
+ const QString funcName = func->isOperatorOverload()
+ ? pythonOperatorFunctionName(func) : func->definitionNames().constFirst();
+
+ const CodeSnipList snips = func->hasInjectedCode()
+ ? func->injectedCodeSnips() : CodeSnipList();
+
+ QString prefix = wrapperName(func->ownerClass()) + u"::"_s;
+ s << '\n' << functionSignature(func, prefix, QString(), Generator::SkipDefaultValues |
+ Generator::OriginalTypeDescription)
+ << "\n{\n" << indent << sbkUnusedVariableCast("gil");
+
+ writeFuncNameVar(s, func, funcName);
+
+ const auto returnStatement = virtualMethodReturn(api(), func,
+ func->modifications());
+ writeVirtualMethodPythonOverride(s, func, snips, returnStatement);
+}
+
void CppGenerator::writeMetaObjectMethod(TextStream &s,
const GeneratorContext &classContext) const
{
@@ -1280,19 +1476,21 @@ void CppGenerator::writeMetaObjectMethod(TextStream &s,
const QString wrapperClassName = classContext.wrapperName();
const QString qualifiedCppName = classContext.metaClass()->qualifiedCppName();
s << "const QMetaObject *" << wrapperClassName << "::metaObject() const\n{\n";
- s << indent << "if (QObject::d_ptr->metaObject)\n"
+ s << indent << "if (QObject::d_ptr->metaObject != nullptr)\n"
<< indent << "return QObject::d_ptr->dynamicMetaObject();\n" << outdent
<< "SbkObject *pySelf = Shiboken::BindingManager::instance().retrieveWrapper(this);\n"
<< "if (pySelf == nullptr)\n"
<< indent << "return " << qualifiedCppName << "::metaObject();\n" << outdent
- << "return PySide::SignalManager::retrieveMetaObject(reinterpret_cast<PyObject *>(pySelf));\n"
+ << "return PySide::SignalManager::retrieveMetaObject("
+ "reinterpret_cast<PyObject *>(pySelf));\n"
<< outdent << "}\n\n";
// qt_metacall function
- s << "int " << wrapperClassName << "::qt_metacall(QMetaObject::Call call, int id, void **args)\n";
+ s << "int " << wrapperClassName
+ << "::qt_metacall(QMetaObject::Call call, int id, void **args)\n";
s << "{\n" << indent;
- const auto list = classContext.metaClass()->queryFunctionsByName(QLatin1String("qt_metacall"));
+ const auto list = classContext.metaClass()->queryFunctionsByName(u"qt_metacall"_s);
CodeSnipList snips;
if (list.size() == 1) {
@@ -1300,12 +1498,15 @@ void CppGenerator::writeMetaObjectMethod(TextStream &s,
snips = func->injectedCodeSnips();
if (func->isUserAdded()) {
CodeSnipList snips = func->injectedCodeSnips();
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::NativeCode, func);
+ const bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(func);
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny,
+ TypeSystem::NativeCode, func, usePyArgs, nullptr);
}
}
s << "int result = " << qualifiedCppName << "::qt_metacall(call, id, args);\n"
- << "return result < 0 ? result : PySide::SignalManager::qt_metacall(this, call, id, args);\n"
+ << "return result < 0 ? result : PySide::SignalManager::qt_metacall("
+ "this, call, id, args);\n"
<< outdent << "}\n\n";
// qt_metacast function
@@ -1318,108 +1519,117 @@ void CppGenerator::writeMetaCast(TextStream &s,
const QString wrapperClassName = classContext.wrapperName();
const QString qualifiedCppName = classContext.metaClass()->qualifiedCppName();
s << "void *" << wrapperClassName << "::qt_metacast(const char *_clname)\n{\n"
- << indent << "if (!_clname)\n" << indent << "return {};\n" << outdent
+ << indent << "if (_clname == nullptr)\n" << indent << "return {};\n" << outdent
<< "SbkObject *pySelf = Shiboken::BindingManager::instance().retrieveWrapper(this);\n"
- << "if (pySelf && PySide::inherits(Py_TYPE(pySelf), _clname))\n"
+ << "if (pySelf != nullptr && PySide::inherits(Py_TYPE(pySelf), _clname))\n"
<< indent << "return static_cast<void *>(const_cast< "
<< wrapperClassName << " *>(this));\n" << outdent
<< "return " << qualifiedCppName << "::qt_metacast(_clname);\n"
<< outdent << "}\n\n";
}
-void CppGenerator::writeEnumConverterFunctions(TextStream &s, const AbstractMetaEnum &metaEnum) const
+static void generateDeprecatedValueWarnings(TextStream &c,
+ const AbstractMetaEnum &metaEnum,
+ bool useSurrogateName)
{
- if (metaEnum.isPrivate() || metaEnum.isAnonymous())
- return;
- writeEnumConverterFunctions(s, metaEnum.typeEntry());
+ EnumTypeEntryCPtr enumType = metaEnum.typeEntry();
+ const QString prefix = enumType->qualifiedCppName() + u"::"_s;
+ c << "switch (value) {\n";
+ const auto &deprecatedValues = metaEnum.deprecatedValues();
+ for (const auto &v : deprecatedValues) {
+ c << "case ";
+ if (useSurrogateName)
+ c << v.value().toString(); // Protected, use int representation
+ else
+ c << prefix << v.name();
+ c << ":\n" << indent
+ << "Shiboken::Warnings::warnDeprecatedEnumValue(\"" << enumType->name()
+ << "\", \"" << v.name() << "\");\nbreak;\n" << outdent;
+ }
+ if (deprecatedValues.size() < metaEnum.values().size())
+ c << "default:\n" << indent << "break;\n" << outdent;
+ c << "}\n";
}
-void CppGenerator::writeEnumConverterFunctions(TextStream &s, const TypeEntry *enumType) const
+void CppGenerator::writeEnumConverterFunctions(TextStream &s, const AbstractMetaEnum &metaEnum) const
{
- if (!enumType)
+ if (metaEnum.isPrivate() || metaEnum.isAnonymous())
return;
+ EnumTypeEntryCPtr enumType = metaEnum.typeEntry();
+ Q_ASSERT(enumType);
QString typeName = fixedCppTypeName(enumType);
QString enumPythonType = cpythonTypeNameExt(enumType);
- QString cppTypeName = getFullTypeName(enumType).trimmed();
- if (avoidProtectedHack()) {
- auto metaEnum = api().findAbstractMetaEnum(enumType);
- if (metaEnum.has_value() && metaEnum->isProtected())
- cppTypeName = protectedEnumSurrogateName(metaEnum.value());
- }
+ const bool useSurrogateName = avoidProtectedHack() && metaEnum.isProtected();
+ QString cppTypeName = useSurrogateName
+ ? protectedEnumSurrogateName(metaEnum) : getFullTypeName(enumType).trimmed();
+
StringStream c(TextStream::Language::Cpp);
- c << "*reinterpret_cast<" << cppTypeName << " *>(cppOut) =\n"
- << " ";
- 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";
+ if (metaEnum.isDeprecated())
+ c << "Shiboken::Warnings::warnDeprecatedEnum(\"" << enumType->name() << "\");\n";
+
+ c << "const auto value = static_cast<" << cppTypeName
+ << ">(Shiboken::Enum::getValue(pyIn));\n";
+
+ // Warn about deprecated values unless it is protected+scoped (inaccessible values)
+ const bool valuesAcccessible = !useSurrogateName || metaEnum.enumKind() != EnumClass;
+ if (valuesAcccessible && metaEnum.hasDeprecatedValues())
+ generateDeprecatedValueWarnings(c, metaEnum, useSurrogateName);
+
+ c << "*reinterpret_cast<" << cppTypeName << " *>(cppOut) = value;\n";
+
+ ConfigurableScope configScope(s, enumType);
writePythonToCppFunction(s, c.toString(), typeName, typeName);
- QString pyTypeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, %1)").arg(enumPythonType);
+ QString pyTypeCheck = u"PyObject_TypeCheck(pyIn, "_s + enumPythonType + u')';
writeIsPythonConvertibleToCppFunction(s, typeName, typeName, pyTypeCheck);
c.clear();
c << "const int castCppIn = int(*reinterpret_cast<const "
- << cppTypeName << " *>(cppIn));\n" << "return ";
- if (enumType->isFlags()) {
- c << "reinterpret_cast<PyObject *>(PySide::QFlags::newObject(castCppIn, "
- << enumPythonType << "))";
- } else {
- c << "Shiboken::Enum::newItem(" << enumPythonType << ", castCppIn)";
- }
- c << ";\n";
+ << cppTypeName << " *>(cppIn));\n" << "return "
+ << "Shiboken::Enum::newItem(" << enumPythonType << ", castCppIn);\n";
writeCppToPythonFunction(s, c.toString(), typeName, typeName);
s << '\n';
+}
- if (enumType->isFlags())
- return;
+static void writePointerToPythonConverter(TextStream &c,
+ const AbstractMetaClassCPtr &metaClass,
+ const QString &typeName,
+ const QString &cpythonType)
+{
+ c << "auto *pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(cppIn));\n"
+ << "if (pyOut) {\n" << indent
+ << "Py_INCREF(pyOut);\nreturn pyOut;\n" << outdent
+ << "}\n";
- auto flags = reinterpret_cast<const EnumTypeEntry *>(enumType)->flags();
- if (!flags)
+ const QString nameFunc = metaClass->typeEntry()->polymorphicNameFunction();
+ if (nameFunc.isEmpty() && !metaClass->hasVirtualDestructor()) {
+ c << "return Shiboken::Object::newObjectWithHeuristics("
+ << cpythonType << ", const_cast<void *>(cppIn), false);\n";
return;
+ }
- // QFlags part.
-
- writeEnumConverterFunctions(s, flags);
-
- c.clear();
- cppTypeName = getFullTypeName(flags).trimmed();
- c << "*reinterpret_cast<" << cppTypeName << " *>(cppOut) =\n"
- << " " << cppTypeName
- << "(QFlag(int(Shiboken::Enum::getValue(pyIn))));\n";
-
- QString flagsTypeName = fixedCppTypeName(flags);
- writePythonToCppFunction(s, c.toString(), typeName, flagsTypeName);
- writeIsPythonConvertibleToCppFunction(s, typeName, flagsTypeName, pyTypeCheck);
+ c << "auto *tCppIn = reinterpret_cast<const " << typeName << R"( *>(cppIn);
+const char *typeName = )";
+ if (nameFunc.isEmpty())
+ c << "typeid(*tCppIn).name();\n";
+ else
+ c << nameFunc << "(tCppIn);\n";
+ c << "return Shiboken::Object::newObjectForPointer("
+ << cpythonType << ", const_cast<void *>(cppIn), false, typeName);\n";
+}
- c.clear();
- c << "Shiboken::AutoDecRef pyLong(PyNumber_Long(pyIn));\n"
- << "*reinterpret_cast<" << cppTypeName << " *>(cppOut) =\n"
- << " " << 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, c.toString(), QLatin1String("number"), flagsTypeName);
- writeIsPythonConvertibleToCppFunction(s, QLatin1String("number"), flagsTypeName, numberCondition);
-}
-
-void CppGenerator::writeConverterFunctions(TextStream &s, const AbstractMetaClass *metaClass,
+void CppGenerator::writeConverterFunctions(TextStream &s, const AbstractMetaClassCPtr &metaClass,
const GeneratorContext &classContext) const
{
s << "// Type conversion functions.\n\n";
AbstractMetaEnumList classEnums = metaClass->enums();
+ auto typeEntry = metaClass->typeEntry();
metaClass->getEnumsFromInvisibleNamespacesToBeGenerated(&classEnums);
if (!classEnums.isEmpty())
s << "// Python to C++ enum conversion.\n";
- for (const AbstractMetaEnum &metaEnum : qAsConst(classEnums))
+ for (const AbstractMetaEnum &metaEnum : std::as_const(classEnums))
writeEnumConverterFunctions(s, metaEnum);
if (metaClass->isNamespace())
@@ -1437,123 +1647,102 @@ void CppGenerator::writeConverterFunctions(TextStream &s, const AbstractMetaClas
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 targetTypeName = metaClass->name() + u"_PTR"_s;
StringStream c(TextStream::Language::Cpp);
c << "Shiboken::Conversions::pythonToCppPointer(" << cpythonType << ", pyIn, cppOut);";
writePythonToCppFunction(s, c.toString(), 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("))");
+ const QString pyTypeCheck = u"PyObject_TypeCheck(pyIn, "_s + cpythonType + u")"_s;
writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, pyTypeCheck, QString(), true);
s << '\n';
// 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";
c.clear();
- if (usePySideExtensions() && metaClass->isQObject()) {
+ if (usePySideExtensions() && isQObject(metaClass)) {
c << "return PySide::getWrapperForQObject(reinterpret_cast<"
<< typeName << " *>(const_cast<void *>(cppIn)), " << cpythonType << ");\n";
} else {
- c << "auto pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(cppIn));\n"
- << "if (pyOut) {\n";
- {
- Indentation indent(c);
- c << "Py_INCREF(pyOut);\nreturn pyOut;\n";
- }
- c << "}\n"
- << "bool changedTypeName = false;\n"
- << "auto tCppIn = reinterpret_cast<const " << typeName << R"( *>(cppIn);
-const char *typeName = typeid(*tCppIn).name();
-auto sbkType = Shiboken::ObjectType::typeForTypeName(typeName);
-if (sbkType && Shiboken::ObjectType::hasSpecialCastFunction(sbkType)) {
- typeName = typeNameOf(tCppIn);
- changedTypeName = true;
-}
-)"
- << "PyObject *result = Shiboken::Object::newObject(" << cpythonType
- << R"(, const_cast<void *>(cppIn), false, /* exactType */ changedTypeName, typeName);
-if (changedTypeName)
- delete [] typeName;
-return result;)";
+ writePointerToPythonConverter(c, metaClass, typeName, cpythonType);
}
std::swap(targetTypeName, sourceTypeName);
writeCppToPythonFunction(s, c.toString(), sourceTypeName, targetTypeName);
// The conversions for an Object Type end here.
- if (!metaClass->typeEntry()->isValue() && !metaClass->typeEntry()->isSmartPointer()) {
+ if (!typeEntry->isValue() && !typeEntry->isSmartPointer()) {
s << '\n';
return;
}
// Always copies C++ value (not pointer, and not reference) to a new Python wrapper.
s << '\n' << "// C++ to Python copy conversion.\n";
- if (!classContext.forSmartPointer())
- targetTypeName = metaClass->name();
- else
- targetTypeName = classContext.preciseType().name();
+ targetTypeName = metaClass->name();
- sourceTypeName = targetTypeName + QLatin1String("_COPY");
+ sourceTypeName = targetTypeName + u"_COPY"_s;
c.clear();
- QString computedWrapperName;
- if (!classContext.forSmartPointer()) {
- computedWrapperName = classContext.useWrapper()
- ? classContext.wrapperName() : metaClass->qualifiedCppName();
+ const bool isUniquePointer = classContext.forSmartPointer()
+ && typeEntry->isUniquePointer();
+
+ if (isUniquePointer) {
+ c << "auto *source = reinterpret_cast<" << typeName
+ << " *>(const_cast<void *>(cppIn));\n";
} else {
- computedWrapperName = classContext.smartPointerWrapperName();
+ c << "auto *source = reinterpret_cast<const " << typeName << " *>(cppIn);\n";
}
-
c << "return Shiboken::Object::newObject(" << cpythonType
- << ", new ::" << computedWrapperName << "(*reinterpret_cast<const "
- << typeName << " *>(cppIn)), true, true);";
+ << ", new " << globalScopePrefix(classContext) << classContext.effectiveClassName() << '('
+ << (isUniquePointer ? "std::move(*source)" : "*source")
+ << "), true, true);";
writeCppToPythonFunction(s, c.toString(), sourceTypeName, targetTypeName);
s << '\n';
// Python to C++ copy conversion.
s << "// Python to C++ copy conversion.\n";
- if (!classContext.forSmartPointer())
- sourceTypeName = metaClass->name();
- else
- sourceTypeName = classContext.preciseType().name();
+ sourceTypeName = metaClass->name();
- targetTypeName = sourceTypeName + QStringLiteral("_COPY");
+ targetTypeName = sourceTypeName + "_COPY"_L1;
c.clear();
- QString pyInVariable = QLatin1String("pyIn");
- QString wrappedCPtrExpression;
- if (!classContext.forSmartPointer())
- wrappedCPtrExpression = cpythonWrapperCPtr(metaClass->typeEntry(), pyInVariable);
- else
- wrappedCPtrExpression = cpythonWrapperCPtr(classContext.preciseType(), pyInVariable);
+ QString pyInVariable = u"pyIn"_s;
+ const QString outPtr = u"reinterpret_cast<"_s + typeName + u" *>(cppOut)"_s;
+ if (!classContext.forSmartPointer()) {
+ c << '*' << outPtr << " = *"
+ << cpythonWrapperCPtr(typeEntry, pyInVariable) << ';';
+ } else {
+ auto ste = std::static_pointer_cast<const SmartPointerTypeEntry>(typeEntry);
+ const QString resetMethod = ste->resetMethod();
+ c << "auto *ptr = " << outPtr << ";\n";
+ c << "if (" << pyInVariable << " == Py_None)\n" << indent;
+ if (resetMethod.isEmpty())
+ c << "*ptr = {};\n";
+ else
+ c << "ptr->" << resetMethod << "();\n";
+ const QString value = u'*' + cpythonWrapperCPtr(classContext.preciseType(), pyInVariable);
+ c << outdent << "else\n" << indent
+ << "*ptr = " << (isUniquePointer ? stdMove(value) : value) << ';';
+ }
- c << "*reinterpret_cast<" << typeName << " *>(cppOut) = *"
- << wrappedCPtrExpression << ';';
writePythonToCppFunction(s, c.toString(), sourceTypeName, targetTypeName);
// "Is convertible" function for the Python object to C++ value copy conversion.
- writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, pyTypeCheck);
+ QString copyTypeCheck = pyTypeCheck;
+ if (classContext.forSmartPointer())
+ copyTypeCheck.prepend(pyInVariable + u" == Py_None || "_s);
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, copyTypeCheck);
s << '\n';
// User provided implicit conversions.
- CustomConversion *customConversion = metaClass->typeEntry()->customConversion();
-
// Implicit conversions.
- AbstractMetaFunctionCList implicitConvs;
- if (!customConversion || !customConversion->replaceOriginalTargetToNativeConversions()) {
- const auto &allImplicitConvs = api().implicitConversions(metaClass->typeEntry());
- for (const auto &func : allImplicitConvs) {
- if (!func->isUserAdded())
- implicitConvs << func;
- }
- }
+ const AbstractMetaFunctionCList implicitConvs = implicitConversions(typeEntry);
if (!implicitConvs.isEmpty())
s << "// Implicit conversions.\n";
- AbstractMetaType targetType = buildAbstractMetaTypeFromAbstractMetaClass(metaClass);
- for (const auto &conv : qAsConst(implicitConvs)) {
+ AbstractMetaType targetType = AbstractMetaType::fromAbstractMetaClass(metaClass);
+ for (const auto &conv : std::as_const(implicitConvs)) {
if (conv->isModifiedRemoved())
continue;
@@ -1561,35 +1750,30 @@ return result;)";
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"));
+ const auto sourceClass = conv->ownerClass();
+ typeCheck = u"PyObject_TypeCheck(pyIn, "_s
+ + cpythonTypeNameExt(sourceClass->typeEntry()) + u')';
+ toCppConv = u'*' + cpythonWrapperCPtr(sourceClass->typeEntry(),
+ pyInVariable);
} else {
// Constructor that does implicit conversion.
- if (!conv->typeReplaced(1).isEmpty() || conv->isModifiedToArray(1))
+ const auto &firstArg = conv->arguments().constFirst();
+ if (firstArg.isTypeModified() || conv->isModifiedToArray(1))
continue;
- const AbstractMetaType sourceType = conv->arguments().constFirst().type();
- typeCheck = cpythonCheckFunction(sourceType);
- bool isUserPrimitiveWithoutTargetLangName = sourceType.isUserPrimitive()
- && sourceType.typeEntry()->targetLangApiName() == sourceType.typeEntry()->name();
- if (!sourceType.isWrapperType()
- && !isUserPrimitiveWithoutTargetLangName
- && !sourceType.typeEntry()->isEnum()
- && !sourceType.typeEntry()->isFlags()
- && !sourceType.typeEntry()->isContainer()) {
- typeCheck += QLatin1Char('(');
- }
+ const AbstractMetaType &sourceType = firstArg.type();
if (sourceType.isWrapperType()) {
- typeCheck += QLatin1String("pyIn)");
- toCppConv = (sourceType.referenceType() == LValueReference
- || !sourceType.isPointerToWrapperType())
- ? 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 (sourceType.referenceType() == LValueReference
+ || !sourceType.isPointerToWrapperType()) {
+ toCppConv = u" *"_s;
+ }
+ toCppConv += cpythonWrapperCPtr(sourceType.typeEntry(), pyInVariable);
+ }
+
+ typeCheck = cpythonCheckFunction(sourceType);
+ if (typeCheck.endsWith(u", ")) {
+ typeCheck += pyInVariable + u')';
+ } else if (typeCheck != u"true" && typeCheck != u"false") {
+ typeCheck += u'(' + pyInVariable + u')';
}
if (sourceType.isUserPrimitive()
@@ -1598,81 +1782,81 @@ return result;)";
|| sourceType.typeEntry()->isEnum()
|| sourceType.typeEntry()->isFlags()) {
StringStream pc(TextStream::Language::Cpp);
- pc << getFullTypeNameWithoutModifiers(sourceType) << " cppIn";
- writeMinimalConstructorExpression(pc, api(), sourceType);
- pc << ";\n";
- writeToCppConversion(pc, sourceType, nullptr, QLatin1String("pyIn"), QLatin1String("cppIn"));
+ pc << getFullTypeNameWithoutModifiers(sourceType) << " cppIn"
+ << minimalConstructorExpression(api(), sourceType) << ";\n";
+ writeToCppConversion(pc, sourceType, pyInVariable,
+ u"cppIn"_s);
pc << ';';
toCppPreConv = pc.toString();
- toCppConv.append(QLatin1String("cppIn"));
+ toCppConv.append(u"cppIn"_s);
} else if (!sourceType.isWrapperType()) {
StringStream tcc(TextStream::Language::Cpp);
- writeToCppConversion(tcc, sourceType, metaClass, QLatin1String("pyIn"), QLatin1String("/*BOZO-1061*/"));
+ writeToCppConversion(tcc, sourceType, pyInVariable,
+ u"/*BOZO-1061*/"_s);
toCppConv = tcc.toString();
}
}
const AbstractMetaType sourceType = conv->isConversionOperator()
- ? buildAbstractMetaTypeFromAbstractMetaClass(conv->ownerClass())
+ ? AbstractMetaType::fromAbstractMetaClass(conv->ownerClass())
: conv->arguments().constFirst().type();
writePythonToCppConversionFunctions(s, sourceType, targetType, typeCheck, toCppConv, toCppPreConv);
}
- writeCustomConverterFunctions(s, customConversion);
+ if (typeEntry->isValue()) {
+ auto vte = std::static_pointer_cast<const ValueTypeEntry>(typeEntry);
+ writeCustomConverterFunctions(s, vte->customConversion());
+ }
}
void CppGenerator::writeCustomConverterFunctions(TextStream &s,
- const CustomConversion *customConversion) const
+ const CustomConversionPtr &customConversion) const
{
if (!customConversion)
return;
- const CustomConversion::TargetToNativeConversions &toCppConversions = customConversion->targetToNativeConversions();
+ const 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());
+ auto ownerType = customConversion->ownerType();
+ s << "// Python to C++ conversions for type '" << ownerType->qualifiedCppName() << "'.\n";
+ for (const auto &toNative : toCppConversions)
+ writePythonToCppConversionFunctions(s, toNative, ownerType);
s << '\n';
}
-void CppGenerator::writeConverterRegister(TextStream &s, const AbstractMetaClass *metaClass,
+void CppGenerator::writeConverterRegister(TextStream &s, const AbstractMetaClassCPtr &metaClass,
const GeneratorContext &classContext) const
{
- if (metaClass->isNamespace())
+ const auto typeEntry = metaClass->typeEntry();
+ if (typeEntry->isNamespace())
return;
s << "// Register Converter\n"
- << "SbkConverter *converter = Shiboken::Conversions::createConverter("
- << cpythonTypeName(metaClass) << ',' << '\n';
- {
- Indentation indent(s);
- QString sourceTypeName = metaClass->name();
- QString targetTypeName = sourceTypeName + QLatin1String("_PTR");
- s << pythonToCppFunctionName(sourceTypeName, targetTypeName) << ',' << '\n'
- << convertibleToCppFunctionName(sourceTypeName, targetTypeName) << ',' << '\n';
- std::swap(targetTypeName, sourceTypeName);
+ << "SbkConverter *converter = Shiboken::Conversions::createConverter(pyType,\n"
+ << indent;
+ QString sourceTypeName = metaClass->name();
+ QString targetTypeName = sourceTypeName + u"_PTR"_s;
+ s << pythonToCppFunctionName(sourceTypeName, targetTypeName) << ',' << '\n'
+ << convertibleToCppFunctionName(sourceTypeName, targetTypeName) << ',' << '\n';
+ std::swap(targetTypeName, sourceTypeName);
+ s << cppToPythonFunctionName(sourceTypeName, targetTypeName);
+ if (typeEntry->isValue() || typeEntry->isSmartPointer()) {
+ s << ',' << '\n';
+ sourceTypeName = metaClass->name() + u"_COPY"_s;
s << cppToPythonFunctionName(sourceTypeName, targetTypeName);
- if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) {
- s << ',' << '\n';
- sourceTypeName = metaClass->name() + QLatin1String("_COPY");
- s << cppToPythonFunctionName(sourceTypeName, targetTypeName);
- }
}
- s << ");\n";
-
- s << '\n';
+ s << outdent << ");\n\n";
auto writeConversions = [&s](const QString &signature)
{
- s << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "\");\n"
- << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "*\");\n"
- << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "&\");\n";
+ s << registerConverterName(signature) << registerConverterName(signature + u'*')
+ << registerConverterName(signature + u'&');
};
auto writeConversionsForType = [writeConversions](const QString &fullTypeName)
{
- QStringList lst = fullTypeName.split(QLatin1String("::"),
+ QStringList lst = fullTypeName.split(u"::"_s,
Qt::SkipEmptyParts);
while (!lst.isEmpty()) {
- QString signature = lst.join(QLatin1String("::"));
+ QString signature = lst.join(u"::"_s);
writeConversions(signature);
lst.removeFirst();
}
@@ -1685,18 +1869,18 @@ void CppGenerator::writeConverterRegister(TextStream &s, const AbstractMetaClass
const QString &smartPointerType = classContext.preciseType().instantiations().at(0).cppSignature();
const QString &smartPointerName = classContext.preciseType().typeEntry()->name();
- QStringList lst = smartPointerType.split(QLatin1String("::"),
+ QStringList lst = smartPointerType.split(u"::"_s,
Qt::SkipEmptyParts);
while (!lst.isEmpty()) {
- QString signature = lst.join(QLatin1String("::"));
- writeConversions(QStringLiteral("%1<%2 >").arg(smartPointerName, signature));
+ QString signature = lst.join(u"::"_s);
+ writeConversions(smartPointerName + u'<' + signature + u'>');
lst.removeFirst();
}
writeConversionsForType(smartPointerType);
}
- s << "Shiboken::Conversions::registerConverterName(converter, typeid(::";
+ s << "Shiboken::Conversions::registerConverterName(converter, typeid(" << m_gsp;
QString qualifiedCppNameInvocation;
if (!classContext.forSmartPointer())
qualifiedCppNameInvocation = metaClass->qualifiedCppName();
@@ -1706,70 +1890,66 @@ void CppGenerator::writeConverterRegister(TextStream &s, const AbstractMetaClass
s << qualifiedCppNameInvocation << ").name());\n";
if (classContext.useWrapper()) {
- s << "Shiboken::Conversions::registerConverterName(converter, typeid(::"
+ s << "Shiboken::Conversions::registerConverterName(converter, typeid("
<< classContext.wrapperName() << ").name());\n";
}
- s << '\n';
-
- if (!metaClass->typeEntry()->isValue() && !metaClass->typeEntry()->isSmartPointer())
+ if (!typeEntry->isValue() && !typeEntry->isSmartPointer())
return;
// Python to C++ copy (value, not pointer neither reference) conversion.
- s << "// Add Python to C++ copy (value, not pointer neither reference) conversion to type converter.\n";
- QString sourceTypeName = metaClass->name();
- QString targetTypeName = sourceTypeName + QLatin1String("_COPY");
+ s << "\n// Add Python to C++ copy (value, not pointer neither reference) conversion to type converter.\n";
+ sourceTypeName = metaClass->name();
+ targetTypeName = sourceTypeName + u"_COPY"_s;
QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName);
QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName);
- writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
+ writeAddPythonToCppConversion(s, u"converter"_s, toCpp, isConv);
// User provided implicit conversions.
- CustomConversion *customConversion = metaClass->typeEntry()->customConversion();
// Add implicit conversions.
- AbstractMetaFunctionCList implicitConvs;
- if (!customConversion || !customConversion->replaceOriginalTargetToNativeConversions()) {
- const auto &allImplicitConvs = api().implicitConversions(metaClass->typeEntry());
- for (const auto &func : allImplicitConvs) {
- if (!func->isUserAdded())
- implicitConvs << func;
- }
- }
+ const AbstractMetaFunctionCList implicitConvs = implicitConversions(typeEntry);
if (!implicitConvs.isEmpty())
s << "// Add implicit conversions to type converter.\n";
- AbstractMetaType targetType = buildAbstractMetaTypeFromAbstractMetaClass(metaClass);
- for (const auto &conv : qAsConst(implicitConvs)) {
+ AbstractMetaType targetType = AbstractMetaType::fromAbstractMetaClass(metaClass);
+ for (const auto &conv : std::as_const(implicitConvs)) {
if (conv->isModifiedRemoved())
continue;
AbstractMetaType sourceType;
if (conv->isConversionOperator()) {
- sourceType = buildAbstractMetaTypeFromAbstractMetaClass(conv->ownerClass());
+ sourceType = AbstractMetaType::fromAbstractMetaClass(conv->ownerClass());
} else {
// Constructor that does implicit conversion.
- if (!conv->typeReplaced(1).isEmpty() || conv->isModifiedToArray(1))
+ const auto &firstArg = conv->arguments().constFirst();
+ if (firstArg.isTypeModified() || conv->isModifiedToArray(1))
continue;
- sourceType = conv->arguments().constFirst().type();
+ sourceType = firstArg.type();
}
QString toCpp = pythonToCppFunctionName(sourceType, targetType);
QString isConv = convertibleToCppFunctionName(sourceType, targetType);
- writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
+ writeAddPythonToCppConversion(s, u"converter"_s, toCpp, isConv);
}
- writeCustomConverterRegister(s, customConversion, QLatin1String("converter"));
+ if (typeEntry->isValue()) {
+ auto vte = std::static_pointer_cast<const ValueTypeEntry>(typeEntry);
+ writeCustomConverterRegister(s, vte->customConversion(), u"converter"_s);
+ }
}
-void CppGenerator::writeCustomConverterRegister(TextStream &s, const CustomConversion *customConversion,
+void CppGenerator::writeCustomConverterRegister(TextStream &s,
+ const CustomConversionPtr &customConversion,
const QString &converterVar)
{
if (!customConversion)
return;
- const CustomConversion::TargetToNativeConversions &toCppConversions = customConversion->targetToNativeConversions();
+ const TargetToNativeConversions &toCppConversions =
+ customConversion->targetToNativeConversions();
if (toCppConversions.isEmpty())
return;
s << "// Add user defined implicit conversions to type converter.\n";
- for (CustomConversion::TargetToNativeConversion *toNative : toCppConversions) {
+ for (const auto &toNative : toCppConversions) {
QString toCpp = pythonToCppFunctionName(toNative, customConversion->ownerType());
QString isConv = convertibleToCppFunctionName(toNative, customConversion->ownerType());
writeAddPythonToCppConversion(s, converterVar, toCpp, isConv);
@@ -1783,38 +1963,25 @@ void CppGenerator::writeContainerConverterFunctions(TextStream &s,
writePythonToCppConversionFunctions(s, containerType);
}
-void CppGenerator::writeSmartPointerConverterFunctions(TextStream &s,
- const AbstractMetaType &smartPointerType) const
+bool CppGenerator::needsArgumentErrorHandling(const OverloadData &overloadData)
{
- auto targetClass = AbstractMetaClass::findClass(api().classes(),
- smartPointerType.instantiations().at(0).typeEntry());
-
- if (targetClass) {
- const auto *smartPointerTypeEntry =
- static_cast<const SmartPointerTypeEntry *>(
- smartPointerType.typeEntry());
-
- // TODO: Missing conversion to smart pointer pointer type:
-
- s << "// Register smartpointer conversion for all derived classes\n";
- const auto classes = targetClass->typeSystemBaseClasses();
- for (auto k : classes) {
- if (smartPointerTypeEntry->matchesInstantiation(k->typeEntry())) {
- if (auto smartTargetType = findSmartPointerInstantiation(k->typeEntry())) {
- s << "// SmartPointer derived class: "
- << smartTargetType->cppSignature() << "\n";
- writePythonToCppConversionFunctions(s, smartPointerType, smartTargetType.value(), {}, {}, {});
- }
- }
- }
- }
+ if (overloadData.maxArgs() > 0)
+ return true;
+ // QObject constructors need error handling when passing properties as kwarg.
+ if (!usePySideExtensions())
+ return false;
+ auto rfunc = overloadData.referenceFunction();
+ return rfunc->functionType() == AbstractMetaFunction::ConstructorFunction
+ && isQObject(rfunc->ownerClass());
}
-void CppGenerator::writeMethodWrapperPreamble(TextStream &s, OverloadData &overloadData,
- const GeneratorContext &context) const
+void CppGenerator::writeMethodWrapperPreamble(TextStream &s,
+ const OverloadData &overloadData,
+ const GeneratorContext &context,
+ ErrorReturn errorReturn)
{
const auto rfunc = overloadData.referenceFunction();
- const AbstractMetaClass *ownerClass = rfunc->targetLangOwner();
+ const auto ownerClass = rfunc->targetLangOwner();
Q_ASSERT(ownerClass == context.metaClass());
int minArgs = overloadData.minArgs();
int maxArgs = overloadData.maxArgs();
@@ -1824,32 +1991,31 @@ void CppGenerator::writeMethodWrapperPreamble(TextStream &s, OverloadData &overl
if (rfunc->isConstructor()) {
// Check if the right constructor was called.
if (!ownerClass->hasPrivateDestructor()) {
- s << "if (Shiboken::Object::isUserType(self) && !Shiboken::ObjectType::canCallConstructor(self->ob_type, Shiboken::SbkType< ::";
+ s << "if (Shiboken::Object::isUserType(self) && "
+ << "!Shiboken::ObjectType::canCallConstructor(self->ob_type, Shiboken::SbkType< "
+ << m_gsp;
QString qualifiedCppName;
if (!context.forSmartPointer())
qualifiedCppName = ownerClass->qualifiedCppName();
else
qualifiedCppName = context.preciseType().cppSignature();
- s << qualifiedCppName << " >()))\n";
- Indentation indent(s);
- s << returnStatement(m_currentErrorCode) << '\n' << '\n';
+ s << qualifiedCppName << " >()))\n" << indent << errorReturn << outdent << '\n';
}
// Declare pointer for the underlying C++ object.
- s << "::";
- if (!context.forSmartPointer()) {
- s << (context.useWrapper() ? context.wrapperName() : ownerClass->qualifiedCppName());
- } else {
- s << context.smartPointerWrapperName();
- }
- s << " *cptr{};\n";
+ s << globalScopePrefix(context) << context.effectiveClassName() << " *cptr{};\n";
initPythonArguments = maxArgs > 0;
} else {
if (rfunc->implementingClass() &&
(!rfunc->implementingClass()->isNamespace() && overloadData.hasInstanceFunction())) {
- writeCppSelfDefinition(s, rfunc, context, overloadData.hasStaticFunction());
+ CppSelfDefinitionFlags flags;
+ if (overloadData.hasStaticFunction())
+ flags.setFlag(CppSelfDefinitionFlag::HasStaticOverload);
+ if (overloadData.hasClassMethod())
+ flags.setFlag(CppSelfDefinitionFlag::HasClassMethodOverload);
+ writeCppSelfDefinition(s, rfunc, context, errorReturn, flags);
}
if (!rfunc->isInplaceOperator() && overloadData.hasNonVoidReturnType())
s << "PyObject *" << PYTHON_RETURN_VAR << "{};\n";
@@ -1857,80 +2023,83 @@ void CppGenerator::writeMethodWrapperPreamble(TextStream &s, OverloadData &overl
initPythonArguments = minArgs != maxArgs || maxArgs > 1;
}
- s << R"(Shiboken::AutoDecRef errInfo{};
-static const char *fullName = ")" << fullPythonFunctionName(rfunc, true)
- << "\";\nSBK_UNUSED(fullName)\n";
+ if (needsArgumentErrorHandling(overloadData))
+ s << "Shiboken::AutoDecRef errInfo{};\n";
+
+ s << "static const char fullName[] = \"" << fullPythonFunctionName(rfunc, true)
+ << "\";\nSBK_UNUSED(fullName)\n"
+ << "Shiboken::PythonContextMarker pcm;\n";
+ // PYSIDE-2335: Mark blocking calls like `exec` or `run` as such.
+ bool isBlockingFunction = rfunc->name() == u"exec"_s || rfunc->name() == u"exec_"_s
+ || rfunc->name() == u"run"_s;
+ if (isBlockingFunction)
+ s << "pcm.setBlocking();\n";
+
if (maxArgs > 0) {
s << "int overloadId = -1;\n"
- << "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));
+ << PYTHON_TO_CPPCONVERSION_STRUCT << ' ' << PYTHON_TO_CPP_VAR;
+ if (overloadData.pythonFunctionWrapperUsesListOfArguments())
+ s << '[' << maxArgs << ']';
+ s << ";\n" << sbkUnusedVariableCast(PYTHON_TO_CPP_VAR);
}
if (initPythonArguments) {
s << "const Py_ssize_t numArgs = ";
- if (minArgs == 0 && maxArgs == 1 && !rfunc->isConstructor() && !pythonFunctionWrapperUsesListOfArguments(overloadData))
+ if (minArgs == 0 && maxArgs == 1 && !rfunc->isConstructor()
+ && !overloadData.pythonFunctionWrapperUsesListOfArguments()) {
s << "(" << PYTHON_ARG << " == 0 ? 0 : 1);\n";
- else
- writeArgumentsInitializer(s, overloadData);
+ } else {
+ writeArgumentsInitializer(s, overloadData, errorReturn);
+ }
}
}
-void CppGenerator::writeConstructorWrapper(TextStream &s, const AbstractMetaFunctionCList &overloads,
+void CppGenerator::writeConstructorWrapper(TextStream &s, const OverloadData &overloadData,
const GeneratorContext &classContext) const
{
- ErrorCode errorCode(-1);
- OverloadData overloadData(overloads, api());
+ const ErrorReturn errorReturn = ErrorReturn::MinusOne;
const auto rfunc = overloadData.referenceFunction();
- const AbstractMetaClass *metaClass = rfunc->ownerClass();
+ const auto metaClass = rfunc->ownerClass();
s << "static int\n";
s << cpythonFunctionName(rfunc)
<< "(PyObject *self, PyObject *args, PyObject *kwds)\n{\n" << indent;
+ if (overloadData.maxArgs() == 0 || metaClass->isAbstract())
+ s << sbkUnusedVariableCast("args");
+ s << sbkUnusedVariableCast("kwds");
- const bool needsMetaObject = usePySideExtensions() && metaClass->isQObject();
+ const bool needsMetaObject = usePySideExtensions() && isQObject(metaClass);
if (needsMetaObject)
s << "const QMetaObject *metaObject;\n";
- s << "SbkObject *sbkSelf = reinterpret_cast<SbkObject *>(self);\n";
+ s << "auto *sbkSelf = reinterpret_cast<SbkObject *>(self);\n";
if (metaClass->isAbstract() || metaClass->baseClassNames().size() > 1) {
- s << "SbkObjectType *type = reinterpret_cast<SbkObjectType *>(self->ob_type);\n"
- << "SbkObjectType *myType = reinterpret_cast<SbkObjectType *>("
- << cpythonTypeNameExt(metaClass->typeEntry()) << ");\n";
+ s << "PyTypeObject *type = self->ob_type;\n"
+ << "PyTypeObject *myType = "
+ << cpythonTypeNameExt(metaClass->typeEntry()) << ";\n";
}
if (metaClass->isAbstract()) {
// C++ Wrapper disabled: Abstract C++ class cannot be instantiated.
if (metaClass->typeEntry()->typeFlags().testFlag(ComplexTypeEntry::DisableWrapper)) {
- writeUnusedVariableCast(s, QStringLiteral("sbkSelf"));
- writeUnusedVariableCast(s, QStringLiteral("type"));
- writeUnusedVariableCast(s, QStringLiteral("myType"));
+ s << sbkUnusedVariableCast("sbkSelf")
+ << sbkUnusedVariableCast("type")
+ << sbkUnusedVariableCast("myType");
if (needsMetaObject)
- writeUnusedVariableCast(s, QStringLiteral("metaObject"));
- s << "PyErr_SetString(PyExc_NotImplementedError,\n" << indent
- << "\"Abstract class '" << metaClass->qualifiedCppName()
- << "' cannot be instantiated since the wrapper has been disabled.\");\n" << outdent
- << returnStatement(m_currentErrorCode) << outdent
- << "\n}\n\n";
+ s << sbkUnusedVariableCast("metaObject");
+ s << "Shiboken::Errors::setInstantiateAbstractClassDisabledWrapper(\""
+ << metaClass->qualifiedCppName() << "\");\n" << errorReturn << outdent
+ << "}\n\n";
return;
}
// Refuse to instantiate Abstract C++ class (via C++ Wrapper) unless it is
// a Python-derived class for which type != myType.
s << "if (type == myType) {\n" << indent
- << "PyErr_SetString(PyExc_NotImplementedError,\n" << indent
- << "\"'" << metaClass->qualifiedCppName()
- << "' represents a C++ abstract class and cannot be instantiated\");\n" << outdent
- << returnStatement(m_currentErrorCode) << '\n' << outdent
+ << "Shiboken::Errors::setInstantiateAbstractClass(\"" << metaClass->qualifiedCppName()
+ << "\");\n" << errorReturn << outdent
<< "}\n\n";
}
@@ -1943,63 +2112,67 @@ void CppGenerator::writeConstructorWrapper(TextStream &s, const AbstractMetaFunc
}
// PYSIDE-1478: Switching must also happen at object creation time.
- if (usePySideExtensions())
+ if (usePySideExtensions() && !classContext.forSmartPointer())
s << "PySide::Feature::Select(self);\n";
- writeMethodWrapperPreamble(s, overloadData, classContext);
+ writeMethodWrapperPreamble(s, overloadData, classContext, errorReturn);
s << '\n';
if (overloadData.maxArgs() > 0)
- writeOverloadedFunctionDecisor(s, overloadData);
+ writeOverloadedFunctionDecisor(s, overloadData, errorReturn);
+
+ // Handles Python Multiple Inheritance
+ QString pre = needsMetaObject ? u"bool usesPyMI = "_s : u""_s;
+ s << "\n// PyMI support\n"
+ << pre << "Shiboken::callInheritedInit(self, args, kwds, fullName);\n"
+ << "if (" << shibokenErrorsOccurred << ")\n"
+ << indent << errorReturn << outdent << "\n";
- writeFunctionCalls(s, overloadData, classContext);
+ writeFunctionCalls(s, overloadData, classContext, errorReturn);
s << '\n';
- s << "if (PyErr_Occurred() || !Shiboken::Object::setCppPointer(sbkSelf, Shiboken::SbkType< ::"
- << metaClass->qualifiedCppName() << " >(), cptr)) {\n";
- {
- Indentation indent(s);
- s << "delete cptr;\n";
- s << returnStatement(m_currentErrorCode) << '\n';
- }
- s << "}\n";
+ const QString typeName = classContext.forSmartPointer()
+ ? classContext.preciseType().cppSignature() : metaClass->qualifiedCppName();
+ s << "if (" << shibokenErrorsOccurred
+ << " || !Shiboken::Object::setCppPointer(sbkSelf, Shiboken::SbkType< "
+ << globalScopePrefix(classContext) << typeName << " >(), cptr)) {\n"
+ << indent << "delete cptr;\n" << errorReturn << outdent
+ << "}\n";
if (overloadData.maxArgs() > 0)
- s << "if (!cptr) goto " << cpythonFunctionName(rfunc) << "_TypeError;\n\n";
+ s << "if (cptr == nullptr)\n" << indent
+ << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n\n"
+ << outdent;
s << "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()))
+ if (shouldGenerateCppWrapper(overloadData.referenceFunction()->ownerClass()))
s << "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 << "if (Shiboken::BindingManager::instance().hasWrapper(cptr)) {\n";
- {
- Indentation indent(s);
- s << "Shiboken::BindingManager::instance().releaseWrapper("
- "Shiboken::BindingManager::instance().retrieveWrapper(cptr));\n";
- }
- s << "}\nShiboken::BindingManager::instance().registerWrapper(sbkSelf, cptr);\n";
+ s << "if (Shiboken::BindingManager::instance().hasWrapper(cptr)) {\n" << indent
+ << "Shiboken::BindingManager::instance().releaseWrapper("
+ "Shiboken::BindingManager::instance().retrieveWrapper(cptr));\n" << outdent
+ << "}\nShiboken::BindingManager::instance().registerWrapper(sbkSelf, cptr);\n";
// Create metaObject and register signal/slot
- bool errHandlerNeeded = overloadData.maxArgs() > 0;
if (needsMetaObject) {
- errHandlerNeeded = true;
s << "\n// QObject setup\n"
<< "PySide::Signal::updateSourceObject(self);\n"
<< "metaObject = cptr->metaObject(); // <- init python qt properties\n"
<< "if (!errInfo.isNull() && PyDict_Check(errInfo.object())) {\n" << indent
- << "if (!PySide::fillQtProperties(self, metaObject, errInfo))\n" << indent
- << "goto " << cpythonFunctionName(rfunc) << "_TypeError;\n" << outdent << outdent
+ << "if (!PySide::fillQtProperties(self, metaObject, errInfo, usesPyMI))\n" << indent
+ << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n"
+ << outdent << outdent
<< "};\n";
}
// Constructor code injections, position=end
bool hasCodeInjectionsAtEnd = false;
- for (const auto &func : overloads) {
+ for (const auto &func : overloadData.overloads()) {
const CodeSnipList &injectedCodeSnips = func->injectedCodeSnips();
for (const CodeSnip &cs : injectedCodeSnips) {
if (cs.position == TypeSystem::CodeSnipPositionEnd) {
@@ -2010,125 +2183,104 @@ void CppGenerator::writeConstructorWrapper(TextStream &s, const AbstractMetaFunc
}
if (hasCodeInjectionsAtEnd) {
// FIXME: C++ arguments are not available in code injection on constructor when position = end.
- s <<"switch (overloadId) {\n";
- for (const auto &func : overloads) {
- Indentation indent(s);
+ s << "switch (overloadId) {\n";
+ for (const auto &func : overloadData.overloads()) {
+ s << indent;
const CodeSnipList &injectedCodeSnips = func->injectedCodeSnips();
for (const CodeSnip &cs : injectedCodeSnips) {
if (cs.position == TypeSystem::CodeSnipPositionEnd) {
s << "case " << metaClass->functions().indexOf(func) << ':' << '\n'
- << "{\n";
- {
- Indentation indent(s);
- writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode, func);
- }
- s << "}\nbreak;\n";
+ << "{\n" << indent;
+ writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionEnd,
+ TypeSystem::TargetLangCode, func,
+ true /* usesPyArgs */, nullptr);
+ s << outdent << "}\nbreak;\n";
break;
}
}
+ s << outdent;
}
s << "}\n";
}
s << "\n\nreturn 1;\n";
- if (errHandlerNeeded)
- writeErrorSection(s, overloadData);
s<< outdent << "}\n\n";
}
-void CppGenerator::writeMethodWrapper(TextStream &s, const AbstractMetaFunctionCList &overloads,
+void CppGenerator::writeMethodWrapper(TextStream &s, const OverloadData &overloadData,
const GeneratorContext &classContext) const
{
- OverloadData overloadData(overloads, api());
const auto rfunc = overloadData.referenceFunction();
int maxArgs = overloadData.maxArgs();
s << "static PyObject *";
s << cpythonFunctionName(rfunc) << "(PyObject *self";
+ bool hasKwdArgs = false;
if (maxArgs > 0) {
- s << ", PyObject *" << (pythonFunctionWrapperUsesListOfArguments(overloadData) ? "args" : PYTHON_ARG);
- if (overloadData.hasArgumentWithDefaultValue() || rfunc->isCallOperator())
+ s << ", PyObject *"
+ << (overloadData.pythonFunctionWrapperUsesListOfArguments() ? u"args"_s : PYTHON_ARG);
+ hasKwdArgs = overloadData.hasArgumentWithDefaultValue() || rfunc->isCallOperator();
+ if (hasKwdArgs)
s << ", PyObject *kwds";
}
s << ")\n{\n" << indent;
+ if (rfunc->ownerClass() == nullptr || overloadData.hasStaticFunction())
+ s << sbkUnusedVariableCast(PYTHON_SELF_VAR);
+ if (hasKwdArgs)
+ s << sbkUnusedVariableCast("kwds");
writeMethodWrapperPreamble(s, overloadData, classContext);
s << '\n';
- /*
- * 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();
-
- QScopedPointer<Indentation> reverseIndent;
-
- if (callExtendedReverseOperator) {
- QString revOpName = ShibokenGenerator::pythonOperatorFunctionName(rfunc).insert(2, QLatin1Char('r'));
+ // 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.
+ const bool hasReturnValue = overloadData.hasNonVoidReturnType();
+
+ if (hasReturnValue && rfunc->functionType() == AbstractMetaFunction::ShiftOperator
+ && rfunc->isBinaryOperator()) {
// For custom classes, operations like __radd__ and __rmul__
// will enter an infinite loop.
- if (rfunc->isBinaryOperator() && revOpName.contains(QLatin1String("shift"))) {
- s << "Shiboken::AutoDecRef attrName(Py_BuildValue(\"s\", \"" << revOpName << "\"));\n";
- s << "if (!isReverse\n";
- {
- Indentation indent(s);
- s << "&& Shiboken::Object::checkType(" << PYTHON_ARG << ")\n"
- << "&& !PyObject_TypeCheck(" << PYTHON_ARG << ", self->ob_type)\n"
- << "&& 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 << "PyObject *revOpMethod = PyObject_GetAttr(" << PYTHON_ARG << ", attrName);\n";
- s << "if (revOpMethod && PyCallable_Check(revOpMethod)) {\n";
- {
- Indentation indent(s);
- s << PYTHON_RETURN_VAR << " = PyObject_CallFunction(revOpMethod, \"O\", self);\n"
- << "if (PyErr_Occurred() && (PyErr_ExceptionMatches(PyExc_NotImplementedError)"
- << " || PyErr_ExceptionMatches(PyExc_AttributeError))) {\n";
- {
- Indentation indent(s);
- s << "PyErr_Clear();\n"
- << "Py_XDECREF(" << PYTHON_RETURN_VAR << ");\n"
- << PYTHON_RETURN_VAR << " = " << NULL_PTR << ";\n";
- }
- s << "}\n";
- }
- s << "}\n"
- << "Py_XDECREF(revOpMethod);\n\n";
- } //
- s << "}\n\n"
- << "// Do not enter here if other object has implemented a reverse operator.\n"
- << "if (!" << PYTHON_RETURN_VAR << ") {\n";
- reverseIndent.reset(new Indentation(s));
- } // binary shift operator
- }
-
- if (maxArgs > 0)
- writeOverloadedFunctionDecisor(s, overloadData);
-
- writeFunctionCalls(s, overloadData, classContext);
-
- if (!reverseIndent.isNull()) { // binary shift operator
- reverseIndent.reset();
- s << '\n' << "} // End of \"if (!" << PYTHON_RETURN_VAR << ")\"\n";
+ const QString pythonOp = ShibokenGenerator::pythonOperatorFunctionName(rfunc);
+ s << "static PyObject *attrName = Shiboken::PyMagicName::r"
+ << pythonOp.mid(2, pythonOp.size() -4) << "();\n" // Strip __
+ << "if (!isReverse\n" << indent
+ << "&& Shiboken::Object::checkType(" << PYTHON_ARG << ")\n"
+ << "&& !PyObject_TypeCheck(" << PYTHON_ARG << ", self->ob_type)\n"
+ << "&& PyObject_HasAttr(" << PYTHON_ARG << ", attrName)) {\n"
+ << "PyObject *revOpMethod = PyObject_GetAttr(" << PYTHON_ARG << ", attrName);\n"
+ << "if (revOpMethod && PyCallable_Check(revOpMethod)) {\n" << indent
+ << PYTHON_RETURN_VAR << " = PyObject_CallFunction(revOpMethod, \"O\", self);\n"
+ << "if (" << shibokenErrorsOccurred
+ << " && (PyErr_ExceptionMatches(PyExc_NotImplementedError)"
+ << " || PyErr_ExceptionMatches(PyExc_AttributeError))) {\n" << indent
+ << "PyErr_Clear();\n"
+ << "Py_XDECREF(" << PYTHON_RETURN_VAR << ");\n"
+ << PYTHON_RETURN_VAR << " = " << NULL_PTR << ";\n"
+ << outdent << "}\n"
+ << outdent << "}\n"
+ << "Py_XDECREF(revOpMethod);\n\n"
+ << outdent << "}\n\n"
+ << "// Do not enter here if other object has implemented a reverse operator.\n"
+ << "if (" << PYTHON_RETURN_VAR << " == nullptr) {\n" << indent;
+ if (maxArgs > 0)
+ writeOverloadedFunctionDecisor(s, overloadData, ErrorReturn::Default);
+ writeFunctionCalls(s, overloadData, classContext, ErrorReturn::Default);
+ s << outdent << '\n' << "} // End of \"if (!" << PYTHON_RETURN_VAR << ")\"\n";
+ } else { // binary shift operator
+ if (maxArgs > 0)
+ writeOverloadedFunctionDecisor(s, overloadData, ErrorReturn::Default);
+ writeFunctionCalls(s, overloadData, classContext, ErrorReturn::Default);
}
s << '\n';
- writeFunctionReturnErrorCheckSection(s, hasReturnValue && !rfunc->isInplaceOperator());
+ writeFunctionReturnErrorCheckSection(s, ErrorReturn::Default,
+ hasReturnValue && !rfunc->isInplaceOperator());
if (hasReturnValue) {
if (rfunc->isInplaceOperator()) {
@@ -2140,24 +2292,21 @@ void CppGenerator::writeMethodWrapper(TextStream &s, const AbstractMetaFunctionC
s << "Py_RETURN_NONE;\n";
}
- if (maxArgs > 0)
- writeErrorSection(s, overloadData);
-
s<< outdent << "}\n\n";
}
-void CppGenerator::writeArgumentsInitializer(TextStream &s, OverloadData &overloadData)
+void CppGenerator::writeArgumentsInitializer(TextStream &s, const OverloadData &overloadData,
+ ErrorReturn errorReturn)
{
const auto rfunc = overloadData.referenceFunction();
- s << "PyTuple_GET_SIZE(args);\n";
- writeUnusedVariableCast(s, QLatin1String("numArgs"));
+ s << "PyTuple_GET_SIZE(args);\n" << sbkUnusedVariableCast("numArgs");
int minArgs = overloadData.minArgs();
int maxArgs = overloadData.maxArgs();
s << "PyObject *";
s << PYTHON_ARGS << "[] = {"
- << QString(maxArgs, QLatin1Char('0')).split(QLatin1String(""), Qt::SkipEmptyParts).join(QLatin1String(", "))
+ << QByteArrayList(maxArgs, "nullptr").join(", ")
<< "};\n\n";
if (overloadData.hasVarargs()) {
@@ -2176,47 +2325,34 @@ void CppGenerator::writeArgumentsInitializer(TextStream &s, OverloadData &overlo
bool usesNamedArguments = overloadData.hasArgumentWithDefaultValue();
s << "// invalid argument lengths\n";
- bool ownerClassIsQObject = rfunc->ownerClass() && rfunc->ownerClass()->isQObject() && rfunc->isConstructor();
- if (usesNamedArguments) {
- if (!ownerClassIsQObject) {
- s << "if (numArgs > " << maxArgs << ") {\n";
- {
- Indentation indent(s);
- s << "static PyObject *const too_many = "
- "Shiboken::String::createStaticString(\">\");\n"
- << "errInfo.reset(too_many);\n"
- << "Py_INCREF(errInfo.object());\n"
- << "goto " << cpythonFunctionName(rfunc) << "_TypeError;\n";
- }
- s << '}';
- }
- if (minArgs > 0) {
- if (!ownerClassIsQObject)
- s << " else ";
- s << "if (numArgs < " << minArgs << ") {\n";
- {
- Indentation indent(s);
- s << "static PyObject *const too_few = "
- "Shiboken::String::createStaticString(\"<\");\n"
- << "errInfo.reset(too_few);\n"
- << "Py_INCREF(errInfo.object());\n"
- << "goto " << cpythonFunctionName(rfunc) << "_TypeError;\n";
- }
- s << '}';
- }
+
+ // Disable argument count checks for QObject constructors to allow for
+ // passing properties as KW args.
+ const auto owner = rfunc->ownerClass();
+ bool isQObjectConstructor = owner && isQObject(owner)
+ && rfunc->functionType() == AbstractMetaFunction::ConstructorFunction;
+
+ if (usesNamedArguments && !isQObjectConstructor) {
+ s << "errInfo.reset(Shiboken::checkInvalidArgumentCount(numArgs, "
+ << minArgs << ", " << maxArgs << "));\n"
+ << "if (!errInfo.isNull())\n" << indent
+ << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n"
+ << outdent;
}
+
const QList<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 ";
- s << "if (" << invArgsLen.join(QLatin1String(" || ")) << ")\n";
- Indentation indent(s);
- s << "goto " << cpythonFunctionName(rfunc) << "_TypeError;";
+ s << "if (";
+ for (qsizetype i = 0, size = invalidArgsLength.size(); i < size; ++i) {
+ if (i)
+ s << " || ";
+ s << "numArgs == " << invalidArgsLength.at(i);
+ }
+ s << ")\n" << indent
+ << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n"
+ << outdent;
}
- s << "\n\n";
+ s << '\n';
QString funcName;
if (rfunc->isOperatorOverload())
@@ -2224,8 +2360,8 @@ void CppGenerator::writeArgumentsInitializer(TextStream &s, OverloadData &overlo
else
funcName = rfunc->name();
- QString argsVar = overloadData.hasVarargs() ? QLatin1String("nonvarargs") : QLatin1String("args");
- s << "if (!";
+ QString argsVar = overloadData.hasVarargs() ? u"nonvarargs"_s : u"args"_s;
+ s << "if (";
if (usesNamedArguments) {
s << "PyArg_ParseTuple(" << argsVar << ", \"|" << QByteArray(maxArgs, 'O')
<< ':' << funcName << '"';
@@ -2235,182 +2371,187 @@ void CppGenerator::writeArgumentsInitializer(TextStream &s, OverloadData &overlo
}
for (int i = 0; i < maxArgs; i++)
s << ", &(" << PYTHON_ARGS << '[' << i << "])";
- s << "))\n";
- {
- Indentation indent(s);
- s << returnStatement(m_currentErrorCode) << '\n';
- }
- s << '\n';
+ s << ") == 0)\n" << indent << errorReturn << outdent << '\n';
}
void CppGenerator::writeCppSelfConversion(TextStream &s, const GeneratorContext &context,
const QString &className, bool useWrapperClass)
{
- static const QString pythonSelfVar = QLatin1String("self");
+ if (context.forSmartPointer()) {
+ writeSmartPointerCppSelfConversion(s, context);
+ return;
+ }
+
if (useWrapperClass)
s << "static_cast<" << className << " *>(";
- if (!context.forSmartPointer())
- s << cpythonWrapperCPtr(context.metaClass(), pythonSelfVar);
- else
- s << cpythonWrapperCPtr(context.preciseType(), pythonSelfVar);
+ s << cpythonWrapperCPtr(context.metaClass(), PYTHON_SELF_VAR);
if (useWrapperClass)
s << ')';
}
+void CppGenerator::writeCppSelfVarDef(TextStream &s,
+ CppSelfDefinitionFlags flags)
+{
+ if (flags.testFlag(CppGenerator::CppSelfAsReference))
+ s << "auto &" << CPP_SELF_VAR << " = *";
+ else
+ s << "auto *" << CPP_SELF_VAR << " = ";
+}
+
void CppGenerator::writeCppSelfDefinition(TextStream &s,
const GeneratorContext &context,
- bool hasStaticOverload,
- bool cppSelfAsReference) const
+ ErrorReturn errorReturn,
+ CppSelfDefinitionFlags flags)
{
- Q_ASSERT(!(cppSelfAsReference && hasStaticOverload));
+ Q_ASSERT(!(flags.testFlag(CppSelfAsReference) && flags.testFlag(HasStaticOverload)));
+ if (context.forSmartPointer()) {
+ writeSmartPointerCppSelfDefinition(s, context, errorReturn, flags);
+ return;
+ }
- const AbstractMetaClass *metaClass = context.metaClass();
+ AbstractMetaClassCPtr metaClass = context.metaClass();
const auto cppWrapper = context.metaClass()->cppWrapper();
// In the Python method, use the wrapper to access the protected
// functions.
const bool useWrapperClass = avoidProtectedHack()
&& cppWrapper.testFlag(AbstractMetaClass::CppProtectedHackWrapper);
Q_ASSERT(!useWrapperClass || context.useWrapper());
- QString className;
- if (!context.forSmartPointer()) {
- className = useWrapperClass
- ? context.wrapperName()
- : (QLatin1String("::") + metaClass->qualifiedCppName());
- } else {
- className = context.smartPointerWrapperName();
- }
+ const QString className = useWrapperClass
+ ? context.wrapperName() : getFullTypeName(metaClass);
- writeInvalidPyObjectCheck(s, QLatin1String("self"));
+ writeInvalidPyObjectCheck(s, PYTHON_SELF_VAR, errorReturn);
- if (cppSelfAsReference) {
- s << "auto &" << CPP_SELF_VAR << " = *";
+ if (flags.testFlag(CppSelfAsReference)) {
+ writeCppSelfVarDef(s, flags);
writeCppSelfConversion(s, context, className, useWrapperClass);
s << ";\n";
return;
}
- if (!hasStaticOverload) {
- s << "auto " << CPP_SELF_VAR << " = ";
- writeCppSelfConversion(s, context, className, useWrapperClass);
- s << ";\n";
- writeUnusedVariableCast(s, QLatin1String(CPP_SELF_VAR));
+ if (!flags.testFlag(HasStaticOverload)) {
+ if (!flags.testFlag(HasClassMethodOverload)) {
+ // PYSIDE-131: The single case of a class method for now: tr().
+ writeCppSelfVarDef(s, flags);
+ writeCppSelfConversion(s, context, className, useWrapperClass);
+ s << ";\n" << sbkUnusedVariableCast(CPP_SELF_VAR);
+ }
return;
}
- s << className << " *" << CPP_SELF_VAR << " = nullptr;\n";
- writeUnusedVariableCast(s, QLatin1String(CPP_SELF_VAR));
+ s << className << " *" << CPP_SELF_VAR << " = nullptr;\n"
+ << sbkUnusedVariableCast(CPP_SELF_VAR);
// Checks if the underlying C++ object is valid.
- s << "if (self)\n";
- {
- Indentation indent(s);
- s << CPP_SELF_VAR << " = ";
- writeCppSelfConversion(s, context, className, useWrapperClass);
- s << ";\n";
- }
+ s << "if (self)\n" << indent
+ << CPP_SELF_VAR << " = ";
+ writeCppSelfConversion(s, context, className, useWrapperClass);
+ s << ";\n"<< outdent;
}
void CppGenerator::writeCppSelfDefinition(TextStream &s,
const AbstractMetaFunctionCPtr &func,
const GeneratorContext &context,
- bool hasStaticOverload) const
+ ErrorReturn errorReturn,
+ CppSelfDefinitionFlags flags)
{
if (!func->ownerClass() || func->isConstructor())
return;
if (func->isOperatorOverload() && func->isBinaryOperator()) {
QString checkFunc = cpythonCheckFunction(func->ownerClass()->typeEntry());
- s << "bool isReverse = " << checkFunc << PYTHON_ARG << ")\n";
- {
- Indentation indent1(s, 4);
- s << "&& !" << checkFunc << "self);\n";
- }
- s << "if (isReverse)\n";
- Indentation indent(s);
- s << "std::swap(self, " << PYTHON_ARG << ");\n";
+ s << "bool isReverse = " << checkFunc << PYTHON_ARG << ")\n"
+ << " && !" << checkFunc << "self);\n"
+ << "if (isReverse)\n" << indent
+ << "std::swap(self, " << PYTHON_ARG << ");\n" << outdent;
}
- writeCppSelfDefinition(s, context, hasStaticOverload);
+ writeCppSelfDefinition(s, context, errorReturn, flags);
}
-void CppGenerator::writeErrorSection(TextStream &s, OverloadData &overloadData)
+QString CppGenerator::returnErrorWrongArguments(const OverloadData &overloadData,
+ ErrorReturn errorReturn)
{
const auto rfunc = overloadData.referenceFunction();
- s << '\n' << cpythonFunctionName(rfunc) << "_TypeError:\n";
- Indentation indentation(s);
- QString argsVar = pythonFunctionWrapperUsesListOfArguments(overloadData)
- ? QLatin1String("args") : QLatin1String(PYTHON_ARG);
- s << "Shiboken::setErrorAboutWrongArguments(" << argsVar << ", fullName, errInfo);\n"
- << "return " << m_currentErrorCode << ";\n";
+ QString argsVar = overloadData.pythonFunctionWrapperUsesListOfArguments()
+ ? u"args"_s : PYTHON_ARG;
+ switch (errorReturn) {
+ case ErrorReturn::Default:
+ return u"Shiboken::returnWrongArguments("_s + argsVar + u", fullName, errInfo)"_s;
+ case ErrorReturn::Zero:
+ return u"Shiboken::returnWrongArguments_Zero("_s + argsVar + u", fullName, errInfo)"_s;
+ case ErrorReturn::MinusOne:
+ return u"Shiboken::returnWrongArguments_MinusOne("_s + argsVar + u", fullName, errInfo)"_s;
+ case ErrorReturn::Void:
+ Q_ASSERT(false);
+ }
+ return {};
}
-void CppGenerator::writeFunctionReturnErrorCheckSection(TextStream &s, bool hasReturnValue)
+void CppGenerator::writeFunctionReturnErrorCheckSection(TextStream &s,
+ ErrorReturn errorReturn,
+ bool hasReturnValue)
{
- s << "if (PyErr_Occurred()";
+ s << "if (" << shibokenErrorsOccurred;
if (hasReturnValue)
- s << " || !" << PYTHON_RETURN_VAR;
- s << ") {\n";
- {
- Indentation indent(s);
- if (hasReturnValue)
- s << "Py_XDECREF(" << PYTHON_RETURN_VAR << ");\n";
- s << returnStatement(m_currentErrorCode) << '\n';
- }
- s << "}\n";
+ s << " || " << PYTHON_RETURN_VAR << " == nullptr";
+ s << ") {\n" << indent;
+ if (hasReturnValue)
+ s << "Py_XDECREF(" << PYTHON_RETURN_VAR << ");\n";
+ s << errorReturn << outdent << "}\n";
}
-void CppGenerator::writeInvalidPyObjectCheck(TextStream &s, const QString &pyObj)
+void CppGenerator::writeInvalidPyObjectCheck(TextStream &s, const QString &pyObj,
+ ErrorReturn errorReturn)
{
- s << "if (!Shiboken::Object::isValid(" << pyObj << "))\n";
- Indentation indent(s);
- s << returnStatement(m_currentErrorCode) << '\n';
+ s << "if (!Shiboken::Object::isValid(" << pyObj << "))\n"
+ << indent << errorReturn << outdent;
}
static QString pythonToCppConverterForArgumentName(const QString &argumentName)
{
- static const QRegularExpression pyArgsRegex(QLatin1String(PYTHON_ARGS)
- + QLatin1String(R"((\[\d+[-]?\d*\]))"));
+ static const QRegularExpression pyArgsRegex(PYTHON_ARGS
+ + uR"((\[\d+[-]?\d*\]))"_s);
Q_ASSERT(pyArgsRegex.isValid());
const QRegularExpressionMatch match = pyArgsRegex.match(argumentName);
- QString result = QLatin1String(PYTHON_TO_CPP_VAR);
+ QString result = PYTHON_TO_CPP_VAR;
if (match.hasMatch())
result += match.captured(1);
return result;
}
-void CppGenerator::writeTypeCheck(TextStream &s, AbstractMetaType argType,
- const QString &argumentName, bool isNumber,
- const QString &customType, bool rejectNull) const
+void CppGenerator::writeTypeCheck(TextStream &s, const QString &customType,
+ const QString &argumentName)
{
- 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.
- auto customCheckResult = guessCPythonCheckFunction(customType);
- customCheck = customCheckResult.checkFunction;
- if (customCheckResult.type.has_value())
- argType = customCheckResult.type.value();
- }
+ QString errorMessage;
+ const auto metaTypeOpt = AbstractMetaType::fromString(customType, &errorMessage);
+ if (!metaTypeOpt.has_value())
+ throw Exception(errorMessage);
+ writeTypeCheck(s, metaTypeOpt.value(), argumentName,
+ ShibokenGenerator::isNumber(metaTypeOpt.value()));
+}
+void CppGenerator::writeTypeCheck(TextStream &s, const AbstractMetaType &argType,
+ const QString &argumentName, bool isNumber,
+ bool rejectNull)
+{
// 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));
+ QString typeCheck = cpythonIsConvertibleFunction(argType);
+ if (typeCheck != u"true") // For PyObject, which is always true
+ typeCheck.append(u'(' +argumentName + u')');
// 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));
+ if (!argType.typeEntry()->isCustom()) {
+ typeCheck = u'(' + pythonToCppConverterForArgumentName(argumentName)
+ + u" = "_s + typeCheck + u"))"_s;
+ if (!isNumber && isCppPrimitive(argType.typeEntry())) {
+ typeCheck.prepend(cpythonCheckFunction(argType) + u'('
+ + argumentName + u") && "_s);
+ }
}
// TODO-CONVERTER -----------------------------------------------------------------------
if (rejectNull)
- typeCheck = QString::fromLatin1("(%1 != Py_None && %2)").arg(argumentName, typeCheck);
+ typeCheck = u'(' + argumentName + u" != Py_None && "_s + typeCheck + u')';
s << typeCheck;
}
@@ -2418,14 +2559,20 @@ void CppGenerator::writeTypeCheck(TextStream &s, AbstractMetaType argType,
static void checkTypeViability(const AbstractMetaFunctionCPtr &func,
const AbstractMetaType &type, int argIdx)
{
+ const bool modified = argIdx == 0
+ ? func->isTypeModified()
+ : func->arguments().at(argIdx -1).isTypeModified();
+ const bool isRemoved = argIdx == 0
+ ? func->argumentRemoved(0)
+ : func->arguments().at(argIdx -1).isModifiedRemoved();
if (type.isVoid()
|| !type.typeEntry()->isPrimitive()
|| type.indirections() == 0
|| (type.indirections() == 1 && type.typeUsagePattern() == AbstractMetaType::NativePointerAsArrayPattern)
|| type.isCString()
- || func->argumentRemoved(argIdx)
- || !func->typeReplaced(argIdx).isEmpty()
- || !func->conversionRule(TypeSystem::All, argIdx).isEmpty()
+ || isRemoved
+ || modified
+ || func->hasConversionRule(TypeSystem::All, argIdx)
|| func->hasInjectedCode())
return;
QString message;
@@ -2449,19 +2596,20 @@ static void checkTypeViability(const AbstractMetaFunctionCPtr &func)
if (func->isUserAdded())
return;
checkTypeViability(func, func->type(), 0);
- for (int i = 0; i < func->arguments().count(); ++i)
- checkTypeViability(func, func->arguments().at(i).type(), i + 1);
+ for (qsizetype i = 0; i < func->arguments().size(); ++i)
+ checkTypeViability(func, func->arguments().at(i).type(), int(i + 1));
}
-void CppGenerator::writeTypeCheck(TextStream &s, const OverloadData *overloadData,
- const QString &argumentName) const
+void CppGenerator::writeTypeCheck(TextStream &s,
+ const std::shared_ptr<OverloadDataNode> &overloadData,
+ const QString &argumentName)
{
- QSet<const TypeEntry *> numericTypes;
- const OverloadDataList &overloads = overloadData->previousOverloadData()->nextOverloadData();
- for (OverloadData *od : overloads) {
- for (const auto &func : od->overloads()) {
+ QSet<TypeEntryCPtr> numericTypes;
+ const OverloadDataList &siblings = overloadData->parent()->children();
+ for (const auto &sibling : siblings) {
+ for (const auto &func : sibling->overloads()) {
checkTypeViability(func);
- const AbstractMetaType &argType = od->argument(func)->type();
+ const AbstractMetaType &argType = sibling->overloadArgument(func)->type();
if (!argType.isPrimitive())
continue;
if (ShibokenGenerator::isNumber(argType.typeEntry()))
@@ -2470,140 +2618,139 @@ void CppGenerator::writeTypeCheck(TextStream &s, const OverloadData *overloadDat
}
// 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)
- AbstractMetaType argType = overloadData->argType();
+ // PyLong type to come after the more precise numeric types (e.g. float and bool)
+ AbstractMetaType argType = overloadData->modifiedArgType();
if (auto viewOn = argType.viewOn())
argType = *viewOn;
- bool numberType = numericTypes.count() == 1 || ShibokenGenerator::isPyInt(argType);
- QString customType = (overloadData->hasArgumentTypeReplace() ? overloadData->argumentTypeReplaced() : QString());
+ const bool numberType = numericTypes.size() == 1 || ShibokenGenerator::isPyInt(argType);
bool rejectNull =
- shouldRejectNullPointerArgument(api(), overloadData->referenceFunction(), overloadData->argPos());
- writeTypeCheck(s, argType, argumentName, numberType, customType, rejectNull);
+ shouldRejectNullPointerArgument(overloadData->referenceFunction(), overloadData->argPos());
+ writeTypeCheck(s, argType, argumentName, numberType, rejectNull);
}
-void CppGenerator::writeArgumentConversion(TextStream &s,
- const AbstractMetaType &argType,
- const QString &argName, const QString &pyArgName,
- const AbstractMetaClass *context,
- const QString &defaultValue,
- bool castArgumentAsUnused) const
+qsizetype CppGenerator::writeArgumentConversion(TextStream &s,
+ const AbstractMetaType &argType,
+ const QString &argName,
+ const QString &pyArgName,
+ ErrorReturn errorReturn,
+ const AbstractMetaClassCPtr &context,
+ const QString &defaultValue,
+ bool castArgumentAsUnused) const
{
+ qsizetype result = 0;
if (argType.typeEntry()->isCustom() || argType.typeEntry()->isVarargs())
- return;
+ return result;
if (argType.isWrapperType())
- writeInvalidPyObjectCheck(s, pyArgName);
- writePythonToCppTypeConversion(s, argType, pyArgName, argName, context, defaultValue);
+ writeInvalidPyObjectCheck(s, pyArgName, errorReturn);
+ result = writePythonToCppTypeConversion(s, argType, pyArgName, argName, context, defaultValue);
if (castArgumentAsUnused)
- writeUnusedVariableCast(s, argName);
-}
-
-static const QStringList &knownPythonTypes()
-{
- static const QStringList result = {
- pyBoolT(), pyIntT(), pyFloatT(), pyLongT(),
- cPyObjectT(), QLatin1String("PyString"),
- cPyBufferT(), cPySequenceT(),
- QLatin1String("PyTuple"), cPyListT(),
- QLatin1String("PyDict"), QLatin1String("PyObject*"),
- QLatin1String("PyObject *"), QLatin1String("PyTupleObject*")};
+ s << sbkUnusedVariableCast(argName);
return result;
}
-std::optional<AbstractMetaType>
- CppGenerator::getArgumentType(const AbstractMetaFunctionCPtr &func, int argPos)
+AbstractMetaType
+ CppGenerator::getArgumentType(const AbstractMetaFunctionCPtr &func, int index)
{
- if (argPos < 0 || argPos > func->arguments().size()) {
+ if (index < 0 || index >= func->arguments().size()) {
qCWarning(lcShiboken).noquote().nospace()
- << QStringLiteral("Argument index for function '%1' out of range.").arg(func->signature());
+ << "Argument index for function '" << func->signature() << "' out of range.";
return {};
}
- QString typeReplaced = func->typeReplaced(argPos);
- if (typeReplaced.isEmpty()) {
- if (argPos == 0)
- return func->type();
- auto argType = func->arguments().at(argPos - 1).type();
- return argType.viewOn() ? *argType.viewOn() : argType;
- }
-
- auto argType = buildAbstractMetaTypeFromString(typeReplaced);
- if (!argType.has_value() && !knownPythonTypes().contains(typeReplaced)) {
- qCWarning(lcShiboken, "%s",
- qPrintable(msgUnknownTypeInArgumentTypeReplacement(typeReplaced, func.data())));
- }
- return argType;
+ auto argType = func->arguments().at(index).modifiedType();
+ return argType.viewOn() ? *argType.viewOn() : argType;
}
static inline QString arrayHandleType(const AbstractMetaTypeList &nestedArrayTypes)
{
switch (nestedArrayTypes.size()) {
case 1:
- return QStringLiteral("Shiboken::Conversions::ArrayHandle<")
- + nestedArrayTypes.constLast().minimalSignature()
- + QLatin1Char('>');
+ return "Shiboken::Conversions::ArrayHandle<"_L1
+ + nestedArrayTypes.constLast().minimalSignature() + u'>';
case 2:
- return QStringLiteral("Shiboken::Conversions::Array2Handle<")
+ return "Shiboken::Conversions::Array2Handle<"_L1
+ nestedArrayTypes.constLast().minimalSignature()
- + QStringLiteral(", ")
+ + ", "_L1
+ QString::number(nestedArrayTypes.constFirst().arrayElementCount())
- + QLatin1Char('>');
+ + u'>';
}
return QString();
}
-void CppGenerator::writePythonToCppTypeConversion(TextStream &s,
+// Helper to write argument initialization code for a function argument
+// in case it has a default value.
+template <class Type> // AbstractMetaType/TypeEntry
+static void writeMinimalConstructorExpression(TextStream &s,
+ const ApiExtractorResult &api,
+ Type type,
+ bool isPrimitive,
+ const QString &defaultValue)
+{
+ if (defaultValue.isEmpty()) {
+ s << ShibokenGenerator::minimalConstructorExpression(api, type);
+ return;
+ }
+ // Use assignment to avoid "Most vexing parse" if it looks like
+ // a function call, or for primitives/pointers
+ const bool isDefault = defaultValue == u"{}";
+ if ((isPrimitive && !isDefault)
+ || defaultValue == u"nullptr" || defaultValue.contains(u'(')) {
+ s << " = " << defaultValue;
+ return;
+ }
+ if (isDefault) {
+ s << defaultValue;
+ return;
+ }
+ s << '(' << defaultValue << ')';
+}
+
+qsizetype CppGenerator::writePythonToCppTypeConversion(TextStream &s,
const AbstractMetaType &type,
const QString &pyIn,
const QString &cppOut,
- const AbstractMetaClass *context,
+ const AbstractMetaClassCPtr &context,
const QString &defaultValue) const
{
- const TypeEntry *typeEntry = type.typeEntry();
+ TypeEntryCPtr typeEntry = type.typeEntry();
if (typeEntry->isCustom() || typeEntry->isVarargs())
- return;
+ return 0;
- QString cppOutAux = cppOut + QLatin1String("_local");
-
- const bool isEnum = typeEntry->isEnum();
- const bool isFlags = typeEntry->isFlags();
- bool treatAsPointer = valueTypeWithCopyConstructorOnlyPassed(api(), type);
- bool isPointerOrObjectType = (type.isObjectType() || type.isPointer())
- && !type.isUserPrimitive() && !type.isExtendedCppPrimitive()
- && !isEnum && !isFlags;
- const bool isNotContainerEnumOrFlags = !typeEntry->isContainer()
- && !isEnum && !isFlags;
- bool mayHaveImplicitConversion = type.referenceType() == LValueReference
- && !type.isUserPrimitive()
- && !type.isExtendedCppPrimitive()
- && isNotContainerEnumOrFlags
- && !(treatAsPointer || isPointerOrObjectType);
-
- const AbstractMetaTypeList &nestedArrayTypes = type.nestedArrayTypes();
- const bool isCppPrimitiveArray = !nestedArrayTypes.isEmpty()
- && nestedArrayTypes.constLast().isCppPrimitive();
- QString typeName = isCppPrimitiveArray
- ? arrayHandleType(nestedArrayTypes)
- : getFullTypeNameWithoutModifiers(type);
+ const auto arg = GeneratorArgument::fromMetaType(type);
+ const bool isPrimitive = arg.type == GeneratorArgument::Type::Primitive;
- bool isProtectedEnum = false;
+ QString cppOutAux = cppOut + u"_local"_s;
- if (mayHaveImplicitConversion) {
- s << typeName << ' ' << cppOutAux;
- writeMinimalConstructorExpression(s, api(), type, defaultValue);
- s << ";\n";
- } else if (avoidProtectedHack() && isEnum) {
+ QString typeName = arg.type == GeneratorArgument::Type::CppPrimitiveArray
+ ? arrayHandleType(type.nestedArrayTypes())
+ : getFullTypeNameWithoutModifiers(type);
+
+ bool isProtectedEnum = false;
+ if (arg.type == GeneratorArgument::Type::Enum && avoidProtectedHack()) {
auto metaEnum = api().findAbstractMetaEnum(type.typeEntry());
if (metaEnum.has_value() && metaEnum->isProtected()) {
- typeName = wrapperName(context) + QLatin1String("::")
+ typeName = wrapperName(context) + u"::"_s
+ metaEnum.value().name();
isProtectedEnum = true;
}
}
s << typeName;
- if (isCppPrimitiveArray) {
+ switch (arg.conversion) {
+ case GeneratorArgument::Conversion::CppPrimitiveArray:
s << ' ' << cppOut;
- } else if (treatAsPointer || isPointerOrObjectType) {
+ break;
+ case GeneratorArgument::Conversion::ValueOrPointer: {
+ // Generate either value conversion for &cppOutAux or pointer
+ // conversion for &cppOut
+ s << ' ' << cppOutAux;
+ // No default value for containers which can also be passed by pointer.
+ if (arg.type != GeneratorArgument::Type::Container || type.indirections() == 0)
+ writeMinimalConstructorExpression(s, api(), type, isPrimitive, defaultValue);
+ s << ";\n" << typeName << " *" << cppOut << " = &" << cppOutAux;
+ }
+ break;
+ case GeneratorArgument::Conversion::Pointer: {
s << " *" << cppOut;
if (!defaultValue.isEmpty()) {
const bool needsConstCast = !isNullPtr(defaultValue)
@@ -2616,9 +2763,9 @@ void CppGenerator::writePythonToCppTypeConversion(TextStream &s,
if (needsConstCast)
s << ')';
}
- } else if (type.referenceType() == LValueReference && !typeEntry->isPrimitive() && isNotContainerEnumOrFlags) {
- s << " *" << cppOut << " = &" << cppOutAux;
- } else {
+ }
+ break;
+ case GeneratorArgument::Conversion::Default:
s << ' ' << cppOut;
if (isProtectedEnum && avoidProtectedHack()) {
s << " = ";
@@ -2626,43 +2773,48 @@ void CppGenerator::writePythonToCppTypeConversion(TextStream &s,
s << "{}";
else
s << defaultValue;
- } else if (type.isUserPrimitive() || isEnum || isFlags) {
- writeMinimalConstructorExpression(s, api(), typeEntry, defaultValue);
- } else if (!type.isContainer() && !type.isSmartPointer()) {
- writeMinimalConstructorExpression(s, api(), type, defaultValue);
+ } else if (type.isUserPrimitive()
+ || arg.type == GeneratorArgument::Type::Enum
+ || arg.type == GeneratorArgument::Type::Flags) {
+ writeMinimalConstructorExpression(s, api(), typeEntry, isPrimitive, defaultValue);
+ } else if ((!type.isContainer() || type.indirections() == 0) && !type.isSmartPointer()) {
+ writeMinimalConstructorExpression(s, api(), type, isPrimitive, defaultValue);
}
+ break;
}
s << ";\n";
QString pythonToCppFunc = pythonToCppConverterForArgumentName(pyIn);
- if (!defaultValue.isEmpty())
- s << "if (" << pythonToCppFunc << ") ";
-
- QString pythonToCppCall = QString::fromLatin1("%1(%2, &%3)").arg(pythonToCppFunc, pyIn, cppOut);
- if (!mayHaveImplicitConversion) {
+ QString pythonToCppCall = pythonToCppFunc + u'(' + pyIn + u", &"_s
+ + cppOut + u')';
+ if (arg.conversion != GeneratorArgument::Conversion::ValueOrPointer) {
+ // pythonToCppFunc may be 0 when less parameters are passed and
+ // the defaultValue takes effect.
+ if (!defaultValue.isEmpty())
+ s << "if (" << pythonToCppFunc << ")\n" << indent;
s << pythonToCppCall << ";\n";
- return;
+ if (!defaultValue.isEmpty())
+ s << outdent;
+ return arg.indirections;
}
+ // pythonToCppFunc may be 0 when less parameters are passed and
+ // the defaultValue takes effect.
if (!defaultValue.isEmpty())
- s << "{\n";
+ s << "if (" << pythonToCppFunc << ") {\n" << indent;
- s << "if (Shiboken::Conversions::isImplicitConversion(reinterpret_cast<SbkObjectType *>("
- << cpythonTypeNameExt(type) << "), " << pythonToCppFunc << "))\n";
- {
- Indentation indent(s);
- s << pythonToCppFunc << '(' << pyIn << ", &" << cppOutAux << ");\n";
- }
- s << "else\n";
- {
- Indentation indent(s);
- s << pythonToCppCall << ";\n";
- }
+ s << "if (" << pythonToCppFunc << ".isValue())\n"
+ << indent << pythonToCppFunc << '(' << pyIn << ", &" << cppOutAux << ");\n"
+ << outdent << "else\n" << indent
+ << pythonToCppCall << ";\n" << outdent;
- if (!defaultValue.isEmpty())
- s << '}';
- s << '\n';
+ if (defaultValue.isEmpty())
+ s << '\n';
+ else
+ s << "}\n" << outdent;
+
+ return arg.indirections;
}
static void addConversionRuleCodeSnippet(CodeSnipList &snippetList, QString &rule,
@@ -2674,10 +2826,10 @@ static void addConversionRuleCodeSnippet(CodeSnipList &snippetList, QString &rul
if (rule.isEmpty())
return;
if (snippetLanguage == TypeSystem::TargetLangCode) {
- rule.replace(QLatin1String("%in"), inputName);
- rule.replace(QLatin1String("%out"), outputName + QLatin1String("_out"));
+ rule.replace(u"%in"_s, inputName);
+ rule.replace(u"%out"_s, outputName + u"_out"_s);
} else {
- rule.replace(QLatin1String("%out"), outputName);
+ rule.replace(u"%out"_s, outputName);
}
CodeSnip snip(snippetLanguage);
snip.position = (snippetLanguage == TypeSystem::NativeCode) ? TypeSystem::CodeSnipPositionAny : TypeSystem::CodeSnipPositionBeginning;
@@ -2686,7 +2838,7 @@ static void addConversionRuleCodeSnippet(CodeSnipList &snippetList, QString &rul
}
void CppGenerator::writeConversionRule(TextStream &s, const AbstractMetaFunctionCPtr &func,
- TypeSystem::Language language) const
+ TypeSystem::Language language, bool usesPyArgs) const
{
CodeSnipList snippets;
@@ -2696,7 +2848,8 @@ void CppGenerator::writeConversionRule(TextStream &s, const AbstractMetaFunction
addConversionRuleCodeSnippet(snippets, rule, language, TypeSystem::TargetLangCode,
arg.name(), arg.name());
}
- writeCodeSnips(s, snippets, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode, func);
+ writeCodeSnips(s, snippets, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode,
+ func, usesPyArgs, nullptr);
}
void CppGenerator::writeConversionRule(TextStream &s, const AbstractMetaFunctionCPtr &func,
@@ -2705,7 +2858,8 @@ void CppGenerator::writeConversionRule(TextStream &s, const AbstractMetaFunction
CodeSnipList snippets;
QString rule = func->conversionRule(language, 0);
addConversionRuleCodeSnippet(snippets, rule, language, language, outputVar);
- writeCodeSnips(s, snippets, TypeSystem::CodeSnipPositionAny, language, func);
+ writeCodeSnips(s, snippets, TypeSystem::CodeSnipPositionAny, language,
+ func, false /* uses PyArgs */, nullptr);
}
void CppGenerator::writeNoneReturn(TextStream &s, const AbstractMetaFunctionCPtr &func,
@@ -2718,45 +2872,46 @@ void CppGenerator::writeNoneReturn(TextStream &s, const AbstractMetaFunctionCPtr
}
}
-void CppGenerator::writeOverloadedFunctionDecisor(TextStream &s, const OverloadData &overloadData) const
+void CppGenerator::writeOverloadedFunctionDecisor(TextStream &s,
+ const OverloadData &overloadData,
+ ErrorReturn errorReturn) const
{
s << "// Overloaded function decisor\n";
const auto rfunc = overloadData.referenceFunction();
- const AbstractMetaFunctionCList &functionOverloads = overloadData.overloadsWithoutRepetition();
- for (int i = 0; i < functionOverloads.count(); i++) {
+ const AbstractMetaFunctionCList &functionOverloads = overloadData.overloads();
+ for (qsizetype i = 0; i < functionOverloads.size(); ++i) {
const auto func = functionOverloads.at(i);
s << "// " << i << ": ";
if (func->isStatic())
s << "static ";
- if (const auto *decl = func->declaringClass())
+ if (const auto &decl = func->declaringClass())
s << decl->name() << "::";
s << func->signatureComment() << '\n';
}
- writeOverloadedFunctionDecisorEngine(s, &overloadData);
+ writeOverloadedFunctionDecisorEngine(s, overloadData, &overloadData);
s << '\n';
// Ensure that the direct overload that called this reverse
// is called.
if (rfunc->isOperatorOverload() && !rfunc->isCallOperator()) {
- s << "if (isReverse && overloadId == -1) {\n";
- {
- Indentation indent(s);
- s << "PyErr_SetString(PyExc_NotImplementedError, \"reverse operator not implemented.\");\n"
- << "return {};\n";
- }
- s << "}\n\n";
+ s << "if (isReverse && overloadId == -1) {\n" << indent
+ << "Shiboken::Errors::setReverseOperatorNotImplemented();\n"
+ << "return {};\n" << outdent
+ << "}\n\n";
}
s << "// Function signature not found.\n"
- << "if (overloadId == -1) goto "
- << cpythonFunctionName(overloadData.referenceFunction()) << "_TypeError;\n\n";
+ << "if (overloadId == -1)\n" << indent
+ << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n\n"
+ << outdent;
}
void CppGenerator::writeOverloadedFunctionDecisorEngine(TextStream &s,
- const OverloadData *parentOverloadData) const
+ const OverloadData &overloadData,
+ const OverloadDataRootNode *node) const
{
- bool hasDefaultCall = parentOverloadData->nextArgumentHasDefaultValue();
- auto referenceFunction = parentOverloadData->referenceFunction();
+ bool hasDefaultCall = node->nextArgumentHasDefaultValue();
+ auto referenceFunction = node->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.
@@ -2764,8 +2919,8 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(TextStream &s,
// variable to be used further on this method on the conditional that identifies default
// method calls.
if (!hasDefaultCall) {
- for (const auto &func : parentOverloadData->overloads()) {
- if (parentOverloadData->isFinalOccurrence(func)) {
+ for (const auto &func : node->overloads()) {
+ if (node->isFinalOccurrence(func)) {
referenceFunction = func;
hasDefaultCall = true;
break;
@@ -2773,13 +2928,13 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(TextStream &s,
}
}
- int maxArgs = parentOverloadData->maxArgs();
+ const int maxArgs = overloadData.maxArgs();
// Python constructors always receive multiple arguments.
- bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(*parentOverloadData);
+ const bool usePyArgs = overloadData.pythonFunctionWrapperUsesListOfArguments();
// Functions without arguments are identified right away.
if (maxArgs == 0) {
- s << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(referenceFunction)
+ s << "overloadId = " << overloadData.functionNumber(referenceFunction)
<< "; // " << referenceFunction->minimalSignature() << '\n';
return;
@@ -2787,15 +2942,15 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(TextStream &s,
// 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;
+ if (!node->isRoot()) {
+ const bool isLastArgument = node->children().isEmpty();
+ const bool signatureFound = node->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 auto func = parentOverloadData->referenceFunction();
- s << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(func)
+ const auto func = node->referenceFunction();
+ s << "overloadId = " << overloadData.functionNumber(func)
<< "; // " << func->minimalSignature() << '\n';
return;
}
@@ -2806,58 +2961,54 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(TextStream &s,
// 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();
+ const OverloadDataList &children = node->children();
if (hasDefaultCall) {
isFirst = false;
- int numArgs = parentOverloadData->argPos() + 1;
- s << "if (numArgs == " << numArgs << ") {\n";
- {
- Indentation indent(s);
- auto func = referenceFunction;
- for (OverloadData *overloadData : overloads) {
- const auto defValFunc = overloadData->getFunctionWithDefaultValue();
- if (!defValFunc.isNull()) {
- func = defValFunc;
- break;
- }
+ int numArgs = node->argPos() + 1;
+ s << "if (numArgs == " << numArgs << ") {\n" << indent;
+ auto func = referenceFunction;
+ for (const auto &child : children) {
+ const auto defValFunc = child->getFunctionWithDefaultValue();
+ if (defValFunc) {
+ func = defValFunc;
+ break;
}
- s << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(func)
- << "; // " << func->minimalSignature() << '\n';
}
- s << '}';
+ s << "overloadId = " << overloadData.functionNumber(func)
+ << "; // " << func->minimalSignature() << '\n' << outdent << '}';
}
- for (OverloadData *overloadData : overloads) {
- bool signatureFound = overloadData->overloads().size() == 1
- && !overloadData->getFunctionWithDefaultValue()
- && !overloadData->findNextArgWithDefault();
+ for (auto child : children) {
+ bool signatureFound = child->overloads().size() == 1
+ && !child->getFunctionWithDefaultValue()
+ && !child->findNextArgWithDefault();
- const auto refFunc = overloadData->referenceFunction();
+ const auto refFunc = child->referenceFunction();
QStringList typeChecks;
QString pyArgName = (usePyArgs && maxArgs > 1)
- ? pythonArgsAt(overloadData->argPos())
- : QLatin1String(PYTHON_ARG);
- OverloadData *od = overloadData;
+ ? pythonArgsAt(child->argPos())
+ : PYTHON_ARG;
+ auto od = child;
int startArg = od->argPos();
int sequenceArgCount = 0;
while (od && !od->argType().isVarargs()) {
- bool typeReplacedByPyObject = od->argumentTypeReplaced() == cPyObjectT();
+ const bool typeReplacedByPyObject = od->isTypeModified()
+ && od->modifiedArgType().name() == cPyObjectT;
if (!typeReplacedByPyObject) {
if (usePyArgs)
pyArgName = pythonArgsAt(od->argPos());
StringStream tck(TextStream::Language::Cpp);
auto func = od->referenceFunction();
- if (func->isConstructor() && func->arguments().count() == 1) {
- const AbstractMetaClass *ownerClass = func->ownerClass();
- const ComplexTypeEntry *baseContainerType = ownerClass->typeEntry()->baseContainerType();
+ if (func->isConstructor() && func->arguments().size() == 1) {
+ AbstractMetaClassCPtr ownerClass = func->ownerClass();
+ ComplexTypeEntryCPtr baseContainerType = ownerClass->typeEntry()->baseContainerType();
if (baseContainerType && baseContainerType == func->arguments().constFirst().type().typeEntry()
&& ownerClass->isCopyable()) {
- tck << '!' << cpythonCheckFunction(ownerClass->typeEntry()) << pyArgName << ")\n";
- Indentation indent(s);
- tck << "&& ";
+ tck << '!' << cpythonCheckFunction(ownerClass->typeEntry())
+ << pyArgName << ")\n" << indent << "&& " << outdent;
}
}
writeTypeCheck(tck, od, pyArgName);
@@ -2866,14 +3017,14 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(TextStream &s,
sequenceArgCount++;
- if (od->nextOverloadData().isEmpty()
+ if (od->children().isEmpty()
|| od->nextArgumentHasDefaultValue()
- || od->nextOverloadData().size() != 1
- || od->overloads().size() != od->nextOverloadData().constFirst()->overloads().size()) {
- overloadData = od;
+ || od->children().size() != 1
+ || od->overloads().size() != od->children().constFirst()->overloads().size()) {
+ child = od;
od = nullptr;
} else {
- od = od->nextOverloadData().constFirst();
+ od = od->children().constFirst();
}
}
@@ -2883,14 +3034,16 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(TextStream &s,
int numArgs = args.size() - OverloadData::numberOfRemovedArguments(refFunc);
if (isVarargs)
--numArgs;
- typeChecks.prepend(QString::fromLatin1("numArgs %1 %2").arg(isVarargs ? QLatin1String(">=") : QLatin1String("==")).arg(numArgs));
- } else if (sequenceArgCount > 1) {
- typeChecks.prepend(QString::fromLatin1("numArgs >= %1").arg(startArg + sequenceArgCount));
+ QString check = (isVarargs ? u"numArgs >= "_s : u"numArgs == "_s)
+ + QString::number(numArgs);
+ typeChecks.prepend(check);
+ } else if (usePyArgs && sequenceArgCount > 0) {
+ typeChecks.prepend(u"numArgs >= "_s + QString::number(startArg + sequenceArgCount));
} else if (refFunc->isOperatorOverload() && !refFunc->isCallOperator()) {
QString check;
if (!refFunc->isReverseOperator())
- check.append(QLatin1Char('!'));
- check.append(QLatin1String("isReverse"));
+ check.append(u'!');
+ check.append(u"isReverse"_s);
typeChecks.prepend(check);
}
@@ -2903,88 +3056,87 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(TextStream &s,
if (typeChecks.isEmpty()) {
s << "true";
} else {
- Indentation indent(s);
- s << typeChecks.join(QLatin1String("\n&& "));
- }
- s << ") {\n";
- {
- Indentation indent(s);
- writeOverloadedFunctionDecisorEngine(s, overloadData);
+ s << indent << typeChecks.join(u"\n&& "_s) << outdent;
}
- s << "}";
+ s << ") {\n" << indent;
+ writeOverloadedFunctionDecisorEngine(s, overloadData, child.get());
+ s << outdent << '}';
}
s << '\n';
}
void CppGenerator::writeFunctionCalls(TextStream &s, const OverloadData &overloadData,
- const GeneratorContext &context) const
+ const GeneratorContext &context,
+ ErrorReturn errorReturn) const
{
- const AbstractMetaFunctionCList &overloads = overloadData.overloadsWithoutRepetition();
+ const AbstractMetaFunctionCList &overloads = overloadData.overloads();
s << "// Call function/method\n"
- << (overloads.count() > 1 ? "switch (overloadId) " : "") << "{\n";
- {
- Indentation indent(s);
- if (overloads.count() == 1) {
- writeSingleFunctionCall(s, overloadData, overloads.constFirst(), context);
- } else {
- for (int i = 0; i < overloads.count(); i++) {
- const auto func = overloads.at(i);
- s << "case " << i << ": // " << func->signature() << "\n{\n";
- {
- Indentation indent(s);
- writeSingleFunctionCall(s, overloadData, func, context);
- if (func->attributes().testFlag(AbstractMetaFunction::Deprecated)) {
- s << "PyErr_WarnEx(PyExc_DeprecationWarning, \"";
- if (auto cls = context.metaClass())
- s << cls->name() << '.';
- s << func->signature() << " is deprecated\", 1);\n";
- }
- s << "break;\n";
- }
- s << "}\n";
- }
+ << (overloads.size() > 1 ? "switch (overloadId) " : "") << "{\n" << indent;
+ if (overloads.size() == 1) {
+ writeSingleFunctionCall(s, overloadData, overloads.constFirst(), context,
+ errorReturn);
+ } else {
+ for (qsizetype i = 0; i < overloads.size(); ++i) {
+ const auto func = overloads.at(i);
+ s << "case " << i << ": // " << func->signature() << "\n{\n" << indent;
+ writeSingleFunctionCall(s, overloadData, func, context, errorReturn);
+ s << "break;\n" << outdent << "}\n";
}
}
- s << "}\n";
+ s << outdent << "}\n";
+}
+
+static void writeDeprecationWarning(TextStream &s,
+ const GeneratorContext &context,
+ const AbstractMetaFunctionCPtr &func,
+ CppGenerator::ErrorReturn errorReturn)
+{
+ s << "Shiboken::Warnings::warnDeprecated(\"";
+ if (const auto cls = context.metaClass())
+ s << cls->name() << "\", ";
+ // Check error in case "warning-as-error" is set.
+ s << '"' << func->signature().replace(u"::"_s, u"."_s) << "\");\n"
+ << "if (" << shibokenErrorsOccurred << ")\n"
+ << indent << errorReturn << outdent;
}
void CppGenerator::writeSingleFunctionCall(TextStream &s,
const OverloadData &overloadData,
const AbstractMetaFunctionCPtr &func,
- const GeneratorContext &context) const
+ const GeneratorContext &context,
+ ErrorReturn errorReturn) const
{
- if (func->isDeprecated()) {
- s << "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->isDeprecated())
+ writeDeprecationWarning(s, context, func, errorReturn);
if (func->functionType() == AbstractMetaFunction::EmptyFunction) {
- s << "PyErr_Format(PyExc_TypeError, \"%s is a private method.\", \""
- << func->signature().replace(QLatin1String("::"), QLatin1String("."))
- << "\");\n"
- << returnStatement(m_currentErrorCode) << '\n';
+ s << "Shiboken::Errors::setPrivateMethod(\""
+ << func->signature().replace(u"::"_s, u"."_s) << "\");\n"
+ << errorReturn;
return;
}
- bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(overloadData);
+ const bool usePyArgs = overloadData.pythonFunctionWrapperUsesListOfArguments();
// Handle named arguments.
- writeNamedArgumentResolution(s, func, usePyArgs, overloadData);
+ writeNamedArgumentResolution(s, func, usePyArgs, overloadData, errorReturn);
bool injectCodeCallsFunc = injectedCodeCallsCppFunction(context, 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 auto argCount = func->arguments().size();
+ QList<qsizetype> indirections(argCount, 0);
+ for (qsizetype argIdx = 0; argIdx < argCount; ++argIdx) {
+ const bool hasConversionRule =
+ func->hasConversionRule(TypeSystem::NativeCode, int(argIdx + 1));
const AbstractMetaArgument &arg = func->arguments().at(argIdx);
- if (func->argumentRemoved(argIdx + 1)) {
+ if (arg.isModifiedRemoved()) {
if (!arg.defaultValueExpression().isEmpty()) {
- const QString cppArgRemoved = QLatin1String(CPP_ARG_REMOVED)
- + QString::number(argIdx);
+ const QString cppArgRemoved = CPP_ARG_REMOVED(argIdx);
s << getFullTypeName(arg.type()) << ' ' << cppArgRemoved;
- s << " = " << guessScopeForDefaultValue(func, arg) << ";\n";
- writeUnusedVariableCast(s, cppArgRemoved);
+ s << " = " << arg.defaultValueExpression() << ";\n"
+ << sbkUnusedVariableCast(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.
@@ -2999,24 +3151,26 @@ void CppGenerator::writeSingleFunctionCall(TextStream &s,
}
if (hasConversionRule)
continue;
- auto argType = getArgumentType(func, argIdx + 1);
- if (!argType.has_value() || (mayHaveUnunsedArguments && !func->injectedCodeUsesArgument(argIdx)))
+ if (mayHaveUnunsedArguments && !func->injectedCodeUsesArgument(argIdx))
continue;
+ auto argType = getArgumentType(func, argIdx);
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.value(), argName, pyArgName,
- func->implementingClass(), defaultValue,
- func->isUserAdded());
+ QString pyArgName = usePyArgs ? pythonArgsAt(argPos) : PYTHON_ARG;
+ indirections[argIdx] =
+ writeArgumentConversion(s, argType, CPP_ARG_N(argPos), pyArgName, errorReturn,
+ func->implementingClass(), arg.defaultValueExpression(),
+ func->isUserAdded());
}
s << '\n';
int numRemovedArgs = OverloadData::numberOfRemovedArguments(func);
- s << "if (!PyErr_Occurred()) {\n" << indent;
- writeMethodCall(s, func, context, func->arguments().size() - numRemovedArgs);
+ s << "if (Shiboken::Errors::occurred() == nullptr) {\n" << indent;
+ writeMethodCall(s, func, context,
+ overloadData.pythonFunctionWrapperUsesListOfArguments(),
+ func->arguments().size() - numRemovedArgs, indirections, errorReturn);
+
if (!func->isConstructor())
writeNoneReturn(s, func, overloadData.hasNonVoidReturnType());
s << outdent << "}\n";
@@ -3026,34 +3180,34 @@ QString CppGenerator::cppToPythonFunctionName(const QString &sourceTypeName, QSt
{
if (targetTypeName.isEmpty())
targetTypeName = sourceTypeName;
- return sourceTypeName + QLatin1String("_CppToPython_") + targetTypeName;
+ return sourceTypeName + u"_CppToPython_"_s + targetTypeName;
}
QString CppGenerator::pythonToCppFunctionName(const QString &sourceTypeName, const QString &targetTypeName)
{
- return sourceTypeName + QLatin1String("_PythonToCpp_") + targetTypeName;
+ return sourceTypeName + u"_PythonToCpp_"_s + 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)
+QString CppGenerator::pythonToCppFunctionName(const TargetToNativeConversion &toNative,
+ const TypeEntryCPtr &targetType)
{
return pythonToCppFunctionName(fixedCppTypeName(toNative), fixedCppTypeName(targetType));
}
QString CppGenerator::convertibleToCppFunctionName(const QString &sourceTypeName, const QString &targetTypeName)
{
- return QLatin1String("is_") + sourceTypeName + QLatin1String("_PythonToCpp_")
- + targetTypeName + QLatin1String("_Convertible");
+ return u"is_"_s + sourceTypeName + u"_PythonToCpp_"_s
+ + targetTypeName + u"_Convertible"_s;
}
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)
+QString CppGenerator::convertibleToCppFunctionName(const TargetToNativeConversion &toNative,
+ const TypeEntryCPtr &targetType)
{
return convertibleToCppFunctionName(fixedCppTypeName(toNative), fixedCppTypeName(targetType));
}
@@ -3063,63 +3217,92 @@ void CppGenerator::writeCppToPythonFunction(TextStream &s, const QString &code,
{
QString prettyCode = code;
- processCodeSnip(prettyCode);
+ const QString funcName = cppToPythonFunctionName(sourceTypeName, targetTypeName);
+ processCodeSnip(prettyCode, funcName);
- s << "static PyObject *" << cppToPythonFunctionName(sourceTypeName, targetTypeName)
+ s << "static PyObject *" << funcName
<< "(const void *cppIn)\n{\n" << indent << prettyCode
<< ensureEndl << outdent << "}\n";
}
-static void replaceCppToPythonVariables(QString &code, const QString &typeName)
+static QString writeCppInRef(const QString &typeName, bool constRef)
{
- const QString line = QLatin1String("auto &cppInRef = *reinterpret_cast<")
- + typeName + QLatin1String(" *>(const_cast<void *>(cppIn));");
- CodeSnipAbstract::prependCode(&code, line);
- code.replace(QLatin1String("%INTYPE"), typeName);
- code.replace(QLatin1String("%OUTTYPE"), QLatin1String("PyObject *"));
- code.replace(QLatin1String("%in"), QLatin1String("cppInRef"));
- code.replace(QLatin1String("%out"), QLatin1String("pyOut"));
+ QString result;
+ QTextStream str(&result);
+ if (constRef)
+ str << "const ";
+ str << "auto &cppInRef = *reinterpret_cast<";
+ if (constRef)
+ str << "const ";
+ str << typeName << " *>("
+ << (constRef ? "cppIn" : "const_cast<void *>(cppIn)") << ");";
+ return result;
}
-void CppGenerator::writeCppToPythonFunction(TextStream &s, const CustomConversion *customConversion) const
+static void replaceCppToPythonVariables(QString &code, const QString &typeName,
+ bool constRef = false)
+{
+ CodeSnipAbstract::prependCode(&code, writeCppInRef(typeName, constRef));
+ code.replace(u"%INTYPE"_s, typeName);
+ code.replace(u"%OUTTYPE"_s, u"PyObject *"_s);
+ code.replace(u"%in"_s, u"cppInRef"_s);
+ code.replace(u"%out"_s, u"pyOut"_s);
+}
+
+void CppGenerator::writeCppToPythonFunction(TextStream &s,
+ const CustomConversionPtr &customConversion) const
{
QString code = customConversion->nativeToTargetConversion();
- replaceCppToPythonVariables(code, getFullTypeName(customConversion->ownerType()));
+ auto ownerType = customConversion->ownerType();
+ const bool constRef = !ownerType->isPrimitive(); // PyCapsule needs a non-const ref
+ replaceCppToPythonVariables(code, getFullTypeName(ownerType), constRef);
writeCppToPythonFunction(s, code, fixedCppTypeName(customConversion->ownerType()));
}
+
+QString CppGenerator::containerNativeToTargetTypeName(const ContainerTypeEntryCPtr &type)
+{
+ QString result = type->targetLangApiName();
+ if (result != cPyObjectT) {
+ result = containerCpythonBaseName(type);
+ if (result == cPySequenceT)
+ result = cPyListT;
+ }
+ return result;
+}
+
void CppGenerator::writeCppToPythonFunction(TextStream &s, const AbstractMetaType &containerType) const
{
- const CustomConversion *customConversion = containerType.typeEntry()->customConversion();
- if (!customConversion) {
+ Q_ASSERT(containerType.typeEntry()->isContainer());
+ auto cte = std::static_pointer_cast<const ContainerTypeEntry>(containerType.typeEntry());
+ if (!cte->hasCustomConversion()) {
QString m;
QTextStream(&m) << "Can't write the C++ to Python conversion function for container type '"
<< containerType.typeEntry()->qualifiedCppName()
<< "' - no conversion rule was defined for it in the type system.";
throw Exception(m);
}
- if (!containerType.typeEntry()->isContainer()) {
- writeCppToPythonFunction(s, customConversion);
- return;
- }
+ const auto customConversion = cte->customConversion();
QString code = customConversion->nativeToTargetConversion();
- for (int i = 0; i < containerType.instantiations().count(); ++i) {
+ for (qsizetype i = 0; i < containerType.instantiations().size(); ++i) {
const 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);
+ typeName = u"const "_s + typeName;
+ code.replace(u"%INTYPE_"_s + QString::number(i), typeName);
}
- replaceCppToPythonVariables(code, getFullTypeNameWithoutModifiers(containerType));
- processCodeSnip(code);
- writeCppToPythonFunction(s, code, fixedCppTypeName(containerType));
+ replaceCppToPythonVariables(code, getFullTypeNameWithoutModifiers(containerType), true);
+ processCodeSnip(code, containerType.typeEntry()->qualifiedCppName());
+ writeCppToPythonFunction(s, code, fixedCppTypeName(containerType),
+ containerNativeToTargetTypeName(cte));
}
void CppGenerator::writePythonToCppFunction(TextStream &s, const QString &code, const QString &sourceTypeName,
const QString &targetTypeName) const
{
QString prettyCode = code;
- processCodeSnip(prettyCode);
- s << "static void " << pythonToCppFunctionName(sourceTypeName, targetTypeName)
+ const QString funcName = pythonToCppFunctionName(sourceTypeName, targetTypeName);
+ processCodeSnip(prettyCode, funcName);
+ s << "static void " << funcName
<< "(PyObject *pyIn, void *cppOut)\n{\n" << indent << prettyCode
<< ensureEndl << outdent << "}\n";
}
@@ -3137,16 +3320,15 @@ void CppGenerator::writeIsPythonConvertibleToCppFunction(TextStream &s,
s << "static PythonToCppFunc " << convertibleToCppFunctionName(sourceTypeName, targetTypeName);
s << "(PyObject *pyIn)\n{\n" << indent;
if (acceptNoneAsCppNull) {
- s << "if (pyIn == Py_None)\n";
- Indentation indent(s);
- s << "return Shiboken::Conversions::nonePythonToCppNullPtr;\n";
- }
- s << "if (" << condition << ")\n";
- {
- Indentation indent(s);
- s << "return " << pythonToCppFuncName << ";\n";
+ s << "if (pyIn == Py_None)\n" << indent
+ << "return Shiboken::Conversions::nonePythonToCppNullPtr;\n" << outdent;
+ } else {
+ if (!condition.contains(u"pyIn"))
+ s << sbkUnusedVariableCast("pyIn");
}
- s << "return {};\n" << outdent << "}\n";
+ s << "if (" << condition << ")\n" << indent
+ << "return " << pythonToCppFuncName << ";\n" << outdent
+ << "return {};\n" << outdent << "}\n";
}
void CppGenerator::writePythonToCppConversionFunctions(TextStream &s,
@@ -3161,102 +3343,97 @@ void CppGenerator::writePythonToCppConversionFunctions(TextStream &s,
// Python to C++ conversion function.
StringStream c(TextStream::Language::Cpp);
if (conversion.isEmpty())
- conversion = QLatin1Char('*') + cpythonWrapperCPtr(sourceType, QLatin1String("pyIn"));
+ conversion = u'*' + cpythonWrapperCPtr(sourceType, u"pyIn"_s);
if (!preConversion.isEmpty())
c << preConversion << '\n';
const QString fullTypeName = targetType.isSmartPointer()
? targetType.cppSignature()
: getFullTypeName(targetType.typeEntry());
c << "*reinterpret_cast<" << fullTypeName << " *>(cppOut) = "
- << fullTypeName << '(' << conversion << ");";
+ << fullTypeName << '('
+ << (sourceType.isUniquePointer() ? stdMove(conversion) : conversion)
+ << ");";
QString sourceTypeName = fixedCppTypeName(sourceType);
QString targetTypeName = fixedCppTypeName(targetType);
writePythonToCppFunction(s, c.toString(), sourceTypeName, targetTypeName);
// Python to C++ convertible check function.
if (typeCheck.isEmpty())
- typeCheck = QString::fromLatin1("PyObject_TypeCheck(pyIn, %1)").arg(sourcePyType);
+ typeCheck = u"PyObject_TypeCheck(pyIn, "_s + sourcePyType + u')';
writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck);
s << '\n';
}
void CppGenerator::writePythonToCppConversionFunctions(TextStream &s,
- const CustomConversion::TargetToNativeConversion *toNative,
- const TypeEntry *targetType) const
+ const TargetToNativeConversion &toNative,
+ const TypeEntryCPtr &targetType) const
{
// Python to C++ conversion function.
- QString code = toNative->conversion();
+ QString code = toNative.conversion();
QString inType;
- if (toNative->sourceType())
- inType = cpythonTypeNameExt(toNative->sourceType());
+ 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)"));
+ inType = u'(' + toNative.sourceTypeName() + u"_TypeF())"_s;
+ code.replace(u"%INTYPE"_s, inType);
+ code.replace(u"%OUTTYPE"_s, targetType->qualifiedCppName());
+ code.replace(u"%in"_s, u"pyIn"_s);
+ code.replace(u"%out"_s,
+ u"*reinterpret_cast<"_s + getFullTypeName(targetType) + u" *>(cppOut)"_s);
QString sourceTypeName = fixedCppTypeName(toNative);
QString targetTypeName = fixedCppTypeName(targetType);
writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
// Python to C++ convertible check function.
- QString typeCheck = toNative->sourceTypeCheck();
+ 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 == cPyTypeObjectT())
- typeCheck = QLatin1String("PyType_Check(%in)");
- else if (pyTypeName == cPyObjectT())
- typeCheck = QLatin1String("PyObject_TypeCheck(%in, &PyBaseObject_Type)");
- // PYSIDE-795: We abuse PySequence for iterables
- else if (pyTypeName == cPySequenceT())
- typeCheck = QLatin1String("Shiboken::String::checkIterable(%in)");
- else if (pyTypeName.startsWith(QLatin1String("Py")))
- typeCheck = pyTypeName + QLatin1String("_Check(%in)");
+ QString pyTypeName = toNative.sourceTypeName();
+ if (pyTypeName == u"Py_None" || pyTypeName == u"PyNone")
+ typeCheck = u"%in == Py_None"_s;
+ else if (pyTypeName == u"SbkObject")
+ typeCheck = u"Shiboken::Object::checkType(%in)"_s;
}
if (typeCheck.isEmpty()) {
- if (!toNative->sourceType() || toNative->sourceType()->isPrimitive()) {
+ if (!toNative.sourceType() || toNative.sourceType()->isPrimitive()) {
QString m;
QTextStream(&m) << "User added implicit conversion for C++ type '" << targetType->qualifiedCppName()
<< "' must provide either an input type check function or a non primitive type entry.";
throw Exception(m);
}
- typeCheck = QString::fromLatin1("PyObject_TypeCheck(%in, %1)").arg(cpythonTypeNameExt(toNative->sourceType()));
+ typeCheck = u"PyObject_TypeCheck(%in, "_s
+ + cpythonTypeNameExt(toNative.sourceType()) + u')';
}
- typeCheck.replace(QLatin1String("%in"), QLatin1String("pyIn"));
- processCodeSnip(typeCheck);
+ typeCheck.replace(u"%in"_s, u"pyIn"_s);
+ processCodeSnip(typeCheck, targetType->qualifiedCppName());
writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck);
}
void CppGenerator::writePythonToCppConversionFunctions(TextStream &s, const AbstractMetaType &containerType) const
{
- const CustomConversion *customConversion = containerType.typeEntry()->customConversion();
- if (!customConversion) {
- //qFatal
- return;
- }
- const CustomConversion::TargetToNativeConversions &toCppConversions = customConversion->targetToNativeConversions();
- if (toCppConversions.isEmpty()) {
- //qFatal
- return;
- }
+ Q_ASSERT(containerType.typeEntry()->isContainer());
+ const auto cte = std::static_pointer_cast<const ContainerTypeEntry>(containerType.typeEntry());
+ const auto customConversion = cte->customConversion();
+ for (const auto &conv : customConversion->targetToNativeConversions())
+ writePythonToCppConversionFunction(s, containerType, conv);
+}
+
+void CppGenerator::writePythonToCppConversionFunction(TextStream &s,
+ const AbstractMetaType &containerType,
+ const TargetToNativeConversion &conv) const
+{
// Python to C++ conversion function.
QString cppTypeName = getFullTypeNameWithoutModifiers(containerType);
- QString code = toCppConversions.constFirst()->conversion();
- const QString line = QLatin1String("auto &cppOutRef = *reinterpret_cast<")
- + cppTypeName + QLatin1String(" *>(cppOut);");
+ QString code = conv.conversion();
+ const QString line = u"auto &cppOutRef = *reinterpret_cast<"_s
+ + cppTypeName + u" *>(cppOut);"_s;
CodeSnipAbstract::prependCode(&code, line);
- for (int i = 0; i < containerType.instantiations().count(); ++i) {
+ for (qsizetype i = 0; i < containerType.instantiations().size(); ++i) {
const AbstractMetaType &type = containerType.instantiations().at(i);
QString typeName = getFullTypeName(type);
- if (valueTypeWithCopyConstructorOnlyPassed(api(), type)) {
+ // Containers of opaque containers are not handled here.
+ const auto generatorArg = GeneratorArgument::fromMetaType(type);
+ if (generatorArg.indirections > 0 && !type.generateOpaqueContainer()) {
for (int pos = 0; ; ) {
const QRegularExpressionMatch match = convertToCppRegEx().match(code, pos);
if (!match.hasMatch())
@@ -3264,171 +3441,220 @@ void CppGenerator::writePythonToCppConversionFunctions(TextStream &s, const Abst
pos = match.capturedEnd();
const QString varName = match.captured(1);
QString rightCode = code.mid(pos);
- rightCode.replace(varName, QLatin1Char('*') + varName);
+ rightCode.replace(varName, u'*' + varName);
code.replace(pos, code.size() - pos, rightCode);
}
- typeName.append(QLatin1String(" *"));
+ typeName.append(u" *"_s);
}
- code.replace(QString::fromLatin1("%OUTTYPE_%1").arg(i), typeName);
+ code.replace(u"%OUTTYPE_"_s + QString::number(i), typeName);
}
- code.replace(QLatin1String("%OUTTYPE"), cppTypeName);
- code.replace(QLatin1String("%in"), QLatin1String("pyIn"));
- code.replace(QLatin1String("%out"), QLatin1String("cppOutRef"));
+ code.replace(u"%OUTTYPE"_s, cppTypeName);
+ code.replace(u"%in"_s, u"pyIn"_s);
+ code.replace(u"%out"_s, u"cppOutRef"_s);
QString typeName = fixedCppTypeName(containerType);
- writePythonToCppFunction(s, code, typeName, typeName);
+ const QString &sourceTypeName = conv.sourceTypeName();
+ writePythonToCppFunction(s, code, sourceTypeName, typeName);
// Python to C++ convertible check function.
QString typeCheck = cpythonCheckFunction(containerType);
if (typeCheck.isEmpty())
- typeCheck = QLatin1String("false");
+ typeCheck = u"false"_s;
else
- typeCheck = typeCheck + QLatin1String("pyIn)");
- writeIsPythonConvertibleToCppFunction(s, typeName, typeName, typeCheck);
+ typeCheck = typeCheck + u"pyIn)"_s;
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, typeName, typeCheck);
s << '\n';
}
+static void writeSetConverterFunction(TextStream &s,
+ const char *function,
+ const QString &converterVar,
+ const QString &pythonToCppFunc,
+ const QString &isConvertibleFunc)
+{
+ s << "Shiboken::Conversions::" << function << '(' << converterVar << ',' << '\n'
+ << indent << pythonToCppFunc << ',' << '\n' << isConvertibleFunc
+ << outdent << ");\n";
+}
+
void CppGenerator::writeAddPythonToCppConversion(TextStream &s, const QString &converterVar,
const QString &pythonToCppFunc,
const QString &isConvertibleFunc)
{
- s << "Shiboken::Conversions::addPythonToCppValueConversion(" << converterVar << ',' << '\n';
- {
- Indentation indent(s);
- s << pythonToCppFunc << ',' << '\n' << isConvertibleFunc;
- }
- s << ");\n";
+ writeSetConverterFunction(s, "addPythonToCppValueConversion",
+ converterVar, pythonToCppFunc, isConvertibleFunc);
+}
+
+void CppGenerator::writeSetPythonToCppPointerConversion(TextStream &s,
+ const QString &converterVar,
+ const QString &pythonToCppFunc,
+ const QString &isConvertibleFunc)
+{
+ writeSetConverterFunction(s, "setPythonToCppPointerFunctions",
+ converterVar, pythonToCppFunc, isConvertibleFunc);
+}
+
+// PYSIDE-1986: Some QObject derived classes, (QVBoxLayout) do not have default
+// arguments, which breaks setting properties by named arguments. Force the
+// handling code to be generated nevertheless for applicable widget classes,
+// so that the mechanism of falling through to the error handling to set
+// the properties works nevertheless.
+static bool forceQObjectNamedArguments(const AbstractMetaFunctionCPtr &func)
+{
+ if (func->functionType() != AbstractMetaFunction::ConstructorFunction)
+ return false;
+ const auto owner = func->ownerClass();
+ Q_ASSERT(owner);
+ if (!isQObject(owner))
+ return false;
+ const QString &name = owner->name();
+ return name == u"QVBoxLayout" || name == u"QHBoxLayout"
+ || name == u"QSplitterHandle" || name == u"QSizeGrip";
}
-void CppGenerator::writeNamedArgumentResolution(TextStream &s, const AbstractMetaFunctionCPtr &func,
- bool usePyArgs, const OverloadData &overloadData) const
+void CppGenerator::writeNamedArgumentResolution(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ bool usePyArgs,
+ const OverloadData &overloadData,
+ ErrorReturn errorReturn)
{
const AbstractMetaArgumentList &args = OverloadData::getArgumentsWithDefaultValues(func);
- if (args.isEmpty()) {
+ const bool hasDefaultArguments = !args.isEmpty();
+ const bool force = !hasDefaultArguments && usePySideExtensions()
+ && forceQObjectNamedArguments(func);
+ if (!hasDefaultArguments && !force) {
if (overloadData.hasArgumentWithDefaultValue()) {
- s << "if (kwds) {\n";
- {
- Indentation indent(s);
- s << "errInfo.reset(kwds);\n"
- << "Py_INCREF(errInfo.object());\n"
- << "goto " << cpythonFunctionName(func) << "_TypeError;\n";
- }
- s << "}\n";
+ // PySide-535: Allow for empty dict instead of nullptr in PyPy
+ s << "if (kwds != nullptr && PyDict_Size(kwds) > 0) {\n" << indent
+ << "errInfo.reset(kwds);\n"
+ << "Py_INCREF(errInfo.object());\n"
+ << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n"
+ << outdent << "}\n";
}
return;
}
- s << "if (kwds) {\n";
- {
- Indentation indent(s);
- s << "PyObject *value{};\n"
- << "PyObject *kwds_dup = PyDict_Copy(kwds);\n";
- for (const AbstractMetaArgument &arg : args) {
- const int pyArgIndex = arg.argumentIndex()
- - OverloadData::numberOfRemovedArguments(func, arg.argumentIndex());
- QString pyArgName = usePyArgs ? pythonArgsAt(pyArgIndex) : QLatin1String(PYTHON_ARG);
- QString pyKeyName = QLatin1String("key_") + arg.name();
- s << "static PyObject *const " << pyKeyName
- << " = Shiboken::String::createStaticString(\"" << arg.name() << "\");\n"
- << "if (PyDict_Contains(kwds, " << pyKeyName << ")) {\n";
- {
- Indentation indent(s);
- s << "value = PyDict_GetItem(kwds, " << pyKeyName << ");\n"
- << "if (value && " << pyArgName << ") {\n";
- {
- Indentation indent(s);
- s << "errInfo.reset(" << pyKeyName << ");\n"
- << "Py_INCREF(errInfo.object());\n"
- << "goto " << cpythonFunctionName(func) << "_TypeError;\n";
- }
- s << "}\nif (value) {\n";
- {
- Indentation indent(s);
- s << pyArgName << " = value;\nif (!";
- writeTypeCheck(s, arg.type(), pyArgName, isNumber(arg.type().typeEntry()),
- func->typeReplaced(arg.argumentIndex() + 1));
- s << ")\n";
- {
- Indentation indent(s);
- s << "goto " << cpythonFunctionName(func) << "_TypeError;\n";
- }
- }
- s << "}\nPyDict_DelItem(kwds_dup, " << pyKeyName << ");\n";
- }
- s << "}\n";
- }
- // PYSIDE-1305: Handle keyword args correctly.
- // Normal functions handle their parameters immediately.
- // For constructors that are QObject, we need to delay that
- // until extra keyword signals and properties are handled.
- s << "if (PyDict_Size(kwds_dup) > 0) {\n";
- {
- Indentation indent(s);
- s << "errInfo.reset(kwds_dup);\n";
- if (!(func->isConstructor() && func->ownerClass()->isQObject()))
- s << "goto " << cpythonFunctionName(func) << "_TypeError;\n";
- else
- s << "// fall through to handle extra keyword signals and properties\n";
- }
- s << "}\n";
- }
- s << "}\n";
+ // PySide-535: Allow for empty dict instead of nullptr in PyPy
+ s << "if (kwds && PyDict_Size(kwds) > 0) {\n" << indent;
+ if (!force)
+ s << "PyObject *value{};\n";
+ s << "Shiboken::AutoDecRef kwds_dup(PyDict_Copy(kwds));\n";
+ for (const AbstractMetaArgument &arg : args) {
+ const int pyArgIndex = arg.argumentIndex()
+ - OverloadData::numberOfRemovedArguments(func, arg.argumentIndex());
+ QString pyArgName = usePyArgs ? pythonArgsAt(pyArgIndex)
+ : PYTHON_ARG;
+ QString pyKeyName = u"key_"_s + arg.name();
+ s << "static PyObject *const " << pyKeyName
+ << " = Shiboken::String::createStaticString(\"" << arg.name() << "\");\n"
+ << "if (PyDict_Contains(kwds, " << pyKeyName << ") != 0) {\n" << indent
+ << "value = PyDict_GetItem(kwds, " << pyKeyName << ");\n"
+ << "if (value != nullptr && " << pyArgName << " != nullptr ) {\n"
+ << indent << "errInfo.reset(" << pyKeyName << ");\n"
+ << "Py_INCREF(errInfo.object());\n"
+ << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n"
+ << outdent << "}\nif (value != nullptr) {\n" << indent
+ << pyArgName << " = value;\nif (!";
+ const auto &type = arg.modifiedType();
+ writeTypeCheck(s, type, pyArgName, isNumber(type.typeEntry()), {});
+ s << ")\n" << indent
+ << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n"
+ << outdent << outdent
+ << "}\nPyDict_DelItem(kwds_dup, " << pyKeyName << ");\n"
+ << outdent << "}\n";
+ }
+ // PYSIDE-1305: Handle keyword args correctly.
+ // Normal functions handle their parameters immediately.
+ // For constructors that are QObject, we need to delay that
+ // until extra keyword signals and properties are handled.
+ s << "if (PyDict_Size(kwds_dup) > 0) {\n" << indent
+ << "errInfo.reset(kwds_dup.release());\n";
+ if (!(func->isConstructor() && isQObject(func->ownerClass())))
+ s << "return " << returnErrorWrongArguments(overloadData, errorReturn) << ";\n";
+ else
+ s << "// fall through to handle extra keyword signals and properties\n";
+ s << outdent << "}\n"
+ << outdent << "}\n";
}
QString CppGenerator::argumentNameFromIndex(const ApiExtractorResult &api,
- const AbstractMetaFunctionCPtr &func, int argIndex,
- const AbstractMetaClass **wrappedClass,
- QString *errorMessage)
-{
- if (errorMessage != nullptr)
- errorMessage->clear();
- *wrappedClass = nullptr;
- QString pyArgName;
- if (argIndex == -1) {
- pyArgName = QLatin1String("self");
- *wrappedClass = func->implementingClass();
- } else if (argIndex == 0) {
- const auto funcType = func->type();
- AbstractMetaType returnType = getTypeWithoutContainer(funcType);
- if (!returnType.isVoid()) {
- pyArgName = QLatin1String(PYTHON_RETURN_VAR);
- *wrappedClass = AbstractMetaClass::findClass(api.classes(), returnType.typeEntry());
- if (*wrappedClass == nullptr && errorMessage != nullptr)
- *errorMessage = msgClassNotFound(returnType.typeEntry());
- } else {
- if (errorMessage != nullptr) {
- QTextStream str(errorMessage);
- str << "Invalid Argument index (0, return value) on function modification: "
- << funcType.name() << ' ';
- if (const AbstractMetaClass *declaringClass = func->declaringClass())
- str << declaringClass->name() << "::";
- str << func->name() << "()";
- }
- }
+ const AbstractMetaFunctionCPtr &func, int argIndex)
+{
+ switch (argIndex) {
+ case -1:
+ return PYTHON_SELF_VAR;
+ case 0:
+ return PYTHON_RETURN_VAR;
+ case 1: { // Single argument?
+ OverloadData data(getFunctionGroups(func->implementingClass()).value(func->name()), api);
+ if (!data.pythonFunctionWrapperUsesListOfArguments())
+ return PYTHON_ARG;
+ break;
+ }
+ }
+ return pythonArgsAt(argIndex - 1);
+}
+
+AbstractMetaClassCPtr
+CppGenerator::argumentClassFromIndex(const ApiExtractorResult &api,
+ const AbstractMetaFunctionCPtr &func, int argIndex)
+{
+ if (argIndex == -1)
+ return func->implementingClass();
+
+ AbstractMetaType type;
+ if (argIndex == 0) {
+ type = func->type();
} else {
- int realIndex = argIndex - 1 - OverloadData::numberOfRemovedArguments(func, argIndex - 1);
- AbstractMetaType argType = getTypeWithoutContainer(func->arguments().at(realIndex).type());
- *wrappedClass = AbstractMetaClass::findClass(api.classes(), argType.typeEntry());
- if (*wrappedClass == nullptr && errorMessage != nullptr)
- *errorMessage = msgClassNotFound(argType.typeEntry());
- if (argIndex == 1
- && !func->isConstructor()
- && OverloadData::isSingleArgument(getFunctionGroups(func->implementingClass()).value(func->name())))
- pyArgName = QLatin1String(PYTHON_ARG);
- else
- pyArgName = pythonArgsAt(argIndex - 1);
+ const int arg = argIndex - 1;
+ const int realIndex = arg - OverloadData::numberOfRemovedArguments(func, arg);
+ type = func->arguments().at(realIndex).type();
+ }
+
+ if (type.typeEntry()->isContainer()) {
+ // only support containers with 1 type
+ if (type.instantiations().size() == 1)
+ type = type.instantiations().constFirst();
}
- return pyArgName;
+
+ auto te = type.typeEntry();
+ if (type.isVoid() || !te->isComplex())
+ throw Exception(msgInvalidArgumentModification(func, argIndex));
+ const auto result = AbstractMetaClass::findClass(api.classes(), te);
+ if (!result)
+ throw Exception(msgClassNotFound(te));
+ return result;
}
+const char tryBlock[] = R"(
+PyObject *errorType{};
+PyObject *errorString{};
+try {
+)";
+
const char defaultExceptionHandling[] = R"(} catch (const std::exception &e) {
- PyErr_SetString(PyExc_RuntimeError, e.what());
+ errorType = PyExc_RuntimeError;
+ errorString = Shiboken::String::fromCString(e.what());
} catch (...) {
- PyErr_SetString(PyExc_RuntimeError, "An unknown exception was caught");
+ errorType = PyExc_RuntimeError;
+ errorString = Shiboken::Messages::unknownException();
}
)";
+const char propagateException[] = R"(
+if (errorType != nullptr)
+ PyErr_SetObject(errorType, errorString);
+)";
+
+static QString explicitConversion(const QString &v, const AbstractMetaType &t)
+{
+ return t.plainType().cppSignature() + u'(' + v + u')';
+}
+
void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr &func,
- const GeneratorContext &context, int maxArgs) const
+ const GeneratorContext &context, bool usesPyArgs,
+ int maxArgs,
+ const QList<qsizetype> &argumentIndirections,
+ ErrorReturn errorReturn) const
{
s << "// " << func->minimalSignature() << (func->isReverseOperator() ? " [reverse operator]": "") << '\n';
if (func->isConstructor()) {
@@ -3445,14 +3671,10 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
}
if (func->isAbstract()) {
- s << "if (Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject *>(self))) {\n";
- {
- Indentation indent(s);
- s << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '";
- s << func->ownerClass()->name() << '.' << func->name() << "()' not implemented.\");\n";
- s << returnStatement(m_currentErrorCode) << '\n';
- }
- s << "}\n";
+ s << "if (Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject *>(self))) {\n"
+ << indent << "Shiboken::Errors::setPureVirtualMethodError(\""
+ << func->ownerClass()->name() << '.' << func->name() << "\");\n"
+ << errorReturn << outdent << "}\n";
}
// Used to provide contextual information to custom code writer function.
@@ -3468,18 +3690,20 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
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))
+ if (func->arguments().at(i).isModifiedRemoved())
removedArgs++;
}
} else if (maxArgs != 0 && !func->arguments().isEmpty()) {
lastArg = &func->arguments().constLast();
}
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode, func, lastArg);
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode, func,
+ usesPyArgs, lastArg);
}
- writeConversionRule(s, func, TypeSystem::NativeCode);
+ writeConversionRule(s, func, TypeSystem::NativeCode, usesPyArgs);
+
+ bool generateExceptionHandling = false;
if (!func->isUserAdded()) {
QStringList userArgs;
@@ -3487,9 +3711,9 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
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)) {
+ const bool hasConversionRule =
+ func->hasConversionRule(TypeSystem::NativeCode, arg.argumentIndex() + 1);
+ if (arg.isModifiedRemoved()) {
// If some argument with default value is removed from a
// method signature, the said value must be explicitly
// added to the method call.
@@ -3497,25 +3721,26 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
// If have conversion rules I will use this for removed args
if (hasConversionRule)
- userArgs << arg.name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX);
+ userArgs << arg.name() + CONV_RULE_OUT_VAR_SUFFIX;
else if (!arg.defaultValueExpression().isEmpty())
- userArgs.append(QLatin1String(CPP_ARG_REMOVED) + QString::number(i));
+ userArgs.append(CPP_ARG_REMOVED(i));
} else {
- int idx = arg.argumentIndex() - removedArgs;
- bool deRef = valueTypeWithCopyConstructorOnlyPassed(api(), arg.type())
- || arg.type().isObjectTypeUsedAsValueType()
- || (arg.type().referenceType() == LValueReference
- && arg.type().isWrapperType() && !arg.type().isPointer());
if (hasConversionRule) {
- userArgs.append(arg.name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX));
+ userArgs.append(arg.name() + CONV_RULE_OUT_VAR_SUFFIX);
} else {
- QString argName;
- if (deRef)
- argName += QLatin1Char('*');
- argName += QLatin1String(CPP_ARG) + QString::number(idx);
+ const int idx = arg.argumentIndex() - removedArgs;
+ const auto deRef = argumentIndirections.at(i);
+ QString argName = AbstractMetaType::dereferencePrefix(deRef)
+ + CPP_ARG_N(idx);
userArgs.append(argName);
}
}
+ // "Pass unique ptr by value" pattern: Apply std::move()
+ auto type = arg.type();
+ if (type.useStdMove())
+ userArgs.last() = stdMove(userArgs.constLast());
+ else if (type.viewOn() != nullptr)
+ userArgs.last() = explicitConversion(userArgs.constLast(), type);
}
// If any argument's default value was modified the method must be called
@@ -3525,19 +3750,19 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
QStringList otherArgs;
bool otherArgsModified = false;
bool argsClear = true;
- for (int i = func->arguments().size() - 1; i >= maxArgs + removedArgs; i--) {
+ for (auto 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();
+ const bool hasConversionRule =
+ func->hasConversionRule(TypeSystem::NativeCode, arg.argumentIndex() + 1);
if (argsClear && !defValModified && !hasConversionRule)
continue;
argsClear = false;
- otherArgsModified |= defValModified || hasConversionRule || func->argumentRemoved(i + 1);
+ otherArgsModified |= defValModified || hasConversionRule || arg.isModifiedRemoved();
if (hasConversionRule)
- otherArgs.prepend(arg.name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX));
+ otherArgs.prepend(arg.name() + CONV_RULE_OUT_VAR_SUFFIX);
else
- otherArgs.prepend(QLatin1String(CPP_ARG_REMOVED) + QString::number(i));
+ otherArgs.prepend(CPP_ARG_REMOVED(i));
}
if (otherArgsModified)
userArgs << otherArgs;
@@ -3548,17 +3773,14 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
StringStream uva(TextStream::Language::Cpp);
if (func->isOperatorOverload() && !func->isCallOperator()) {
- QString firstArg(QLatin1Char('('));
+ QString firstArg(u'(');
if (!func->isPointerOperator()) // no de-reference operator
- firstArg += QLatin1Char('*');
- firstArg += QLatin1String(CPP_SELF_VAR);
- firstArg += QLatin1Char(')');
- QString secondArg = QLatin1String(CPP_ARG0);
- if (!func->isUnaryOperator()
- && func->arguments().constFirst().type().shouldDereferencePointer()) {
- secondArg.prepend(QLatin1String("(*"));
- secondArg.append(QLatin1Char(')'));
- }
+ firstArg += u'*';
+ firstArg += CPP_SELF_VAR;
+ firstArg += u')';
+ QString secondArg = CPP_ARG0;
+ if (!func->isUnaryOperator())
+ AbstractMetaType::applyDereference(&secondArg, argumentIndirections.at(0));
if (func->isUnaryOperator())
std::swap(firstArg, secondArg);
@@ -3571,7 +3793,7 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
std::swap(firstArg, secondArg);
// Emulate operator+=/-= (__iadd__, __isub__) by using ++/--
- if (((op == QLatin1String("++")) || (op == QLatin1String("--"))) && !func->isReverseOperator()) {
+ if (((op == u"++") || (op == u"--")) && !func->isReverseOperator()) {
s << "\nfor (int i = 0; i < " << secondArg
<< "; ++i, " << op << firstArg << ");\n";
mc << firstArg;
@@ -3586,31 +3808,23 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
isCtor = true;
const auto owner = func->ownerClass();
Q_ASSERT(owner == context.metaClass());
- QString className = context.useWrapper()
- ? context.wrapperName() : owner->qualifiedCppName();
-
- if (func->functionType() == AbstractMetaFunction::CopyConstructorFunction && maxArgs == 1) {
- mc << "new ::" << className << "(*" << CPP_ARG0 << ')';
+ if (func->functionType() == AbstractMetaFunction::CopyConstructorFunction
+ && maxArgs == 1) {
+ mc << "new " << globalScopePrefix(context) << context.effectiveClassName()
+ << "(*" << CPP_ARG0 << ')';
} else {
- QString ctorCall = className + QLatin1Char('(') + userArgs.join(QLatin1String(", ")) + QLatin1Char(')');
- if (usePySideExtensions() && owner->isQObject()) {
+ const QString ctorCall = context.effectiveClassName() + u'('
+ + userArgs.join(u", "_s) + u')';
+ if (usePySideExtensions() && isQObject(owner)) {
s << "void *addr = PySide::nextQObjectMemoryAddr();\n";
- uva << "if (addr) {\n";
- {
- Indentation indent(uva);
-
- uva << "cptr = new (addr) ::" << ctorCall << ";\n"
- << "PySide::setNextQObjectMemoryAddr(0);"
- << '\n';
- }
- uva << "} else {\n";
- {
- Indentation indent(uva);
- uva << "cptr = new ::" << ctorCall << ";\n";
- }
- uva << "}\n";
+ uva << "if (addr != nullptr) {\n" << indent
+ << "cptr = new (addr) " << globalScopePrefix(context) << ctorCall
+ << ";\nPySide::setNextQObjectMemoryAddr(nullptr);\n" << outdent
+ << "} else {\n" << indent
+ << "cptr = new " << globalScopePrefix(context) << ctorCall << ";\n"
+ << outdent << "}\n";
} else {
- mc << "new ::" << ctorCall;
+ mc << "new " << globalScopePrefix(context) << ctorCall;
}
}
} else {
@@ -3624,21 +3838,22 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
const bool hasWrapper = shouldGenerateCppWrapper(ownerClass);
if (!avoidProtectedHack() || !func->isProtected() || !hasWrapper) {
if (func->isStatic()) {
- mc << "::" << methodCallClassName << "::";
+ mc << m_gsp << methodCallClassName << "::";
} else {
+ const QString cppSelfVar = CPP_SELF_VAR;
const QString selfVarCast = func->ownerClass() == func->implementingClass()
- ? QLatin1String(CPP_SELF_VAR)
- : QLatin1String("reinterpret_cast<") + methodCallClassName
- + QLatin1String(" *>(") + QLatin1String(CPP_SELF_VAR) + QLatin1Char(')');
+ ? cppSelfVar
+ : u"reinterpret_cast<"_s + methodCallClassName
+ + u" *>("_s + cppSelfVar + u')';
if (func->isConstant()) {
if (avoidProtectedHack()) {
- mc << "const_cast<const ::";
+ mc << "const_cast<const " << globalScopePrefix(context);
if (ownerClass->cppWrapper().testFlag(AbstractMetaClass::CppProtectedHackWrapper)) {
// PYSIDE-500: Need a special wrapper cast when inherited
const QString selfWrapCast = ownerClass == func->implementingClass()
- ? QLatin1String(CPP_SELF_VAR)
- : QLatin1String("reinterpret_cast<") + wrapperName(ownerClass)
- + QLatin1String(" *>(") + QLatin1String(CPP_SELF_VAR) + QLatin1Char(')');
+ ? cppSelfVar
+ : u"reinterpret_cast<"_s + wrapperName(ownerClass)
+ + u" *>("_s + cppSelfVar + u')';
mc << wrapperName(ownerClass);
mc << " *>(" << selfWrapCast << ")->";
}
@@ -3647,7 +3862,7 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
mc << " *>(" << selfVarCast << ")->";
}
} else {
- mc << "const_cast<const ::" << methodCallClassName;
+ mc << "const_cast<const " << m_gsp << methodCallClassName;
mc << " *>(" << selfVarCast << ")->";
}
} else {
@@ -3663,26 +3878,26 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
if (!func->isStatic()) {
const bool directInheritance = context.metaClass() == ownerClass;
mc << (directInheritance ? "static_cast" : "reinterpret_cast")
- << "<::" << wrapperName(ownerClass) << " *>(" << CPP_SELF_VAR << ")->";
+ << '<' << wrapperName(ownerClass) << " *>("
+ << CPP_SELF_VAR << ")->";
}
if (!func->isAbstract())
mc << (func->isProtected() ? wrapperName(func->ownerClass()) :
- QLatin1String("::")
- + methodCallClassName) << "::";
+ m_gsp + methodCallClassName) << "::";
mc << func->originalName() << "_protected";
}
} else {
mc << func->originalName();
}
- mc << '(' << userArgs.join(QLatin1String(", ")) << ')';
+ mc << '(' << userArgs.join(u", "_s) << ')';
if (!func->isAbstract() && func->isVirtual()) {
if (!avoidProtectedHack() || !func->isProtected()) {
QString virtualCall = mc;
QString normalCall = virtualCall;
- virtualCall.replace(QLatin1String("%CLASS_NAME"),
+ virtualCall.replace(u"%CLASS_NAME"_s,
methodCallClassName);
- normalCall.remove(QLatin1String("::%CLASS_NAME::"));
+ normalCall.remove(u"::%CLASS_NAME::"_s);
mc.clear();
mc << "Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject *>(self))\n"
<< " ? " << virtualCall << '\n'
@@ -3694,9 +3909,9 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
if (!injectedCodeCallsCppFunction(context, func)) {
const bool allowThread = func->allowThread();
- const bool generateExceptionHandling = func->generateExceptionHandling();
+ generateExceptionHandling = func->generateExceptionHandling();
if (generateExceptionHandling) {
- s << "try {\n" << indent;
+ s << tryBlock << indent;
if (allowThread) {
s << "Shiboken::ThreadStateSaver threadSaver;\n"
<< "threadSaver.save();\n";
@@ -3716,13 +3931,13 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
if (metaEnum.has_value()) {
QString enumName;
if (metaEnum->isProtected()) {
- enumName = context.wrapperName() + QLatin1String("::")
+ enumName = context.wrapperName() + u"::"_s
+ metaEnum.value().name();
} else {
enumName = func->type().cppSignature();
}
- const QString methodCall = enumName + QLatin1Char('(')
- + mc.toString() + QLatin1Char(')');
+ const QString methodCall = enumName + u'('
+ + mc.toString() + u')';
mc.clear();
mc << methodCall;
s << enumName;
@@ -3734,9 +3949,9 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
s << func->type().cppSignature();
if (func->type().isObjectTypeUsedAsValueType()) {
s << '*';
- methodCall = QLatin1String("new ")
+ methodCall = u"new "_s
+ func->type().typeEntry()->qualifiedCppName()
- + QLatin1Char('(') + mc.toString() + QLatin1Char(')');
+ + u'(' + mc.toString() + u')';
}
}
s << " " << CPP_RETURN_VAR << " = " << methodCall << ";\n";
@@ -3746,21 +3961,29 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
if (allowThread) {
s << (generateExceptionHandling
- ? "threadSaver.restore();" : END_ALLOW_THREADS) << '\n';
+ ? u"threadSaver.restore();"_s : END_ALLOW_THREADS) << '\n';
}
// Convert result
- if (!func->conversionRule(TypeSystem::TargetLangCode, 0).isEmpty()) {
- writeConversionRule(s, func, TypeSystem::TargetLangCode, QLatin1String(PYTHON_RETURN_VAR));
+ const auto funcType = func->type();
+ if (func->hasConversionRule(TypeSystem::TargetLangCode, 0)) {
+ writeConversionRule(s, func, TypeSystem::TargetLangCode,
+ PYTHON_RETURN_VAR);
} else if (!isCtor && !func->isInplaceOperator() && !func->isVoid()
&& !func->injectedCodeHasReturnValueAttribution(TypeSystem::TargetLangCode)) {
- s << PYTHON_RETURN_VAR << " = ";
if (func->type().isObjectTypeUsedAsValueType()) {
- s << "Shiboken::Object::newObject(reinterpret_cast<SbkObjectType *>("
+ s << PYTHON_RETURN_VAR << " = Shiboken::Object::newObject("
<< cpythonTypeNameExt(func->type().typeEntry())
- << "), " << CPP_RETURN_VAR << ", true, true)";
+ << ", " << CPP_RETURN_VAR << ", true, true)";
+ } else if (func->generateOpaqueContainerReturn()) {
+ const QString creationFunc = opaqueContainerCreationFunc(funcType);
+ writeOpaqueContainerCreationFuncDecl(s, creationFunc, funcType);
+ s << PYTHON_RETURN_VAR << " = " << creationFunc
+ << "(&" << CPP_RETURN_VAR << ");\n";
} else {
- writeToPythonConversion(s, func->type(), func->ownerClass(), QLatin1String(CPP_RETURN_VAR));
+ s << PYTHON_RETURN_VAR << " = ";
+ writeToPythonConversion(s, funcType, func->ownerClass(),
+ CPP_RETURN_VAR);
}
s << ";\n";
}
@@ -3768,11 +3991,12 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
if (generateExceptionHandling) { // "catch" code
s << outdent << defaultExceptionHandling;
}
- }
- }
+ } // !injected code calls C++ function
+ } // !userAdded
if (func->hasInjectedCode() && !func->isConstructor())
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode, func, lastArg);
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd,
+ TypeSystem::TargetLangCode, func, usesPyArgs, lastArg);
bool hasReturnPolicy = false;
@@ -3795,25 +4019,11 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
if (!ownership_mods.isEmpty()) {
s << '\n' << "// Ownership transferences.\n";
- for (const ArgumentModification &arg_mod : qAsConst(ownership_mods)) {
- const AbstractMetaClass *wrappedClass = nullptr;
- QString errorMessage;
- QString pyArgName = argumentNameFromIndex(api(), func, arg_mod.index(),
- &wrappedClass, &errorMessage);
- if (!wrappedClass) {
- QString message;
- QTextStream str(&message);
- str << "Invalid ownership modification for argument " << arg_mod.index()
- << " (" << pyArgName << ") of ";
- if (const AbstractMetaClass *declaringClass = func->declaringClass())
- str << declaringClass->name() << "::";
- str << func->name() << "(): " << errorMessage;
- qCWarning(lcShiboken, "%s", qPrintable(message));
- s << "#error " << message << '\n';
- break;
- }
+ for (const ArgumentModification &arg_mod : std::as_const(ownership_mods)) {
+ const int argIndex = arg_mod.index();
+ const QString pyArgName = argumentNameFromIndex(api(), func, argIndex);
- if (arg_mod.index() == 0 || arg_mod.owner().index == 0)
+ if (argIndex == 0 || arg_mod.owner().index == 0)
hasReturnPolicy = true;
// The default ownership does nothing. This is useful to avoid automatic heuristically
@@ -3825,11 +4035,9 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
s << "Shiboken::Object::";
if (ownership == TypeSystem::TargetLangOwnership) {
s << "getOwnership(" << pyArgName << ");";
- } else if (wrappedClass->hasVirtualDestructor()) {
- if (arg_mod.index() == 0)
- s << "releaseOwnership(" << PYTHON_RETURN_VAR << ");";
- else
- s << "releaseOwnership(" << pyArgName << ");";
+ } else if (auto ac = argumentClassFromIndex(api(), func, argIndex);
+ ac && ac->hasVirtualDestructor()) {
+ s << "releaseOwnership(" << pyArgName << ");";
} else {
s << "invalidate(" << pyArgName << ");";
}
@@ -3837,7 +4045,7 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
}
} else if (!refcount_mods.isEmpty()) {
- for (const ArgumentModification &arg_mod : qAsConst(refcount_mods)) {
+ for (const ArgumentModification &arg_mod : std::as_const(refcount_mods)) {
ReferenceCount refCount = arg_mod.referenceCounts().constFirst();
if (refCount.action != ReferenceCount::Set
&& refCount.action != ReferenceCount::Remove
@@ -3845,28 +4053,9 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
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 {
- QString errorMessage;
- pyArgName = argumentNameFromIndex(api(), func, arg_mod.index(),
- &wrappedClass, &errorMessage);
- if (pyArgName.isEmpty()) {
- QString message;
- QTextStream str(&message);
- str << "Invalid reference count modification for argument "
- << arg_mod.index() << " of ";
- if (const AbstractMetaClass *declaringClass = func->declaringClass())
- str << declaringClass->name() << "::";
- str << func->name() << "(): " << errorMessage;
- qCWarning(lcShiboken, "%s", qPrintable(message));
- s << "#error " << message << "\n\n";
- break;
- }
- }
+ const int argIndex = arg_mod.index();
+ const QString pyArgName = refCount.action == ReferenceCount::Remove
+ ? u"Py_None"_s : argumentNameFromIndex(api(), func, argIndex);
if (refCount.action == ReferenceCount::Add || refCount.action == ReferenceCount::Set)
s << "Shiboken::Object::keepReference(";
@@ -3876,25 +4065,28 @@ void CppGenerator::writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr
s << "reinterpret_cast<SbkObject *>(self), \"";
QString varName = arg_mod.referenceCounts().constFirst().varName;
if (varName.isEmpty())
- varName = func->minimalSignature() + QString::number(arg_mod.index());
+ varName = func->minimalSignature() + QString::number(argIndex);
s << varName << "\", " << pyArgName
<< (refCount.action == ReferenceCount::Add ? ", true" : "")
<< ");\n";
- if (arg_mod.index() == 0)
+ if (argIndex == 0)
hasReturnPolicy = true;
}
}
- writeParentChildManagement(s, func, !hasReturnPolicy);
+ writeParentChildManagement(s, func, usesPyArgs, !hasReturnPolicy);
+
+ if (generateExceptionHandling)
+ s << propagateException;
}
-QStringList CppGenerator::getAncestorMultipleInheritance(const AbstractMetaClass *metaClass)
+QStringList CppGenerator::getAncestorMultipleInheritance(const AbstractMetaClassCPtr &metaClass)
{
QStringList result;
- const AbstractMetaClassList &baseClases = metaClass->typeSystemBaseClasses();
+ const auto &baseClases = metaClass->typeSystemBaseClasses();
if (!baseClases.isEmpty()) {
- for (const AbstractMetaClass *baseClass : baseClases) {
+ for (const auto &baseClass : baseClases) {
QString offset;
QTextStream(&offset) << "reinterpret_cast<uintptr_t>(static_cast<const "
<< baseClass->qualifiedCppName() << " *>(class_ptr)) - base";
@@ -3907,247 +4099,203 @@ QStringList CppGenerator::getAncestorMultipleInheritance(const AbstractMetaClass
result.append(offset);
}
- for (const AbstractMetaClass *baseClass : baseClases)
+ for (const auto &baseClass : baseClases)
result.append(getAncestorMultipleInheritance(baseClass));
}
return result;
}
-void CppGenerator::writeMultipleInheritanceInitializerFunction(TextStream &s, const AbstractMetaClass *metaClass)
+void CppGenerator::writeMultipleInheritanceInitializerFunction(TextStream &s,
+ const AbstractMetaClassCPtr &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"
- << "int *\n"
+ s << "int *\n"
<< multipleInheritanceInitializerFunctionName(metaClass) << "(const void *cptr)\n"
- << "{\n" << indent
- << "if (mi_offsets[0] == -1) {\n";
- {
- Indentation indent(s);
- s << "std::set<int> offsets;\n"
- << "const auto *class_ptr = reinterpret_cast<const " << className << " *>(cptr);\n"
- << "const auto base = reinterpret_cast<uintptr_t>(class_ptr);\n";
-
- for (const QString &ancestor : ancestors)
- s << "offsets.insert(int(" << ancestor << "));\n";
-
- s << "\noffsets.erase(0);\n\n"
- << "std::copy(offsets.cbegin(), offsets.cend(), mi_offsets);\n";
- }
- s << "}\nreturn mi_offsets;\n" << outdent << "}\n";
-}
-
-void CppGenerator::writeSpecialCastFunction(TextStream &s, const AbstractMetaClass *metaClass)
+ << "{\n" << indent;
+ s << "static int mi_offsets[] = {-2";
+ for (qsizetype i = 0; i < ancestors.size(); i++)
+ s << ", 0";
+ s << "};\n"
+ << "if (mi_offsets[0] == -2) {\n" << indent
+ << "const auto *class_ptr = reinterpret_cast<const " << className << " *>(cptr);\n"
+ << "const auto base = reinterpret_cast<uintptr_t>(class_ptr);\n"
+ << "int *p = mi_offsets;\n";
+
+ for (const QString &ancestor : ancestors)
+ s << "*p++ = int(" << ancestor << ");\n";
+ s << "std::sort(mi_offsets, p);\n"
+ << "auto *end = std::unique(mi_offsets, p);\n"
+ << "*end++ = -1;\n"
+ << "if (mi_offsets[0] == 0)\n"
+ << indent
+ << "std::memmove(&mi_offsets[0], &mi_offsets[1], (end - mi_offsets - 1) * sizeof(int));\n"
+ << outdent << outdent
+ << "}\nreturn mi_offsets;\n" << outdent << "}\n";
+}
+
+void CppGenerator::writeSpecialCastFunction(TextStream &s, const AbstractMetaClassCPtr &metaClass)
{
QString className = metaClass->qualifiedCppName();
s << "static void * " << cpythonSpecialCastFunctionName(metaClass)
- << "(void *obj, SbkObjectType *desiredType)\n{\n" << indent
- << "auto me = reinterpret_cast< ::" << className << " *>(obj);\n";
+ << "(void *obj, PyTypeObject *desiredType)\n{\n" << indent
+ << "auto me = reinterpret_cast< " << m_gsp << className << " *>(obj);\n";
bool firstClass = true;
- const AbstractMetaClassList &allAncestors = metaClass->allTypeSystemAncestors();
- for (const AbstractMetaClass *baseClass : allAncestors) {
+ const auto &allAncestors = metaClass->allTypeSystemAncestors();
+ for (const auto &baseClass : allAncestors) {
if (!firstClass)
s << "else ";
- s << "if (desiredType == reinterpret_cast<SbkObjectType *>("
- << cpythonTypeNameExt(baseClass->typeEntry()) << "))\n";
- Indentation indent(s);
- s << "return static_cast< ::" << baseClass->qualifiedCppName() << " *>(me);\n";
+ s << "if (desiredType == " << cpythonTypeNameExt(baseClass->typeEntry())
+ << ")\n" << indent
+ << "return static_cast< " << getFullTypeName(baseClass) << " *>(me);\n"
+ << outdent;
firstClass = false;
}
s << "return me;\n" << outdent << "}\n\n";
}
void CppGenerator::writePrimitiveConverterInitialization(TextStream &s,
- const CustomConversion *customConversion)
+ const CustomConversionPtr &customConversion)
{
- const TypeEntry *type = customConversion->ownerType();
+ TypeEntryCPtr type = customConversion->ownerType();
QString converter = converterObject(type);
s << "// Register converter for type '" << type->qualifiedTargetLangName() << "'.\n"
<< converter << " = Shiboken::Conversions::createConverter(";
- if (type->targetLangApiName() == type->name())
- s << '0';
- else if (type->targetLangApiName() == cPyObjectT())
+ if (!type->hasTargetLangApiType())
+ s << "nullptr";
+ else if (type->targetLangApiName() == cPyObjectT)
s << "&PyBaseObject_Type";
else
s << '&' << type->targetLangApiName() << "_Type";
QString typeName = fixedCppTypeName(type);
s << ", " << cppToPythonFunctionName(typeName, typeName) << ");\n"
- << "Shiboken::Conversions::registerConverterName(" << converter << ", \""
- << type->qualifiedCppName() << "\");\n";
+ << registerConverterName(type->qualifiedCppName(), converter);
writeCustomConverterRegister(s, customConversion, converter);
}
-void CppGenerator::writeEnumConverterInitialization(TextStream &s, const AbstractMetaEnum &metaEnum)
+static void registerConverterInScopes(TextStream &s, QStringView signature,
+ QAnyStringView varName = converterVar)
{
- if (metaEnum.isPrivate() || metaEnum.isAnonymous())
- return;
- writeEnumConverterInitialization(s, metaEnum.typeEntry());
+ while (true) {
+ s << registerConverterName(signature, varName);
+ const auto qualifierPos = signature.indexOf("::"_L1);
+ if (qualifierPos == -1)
+ break;
+ signature = signature.sliced(qualifierPos + 2);
+ }
}
-void CppGenerator::writeEnumConverterInitialization(TextStream &s, const TypeEntry *enumType)
+void CppGenerator::writeEnumConverterInitialization(TextStream &s, const AbstractMetaEnum &metaEnum)
{
- if (!enumType)
+ if (metaEnum.isPrivate() || metaEnum.isAnonymous())
return;
- QString enumFlagName = enumType->isFlags() ? QLatin1String("flag") : QLatin1String("enum");
- QString enumPythonType = cpythonTypeNameExt(enumType);
+ EnumTypeEntryCPtr enumType = metaEnum.typeEntry();
+ Q_ASSERT(enumType);
- const FlagsTypeEntry *flags = nullptr;
- if (enumType->isFlags())
- flags = static_cast<const FlagsTypeEntry *>(enumType);
+ static const char enumPythonVar[] = "EType";
- s << "// Register converter for " << enumFlagName << " '" << enumType->qualifiedCppName()
- << "'.\n{\n";
- {
- Indentation indent(s);
- QString typeName = fixedCppTypeName(enumType);
- s << "SbkConverter *converter = Shiboken::Conversions::createConverter("
- << enumPythonType << ',' << '\n';
- {
- Indentation indent(s);
- s << 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);
+ s << "// Register converter for enum '" << enumType->qualifiedCppName()
+ << "'.\n{\n" << indent;
- if (flags) {
- QString toCpp = pythonToCppFunctionName(QLatin1String("number"), typeName);
- QString isConv = convertibleToCppFunctionName(QLatin1String("number"), typeName);
- writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
- }
+ const QString typeName = fixedCppTypeName(enumType);
+ s << "SbkConverter *converter = Shiboken::Conversions::createConverter("
+ << enumPythonVar << ',' << '\n' << indent
+ << cppToPythonFunctionName(typeName, typeName) << ");\n" << outdent;
- s << "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();
- }
- }
+ const QString toCpp = pythonToCppFunctionName(typeName, typeName);
+ const QString isConv = convertibleToCppFunctionName(typeName, typeName);
+ writeAddPythonToCppConversion(s, u"converter"_s, toCpp, isConv);
+ s << "Shiboken::Enum::setTypeConverter(" << enumPythonVar
+ << ", converter);\n";
- while (true) {
- s << "Shiboken::Conversions::registerConverterName(converter, \""
- << signature << "\");\n";
- const int qualifierPos = signature.indexOf(QLatin1String("::"));
- if (qualifierPos != -1)
- signature.remove(0, qualifierPos + 2);
- else
- break;
- }
- }
- s << "}\n";
+ registerConverterInScopes(s, enumType->qualifiedCppName());
+ if (auto flags = enumType->flags())
+ s << "// Register converter for flag '" << flags->qualifiedCppName() << "'.\n"
+ << registerConverterName(flags->name()) // QMetaType
+ << registerConverterName(flags->originalName()); // Signals with flags
- if (!flags)
- writeEnumConverterInitialization(s, static_cast<const EnumTypeEntry *>(enumType)->flags());
+ s << outdent << "}\n";
}
-void CppGenerator::writeContainerConverterInitialization(TextStream &s, const AbstractMetaType &type) const
+QString CppGenerator::writeContainerConverterInitialization(TextStream &s,
+ const AbstractMetaType &type,
+ const ApiExtractorResult &api)
{
- QByteArray cppSignature = QMetaObject::normalizedSignature(type.cppSignature().toUtf8());
+ const auto cppSignature =
+ QString::fromUtf8(QMetaObject::normalizedSignature(type.cppSignature().toUtf8()));
s << "// Register converter for type '" << cppSignature << "'.\n";
- QString converter = converterObject(type);
+ const QString converter = converterObject(type);
s << converter << " = Shiboken::Conversions::createConverter(";
- if (type.typeEntry()->targetLangApiName() == cPyObjectT()) {
+
+ Q_ASSERT(type.typeEntry()->isContainer());
+ const auto typeEntry = std::static_pointer_cast<const ContainerTypeEntry>(type.typeEntry());
+
+ const QString targetTypeName = containerNativeToTargetTypeName(typeEntry);
+ if (targetTypeName == cPyObjectT) {
s << "&PyBaseObject_Type";
} else {
- QString baseName = cpythonBaseName(type.typeEntry());
- if (baseName == cPySequenceT())
- baseName = cPyListT();
- s << '&' << baseName << "_Type";
+ s << '&' << targetTypeName << "_Type";
}
- QString typeName = fixedCppTypeName(type);
- s << ", " << cppToPythonFunctionName(typeName, typeName) << ");\n";
- QString toCpp = pythonToCppFunctionName(typeName, typeName);
- QString isConv = convertibleToCppFunctionName(typeName, typeName);
- s << "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 << "Shiboken::Conversions::registerConverterName(" << converter << ", \"" << cppSignature << "\");\n";
- }
- writeAddPythonToCppConversion(s, converterObject(type), toCpp, isConv);
-}
-
-void CppGenerator::writeSmartPointerConverterInitialization(TextStream &s, const AbstractMetaType &type) const
-{
- const QByteArray cppSignature = type.cppSignature().toUtf8();
- auto writeConversionRegister = [&s](const AbstractMetaType &sourceType, const QString &targetTypeName, const QString &targetConverter)
- {
- const QString sourceTypeName = fixedCppTypeName(sourceType);
- const QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName);
- const QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName);
- writeAddPythonToCppConversion(s, targetConverter, toCpp, isConv);
- };
+ const QString typeName = fixedCppTypeName(type);
+ s << ", " << cppToPythonFunctionName(typeName, targetTypeName) << ");\n";
- auto klass = AbstractMetaClass::findClass(api().classes(), type.instantiations().at(0).typeEntry());
- if (!klass)
- return;
+ s << registerConverterName(cppSignature, converter);
+ if (usePySideExtensions() && cppSignature.startsWith("const "_L1)
+ && cppSignature.endsWith(u'&')) {
+ auto underlyingType = QStringView{cppSignature}.sliced(6, cppSignature.size() - 7);
+ s << registerConverterName(underlyingType, converter);
+ }
- const auto classes = klass->typeSystemBaseClasses();
- if (classes.isEmpty())
- return;
+ for (const auto &conv : typeEntry->customConversion()->targetToNativeConversions()) {
+ const QString &sourceTypeName = conv.sourceTypeName();
+ QString toCpp = pythonToCppFunctionName(sourceTypeName, typeName);
+ QString isConv = convertibleToCppFunctionName(sourceTypeName, typeName);
+ writeAddPythonToCppConversion(s, converter, toCpp, isConv);
+ }
- s << "// Register SmartPointer converter for type '" << cppSignature << "'." << '\n'
- << "///////////////////////////////////////////////////////////////////////////////////////\n\n";
-
- for (auto k : classes) {
- auto smartTargetType = findSmartPointerInstantiation(k->typeEntry());
- if (smartTargetType.has_value()) {
- s << "// Convert to SmartPointer derived class: ["
- << smartTargetType->cppSignature() << "]\n";
- const QString converter =
- QLatin1String("Shiboken::Conversions::getConverter(\"%1\")").arg(smartTargetType->cppSignature());
- writeConversionRegister(type, fixedCppTypeName(smartTargetType.value()), converter);
- } else {
- s << "// Class not found:" << type.instantiations().at(0).cppSignature();
+ auto typedefItPair = api.typedefTargetToName().equal_range(type.cppSignature());
+ if (typedefItPair.first != typedefItPair.second) {
+ auto *typeDb = TypeDatabase::instance();
+ s << "// Register converters for type aliases of " << cppSignature << "'.\n";
+ for (auto it = typedefItPair.first; it != typedefItPair.second; ++it) {
+ if (!typeDb->findType(it.value()))
+ s << registerConverterName(it.value(), converter);
}
}
- s << "///////////////////////////////////////////////////////////////////////////////////////" << '\n' << '\n';
+ return converter;
}
-void CppGenerator::writeExtendedConverterInitialization(TextStream &s, const TypeEntry *externalType,
+QString CppGenerator::typeInitStruct(const TypeEntryCPtr &te)
+{
+ return cppApiVariableName(te->targetLangPackage()) + u'['
+ + getTypeIndexVariableName(te) + u']';
+}
+
+void CppGenerator::writeExtendedConverterInitialization(TextStream &s,
+ const TypeEntryCPtr &externalType,
const AbstractMetaClassCList &conversions)
{
s << "// Extended implicit conversions for " << externalType->qualifiedTargetLangName()
<< ".\n";
- for (const AbstractMetaClass *sourceClass : conversions) {
- const QString converterVar = QLatin1String("reinterpret_cast<SbkObjectType *>(")
- + cppApiVariableName(externalType->targetLangPackage()) + QLatin1Char('[')
- + getTypeIndexVariableName(externalType) + QLatin1String("])");
+ for (const auto &sourceClass : conversions) {
QString sourceTypeName = fixedCppTypeName(sourceClass->typeEntry());
QString targetTypeName = fixedCppTypeName(externalType);
QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName);
QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName);
- writeAddPythonToCppConversion(s, converterVar, toCpp, isConv);
+ if (!externalType->isPrimitive())
+ s << cpythonTypeNameExt(externalType) << ";\n";
+ writeAddPythonToCppConversion(s, typeInitStruct(externalType), toCpp, isConv);
}
}
-QString CppGenerator::multipleInheritanceInitializerFunctionName(const AbstractMetaClass *metaClass)
+QString CppGenerator::multipleInheritanceInitializerFunctionName(const AbstractMetaClassCPtr &metaClass)
{
- return cpythonBaseName(metaClass->typeEntry()) + QLatin1String("_mi_init");
+ return cpythonBaseName(metaClass->typeEntry()) + u"_mi_init"_s;
}
-bool CppGenerator::supportsMappingProtocol(const AbstractMetaClass *metaClass)
+bool CppGenerator::supportsMappingProtocol(const AbstractMetaClassCPtr &metaClass)
{
for (const auto &m : mappingProtocols()) {
if (metaClass->hasFunction(m.name))
@@ -4157,7 +4305,7 @@ bool CppGenerator::supportsMappingProtocol(const AbstractMetaClass *metaClass)
return false;
}
-bool CppGenerator::supportsNumberProtocol(const AbstractMetaClass *metaClass) const
+bool CppGenerator::supportsNumberProtocol(const AbstractMetaClassCPtr &metaClass)
{
return metaClass->hasArithmeticOperatorOverload()
|| metaClass->hasIncDecrementOperatorOverload()
@@ -4166,18 +4314,18 @@ bool CppGenerator::supportsNumberProtocol(const AbstractMetaClass *metaClass) co
|| hasBoolCast(metaClass);
}
-bool CppGenerator::supportsSequenceProtocol(const AbstractMetaClass *metaClass)
+bool CppGenerator::supportsSequenceProtocol(const AbstractMetaClassCPtr &metaClass)
{
for (const auto &seq : sequenceProtocols()) {
if (metaClass->hasFunction(seq.name))
return true;
}
- const ComplexTypeEntry *baseType = metaClass->typeEntry()->baseContainerType();
+ ComplexTypeEntryCPtr baseType = metaClass->typeEntry()->baseContainerType();
return baseType && baseType->isContainer();
}
-bool CppGenerator::shouldGenerateGetSetList(const AbstractMetaClass *metaClass) const
+bool CppGenerator::shouldGenerateGetSetList(const AbstractMetaClassCPtr &metaClass)
{
for (const AbstractMetaField &f : metaClass->fields()) {
if (!f.isStatic())
@@ -4195,63 +4343,57 @@ bool CppGenerator::shouldGenerateGetSetList(const AbstractMetaClass *metaClass)
struct pyTypeSlotEntry
{
- explicit pyTypeSlotEntry(const char *name, const QString &function) :
+ explicit pyTypeSlotEntry(QAnyStringView name, QAnyStringView function) :
m_name(name), m_function(function) {}
- const char *m_name;
- const QString &m_function;
+ QAnyStringView m_name;
+ QAnyStringView m_function;
};
TextStream &operator<<(TextStream &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";
+ if (!e.m_function.isEmpty()) {
+ str << '{' << e.m_name << ',' << Pad(' ', qMax(0, 18 - e.m_name.size()))
+ << "reinterpret_cast<void *>(" << e.m_function << ")},\n";
+ }
return str;
}
void CppGenerator::writeClassDefinition(TextStream &s,
- const AbstractMetaClass *metaClass,
+ const AbstractMetaClassCPtr &metaClass,
const GeneratorContext &classContext)
{
- QString tp_flags;
QString tp_init;
QString tp_new;
QString tp_dealloc;
QString tp_hash;
QString tp_call;
const QString className = chopType(cpythonTypeName(metaClass));
- QString baseClassName;
AbstractMetaFunctionCList ctors;
- const auto &allCtors = metaClass->queryFunctions(FunctionQueryOption::Constructors);
+ const auto &allCtors = metaClass->queryFunctions(FunctionQueryOption::AnyConstructor);
for (const auto &f : allCtors) {
- if (!f->isPrivate() && !f->isModifiedRemoved() && !classContext.forSmartPointer())
+ if (!f->isPrivate() && !f->isModifiedRemoved()
+ && f->functionType() != AbstractMetaFunction::MoveConstructorFunction) {
ctors.append(f);
+ }
}
- if (!metaClass->baseClass())
- baseClassName = QLatin1String("reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())");
-
bool onlyPrivCtor = !metaClass->hasNonPrivateConstructor();
- const AbstractMetaClass *qCoreApp = AbstractMetaClass::findClass(api().classes(), QLatin1String("QCoreApplication"));
- const bool isQApp = qCoreApp != Q_NULLPTR && metaClass->inheritsFrom(qCoreApp);
+ const bool isQApp = usePySideExtensions()
+ && inheritsFrom(metaClass, u"QCoreApplication"_s);
- tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES");
+ QString tp_flags = u"Py_TPFLAGS_DEFAULT"_s;
+ if (!metaClass->attributes().testFlag(AbstractMetaClass::FinalCppClass))
+ tp_flags += u"|Py_TPFLAGS_BASETYPE"_s;
if (metaClass->isNamespace() || metaClass->hasPrivateDestructor()) {
tp_dealloc = metaClass->hasPrivateDestructor() ?
- QLatin1String("SbkDeallocWrapperWithPrivateDtor") :
- QLatin1String("Sbk_object_dealloc /* PYSIDE-832: Prevent replacement of \"0\" with subtype_dealloc. */");
+ u"SbkDeallocWrapperWithPrivateDtor"_s :
+ u"Sbk_object_dealloc /* PYSIDE-832: Prevent replacement of \"0\" with subtype_dealloc. */"_s;
tp_init.clear();
} else {
tp_dealloc = isQApp
- ? QLatin1String("&SbkDeallocQAppWrapper") : QLatin1String("&SbkDeallocWrapper");
+ ? u"&SbkDeallocQAppWrapper"_s : u"&SbkDeallocWrapper"_s;
if (!onlyPrivCtor && !ctors.isEmpty())
tp_init = cpythonFunctionName(ctors.constFirst());
}
@@ -4263,53 +4405,59 @@ void CppGenerator::writeClassDefinition(TextStream &s,
? cpythonSetattroFunctionName(metaClass) : QString();
if (metaClass->hasPrivateDestructor() || onlyPrivCtor) {
- // tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES");
+ // tp_flags = u"Py_TPFLAGS_DEFAULT"_s;
// 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("PySide6.Qt"))) {
+ // Instead, we check this at runtime, see SbkObjectType_tp_new.
+ if (metaClass->fullName().startsWith(u"PySide6.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");
+ tp_new = u"SbkObject_tp_new"_s;
}
else {
- tp_new = QLatin1String("SbkDummyNew /* PYSIDE-595: Prevent replacement "
- "of \"0\" with base->tp_new. */");
+ tp_new = u"SbkDummyNew /* PYSIDE-595: Prevent replacement "
+ "of \"0\" with base->tp_new. */"_s;
}
}
else if (isQApp) {
- tp_new = QLatin1String("SbkQAppTpNew"); // PYSIDE-571: need singleton app
+ tp_new = u"SbkQApp_tp_new"_s; // PYSIDE-571: need singleton app
}
else {
- tp_new = QLatin1String("SbkObjectTpNew");
+ tp_new = u"SbkObject_tp_new"_s;
}
- tp_flags.append(QLatin1String("|Py_TPFLAGS_HAVE_GC"));
+ tp_flags.append(u"|Py_TPFLAGS_HAVE_GC"_s);
QString tp_richcompare;
- if (!metaClass->isNamespace() && metaClass->hasComparisonOperatorOverload())
- tp_richcompare = cpythonBaseName(metaClass) + QLatin1String("_richcompare");
+ if (generateRichComparison(classContext))
+ tp_richcompare = cpythonBaseName(metaClass) + u"_richcompare"_s;
+ const bool isSmartPointer = classContext.forSmartPointer();
QString tp_getset;
- if (shouldGenerateGetSetList(metaClass) && !classContext.forSmartPointer())
+ if (shouldGenerateGetSetList(metaClass) && !isSmartPointer)
tp_getset = cpythonGettersSettersDefinitionName(metaClass);
// search for special functions
clearTpFuncs();
for (const auto &func : metaClass->functions()) {
- if (m_tpFuncs.contains(func->name()))
- m_tpFuncs[func->name()] = cpythonFunctionName(func);
+ // Special non-operator functions identified by name
+ auto it = m_tpFuncs.find(func->name());
+ if (it != m_tpFuncs.end())
+ it.value() = cpythonFunctionName(func);
+ else if ( it = m_nbFuncs.find(func->name()); it != m_nbFuncs.end() )
+ it.value() = cpythonFunctionName(func);
}
- if (m_tpFuncs.value(reprFunction()).isEmpty()
- && metaClass->hasToStringCapability()) {
- m_tpFuncs[reprFunction()] = writeReprFunction(s,
- classContext,
- metaClass->toStringCapabilityIndirections());
+ if (m_tpFuncs.value(REPR_FUNCTION).isEmpty()
+ && (isSmartPointer || metaClass->hasToStringCapability())) {
+ const QString name = isSmartPointer
+ ? writeSmartPointerReprFunction(s, classContext)
+ : writeReprFunction(s, classContext, metaClass->toStringCapabilityIndirections());
+ m_tpFuncs[REPR_FUNCTION] = name;
}
// class or some ancestor has multiple inheritance
- const AbstractMetaClass *miClass = getMultipleInheritingClass(metaClass);
+ const auto miClass = getMultipleInheritingClass(metaClass);
if (miClass) {
if (metaClass == miClass)
writeMultipleInheritanceInitializerFunction(s, metaClass);
@@ -4320,39 +4468,33 @@ void CppGenerator::writeClassDefinition(TextStream &s,
s << "// Class Definition -----------------------------------------------\n"
"extern \"C\" {\n";
- if (!metaClass->typeEntry()->hashFunction().isEmpty())
- tp_hash = QLatin1Char('&') + cpythonBaseName(metaClass) + QLatin1String("_HashFunc");
+ if (hasHashFunction(metaClass))
+ tp_hash = u'&' + cpythonBaseName(metaClass) + u"_HashFunc"_s;
- const auto callOp = metaClass->findFunction(QLatin1String("operator()"));
- if (!callOp.isNull() && !callOp->isModifiedRemoved())
- tp_call = QLatin1Char('&') + cpythonFunctionName(callOp);
-
- QString computedClassTargetFullName;
- if (!classContext.forSmartPointer())
- computedClassTargetFullName = getClassTargetFullName(metaClass);
- else
- computedClassTargetFullName = getClassTargetFullName(classContext.preciseType());
+ const auto callOp = metaClass->findFunction("operator()");
+ if (callOp && !callOp->isModifiedRemoved())
+ tp_call = u'&' + cpythonFunctionName(callOp);
- const QString typePtr = QLatin1String("_") + className
- + QLatin1String("_Type");
- s << "static SbkObjectType *" << typePtr << " = nullptr;\n"
- << "static SbkObjectType *" << className << "_TypeF(void)\n"
+ const QString typePtr = u"_"_s + className
+ + u"_Type"_s;
+ s << "static PyTypeObject *" << typePtr << " = nullptr;\n"
+ << "static PyTypeObject *" << className << "_TypeF(void)\n"
<< "{\n" << indent << "return " << typePtr << ";\n" << outdent
<< "}\n\nstatic PyType_Slot " << className << "_slots[] = {\n" << indent
<< "{Py_tp_base, nullptr}, // inserted by introduceWrapperType\n"
<< pyTypeSlotEntry("Py_tp_dealloc", tp_dealloc)
- << pyTypeSlotEntry("Py_tp_repr", m_tpFuncs.value(reprFunction()))
+ << pyTypeSlotEntry("Py_tp_repr", m_tpFuncs.value(REPR_FUNCTION))
<< pyTypeSlotEntry("Py_tp_hash", tp_hash)
<< pyTypeSlotEntry("Py_tp_call", tp_call)
- << pyTypeSlotEntry("Py_tp_str", m_tpFuncs.value(QLatin1String("__str__")))
+ << pyTypeSlotEntry("Py_tp_str", m_tpFuncs.value(u"__str__"_s))
<< pyTypeSlotEntry("Py_tp_getattro", tp_getattro)
<< pyTypeSlotEntry("Py_tp_setattro", tp_setattro)
- << pyTypeSlotEntry("Py_tp_traverse", className + QLatin1String("_traverse"))
- << pyTypeSlotEntry("Py_tp_clear", className + QLatin1String("_clear"))
+ << pyTypeSlotEntry("Py_tp_traverse", className + u"_traverse"_s)
+ << pyTypeSlotEntry("Py_tp_clear", className + u"_clear"_s)
<< pyTypeSlotEntry("Py_tp_richcompare", tp_richcompare)
- << pyTypeSlotEntry("Py_tp_iter", m_tpFuncs.value(QLatin1String("__iter__")))
- << pyTypeSlotEntry("Py_tp_iternext", m_tpFuncs.value(QLatin1String("__next__")))
- << pyTypeSlotEntry("Py_tp_methods", className + QLatin1String("_methods"))
+ << pyTypeSlotEntry("Py_tp_iter", m_tpFuncs.value(u"__iter__"_s))
+ << pyTypeSlotEntry("Py_tp_iternext", m_tpFuncs.value(u"__next__"_s))
+ << pyTypeSlotEntry("Py_tp_methods", className + u"_methods"_s)
<< pyTypeSlotEntry("Py_tp_getset", tp_getset)
<< pyTypeSlotEntry("Py_tp_init", tp_init)
<< pyTypeSlotEntry("Py_tp_new", tp_new);
@@ -4365,63 +4507,62 @@ void CppGenerator::writeClassDefinition(TextStream &s,
writeTypeAsMappingDefinition(s, metaClass);
}
if (supportsNumberProtocol(metaClass)) {
- // This one must come last. See the function itself.
s << "// type supports number protocol\n";
writeTypeAsNumberDefinition(s, metaClass);
}
s << "{0, " << NULL_PTR << "}\n" << outdent << "};\n";
- int packageLevel = packageName().count(QLatin1Char('.')) + 1;
+ int packageLevel = packageName().count(u'.') + 1;
s << "static PyType_Spec " << className << "_spec = {\n" << indent
- << '"' << packageLevel << ':' << computedClassTargetFullName << "\",\n"
+ << '"' << packageLevel << ':' << getClassTargetFullName(metaClass) << "\",\n"
<< "sizeof(SbkObject),\n0,\n" << tp_flags << ",\n"
<< className << "_slots\n" << outdent
<< "};\n\n} //extern \"C\"\n";
}
void CppGenerator::writeMappingMethods(TextStream &s,
- const AbstractMetaClass *metaClass,
+ const AbstractMetaClassCPtr &metaClass,
const GeneratorContext &context) const
{
for (const auto & m : mappingProtocols()) {
const auto func = metaClass->findFunction(m.name);
- if (func.isNull())
+ if (!func)
continue;
QString funcName = cpythonFunctionName(func);
CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
- s << m.returnType << ' ' << funcName << '(' << m.arguments << ")\n{\n";
- writeInvalidPyObjectCheck(s, QLatin1String("self"));
+ s << m.returnType << ' ' << funcName << '(' << m.arguments << ")\n{\n" << indent;
- writeCppSelfDefinition(s, func, context);
+ writeCppSelfDefinition(s, func, context, ErrorReturn::Default);
const AbstractMetaArgument *lastArg = func->arguments().isEmpty()
? nullptr : &func->arguments().constLast();
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, lastArg);
- s<< "}\n\n";
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny,
+ TypeSystem::TargetLangCode, func, false, lastArg);
+ s << outdent << "}\n\n";
}
}
void CppGenerator::writeSequenceMethods(TextStream &s,
- const AbstractMetaClass *metaClass,
+ const AbstractMetaClassCPtr &metaClass,
const GeneratorContext &context) const
{
bool injectedCode = false;
for (const auto &seq : sequenceProtocols()) {
const auto func = metaClass->findFunction(seq.name);
- if (func.isNull())
+ if (!func)
continue;
injectedCode = true;
QString funcName = cpythonFunctionName(func);
CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
s << seq.returnType << ' ' << funcName << '(' << seq.arguments << ")\n{\n" << indent;
- writeInvalidPyObjectCheck(s, QLatin1String("self"));
- writeCppSelfDefinition(s, func, context);
+ writeCppSelfDefinition(s, func, context, ErrorReturn::Default);
const AbstractMetaArgument *lastArg = func->arguments().isEmpty() ? nullptr : &func->arguments().constLast();
- writeCodeSnips(s, snips,TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, lastArg);
+ writeCodeSnips(s, snips,TypeSystem::CodeSnipPositionAny,
+ TypeSystem::TargetLangCode, func, false /* uses PyArgs */, lastArg);
s<< outdent << "}\n\n";
}
@@ -4433,26 +4574,26 @@ void CppGenerator::writeSequenceMethods(TextStream &s,
static const QHash<QString, QString> &sqFuncs()
{
static const QHash<QString, QString> result = {
- {QLatin1String("__concat__"), QLatin1String("sq_concat")},
- {QLatin1String("__contains__"), QLatin1String("sq_contains")},
- {QLatin1String("__getitem__"), QLatin1String("sq_item")},
- {QLatin1String("__getslice__"), QLatin1String("sq_slice")},
- {QLatin1String("__len__"), QLatin1String("sq_length")},
- {QLatin1String("__setitem__"), QLatin1String("sq_ass_item")},
- {QLatin1String("__setslice__"), QLatin1String("sq_ass_slice")}
+ {u"__concat__"_s, u"Py_sq_concat"_s},
+ {u"__contains__"_s, u"Py_sq_contains"_s},
+ {u"__getitem__"_s, u"Py_sq_item"_s},
+ {u"__getslice__"_s, u"Py_sq_slice"_s},
+ {u"__len__"_s, u"Py_sq_length"_s},
+ {u"__setitem__"_s, u"Py_sq_ass_item"_s},
+ {u"__setslice__"_s, u"Py_sq_ass_slice"_s}
};
return result;
}
void CppGenerator::writeTypeAsSequenceDefinition(TextStream &s,
- const AbstractMetaClass *metaClass)
+ const AbstractMetaClassCPtr &metaClass)
{
bool hasFunctions = false;
QMap<QString, QString> funcs;
for (const auto &seq : sequenceProtocols()) {
const auto func = metaClass->findFunction(seq.name);
- if (!func.isNull()) {
- funcs.insert(seq.name, QLatin1Char('&') + cpythonFunctionName(func));
+ if (func) {
+ funcs.insert(seq.name, u'&' + cpythonFunctionName(func));
hasFunctions = true;
}
}
@@ -4461,46 +4602,42 @@ void CppGenerator::writeTypeAsSequenceDefinition(TextStream &s,
//use default implementation
if (!hasFunctions) {
- funcs[QLatin1String("__len__")] = baseName + QLatin1String("__len__");
- funcs[QLatin1String("__getitem__")] = baseName + QLatin1String("__getitem__");
- funcs[QLatin1String("__setitem__")] = baseName + QLatin1String("__setitem__");
+ funcs[u"__len__"_s] = baseName + u"__len__"_s;
+ funcs[u"__getitem__"_s] = baseName + u"__getitem__"_s;
+ funcs[u"__setitem__"_s] = baseName + u"__setitem__"_s;
}
for (auto it = sqFuncs().cbegin(), end = sqFuncs().cend(); it != end; ++it) {
const QString &sqName = it.key();
auto fit = funcs.constFind(sqName);
- if (fit != funcs.constEnd()) {
- s << "{Py_" << it.value() << ", reinterpret_cast<void *>("
- << fit.value() << ")},\n";
- }
+ if (fit != funcs.constEnd())
+ s << pyTypeSlotEntry(it.value(), fit.value());
}
}
void CppGenerator::writeTypeAsMappingDefinition(TextStream &s,
- const AbstractMetaClass *metaClass)
+ const AbstractMetaClassCPtr &metaClass)
{
// Sequence protocol structure members names
static const QHash<QString, QString> mpFuncs{
- {QLatin1String("__mlen__"), QLatin1String("mp_length")},
- {QLatin1String("__mgetitem__"), QLatin1String("mp_subscript")},
- {QLatin1String("__msetitem__"), QLatin1String("mp_ass_subscript")},
+ {u"__mlen__"_s, u"Py_mp_length"_s},
+ {u"__mgetitem__"_s, u"Py_mp_subscript"_s},
+ {u"__msetitem__"_s, u"Py_mp_ass_subscript"_s},
};
QMap<QString, QString> funcs;
for (const auto &m : mappingProtocols()) {
const auto func = metaClass->findFunction(m.name);
- if (!func.isNull()) {
- const QString entry = QLatin1String("reinterpret_cast<void *>(&")
- + cpythonFunctionName(func) + QLatin1Char(')');
+ if (func) {
+ const QString entry = u"reinterpret_cast<void *>(&"_s
+ + cpythonFunctionName(func) + u')';
funcs.insert(m.name, entry);
- } else {
- funcs.insert(m.name, QLatin1String(NULL_PTR));
}
}
for (auto it = mpFuncs.cbegin(), end = mpFuncs.cend(); it != end; ++it) {
const auto fit = funcs.constFind(it.key());
if (fit != funcs.constEnd())
- s << "{Py_" << it.value() << ", " << fit.value() << "},\n";
+ s << pyTypeSlotEntry(it.value(), fit.value());
}
}
@@ -4508,106 +4645,103 @@ void CppGenerator::writeTypeAsMappingDefinition(TextStream &s,
static const QHash<QString, QString> &nbFuncs()
{
static const QHash<QString, QString> result = {
- {QLatin1String("__add__"), QLatin1String("nb_add")},
- {QLatin1String("__sub__"), QLatin1String("nb_subtract")},
- {QLatin1String("__mul__"), QLatin1String("nb_multiply")},
- {QLatin1String("__div__"), QLatin1String("nb_divide")},
- {QLatin1String("__mod__"), QLatin1String("nb_remainder")},
- {QLatin1String("__neg__"), QLatin1String("nb_negative")},
- {QLatin1String("__pos__"), QLatin1String("nb_positive")},
- {QLatin1String("__invert__"), QLatin1String("nb_invert")},
- {QLatin1String("__lshift__"), QLatin1String("nb_lshift")},
- {QLatin1String("__rshift__"), QLatin1String("nb_rshift")},
- {QLatin1String("__and__"), QLatin1String("nb_and")},
- {QLatin1String("__xor__"), QLatin1String("nb_xor")},
- {QLatin1String("__or__"), QLatin1String("nb_or")},
- {QLatin1String("__iadd__"), QLatin1String("nb_inplace_add")},
- {QLatin1String("__isub__"), QLatin1String("nb_inplace_subtract")},
- {QLatin1String("__imul__"), QLatin1String("nb_inplace_multiply")},
- {QLatin1String("__idiv__"), QLatin1String("nb_inplace_divide")},
- {QLatin1String("__imod__"), QLatin1String("nb_inplace_remainder")},
- {QLatin1String("__ilshift__"), QLatin1String("nb_inplace_lshift")},
- {QLatin1String("__irshift__"), QLatin1String("nb_inplace_rshift")},
- {QLatin1String("__iand__"), QLatin1String("nb_inplace_and")},
- {QLatin1String("__ixor__"), QLatin1String("nb_inplace_xor")},
- {QLatin1String("__ior__"), QLatin1String("nb_inplace_or")},
- {boolT(), QLatin1String("nb_nonzero")}
+ {u"__abs__"_s, u"Py_nb_absolute"_s},
+ {u"__add__"_s, u"Py_nb_add"_s},
+ {u"__sub__"_s, u"Py_nb_subtract"_s},
+ {u"__mul__"_s, u"Py_nb_multiply"_s},
+ {u"__div__"_s, u"Py_nb_true_divide"_s},
+ {u"__mod__"_s, u"Py_nb_remainder"_s},
+ {u"__neg__"_s, u"Py_nb_negative"_s},
+ {u"__pos__"_s, u"Py_nb_positive"_s},
+ {u"__pow__"_s, u"Py_nb_power"_s},
+ {u"__invert__"_s, u"Py_nb_invert"_s},
+ {u"__lshift__"_s, u"Py_nb_lshift"_s},
+ {u"__rshift__"_s, u"Py_nb_rshift"_s},
+ {u"__and__"_s, u"Py_nb_and"_s},
+ {u"__xor__"_s, u"Py_nb_xor"_s},
+ {u"__or__"_s, u"Py_nb_or"_s},
+ {u"__iadd__"_s, u"Py_nb_inplace_add"_s},
+ {u"__isub__"_s, u"Py_nb_inplace_subtract"_s},
+ {u"__imul__"_s, u"Py_nb_inplace_multiply"_s},
+ {u"__imod__"_s, u"Py_nb_inplace_remainder"_s},
+ {u"__ilshift__"_s, u"Py_nb_inplace_lshift"_s},
+ {u"__irshift__"_s, u"Py_nb_inplace_rshift"_s},
+ {u"__iand__"_s, u"Py_nb_inplace_and"_s},
+ {u"__ixor__"_s, u"Py_nb_inplace_xor"_s},
+ {u"__ior__"_s, u"Py_nb_inplace_or"_s},
+ {u"__bool__"_s, u"Py_nb_bool"_s},
+ {u"__int__"_s, u"Py_nb_int"_s},
+ {u"__float__"_s, u"Py_nb_float"_s}
};
return result;
}
-void CppGenerator::writeTypeAsNumberDefinition(TextStream &s, const AbstractMetaClass *metaClass) const
+void CppGenerator::writeTypeAsNumberDefinition(TextStream &s, const AbstractMetaClassCPtr &metaClass) const
{
QMap<QString, QString> nb;
- const QList<AbstractMetaFunctionCList> opOverloads =
- filterGroupedOperatorFunctions(metaClass,
- OperatorQueryOption::ArithmeticOp
- | OperatorQueryOption::IncDecrementOp
- | OperatorQueryOption::LogicalOp
- | OperatorQueryOption::BitwiseOp);
-
- for (const AbstractMetaFunctionCList &opOverload : opOverloads) {
+ const QList<AbstractMetaFunctionCList> opOverloads = numberProtocolOperators(metaClass);
+ for (const auto &opOverload : opOverloads) {
const auto rfunc = opOverload.at(0);
QString opName = ShibokenGenerator::pythonOperatorFunctionName(rfunc);
nb[opName] = cpythonFunctionName(rfunc);
}
+ for (auto it = m_nbFuncs.cbegin(), end = m_nbFuncs.cend(); it != end; ++it) {
+ if (!it.value().isEmpty())
+ nb.insert(it.key(), it.value());
+ }
+
QString baseName = cpythonBaseName(metaClass);
if (hasBoolCast(metaClass))
- nb.insert(boolT(), baseName + QLatin1String("___nb_bool"));
+ nb.insert(u"__bool__"_s, baseName + u"___nb_bool"_s);
for (auto it = nbFuncs().cbegin(), end = nbFuncs().cend(); it != end; ++it) {
const QString &nbName = it.key();
- if (nbName == QLatin1String("__div__") || nbName == QLatin1String("__idiv__"))
- continue; // excludeFromPy3K
const auto nbIt = nb.constFind(nbName);
- if (nbIt != nb.constEnd()) {
- const QString fixednbName = nbName == boolT()
- ? QLatin1String("nb_bool") : it.value();
- s << "{Py_" << fixednbName << ", reinterpret_cast<void *>("
- << nbIt.value() << ")},\n";
- }
- }
-
- auto nbIt = nb.constFind(QLatin1String("__div__"));
- if (nbIt != nb.constEnd())
- s << "{Py_nb_true_divide, reinterpret_cast<void *>(" << nbIt.value() << ")},\n";
-
- nbIt = nb.constFind(QLatin1String("__idiv__"));
- if (nbIt != nb.constEnd()) {
- s << "// This function is unused in Python 3. We reference it here.\n"
- << "{0, reinterpret_cast<void *>(" << nbIt.value() << ")},\n"
- << "// This list is ending at the first 0 entry.\n"
- << "// Therefore, we need to put the unused functions at the very end.\n";
+ if (nbIt != nb.constEnd())
+ s << pyTypeSlotEntry(it.value(), nbIt.value());
}
}
-void CppGenerator::writeTpTraverseFunction(TextStream &s, const AbstractMetaClass *metaClass)
+void CppGenerator::writeTpTraverseFunction(TextStream &s, const AbstractMetaClassCPtr &metaClass)
{
QString baseName = cpythonBaseName(metaClass);
s << "static int " << baseName
<< "_traverse(PyObject *self, visitproc visit, void *arg)\n{\n" << indent
- << "return reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())->tp_traverse(self, visit, arg);\n"
+ << "auto traverseProc = "
+ << pyTypeGetSlot("traverseproc", sbkObjectTypeF, "Py_tp_traverse") << ";\n"
+ << "return traverseProc(self, visit, arg);\n"
<< outdent << "}\n";
}
-void CppGenerator::writeTpClearFunction(TextStream &s, const AbstractMetaClass *metaClass)
+void CppGenerator::writeTpClearFunction(TextStream &s, const AbstractMetaClassCPtr &metaClass)
{
QString baseName = cpythonBaseName(metaClass);
s << "static int " << baseName << "_clear(PyObject *self)\n{\n" << indent
- << "return reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())->tp_clear(self);\n"
+ << "auto clearProc = "
+ << pyTypeGetSlot("inquiry", sbkObjectTypeF, "Py_tp_clear") << ";\n"
+ << "return clearProc(self);\n"
<< outdent << "}\n";
}
-void CppGenerator::writeCopyFunction(TextStream &s, const GeneratorContext &context) const
+QString CppGenerator::writeCopyFunction(TextStream &s,
+ TextStream &definitionStream,
+ TextStream &signatureStream,
+ const GeneratorContext &context)
{
- const AbstractMetaClass *metaClass = context.metaClass();
+ const auto metaClass = context.metaClass();
const QString className = chopType(cpythonTypeName(metaClass));
- s << "static PyObject *" << className << "___copy__(PyObject *self)\n"
- << "{\n" << indent;
- writeCppSelfDefinition(s, context, false, true);
+ const QString funcName = className + u"__copy__"_s;
+
+ signatureStream << fullPythonClassName(metaClass) << ".__copy__()\n";
+ definitionStream << PyMethodDefEntry{u"__copy__"_s, funcName, {"METH_NOARGS"_ba}, {}}
+ << ",\n";
+
+ s << "static PyObject *" << funcName << "(PyObject *self)\n"
+ << "{\n" << indent;
+ writeCppSelfDefinition(s, context, ErrorReturn::Default, CppSelfDefinitionFlag::CppSelfAsReference);
QString conversionCode;
if (!context.forSmartPointer())
conversionCode = cpythonToPythonConversionFunction(metaClass);
@@ -4616,19 +4750,21 @@ void CppGenerator::writeCopyFunction(TextStream &s, const GeneratorContext &cont
s << "PyObject *" << PYTHON_RETURN_VAR << " = " << conversionCode
<< CPP_SELF_VAR << ");\n";
- writeFunctionReturnErrorCheckSection(s);
+ writeFunctionReturnErrorCheckSection(s, ErrorReturn::Default);
s << "return " << PYTHON_RETURN_VAR << ";\n" << outdent
<< "}\n\n";
+
+ return funcName;
}
static inline void writeGetterFunctionStart(TextStream &s, const QString &funcName)
{
- s << "static PyObject *" << funcName << "(PyObject *self, void *)\n"
+ s << "static PyObject *" << funcName << "(PyObject *self, void * /* closure */)\n"
<< "{\n" << indent;
}
QString CppGenerator::cppFieldAccess(const AbstractMetaField &metaField,
- const GeneratorContext &context) const
+ const GeneratorContext &context)
{
QString result;
QTextStream str(&result);
@@ -4642,9 +4778,8 @@ QString CppGenerator::cppFieldAccess(const AbstractMetaField &metaField,
void CppGenerator::writeGetterFunction(TextStream &s,
const AbstractMetaField &metaField,
- const GeneratorContext &context) const
+ const GeneratorContext &context)
{
- ErrorCode errorCode(QString::fromLatin1(NULL_PTR));
writeGetterFunctionStart(s, cpythonGetterFunctionName(metaField));
writeCppSelfDefinition(s, context);
@@ -4655,6 +4790,17 @@ void CppGenerator::writeGetterFunction(TextStream &s,
&& !fieldType.isPointer();
QString cppField = cppFieldAccess(metaField, context);
+
+ if (metaField.generateOpaqueContainer()
+ && fieldType.generateOpaqueContainer()) {
+ const QString creationFunc = opaqueContainerCreationFunc(fieldType);
+ writeOpaqueContainerCreationFuncDecl(s, creationFunc, fieldType);
+ s << "PyObject *pyOut = " << creationFunc
+ << "(&" << cppField << ");\nPy_IncRef(pyOut);\n"
+ << "return pyOut;\n" << outdent << "}\n";
+ return;
+ }
+
if (newWrapperSameObject) {
cppField.prepend(u"&(");
cppField.append(u')');
@@ -4662,44 +4808,41 @@ void CppGenerator::writeGetterFunction(TextStream &s,
if (fieldType.isCppIntegralPrimitive() || fieldType.isEnum()) {
s << getFullTypeNameWithoutModifiers(fieldType) << " cppOut_local = " << cppField << ";\n";
- cppField = QLatin1String("cppOut_local");
+ cppField = u"cppOut_local"_s;
}
s << "PyObject *pyOut = {};\n";
if (newWrapperSameObject) {
// Special case colocated field with same address (first field in a struct)
s << "if (reinterpret_cast<void *>("
- << cppField
- << ") == reinterpret_cast<void *>("
- << CPP_SELF_VAR << ")) {\n";
- {
- Indentation indent(s);
- s << "pyOut = reinterpret_cast<PyObject *>(Shiboken::Object::findColocatedChild("
- << "reinterpret_cast<SbkObject *>(self), reinterpret_cast<SbkObjectType *>("
- << cpythonTypeNameExt(fieldType)
- << ")));\n";
- s << "if (pyOut) {\n";
- {
- Indentation indent(s);
- s << "Py_IncRef(pyOut);\n"
- << "return pyOut;\n";
- }
- s << "}\n";
- }
+ << cppField << ") == reinterpret_cast<void *>("
+ << CPP_SELF_VAR << ")) {\n" << indent
+ << "pyOut = reinterpret_cast<PyObject *>(Shiboken::Object::findColocatedChild("
+ << "reinterpret_cast<SbkObject *>(self), "
+ << cpythonTypeNameExt(fieldType) << "));\n"
+ << "if (pyOut != nullptr) {\n" << indent
+ << "Py_IncRef(pyOut);\n"
+ << "return pyOut;\n"
+ << outdent << "}\n";
// Check if field wrapper has already been created.
- s << "} else if (Shiboken::BindingManager::instance().hasWrapper(" << cppField << ")) {" << "\n";
- {
- Indentation indent(s);
- s << "pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper("
- << cppField << "));" << "\n"
- << "Py_IncRef(pyOut);" << "\n"
- << "return pyOut;" << "\n";
- }
- s << "}\n";
- // Create and register new wrapper
+ s << outdent << "} else if (Shiboken::BindingManager::instance().hasWrapper("
+ << cppField << ")) {" << "\n" << indent
+ << "pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper("
+ << cppField << "));" << "\n"
+ << "Py_IncRef(pyOut);" << "\n"
+ << "return pyOut;" << "\n"
+ << outdent << "}\n";
+ // Create and register new wrapper. We force a pointer conversion also
+ // for wrapped value types so that they refer to the struct member,
+ // avoiding any trouble copying them. Add a parent relationship to
+ // properly notify if the struct is deleted (see protected_test.py,
+ // testProtectedValueTypeProperty()). Note that this has currently
+ // unsolved issues when using temporary Python lists of structs
+ // which can cause elements to be reported deleted in expressions like
+ // "foo.list_of_structs[2].field".
s << "pyOut = "
- << "Shiboken::Object::newObject(reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(fieldType)
- << "), " << cppField << ", false, true);\n"
+ << "Shiboken::Object::newObject(" << cpythonTypeNameExt(fieldType)
+ << ", " << cppField << ", false, true);\n"
<< "Shiboken::Object::setParent(self, pyOut)";
} else {
s << "pyOut = ";
@@ -4709,57 +4852,52 @@ void CppGenerator::writeGetterFunction(TextStream &s,
}
// Write a getter for QPropertySpec
-void CppGenerator::writeGetterFunction(TextStream &s, const QPropertySpec &property,
- const GeneratorContext &context) const
+void CppGenerator::writeGetterFunction(TextStream &s,
+ const QPropertySpec &property,
+ const GeneratorContext &context)
{
- ErrorCode errorCode(0);
writeGetterFunctionStart(s, cpythonGetterFunctionName(property, context.metaClass()));
writeCppSelfDefinition(s, context);
- const QString value = QStringLiteral("value");
+ const QString value = "value"_L1;
s << "auto " << value << " = " << CPP_SELF_VAR << "->" << property.read() << "();\n"
- << "auto pyResult = ";
+ << "auto *pyResult = ";
writeToPythonConversion(s, property.type(), context.metaClass(), value);
- s << ";\nif (PyErr_Occurred() || !pyResult) {\n";
- {
- Indentation indent(s);
- s << "Py_XDECREF(pyResult);\nreturn {};\n";
- }
- s << "}\nreturn pyResult;\n" << outdent << "}\n\n";
+ s << ";\nif (" << shibokenErrorsOccurred << " || pyResult == nullptr) {\n"
+ << indent << "Py_XDECREF(pyResult);\nreturn {};\n" << outdent
+ << "}\nreturn pyResult;\n" << outdent << "}\n\n";
}
// Write setter function preamble (type checks on "pyIn")
-void CppGenerator::writeSetterFunctionPreamble(TextStream &s, const QString &name,
+void CppGenerator::writeSetterFunctionPreamble(TextStream &s,
+ const QString &name,
const QString &funcName,
const AbstractMetaType &type,
- const GeneratorContext &context) const
+ const GeneratorContext &context)
{
- s << "static int " << funcName << "(PyObject *self, PyObject *pyIn, void *)\n"
+ s << "static int " << funcName << "(PyObject *self, PyObject *pyIn, void * /* closure */)\n"
<< "{\n" << indent;
- writeCppSelfDefinition(s, context);
+ writeCppSelfDefinition(s, context, ErrorReturn::Zero);
s << "if (pyIn == " << NULL_PTR << ") {\n" << indent
- << "PyErr_SetString(PyExc_TypeError, \"'"
- << name << "' may not be deleted\");\n"
+ << "Shiboken::Errors::setInvalidTypeDeletion(\"" << name << "\");\n"
<< "return -1;\n"
<< outdent << "}\n";
- s << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << "{nullptr};\n"
+ s << PYTHON_TO_CPPCONVERSION_STRUCT << ' ' << PYTHON_TO_CPP_VAR << ";\n"
<< "if (!";
- writeTypeCheck(s, type, QLatin1String("pyIn"), isNumber(type.typeEntry()));
+ writeTypeCheck(s, type, u"pyIn"_s, isNumber(type.typeEntry()));
s << ") {\n" << indent
- << "PyErr_SetString(PyExc_TypeError, \"wrong type attributed to '"
- << name << "', '" << type.name() << "' or convertible type expected\");\n"
+ << "Shiboken::Errors::setSetterTypeError(\"" << name << "\", \""
+ << type.name() << "\");\n"
<< "return -1;\n"
<< outdent << "}\n\n";
}
void CppGenerator::writeSetterFunction(TextStream &s,
const AbstractMetaField &metaField,
- const GeneratorContext &context) const
+ const GeneratorContext &context)
{
- ErrorCode errorCode(0);
-
const AbstractMetaType &fieldType = metaField.type();
writeSetterFunctionPreamble(s, metaField.name(), cpythonSetterFunctionName(metaField),
fieldType, context);
@@ -4790,218 +4928,193 @@ void CppGenerator::writeSetterFunction(TextStream &s,
}
// Write a setter for QPropertySpec
-void CppGenerator::writeSetterFunction(TextStream &s, const QPropertySpec &property,
- const GeneratorContext &context) const
+void CppGenerator::writeSetterFunction(TextStream &s,
+ const QPropertySpec &property,
+ const GeneratorContext &context)
{
- ErrorCode errorCode(0);
- writeSetterFunctionPreamble(s, property.name(),
+ writeSetterFunctionPreamble(s,
+ property.name(),
cpythonSetterFunctionName(property, context.metaClass()),
property.type(), context);
s << "auto cppOut = " << CPP_SELF_VAR << "->" << property.read() << "();\n"
<< PYTHON_TO_CPP_VAR << "(pyIn, &cppOut);\n"
- << "if (PyErr_Occurred())\n";
- {
- Indentation indent(s);
- s << "return -1;\n";
- }
- s << CPP_SELF_VAR << "->" << property.write() << "(cppOut);\n"
+ << "if (" << shibokenErrorsOccurred << ")\n" << indent
+ << "return -1;\n" << outdent
+ << CPP_SELF_VAR << "->" << property.write() << "(cppOut);\n"
<< "return 0;\n" << outdent << "}\n\n";
}
-void CppGenerator::writeRichCompareFunction(TextStream &s,
- const GeneratorContext &context) const
+void CppGenerator::writeRichCompareFunctionHeader(TextStream &s,
+ const QString &baseName,
+ const 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" << indent;
- writeCppSelfDefinition(s, context, false, true);
- writeUnusedVariableCast(s, QLatin1String(CPP_SELF_VAR));
- s << "PyObject *" << PYTHON_RETURN_VAR << "{};\n"
- << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ";\n";
- writeUnusedVariableCast(s, QLatin1String(PYTHON_TO_CPP_VAR));
- s << '\n';
+ writeCppSelfDefinition(s, context, ErrorReturn::Default, CppSelfDefinitionFlag::CppSelfAsReference);
+ s << sbkUnusedVariableCast(CPP_SELF_VAR)
+ << "PyObject *" << PYTHON_RETURN_VAR << "{};\n"
+ << PYTHON_TO_CPPCONVERSION_STRUCT << ' ' << PYTHON_TO_CPP_VAR << ";\n"
+ << sbkUnusedVariableCast(PYTHON_TO_CPP_VAR) << '\n';
+}
- s << "switch (op) {\n";
- {
- Indentation indent(s);
- const QList<AbstractMetaFunctionCList> &groupedFuncs =
- filterGroupedOperatorFunctions(metaClass, OperatorQueryOption::ComparisonOp);
- for (const AbstractMetaFunctionCList &overloads : groupedFuncs) {
- const auto rfunc = overloads[0];
+void CppGenerator::writeRichCompareFunction(TextStream &s,
+ const GeneratorContext &context) const
+{
+ const auto metaClass = context.metaClass();
+ QString baseName = cpythonBaseName(metaClass);
+ writeRichCompareFunctionHeader(s, baseName, context);
- QString operatorId = ShibokenGenerator::pythonRichCompareOperatorId(rfunc);
- s << "case " << operatorId << ':' << '\n';
+ s << "switch (op) {\n" << indent;
+ const QList<AbstractMetaFunctionCList> &groupedFuncs =
+ filterGroupedOperatorFunctions(metaClass, OperatorQueryOption::ComparisonOp);
+ for (const AbstractMetaFunctionCList &overloads : groupedFuncs) {
+ const auto rfunc = overloads[0];
- Indentation indent(s);
+ const auto op = rfunc->comparisonOperatorType().value();
+ s << "case " << AbstractMetaFunction::pythonRichCompareOpCode(op)
+ << ":\n" << indent;
- QString op = rfunc->originalName();
- op = op.right(op.size() - QLatin1String("operator").size());
+ int alternativeNumericTypes = 0;
+ for (const auto &func : overloads) {
+ if (!func->isStatic() &&
+ ShibokenGenerator::isNumber(func->arguments().at(0).type().typeEntry()))
+ alternativeNumericTypes++;
+ }
- int alternativeNumericTypes = 0;
- for (const auto &func : overloads) {
- if (!func->isStatic() &&
- ShibokenGenerator::isNumber(func->arguments().at(0).type().typeEntry()))
- alternativeNumericTypes++;
+ bool first = true;
+ OverloadData overloadData(overloads, api());
+ const OverloadDataList &nextOverloads = overloadData.children();
+ for (const auto &od : nextOverloads) {
+ const auto func = od->referenceFunction();
+ if (func->isStatic())
+ continue;
+ auto argType = getArgumentType(func, 0);
+ if (!first) {
+ s << " else ";
+ } else {
+ first = false;
}
-
- bool first = true;
- OverloadData overloadData(overloads, api());
- const OverloadDataList &nextOverloads = overloadData.nextOverloadData();
- for (OverloadData *od : nextOverloads) {
- const auto func = od->referenceFunction();
- if (func->isStatic())
- continue;
- auto argTypeO = getArgumentType(func, 1);
- if (!argTypeO.has_value())
- continue;
- auto argType = argTypeO.value();
- if (!first) {
- s << " else ";
- } else {
- first = false;
+ s << "if (";
+ writeTypeCheck(s, argType, PYTHON_ARG,
+ alternativeNumericTypes == 1 || isPyInt(argType));
+ s << ") {\n" << indent
+ << "// " << func->signature() << '\n';
+ writeArgumentConversion(s, argType, CPP_ARG0,
+ PYTHON_ARG, ErrorReturn::Default,
+ metaClass,
+ QString(), func->isUserAdded());
+ // If the function is user added, use the inject code
+ bool generateOperatorCode = true;
+ if (func->isUserAdded()) {
+ CodeSnipList snips = func->injectedCodeSnips();
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny,
+ TypeSystem::TargetLangCode, func,
+ false /* uses PyArgs */, &func->arguments().constLast());
+ generateOperatorCode = false;
}
- s << "if (";
- writeTypeCheck(s, argType, QLatin1String(PYTHON_ARG), alternativeNumericTypes == 1 || isPyInt(argType));
- s << ") {\n";
- {
- Indentation indent(s);
- s << "// " << func->signature() << '\n';
- writeArgumentConversion(s, argType, QLatin1String(CPP_ARG0),
- QLatin1String(PYTHON_ARG), metaClass,
- QString(), func->isUserAdded());
-
- // If the function is user added, use the inject code
- bool generateOperatorCode = true;
- if (func->isUserAdded()) {
- CodeSnipList snips = func->injectedCodeSnips();
- if (!snips.isEmpty()) {
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny,
- TypeSystem::TargetLangCode, func,
- &func->arguments().constLast());
- generateOperatorCode = false;
- }
- }
- if (generateOperatorCode) {
- if (!func->isVoid())
- s << func->type().cppSignature() << " " << CPP_RETURN_VAR << " = ";
- // expression
- if (func->isPointerOperator())
- s << '&';
- s << CPP_SELF_VAR << ' ' << op << '(';
- if (argType.shouldDereferencePointer())
- s << '*';
- s << CPP_ARG0 << ");\n"
- << PYTHON_RETURN_VAR << " = ";
- if (!func->isVoid())
- writeToPythonConversion(s, func->type(), metaClass, QLatin1String(CPP_RETURN_VAR));
- else
- s << "Py_None;\n" << "Py_INCREF(Py_None)";
- s << ";\n";
- }
- }
- s << '}';
}
-
- s << " else {\n";
- if (operatorId == QLatin1String("Py_EQ") || operatorId == QLatin1String("Py_NE")) {
- Indentation indent(s);
- s << PYTHON_RETURN_VAR << " = "
- << (operatorId == QLatin1String("Py_EQ") ? "Py_False" : "Py_True") << ";\n"
- << "Py_INCREF(" << PYTHON_RETURN_VAR << ");\n";
- } else {
- Indentation indent(s);
- s << "goto " << baseName << "_RichComparison_TypeError;\n";
+ if (generateOperatorCode) {
+ if (!func->isVoid())
+ s << func->type().cppSignature() << " " << CPP_RETURN_VAR << " = ";
+ // expression
+ if (func->isPointerOperator())
+ s << '&';
+ s << CPP_SELF_VAR << ' '
+ << AbstractMetaFunction::cppComparisonOperator(op) << " (";
+ auto generatorArg = GeneratorArgument::fromMetaType(argType);
+ if (generatorArg.indirections != 0)
+ s << QByteArray(generatorArg.indirections, '*');
+ s << CPP_ARG0 << ");\n"
+ << PYTHON_RETURN_VAR << " = ";
+ if (!func->isVoid()) {
+ writeToPythonConversion(s, func->type(), metaClass,
+ CPP_RETURN_VAR);
+ } else {
+ s << "Py_None;\n" << "Py_INCREF(Py_None)";
+ }
+ s << ";\n";
}
- s << "}\n\n";
-
- s << "break;\n";
+ s << outdent << '}';
}
- s << "default:\n";
- {
- Indentation indent(s);
- s << "// PYSIDE-74: By default, we redirect to object's tp_richcompare (which is `==`, `!=`).\n"
- << "return FallbackRichCompare(self, " << PYTHON_ARG << ", op);\n"
- << "goto " << baseName << "_RichComparison_TypeError;\n";
+
+ s << " else {\n";
+ if (op == AbstractMetaFunction::OperatorEqual ||
+ op == AbstractMetaFunction::OperatorNotEqual) {
+ s << indent << PYTHON_RETURN_VAR << " = "
+ << (op == AbstractMetaFunction::OperatorEqual ? "Py_False" : "Py_True") << ";\n"
+ << "Py_INCREF(" << PYTHON_RETURN_VAR << ");\n" << outdent;
+ } else {
+ s << indent << "return Shiboken::returnFromRichCompare("
+ << PYTHON_RETURN_VAR << ");\n" << outdent;
}
- }
- s << "}\n\n";
+ s << "}\n\n";
- s << "if (" << PYTHON_RETURN_VAR << " && !PyErr_Occurred())\n";
- {
- Indentation indent(s);
- s << "return " << PYTHON_RETURN_VAR << ";\n";
+ s << "break;\n" << outdent;
}
- s << baseName << "_RichComparison_TypeError:\n"
- << "PyErr_SetString(PyExc_NotImplementedError, \"operator not implemented.\");\n"
- << returnStatement(m_currentErrorCode) << '\n' << '\n'
- << outdent << "}\n\n";
+ s << "default:\n" << indent
+ << richCompareComment
+ << "return FallbackRichCompare(self, " << PYTHON_ARG << ", op);\n"
+ << outdent << outdent << "}\n\n"
+ << "return Shiboken::returnFromRichCompare(" << PYTHON_RETURN_VAR << ");\n" << outdent
+ << "}\n\n";
}
-QString CppGenerator::methodDefinitionParameters(const OverloadData &overloadData) const
+// Return a flag combination for PyMethodDef
+QByteArrayList CppGenerator::methodDefinitionParameters(const OverloadData &overloadData) const
{
- bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(overloadData);
- const auto func = overloadData.referenceFunction();
+ const bool usePyArgs = overloadData.pythonFunctionWrapperUsesListOfArguments();
int min = overloadData.minArgs();
int max = overloadData.maxArgs();
- QString result;
- QTextStream s(&result);
- s << "reinterpret_cast<PyCFunction>("
- << cpythonFunctionName(func) << "), ";
+ QByteArrayList result;
if ((min == max) && (max < 2) && !usePyArgs) {
- if (max == 0)
- s << "METH_NOARGS";
- else
- s << "METH_O";
+ result.append(max == 0 ? QByteArrayLiteral("METH_NOARGS")
+ : QByteArrayLiteral("METH_O"));
} else {
- s << "METH_VARARGS";
+ result.append(QByteArrayLiteral("METH_VARARGS"));
if (overloadData.hasArgumentWithDefaultValue())
- s << "|METH_KEYWORDS";
+ result.append(QByteArrayLiteral("METH_KEYWORDS"));
}
// METH_STATIC causes a crash when used for global functions (also from
// invisible namespaces).
- auto ownerClass = func->ownerClass();
+ const auto ownerClass = overloadData.referenceFunction()->ownerClass();
if (ownerClass
- && !invisibleTopNamespaces().contains(const_cast<AbstractMetaClass *>(ownerClass))
- && overloadData.hasStaticFunction()) {
- s << "|METH_STATIC";
+ && !invisibleTopNamespaces().contains(std::const_pointer_cast<AbstractMetaClass>(ownerClass))) {
+ if (overloadData.hasStaticFunction())
+ result.append(QByteArrayLiteral("METH_STATIC"));
+ if (overloadData.hasClassMethod())
+ result.append(QByteArrayLiteral("METH_CLASS"));
}
return result;
}
-void CppGenerator::writeMethodDefinitionEntries(TextStream &s,
- const AbstractMetaFunctionCList &overloads,
- qsizetype maxEntries) const
+QList<PyMethodDefEntry>
+ CppGenerator::methodDefinitionEntries(const OverloadData &overloadData) const
{
- Q_ASSERT(!overloads.isEmpty());
- OverloadData overloadData(overloads, api());
+
const QStringList names = overloadData.referenceFunction()->definitionNames();
- const QString parameters = methodDefinitionParameters(overloadData);
- const qsizetype count = maxEntries > 0
- ? qMin(names.size(), maxEntries) : names.size();
- for (qsizetype i = 0; i < count; ++i) {
- if (i)
- s << ",\n";
- s << "{\"" << names.at(i) << "\", " << parameters << '}';
- }
+ const QString funcName = cpythonFunctionName(overloadData.referenceFunction());
+ const QByteArrayList parameters = methodDefinitionParameters(overloadData);
+
+ QList<PyMethodDefEntry> result;
+ result.reserve(names.size());
+ for (const auto &name : names)
+ result.append({name, funcName, parameters, {}});
+ return result;
}
-void CppGenerator::writeMethodDefinition(TextStream &s, const AbstractMetaFunctionCList &overloads) const
+QString CppGenerator::pythonSignature(const AbstractMetaType &type) const
{
- Q_ASSERT(!overloads.isEmpty());
- const auto func = overloads.constFirst();
- if (m_tpFuncs.contains(func->name()))
- return;
-
- if (OverloadData::hasStaticAndInstanceFunctions(overloads)) {
- s << cpythonMethodDefinitionName(func);
- } else {
- writeMethodDefinitionEntries(s, overloads);
+ if (type.isSmartPointer() && !type.instantiations().isEmpty()) {
+ const auto ste = std::static_pointer_cast<const SmartPointerTypeEntry>(type.typeEntry());
+ const auto instantiationTe = type.instantiations().constFirst().typeEntry();
+ if (auto opt = api().findSmartPointerInstantiation(ste, instantiationTe))
+ return opt->specialized->typeEntry()->qualifiedTargetLangName();
}
- s << ',' << '\n';
+ return type.pythonSignature();
}
// Format the type signature of a function parameter
@@ -5015,17 +5128,22 @@ QString CppGenerator::signatureParameter(const AbstractMetaArgument &arg) const
metaType = *viewOn;
s << arg.name() << ':';
- QStringList signatures(metaType.pythonSignature());
+ QStringList signatures(pythonSignature(metaType));
// Implicit conversions (C++): Check for converting constructors
// "QColor(Qt::GlobalColor)" or conversion operators
const AbstractMetaFunctionCList conversions =
api().implicitConversions(metaType);
for (const auto &f : conversions) {
- if (f->isConstructor() && !f->arguments().isEmpty())
- signatures << f->arguments().constFirst().type().pythonSignature();
- else if (f->isConversionOperator())
+ if (f->isConstructor() && !f->arguments().isEmpty()) {
+ // PYSIDE-2712: modified types from converting constructors are not always correct
+ // candidates if they are modified by the type system reference
+ if (!f->arguments().constFirst().isTypeModified()) {
+ signatures << pythonSignature(f->arguments().constFirst().type());
+ }
+ } else if (f->isConversionOperator()) {
signatures << f->ownerClass()->fullName();
+ }
}
const qsizetype size = signatures.size();
@@ -5039,204 +5157,229 @@ QString CppGenerator::signatureParameter(const AbstractMetaArgument &arg) const
if (size > 1)
s << ']';
- if (!arg.defaultValueExpression().isEmpty()) {
- s << '=';
- QString e = arg.defaultValueExpression();
- e.replace(QLatin1String("::"), QLatin1String("."));
- s << e;
- }
return result;
}
-void CppGenerator::writeSignatureInfo(TextStream &s, const AbstractMetaFunctionCList &overloads) const
+void CppGenerator::writeSignatureInfo(TextStream &s, const OverloadData &overloadData) const
{
- OverloadData overloadData(overloads, api());
const auto rfunc = overloadData.referenceFunction();
QString funcName = fullPythonFunctionName(rfunc, false);
- int idx = overloads.length() - 1;
+ int idx = overloadData.overloads().length() - 1;
bool multiple = idx > 0;
- for (const auto &f : overloads) {
+ for (const auto &f : overloadData.overloads()) {
QStringList args;
// PYSIDE-1328: `self`-ness cannot be computed in Python because there are mixed cases.
// Toplevel functions like `PySide6.QtCore.QEnum` are always self-less.
if (!(f->isStatic()) && f->ownerClass())
- args << QLatin1String("self");
+ args << PYTHON_SELF_VAR;
const auto &arguments = f->arguments();
for (qsizetype i = 0, size = arguments.size(); i < size; ++i) {
- QString t = f->pyiTypeReplaced(i + 1);
- if (t.isEmpty()) {
- t = signatureParameter(arguments.at(i));
- } else {
- t.prepend(u':');
- t.prepend(arguments.at(i).name());
+ const auto n = i + 1;
+ const auto &arg = arguments.at(i);
+ if (!f->argumentRemoved(n)) {
+ QString t = f->pyiTypeReplaced(n);
+ if (t.isEmpty()) {
+ t = signatureParameter(arg);
+ } else {
+ t.prepend(u':');
+ t.prepend(arg.name());
+ }
+ QString defaultValue = arg.defaultValueExpression();
+ if (!defaultValue.isEmpty())
+ t += u'=' + defaultValue.replace(u"::"_s, u"."_s);
+ args.append(t);
}
- args.append(t);
}
// 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->isVoid()) {
- QString t = f->pyiTypeReplaced(0);
- if (t.isEmpty())
- t = f->type().pythonSignature();
- s << "->" << t;
- }
+ s << funcName << '(' << args.join(u',') << ')';
+
+ QString returnType = f->pyiTypeReplaced(0); // pyi or modified type
+ if (returnType.isEmpty() && !f->isVoid())
+ returnType = pythonSignature(f->type());
+ if (!returnType.isEmpty())
+ s << "->" << returnType;
+
s << '\n';
}
}
-void CppGenerator::writeEnumsInitialization(TextStream &s, AbstractMetaEnumList &enums) const
+void CppGenerator::writeEnumsInitialization(TextStream &s, AbstractMetaEnumList &enums)
{
if (enums.isEmpty())
return;
- s << "// Initialization of enums.\n\n";
- for (const AbstractMetaEnum &cppEnum : qAsConst(enums)) {
+ bool preambleWritten = false;
+ bool etypeUsed = false;
+
+ for (const AbstractMetaEnum &cppEnum : std::as_const(enums)) {
if (cppEnum.isPrivate())
continue;
- writeEnumInitialization(s, cppEnum);
+ if (!preambleWritten) {
+ s << "// Initialization of enums.\n"
+ << "Shiboken::AutoDecRef tpDict{};\n"
+ << "PyTypeObject *EType{};\n\n";
+ preambleWritten = true;
+ }
+ ConfigurableScope configScope(s, cppEnum.typeEntry());
+ etypeUsed |= writeEnumInitialization(s, cppEnum);
}
+ if (preambleWritten && !etypeUsed)
+ s << sbkUnusedVariableCast("EType");
}
-static QString mangleName(QString name)
+static qsizetype maxLineLength(const QStringList &list)
{
- if ( name == QLatin1String("None")
- || name == QLatin1String("False")
- || name == QLatin1String("True"))
- name += QLatin1Char('_');
- return name;
+ qsizetype result = 0;
+ for (const auto &s : list) {
+ if (auto len = s.size(); len > result)
+ result = len;
+ }
+ return result;
}
-void CppGenerator::writeEnumInitialization(TextStream &s, const AbstractMetaEnum &cppEnum) const
+bool CppGenerator::writeEnumInitialization(TextStream &s, const AbstractMetaEnum &cppEnum)
{
- const AbstractMetaClass *enclosingClass = cppEnum.targetLangEnclosingClass();
- bool hasUpperEnclosingClass = enclosingClass && enclosingClass->targetLangEnclosingClass() != nullptr;
- const EnumTypeEntry *enumTypeEntry = cppEnum.typeEntry();
+ const auto enclosingClass = cppEnum.targetLangEnclosingClass();
+ const bool hasUpperEnclosingClass = enclosingClass
+ && enclosingClass->targetLangEnclosingClass();
+ EnumTypeEntryCPtr enumTypeEntry = cppEnum.typeEntry();
QString enclosingObjectVariable;
if (enclosingClass)
enclosingObjectVariable = cpythonTypeName(enclosingClass);
else if (hasUpperEnclosingClass)
- enclosingObjectVariable = QLatin1String("enclosingClass");
+ enclosingObjectVariable = u"enclosingClass"_s;
else
- enclosingObjectVariable = QLatin1String("module");
+ enclosingObjectVariable = u"module"_s;
s << "// Initialization of ";
s << (cppEnum.isAnonymous() ? "anonymous enum identified by enum value" : "enum");
s << " '" << cppEnum.name() << "'.\n";
- QString enumVarTypeObj;
- if (!cppEnum.isAnonymous()) {
- int packageLevel = packageName().count(QLatin1Char('.')) + 1;
- 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 << cpythonTypeNameExt(flags) << " = PySide::QFlags::create(\""
- << packageLevel << ':' << fullPath << flags->flagsName() << "\", "
- << cpythonEnumName(cppEnum) << "_number_slots);\n";
- }
+ const QString userType = cppEnum.typeEntry()->cppType();
+ const bool isSigned = cppEnum.isSigned() && !userType.contains(u"unsigned"_s);
+ const bool isAccessible = !avoidProtectedHack() || !cppEnum.isProtected();
+ const auto enumValues = cppEnum.nonRejectedValues();
- enumVarTypeObj = cpythonTypeNameExt(enumTypeEntry);
-
- s << enumVarTypeObj << " = Shiboken::Enum::"
- << ((enclosingClass || hasUpperEnclosingClass) ? "createScopedEnum" : "createGlobalEnum")
- << '(' << enclosingObjectVariable << ',' << '\n';
- {
- Indentation indent(s);
- s << '"' << cppEnum.name() << "\",\n"
- << '"' << packageLevel << ':' << getClassTargetFullName(cppEnum) << "\",\n"
- << '"' << cppEnum.qualifiedCppName() << '"';
- if (flags)
- s << ",\n" << cpythonTypeNameExt(flags);
- s << ");\n";
- }
- s << "if (!" << cpythonTypeNameExt(cppEnum.typeEntry()) << ")\n";
- {
- Indentation indent(s);
- s << returnStatement(m_currentErrorCode) << "\n\n";
+ const QString prefix = cppEnum.name();
+
+ const QString intType = userType.isEmpty() ? cppEnum.underlyingType() : userType;
+
+ // Create a list of values
+ const QString initializerValues = prefix + u"_InitializerValues"_s;
+ const QString initializerName = prefix + u"_Initializer"_s;
+
+ // Build maybe array of enum names.
+ if (cppEnum.enumKind() != AnonymousEnum) {
+ s << "const char *" << initializerName << "[] = {\n" << indent;
+ for (const auto &enumValue : enumValues) {
+ QString name = mangleName(enumValue.name());
+ s << '\"' << name << "\",\n";
}
+ s << "nullptr};\n" << outdent;
}
- for (const AbstractMetaEnumValue &enumValue : cppEnum.values()) {
- if (enumTypeEntry->isEnumValueRejected(enumValue.name()))
- continue;
+ int targetHexLen = 0;
+ QString usedIntType = userType;
+ if (usedIntType.isEmpty()) {
+ const int usedBits = cppEnum.usedBits();
+ targetHexLen = usedBits / 4;
+ usedIntType = AbstractMetaEnum::intTypeForSize(usedBits, cppEnum.isSigned());
+ }
- 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();
- }
+ if (usedIntType != intType)
+ s << "// \"" << usedIntType << "\" used instead of \"" << intType << "\"\n";
- const QString mangledName = mangleName(enumValue.name());
- switch (cppEnum.enumKind()) {
- case AnonymousEnum:
+ // Calculating formatting columns
+ QString enumValuePrefix;
+ if (isAccessible) {
+ if (cppEnum.enclosingClass())
+ enumValuePrefix += cppEnum.enclosingClass()->qualifiedCppName() + u"::"_s;
+ if (!cppEnum.isAnonymous())
+ enumValuePrefix += cppEnum.name() + u"::"_s;
+ }
+
+ // Build array of enum values
+ if (enumValues.isEmpty()) {
+ s << "const " << usedIntType << " *" << initializerValues << "{};\n";
+ } else {
+ QStringList values;
+ values.reserve(enumValues.size());
+ s << "constexpr " << usedIntType << ' ' << initializerValues << "[] = {\n" << indent;
+ for (qsizetype idx = 0, last = enumValues.size() - 1; idx <= last; ++idx) {
+ const auto &enumValue = enumValues.at(idx);
+ QString line = usedIntType + u'(' + (isAccessible
+ ? enumValuePrefix + enumValue.name()
+ : enumValue.value().toString()) + u')';
+ if (idx != last)
+ line += u',';
+ values.append(line);
+ }
+
+ const auto len = maxLineLength(values) + 1;
+ for (qsizetype idx = 0, size = enumValues.size(); idx < size; ++idx) {
+ const auto &enumValue = enumValues.at(idx).value();
+ const char *numberSpace = enumValue.isNegative() ? " " : " ";
+ s << values.at(idx) << Pad(' ', len - values.at(idx).size())
+ << "//" << numberSpace << enumValue.toHex(targetHexLen)
+ << numberSpace << enumValue.toString() << '\n';
+ }
+ s << "};\n" << outdent;
+ }
+
+ // Build initialization of anonymous enums
+ if (cppEnum.enumKind() == AnonymousEnum) {
+ int idx = 0;
+ for (const auto &enumValue : enumValues) {
+ const QString mangledName = mangleName(enumValue.name());
+ const QString pyValue = initializerValues + u'[' + QString::number(idx++) + u']';
if (enclosingClass || hasUpperEnclosingClass) {
- s << "{\n";
- {
- Indentation indent(s);
- s << "PyObject *anonEnumItem = PyInt_FromLong(" << enumValueText << ");\n"
- << "if (PyDict_SetItemString(reinterpret_cast<PyTypeObject *>(reinterpret_cast<SbkObjectType *>("
- << enclosingObjectVariable
- << "))->tp_dict, \"" << mangledName << "\", anonEnumItem) < 0)\n";
- {
- Indentation indent(s);
- s << returnStatement(m_currentErrorCode) << '\n';
- }
- s << "Py_DECREF(anonEnumItem);\n";
- }
- s << "}\n";
+ s << "tpDict.reset(PepType_GetDict(reinterpret_cast<PyTypeObject *>("
+ << enclosingObjectVariable << ")));\n"
+ << "PyDict_SetItemString(tpDict.object(), \"" << mangledName << "\",\n"
+ << indent << (isSigned ? "PyLong_FromLongLong" : "PyLong_FromUnsignedLongLong")
+ << "(" << pyValue << "));\n" << outdent;
} else {
- s << "if (PyModule_AddIntConstant(module, \"" << mangledName << "\", ";
- s << enumValueText << ") < 0)\n";
- {
- Indentation indent(s);
- s << returnStatement(m_currentErrorCode) << '\n';
- }
+ s << "PyModule_AddObject(module, \"" << mangledName << "\",\n" << indent
+ << (isSigned ? "PyLong_FromLongLong" : "PyLong_FromUnsignedLongLong") << "("
+ << pyValue << "));\n" << outdent;
}
- break;
- case CEnum: {
- s << "if (!Shiboken::Enum::";
- s << ((enclosingClass || hasUpperEnclosingClass) ? "createScopedEnumItem" : "createGlobalEnumItem");
- s << '(' << enumVarTypeObj << ',' << '\n';
- Indentation indent(s);
- s << enclosingObjectVariable << ", \"" << mangledName << "\", "
- << enumValueText << "))\n"
- << returnStatement(m_currentErrorCode) << '\n';
- }
- break;
- case EnumClass: {
- s << "if (!Shiboken::Enum::createScopedEnumItem("
- << enumVarTypeObj << ',' << '\n';
- Indentation indent(s);
- s << enumVarTypeObj<< ", \"" << mangledName << "\", "
- << enumValueText << "))\n"
- << returnStatement(m_currentErrorCode) << '\n';
- }
- break;
}
}
+ bool etypeUsed = false;
+
+ QString enumVarTypeObj = cpythonTypeNameExtSet(enumTypeEntry);
+ if (!cppEnum.isAnonymous()) {
+ int packageLevel = packageName().count(u'.') + 1;
+ s << "EType = Shiboken::Enum::"
+ << "createPythonEnum"
+ << '(' << enclosingObjectVariable << ",\n" << indent
+ << '"' << packageLevel << ':' << getClassTargetFullName(cppEnum) << "\",\n"
+ << initializerName << ", " << initializerValues << ");\n" << outdent
+ << enumVarTypeObj << " = EType;\n";
+ etypeUsed = true;
+ }
+
+ if (cppEnum.typeEntry()->flags()) {
+ s << "// PYSIDE-1735: Mapping the flags class to the same enum class.\n"
+ << cpythonTypeNameExtSet(cppEnum.typeEntry()->flags()) << " =\n"
+ << indent << "EType;\n" << outdent;
+ }
writeEnumConverterInitialization(s, cppEnum);
s << "// End of '" << cppEnum.name() << "' enum";
if (cppEnum.typeEntry()->flags())
s << "/flags";
s << ".\n\n";
+
+ return etypeUsed;
}
-void CppGenerator::writeSignalInitialization(TextStream &s, const AbstractMetaClass *metaClass)
+void CppGenerator::writeSignalInitialization(TextStream &s, const AbstractMetaClassCPtr &metaClass)
{
// Try to check something and print some warnings
const auto &signalFuncs = metaClass->cppSignalFunctions();
@@ -5258,151 +5401,31 @@ void CppGenerator::writeSignalInitialization(TextStream &s, const AbstractMetaCl
}
}
- s << "PySide::Signal::registerSignals(" << cpythonTypeName(metaClass) << ", &::"
+ s << "PySide::Signal::registerSignals(pyType, &" << m_gsp
<< metaClass->qualifiedCppName() << "::staticMetaObject);\n";
}
-void CppGenerator::writeFlagsToLong(TextStream &s, const AbstractMetaEnum &cppEnum)
-{
- FlagsTypeEntry *flagsEntry = cppEnum.typeEntry()->flags();
- if (!flagsEntry)
- return;
- s << "static PyObject *" << cpythonEnumName(cppEnum) << "_long(PyObject *self)\n"
- << "{\n" << indent
- << "int val;\n";
- AbstractMetaType flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
- s << cpythonToCppConversionFunction(flagsType) << "self, &val);\n"
- << "return Shiboken::Conversions::copyToPython(Shiboken::Conversions::PrimitiveTypeConverter<int>(), &val);\n"
- << outdent << "}\n";
-}
-
-void CppGenerator::writeFlagsNonZero(TextStream &s, const AbstractMetaEnum &cppEnum)
-{
- FlagsTypeEntry *flagsEntry = cppEnum.typeEntry()->flags();
- if (!flagsEntry)
- return;
- s << "static int " << cpythonEnumName(cppEnum) << "__nonzero(PyObject *self)\n";
- s << "{\n" << indent << "int val;\n";
- AbstractMetaType flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
- s << cpythonToCppConversionFunction(flagsType) << "self, &val);\n"
- << "return val != 0;\n"
- << outdent << "}\n";
-}
-
-void CppGenerator::writeFlagsMethods(TextStream &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 << '\n';
-}
-
-void CppGenerator::writeFlagsNumberMethodsDefinition(TextStream &s, const AbstractMetaEnum &cppEnum)
-{
- QString cpythonName = cpythonEnumName(cppEnum);
-
- s << "static PyType_Slot " << cpythonName << "_number_slots[] = {\n" << indent
- << "{Py_nb_bool, reinterpret_cast<void *>(" << cpythonName << "__nonzero)},\n"
- << "{Py_nb_invert, reinterpret_cast<void *>(" << cpythonName << "___invert__)},\n"
- << "{Py_nb_and, reinterpret_cast<void *>(" << cpythonName << "___and__)},\n"
- << "{Py_nb_xor, reinterpret_cast<void *>(" << cpythonName << "___xor__)},\n"
- << "{Py_nb_or, reinterpret_cast<void *>(" << cpythonName << "___or__)},\n"
- << "{Py_nb_int, reinterpret_cast<void *>(" << cpythonName << "_long)},\n"
- << "{Py_nb_index, reinterpret_cast<void *>(" << cpythonName << "_long)},\n"
- << "{0, " << NULL_PTR << "} // sentinel\n" << outdent
- << "};\n\n";
-}
-
-void CppGenerator::writeFlagsNumberMethodsDefinitions(TextStream &s,
- const AbstractMetaEnumList &enums)
-{
- for (const AbstractMetaEnum &e : enums) {
- if (!e.isAnonymous() && !e.isPrivate() && e.typeEntry()->flags()) {
- writeFlagsMethods(s, e);
- writeFlagsNumberMethodsDefinition(s, e);
- s << '\n';
- }
- }
-}
-
-void CppGenerator::writeFlagsBinaryOperator(TextStream &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" << indent;
-
- AbstractMetaType flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
- s << "::" << flagsEntry->originalName() << " cppResult, " << CPP_SELF_VAR
- << ", cppArg;\n"
- << CPP_SELF_VAR << " = static_cast<::" << flagsEntry->originalName()
- << ">(int(PyLong_AsLong(self)));\n"
- << "cppArg = static_cast<" << flagsEntry->originalName()
- << ">(int(PyLong_AsLong(" << PYTHON_ARG << ")));\n"
- << "if (PyErr_Occurred())\n" << indent
- << "return nullptr;\n" << outdent
- << "cppResult = " << CPP_SELF_VAR << " " << cppOpName << " cppArg;\n"
- << "return ";
- writeToPythonConversion(s, flagsType, nullptr, QLatin1String("cppResult"));
- s << ";\n" << outdent << "}\n\n";
-}
-
-void CppGenerator::writeFlagsUnaryOperator(TextStream &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" << indent;
-
- AbstractMetaType flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
- s << "::" << flagsEntry->originalName() << " " << CPP_SELF_VAR << ";\n"
- << cpythonToCppConversionFunction(flagsType) << "self, &" << CPP_SELF_VAR
- << ");\n";
- if (boolResult)
- s << "bool";
- else
- s << "::" << flagsEntry->originalName();
- s << " cppResult = " << cppOpName << CPP_SELF_VAR << ";\n"
- << "return ";
- if (boolResult)
- s << "PyBool_FromLong(cppResult)";
- else
- writeToPythonConversion(s, flagsType, nullptr, QLatin1String("cppResult"));
- s << ";\n" << outdent << "}\n\n";
-}
-
-QString CppGenerator::getSimpleClassInitFunctionName(const AbstractMetaClass *metaClass)
+QString CppGenerator::getSimpleClassInitFunctionName(const AbstractMetaClassCPtr &metaClass)
{
QString initFunctionName;
// Disambiguate namespaces per module to allow for extending them.
if (metaClass->isNamespace())
initFunctionName += moduleName();
initFunctionName += metaClass->qualifiedCppName();
- initFunctionName.replace(QLatin1String("::"), QLatin1String("_"));
+ initFunctionName.replace(u"::"_s, u"_"_s);
return initFunctionName;
}
-QString CppGenerator::getSimpleClassStaticFieldsInitFunctionName(const AbstractMetaClass *metaClass)
+QString
+ CppGenerator::getSimpleClassStaticFieldsInitFunctionName(const AbstractMetaClassCPtr &metaClass)
{
- return QLatin1String("init_") + getSimpleClassInitFunctionName(metaClass)
- + QLatin1String("StaticFields");
+ return u"init_"_s + getSimpleClassInitFunctionName(metaClass)
+ + u"StaticFields"_s;
}
QString CppGenerator::getInitFunctionName(const GeneratorContext &context)
{
- return !context.forSmartPointer()
- ? getSimpleClassInitFunctionName(context.metaClass())
- : getFilteredCppSignatureString(context.preciseType().cppSignature());
+ return getSimpleClassInitFunctionName(context.metaClass());
}
void CppGenerator::writeSignatureStrings(TextStream &s,
@@ -5416,7 +5439,7 @@ void CppGenerator::writeSignatureStrings(TextStream &s,
const auto lines = QStringView{signatures}.split(u'\n', Qt::SkipEmptyParts);
for (auto line : lines) {
// must anything be escaped?
- if (line.contains(QLatin1Char('"')) || line.contains(QLatin1Char('\\')))
+ if (line.contains(u'"') || line.contains(u'\\'))
s << "R\"CPP(" << line << ")CPP\",\n";
else
s << '"' << line << "\",\n";
@@ -5425,13 +5448,13 @@ void CppGenerator::writeSignatureStrings(TextStream &s,
}
// Return the class name for which to invoke the destructor
-QString CppGenerator::destructorClassName(const AbstractMetaClass *metaClass,
- const GeneratorContext &classContext) const
+QString CppGenerator::destructorClassName(const AbstractMetaClassCPtr &metaClass,
+ const GeneratorContext &classContext)
{
if (metaClass->isNamespace() || metaClass->hasPrivateDestructor())
return {};
if (classContext.forSmartPointer())
- return classContext.smartPointerWrapperName();
+ return classContext.effectiveClassName();
const bool isValue = metaClass->typeEntry()->isValue();
const bool hasProtectedDestructor = metaClass->hasProtectedDestructor();
if (((avoidProtectedHack() && hasProtectedDestructor) || isValue)
@@ -5443,130 +5466,162 @@ QString CppGenerator::destructorClassName(const AbstractMetaClass *metaClass,
return metaClass->qualifiedCppName();
}
+// Return the base type entries for introduceWrapperType()
+static ComplexTypeEntryCList pyBaseTypeEntries(const AbstractMetaClassCPtr &metaClass)
+{
+ ComplexTypeEntryCList result;
+ if (metaClass->isNamespace()) {
+ if (auto extended = metaClass->extendedNamespace())
+ result.append(extended->typeEntry());
+ return result;
+ }
+
+ const auto &baseClasses = metaClass->typeSystemBaseClasses();
+ for (auto base : baseClasses) {
+ for (; base != nullptr; base = base->baseClass()) { // Find a type that is not disabled.
+ const auto ct = base->typeEntry()->codeGeneration();
+ if (ct == TypeEntry::GenerateCode || ct == TypeEntry::GenerateForSubclass)
+ break;
+ }
+ result.append(base->typeEntry());
+ }
+ return result;
+}
+
+// Return the base type strings for introduceWrapperType()
+QStringList CppGenerator::pyBaseTypes(const AbstractMetaClassCPtr &metaClass)
+{
+ const auto &baseEntries = pyBaseTypeEntries(metaClass);
+ QStringList result;
+ for (const auto &baseEntry : baseEntries)
+ result.append("reinterpret_cast<PyObject *>("_L1 + cpythonTypeNameExt(baseEntry) + u')');
+ if (result.isEmpty()) // no base classes -> SbkObjectType.
+ result.append(sbkObjectTypeF);
+ return result;
+}
+
+void CppGenerator::writeInitInheritance(TextStream &s) const
+{
+ s << "static void " << initInheritanceFunction << "()\n{\n" << indent
+ << "auto &bm = Shiboken::BindingManager::instance();\n"
+ << sbkUnusedVariableCast("bm");
+ for (const auto &cls : api().classes()){
+ auto te = cls->typeEntry();
+ if (shouldGenerate(te)) {
+ const auto &baseEntries = pyBaseTypeEntries(cls);
+ if (!baseEntries.isEmpty()) {
+ const QString childTypeInitStruct = typeInitStruct(cls->typeEntry());
+ for (const auto &baseEntry : baseEntries) {
+ s << "bm.addClassInheritance(&" << typeInitStruct(baseEntry) << ",\n"
+ << Pad(' ', 23) << '&' << childTypeInitStruct << ");\n";
+ }
+ }
+ }
+ }
+ s << outdent << "}\n\n";
+}
+
void CppGenerator::writeClassRegister(TextStream &s,
- const AbstractMetaClass *metaClass,
+ const AbstractMetaClassCPtr &metaClass,
const GeneratorContext &classContext,
const QString &signatures) const
{
- const ComplexTypeEntry *classTypeEntry = metaClass->typeEntry();
+ ComplexTypeEntryCPtr classTypeEntry = metaClass->typeEntry();
- const AbstractMetaClass *enc = metaClass->targetLangEnclosingClass();
- QString enclosingObjectVariable = enc ? QLatin1String("enclosingClass") : QLatin1String("module");
+ AbstractMetaClassCPtr enc = metaClass->targetLangEnclosingClass();
+ QString enclosingObjectVariable = enc ? u"enclosingClass"_s : u"module"_s;
QString pyTypeName = cpythonTypeName(metaClass);
QString initFunctionName = getInitFunctionName(classContext);
// PYSIDE-510: Create a signatures string for the introspection feature.
writeSignatureStrings(s, signatures, initFunctionName, "functions");
- s << "void init_" << initFunctionName;
- s << "(PyObject *" << enclosingObjectVariable << ")\n{\n" << indent;
+ s << "PyTypeObject *init_" << initFunctionName
+ << "(PyObject *" << enclosingObjectVariable << ")\n{\n" << indent;
+
+ const QString globalTypeVarExpr = !classContext.forSmartPointer()
+ ? cpythonTypeNameExtSet(classTypeEntry)
+ : cpythonTypeNameExtSet(classContext.preciseType());
+ s << "if (" << globalTypeVarExpr << " != nullptr)\n" << indent
+ << "return " << globalTypeVarExpr << ";\n\n" << outdent;
// Multiple inheritance
- QString pyTypeBasesVariable = chopType(pyTypeName) + QLatin1String("_Type_bases");
- const AbstractMetaClassList baseClasses = metaClass->typeSystemBaseClasses();
- if (metaClass->baseClassNames().size() > 1) {
- s << "PyObject *" << pyTypeBasesVariable
- << " = PyTuple_Pack(" << baseClasses.size() << ',' << '\n';
- Indentation indent(s);
- for (int i = 0, size = baseClasses.size(); i < size; ++i) {
- if (i)
- s << ",\n";
- s << "reinterpret_cast<PyObject *>("
- << cpythonTypeNameExt(baseClasses.at(i)->typeEntry()) << ')';
- }
- s << ");\n\n";
+ QString pyTypeBasesVariable = chopType(pyTypeName) + u"_Type_bases"_s;
+ const QStringList pyBases = pyBaseTypes(metaClass);
+ s << "Shiboken::AutoDecRef " << pyTypeBasesVariable << "(PyTuple_Pack("
+ << pyBases.size() << ",\n" << indent;
+ for (qsizetype i = 0, size = pyBases.size(); i < size; ++i) {
+ if (i)
+ s << ",\n";
+ s << pyBases.at(i);
}
+ s << "));\n\n" << outdent;
// Create type and insert it in the module or enclosing class.
- const QString typePtr = QLatin1String("_") + chopType(pyTypeName)
- + QLatin1String("_Type");
+ const QString typePtr = u"_"_s + chopType(pyTypeName)
+ + u"_Type"_s;
- s << typePtr << " = Shiboken::ObjectType::introduceWrapperType(\n";
- {
- Indentation indent(s);
- // 1:enclosingObject
- s << enclosingObjectVariable << ",\n";
- QString typeName;
- if (!classContext.forSmartPointer())
- typeName = metaClass->name();
- else
- typeName = classContext.preciseType().cppSignature();
+ s << typePtr << " = Shiboken::ObjectType::introduceWrapperType(\n" << indent;
+ // 1:enclosingObject
+ s << enclosingObjectVariable << ",\n";
- // 2:typeName
- s << "\"" << typeName << "\",\n";
+ // 2:typeName
+ s << "\"" << metaClass->name() << "\",\n";
- // 3:originalName
- s << "\"";
- if (!classContext.forSmartPointer()) {
- s << metaClass->qualifiedCppName();
- if (classTypeEntry->isObject())
- s << '*';
- } else {
- s << classContext.preciseType().cppSignature();
- }
+ // 3:originalName
+ s << "\"";
+ if (!classContext.forSmartPointer()) {
+ s << metaClass->qualifiedCppName();
+ if (classTypeEntry->isObject())
+ s << '*';
+ } else {
+ s << classContext.preciseType().cppSignature();
+ }
- s << "\",\n";
- // 4:typeSpec
- s << '&' << chopType(pyTypeName) << "_spec,\n";
+ s << "\",\n";
+ // 4:typeSpec
+ s << '&' << chopType(pyTypeName) << "_spec,\n";
- // 5:cppObjDtor
- QString dtorClassName = destructorClassName(metaClass, classContext);
- if (dtorClassName.isEmpty())
- s << "nullptr,\n";
- else
- s << "&Shiboken::callCppDestructor< ::" << dtorClassName << " >,\n";
-
- // 6:baseType: Find a type that is not disabled.
- auto base = metaClass->isNamespace()
- ? metaClass->extendedNamespace() : metaClass->baseClass();
- if (!metaClass->isNamespace()) {
- for (; base != nullptr; base = base->baseClass()) {
- const auto ct = base->typeEntry()->codeGeneration();
- if (ct == TypeEntry::GenerateCode || ct == TypeEntry::GenerateForSubclass)
- break;
- }
- }
- if (base) {
- s << "reinterpret_cast<SbkObjectType *>("
- << cpythonTypeNameExt(base->typeEntry()) << "),\n";
- } else {
- s << "0,\n";
- }
+ // 5:cppObjDtor
+ QString dtorClassName = destructorClassName(metaClass, classContext);
+ if (dtorClassName.isEmpty())
+ s << "nullptr,\n";
+ else
+ s << "&Shiboken::callCppDestructor< " << globalScopePrefix(classContext)
+ << dtorClassName << " >,\n";
+
+ // 7:baseTypes
+ s << pyTypeBasesVariable << ".object()," << '\n';
+
+ // 8:wrapperflags
+ QByteArrayList wrapperFlags;
+ if (enc)
+ wrapperFlags.append(QByteArrayLiteral("Shiboken::ObjectType::WrapperFlags::InnerClass"));
+ if (metaClass->deleteInMainThread())
+ wrapperFlags.append(QByteArrayLiteral("Shiboken::ObjectType::WrapperFlags::DeleteInMainThread"));
+ if (classTypeEntry->isValue())
+ wrapperFlags.append("Shiboken::ObjectType::WrapperFlags::Value"_ba);
+ if (wrapperFlags.isEmpty())
+ s << '0';
+ else
+ s << wrapperFlags.join(" | ");
- // 7:baseTypes
- if (metaClass->baseClassNames().size() > 1)
- s << pyTypeBasesVariable << ',' << '\n';
- else
- s << "0,\n";
-
- // 8: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 << '0';
- else
- s << wrapperFlags.join(" | ");
- }
- s << ");\nauto pyType = reinterpret_cast<PyTypeObject *>(" << typePtr << ");\n"
+ s << outdent << ");\nauto *pyType = " << pyTypeName << "; // references "
+ << typePtr << "\n"
<< "InitSignatureStrings(pyType, " << initFunctionName << "_SignatureStrings);\n";
- if (usePySideExtensions())
- s << "SbkObjectType_SetPropertyStrings(reinterpret_cast<PyTypeObject *>(" << typePtr << "), "
+ if (usePySideExtensions() && !classContext.forSmartPointer())
+ s << "SbkObjectType_SetPropertyStrings(pyType, "
<< chopType(pyTypeName) << "_PropertyStrings);\n";
-
- if (!classContext.forSmartPointer())
- s << cpythonTypeNameExt(classTypeEntry) << '\n';
- else
- s << cpythonTypeNameExt(classContext.preciseType()) << '\n';
- s << " = reinterpret_cast<PyTypeObject *>(" << pyTypeName << ");\n\n";
+ s << globalTypeVarExpr << " = pyType;\n\n";
// Register conversions for the type.
writeConverterRegister(s, metaClass, classContext);
s << '\n';
+ if (classContext.forSmartPointer())
+ writeSmartPointerConverterInitialization(s, classContext.preciseType());
+
// class inject-code target/beginning
if (!classTypeEntry->codeSnips().isEmpty()) {
writeClassCodeSnips(s, classTypeEntry->codeSnips(),
@@ -5576,14 +5631,14 @@ void CppGenerator::writeClassRegister(TextStream &s,
}
// Fill multiple inheritance data, if needed.
- const AbstractMetaClass *miClass = getMultipleInheritingClass(metaClass);
+ const auto miClass = getMultipleInheritingClass(metaClass);
if (miClass) {
s << "MultipleInheritanceInitFunction func = ";
if (miClass == metaClass) {
s << multipleInheritanceInitializerFunctionName(miClass) << ";\n";
} else {
- s << "Shiboken::ObjectType::getMultipleInheritanceFunction(reinterpret_cast<SbkObjectType *>("
- << cpythonTypeNameExt(miClass->typeEntry()) << "));\n";
+ s << "Shiboken::ObjectType::getMultipleInheritanceFunction("
+ << cpythonTypeNameExt(miClass->typeEntry()) << ");\n";
}
s << "Shiboken::ObjectType::setMultipleInheritanceFunction("
<< cpythonTypeName(metaClass) << ", func);\n"
@@ -5592,15 +5647,19 @@ void CppGenerator::writeClassRegister(TextStream &s,
}
// Set typediscovery struct or fill the struct of another one
- if (metaClass->isPolymorphic() && metaClass->baseClass()) {
- s << "Shiboken::ObjectType::setTypeDiscoveryFunctionV2(" << cpythonTypeName(metaClass)
- << ", &" << cpythonBaseName(metaClass) << "_typeDiscovery);\n\n";
+ if (needsTypeDiscoveryFunction(metaClass)) {
+ s << "Shiboken::ObjectType::setTypeDiscoveryFunctionV2(\n" << indent
+ << cpythonTypeName(metaClass)
+ << ", &" << cpythonBaseName(metaClass) << "_typeDiscovery);" << outdent << "\n\n";
}
AbstractMetaEnumList classEnums = metaClass->enums();
metaClass->getEnumsFromInvisibleNamespacesToBeGenerated(&classEnums);
- ErrorCode errorCode(QString::fromLatin1(""));
+ if (!classContext.forSmartPointer() && !classEnums.isEmpty())
+ s << "// Pass the ..._EnumFlagInfo to the class.\n"
+ << "SbkObjectType_SetEnumFlagInfo(pyType, " << chopType(pyTypeName)
+ << "_EnumFlagInfo);\n\n";
writeEnumsInitialization(s, classEnums);
if (metaClass->hasSignals())
@@ -5621,26 +5680,40 @@ void CppGenerator::writeClassRegister(TextStream &s,
writeInitQtMetaTypeFunctionBody(s, classContext);
}
- if (usePySideExtensions() && metaClass->isQObject()) {
- s << "Shiboken::ObjectType::setSubTypeInitHook(" << pyTypeName
- << ", &PySide::initQObjectSubType);\n"
- << "PySide::initDynamicMetaObject(" << pyTypeName << ", &::"
- << metaClass->qualifiedCppName() << "::staticMetaObject, sizeof(";
- if (shouldGenerateCppWrapper(metaClass))
- s << wrapperName(metaClass);
- else
- s << "::" << metaClass->qualifiedCppName();
- s << "));\n";
+ if (usePySideExtensions() && isQObject(metaClass)) {
+ s << "Shiboken::ObjectType::setSubTypeInitHook(pyType, &PySide::initQObjectSubType);\n"
+ << "PySide::initDynamicMetaObject(pyType, &" << m_gsp
+ << metaClass->qualifiedCppName() << "::staticMetaObject, sizeof("
+ << (shouldGenerateCppWrapper(metaClass)
+ ? wrapperName(metaClass) : getFullTypeName(metaClass))
+ << "));\n";
}
- s << outdent << "}\n";
+ s << "\nreturn pyType;\n" << outdent << "}\n";
}
-void CppGenerator::writeStaticFieldInitialization(TextStream &s, const AbstractMetaClass *metaClass)
+void CppGenerator::writeStaticFieldInitialization(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass)
{
- s << "\nvoid " << getSimpleClassStaticFieldsInitFunctionName(metaClass)
- << "()\n{\n" << indent << "auto dict = reinterpret_cast<PyTypeObject *>("
- << cpythonTypeName(metaClass) << ")->tp_dict;\n";
+ // cpythonTypeName == "Sbk_QRhiShaderResourceBinding_Data_TypeF"
+ QString name = cpythonTypeName(metaClass);
+ const auto parts = QStringView{name}.split(u'_', Qt::SkipEmptyParts);
+ if (parts.size() < 4) {
+ s << "\nPyTypeObject *" << getSimpleClassStaticFieldsInitFunctionName(metaClass)
+ << "(PyObject *module)\n{\n" << indent
+ << "auto *obType = PyObject_GetAttrString(module, \"" << metaClass->name() << "\");\n"
+ << "auto *type = reinterpret_cast<PyTypeObject *>(obType);\n"
+ << "Shiboken::AutoDecRef dict(PepType_GetDict(type));\n";
+ } else {
+ s << "\nPyTypeObject *" << getSimpleClassStaticFieldsInitFunctionName(metaClass)
+ << "(PyObject *module)\n{\n" << indent
+ << "auto *obContainerType = PyObject_GetAttrString(module, \""
+ << parts.at(1) << "\");\n"
+ << "auto *obType = PyObject_GetAttrString(obContainerType, \""
+ << parts.at(2) << "\");\n"
+ << "auto *type = reinterpret_cast<PyTypeObject *>(obType);\n"
+ << "Shiboken::AutoDecRef dict(PepType_GetDict(type));\n";
+ }
for (const AbstractMetaField &field : metaClass->fields()) {
if (field.isStatic()) {
s << "PyDict_SetItemString(dict, \"" << field.name()
@@ -5649,12 +5722,59 @@ void CppGenerator::writeStaticFieldInitialization(TextStream &s, const AbstractM
s << ");\n";
}
}
- s << '\n' << outdent << "}\n";
+ s << "return type;\n" << outdent << "}\n";
+}
+
+enum class QtRegisterMetaType
+{
+ None, Pointer, Value
+};
+
+static bool hasQtMetaTypeRegistrationSpec(const AbstractMetaClassCPtr &c)
+{
+ return c->typeEntry()->qtMetaTypeRegistration() !=
+ TypeSystem::QtMetaTypeRegistration::Unspecified;
+}
+
+// Returns if and how to register the Qt meta type. By default, "pointer" for
+// non-QObject object types and "value" for non-abstract, default-constructible
+// value types.
+QtRegisterMetaType qtMetaTypeRegistration(const AbstractMetaClassCPtr &c)
+{
+ if (c->isNamespace())
+ return QtRegisterMetaType::None;
+
+ // Specified in type system?
+ const bool isObject = c->isObjectType();
+ switch (c->typeEntry()->qtMetaTypeRegistration()) {
+ case TypeSystem::QtMetaTypeRegistration::Disabled:
+ return QtRegisterMetaType::None;
+ case TypeSystem::QtMetaTypeRegistration::Enabled:
+ case TypeSystem::QtMetaTypeRegistration::BaseEnabled:
+ return isObject ? QtRegisterMetaType::Pointer : QtRegisterMetaType::Value;
+ case TypeSystem::QtMetaTypeRegistration::Unspecified:
+ break;
+ }
+
+ // Is there a "base" specification in some base class, meaning only the
+ // base class is to be registered?
+ if (auto base = recurseClassHierarchy(c, hasQtMetaTypeRegistrationSpec)) {
+ const auto baseSpec = base->typeEntry()->qtMetaTypeRegistration();
+ if (baseSpec == TypeSystem::QtMetaTypeRegistration::BaseEnabled)
+ return QtRegisterMetaType::None;
+ }
+
+ // Default.
+ if (isObject)
+ return isQObject(c) ? QtRegisterMetaType::None : QtRegisterMetaType::Pointer;
+
+ return !c->isAbstract() && c->isDefaultConstructible()
+ ? QtRegisterMetaType::Value : QtRegisterMetaType::None;
}
void CppGenerator::writeInitQtMetaTypeFunctionBody(TextStream &s, const GeneratorContext &context)
{
- const AbstractMetaClass *metaClass = context.metaClass();
+ const auto metaClass = context.metaClass();
// Gets all class name variants used on different possible scopes
QStringList nameVariants;
if (!context.forSmartPointer())
@@ -5662,10 +5782,10 @@ void CppGenerator::writeInitQtMetaTypeFunctionBody(TextStream &s, const Generato
else
nameVariants << context.preciseType().cppSignature();
- const AbstractMetaClass *enclosingClass = metaClass->enclosingClass();
+ AbstractMetaClassCPtr enclosingClass = metaClass->enclosingClass();
while (enclosingClass) {
if (enclosingClass->typeEntry()->generateCode())
- nameVariants << (enclosingClass->name() + QLatin1String("::") + nameVariants.constLast());
+ nameVariants << (enclosingClass->name() + u"::"_s + nameVariants.constLast());
enclosingClass = enclosingClass->enclosingClass();
}
@@ -5675,69 +5795,74 @@ void CppGenerator::writeInitQtMetaTypeFunctionBody(TextStream &s, const Generato
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 (!metaClass->isObjectType()) {
- // check if there's a empty ctor
- for (const auto &func : metaClass->functions()) {
- if (func->isConstructor() && !func->arguments().count()) {
- canBeValue = true;
- break;
- }
- }
- }
-
- if (canBeValue) {
- for (const QString &name : qAsConst(nameVariants)) {
- s << "qRegisterMetaType< ::" << className << " >(\"" << name << "\");\n";
- }
- }
+ // Register meta types for signal/slot connections to work
+ // Qt metatypes are registered only on their first use, so we do this now.
+ switch (qtMetaTypeRegistration(metaClass)) {
+ case QtRegisterMetaType::None:
+ break;
+ case QtRegisterMetaType::Pointer:
+ s << "qRegisterMetaType< " << m_gsp << className << " *>();\n";
+ break;
+ case QtRegisterMetaType::Value:
+ for (const QString &name : std::as_const(nameVariants))
+ s << "qRegisterMetaType< " << m_gsp << className << " >(\"" << name << "\");\n";
+ break;
}
for (const AbstractMetaEnum &metaEnum : metaClass->enums()) {
if (!metaEnum.isPrivate() && !metaEnum.isAnonymous()) {
- for (const QString &name : qAsConst(nameVariants)) {
- s << "qRegisterMetaType< ::"
+ for (const QString &name : std::as_const(nameVariants)) {
+ s << "qRegisterMetaType< " << m_gsp
<< metaEnum.typeEntry()->qualifiedCppName() << " >(\""
<< name << "::" << metaEnum.name() << "\");\n";
}
- if (metaEnum.typeEntry()->flags()) {
- QString n = metaEnum.typeEntry()->flags()->originalName();
- s << "qRegisterMetaType< ::" << n << " >(\"" << n << "\");\n";
- }
}
}
}
-void CppGenerator::writeTypeDiscoveryFunction(TextStream &s, const AbstractMetaClass *metaClass)
+void CppGenerator::replacePolymorphicIdPlaceHolders(const AbstractMetaClassCPtr &metaClass,
+ QString *id)
+{
+ if (id->contains("%1"_L1)) {
+ QString replacement = " reinterpret_cast< "_L1 + m_gsp + metaClass->qualifiedCppName()
+ + " *>(cptr)"_L1;
+ id->replace("%1"_L1, replacement);
+ }
+ if (id->contains("%B"_L1)) {
+ auto baseClass = metaClass;
+ while (!baseClass->typeEntry()->isPolymorphicBase() && baseClass->baseClass())
+ baseClass = baseClass->baseClass();
+ QString replacement = " reinterpret_cast< "_L1 + m_gsp + baseClass->qualifiedCppName()
+ + " *>(cptr)"_L1;
+ id->replace("%B"_L1, replacement);
+ }
+}
+
+void CppGenerator::writeTypeDiscoveryFunction(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass)
{
QString polymorphicExpr = metaClass->typeEntry()->polymorphicIdValue();
s << "static void *" << cpythonBaseName(metaClass)
- << "_typeDiscovery(void *cptr, SbkObjectType *instanceType)\n{\n" << indent;
+ << "_typeDiscovery(void *cptr, PyTypeObject *instanceType)\n{\n" << indent
+ << sbkUnusedVariableCast("cptr")
+ << sbkUnusedVariableCast("instanceType");
if (!polymorphicExpr.isEmpty()) {
- polymorphicExpr = polymorphicExpr.replace(QLatin1String("%1"),
- QLatin1String(" reinterpret_cast< ::")
- + metaClass->qualifiedCppName()
- + QLatin1String(" *>(cptr)"));
- s << " if (" << polymorphicExpr << ")\n";
- {
- Indentation indent(s);
- s << "return cptr;\n";
- }
+ replacePolymorphicIdPlaceHolders(metaClass, &polymorphicExpr);
+ s << "if (" << polymorphicExpr << ")\n" << indent
+ << "return cptr;\n" << outdent;
} else if (metaClass->isPolymorphic()) {
- const AbstractMetaClassList &ancestors = metaClass->allTypeSystemAncestors();
- for (AbstractMetaClass *ancestor : ancestors) {
- if (ancestor->baseClass())
+ const auto &ancestors = metaClass->allTypeSystemAncestors();
+ for (const auto &ancestor : ancestors) {
+ if (ancestor->baseClass() && !ancestor->typeEntry()->isPolymorphicBase())
continue;
if (ancestor->isPolymorphic()) {
- s << "if (instanceType == reinterpret_cast<SbkObjectType *>(Shiboken::SbkType< ::"
- << ancestor->qualifiedCppName() << " >()))\n";
- Indentation indent(s);
- s << "return dynamic_cast< ::" << metaClass->qualifiedCppName()
- << " *>(reinterpret_cast< ::"<< ancestor->qualifiedCppName() << " *>(cptr));\n";
+ s << "if (instanceType == Shiboken::SbkType< " << m_gsp
+ << ancestor->qualifiedCppName() << " >())\n" << indent
+ << "return dynamic_cast< " << getFullTypeName(metaClass)
+ << " *>(reinterpret_cast< "<< getFullTypeName(ancestor)
+ << " *>(cptr));\n" << outdent;
} else {
qCWarning(lcShiboken).noquote().nospace()
<< metaClass->qualifiedCppName() << " inherits from a non polymorphic type ("
@@ -5750,7 +5875,8 @@ void CppGenerator::writeTypeDiscoveryFunction(TextStream &s, const AbstractMetaC
s << "return {};\n" << outdent << "}\n\n";
}
-void CppGenerator::writeSetattroDefinition(TextStream &s, const AbstractMetaClass *metaClass) const
+void CppGenerator::writeSetattroDefinition(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass)
{
s << "static int " << ShibokenGenerator::cpythonSetattroFunctionName(metaClass)
<< "(PyObject *self, PyObject *name, PyObject *value)\n{\n" << indent;
@@ -5760,7 +5886,7 @@ void CppGenerator::writeSetattroDefinition(TextStream &s, const AbstractMetaClas
}
}
-inline void CppGenerator::writeSetattroDefaultReturn(TextStream &s)
+void CppGenerator::writeSetattroDefaultReturn(TextStream &s)
{
s << "return PyObject_GenericSetAttr(self, name, value);\n"
<< outdent << "}\n\n";
@@ -5770,7 +5896,7 @@ void CppGenerator::writeSetattroFunction(TextStream &s, AttroCheck attroCheck,
const GeneratorContext &context) const
{
Q_ASSERT(!context.forSmartPointer());
- const AbstractMetaClass *metaClass = context.metaClass();
+ const auto metaClass = context.metaClass();
writeSetattroDefinition(s, metaClass);
// PYSIDE-1019: Switch tp_dict before doing tp_setattro.
@@ -5780,62 +5906,36 @@ void CppGenerator::writeSetattroFunction(TextStream &s, AttroCheck attroCheck,
// PYSIDE-803: Detect duck-punching; clear cache if a method is set.
if (attroCheck.testFlag(AttroCheckFlag::SetattroMethodOverride)
&& context.useWrapper()) {
- s << "if (value && PyCallable_Check(value)) {\n" << indent
- << "auto plain_inst = " << cpythonWrapperCPtr(metaClass, QLatin1String("self")) << ";\n"
- << "auto inst = dynamic_cast<" << context.wrapperName() << " *>(plain_inst);\n"
- << "if (inst)\n" << indent
+ s << "if (value != nullptr && PyCallable_Check(value) != 0) {\n" << indent
+ << "auto plain_inst = " << cpythonWrapperCPtr(metaClass, PYTHON_SELF_VAR) << ";\n"
+ << "auto *inst = dynamic_cast<" << context.wrapperName() << " *>(plain_inst);\n"
+ << "if (inst != nullptr)\n" << indent
<< "inst->resetPyMethodCache();\n" << outdent << outdent
<< "}\n";
}
if (attroCheck.testFlag(AttroCheckFlag::SetattroQObject)) {
s << "Shiboken::AutoDecRef pp(reinterpret_cast<PyObject *>(PySide::Property::getObject(self, name)));\n"
- << "if (!pp.isNull())\n";
- Indentation indent(s);
- s << "return PySide::Property::setValue(reinterpret_cast<PySideProperty *>(pp.object()), self, value);\n";
+ << "if (!pp.isNull())\n" << indent
+ << "return PySide::Property::setValue(reinterpret_cast<PySideProperty *>(pp.object()), self, value);\n"
+ << outdent;
}
if (attroCheck.testFlag(AttroCheckFlag::SetattroUser)) {
auto func = AbstractMetaClass::queryFirstFunction(metaClass->functions(),
FunctionQueryOption::SetAttroFunction);
Q_ASSERT(func);
- s << "{\n";
- {
- Indentation indent(s);
- s << "auto " << CPP_SELF_VAR << " = "
- << cpythonWrapperCPtr(metaClass, QLatin1String("self")) << ";\n";
- writeClassCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionAny,
- TypeSystem::TargetLangCode, context);
- }
- s << "}\n";
+ s << "{\n" << indent
+ << "auto " << CPP_SELF_VAR << " = "
+ << cpythonWrapperCPtr(metaClass, PYTHON_SELF_VAR) << ";\n";
+ writeClassCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionAny,
+ TypeSystem::TargetLangCode, context);
+ s << outdent << "}\n";
}
writeSetattroDefaultReturn(s);
}
-void CppGenerator::writeSmartPointerSetattroFunction(TextStream &s,
- const GeneratorContext &context) const
-{
- Q_ASSERT(context.forSmartPointer());
- writeSetattroDefinition(s, context.metaClass());
- s << "// Try to find the 'name' attribute, by retrieving the PyObject for the corresponding C++ object held by the smart pointer.\n"
- << "PyObject *rawObj = PyObject_CallMethod(self, "
- << SMART_POINTER_GETTER << ", 0);\n";
- s << "if (rawObj) {\n";
- {
- Indentation indent(s);
- s << "int hasAttribute = PyObject_HasAttr(rawObj, name);\n"
- << "if (hasAttribute) {\n";
- {
- Indentation indent(s);
- s << "return PyObject_GenericSetAttr(rawObj, name, value);\n";
- }
- s << "}\nPy_DECREF(rawObj);\n";
- }
- s << "}\n";
- writeSetattroDefaultReturn(s);
-}
-
-void CppGenerator::writeGetattroDefinition(TextStream &s, const AbstractMetaClass *metaClass)
+void CppGenerator::writeGetattroDefinition(TextStream &s, const AbstractMetaClassCPtr &metaClass)
{
s << "static PyObject *" << cpythonGetattroFunctionName(metaClass)
<< "(PyObject *self, PyObject *name)\n{\n" << indent;
@@ -5845,11 +5945,11 @@ QString CppGenerator::qObjectGetAttroFunction() const
{
static QString result;
if (result.isEmpty()) {
- auto qobjectClass = AbstractMetaClass::findClass(api().classes(), qObjectT());
+ auto qobjectClass = AbstractMetaClass::findClass(api().classes(), qObjectT);
Q_ASSERT(qobjectClass);
- result = QLatin1String("PySide::getMetaDataFromQObject(")
- + cpythonWrapperCPtr(qobjectClass, QLatin1String("self"))
- + QLatin1String(", self, name)");
+ result = u"PySide::getHiddenDataFromQObject("_s
+ + cpythonWrapperCPtr(qobjectClass, PYTHON_SELF_VAR)
+ + u", self, name)"_s;
}
return result;
}
@@ -5858,68 +5958,49 @@ void CppGenerator::writeGetattroFunction(TextStream &s, AttroCheck attroCheck,
const GeneratorContext &context) const
{
Q_ASSERT(!context.forSmartPointer());
- const AbstractMetaClass *metaClass = context.metaClass();
+ const auto metaClass = context.metaClass();
writeGetattroDefinition(s, metaClass);
// PYSIDE-1019: Switch tp_dict before doing tp_getattro.
if (usePySideExtensions())
s << "PySide::Feature::Select(self);\n";
- const QString getattrFunc = usePySideExtensions() && metaClass->isQObject()
- ? qObjectGetAttroFunction() : QLatin1String("PyObject_GenericGetAttr(self, name)");
+ const QString getattrFunc = usePySideExtensions() && isQObject(metaClass)
+ ? qObjectGetAttroFunction() : u"PyObject_GenericGetAttr(self, name)"_s;
if (attroCheck.testFlag(AttroCheckFlag::GetattroOverloads)) {
s << "// Search the method in the instance dict\n"
- << "if (auto ob_dict = reinterpret_cast<SbkObject *>(self)->ob_dict) {\n";
- {
- Indentation indent(s);
- s << "if (auto meth = PyDict_GetItem(ob_dict, name)) {\n";
- {
- Indentation indent(s);
- s << "Py_INCREF(meth);\n"
- << "return meth;\n";
- }
- s << "}\n";
- }
- s << "}\n"
+ << "auto *ob_dict = SbkObject_GetDict_NoRef(self);\n";
+ s << "if (auto *meth = PyDict_GetItem(ob_dict, name)) {\n" << indent
+ << "Py_INCREF(meth);\nreturn meth;\n" << outdent << "}\n"
<< "// Search the method in the type dict\n"
- << "if (Shiboken::Object::isUserType(self)) {\n";
- {
- Indentation indent(s);
- // PYSIDE-772: Perform optimized name mangling.
- s << "Shiboken::AutoDecRef tmp(_Pep_PrivateMangle(self, name));\n"
- << "if (auto meth = PyDict_GetItem(Py_TYPE(self)->tp_dict, tmp)) {\n";
- {
- Indentation indent(s);
- // PYSIDE-1523: PyFunction_Check is not accepting compiled functions.
- s << "if (strcmp(Py_TYPE(meth)->tp_name, \"compiled_function\") == 0)\n";
- {
- Indentation indent(s);
- s << "return Py_TYPE(meth)->tp_descr_get(meth, self, nullptr);\n";
- }
- s << "return PyFunction_Check(meth) ? SBK_PyMethod_New(meth, self)\n"
- << " : " << getattrFunc << ";\n";
- }
- s << "}\n";
- }
- s << "}\n";
+ << "if (Shiboken::Object::isUserType(self)) {\n" << indent;
+ // PYSIDE-772: Perform optimized name mangling.
+ s << "Shiboken::AutoDecRef tmp(_Pep_PrivateMangle(self, name));\n"
+ << "Shiboken::AutoDecRef tpDict(PepType_GetDict(Py_TYPE(self)));\n"
+ << "if (auto *meth = PyDict_GetItem(tpDict.object(), tmp)) {\n" << indent;
+ // PYSIDE-1523: PyFunction_Check is not accepting compiled functions.
+ s << "if (std::strcmp(Py_TYPE(meth)->tp_name, \"compiled_function\") == 0) {\n" << indent
+ << "auto descrGetFunc = "
+ << pyTypeGetSlot("descrgetfunc", "Py_TYPE(meth)", "Py_tp_descr_get") << ";\n"
+ << "return descrGetFunc(meth, self, nullptr);\n" << outdent
+ << "}\nreturn PyFunction_Check(meth) ? PyMethod_New(meth, self)\n"
+ << " : " << getattrFunc << ";\n" << outdent
+ << "}\n" << outdent << "}\n";
const auto &funcs = getMethodsWithBothStaticAndNonStaticMethods(metaClass);
for (const auto &func : funcs) {
QString defName = cpythonMethodDefinitionName(func);
- s << "static PyMethodDef non_static_" << defName << " = {\n";
- {
- Indentation indent(s);
- s << defName << ".ml_name,\n"
- << defName << ".ml_meth,\n"
- << defName << ".ml_flags & (~METH_STATIC),\n"
- << defName << ".ml_doc,\n";
- }
- s << "};\n"
+ s << "static PyMethodDef non_static_" << defName << " = {\n" << indent
+ << defName << ".ml_name,\n"
+ << defName << ".ml_meth,\n"
+ << defName << ".ml_flags & (~METH_STATIC),\n"
+ << defName << ".ml_doc,\n" << outdent
+ << "};\n"
<< "if (Shiboken::String::compare(name, \""
- << func->definitionNames().constFirst() << "\") == 0)\n";
- Indentation indent(s);
- s << "return PyCFunction_NewEx(&non_static_" << defName << ", self, 0);\n";
+ << func->definitionNames().constFirst() << "\") == 0)\n" << indent
+ << "return PyCFunction_NewEx(&non_static_" << defName << ", self, 0);\n"
+ << outdent;
}
}
@@ -5927,106 +6008,118 @@ void CppGenerator::writeGetattroFunction(TextStream &s, AttroCheck attroCheck,
auto func = AbstractMetaClass::queryFirstFunction(metaClass->functions(),
FunctionQueryOption::GetAttroFunction);
Q_ASSERT(func);
- s << "{\n";
- {
- Indentation indent(s);
- s << "auto " << CPP_SELF_VAR << " = "
- << cpythonWrapperCPtr(metaClass, QLatin1String("self")) << ";\n";
- writeClassCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionAny,
- TypeSystem::TargetLangCode, context);
- }
- s << "}\n";
+ s << "{\n" << indent
+ << "auto " << CPP_SELF_VAR << " = "
+ << cpythonWrapperCPtr(metaClass, PYTHON_SELF_VAR) << ";\n";
+ writeClassCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionAny,
+ TypeSystem::TargetLangCode, context);
+ s << outdent << "}\n";
}
s << "return " << getattrFunc << ";\n" << outdent << "}\n\n";
}
-void CppGenerator::writeSmartPointerGetattroFunction(TextStream &s, const GeneratorContext &context)
+void CppGenerator::writeNbBoolExpression(TextStream &s, const BoolCastFunction &f,
+ bool invert)
{
- Q_ASSERT(context.forSmartPointer());
- const AbstractMetaClass *metaClass = context.metaClass();
- writeGetattroDefinition(s, metaClass);
- s << "PyObject *tmp = PyObject_GenericGetAttr(self, name);\n"
- << "if (tmp)\n";
- {
- Indentation indent(s);
- s << "return tmp;\n";
- }
- s << "if (!PyErr_ExceptionMatches(PyExc_AttributeError))\n";
- {
- Indentation indent(s);
- s << "return nullptr;\n";
+ if (f.function->isOperatorBool()) {
+ if (invert)
+ s << '!';
+ s << '*' << CPP_SELF_VAR;
+ return;
}
- s << "PyErr_Clear();\n";
+ if (invert != f.invert)
+ s << '!';
+ s << CPP_SELF_VAR << "->" << f.function->name() << "()";
+}
- // This generates the code which dispatches access to member functions
- // and fields from the smart pointer to its pointee.
- s << "// Try to find the 'name' attribute, by retrieving the PyObject for "
- "the corresponding C++ object held by the smart pointer.\n"
- << "if (auto rawObj = PyObject_CallMethod(self, "
- << SMART_POINTER_GETTER << ", 0)) {\n";
- {
- Indentation indent(s);
- s << "if (auto attribute = PyObject_GetAttr(rawObj, name))\n";
- {
- Indentation indent(s);
- s << "tmp = attribute;\n";
- }
- s << "Py_DECREF(rawObj);\n";
- }
- s << "}\n"
- << "if (!tmp) {\n";
- {
- Indentation indent(s);
- s << R"(PyTypeObject *tp = Py_TYPE(self);
-PyErr_Format(PyExc_AttributeError,
- "'%.50s' object has no attribute '%.400s'",
- tp->tp_name, Shiboken::String::toCString(name));
-)";
- }
- s << "}\n"
- << "return tmp;\n" << outdent << "}\n\n";
+void CppGenerator::writeNbBoolFunction(const GeneratorContext &context,
+ const BoolCastFunction &f,
+ TextStream &s)
+{
+ s << "static int " << cpythonBaseName(context.metaClass()) << "___nb_bool(PyObject *self)\n"
+ << "{\n" << indent;
+ writeCppSelfDefinition(s, context, ErrorReturn::MinusOne);
+
+ const bool allowThread = f.function->allowThread();
+ if (allowThread)
+ s << "int result;\n" << BEGIN_ALLOW_THREADS << "\nresult = ";
+ else
+ s << "return ";
+
+ writeNbBoolExpression(s, f);
+ s << " ? 1 : 0;\n";
+
+ if (allowThread)
+ s << END_ALLOW_THREADS << "\nreturn result;\n";
+ s << outdent << "}\n\n";
}
// Write declaration and invocation of the init function for the module init
// function.
-void CppGenerator::writeInitFunc(TextStream &declStr, TextStream &callStr,
- const QString &initFunctionName,
- const TypeEntry *enclosingEntry)
-{
- const bool hasParent =
- enclosingEntry && enclosingEntry->type() != TypeEntry::TypeSystemType;
- declStr << "void init_" << initFunctionName << "(PyObject *"
- << (hasParent ? "enclosingClass" : "module") << ");\n";
- callStr << "init_" << initFunctionName;
- if (hasParent) {
- callStr << "(reinterpret_cast<PyTypeObject *>("
- << cpythonTypeNameExt(enclosingEntry) << ")->tp_dict);\n";
+static void writeInitFuncDecl(TextStream &declStr,
+ const QString &functionName)
+{
+ declStr << "PyTypeObject *" << functionName << "(PyObject *enclosing);\n";
+}
+
+// Write declaration and invocation of the init function for the module init
+// function.
+void CppGenerator::writeInitFuncCall(TextStream &callStr,
+ const QString &functionName,
+ const TypeEntryCPtr &enclosingEntry,
+ const QString &pythonName, bool lazy)
+{
+ const bool hasParent = enclosingEntry && enclosingEntry->type() != TypeEntry::TypeSystemType;
+ if (!lazy) {
+ const QString enclosing = hasParent
+ ? "reinterpret_cast<PyObject *>("_L1 + cpythonTypeNameExt(enclosingEntry) + u')'
+ : "module"_L1;
+ callStr << functionName << '(' << enclosing << ");\n";
+ } else if (hasParent) {
+ const QString &enclosingName = enclosingEntry->name();
+ const auto parts = QStringView{enclosingName}.split(u"::", Qt::SkipEmptyParts);
+ const QString namePathPrefix = enclosingEntry->name().replace("::"_L1, "."_L1);
+ callStr << "Shiboken::Module::AddTypeCreationFunction("
+ << "module, \"" << parts[0] << "\", "
+ << functionName << ", \"" << namePathPrefix << '.' << pythonName << "\");\n";
} else {
- callStr << "(module);\n";
+ callStr << "Shiboken::Module::AddTypeCreationFunction("
+ << "module, \"" << pythonName << "\", "
+ << functionName << ");\n";
}
}
+static void writeSubModuleHandling(TextStream &s, const QString &moduleName,
+ const QString &subModuleOf)
+{
+ s << "{\n" << indent
+ << "Shiboken::AutoDecRef parentModule(Shiboken::Module::import(\""
+ << subModuleOf << "\"));\n"
+ << "if (parentModule.isNull())\n" << indent
+ << "return nullptr;\n" << outdent
+ << "if (PyModule_AddObject(parentModule.object(), \"" << moduleName
+ << "\", module) < 0)\n"
+ << indent << "return nullptr;\n" << outdent << outdent << "}\n";
+}
+
bool CppGenerator::finishGeneration()
{
//Generate CPython wrapper file
StringStream s_classInitDecl(TextStream::Language::Cpp);
StringStream s_classPythonDefines(TextStream::Language::Cpp);
- QSet<Include> includes;
+ std::set<Include> includes;
StringStream s_globalFunctionImpl(TextStream::Language::Cpp);
StringStream s_globalFunctionDef(TextStream::Language::Cpp);
StringStream signatureStream(TextStream::Language::Cpp);
const auto functionGroups = getGlobalFunctionGroups();
for (auto it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
- AbstractMetaFunctionCList overloads;
- for (const auto &func : it.value()) {
- if (!func->isModifiedRemoved()) {
- overloads.append(func);
- if (func->typeEntry())
- includes << func->typeEntry()->include();
- }
+ const AbstractMetaFunctionCList &overloads = it.value();
+ for (const auto &func : overloads) {
+ if (auto te = func->typeEntry())
+ includes.insert(te->include());
}
if (overloads.isEmpty())
@@ -6034,39 +6127,74 @@ bool CppGenerator::finishGeneration()
// Dummy context to satisfy the API.
GeneratorContext classContext;
- writeMethodWrapper(s_globalFunctionImpl, overloads, classContext);
- writeSignatureInfo(signatureStream, overloads);
- writeMethodDefinition(s_globalFunctionDef, overloads);
+ OverloadData overloadData(overloads, api());
+
+ writeMethodWrapper(s_globalFunctionImpl, overloadData, classContext);
+ writeSignatureInfo(signatureStream, overloadData);
+ s_globalFunctionDef << methodDefinitionEntries(overloadData);
}
AbstractMetaClassCList classesWithStaticFields;
- for (auto cls : api().classes()){
- if (shouldGenerate(cls)) {
- writeInitFunc(s_classInitDecl, s_classPythonDefines,
- getSimpleClassInitFunctionName(cls),
- cls->typeEntry()->targetLangEnclosingEntry());
+ for (const auto &cls : api().classes()){
+ auto te = cls->typeEntry();
+ if (shouldGenerate(te)) {
+ const bool hasConfigCondition = te->hasConfigCondition();
+ if (hasConfigCondition) {
+ s_classInitDecl << te->configCondition() << '\n';
+ s_classPythonDefines << te->configCondition() << '\n';
+ }
+ const QString initFunc = initFuncPrefix + getSimpleClassInitFunctionName(cls);
+ writeInitFuncDecl(s_classInitDecl, initFunc);
+ writeInitFuncCall(s_classPythonDefines, initFunc,
+ targetLangEnclosingEntry(te), cls->name());
if (cls->hasStaticFields()) {
- s_classInitDecl << "void "
- << getSimpleClassStaticFieldsInitFunctionName(cls) << "();\n";
+ s_classInitDecl << "PyTypeObject *"
+ << getSimpleClassStaticFieldsInitFunctionName(cls) << "(PyObject *module);\n";
classesWithStaticFields.append(cls);
}
+ if (hasConfigCondition) {
+ s_classInitDecl << "#endif\n";
+ s_classPythonDefines << "#endif\n";
+ }
}
}
// Initialize smart pointer types.
- const auto &smartPtrs = instantiatedSmartPointers();
- for (const AbstractMetaType &metaType : smartPtrs) {
- GeneratorContext context = contextForSmartPointer(nullptr, metaType);
- writeInitFunc(s_classInitDecl, s_classPythonDefines,
- getInitFunctionName(context),
- metaType.typeEntry()->targetLangEnclosingEntry());
+ for (const auto &smp : api().instantiatedSmartPointers()) {
+ GeneratorContext context = contextForSmartPointer(smp.specialized, smp.type);
+ const auto enclosingClass = context.metaClass()->enclosingClass();
+ auto enclosingTypeEntry = targetLangEnclosingEntry(smp.specialized->typeEntry());
+
+ const QString initFunc = initFuncPrefix + getInitFunctionName(context);
+ writeInitFuncDecl(s_classInitDecl, initFunc);
+ writeInitFuncCall(s_classPythonDefines,
+ initFunc, enclosingTypeEntry, smp.specialized->name());
+ includes.insert(smp.type.instantiations().constFirst().typeEntry()->include());
+ }
+
+ for (auto &instantiatedContainer : api().instantiatedContainers()) {
+ includes.insert(instantiatedContainer.typeEntry()->include());
+ for (const auto &inst : instantiatedContainer.instantiations())
+ includes.insert(inst.typeEntry()->include());
}
- QString moduleFileName(outputDirectory() + QLatin1Char('/') + subDirectoryForPackage(packageName()));
- moduleFileName += QLatin1Char('/') + moduleName().toLower() + QLatin1String("_module_wrapper.cpp");
+ const ExtendedConverterData extendedConverters = getExtendedConverters();
+ for (auto it = extendedConverters.cbegin(), end = extendedConverters.cend(); it != end; ++it) {
+ TypeEntryCPtr te = it.key();
+ includes.insert(te->include());
+ for (const auto &metaClass : it.value())
+ includes.insert(metaClass->typeEntry()->include());
+ }
+ const QList<CustomConversionPtr> &typeConversions = getPrimitiveCustomConversions();
+ for (const auto &c : typeConversions) {
+ if (auto te = c->ownerType())
+ includes.insert(te->include());
+ }
+
+ QString moduleFileName(outputDirectory() + u'/' + subDirectoryForPackage(packageName()));
+ moduleFileName += u'/' + moduleName().toLower() + u"_module_wrapper.cpp"_s;
- verifyDirectoryFor(moduleFileName);
FileOut file(moduleFileName);
TextStream &s = file.stream;
@@ -6079,60 +6207,78 @@ bool CppGenerator::finishGeneration()
#include <algorithm>
#include <signature.h>
)";
+
+ if (!api().instantiatedContainers().isEmpty())
+ s << "#include <sbkcontainer.h>\n#include <sbkstaticstrings.h>\n";
+
if (usePySideExtensions()) {
s << includeQDebug;
- s << R"(#include <pyside.h>
+ s << R"(#include <pysidecleanup.h>
#include <pysideqenum.h>
#include <feature_select.h>
+#include <pysidestaticstrings.h>
)";
}
s << "#include \"" << getModuleHeaderFileName() << '"' << "\n\n";
- for (const Include &include : qAsConst(includes))
+ for (const Include &include : includes)
s << include;
s << '\n';
// Global enums
AbstractMetaEnumList globalEnums = api().globalEnums();
- for (const AbstractMetaClass *nsp : invisibleTopNamespaces())
+ for (const auto &nsp : invisibleTopNamespaces()) {
+ const auto oldSize = globalEnums.size();
nsp->getEnumsToBeGenerated(&globalEnums);
+ if (globalEnums.size() > oldSize)
+ s << nsp->typeEntry()->include();
+ }
TypeDatabase *typeDb = TypeDatabase::instance();
- const TypeSystemTypeEntry *moduleEntry = typeDb->defaultTypeSystemType();
+ TypeSystemTypeEntryCPtr moduleEntry = typeDb->defaultTypeSystemType();
Q_ASSERT(moduleEntry);
- //Extra includes
- s << '\n' << "// Extra includes\n";
+ s << '\n';
+ // Extra includes
QList<Include> extraIncludes = moduleEntry->extraIncludes();
- for (const AbstractMetaEnum &cppEnum : qAsConst(globalEnums))
+ for (const AbstractMetaEnum &cppEnum : std::as_const(globalEnums))
extraIncludes.append(cppEnum.typeEntry()->extraIncludes());
- std::sort(extraIncludes.begin(), extraIncludes.end());
- for (const Include &inc : qAsConst(extraIncludes))
- s << inc;
- s << '\n'
- << "// Current module's type array.\n"
- << "PyTypeObject **" << cppApiVariableName() << " = nullptr;\n"
+ if (!extraIncludes.isEmpty()) {
+ s << "// Extra includes\n";
+ std::sort(extraIncludes.begin(), extraIncludes.end());
+ for (const Include &inc : std::as_const(extraIncludes))
+ s << inc;
+ s << '\n';
+ }
+
+ // FIXME PYSIDE-7: Remove backwards compatible structure
+ s << "// Current module's type array.\n"
+ << "Shiboken::Module::TypeInitStruct *" << cppApiVariableName() << " = nullptr;\n"
+ << "// Backwards compatible structure with identical indexing.\n"
+ << "PyTypeObject **" << cppApiVariableNameOld() << " = nullptr;\n"
<< "// Current module's PyObject pointer.\n"
<< "PyObject *" << pythonModuleObjectName() << " = nullptr;\n"
<< "// Current module's converter array.\n"
- << "SbkConverter **" << convertersVariableName() << " = nullptr;\n";
+ << "SbkConverter **" << convertersVariableName() << " = nullptr;\n\n";
const CodeSnipList snips = moduleEntry->codeSnips();
// module inject-code native/beginning
- if (!snips.isEmpty())
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode);
+ writeModuleCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode);
// cleanup staticMetaObject attribute
if (usePySideExtensions()) {
+ QString iType = cppApiVariableName() + "[i].type"_L1;
+ QString iName = cppApiVariableName() + "[i].fullName"_L1;
+
s << "void cleanTypesAttributes() {\n" << indent
- << "for (int i = 0, imax = SBK_" << moduleName()
- << "_IDX_COUNT; i < imax; i++) {\n" << indent
- << "PyObject *pyType = reinterpret_cast<PyObject *>(" << cppApiVariableName() << "[i]);\n"
- << "Shiboken::AutoDecRef attrName(Py_BuildValue(\"s\", \"staticMetaObject\"));\n"
- << "if (pyType && PyObject_HasAttr(pyType, attrName))\n" << indent
+ << "static PyObject *attrName = Shiboken::PyName::qtStaticMetaObject();\n"
+ << "const int imax = SBK_" << moduleName() << "_IDX_COUNT;\n"
+ << "for (int i = 0; i < imax && " << iName << " != nullptr; ++i) {\n" << indent
+ << "auto *pyType = reinterpret_cast<PyObject *>(" << iType << ");\n"
+ << "if (pyType != nullptr && PyObject_HasAttr(pyType, attrName))\n" << indent
<< "PyObject_SetAttr(pyType, attrName, Py_None);\n" << outdent
- << outdent << "}\n" << outdent << "}\n";
+ << outdent << "}\n" << outdent << "}\n\n";
}
s << "// Global functions "
@@ -6140,7 +6286,7 @@ bool CppGenerator::finishGeneration()
<< s_globalFunctionImpl.toString() << '\n'
<< "static PyMethodDef " << moduleName() << "_methods[] = {\n" << indent
<< s_globalFunctionDef.toString()
- << "{0} // Sentinel\n" << outdent << "};\n\n"
+ << METHOD_DEF_SENTINEL << outdent << "};\n\n"
<< "// Classes initialization functions "
<< "------------------------------------------------------------\n"
<< s_classInitDecl.toString() << '\n';
@@ -6150,12 +6296,8 @@ bool CppGenerator::finishGeneration()
s << "// Enum definitions "
<< "------------------------------------------------------------\n";
- for (const AbstractMetaEnum &cppEnum : qAsConst(globalEnums)) {
- if (cppEnum.isAnonymous() || cppEnum.isPrivate())
- continue;
+ for (const AbstractMetaEnum &cppEnum : std::as_const(globalEnums))
writeEnumConverterFunctions(s, cppEnum);
- s << '\n';
- }
if (convImpl.size() > 0) {
s << "// Enum converters "
@@ -6165,7 +6307,6 @@ bool CppGenerator::finishGeneration()
<< "} // namespace Shiboken\n\n";
}
- writeFlagsNumberMethodsDefinitions(s, globalEnums);
s << '\n';
}
@@ -6173,31 +6314,29 @@ bool CppGenerator::finishGeneration()
if (!requiredModules.isEmpty())
s << "// Required modules' type and converter arrays.\n";
for (const QString &requiredModule : requiredModules) {
- s << "PyTypeObject **" << cppApiVariableName(requiredModule) << ";\n"
+ s << "Shiboken::Module::TypeInitStruct *" << cppApiVariableName(requiredModule) << ";\n"
<< "SbkConverter **" << convertersVariableName(requiredModule) << ";\n";
}
s << "\n// Module initialization "
<< "------------------------------------------------------------\n";
- ExtendedConverterData extendedConverters = getExtendedConverters();
if (!extendedConverters.isEmpty()) {
s << '\n' << "// Extended Converters.\n\n";
for (ExtendedConverterData::const_iterator it = extendedConverters.cbegin(), end = extendedConverters.cend(); it != end; ++it) {
- const TypeEntry *externalType = it.key();
+ TypeEntryCPtr externalType = it.key();
s << "// Extended implicit conversions for "
<< externalType->qualifiedTargetLangName() << '.' << '\n';
- for (const AbstractMetaClass *sourceClass : it.value()) {
- AbstractMetaType sourceType = buildAbstractMetaTypeFromAbstractMetaClass(sourceClass);
- AbstractMetaType targetType = buildAbstractMetaTypeFromTypeEntry(externalType);
+ for (const auto &sourceClass : it.value()) {
+ AbstractMetaType sourceType = AbstractMetaType::fromAbstractMetaClass(sourceClass);
+ AbstractMetaType targetType = AbstractMetaType::fromTypeEntry(externalType);
writePythonToCppConversionFunctions(s, sourceType, targetType);
}
}
}
- const QList<const CustomConversion *> &typeConversions = getPrimitiveCustomConversions();
if (!typeConversions.isEmpty()) {
s << "\n// Primitive Type converters.\n\n";
- for (const CustomConversion *conversion : typeConversions) {
+ for (const auto &conversion : typeConversions) {
s << "// C++ to Python conversion for primitive type '" << conversion->ownerType()->qualifiedCppName() << "'.\n";
writeCppToPythonFunction(s, conversion);
writeCustomConverterFunctions(s, conversion);
@@ -6205,23 +6344,20 @@ bool CppGenerator::finishGeneration()
s << '\n';
}
- const auto &containers = instantiatedContainers();
+ QHash<AbstractMetaType, OpaqueContainerData> opaqueContainers;
+ const auto &containers = api().instantiatedContainers();
+ QSet<AbstractMetaType> valueConverters;
if (!containers.isEmpty()) {
s << "// Container Type converters.\n\n";
for (const AbstractMetaType &container : containers) {
- s << "// C++ to Python conversion for container type '" << container.cppSignature() << "'.\n";
+ s << "// C++ to Python conversion for container type '"
+ << container.cppSignature() << "'.\n";
writeContainerConverterFunctions(s, container);
- }
- s << '\n';
- }
-
- // Implicit smart pointers conversions
- const auto smartPointersList = instantiatedSmartPointers();
- if (!smartPointersList.isEmpty()) {
- s << "// SmartPointers converters.\n\n";
- for (const AbstractMetaType &smartPointer : smartPointersList) {
- s << "// C++ to Python conversion for smart pointer type '" << smartPointer.cppSignature() << "'.\n";
- writeSmartPointerConverterFunctions(s, smartPointer);
+ if (container.generateOpaqueContainer()) {
+ auto data = writeOpaqueContainerConverterFunctions(s, container,
+ &valueConverters);
+ opaqueContainers.insert(container, data);
+ }
}
s << '\n';
}
@@ -6240,6 +6376,8 @@ bool CppGenerator::finishGeneration()
// PYSIDE-510: Create a signatures string for the introspection feature.
writeSignatureStrings(s, signatureStream.toString(), moduleName(), "global functions");
+ writeInitInheritance(s);
+
// Write module init function
const QString globalModuleVar = pythonModuleObjectName();
s << "extern \"C\" LIBSHIBOKEN_EXPORT PyObject *PyInit_"
@@ -6248,10 +6386,9 @@ bool CppGenerator::finishGeneration()
s << "if (" << globalModuleVar << " != nullptr)\n"
<< indent << "return " << globalModuleVar << ";\n" << outdent;
- ErrorCode errorCode(QLatin1String("nullptr"));
// module inject-code target/beginning
- if (!snips.isEmpty())
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode);
+ writeModuleCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning,
+ TypeSystem::TargetLangCode);
for (const QString &requiredModule : requiredModules) {
s << "{\n" << indent
@@ -6265,11 +6402,32 @@ bool CppGenerator::finishGeneration()
<< "}\n\n";
}
- int maxTypeIndex = getMaxTypeIndex() + instantiatedSmartPointers().size();
+ int maxTypeIndex = getMaxTypeIndex() + api().instantiatedSmartPointers().size();
if (maxTypeIndex) {
- s << "// Create an array of wrapper types for the current module.\n"
- << "static PyTypeObject *cppApi[SBK_" << moduleName() << "_IDX_COUNT];\n"
- << cppApiVariableName() << " = cppApi;\n\n";
+ s << "// Create an array of wrapper types/names for the current module.\n"
+ << "static Shiboken::Module::TypeInitStruct cppApi[] = {\n" << indent;
+
+ // Windows did not like an array of QString.
+ QStringList typeNames;
+ for (int idx = 0; idx < maxTypeIndex; ++idx)
+ typeNames.append("+++ unknown entry #"_L1 + QString::number(idx)
+ + " in "_L1 + moduleName());
+
+ collectFullTypeNamesArray(typeNames);
+
+ for (auto typeName : typeNames)
+ s << "{nullptr, \"" << typeName << "\"},\n";
+
+ s << "{nullptr, nullptr}\n" << outdent << "};\n"
+ << "// The new global structure consisting of (type, name) pairs.\n"
+ << cppApiVariableName() << " = cppApi;\n";
+ if (usePySideExtensions())
+ s << "QT_WARNING_PUSH\nQT_WARNING_DISABLE_DEPRECATED\n";
+ s << "// The backward compatible alias with upper case indexes.\n"
+ << cppApiVariableNameOld() << " = reinterpret_cast<PyTypeObject **>(cppApi);\n";
+ if (usePySideExtensions())
+ s << "QT_WARNING_POP\n";
+ s << '\n';
}
s << "// Create an array of primitive type converters for the current module.\n"
@@ -6279,13 +6437,18 @@ bool CppGenerator::finishGeneration()
<< "PyObject *module = Shiboken::Module::create(\"" << moduleName()
<< "\", &moduledef);\n\n"
<< "// Make module available from global scope\n"
- << globalModuleVar << " = module;\n\n"
- << "// Initialize classes in the type system\n"
+ << globalModuleVar << " = module;\n\n";
+
+ const QString subModuleOf = typeDb->defaultTypeSystemType()->subModuleOf();
+ if (!subModuleOf.isEmpty())
+ writeSubModuleHandling(s, moduleName(), subModuleOf);
+
+ s << "// Initialize classes in the type system\n"
<< s_classPythonDefines.toString();
if (!typeConversions.isEmpty()) {
s << '\n';
- for (const CustomConversion *conversion : typeConversions) {
+ for (const auto &conversion : typeConversions) {
writePrimitiveConverterInitialization(s, conversion);
s << '\n';
}
@@ -6294,17 +6457,23 @@ bool CppGenerator::finishGeneration()
if (!containers.isEmpty()) {
s << '\n';
for (const AbstractMetaType &container : containers) {
- writeContainerConverterInitialization(s, container);
+ const QString converterObj = writeContainerConverterInitialization(s, container, api());
+ const auto it = opaqueContainers.constFind(container);
+ if (it != opaqueContainers.constEnd()) {
+ writeSetPythonToCppPointerConversion(s, converterObj,
+ it.value().pythonToConverterFunctionName,
+ it.value().converterCheckFunctionName);
+ }
s << '\n';
}
}
- if (!smartPointersList.isEmpty()) {
+ if (!opaqueContainers.isEmpty()) {
+ s << "\n// Opaque container type registration\n"
+ << "PyObject *ob_type{};\n";
+ for (const auto &d : opaqueContainers)
+ s << d.registrationCode;
s << '\n';
- for (const AbstractMetaType &smartPointer : smartPointersList) {
- writeSmartPointerConverterInitialization(s, smartPointer);
- s << '\n';
- }
}
if (!extendedConverters.isEmpty()) {
@@ -6318,21 +6487,14 @@ bool CppGenerator::finishGeneration()
writeEnumsInitialization(s, globalEnums);
s << "// Register primitive types converters.\n";
- const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes();
- for (const PrimitiveTypeEntry *pte : primitiveTypeList) {
- if (!pte->generateCode() || !pte->isCppPrimitive())
+ const PrimitiveTypeEntryCList &primitiveTypeList = primitiveTypes();
+ for (const auto &pte : primitiveTypeList) {
+ if (!pte->generateCode() || !isCppPrimitive(pte))
continue;
- const TypeEntry *referencedType = pte->basicReferencedTypeEntry();
- if (!referencedType)
+ if (!pte->referencesType())
continue;
- QString converter = converterObject(referencedType);
- QStringList cppSignature = pte->qualifiedCppName().split(QLatin1String("::"), Qt::SkipEmptyParts);
- while (!cppSignature.isEmpty()) {
- QString signature = cppSignature.join(QLatin1String("::"));
- s << "Shiboken::Conversions::registerConverterName("
- << converter << ", \"" << signature << "\");\n";
- cppSignature.removeFirst();
- }
+ TypeEntryCPtr referencedType = basicReferencedTypeEntry(pte);
+ registerConverterInScopes(s, pte->qualifiedCppName(), converterObject(referencedType));
}
s << '\n';
@@ -6344,27 +6506,29 @@ bool CppGenerator::finishGeneration()
// of the previously registered types (PYSIDE-1529).
if (!classesWithStaticFields.isEmpty()) {
s << "\n// Static field initialization\n";
- for (auto cls : qAsConst(classesWithStaticFields))
- s << getSimpleClassStaticFieldsInitFunctionName(cls) << "();\n";
+ for (const auto &cls : std::as_const(classesWithStaticFields)) {
+ ConfigurableScope configScope(s, cls->typeEntry());
+ s << getSimpleClassStaticFieldsInitFunctionName(cls) << "(module);\n";
+ }
}
- s << "\nif (PyErr_Occurred()) {\n" << indent
+ s << '\n' << initInheritanceFunction << "();\n"
+ << "\nif (" << shibokenErrorsOccurred << ") {\n" << indent
<< "PyErr_Print();\n"
<< "Py_FatalError(\"can't initialize module " << moduleName() << "\");\n"
<< outdent << "}\n";
// module inject-code target/end
- if (!snips.isEmpty())
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode);
+ writeModuleCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode);
// module inject-code native/end
- if (!snips.isEmpty())
- writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode);
+ writeModuleCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode);
if (usePySideExtensions()) {
- for (const AbstractMetaEnum &metaEnum : qAsConst(globalEnums))
+ for (const AbstractMetaEnum &metaEnum : std::as_const(globalEnums))
if (!metaEnum.isAnonymous()) {
- s << "qRegisterMetaType< ::" << metaEnum.typeEntry()->qualifiedCppName()
+ ConfigurableScope configScope(s, metaEnum.typeEntry());
+ s << "qRegisterMetaType< " << getFullTypeName(metaEnum.typeEntry())
<< " >(\"" << metaEnum.name() << "\");\n";
}
@@ -6372,19 +6536,11 @@ bool CppGenerator::finishGeneration()
s << "PySide::registerCleanupFunction(cleanTypesAttributes);\n\n";
}
- // finish the rest of __signature__ initialization.
+ // finish the rest of get_signature() initialization.
s << "FinishSignatureInitialization(module, " << moduleName()
<< "_SignatureStrings);\n"
<< "\nreturn module;\n" << outdent << "}\n";
- // Temporary hack to allow that the same module can be used both as
- // `Shiboken` and `shiboken6`; this will go away in 6.1.
- if (moduleName() == QLatin1String("Shiboken")) {
- s << "\n// This function should be removed in version 6.2.\n"
- << "extern \"C\" LIBSHIBOKEN_EXPORT PyObject *PyInit_shiboken6()\n{\n" << indent
- << "return PyInit_Shiboken();\n" << outdent
- << "}\n";
- }
file.done();
return true;
}
@@ -6397,16 +6553,35 @@ static ArgumentOwner getArgumentOwner(const AbstractMetaFunctionCPtr &func, int
return argOwner;
}
+// Whether to enable parent ownership heuristic for a function and its argument.
+// Both must belong to the same class hierarchy and have the same
+// type entry enabling parent management.
+static bool useParentHeuristics(const ApiExtractorResult &api,
+ const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaType &argType)
+{
+ if (!ComplexTypeEntry::isParentManagementEnabled()) // FIXME PYSIDE 7: Remove this
+ return true;
+ const auto owner = func->ownerClass();
+ if (!owner)
+ return false;
+ auto ownerEntry = parentManagementEntry(owner);
+ if (!ownerEntry)
+ return false;
+ auto argTypeEntry = argType.typeEntry();
+ if (!argTypeEntry->isComplex())
+ return false;
+ const auto argClass = AbstractMetaClass::findClass(api.classes(), argTypeEntry);
+ return argClass && parentManagementEntry(argClass) == ownerEntry;
+}
+
bool CppGenerator::writeParentChildManagement(TextStream &s, const AbstractMetaFunctionCPtr &func,
- int argIndex, bool useHeuristicPolicy) const
+ int argIndex,
+ bool usePyArgs, bool useHeuristicPolicy) const
{
- const int numArgs = func->arguments().count();
+ const int numArgs = func->arguments().size();
bool ctorHeuristicEnabled = func->isConstructor() && useCtorHeuristic() && useHeuristicPolicy;
-
- const auto &groups = func->implementingClass()
- ? getFunctionGroups(func->implementingClass())
- : getGlobalFunctionGroups();
- bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(OverloadData(groups[func->name()], api()));
+ bool heuristicTriggered = false;
ArgumentOwner argOwner = getArgumentOwner(func, argIndex);
ArgumentOwner::Action action = argOwner.action;
@@ -6414,10 +6589,12 @@ bool CppGenerator::writeParentChildManagement(TextStream &s, const AbstractMetaF
int childIndex = argIndex;
if (ctorHeuristicEnabled && argIndex > 0 && argIndex <= numArgs) {
const AbstractMetaArgument &arg = func->arguments().at(argIndex-1);
- if (arg.name() == QLatin1String("parent") && arg.type().isObjectType()) {
+ if (arg.name() == u"parent" && arg.type().isObjectType()
+ && useParentHeuristics(api(), func, arg.type())) {
action = ArgumentOwner::Add;
parentIndex = argIndex;
childIndex = -1;
+ heuristicTriggered = true;
}
}
@@ -6429,28 +6606,32 @@ bool CppGenerator::writeParentChildManagement(TextStream &s, const AbstractMetaF
<< "Argument index for parent tag out of bounds: " << func->signature();
if (action == ArgumentOwner::Remove) {
- parentVariable = QLatin1String("Py_None");
+ parentVariable = u"Py_None"_s;
} else {
if (parentIndex == 0) {
- parentVariable = QLatin1String(PYTHON_RETURN_VAR);
+ parentVariable = PYTHON_RETURN_VAR;
} else if (parentIndex == -1) {
- parentVariable = QLatin1String("self");
+ parentVariable = PYTHON_SELF_VAR;
} else {
parentVariable = usePyArgs
- ? pythonArgsAt(parentIndex - 1) : QLatin1String(PYTHON_ARG);
+ ? pythonArgsAt(parentIndex - 1) : PYTHON_ARG;
}
}
if (childIndex == 0) {
- childVariable = QLatin1String(PYTHON_RETURN_VAR);
+ childVariable = PYTHON_RETURN_VAR;
} else if (childIndex == -1) {
- childVariable = QLatin1String("self");
+ childVariable = PYTHON_SELF_VAR;
} else {
childVariable = usePyArgs
- ? pythonArgsAt(childIndex - 1) : QLatin1String(PYTHON_ARG);
+ ? pythonArgsAt(childIndex - 1) : PYTHON_ARG;
}
- s << "Shiboken::Object::setParent(" << parentVariable << ", " << childVariable << ");\n";
+ s << "// Ownership transferences";
+ if (heuristicTriggered)
+ s << " (constructor heuristics)";
+ s << ".\nShiboken::Object::setParent(" << parentVariable << ", "
+ << childVariable << ");\n";
return true;
}
@@ -6458,15 +6639,16 @@ bool CppGenerator::writeParentChildManagement(TextStream &s, const AbstractMetaF
}
void CppGenerator::writeParentChildManagement(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ bool usesPyArgs,
bool useHeuristicForReturn) const
{
- const int numArgs = func->arguments().count();
+ const int numArgs = func->arguments().size();
// -1 = return value
// 0 = self
// 1..n = func. args.
for (int i = -1; i <= numArgs; ++i)
- writeParentChildManagement(s, func, i, useHeuristicForReturn);
+ writeParentChildManagement(s, func, i, usesPyArgs, useHeuristicForReturn);
if (useHeuristicForReturn)
writeReturnValueHeuristics(s, func);
@@ -6480,27 +6662,40 @@ void CppGenerator::writeReturnValueHeuristics(TextStream &s, const AbstractMetaF
|| type.isVoid()
|| func->isStatic()
|| func->isConstructor()
- || !func->typeReplaced(0).isEmpty()) {
+ || func->isTypeModified()
+ || !useParentHeuristics(api(), func, type)
+ // Something like parent(), parentWidget(): No child relationship here.
+ || (func->maybeAccessor() && func->name().startsWith(u"parent"))) {
return;
}
ArgumentOwner argOwner = getArgumentOwner(func, ArgumentOwner::ReturnIndex);
if (argOwner.action == ArgumentOwner::Invalid || argOwner.index != ArgumentOwner::ThisIndex) {
- if (type.isPointerToWrapperType())
- s << "Shiboken::Object::setParent(self, " << PYTHON_RETURN_VAR << ");\n";
+ if (type.isPointerToWrapperType()) {
+ s << "// Ownership transferences (return value heuristics).\n"
+ << "Shiboken::Object::setParent(self, " << PYTHON_RETURN_VAR << ");\n";
+ }
}
}
-void CppGenerator::writeHashFunction(TextStream &s, const GeneratorContext &context) const
+void CppGenerator::writeHashFunction(TextStream &s, const GeneratorContext &context)
{
- const AbstractMetaClass *metaClass = context.metaClass();
+ const auto metaClass = context.metaClass();
const char hashType[] = "Py_hash_t";
s << "static " << hashType << ' ' << cpythonBaseName(metaClass)
- << "_HashFunc(PyObject *self) {\n" << indent;
+ << "_HashFunc(PyObject *self)\n{\n" << indent;
writeCppSelfDefinition(s, context);
- s << "return " << hashType << '('
- << metaClass->typeEntry()->hashFunction() << '(';
- if (!metaClass->isObjectType())
+
+ bool deref = true;
+ QString name = metaClass->typeEntry()->hashFunction();
+ if (name.isEmpty())
+ name = metaClass->hashFunction();
+ else
+ deref = !metaClass->isObjectType();
+ Q_ASSERT(!name.isEmpty());
+
+ s << "return " << hashType << '(' << name << '(';
+ if (deref)
s << '*';
s << CPP_SELF_VAR << "));\n"
<< outdent << "}\n\n";
@@ -6509,21 +6704,22 @@ void CppGenerator::writeHashFunction(TextStream &s, const GeneratorContext &cont
void CppGenerator::writeDefaultSequenceMethods(TextStream &s,
const GeneratorContext &context) const
{
- const AbstractMetaClass *metaClass = context.metaClass();
- ErrorCode errorCode(0);
+ const auto metaClass = context.metaClass();
+ ErrorReturn errorReturn = ErrorReturn::Zero;
// __len__
- s << "Py_ssize_t " << cpythonBaseName(metaClass->typeEntry())
+ const QString namePrefix = cpythonBaseName(metaClass->typeEntry());
+ s << "Py_ssize_t " << namePrefix
<< "__len__(PyObject *self)\n{\n" << indent;
- writeCppSelfDefinition(s, context);
+ writeCppSelfDefinition(s, context, errorReturn);
s << "return " << CPP_SELF_VAR << "->size();\n"
<< outdent << "}\n";
// __getitem__
- s << "PyObject *" << cpythonBaseName(metaClass->typeEntry())
+ s << "PyObject *" << namePrefix
<< "__getitem__(PyObject *self, Py_ssize_t _i)\n{\n" << indent;
- writeCppSelfDefinition(s, context);
- writeIndexError(s, QLatin1String("index out of bounds"));
+ writeCppSelfDefinition(s, context, errorReturn);
+ writeIndexError(s, u"index out of bounds"_s, errorReturn);
s << metaClass->qualifiedCppName() << "::const_iterator _item = "
<< CPP_SELF_VAR << "->begin();\n"
@@ -6540,29 +6736,25 @@ void CppGenerator::writeDefaultSequenceMethods(TextStream &s,
const AbstractMetaType &itemType = instantiations.constFirst();
s << "return ";
- writeToPythonConversion(s, itemType, metaClass, QLatin1String("*_item"));
+ writeToPythonConversion(s, itemType, metaClass, u"*_item"_s);
s << ";\n" << outdent << "}\n";
// __setitem__
- ErrorCode errorCode2(-1);
- s << "int " << cpythonBaseName(metaClass->typeEntry())
+ s << "int " << namePrefix
<< "__setitem__(PyObject *self, Py_ssize_t _i, PyObject *pyArg)\n{\n"
<< indent;
- writeCppSelfDefinition(s, context);
- writeIndexError(s, QLatin1String("list assignment index out of range"));
+ errorReturn = ErrorReturn::MinusOne;
+ writeCppSelfDefinition(s, context, errorReturn);
+ writeIndexError(s, u"list assignment index out of range"_s, errorReturn);
- s << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ";\n"
+ s << PYTHON_TO_CPPCONVERSION_STRUCT << ' ' << PYTHON_TO_CPP_VAR << ";\n"
<< "if (!";
- writeTypeCheck(s, itemType, QLatin1String("pyArg"), isNumber(itemType.typeEntry()));
- s << ") {\n";
- {
- Indentation indent(s);
- s << "PyErr_SetString(PyExc_TypeError, \"attributed value with wrong type, '"
- << itemType.name() << "' or other convertible type expected\");\n"
- << "return -1;\n";
- }
- s << "}\n";
- writeArgumentConversion(s, itemType, QLatin1String("cppValue"), QLatin1String("pyArg"), metaClass);
+ writeTypeCheck(s, itemType, u"pyArg"_s, isNumber(itemType.typeEntry()));
+ s << ") {\n" << indent
+ << "Shiboken::Errors::setSequenceTypeError(\"" << itemType.name() << "\");\n"
+ << "return -1;\n" << outdent << "}\n";
+ writeArgumentConversion(s, itemType, u"cppValue"_s,
+ u"pyArg"_s, errorReturn, metaClass);
s << metaClass->qualifiedCppName() << "::iterator _item = "
<< CPP_SELF_VAR << "->begin();\n"
@@ -6571,25 +6763,28 @@ void CppGenerator::writeDefaultSequenceMethods(TextStream &s,
s << "return {};\n" << outdent << "}\n";
}
-void CppGenerator::writeIndexError(TextStream &s, const QString &errorMsg)
+void CppGenerator::writeIndexError(TextStream &s, const QString &errorMsg,
+ ErrorReturn errorReturn)
{
- s << "if (_i < 0 || _i >= (Py_ssize_t) " << CPP_SELF_VAR << "->size()) {\n";
- {
- Indentation indent(s);
- s << "PyErr_SetString(PyExc_IndexError, \"" << errorMsg << "\");\n"
- << returnStatement(m_currentErrorCode) << '\n';
- }
- s << "}\n";
+ s << "if (_i < 0 || _i >= (Py_ssize_t) " << CPP_SELF_VAR << "->size()) {\n"
+ << indent << "PyErr_SetString(PyExc_IndexError, \"" << errorMsg << "\");\n"
+ << errorReturn << outdent << "}\n";
+}
+
+QString CppGenerator::writeReprFunctionHeader(TextStream &s, const GeneratorContext &context)
+{
+ QString funcName = cpythonBaseName(context.metaClass()) + REPR_FUNCTION;
+ s << "extern \"C\"\n{\n"
+ << "static PyObject *" << funcName << "(PyObject *self)\n{\n" << indent;
+ return funcName;
}
QString CppGenerator::writeReprFunction(TextStream &s,
const GeneratorContext &context,
- uint indirections) const
+ uint indirections)
{
- const AbstractMetaClass *metaClass = context.metaClass();
- QString funcName = cpythonBaseName(metaClass) + reprFunction();
- s << "extern \"C\"\n{\n"
- << "static PyObject *" << funcName << "(PyObject *self)\n{\n" << indent;
+ const auto metaClass = context.metaClass();
+ QString funcName = writeReprFunctionHeader(s, context);
writeCppSelfDefinition(s, context);
s << R"(QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
@@ -6600,27 +6795,25 @@ dbg << )";
s << CPP_SELF_VAR << R"(;
buffer.close();
QByteArray str = buffer.data();
-int idx = str.indexOf('(');
+const auto idx = str.indexOf('(');
+auto *typeName = Py_TYPE(self)->tp_name;
if (idx >= 0)
-)";
- {
- Indentation indent(s);
- s << "str.replace(0, idx, Py_TYPE(self)->tp_name);\n";
- }
- s << "str = str.trimmed();\n"
- << "PyObject *mod = PyDict_GetItem(Py_TYPE(self)->tp_dict, Shiboken::PyMagicName::module());\n";
+)" << indent << "str.replace(0, idx, typeName);\n" << outdent
+ << "str = str.trimmed();\n"
+ << "Shiboken::AutoDecRef tpDict(PepType_GetDict(Py_TYPE(self)));\n"
+ << "PyObject *mod = PyDict_GetItem(tpDict.object(), 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 << "if (mod && !strchr(str, '.'))\n";
- {
- Indentation indent(s);
- s << "return Shiboken::String::fromFormat(\"<%s.%s at %p>\", Shiboken::String::toCString(mod), str.constData(), self);\n";
- }
- s << "else\n";
- {
- Indentation indent(s);
- s << "return Shiboken::String::fromFormat(\"<%s at %p>\", str.constData(), self);\n";
- }
- s << outdent << "}\n} // extern C\n\n";
+ s << "if (mod != nullptr && std::strchr(typeName, '.') == nullptr)\n" << indent
+ << "return Shiboken::String::fromFormat(\"<%s.%s at %p>\","
+ " Shiboken::String::toCString(mod), str.constData(), self);\n"
+ << outdent
+ << "return Shiboken::String::fromFormat(\"<%s at %p>\", str.constData(), self);\n";
+ writeReprFunctionFooter(s);
return funcName;
}
+
+void CppGenerator::writeReprFunctionFooter(TextStream &s)
+{
+ s << outdent << "}\n} // extern C\n\n";
+}
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.h b/sources/shiboken6/generator/shiboken/cppgenerator.h
index 7795b4e11..5920c9a3a 100644
--- a/sources/shiboken6/generator/shiboken/cppgenerator.h
+++ b/sources/shiboken6/generator/shiboken/cppgenerator.h
@@ -1,36 +1,23 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef CPPGENERATOR_H
#define CPPGENERATOR_H
#include "shibokengenerator.h"
-#include "abstractmetalang_enums.h"
+#include "include.h"
+#include "modifications_typedefs.h"
+
+#include <QtCore/QFlags>
+#include <QtCore/QSet>
+#include <QtCore/QHash>
+
+#include <memory>
+#include <utility>
+
+class OverloadDataNode;
+class OverloadDataRootNode;
+struct PyMethodDefEntry;
/**
* The CppGenerator generate the implementations of C++ bindings classes.
@@ -38,103 +25,200 @@
class CppGenerator : public ShibokenGenerator
{
public:
+ enum class ErrorReturn {
+ Default, // "{}"
+ Zero,
+ MinusOne,
+ Void
+ };
+
+ enum CppSelfDefinitionFlag {
+ HasStaticOverload = 0x1,
+ HasClassMethodOverload = 0x2,
+ CppSelfAsReference = 0x4
+ };
+ Q_DECLARE_FLAGS(CppSelfDefinitionFlags, CppSelfDefinitionFlag)
+
CppGenerator();
const char *name() const override { return "Source generator"; }
protected:
- QString fileNameSuffix() const override;
QString fileNameForContext(const GeneratorContext &context) const override;
- static QList<AbstractMetaFunctionCList>
- filterGroupedOperatorFunctions(const AbstractMetaClass *metaClass,
- OperatorQueryOptions query);
void generateClass(TextStream &s, const GeneratorContext &classContext) override;
bool finishGeneration() override;
private:
- static void writeInitFunc(TextStream &declStr, TextStream &callStr,
- const QString &initFunctionName,
- const TypeEntry *enclosingEntry = nullptr);
+ struct VirtualMethodReturn
+ {
+ QString statement;
+ bool needsReference = false;
+ };
+
+
+ void generateSmartPointerClass(TextStream &s, const GeneratorContext &classContext);
+ void generateIncludes(TextStream &s, const GeneratorContext &classContext,
+ const IncludeGroupList &includes = {},
+ const AbstractMetaClassCList &innerClasses = {}) const;
+ static void writeInitFuncCall(TextStream &callStr,
+ const QString &functionName,
+ const TypeEntryCPtr &enclosingEntry,
+ const QString &pythonName, bool lazy = true);
static void writeCacheResetNative(TextStream &s, const GeneratorContext &classContext);
void writeConstructorNative(TextStream &s, const GeneratorContext &classContext,
const AbstractMetaFunctionCPtr &func) const;
- void writeDestructorNative(TextStream &s, const GeneratorContext &classContext) const;
+ static void writeDestructorNative(TextStream &s, const GeneratorContext &classContext);
QString getVirtualFunctionReturnTypeName(const AbstractMetaFunctionCPtr &func) const;
- void writeVirtualMethodNative(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ static std::pair<QString, QChar> virtualMethodNativeArg(const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgument &arg);
+ static void writeVirtualMethodNativeVectorCallArgs(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgumentList &arguments,
+ const QList<int> &invalidateArgs);
+ static void writeVirtualMethodNativeArgs(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgumentList &arguments,
+ const QList<int> &invalidateArgs);
+ void writeVirtualMethodNative(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
int cacheIndex) const;
+ void writeVirtualMethodPythonOverride(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const CodeSnipList &snips,
+ const VirtualMethodReturn &returnStatement) const;
+ void writeUserAddedPythonOverride(TextStream &s,
+ const AbstractMetaFunctionCPtr &func) const;
void writeVirtualMethodCppCall(TextStream &s, const AbstractMetaFunctionCPtr &func,
- const QString &funcName, const CodeSnipList &snips,
- const AbstractMetaArgument *lastArg, const TypeEntry *retType,
- const QString &returnStatement) const;
- static QString virtualMethodReturn(TextStream &s, const ApiExtractorResult &api,
- const AbstractMetaFunctionCPtr &func,
- const FunctionModificationList &functionModifications);
+ const QString &funcName, const QList<CodeSnip> &snips,
+ const AbstractMetaArgument *lastArg, const TypeEntryCPtr &retType,
+ const QString &returnStatement, bool hasGil) const;
+
+ static VirtualMethodReturn virtualMethodReturn(const ApiExtractorResult &api,
+ const AbstractMetaFunctionCPtr &func,
+ const FunctionModificationList &functionModifications);
void writeMetaObjectMethod(TextStream &s, const GeneratorContext &classContext) const;
static void writeMetaCast(TextStream &s, const GeneratorContext &classContext);
- void writeEnumConverterFunctions(TextStream &s, const TypeEntry *enumType) const;
void writeEnumConverterFunctions(TextStream &s, const AbstractMetaEnum &metaEnum) const;
- void writeConverterFunctions(TextStream &s, const AbstractMetaClass *metaClass,
+ void writeConverterFunctions(TextStream &s, const AbstractMetaClassCPtr &metaClass,
const GeneratorContext &classContext) const;
void writeCustomConverterFunctions(TextStream &s,
- const CustomConversion *customConversion) const;
- void writeConverterRegister(TextStream &s, const AbstractMetaClass *metaClass,
+ const CustomConversionPtr &customConversion) const;
+ void writeConverterRegister(TextStream &s, const AbstractMetaClassCPtr &metaClass,
const GeneratorContext &classContext) const;
- static void writeCustomConverterRegister(TextStream &s, const CustomConversion *customConversion,
+ static void writeCustomConverterRegister(TextStream &s,
+ const CustomConversionPtr &customConversion,
const QString &converterVar);
void writeContainerConverterFunctions(TextStream &s,
const AbstractMetaType &containerType) const;
+ struct OpaqueContainerData
+ {
+ QString name;
+ QString checkFunctionName;
+ QString converterCheckFunctionName;
+ QString pythonToConverterFunctionName;
+ QString registrationCode;
+ };
+
+ OpaqueContainerData
+ writeOpaqueContainerConverterFunctions(TextStream &s,
+ const AbstractMetaType &containerType,
+ QSet<AbstractMetaType> *valueTypes) const;
+ void writeOpaqueContainerValueConverter(TextStream &s,
+ const AbstractMetaType &valueType) const;
+
void writeSmartPointerConverterFunctions(TextStream &s,
const AbstractMetaType &smartPointerType) const;
- void writeMethodWrapperPreamble(TextStream &s, OverloadData &overloadData,
- const GeneratorContext &context) const;
- void writeConstructorWrapper(TextStream &s, const AbstractMetaFunctionCList &overloads,
+ static bool needsArgumentErrorHandling(const OverloadData &overloadData);
+ static void writeMethodWrapperPreamble(TextStream &s,
+ const OverloadData &overloadData,
+ const GeneratorContext &context,
+ ErrorReturn errorReturn = ErrorReturn::Default);
+ void writeConstructorWrapper(TextStream &s,
+ const OverloadData &overloadData,
const GeneratorContext &classContext) const;
- void writeMethodWrapper(TextStream &s, const AbstractMetaFunctionCList &overloads,
+ void writeMethodWrapper(TextStream &s, const OverloadData &overloadData,
+ const GeneratorContext &classContext) const;
+ void writeMethodWrapper(TextStream &s, TextStream &definitionStream,
+ TextStream &signatureStream,
+ const AbstractMetaFunctionCList &overloads,
const GeneratorContext &classContext) const;
- static void writeArgumentsInitializer(TextStream &s, OverloadData &overloadData) ;
+ static void writeArgumentsInitializer(TextStream &s, const OverloadData &overloadData,
+ ErrorReturn errorReturn = ErrorReturn::Default);
static void writeCppSelfConversion(TextStream &s,
const GeneratorContext &context,
const QString &className,
bool useWrapperClass);
- void writeCppSelfDefinition(TextStream &s,
- const AbstractMetaFunctionCPtr &func,
- const GeneratorContext &context,
- bool hasStaticOverload = false) const;
- void writeCppSelfDefinition(TextStream &s,
- const GeneratorContext &context,
- bool hasStaticOverload = false,
- bool cppSelfAsReference = false) const;
-
- static void writeErrorSection(TextStream &s, OverloadData &overloadData) ;
- static void writeFunctionReturnErrorCheckSection(TextStream &s, bool hasReturnValue = true);
+ static void writeSmartPointerCppSelfConversion(TextStream &s,
+ const GeneratorContext &context);
+
+ static void writeCppSelfVarDef(TextStream &s, CppSelfDefinitionFlags flags = {});
+ static void writeSmartPointerCppSelfDefinition(TextStream &s,
+ const GeneratorContext &,
+ ErrorReturn errorReturn = ErrorReturn::Default,
+ CppSelfDefinitionFlags flags = {});
+ static void writeCppSelfDefinition(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const GeneratorContext &context,
+ ErrorReturn errorReturn = ErrorReturn::Default,
+ CppSelfDefinitionFlags flags = {});
+ static void writeCppSelfDefinition(TextStream &s,
+ const GeneratorContext &context,
+ ErrorReturn errorReturn = ErrorReturn::Default,
+ CppSelfDefinitionFlags flags = {});
- /// Writes the check section for the validity of wrapped C++ objects.
- static void writeInvalidPyObjectCheck(TextStream &s, const QString &pyObj);
+ static void writeErrorSection(TextStream &s,
+ const OverloadData &overloadData,
+ ErrorReturn errorReturn);
- void writeTypeCheck(TextStream &s, AbstractMetaType argType, const QString &argumentName,
- bool isNumber = false, const QString &customType = QString(),
- bool rejectNull = false) const;
- void writeTypeCheck(TextStream& s, const OverloadData *overloadData,
- const QString &argumentName) const;
+ static QString returnErrorWrongArguments(const OverloadData &overloadData,
+ ErrorReturn errorReturn);
- static void writeTypeDiscoveryFunction(TextStream &s, const AbstractMetaClass *metaClass);
+ static void writeFunctionReturnErrorCheckSection(TextStream &s,
+ ErrorReturn errorReturn,
+ bool hasReturnValue = true);
- void writeSetattroDefinition(TextStream &s, const AbstractMetaClass *metaClass) const;
+ /// Writes the check section for the validity of wrapped C++ objects.
+ static void writeInvalidPyObjectCheck(TextStream &s, const QString &pyObj,
+ ErrorReturn errorReturn);
+
+ static void writeTypeCheck(TextStream &s, const AbstractMetaType &argType,
+ const QString &argumentName,
+ bool isNumber = false, bool rejectNull = false);
+ static void writeTypeCheck(TextStream &s, const QString &customType,
+ const QString &argumentName);
+ static void writeTypeCheck(TextStream& s, const std::shared_ptr<OverloadDataNode> &overloadData,
+ const QString &argumentName);
+
+ static void replacePolymorphicIdPlaceHolders(const AbstractMetaClassCPtr &metaClass,
+ QString *id);
+ static void writeTypeDiscoveryFunction(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass);
+
+ static void writeSetattroDefinition(TextStream &s, const AbstractMetaClassCPtr &metaClass);
static void writeSetattroDefaultReturn(TextStream &s);
- void writeSmartPointerSetattroFunction(TextStream &s, const GeneratorContext &context) const;
- void writeSetattroFunction(TextStream &s, AttroCheck attroCheck,
+ static void writeSmartPointerSetattroFunction(TextStream &s,
+ const GeneratorContext &context);
+ void writeSetattroFunction(TextStream &s,
+ AttroCheck attroCheck,
const GeneratorContext &context) const;
- static void writeGetattroDefinition(TextStream &s, const AbstractMetaClass *metaClass);
- static void writeSmartPointerGetattroFunction(TextStream &s, const GeneratorContext &context);
+ static void writeGetattroDefinition(TextStream &s, const AbstractMetaClassCPtr &metaClass);
+ static void writeSmartPointerGetattroFunction(TextStream &s,
+ const GeneratorContext &context,
+ const BoolCastFunctionOptional &boolCast);
void writeGetattroFunction(TextStream &s, AttroCheck attroCheck,
const GeneratorContext &context) const;
QString qObjectGetAttroFunction() const;
+ static void writeNbBoolFunction(const GeneratorContext &context,
+ const BoolCastFunction &f,
+ TextStream &s);
+ static void writeNbBoolExpression(TextStream &s, const BoolCastFunction &f, bool invert = false);
+
/**
* Writes Python to C++ conversions for arguments on Python wrappers.
* If implicit conversions, and thus new object allocation, are needed,
@@ -147,36 +231,37 @@ private:
* \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(TextStream &s, const AbstractMetaType &argType,
- const QString &argName, const QString &pyArgName,
- const AbstractMetaClass *context = nullptr,
- const QString &defaultValue = QString(),
- bool castArgumentAsUnused = false) const;
+ qsizetype writeArgumentConversion(TextStream &s, const AbstractMetaType &argType,
+ const QString &argName, const QString &pyArgName,
+ ErrorReturn errorReturn,
+ const AbstractMetaClassCPtr &context = {},
+ const QString &defaultValue = QString(),
+ bool castArgumentAsUnused = false) const;
/**
* 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.
+ * \param index Argument index in the function signature.
+ * \return The type of the argument indicated by \p index.
*/
- static std::optional<AbstractMetaType>
- getArgumentType(const AbstractMetaFunctionCPtr &func, int argPos);
+ static AbstractMetaType
+ getArgumentType(const AbstractMetaFunctionCPtr &func, int index);
- void writePythonToCppTypeConversion(TextStream &s,
+ /// Writes the Python to C++ Conversion for function arguments and return
+ /// values of virtual methods for wrappers.
+ /// \return The number of indirections in case of return types
+ qsizetype writePythonToCppTypeConversion(TextStream &s,
const AbstractMetaType &type,
const QString &pyIn,
const QString &cppOut,
- const AbstractMetaClass *context = nullptr,
- const QString &defaultValue = QString()) const;
+ const AbstractMetaClassCPtr &context = {},
+ const QString &defaultValue = {}) const;
/// Writes the conversion rule for arguments of regular and virtual methods.
void writeConversionRule(TextStream &s, const AbstractMetaFunctionCPtr &func,
- TypeSystem::Language language) const;
+ TypeSystem::Language language, bool usesPyArgs) const;
/// Writes the conversion rule for the return value of a method.
void writeConversionRule(TextStream &s, const AbstractMetaFunctionCPtr &func,
TypeSystem::Language language, const QString &outputVar) const;
@@ -199,21 +284,25 @@ private:
* \param s text stream to write
* \param overloadData the overload data describing all the possible overloads for the function/method
*/
- void writeOverloadedFunctionDecisor(TextStream &s, const OverloadData &overloadData) const;
+ void writeOverloadedFunctionDecisor(TextStream &s, const OverloadData &overloadData,
+ ErrorReturn errorReturn) const;
/// Recursive auxiliar method to the other writeOverloadedFunctionDecisor.
void writeOverloadedFunctionDecisorEngine(TextStream &s,
- const OverloadData *parentOverloadData) const;
+ const OverloadData &overloadData,
+ const OverloadDataRootNode *node) const;
/// Writes calls to all the possible method/function overloads.
void writeFunctionCalls(TextStream &s,
const OverloadData &overloadData,
- const GeneratorContext &context) const;
+ const GeneratorContext &context,
+ ErrorReturn errorReturn) const;
/// Writes the call to a single function usually from a collection of overloads.
void writeSingleFunctionCall(TextStream &s,
const OverloadData &overloadData,
const AbstractMetaFunctionCPtr &func,
- const GeneratorContext &context) const;
+ const GeneratorContext &context,
+ ErrorReturn errorReturn) const;
/// Returns the name of a C++ to Python conversion function.
static QString cppToPythonFunctionName(const QString &sourceTypeName, QString targetTypeName = QString());
@@ -221,18 +310,22 @@ private:
/// 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);
+ static QString pythonToCppFunctionName(const TargetToNativeConversion &toNative,
+ const TypeEntryCPtr &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);
+ static QString convertibleToCppFunctionName(const TargetToNativeConversion &toNative,
+ const TypeEntryCPtr &targetType);
/// Writes a C++ to Python conversion function.
void writeCppToPythonFunction(TextStream &s, const QString &code, const QString &sourceTypeName,
QString targetTypeName = QString()) const;
- void writeCppToPythonFunction(TextStream &s, const CustomConversion *customConversion) const;
+ void writeCppToPythonFunction(TextStream &s, const CustomConversionPtr &customConversion) const;
void writeCppToPythonFunction(TextStream &s, const AbstractMetaType &containerType) const;
+ /// Main target type name of a container (for naming the functions).
+ static QString containerNativeToTargetTypeName(const ContainerTypeEntryCPtr &type);
/// Writes a Python to C++ conversion function.
void writePythonToCppFunction(TextStream &s, const QString &code, const QString &sourceTypeName,
@@ -255,135 +348,153 @@ private:
const QString &preConversion = QString()) const;
/// Writes a pair of Python to C++ conversion and check functions for implicit conversions.
void writePythonToCppConversionFunctions(TextStream &s,
- const CustomConversion::TargetToNativeConversion *toNative,
- const TypeEntry *targetType) const;
+ const TargetToNativeConversion &toNative,
+ const TypeEntryCPtr &targetType) const;
/// Writes a pair of Python to C++ conversion and check functions for instantiated container types.
void writePythonToCppConversionFunctions(TextStream &s,
const AbstractMetaType &containerType) const;
+ void writePythonToCppConversionFunction(TextStream &s,
+ const AbstractMetaType &containerType,
+ const TargetToNativeConversion &conv) const;
+
static void writeAddPythonToCppConversion(TextStream &s, const QString &converterVar,
- const QString &pythonToCppFunc,
- const QString &isConvertibleFunc);
+ const QString &pythonToCppFunc,
+ const QString &isConvertibleFunc);
+
+ static void writeSetPythonToCppPointerConversion(TextStream &s, const QString &converterVar,
+ const QString &pythonToCppFunc,
+ const QString &isConvertibleFunc);
- void writeNamedArgumentResolution(TextStream &s, const AbstractMetaFunctionCPtr &func,
- bool usePyArgs, const OverloadData &overloadData) const;
+ static void writeNamedArgumentResolution(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ bool usePyArgs,
+ const OverloadData &overloadData,
+ ErrorReturn errorReturn);
/// Returns a string containing the name of an argument for the given function and argument index.
static QString argumentNameFromIndex(const ApiExtractorResult &api,
- const AbstractMetaFunctionCPtr &func, int argIndex,
- const AbstractMetaClass **wrappedClass,
- QString *errorMessage = nullptr);
+ const AbstractMetaFunctionCPtr &func, int argIndex);
+ /// Returns the class for an ownership modification of the argument.
+ /// Throws if the argument is not a class or cannot be found.
+ static AbstractMetaClassCPtr
+ argumentClassFromIndex(const ApiExtractorResult &api,
+ const AbstractMetaFunctionCPtr &func, int argIndex);
+
void writeMethodCall(TextStream &s, const AbstractMetaFunctionCPtr &func,
- const GeneratorContext &context, int maxArgs = 0) const;
+ const GeneratorContext &context, bool usesPyArgs,
+ int maxArgs, const QList<qsizetype> &argumentIndirections,
+ ErrorReturn errorReturn) const;
static QString getInitFunctionName(const GeneratorContext &context) ;
- static QString getSimpleClassInitFunctionName(const AbstractMetaClass *metaClass) ;
- static QString getSimpleClassStaticFieldsInitFunctionName(const AbstractMetaClass *metaClass);
+ static QString getSimpleClassInitFunctionName(const AbstractMetaClassCPtr &metaClass);
+ static QString
+ getSimpleClassStaticFieldsInitFunctionName(const AbstractMetaClassCPtr &metaClass);
static void writeSignatureStrings(TextStream &s, const QString &signatures,
const QString &arrayName,
const char *comment);
+ void writeInitInheritance(TextStream &s) const;
void writeClassRegister(TextStream &s,
- const AbstractMetaClass *metaClass,
+ const AbstractMetaClassCPtr &metaClass,
const GeneratorContext &classContext,
const QString &signatures) const;
- QString destructorClassName(const AbstractMetaClass *metaClass,
- const GeneratorContext &classContext) const;
+ static QStringList pyBaseTypes(const AbstractMetaClassCPtr &metaClass);
+ static QString destructorClassName(const AbstractMetaClassCPtr &metaClass,
+ const GeneratorContext &classContext);
static void writeStaticFieldInitialization(TextStream &s,
- const AbstractMetaClass *metaClass);
+ const AbstractMetaClassCPtr &metaClass);
void writeClassDefinition(TextStream &s,
- const AbstractMetaClass *metaClass,
+ const AbstractMetaClassCPtr &metaClass,
const GeneratorContext &classContext);
- QString methodDefinitionParameters(const OverloadData &overloadData) const;
- void writeMethodDefinitionEntries(TextStream &s,
- const AbstractMetaFunctionCList &overloads,
- qsizetype maxEntries = -1) const;
- void writeMethodDefinition(TextStream &s, const AbstractMetaFunctionCList &overloads) const;
- void writeSignatureInfo(TextStream &s, const AbstractMetaFunctionCList &overloads) const;
+ QByteArrayList methodDefinitionParameters(const OverloadData &overloadData) const;
+ QList<PyMethodDefEntry> methodDefinitionEntries(const OverloadData &overloadData) const;
+
+ void writeSignatureInfo(TextStream &s, const OverloadData &overloads) const;
QString signatureParameter(const AbstractMetaArgument &arg) const;
+ QString pythonSignature(const AbstractMetaType &type) const;
/// Writes the implementation of all methods part of python sequence protocol
void writeSequenceMethods(TextStream &s,
- const AbstractMetaClass *metaClass,
+ const AbstractMetaClassCPtr &metaClass,
const GeneratorContext &context) const;
static void writeTypeAsSequenceDefinition(TextStream &s,
- const AbstractMetaClass *metaClass);
+ const AbstractMetaClassCPtr &metaClass);
/// Writes the PyMappingMethods structure for types that supports the python mapping protocol.
static void writeTypeAsMappingDefinition(TextStream &s,
- const AbstractMetaClass *metaClass);
+ const AbstractMetaClassCPtr &metaClass);
void writeMappingMethods(TextStream &s,
- const AbstractMetaClass *metaClass,
+ const AbstractMetaClassCPtr &metaClass,
const GeneratorContext &context) const;
- void writeTypeAsNumberDefinition(TextStream &s, const AbstractMetaClass *metaClass) const;
-
- static void writeTpTraverseFunction(TextStream &s, const AbstractMetaClass *metaClass);
- static void writeTpClearFunction(TextStream &s, const AbstractMetaClass *metaClass);
-
- void writeCopyFunction(TextStream &s, const GeneratorContext &context) const;
+ void writeTypeAsNumberDefinition(TextStream &s, const AbstractMetaClassCPtr &metaClass) const;
+
+ static void writeTpTraverseFunction(TextStream &s, const AbstractMetaClassCPtr &metaClass);
+ static void writeTpClearFunction(TextStream &s, const AbstractMetaClassCPtr &metaClass);
+
+ static QString writeCopyFunction(TextStream &s, TextStream &definitionStream,
+ TextStream &signatureStream, const GeneratorContext &context);
+
+ static QString cppFieldAccess(const AbstractMetaField &metaField,
+ const GeneratorContext &context);
+ static void writeGetterFunction(TextStream &s,
+ const AbstractMetaField &metaField,
+ const GeneratorContext &context);
+ static void writeGetterFunction(TextStream &s,
+ const QPropertySpec &property,
+ const GeneratorContext &context);
+ static void writeSetterFunctionPreamble(TextStream &s,
+ const QString &name,
+ const QString &funcName,
+ const AbstractMetaType &type,
+ const GeneratorContext &context);
+ static void writeSetterFunction(TextStream &s,
+ const AbstractMetaField &metaField,
+ const GeneratorContext &context);
+ static void writeSetterFunction(TextStream &s,
+ const QPropertySpec &property,
+ const GeneratorContext &context);
+
+ static void writeRichCompareFunctionHeader(TextStream &s,
+ const QString &baseName,
+ const GeneratorContext &context);
+ void writeRichCompareFunction(TextStream &s, const GeneratorContext &context) const;
+ void writeSmartPointerRichCompareFunction(TextStream &s, const GeneratorContext &context) const;
- QString cppFieldAccess(const AbstractMetaField &metaField,
- const GeneratorContext &context) const;
- void writeGetterFunction(TextStream &s,
- const AbstractMetaField &metaField,
- const GeneratorContext &context) const;
- void writeGetterFunction(TextStream &s,
- const QPropertySpec &property,
- const GeneratorContext &context) const;
- void writeSetterFunctionPreamble(TextStream &s,
- const QString &name,
- const QString &funcName,
- const AbstractMetaType &type,
- const GeneratorContext &context) const;
- void writeSetterFunction(TextStream &s,
- const AbstractMetaField &metaField,
- const GeneratorContext &context) const;
- void writeSetterFunction(TextStream &s,
- const QPropertySpec &property,
- const GeneratorContext &context) const;
+ static void writeEnumsInitialization(TextStream &s, AbstractMetaEnumList &enums);
+ static bool writeEnumInitialization(TextStream &s, const AbstractMetaEnum &metaEnum);
- void writeRichCompareFunction(TextStream &s, const GeneratorContext &context) const;
+ static void writeSignalInitialization(TextStream &s, const AbstractMetaClassCPtr &metaClass);
- void writeEnumsInitialization(TextStream &s, AbstractMetaEnumList &enums) const;
- void writeEnumInitialization(TextStream &s, const AbstractMetaEnum &metaEnum) const;
-
- static void writeSignalInitialization(TextStream &s, const AbstractMetaClass *metaClass);
-
- static void writeFlagsMethods(TextStream &s, const AbstractMetaEnum &cppEnum);
- static void writeFlagsToLong(TextStream &s, const AbstractMetaEnum &cppEnum);
- static void writeFlagsNonZero(TextStream &s, const AbstractMetaEnum &cppEnum);
- static void writeFlagsNumberMethodsDefinition(TextStream &s, const AbstractMetaEnum &cppEnum);
- static void writeFlagsNumberMethodsDefinitions(TextStream &s,
- const AbstractMetaEnumList &enums);
- static void writeFlagsBinaryOperator(TextStream &s,
- const AbstractMetaEnum &cppEnum,
- const QString &pyOpName,
- const QString &cppOpName);
- static void writeFlagsUnaryOperator(TextStream &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.
- static void writeMultipleInheritanceInitializerFunction(TextStream &s, const AbstractMetaClass *metaClass);
- /// Writes the implementation of special cast functions, used when we need to cast a class with multiple inheritance.
- static void writeSpecialCastFunction(TextStream &s, const AbstractMetaClass *metaClass);
+ /// Writes the function that registers the multiple inheritance information
+ /// for the classes that need it.
+ static void writeMultipleInheritanceInitializerFunction(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass);
+ /// Writes the implementation of special cast functions, used when we need
+ /// to cast a class with multiple inheritance.
+ static void writeSpecialCastFunction(TextStream &s, const AbstractMetaClassCPtr &metaClass);
static void writePrimitiveConverterInitialization(TextStream &s,
- const CustomConversion *customConversion);
- static void writeEnumConverterInitialization(TextStream &s, const TypeEntry *enumType);
+ const CustomConversionPtr &customConversion);
static void writeEnumConverterInitialization(TextStream &s, const AbstractMetaEnum &metaEnum);
- void writeContainerConverterInitialization(TextStream &s, const AbstractMetaType &type) const;
+ static QString writeContainerConverterInitialization(TextStream &s,
+ const AbstractMetaType &type,
+ const ApiExtractorResult &api);
void writeSmartPointerConverterInitialization(TextStream &s, const AbstractMetaType &ype) const;
- static void writeExtendedConverterInitialization(TextStream &s, const TypeEntry *externalType,
+
+ static QString typeInitStruct(const TypeEntryCPtr &te);
+ static void writeExtendedConverterInitialization(TextStream &s,
+ const TypeEntryCPtr &externalType,
const AbstractMetaClassCList &conversions);
void writeParentChildManagement(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ bool usesPyArgs,
bool userHeuristicForReturn) const;
bool writeParentChildManagement(TextStream &s, const AbstractMetaFunctionCPtr &func,
- int argIndex, bool userHeuristicPolicy) const;
+ int argIndex,
+ bool usePyArgs,
+ bool userHeuristicPolicy) const;
void writeReturnValueHeuristics(TextStream &s, const AbstractMetaFunctionCPtr &func) const;
static void writeInitQtMetaTypeFunctionBody(TextStream &s, const GeneratorContext &context);
@@ -393,63 +504,62 @@ private:
* \return name of the multiple inheritance information initializer function or
* an empty string if there is no multiple inheritance in its ancestry.
*/
- static QString multipleInheritanceInitializerFunctionName(const AbstractMetaClass *metaClass);
+ static QString multipleInheritanceInitializerFunctionName(const AbstractMetaClassCPtr &metaClass);
/// Returns a list of all classes to which the given class could be cast.
- static QStringList getAncestorMultipleInheritance(const AbstractMetaClass *metaClass);
+ static QStringList getAncestorMultipleInheritance(const AbstractMetaClassCPtr &metaClass);
/// Returns true if the given class supports the python number protocol
- bool supportsNumberProtocol(const AbstractMetaClass *metaClass) const;
+ static bool supportsNumberProtocol(const AbstractMetaClassCPtr &metaClass);
/// Returns true if the given class supports the python sequence protocol
- static bool supportsSequenceProtocol(const AbstractMetaClass *metaClass) ;
+ static bool supportsSequenceProtocol(const AbstractMetaClassCPtr &metaClass) ;
/// Returns true if the given class supports the python mapping protocol
- static bool supportsMappingProtocol(const AbstractMetaClass *metaClass) ;
+ static bool supportsMappingProtocol(const AbstractMetaClassCPtr &metaClass) ;
/// Returns true if generator should produce getters and setters for the given class.
- bool shouldGenerateGetSetList(const AbstractMetaClass *metaClass) const;
+ static bool shouldGenerateGetSetList(const AbstractMetaClassCPtr &metaClass);
- void writeHashFunction(TextStream &s, const GeneratorContext &context) const;
+ static bool hasHashFunction(const AbstractMetaClassCPtr &c);
+ static void writeHashFunction(TextStream &s, const GeneratorContext &context);
/// Write default implementations for sequence protocol
void writeDefaultSequenceMethods(TextStream &s, const GeneratorContext &context) const;
/// Helper function for writeStdListWrapperMethods.
- static void writeIndexError(TextStream &s, const QString &errorMsg);
-
- QString writeReprFunction(TextStream &s, const GeneratorContext &context,
- uint indirections) const;
-
- AbstractMetaFunctionCPtr boolCast(const AbstractMetaClass *metaClass) const;
- bool hasBoolCast(const AbstractMetaClass *metaClass) const
- { return !boolCast(metaClass).isNull(); }
-
- std::optional<AbstractMetaType>
- findSmartPointerInstantiation(const TypeEntry *entry) const;
+ static void writeIndexError(TextStream &s, const QString &errorMsg,
+ ErrorReturn errorReturn);
+
+ static QString writeReprFunctionHeader(TextStream &s, const GeneratorContext &context);
+ static QString writeReprFunction(TextStream &s,
+ const GeneratorContext &context,
+ uint indirections);
+ static QString writeSmartPointerReprFunction(TextStream &s,
+ const GeneratorContext &context);
+ static QString writeSmartPointerDirFunction(TextStream &s,
+ TextStream &definitionStream,
+ TextStream &signatureStream,
+ const GeneratorContext &context);
+ static void writeReprFunctionFooter(TextStream &s);
+ static void writePyMethodDefs(TextStream &s, const QString &className,
+ const QString &methodsDefinitions);
+
+ void writeModuleCodeSnips(TextStream &s, const CodeSnipList &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language) const;
+
+ static bool hasBoolCast(const AbstractMetaClassCPtr &metaClass)
+ { return boolCast(metaClass).has_value(); }
void clearTpFuncs();
+ static QString chopType(QString s);
QHash<QString, QString> m_tpFuncs;
-
- 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;
- };
+ QHash<QString, QString> m_nbFuncs;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(CppGenerator::CppSelfDefinitionFlags)
+
+TextStream &operator<<(TextStream &s, CppGenerator::ErrorReturn r);
+
#endif // CPPGENERATOR_H
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp b/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp
new file mode 100644
index 000000000..00e0cabea
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp
@@ -0,0 +1,272 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "cppgenerator.h"
+#include "generatorstrings.h"
+#include <abstractmetalang.h>
+#include "apiextractorresult.h"
+#include "ctypenames.h"
+#include "containertypeentry.h"
+#include "textstream.h"
+#include "typedatabase.h"
+
+#include <QtCore/QDebug>
+
+#include <algorithm>
+
+using namespace Qt::StringLiterals;
+
+// Write a PyMethodDef entry, allowing for registering C++ functions
+// under different names for Python.
+static void writeMethod(TextStream &s, const QString &privateObjType,
+ const char *cppName, const char *pythonName,
+ const char *flags)
+{
+ if (pythonName == nullptr)
+ pythonName = cppName;
+ s << "{\"" << pythonName << "\", reinterpret_cast<PyCFunction>("
+ << privateObjType << "::" << cppName << "), "<< flags
+ << ", \"" << /* doc */ pythonName << "\"},\n";
+}
+
+static inline void writeMethod(TextStream &s, const QString &privateObjType,
+ const char *cppName, const char *pythonName = nullptr)
+{
+ writeMethod(s, privateObjType, cppName, pythonName, "METH_O");
+}
+
+static inline void writeNoArgsMethod(TextStream &s, const QString &privateObjType,
+ const char *cppName, const char *pythonName = nullptr)
+{
+ writeMethod(s, privateObjType, cppName, pythonName, "METH_NOARGS");
+}
+
+static void writeSlot(TextStream &s, const char *tpName, const char *value)
+{
+ s << '{' << tpName << ", reinterpret_cast<void *>(" << value << ")},\n";
+}
+
+static void writeSlot(TextStream &s, const QString &privateObjType,
+ const char *tpName, const char *methodName)
+{
+ s << '{' << tpName << ", reinterpret_cast<void *>(" << privateObjType
+ << "::" << methodName << ")},\n";
+}
+
+// Write creation function from C++ reference, used by field accessors
+// and getters which are within extern "C"
+
+enum ContainerCreationFlag
+{
+ None = 0,
+ Const = 0x1,
+ Allocate = 0x2
+};
+
+Q_DECLARE_FLAGS(ContainerCreationFlags, ContainerCreationFlag)
+Q_DECLARE_OPERATORS_FOR_FLAGS(ContainerCreationFlags)
+
+static void writeContainerCreationFunc(TextStream &s,
+ const QString &funcName,
+ const QString &typeFName,
+ const QString &containerSignature,
+ ContainerCreationFlags flags = {})
+{
+
+ // creation function from C++ reference, used by field accessors
+ // which are within extern "C"
+ s << "extern \"C\" PyObject *" << funcName << '(';
+ if (flags.testFlag(ContainerCreationFlag::Const))
+ s << "const ";
+ s << containerSignature << "* ct)\n{\n" << indent
+ << "auto *container = PyObject_New(ShibokenContainer, " << typeFName << "());\n"
+ << "auto *d = new ShibokenSequenceContainerPrivate<"
+ << containerSignature << ">();\n";
+ if (flags.testFlag(ContainerCreationFlag::Allocate)) {
+ s << "d->m_list = new " << containerSignature << "(*ct);\n"
+ << "d->m_ownsList = true;\n";
+ } else if (flags.testFlag(ContainerCreationFlag::Const)) {
+ s << "d->m_list = const_cast<" << containerSignature << " *>(ct);\n"
+ << "d->m_const = true;\n";
+ } else {
+ s << "d->m_list = ct;\n";
+ }
+ s << "container->d = d;\n";
+ s << "return reinterpret_cast<PyObject *>(container);\n" << outdent
+ << "}\n\n";
+}
+
+// Generate template specialization of value converter helper
+void CppGenerator::writeOpaqueContainerValueConverter(TextStream &s,
+ const AbstractMetaType &valueType) const
+{
+ // Generate template specialization of value converter helper unless it is already there
+ const QString valueTypeName = valueType.cppSignature();
+ const QString checkFunction = cpythonCheckFunction(valueType);
+
+ s << "template <>\nstruct ShibokenContainerValueConverter<"
+ << valueTypeName << ">\n{\n";
+ // Type check
+ s << indent << "static bool checkValue(PyObject *" << PYTHON_ARG << ")\n{\n"
+ << indent << "return " << checkFunction;
+ if (!checkFunction.contains(u'('))
+ s << '(';
+ s << PYTHON_ARG << ");\n"
+ << outdent << "}\n\n";
+
+ // C++ to Python
+ const bool passByConstRef = valueType.indirectionsV().isEmpty()
+ && !valueType.isCppPrimitive();
+ s << "static PyObject *convertValueToPython(";
+ if (passByConstRef)
+ s << "const ";
+ s << valueTypeName << ' ';
+ if (passByConstRef)
+ s << '&';
+ s << CPP_ARG << ")\n{\n" << indent << "return ";
+ writeToPythonConversion(s, valueType, nullptr, CPP_ARG);
+ s << ";\n" << outdent << "}\n\n";
+
+ // Python to C++
+ s << "static std::optional<" << valueTypeName << "> convertValueToCpp(PyObject *"
+ << PYTHON_ARG << ")\n{\n" << indent;
+ s << PYTHON_TO_CPPCONVERSION_STRUCT << ' ' << PYTHON_TO_CPP_VAR << ";\n"
+ << "if (!(";
+ writeTypeCheck(s, valueType, PYTHON_ARG), isNumber(valueType.typeEntry());
+ s << ")) {\n" << indent
+ << "Shiboken::Errors::setWrongContainerType();\n"
+ << "return {};\n" << outdent << "}\n";
+ writePythonToCppTypeConversion(s, valueType, PYTHON_ARG, CPP_ARG, nullptr, {});
+ s << "return " << CPP_ARG << ";\n" << outdent << "}\n" << outdent << "};\n\n";
+}
+
+// Generate code for a type wrapping a C++ container instantiation
+CppGenerator::OpaqueContainerData
+ CppGenerator::writeOpaqueContainerConverterFunctions(TextStream &s,
+ const AbstractMetaType &containerType,
+ QSet<AbstractMetaType> *valueTypes) const
+{
+ OpaqueContainerData result;
+ const auto &valueType = containerType.instantiations().constFirst();
+ const auto containerTypeEntry = std::static_pointer_cast<const ContainerTypeEntry>(containerType.typeEntry());
+ result.name =
+ containerTypeEntry->opaqueContainerName(containerType.instantiationCppSignatures());
+
+ const auto cppSignature = containerType.cppSignature();
+ s << "\n// Binding for " << cppSignature << "\n\n";
+
+ if (!valueTypes->contains(valueType)) {
+ valueTypes->insert(valueType);
+ writeOpaqueContainerValueConverter(s, valueType);
+ }
+
+ const QString privateObjType = u"ShibokenSequenceContainerPrivate<"_s
+ + cppSignature + u'>';
+
+ // methods
+ const QString &containerName = containerType.name();
+ const bool isStdVector = containerName == u"std::vector";
+ const auto kind = containerTypeEntry->containerKind();
+ const bool isFixed = kind == ContainerTypeEntry::SpanContainer || containerName == u"std::array";
+ const QString methods = result.name + u"_methods"_s;
+ s << "static PyMethodDef " << methods << "[] = {\n" << indent;
+ if (!isFixed) {
+ writeMethod(s, privateObjType, "push_back");
+ writeMethod(s, privateObjType, "push_back", "append"); // Qt convention
+ writeNoArgsMethod(s, privateObjType, "clear");
+ writeNoArgsMethod(s, privateObjType, "pop_back");
+ writeNoArgsMethod(s, privateObjType, "pop_back", "removeLast"); // Qt convention
+ if (!isStdVector) {
+ writeMethod(s, privateObjType, "push_front");
+ writeMethod(s, privateObjType, "push_front", "prepend"); // Qt convention
+ writeNoArgsMethod(s, privateObjType, "pop_front");
+ writeMethod(s, privateObjType, "pop_front", "removeFirst"); // Qt convention
+ }
+ writeMethod(s, privateObjType, "reserve"); // SFINAE'd out for list
+ writeNoArgsMethod(s, privateObjType, "capacity");
+ }
+ writeNoArgsMethod(s, privateObjType, "data");
+ writeNoArgsMethod(s, privateObjType, "constData");
+ s << "{nullptr, nullptr, 0, nullptr} // Sentinel\n"
+ << outdent << "};\n\n";
+
+ // slots
+ const QString slotsList = result.name + u"_slots"_s;
+ s << "static PyType_Slot " << slotsList << "[] = {\n" << indent;
+ writeSlot(s, privateObjType, "Py_tp_init", "tpInit");
+ const auto *tpNew = containerTypeEntry->viewOn() == nullptr ? "tpNew" : "tpNewInvalid";
+ writeSlot(s, privateObjType, "Py_tp_new", tpNew);
+ writeSlot(s, privateObjType, "Py_tp_free", "tpFree");
+ writeSlot(s, "Py_tp_dealloc", "Sbk_object_dealloc"); // FIXME?
+ writeSlot(s, "Py_tp_methods", methods.toUtf8().constData());
+ writeSlot(s, privateObjType, "Py_sq_ass_item", "sqSetItem");
+ writeSlot(s, privateObjType, "Py_sq_length", "sqLen");
+ writeSlot(s, privateObjType, "Py_sq_item", "sqGetItem");
+ s << "{0, nullptr}\n" << outdent << "};\n\n";
+
+ // spec
+ const QString specName = result.name + u"_spec"_s;
+ const QString name = TypeDatabase::instance()->defaultPackageName()
+ + u'.' + result.name;
+ s << "static PyType_Spec " << specName << " = {\n" << indent
+ << "\"" << name.count(u'.') << ':' << name << "\",\n"
+ << "sizeof(ShibokenContainer),\n0,\nPy_TPFLAGS_DEFAULT,\n"
+ << slotsList << outdent << "\n};\n\n";
+
+ // type creation function that sets a key in the type dict.
+ const QString typeCreationFName = u"create"_s + result.name + u"Type"_s;
+ s << "static inline PyTypeObject *" << typeCreationFName << "()\n{\n" << indent
+ << "auto *result = reinterpret_cast<PyTypeObject *>(SbkType_FromSpec(&"
+ << specName << "));\nPy_INCREF(Py_True);\n"
+ << "Shiboken::AutoDecRef tpDict(PepType_GetDict(result));\n"
+ << "PyDict_SetItem(tpDict.object(), "
+ "Shiboken::PyMagicName::opaque_container(), Py_True);\n"
+ << "return result;\n" << outdent << "}\n\n";
+
+ // _TypeF() function
+ const QString typeFName = result.name + u"_TypeF"_s;
+ s << "static PyTypeObject *" << typeFName << "()\n{\n" << indent
+ << "static PyTypeObject *type = " << typeCreationFName
+ << "();\nreturn type;\n" << outdent << "}\n\n";
+
+ // creation functions from C++ references
+ ContainerCreationFlags flags;
+ if (kind == ContainerTypeEntry::SpanContainer)
+ flags.setFlag(ContainerCreationFlag::Allocate);
+
+ writeContainerCreationFunc(s, u"create"_s + result.name, typeFName,
+ containerType.cppSignature(), flags);
+ flags.setFlag(ContainerCreationFlag::Const);
+ writeContainerCreationFunc(s, u"createConst"_s + result.name, typeFName,
+ containerType.cppSignature(), flags);
+
+ // Check function
+ result.checkFunctionName = result.name + u"_Check"_s;
+ s << "extern \"C\" int " << result.checkFunctionName << "(PyObject *" << PYTHON_ARG
+ << ")\n{\n" << indent << "return " << PYTHON_ARG << " != nullptr && "
+ << PYTHON_ARG << " != Py_None && " << PYTHON_ARG << "->ob_type == "
+ << typeFName << "();\n" << outdent << "}\n\n";
+
+ // SBK converter Python to C++
+ result.pythonToConverterFunctionName = u"PythonToCpp"_s + result.name;
+ s << "extern \"C\" void " << result.pythonToConverterFunctionName
+ << "(PyObject *" << PYTHON_ARG << ", void *cppOut)\n{\n" << indent
+ << "auto *d = ShibokenSequenceContainerPrivate<" << cppSignature
+ << ">::get(" << PYTHON_ARG << ");\n"
+ << "*reinterpret_cast<" << cppSignature << "**>(cppOut) = d->m_list;\n"
+ << outdent << "}\n\n";
+
+ // SBK check function for converting Python to C++ that returns the converter
+ result.converterCheckFunctionName = u"is"_s + result.name + u"PythonToCppConvertible"_s;
+ s << "extern \"C\" PythonToCppFunc " << result.converterCheckFunctionName
+ << "(PyObject *" << PYTHON_ARG << ")\n{\n" << indent << "if ("
+ << result.checkFunctionName << '(' << PYTHON_ARG << "))\n" << indent
+ << "return " << result.pythonToConverterFunctionName << ";\n"
+ << outdent << "return {};\n" << outdent << "}\n\n";
+
+ QTextStream(&result.registrationCode) << "ob_type = reinterpret_cast<PyObject *>("
+ << typeFName
+ << "());\nPy_XINCREF(ob_type);\nPyModule_AddObject(module, \""
+ << result.name << "\", ob_type);\n";
+ return result;
+}
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp b/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp
new file mode 100644
index 000000000..44b76f181
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp
@@ -0,0 +1,476 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "cppgenerator.h"
+#include "generatorstrings.h"
+#include "generatorcontext.h"
+#include <apiextractorresult.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <codesnip.h>
+#include <exception.h>
+#include <messages.h>
+#include <textstream.h>
+#include <overloaddata.h>
+#include <smartpointertypeentry.h>
+
+#include <QtCore/QDebug>
+
+using namespace Qt::StringLiterals;
+
+static const char smartPtrComment[] =
+ "// Try to find the 'name' attribute, by retrieving the PyObject for "
+ "the corresponding C++ object held by the smart pointer.\n";
+
+static QString smartPointerGetter(const GeneratorContext &context)
+{
+ const auto te = context.metaClass()->typeEntry();
+ Q_ASSERT(te->isSmartPointer());
+ return std::static_pointer_cast<const SmartPointerTypeEntry>(te)->getter();
+}
+
+struct callGetter
+{
+ explicit callGetter(const GeneratorContext &context) : m_context(context) {}
+
+ const GeneratorContext &m_context;
+};
+
+TextStream &operator<<(TextStream &str, const callGetter &c)
+{
+ str << "PyObject_CallMethod(self, \"" << smartPointerGetter(c.m_context) << "\", 0)";
+ return str;
+}
+
+// Helpers to collect all smart pointer pointee base classes
+static AbstractMetaClassCList
+ findSmartPointeeBaseClasses(const ApiExtractorResult &api,
+ const AbstractMetaType &smartPointerType)
+{
+ AbstractMetaClassCList result;
+ auto instantiationsTe = smartPointerType.instantiations().at(0).typeEntry();
+ auto targetClass = AbstractMetaClass::findClass(api.classes(), instantiationsTe);
+ if (targetClass != nullptr)
+ result = targetClass->allTypeSystemAncestors();
+ return result;
+}
+
+using ComparisonOperatorList = QList<AbstractMetaFunction::ComparisonOperatorType>;
+
+// Return the available comparison operators for smart pointers
+static ComparisonOperatorList smartPointeeComparisons(const GeneratorContext &context)
+{
+ Q_ASSERT(context.forSmartPointer());
+ auto te = context.preciseType().instantiations().constFirst().typeEntry();
+ if (isExtendedCppPrimitive(te)) { // Primitive pointee types have all
+ return {AbstractMetaFunction::OperatorEqual,
+ AbstractMetaFunction::OperatorNotEqual,
+ AbstractMetaFunction::OperatorLess,
+ AbstractMetaFunction::OperatorLessEqual,
+ AbstractMetaFunction::OperatorGreater,
+ AbstractMetaFunction::OperatorGreaterEqual};
+ }
+
+ const auto pointeeClass = context.pointeeClass();
+ if (!pointeeClass)
+ return {};
+
+ ComparisonOperatorList result;
+ const auto &comparisons =
+ pointeeClass->operatorOverloads(OperatorQueryOption::SymmetricalComparisonOp);
+ for (const auto &f : comparisons) {
+ const auto ct = f->comparisonOperatorType().value();
+ if (!result.contains(ct))
+ result.append(ct);
+ }
+ return result;
+}
+
+static bool hasParameterPredicate(const AbstractMetaFunctionCPtr &f)
+{
+ return !f->arguments().isEmpty();
+}
+
+void CppGenerator::generateSmartPointerClass(TextStream &s, const GeneratorContext &classContext)
+{
+ s.setLanguage(TextStream::Language::Cpp);
+ AbstractMetaClassCPtr metaClass = classContext.metaClass();
+ const auto typeEntry = std::static_pointer_cast<const SmartPointerTypeEntry>(metaClass->typeEntry());
+ const bool hasPointeeClass = classContext.pointeeClass() != nullptr;
+ const auto smartPointerType = typeEntry->smartPointerType();
+ const bool isValueHandle = smartPointerType ==TypeSystem::SmartPointerType::ValueHandle;
+
+ IncludeGroup includes{u"Extra includes"_s, typeEntry->extraIncludes()};
+ if (hasPointeeClass)
+ includes.append(classContext.pointeeClass()->typeEntry()->include());
+ includes.includes.append({Include::IncludePath, u"sbksmartpointer.h"_s});
+ generateIncludes(s, classContext, {includes});
+
+ s << '\n';
+
+ // class inject-code native/beginning
+ if (!typeEntry->codeSnips().isEmpty()) {
+ writeClassCodeSnips(s, typeEntry->codeSnips(),
+ TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode,
+ classContext);
+ s << '\n';
+ }
+
+ StringStream smd(TextStream::Language::Cpp);
+ StringStream md(TextStream::Language::Cpp);
+ StringStream signatureStream(TextStream::Language::Cpp);
+
+ s << openTargetExternC;
+
+ const auto &functionGroups = getFunctionGroups(metaClass);
+
+ // Skip all public methods of the smart pointer except for the special
+ // methods declared in the type entry.
+
+ auto ctors = metaClass->queryFunctions(FunctionQueryOption::Constructors);
+ if (!hasPointeeClass && !isValueHandle) { // Cannot generate "int*"
+ auto end = std::remove_if(ctors.begin(), ctors.end(), hasParameterPredicate);
+ ctors.erase(end, ctors.end());
+ }
+
+ if (!ctors.isEmpty()) {
+ OverloadData overloadData(ctors, api());
+ writeConstructorWrapper(s, overloadData, classContext);
+ writeSignatureInfo(signatureStream, overloadData);
+ }
+
+ if (!typeEntry->resetMethod().isEmpty()) {
+ auto it = functionGroups.constFind(typeEntry->resetMethod());
+ if (it == functionGroups.cend())
+ throw Exception(msgCannotFindSmartPointerMethod(typeEntry, typeEntry->resetMethod()));
+ AbstractMetaFunctionCList resets = it.value();
+ if (!hasPointeeClass && !isValueHandle) { // Cannot generate "int*"
+ auto end = std::remove_if(resets.begin(), resets.end(), hasParameterPredicate);
+ resets.erase(end, resets.end());
+ }
+ if (!resets.isEmpty())
+ writeMethodWrapper(s, md, signatureStream, resets, classContext);
+ }
+
+ auto it = functionGroups.constFind(typeEntry->getter());
+ if (it == functionGroups.cend() || it.value().size() != 1)
+ throw Exception(msgCannotFindSmartPointerGetter(typeEntry));
+
+ writeMethodWrapper(s, md, signatureStream, it.value(), classContext);
+
+ QStringList optionalMethods;
+ if (!typeEntry->refCountMethodName().isEmpty())
+ optionalMethods.append(typeEntry->refCountMethodName());
+ const QString valueCheckMethod = typeEntry->valueCheckMethod();
+ if (!valueCheckMethod.isEmpty() && !valueCheckMethod.startsWith(u"operator"))
+ optionalMethods.append(valueCheckMethod);
+ if (!typeEntry->nullCheckMethod().isEmpty())
+ optionalMethods.append(typeEntry->nullCheckMethod());
+
+ for (const QString &optionalMethod : optionalMethods) {
+ auto it = functionGroups.constFind(optionalMethod);
+ if (it == functionGroups.cend() || it.value().size() != 1)
+ throw Exception(msgCannotFindSmartPointerMethod(typeEntry, optionalMethod));
+ writeMethodWrapper(s, md, signatureStream, it.value(), classContext);
+ }
+
+ writeCopyFunction(s, md, signatureStream, classContext);
+ writeSmartPointerDirFunction(s, md, signatureStream, classContext);
+
+ const QString methodsDefinitions = md.toString();
+ const QString singleMethodDefinitions = smd.toString();
+
+ const QString className = chopType(cpythonTypeName(typeEntry));
+
+ // Write single method definitions
+ s << singleMethodDefinitions;
+
+ // Write methods definition
+ writePyMethodDefs(s, className, methodsDefinitions);
+
+ // Write tp_s/getattro function
+ const auto boolCastOpt = boolCast(metaClass);
+ writeSmartPointerGetattroFunction(s, classContext, boolCastOpt);
+ writeSmartPointerSetattroFunction(s, classContext);
+
+ if (boolCastOpt.has_value())
+ writeNbBoolFunction(classContext, boolCastOpt.value(), s);
+
+ if (smartPointerType == TypeSystem::SmartPointerType::Shared)
+ writeSmartPointerRichCompareFunction(s, classContext);
+
+ s << closeExternC;
+
+ if (hasHashFunction(metaClass))
+ writeHashFunction(s, classContext);
+
+ // Write tp_traverse and tp_clear functions.
+ writeTpTraverseFunction(s, metaClass);
+ writeTpClearFunction(s, metaClass);
+
+ writeClassDefinition(s, metaClass, classContext);
+
+ s << '\n';
+
+ writeConverterFunctions(s, metaClass, classContext);
+ // Implicit smart pointers conversions
+ writeSmartPointerConverterFunctions(s, classContext.preciseType());
+ writeClassRegister(s, metaClass, classContext, signatureStream);
+
+ // class inject-code native/end
+ if (!typeEntry->codeSnips().isEmpty()) {
+ writeClassCodeSnips(s, typeEntry->codeSnips(),
+ TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode,
+ classContext);
+ s << '\n';
+ }
+}
+
+void CppGenerator::writeSmartPointerConverterFunctions(TextStream &s,
+ const AbstractMetaType &smartPointerType) const
+{
+ const auto baseClasses = findSmartPointeeBaseClasses(api(), smartPointerType);
+ if (baseClasses.isEmpty())
+ return;
+
+ auto smartPointerTypeEntry =
+ std::static_pointer_cast<const SmartPointerTypeEntry>(smartPointerType.typeEntry());
+
+ // TODO: Missing conversion to smart pointer pointer type:
+
+ s << "// Register smartpointer conversion for all derived classes\n";
+ for (const auto &base : baseClasses) {
+ auto baseTe = base->typeEntry();
+ if (smartPointerTypeEntry->matchesInstantiation(baseTe)) {
+ if (auto opt = api().findSmartPointerInstantiation(smartPointerTypeEntry, baseTe)) {
+ const auto &smartTargetType = opt.value().type;
+ s << "// SmartPointer derived class: "
+ << smartTargetType.cppSignature() << "\n";
+ writePythonToCppConversionFunctions(s, smartPointerType,
+ smartTargetType, {}, {}, {});
+ }
+ }
+ }
+}
+
+void CppGenerator::writeSmartPointerCppSelfConversion(TextStream &s,
+ const GeneratorContext &context)
+{
+ Q_ASSERT(context.forSmartPointer());
+ s << cpythonWrapperCPtr(context.preciseType(), u"self"_s);
+}
+
+void CppGenerator::writeSmartPointerCppSelfDefinition(TextStream &s,
+ const GeneratorContext &context,
+ ErrorReturn errorReturn,
+ CppSelfDefinitionFlags flags)
+{
+ Q_ASSERT(context.forSmartPointer());
+ writeInvalidPyObjectCheck(s, u"self"_s, errorReturn);
+ writeCppSelfVarDef(s, flags);
+ writeSmartPointerCppSelfConversion(s, context);
+ s << ";\n";
+}
+
+void CppGenerator::writeSmartPointerConverterInitialization(TextStream &s,
+ const AbstractMetaType &type) const
+{
+ const QByteArray cppSignature = type.cppSignature().toUtf8();
+ auto writeConversionRegister = [&s](const AbstractMetaType &sourceType,
+ const QString &targetTypeName,
+ const QString &targetConverter)
+ {
+ const QString sourceTypeName = fixedCppTypeName(sourceType);
+ const QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName);
+ const QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName);
+
+ writeAddPythonToCppConversion(s, targetConverter, toCpp, isConv);
+ };
+
+ const auto classes = findSmartPointeeBaseClasses(api(), type);
+ if (classes.isEmpty())
+ return;
+
+ auto smartPointerTypeEntry = std::static_pointer_cast<const SmartPointerTypeEntry>(type.typeEntry());
+
+ s << "// Register SmartPointer converter for type '" << cppSignature << "'." << '\n'
+ << "///////////////////////////////////////////////////////////////////////////////////////\n\n";
+
+ for (const auto &base : classes) {
+ auto baseTe = base->typeEntry();
+ if (auto opt = api().findSmartPointerInstantiation(smartPointerTypeEntry, baseTe)) {
+ const auto &smartTargetType = opt.value().type;
+ s << "// Convert to SmartPointer derived class: ["
+ << smartTargetType.cppSignature() << "]\n";
+ const QString converter = u"Shiboken::Conversions::getConverter(\""_s
+ + smartTargetType.cppSignature() + u"\")"_s;
+ writeConversionRegister(type, fixedCppTypeName(smartTargetType), converter);
+ } else {
+ s << "// Class not found:" << type.instantiations().at(0).cppSignature();
+ }
+ }
+
+ s << "///////////////////////////////////////////////////////////////////////////////////////" << '\n' << '\n';
+}
+
+void CppGenerator::writeSmartPointerRichCompareFunction(TextStream &s,
+ const GeneratorContext &context) const
+{
+ static const char selfPointeeVar[] = "cppSelfPointee";
+ static const char cppArg0PointeeVar[] = "cppArg0Pointee";
+
+ const auto metaClass = context.metaClass();
+ QString baseName = cpythonBaseName(metaClass);
+ writeRichCompareFunctionHeader(s, baseName, context);
+
+ s << "if (";
+ writeTypeCheck(s, context.preciseType(), PYTHON_ARG);
+ s << ") {\n" << indent;
+ writeArgumentConversion(s, context.preciseType(), CPP_ARG0,
+ PYTHON_ARG, ErrorReturn::Default, metaClass);
+
+ const auto te = context.preciseType().typeEntry();
+ Q_ASSERT(te->isSmartPointer());
+ const auto ste = std::static_pointer_cast<const SmartPointerTypeEntry>(te);
+
+ s << "const auto *" << selfPointeeVar << " = " << CPP_SELF_VAR
+ << '.' << ste->getter() << "();\n";
+ s << "const auto *" << cppArg0PointeeVar << " = " << CPP_ARG0
+ << '.' << ste->getter() << "();\n";
+
+ // If we have an object without any comparisons, only generate a simple
+ // equality check by pointee address
+ auto availableOps = smartPointeeComparisons(context);
+ const bool comparePointeeAddressOnly = availableOps.isEmpty();
+ if (comparePointeeAddressOnly) {
+ availableOps << AbstractMetaFunction::OperatorEqual
+ << AbstractMetaFunction::OperatorNotEqual;
+ } else {
+ // For value types with operators, we complain about nullptr
+ s << "if (" << selfPointeeVar << " == nullptr || " << cppArg0PointeeVar
+ << " == nullptr) {\n" << indent
+ << "PyErr_SetString(PyExc_NotImplementedError, \"nullptr passed to comparison.\");\n"
+ << ErrorReturn::Default << '\n' << outdent << "}\n";
+ }
+
+ s << "bool " << CPP_RETURN_VAR << "= false;\n"
+ << "switch (op) {\n";
+ for (auto op : availableOps) {
+ s << "case " << AbstractMetaFunction::pythonRichCompareOpCode(op) << ":\n"
+ << indent << CPP_RETURN_VAR << " = ";
+ if (comparePointeeAddressOnly) {
+ s << selfPointeeVar << ' ' << AbstractMetaFunction::cppComparisonOperator(op)
+ << ' ' << cppArg0PointeeVar << ";\n";
+ } else {
+ // Shortcut for equality: Check pointee address
+ if (op == AbstractMetaFunction::OperatorEqual
+ || op == AbstractMetaFunction::OperatorLessEqual
+ || op == AbstractMetaFunction::OperatorGreaterEqual) {
+ s << selfPointeeVar << " == " << cppArg0PointeeVar << " || ";
+ }
+ // Generate object's comparison
+ s << "*" << selfPointeeVar << ' '
+ << AbstractMetaFunction::cppComparisonOperator(op) << " *"
+ << cppArg0PointeeVar << ";\n";
+ }
+ s << "break;\n" << outdent;
+
+ }
+ if (availableOps.size() < 6) {
+ s << "default:\n" << indent
+ << richCompareComment
+ << "return FallbackRichCompare(self, " << PYTHON_ARG << ", op);\n" << outdent;
+ }
+ s << "}\n" << PYTHON_RETURN_VAR << " = " << CPP_RETURN_VAR
+ << " ? Py_True : Py_False;\n"
+ << "Py_INCREF(" << PYTHON_RETURN_VAR << ");\n"
+ << outdent << "}\n"
+ << "return Shiboken::returnFromRichCompare(" << PYTHON_RETURN_VAR << ");\n"
+ << outdent << "}\n\n";
+}
+
+void CppGenerator::writeSmartPointerSetattroFunction(TextStream &s,
+ const GeneratorContext &context)
+{
+ Q_ASSERT(context.forSmartPointer());
+ writeSetattroDefinition(s, context.metaClass());
+ s << smartPtrComment
+ << "if (auto *rawObj = " << callGetter(context) << ") {\n" << indent
+ << "if (PyObject_HasAttr(rawObj, name) != 0)\n" << indent
+ << "return PyObject_GenericSetAttr(rawObj, name, value);\n" << outdent
+ << "Py_DECREF(rawObj);\n" << outdent
+ << "}\n";
+ writeSetattroDefaultReturn(s);
+}
+
+void CppGenerator::writeSmartPointerGetattroFunction(TextStream &s,
+ const GeneratorContext &context,
+ const BoolCastFunctionOptional &boolCast)
+{
+ Q_ASSERT(context.forSmartPointer());
+ const auto metaClass = context.metaClass();
+ writeGetattroDefinition(s, metaClass);
+ s << "PyObject *tmp = PyObject_GenericGetAttr(self, name);\n"
+ << "if (tmp)\n" << indent << "return tmp;\n" << outdent
+ << "if (PyErr_ExceptionMatches(PyExc_AttributeError) == 0)\n"
+ << indent << "return nullptr;\n" << outdent
+ << "PyErr_Clear();\n";
+
+ if (boolCast.has_value()) {
+ writeSmartPointerCppSelfDefinition(s, context);
+ s << "if (";
+ writeNbBoolExpression(s, boolCast.value(), true /* invert */);
+ s << ") {\n" << indent
+ << R"(PyTypeObject *tp = Py_TYPE(self);
+PyErr_Format(PyExc_AttributeError, "Attempt to retrieve '%s' from null object '%s'.",
+ Shiboken::String::toCString(name), tp->tp_name);
+return nullptr;
+)" << outdent << "}\n";
+ }
+
+ // This generates the code which dispatches access to member functions
+ // and fields from the smart pointer to its pointee.
+ s << smartPtrComment
+ << "if (auto *rawObj = " << callGetter(context) << ") {\n" << indent
+ << "if (auto *attribute = PyObject_GetAttr(rawObj, name))\n"
+ << indent << "tmp = attribute;\n" << outdent
+ << "Py_DECREF(rawObj);\n" << outdent
+ << "}\n"
+ << "if (!tmp) {\n" << indent
+ << R"(PyTypeObject *tp = Py_TYPE(self);
+PyErr_Format(PyExc_AttributeError,
+ "'%.50s' object has no attribute '%.400s'",
+ tp->tp_name, Shiboken::String::toCString(name));
+)" << outdent
+ << "}\n"
+ << "return tmp;\n" << outdent << "}\n\n";
+}
+
+QString CppGenerator::writeSmartPointerReprFunction(TextStream &s,
+ const GeneratorContext &context)
+{
+ const auto metaClass = context.metaClass();
+ QString funcName = writeReprFunctionHeader(s, context);
+ s << "Shiboken::AutoDecRef pointee(" << callGetter(context) << ");\n"
+ << "return Shiboken::SmartPointer::repr(self, pointee);\n";
+ writeReprFunctionFooter(s);
+ return funcName;
+}
+
+QString CppGenerator::writeSmartPointerDirFunction(TextStream &s, TextStream &definitionStream,
+ TextStream &signatureStream,
+ const GeneratorContext &context)
+{
+ QString funcName = cpythonBaseName(context.metaClass()) + u"__dir__"_s;
+
+ signatureStream << fullPythonClassName(context.metaClass()) << ".__dir__()\n";
+ definitionStream << PyMethodDefEntry{u"__dir__"_s, funcName, {"METH_NOARGS"_ba}, {}}
+ << ",\n";
+
+ s << "extern \"C\"\n{\n"
+ << "static PyObject *" << funcName << "(PyObject *self)\n{\n" << indent
+ << "Shiboken::AutoDecRef pointee(" << callGetter(context) << ");\n"
+ << "return Shiboken::SmartPointer::dir(self, pointee);\n"
+ << outdent << "}\n} // extern C\n\n";
+ return funcName;
+}
diff --git a/sources/shiboken6/generator/shiboken/ctypenames.h b/sources/shiboken6/generator/shiboken/ctypenames.h
index abac261d5..f665b30ff 100644
--- a/sources/shiboken6/generator/shiboken/ctypenames.h
+++ b/sources/shiboken6/generator/shiboken/ctypenames.h
@@ -1,56 +1,31 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef CTYPENAMES_H
#define CTYPENAMES_H
#include <QtCore/QString>
-static inline QString boolT() { return QStringLiteral("bool"); }
-static inline QString intT() { return QStringLiteral("int"); }
-static inline QString unsignedT() { return QStringLiteral("unsigned"); }
-static inline QString unsignedIntT() { return QStringLiteral("unsigned int"); }
-static inline QString longT() { return QStringLiteral("long"); }
-static inline QString unsignedLongT() { return QStringLiteral("unsigned long"); }
-static inline QString shortT() { return QStringLiteral("short"); }
-static inline QString unsignedShortT() { return QStringLiteral("unsigned short"); }
-static inline QString unsignedCharT() { return QStringLiteral("unsigned char"); }
-static inline QString longLongT() { return QStringLiteral("long long"); }
-static inline QString unsignedLongLongT() { return QStringLiteral("unsigned long long"); }
-static inline QString charT() { return QStringLiteral("char"); }
-static inline QString floatT() { return QStringLiteral("float"); }
-static inline QString doubleT() { return QStringLiteral("double"); }
-static inline QString constCharPtrT() { return QStringLiteral("const char*"); }
+constexpr auto boolT = QLatin1StringView("bool");
+constexpr auto intT = QLatin1StringView("int");
+constexpr auto unsignedT = QLatin1StringView("unsigned");
+constexpr auto unsignedIntT = QLatin1StringView("unsigned int");
+constexpr auto longT = QLatin1StringView("long");
+constexpr auto unsignedLongT = QLatin1StringView("unsigned long");
+constexpr auto shortT = QLatin1StringView("short");
+constexpr auto unsignedShortT = QLatin1StringView("unsigned short");
+constexpr auto unsignedCharT = QLatin1StringView("unsigned char");
+constexpr auto longLongT = QLatin1StringView("long long");
+constexpr auto unsignedLongLongT = QLatin1StringView("unsigned long long");
+constexpr auto charT = QLatin1StringView("char");
+constexpr auto floatT = QLatin1StringView("float");
+constexpr auto doubleT = QLatin1StringView("double");
+constexpr auto constCharPtrT = QLatin1StringView("const char*");
-static inline QString qByteArrayT() { return QStringLiteral("QByteArray"); }
-static inline QString qMetaObjectT() { return QStringLiteral("QMetaObject"); }
-static inline QString qObjectT() { return QStringLiteral("QObject"); }
-static inline QString qStringT() { return QStringLiteral("QString"); }
-static inline QString qVariantT() { return QStringLiteral("QVariant"); }
+constexpr auto qByteArrayT = QLatin1StringView("QByteArray");
+constexpr auto qMetaObjectT = QLatin1StringView("QMetaObject");
+constexpr auto qObjectT = QLatin1StringView("QObject");
+constexpr auto qStringT = QLatin1StringView("QString");
+constexpr auto qVariantT = QLatin1StringView("QVariant");
#endif // CTYPENAMES_H
diff --git a/sources/shiboken6/generator/shiboken/generatorargument.cpp b/sources/shiboken6/generator/shiboken/generatorargument.cpp
new file mode 100644
index 000000000..e81ad0797
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/generatorargument.cpp
@@ -0,0 +1,110 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "generatorargument.h"
+#include <abstractmetatype.h>
+#include <messages.h>
+#include <typesystem.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QSet>
+
+static bool isCppPrimitiveString(const AbstractMetaType &type)
+{
+ return type.referenceType() == NoReference && type.indirections() == 1
+ && AbstractMetaType::cppSignedCharTypes().contains(type.name());
+}
+
+GeneratorArgument GeneratorArgument::fromMetaType(const AbstractMetaType &type)
+{
+ GeneratorArgument result;
+
+ const auto typeEntry = type.typeEntry();
+ if (typeEntry->isCustom() || typeEntry->isVarargs())
+ return result;
+
+ result.indirections = -type.indirectionsV().size();
+ if (isCppPrimitiveString(type)
+ || type.isVoidPointer()
+ || type.typeUsagePattern() == AbstractMetaType::NativePointerAsArrayPattern) {
+ result.indirections += 1;
+ }
+
+ if (typeEntry->isEnum()) {
+ result.type = Type::Enum;
+ } else if (typeEntry->isFlags()) {
+ result.type = Type::Flags;
+ } else if (typeEntry->isContainer()) {
+ result.type = Type::Container;
+ } else {
+ if (typeEntry->isPrimitive())
+ result.type = Type::Primitive;
+
+ const AbstractMetaTypeList &nestedArrayTypes = type.nestedArrayTypes();
+ if (!nestedArrayTypes.isEmpty()) {
+ if (nestedArrayTypes.constLast().isCppPrimitive()) {
+ result.type = Type::CppPrimitiveArray;
+ } else {
+ static QSet<QString> warnedTypes;
+ const QString &signature = type.cppSignature();
+ if (!warnedTypes.contains(signature)) {
+ warnedTypes.insert(signature);
+ qWarning("%s", qPrintable(msgUnknownArrayPointerConversion(signature)));
+ }
+ result.indirections -= 1;
+ }
+ }
+ }
+
+ if (result.type == Type::Other || result.type == Type::Primitive) {
+ if (type.valueTypeWithCopyConstructorOnlyPassed()) {
+ result.flags.setFlag(Flag::TreatAsPointer);
+ } else if ((type.isObjectType() || type.isPointer())
+ && !type.isUserPrimitive() && !type.isExtendedCppPrimitive()) {
+ result.flags.setFlag(Flag::PointerOrObjectType);
+ } else if (type.referenceType() == LValueReference
+ && !type.isUserPrimitive()
+ && !type.isExtendedCppPrimitive()) {
+ result.flags.setFlag(Flag::MayHaveImplicitConversion);
+ }
+ }
+
+ // For implicit conversions or containers, either value or pointer conversion
+ // may occur. An implicit conversion uses value conversion whereas the object
+ // itself uses pointer conversion. For containers, the PyList/container
+ // conversion is by value whereas opaque containers use pointer conversion.
+ // For a container passed by pointer, a local variable is also needed.
+ if (result.flags.testFlag(Flag::MayHaveImplicitConversion)
+ || type.generateOpaqueContainer()
+ || (result.type == Type::Container && result.indirections != 0)) {
+ result.flags.setFlag(Flag::ValueOrPointer);
+ }
+
+ if (result.type == Type::CppPrimitiveArray) {
+ result.conversion = Conversion::CppPrimitiveArray;
+ } else if (result.flags.testFlag(Flag::ValueOrPointer)) {
+ result.conversion = Conversion::ValueOrPointer;
+ ++result.indirections;
+ } else if (result.flags.testAnyFlags(Flag::TreatAsPointer | Flag::PointerOrObjectType)) {
+ result.conversion = Conversion::Pointer;
+ ++result.indirections;
+ }
+
+ return result;
+}
+
+QDebug operator<<(QDebug debug, const GeneratorArgument &a)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "GeneratorArgument(" << a.type;
+ if (a.conversion != GeneratorArgument::Conversion::Default)
+ debug << ", conversion=" << a.conversion;
+ if (a.flags)
+ debug << ", flags(" << a.flags;
+ if (a.indirections != 0)
+ debug << ", indirections=" << a.indirections;
+ debug << ')';
+ return debug;
+}
diff --git a/sources/shiboken6/generator/shiboken/generatorargument.h b/sources/shiboken6/generator/shiboken/generatorargument.h
new file mode 100644
index 000000000..385ad0f63
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/generatorargument.h
@@ -0,0 +1,60 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef GENERATORARGUMENT_H
+#define GENERATORARGUMENT_H
+
+#include <QtCore/QFlags>
+#include <QtCore/qobjectdefs.h>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+class AbstractMetaType;
+
+/// A struct containing information on how the generator processes a function argument.
+struct GeneratorArgument
+{
+ Q_GADGET
+
+public:
+ enum class Type {
+ Other,
+ Primitive,
+ Enum,
+ Flags,
+ Container,
+ CppPrimitiveArray
+ };
+ Q_ENUM(Type)
+
+ enum class Conversion {
+ Default,
+ CppPrimitiveArray, // Similar to Default except default values
+ Pointer,
+ ValueOrPointer
+ };
+ Q_ENUM(Conversion)
+
+ enum class Flag {
+ TreatAsPointer = 0x1,
+ PointerOrObjectType = 0x2,
+ MayHaveImplicitConversion = 0x4,
+ ValueOrPointer = 0x8,
+ };
+ Q_ENUM(Flag)
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ static GeneratorArgument fromMetaType(const AbstractMetaType &type);
+
+ Flags flags;
+ /// Indirections from generated "cppArg<n>" variable to function argument.
+ qsizetype indirections = 0;
+ Type type = Type::Other;
+ Conversion conversion = Conversion::Default;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(GeneratorArgument::Flags)
+
+QDebug operator<<(QDebug debug, const GeneratorArgument &a);
+
+#endif // GENERATORARGUMENT_H
diff --git a/sources/shiboken6/generator/shiboken/generatorstrings.h b/sources/shiboken6/generator/shiboken/generatorstrings.h
new file mode 100644
index 000000000..9ce91e599
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/generatorstrings.h
@@ -0,0 +1,39 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef GENERATORSTRINGS_H
+#define GENERATORSTRINGS_H
+
+#include <QtCore/QString>
+
+QString CPP_ARG_N(int i);
+QString CPP_ARG_REMOVED(int i);
+
+constexpr auto CPP_RETURN_VAR = QLatin1StringView("cppResult");
+constexpr auto CPP_SELF_VAR = QLatin1StringView("cppSelf");
+constexpr auto CPP_ARG = QLatin1StringView("cppArg");
+constexpr auto NULL_PTR = QLatin1StringView("nullptr");
+constexpr auto PYTHON_ARG = QLatin1StringView("pyArg");
+constexpr auto PYTHON_ARGS = QLatin1StringView("pyArgs");
+constexpr auto PYTHON_OVERRIDE_VAR = QLatin1StringView("pyOverride");
+constexpr auto PYTHON_RETURN_VAR = QLatin1StringView("pyResult");
+constexpr auto PYTHON_SELF_VAR = QLatin1StringView("self");
+constexpr auto PYTHON_TO_CPP_VAR = QLatin1StringView("pythonToCpp");
+
+constexpr auto CONV_RULE_OUT_VAR_SUFFIX = QLatin1StringView("_out");
+constexpr auto BEGIN_ALLOW_THREADS
+ = QLatin1StringView("PyThreadState *_save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS");
+constexpr auto END_ALLOW_THREADS
+ = QLatin1StringView("PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS");
+
+constexpr auto REPR_FUNCTION = QLatin1StringView("__repr__");
+
+constexpr auto CPP_ARG0 = QLatin1StringView("cppArg0");
+
+extern const char *const METHOD_DEF_SENTINEL;
+extern const char *const PYTHON_TO_CPPCONVERSION_STRUCT;
+extern const char *const openTargetExternC;
+extern const char *const closeExternC;
+extern const char *const richCompareComment;
+
+#endif // GENERATORSTRINGS_H
diff --git a/sources/shiboken6/generator/shiboken/headergenerator.cpp b/sources/shiboken6/generator/shiboken/headergenerator.cpp
index 2b9074fd8..7cec9c38e 100644
--- a/sources/shiboken6/generator/shiboken/headergenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/headergenerator.cpp
@@ -1,76 +1,106 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "headergenerator.h"
+#include "configurablescope.h"
+#include "generatorcontext.h"
#include <apiextractorresult.h>
+#include <abstractmetaargument.h>
#include <abstractmetaenum.h>
#include <abstractmetafield.h>
#include <abstractmetafunction.h>
#include <abstractmetalang.h>
#include <abstractmetalang_helpers.h>
-#include <modifications.h>
+#include <codesnip.h>
+#include <clangparser/compilersupport.h>
+#include <exception.h>
#include <typedatabase.h>
#include <reporthandler.h>
#include <textstream.h>
#include <fileout.h>
-#include "parser/codemodel.h"
+#include "containertypeentry.h"
+#include "enumtypeentry.h"
+#include "flagstypeentry.h"
+#include <messages.h>
+#include "namespacetypeentry.h"
+#include "primitivetypeentry.h"
+#include "typedefentry.h"
+#include "typesystemtypeentry.h"
+
+#include "qtcompat.h"
#include <algorithm>
+#include <set>
#include <QtCore/QDir>
#include <QtCore/QTextStream>
#include <QtCore/QVariant>
#include <QtCore/QDebug>
-QString HeaderGenerator::fileNameSuffix() const
+using namespace Qt::StringLiterals;
+
+struct IndexValue
+{
+ QString name; // "SBK_..."
+ int value;
+ QString comment;
+};
+
+TextStream &operator<<(TextStream &s, const IndexValue &iv)
+{
+ s << " " << AlignedField(iv.name, 56) << " = " << iv.value << ',';
+ if (!iv.comment.isEmpty())
+ s << " // " << iv.comment;
+ s << '\n';
+ return s;
+}
+
+// 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.
+
+static bool alwaysGenerateDestructorDeclaration()
{
- return QLatin1String("_wrapper.h");
+ return clang::compiler() == Compiler::Msvc;
}
+const char *HeaderGenerator::protectedHackDefine = R"(// Workaround to access protected functions
+#ifndef protected
+# define protected public
+#endif
+
+)";
+
QString HeaderGenerator::fileNameForContext(const GeneratorContext &context) const
{
- const AbstractMetaClass *metaClass = context.metaClass();
- if (!context.forSmartPointer()) {
- QString fileNameBase = metaClass->qualifiedCppName().toLower();
- fileNameBase.replace(QLatin1String("::"), QLatin1String("_"));
- return fileNameBase + fileNameSuffix();
- }
- QString fileNameBase = getFileNameBaseForSmartPointer(context.preciseType(), metaClass);
- return fileNameBase + fileNameSuffix();
+ return headerFileNameForContext(context);
}
-void HeaderGenerator::writeCopyCtor(TextStream &s, const AbstractMetaClass *metaClass) const
+void HeaderGenerator::writeCopyCtor(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass)
{
s << wrapperName(metaClass) << "(const " << metaClass->qualifiedCppName()
<< "& self) : " << metaClass->qualifiedCppName() << "(self)\n{\n}\n\n";
}
-static void writeProtectedEnums(TextStream &s, const AbstractMetaClass *metaClass)
+static void writeProtectedEnums(TextStream &s, const AbstractMetaClassCPtr &metaClass)
{
const QString name = metaClass->qualifiedCppName();
for (const auto &e : metaClass->enums()) {
@@ -79,145 +109,178 @@ static void writeProtectedEnums(TextStream &s, const AbstractMetaClass *metaClas
}
}
-void HeaderGenerator::generateClass(TextStream &s, const GeneratorContext &classContextIn)
+void HeaderGenerator::generateClass(TextStream &s, const GeneratorContext &classContext)
{
- GeneratorContext classContext = classContextIn;
- const AbstractMetaClass *metaClass = classContext.metaClass();
- m_inheritedOverloads.clear();
+ const AbstractMetaClassCPtr metaClass = classContext.metaClass();
// write license comment
s << licenseComment();
- QString wrapperName;
- if (!classContext.forSmartPointer()) {
- wrapperName = classContext.useWrapper()
- ? classContext.wrapperName() : metaClass->qualifiedCppName();
- } else {
- wrapperName = classContext.smartPointerWrapperName();
- }
- QString outerHeaderGuard = getFilteredCppSignatureString(wrapperName).toUpper();
- QString innerHeaderGuard;
+ QString wrapperName = classContext.effectiveClassName();
+ QString outerHeaderGuard = getFilteredCppSignatureString(wrapperName);
// Header
s << "#ifndef SBK_" << outerHeaderGuard << "_H\n";
s << "#define SBK_" << outerHeaderGuard << "_H\n\n";
if (!avoidProtectedHack())
- s << "#define protected public\n\n";
+ s << protectedHackDefine;
- //Includes
- auto typeEntry = metaClass->typeEntry();
- s << typeEntry->include() << '\n';
- if (classContext.useWrapper() && !typeEntry->extraIncludes().isEmpty()) {
- s << "\n// Extra includes\n";
- for (const Include &inc : typeEntry->extraIncludes())
- s << inc.toString() << '\n';
+ // Includes
+ s << metaClass->typeEntry()->include() << '\n';
+ for (auto &inst : metaClass->templateBaseClassInstantiations())
+ s << inst.typeEntry()->include();
+
+ if (classContext.useWrapper())
+ writeWrapperClass(s, wrapperName, classContext);
+
+ s << "#endif // SBK_" << outerHeaderGuard << "_H\n\n";
+}
+
+void HeaderGenerator::writeWrapperClass(TextStream &s,
+ const QString &wrapperName,
+ const GeneratorContext &classContext) const
+{
+ const auto metaClass = classContext.metaClass();
+
+ if (avoidProtectedHack()) {
+ const auto includeGroups = classIncludes(metaClass);
+ for( const auto &includeGroup : includeGroups)
+ s << includeGroup;
}
- if (classContext.useWrapper() && usePySideExtensions() && metaClass->isQObject())
+ if (usePySideExtensions() && isQObject(metaClass))
s << "namespace PySide { class DynamicQMetaObject; }\n\n";
- while (classContext.useWrapper()) {
- if (!innerHeaderGuard.isEmpty()) {
- s << "# ifndef SBK_" << innerHeaderGuard << "_H\n";
- s << "# define SBK_" << innerHeaderGuard << "_H\n\n";
- s << "// Inherited base class:\n";
+ writeWrapperClassDeclaration(s, wrapperName, classContext);
+
+ // PYSIDE-500: Use also includes for inherited wrapper classes other
+ // modules, because without the protected hack, we sometimes need to
+ // cast inherited wrappers. CppGenerator generates include statements for
+ // the classes of the current module. For other modules, we insert the
+ // declarations as recursive headers, since wrapper headers are not
+ // installed. This keeps the file structure as simple as before the
+ // enhanced inheritance.
+ if (avoidProtectedHack()) {
+ const auto &baseClasses = allBaseClasses(classContext.metaClass());
+ for (const auto &baseClass : baseClasses) {
+ const auto gen = baseClass->typeEntry()->codeGeneration();
+ if (gen == TypeEntry::GenerateForSubclass) { // other module
+ const auto baseContext = contextForClass(baseClass);
+ if (baseContext.useWrapper())
+ writeInheritedWrapperClassDeclaration(s, baseContext);
+ }
}
+ }
+}
- // Class
- s << "class " << wrapperName
- << " : public " << metaClass->qualifiedCppName()
- << "\n{\npublic:\n" << indent;
-
- // Make protected enums accessible
- if (avoidProtectedHack()) {
- recurseClassHierarchy(metaClass, [&s] (const AbstractMetaClass *metaClass) {
- writeProtectedEnums(s, metaClass);
- return false;
- });
- }
+void HeaderGenerator::writeInheritedWrapperClassDeclaration(TextStream &s,
+ const GeneratorContext &classContext) const
+{
+ const QString wrapperName = classContext.effectiveClassName();
+ const QString innerHeaderGuard =
+ getFilteredCppSignatureString(wrapperName).toUpper();
- if (avoidProtectedHack() && metaClass->hasProtectedFields()) {
- s << "\n// Make protected fields accessible\n";
- const QString name = metaClass->qualifiedCppName();
- for (const auto &f : metaClass->fields()) {
- if (f.isProtected())
- s << "using " << name << "::" << f.originalName() << ";\n";
- }
- s << '\n';
- }
+ s << "# ifndef SBK_" << innerHeaderGuard << "_H\n"
+ << "# define SBK_" << innerHeaderGuard << "_H\n\n"
+ << "// Inherited base class:\n";
- const auto &funcs = filterFunctions(metaClass);
- int maxOverrides = 0;
- for (const auto &func : funcs) {
- if (!func->attributes().testFlag(AbstractMetaFunction::FinalCppMethod)) {
- writeFunction(s, func);
- // PYSIDE-803: Build a boolean cache for unused overrides.
- if (shouldWriteVirtualMethodNative(func))
- maxOverrides++;
- }
- }
- if (!maxOverrides)
- maxOverrides = 1;
-
- //destructor
- // PYSIDE-504: When C++ 11 is used, then the destructor must always be declared.
- // See abstractmetalang.cpp, determineCppWrapper() and generator.h for further
- // reference.
- if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor() || alwaysGenerateDestructor) {
- if (avoidProtectedHack() && metaClass->hasPrivateDestructor())
- s << "// C++11: need to declare (unimplemented) destructor because "
- "the base class destructor is private.\n";
- s << '~' << wrapperName << "();\n";
+ writeWrapperClassDeclaration(s, wrapperName, classContext);
+
+ s << "# endif // SBK_" << innerHeaderGuard << "_H\n\n";
+}
+
+void HeaderGenerator::writeWrapperClassDeclaration(TextStream &s,
+ const QString &wrapperName,
+ const GeneratorContext &classContext) const
+{
+ const AbstractMetaClassCPtr metaClass = classContext.metaClass();
+ const auto typeEntry = metaClass->typeEntry();
+ InheritedOverloadSet inheritedOverloads;
+
+ // Class
+ s << "class " << wrapperName
+ << " : public " << metaClass->qualifiedCppName()
+ << "\n{\npublic:\n" << indent
+ << wrapperName << "(const " << wrapperName << " &) = delete;\n"
+ << wrapperName << "& operator=(const " << wrapperName << " &) = delete;\n"
+ << wrapperName << '(' << wrapperName << " &&) = delete;\n"
+ << wrapperName << "& operator=(" << wrapperName << " &&) = delete;\n\n";
+
+ // Make protected enums accessible
+ if (avoidProtectedHack()) {
+ recurseClassHierarchy(metaClass, [&s] (const AbstractMetaClassCPtr &metaClass) {
+ writeProtectedEnums(s, metaClass);
+ return false;
+ });
+ }
+
+ if (avoidProtectedHack() && metaClass->hasProtectedFields()) {
+ s << "\n// Make protected fields accessible\n";
+ const QString name = metaClass->qualifiedCppName();
+ for (const auto &f : metaClass->fields()) {
+ if (f.isProtected())
+ s << "using " << name << "::" << f.originalName() << ";\n";
}
+ s << '\n';
+ }
- writeClassCodeSnips(s, metaClass->typeEntry()->codeSnips(),
- TypeSystem::CodeSnipPositionDeclaration, TypeSystem::NativeCode,
- classContext);
+ int maxOverrides = 0;
+ for (const auto &func : metaClass->functions()) {
+ const auto generation = functionGeneration(func);
+ writeFunction(s, func, &inheritedOverloads, generation);
+ // PYSIDE-803: Build a boolean cache for unused overrides.
+ if (generation.testFlag(FunctionGenerationFlag::VirtualMethod))
+ maxOverrides++;
+ }
+ if (!maxOverrides)
+ maxOverrides = 1;
+
+ //destructor
+ // PYSIDE-504: When C++ 11 is used, then the destructor must always be declared.
+ if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor()
+ || alwaysGenerateDestructorDeclaration()) {
+ if (avoidProtectedHack() && metaClass->hasPrivateDestructor())
+ s << "// C++11: need to declare (unimplemented) destructor because "
+ "the base class destructor is private.\n";
+ s << '~' << wrapperName << "()";
+ if (metaClass->hasVirtualDestructor())
+ s << " override";
+ s << ";\n";
+ }
+
+ writeClassCodeSnips(s, typeEntry->codeSnips(),
+ TypeSystem::CodeSnipPositionDeclaration, TypeSystem::NativeCode,
+ classContext);
- if ((!avoidProtectedHack() || !metaClass->hasPrivateDestructor())
- && usePySideExtensions() && metaClass->isQObject()) {
- s << outdent << "public:\n" << indent <<
-R"(int qt_metacall(QMetaObject::Call call, int id, void **args) override;
+ if (shouldGenerateMetaObjectFunctions(metaClass)) {
+ s << R"(
+const ::QMetaObject * metaObject() const override;
+int qt_metacall(QMetaObject::Call call, int id, void **args) override;
void *qt_metacast(const char *_clname) override;
)";
- }
+ }
- if (!m_inheritedOverloads.isEmpty()) {
- s << "// Inherited overloads, because the using keyword sux\n";
- for (const auto &func : qAsConst(m_inheritedOverloads))
- writeMemberFunctionWrapper(s, func);
- m_inheritedOverloads.clear();
- }
+ if (!inheritedOverloads.isEmpty()) {
+ s << "// Inherited overloads, because the using keyword sux\n";
+ for (const auto &func : std::as_const(inheritedOverloads))
+ writeMemberFunctionWrapper(s, func);
+ }
- if (usePySideExtensions())
- s << "static void pysideInitQtMetaTypes();\n";
-
- s << "void resetPyMethodCache();\n"
- << outdent << "private:\n" << indent
- << "mutable bool m_PyMethodCache[" << maxOverrides << "];\n"
- << outdent << "};\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 = contextForClass(metaClass);
- if (!classContext.forSmartPointer()) {
- wrapperName = classContext.useWrapper()
- ? classContext.wrapperName() : metaClass->qualifiedCppName();
- } else {
- wrapperName = classContext.smartPointerWrapperName();
- }
- innerHeaderGuard = getFilteredCppSignatureString(wrapperName).toUpper();
+ if (usePySideExtensions())
+ s << "static void pysideInitQtMetaTypes();\n";
+
+ s << "void resetPyMethodCache();\n"
+ << outdent << "private:\n" << indent;
+
+ if (!metaClass->userAddedPythonOverrides().isEmpty()) {
+ for (const auto &f : metaClass->userAddedPythonOverrides())
+ s << functionSignature(f, {}, {}, Generator::OriginalTypeDescription) << ";\n";
+ s << '\n';
}
- s << "#endif // SBK_" << outerHeaderGuard << "_H\n\n";
+ s << "mutable bool m_PyMethodCache[" << maxOverrides << "];\n"
+ << outdent << "};\n\n";
}
// Write an inline wrapper around a function
@@ -227,8 +290,6 @@ void HeaderGenerator::writeMemberFunctionWrapper(TextStream &s,
{
Q_ASSERT(!func->isConstructor() && !func->isOperatorOverload());
s << "inline ";
- if (func->isStatic())
- s << "static ";
s << functionSignature(func, {}, postfix, Generator::OriginalTypeDescription)
<< " { ";
if (!func->isVoid())
@@ -248,58 +309,52 @@ void HeaderGenerator::writeMemberFunctionWrapper(TextStream &s,
if (i > 0)
s << ", ";
const AbstractMetaArgument &arg = arguments.at(i);
- 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)
- s << arg.type().cppSignature() << '(' << arg.name() << ')';
- else
+ const auto &type = arg.type();
+ TypeEntryCPtr enumTypeEntry;
+ if (type.isFlags())
+ enumTypeEntry = std::static_pointer_cast<const FlagsTypeEntry>(type.typeEntry())->originator();
+ else if (type.isEnum())
+ enumTypeEntry = type.typeEntry();
+ if (enumTypeEntry) {
+ s << type.cppSignature() << '(' << arg.name() << ')';
+ } else if (type.passByValue() && type.isUniquePointer()) {
+ s << stdMove(arg.name());
+ } else {
s << arg.name();
+ }
}
s << "); }\n";
}
-void HeaderGenerator::writeFunction(TextStream &s, const AbstractMetaFunctionCPtr &func)
+void HeaderGenerator::writeFunction(TextStream &s, const AbstractMetaFunctionCPtr &func,
+ InheritedOverloadSet *inheritedOverloads,
+ FunctionGeneration generation) const
{
// do not write copy ctors here.
- if (!func->isPrivate() && func->functionType() == AbstractMetaFunction::CopyConstructorFunction) {
+ if (generation.testFlag(FunctionGenerationFlag::WrapperSpecialCopyConstructor)) {
writeCopyCtor(s, func->ownerClass());
return;
}
- if (func->isUserAdded())
- return;
- if (avoidProtectedHack() && func->isProtected() && !func->isConstructor()
- && !func->isOperatorOverload()) {
- writeMemberFunctionWrapper(s, func, QLatin1String("_protected"));
- }
+ if (generation.testFlag(FunctionGenerationFlag::ProtectedWrapper))
+ writeMemberFunctionWrapper(s, func, u"_protected"_s);
- // pure virtual functions need a default implementation
- const bool notAbstract = !func->isAbstract();
- if ((func->isPrivate() && notAbstract && !func->isVisibilityModifiedToPrivate())
- || (func->isModifiedRemoved() && notAbstract))
+ if (generation.testFlag(FunctionGenerationFlag::WrapperConstructor)) {
+ Options option = func->hasSignatureModifications()
+ ? Generator::OriginalTypeDescription : Generator::NoOption;
+ s << functionSignature(func, {}, {}, option) << ";\n";
return;
+ }
- if (avoidProtectedHack() && func->ownerClass()->hasPrivateDestructor()
- && (func->isAbstract() || func->isVirtual()))
- return;
-
- if (func->isConstructor() || func->isAbstract() || func->isVirtual()) {
- Options virtualOption = Generator::OriginalTypeDescription;
-
- const bool virtualFunc = func->isVirtual() || func->isAbstract();
- if (!virtualFunc && !func->hasSignatureModifications())
- virtualOption = Generator::NoOption;
-
- s << functionSignature(func, QString(), QString(), virtualOption);
+ const bool isVirtual = generation.testFlag(FunctionGenerationFlag::VirtualMethod);
+ if (isVirtual) {
+ s << functionSignature(func, {}, {}, Generator::OriginalTypeDescription)
+ << " override;\n";
+ }
- if (virtualFunc)
- s << " override";
- s << ";\n";
- // Check if this method hide other methods in base classes
+ // Check if this method hide other methods in base classes
+ if (isVirtual) {
for (const auto &f : func->ownerClass()->functions()) {
if (f != func
&& !f->isConstructor()
@@ -308,7 +363,7 @@ void HeaderGenerator::writeFunction(TextStream &s, const AbstractMetaFunctionCPt
&& !f->isAbstract()
&& !f->isStatic()
&& f->name() == func->name()) {
- m_inheritedOverloads << f;
+ inheritedOverloads->insert(f);
}
}
@@ -318,28 +373,14 @@ void HeaderGenerator::writeFunction(TextStream &s, const AbstractMetaFunctionCPt
}
}
-static void _writeTypeIndexValue(TextStream &s, const QString &variableName,
- int typeIndex)
-{
- s << " " << AlignedField(variableName, 56) << " = " << typeIndex;
-}
-
-static inline void _writeTypeIndexValueLine(TextStream &s,
- const QString &variableName,
- int typeIndex)
-{
- _writeTypeIndexValue(s, variableName, typeIndex);
- s << ",\n";
-}
-
// Find equivalent typedefs "using Foo=QList<int>", "using Bar=QList<int>"
-static const AbstractMetaClass *
+static AbstractMetaClassCPtr
findEquivalentTemplateTypedef(const AbstractMetaClassCList &haystack,
- const AbstractMetaClass *needle)
+ const AbstractMetaClassCPtr &needle)
{
- auto *templateBaseClass = needle->templateBaseClass();
+ auto templateBaseClass = needle->templateBaseClass();
const auto &instantiations = needle->templateBaseClassInstantiations();
- for (auto *candidate : haystack) {
+ for (const auto &candidate : haystack) {
if (candidate->isTypeDef()
&& candidate->templateBaseClass() == templateBaseClass
&& candidate->templateBaseClassInstantiations() == instantiations) {
@@ -349,19 +390,20 @@ static const AbstractMetaClass *
return nullptr;
}
-void HeaderGenerator::writeTypeIndexValueLine(TextStream &s, const ApiExtractorResult &api,
- const TypeEntry *typeEntry)
+void HeaderGenerator::collectTypeEntryTypeIndexes(const ApiExtractorResult &api,
+ const TypeEntryCPtr &typeEntry,
+ IndexValues *indexValues)
{
if (!typeEntry || !typeEntry->generateCode())
return;
- s.setFieldAlignment(QTextStream::AlignLeft);
const int typeIndex = typeEntry->sbkIndex();
- _writeTypeIndexValueLine(s, getTypeIndexVariableName(typeEntry), typeIndex);
+ indexValues->append({getTypeIndexVariableName(typeEntry), typeIndex, {}});
+
if (typeEntry->isComplex()) {
// For a typedef "using Foo=QList<int>", write a type index
// SBK_QLIST_INT besides SBK_FOO which is then matched by function
// argument. Check against duplicate typedefs for the same types.
- const auto *cType = static_cast<const ComplexTypeEntry *>(typeEntry);
+ const auto cType = std::static_pointer_cast<const ComplexTypeEntry>(typeEntry);
if (cType->baseContainerType()) {
auto metaClass = AbstractMetaClass::findClass(api.classes(), cType);
Q_ASSERT(metaClass != nullptr);
@@ -371,20 +413,21 @@ void HeaderGenerator::writeTypeIndexValueLine(TextStream &s, const ApiExtractorR
metaClass) == nullptr) {
const QString indexVariable =
getTypeAlternateTemplateIndexVariableName(metaClass);
- _writeTypeIndexValueLine(s, indexVariable, typeIndex);
+ indexValues->append({indexVariable, typeIndex, {}});
m_alternateTemplateIndexes.append(m_alternateTemplateIndexes);
}
}
}
if (typeEntry->isEnum()) {
- auto ete = static_cast<const EnumTypeEntry *>(typeEntry);
+ auto ete = std::static_pointer_cast<const EnumTypeEntry>(typeEntry);
if (ete->flags())
- writeTypeIndexValueLine(s, api, ete->flags());
+ collectTypeEntryTypeIndexes(api, ete->flags(), indexValues);
}
}
-void HeaderGenerator::writeTypeIndexValueLines(TextStream &s, const ApiExtractorResult &api,
- const AbstractMetaClass *metaClass)
+void HeaderGenerator::collectClassTypeIndexes(const ApiExtractorResult &api,
+ const AbstractMetaClassCPtr &metaClass,
+ IndexValues *indexValues)
{
auto typeEntry = metaClass->typeEntry();
if (!typeEntry->generateCode())
@@ -392,16 +435,16 @@ void HeaderGenerator::writeTypeIndexValueLines(TextStream &s, const ApiExtractor
// enum indices are required for invisible namespaces as well.
for (const AbstractMetaEnum &metaEnum : metaClass->enums()) {
if (!metaEnum.isPrivate())
- writeTypeIndexValueLine(s, api, metaEnum.typeEntry());
+ collectTypeEntryTypeIndexes(api, metaEnum.typeEntry(), indexValues);
}
if (NamespaceTypeEntry::isVisibleScope(typeEntry))
- writeTypeIndexValueLine(s, api, metaClass->typeEntry());
+ collectTypeEntryTypeIndexes(api, typeEntry, indexValues);
}
// Format the typedefs for the typedef entries to be generated
static void formatTypeDefEntries(TextStream &s)
{
- QList<const TypedefEntry *> entries;
+ QList<TypedefEntryCPtr> entries;
const auto typeDbEntries = TypeDatabase::instance()->typedefEntries();
for (auto it = typeDbEntries.cbegin(), end = typeDbEntries.cend(); it != end; ++it) {
if (it.value()->generateCode() != 0)
@@ -410,76 +453,262 @@ static void formatTypeDefEntries(TextStream &s)
if (entries.isEmpty())
return;
s << "\n// typedef entries\n";
- for (const auto e : entries) {
+ for (const auto &e : entries) {
const QString name = e->qualifiedCppName();
// Fixme: simplify by using nested namespaces in C++ 17.
const auto components = QStringView{name}.split(u"::");
- const int nameSpaceCount = components.size() - 1;
- for (int n = 0; n < nameSpaceCount; ++n)
+ const auto nameSpaceCount = components.size() - 1;
+ for (qsizetype 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)
+ for (qsizetype n = 0; n < nameSpaceCount; ++n)
s << "}\n";
}
s << '\n';
}
+// Helpers for forward-declaring classes in the module header for the
+// specialization of the SbkType template functions. This is possible if the
+// class does not have inner types or enums which need to be known.
+static bool canForwardDeclare(const AbstractMetaClassCPtr &c)
+{
+ if (c->isNamespace() || !c->enums().isEmpty()
+ || !c->innerClasses().isEmpty() || c->isTypeDef()) {
+ return false;
+ }
+ if (auto encl = c->enclosingClass())
+ return encl->isNamespace();
+ return true;
+}
-bool HeaderGenerator::finishGeneration()
+static void writeForwardDeclaration(TextStream &s, const AbstractMetaClassCPtr &c)
{
- // Generate the main header for this module.
- // This header should be included by binding modules
- // extendind on top of this one.
- QSet<Include> includes;
- QSet<Include> privateIncludes;
- StringStream macrosStream(TextStream::Language::Cpp);
+ Q_ASSERT(!c->isNamespace());
+ const bool isStruct = c->attributes().testFlag(AbstractMetaClass::Struct);
+ s << (isStruct ? "struct " : "class ");
+ // Do not use name as this can be modified/renamed for target lang.
+ const QString qualifiedCppName = c->qualifiedCppName();
+ const auto lastQualifier = qualifiedCppName.lastIndexOf(u':');
+ if (lastQualifier != -1)
+ s << QStringView{qualifiedCppName}.mid(lastQualifier + 1);
+ else
+ s << qualifiedCppName;
+ s << ";\n";
+}
- const auto snips = TypeDatabase::instance()->defaultTypeSystemType()->codeSnips();
- if (!snips.isEmpty()) {
- writeCodeSnips(macrosStream, snips, TypeSystem::CodeSnipPositionDeclaration,
- TypeSystem::TargetLangCode);
+// Helpers for writing out namespaces hierarchically when writing class
+// forward declarations to the module header. Ensure inline namespaces
+// are marked as such (else clang complains) and namespaces are ordered.
+struct NameSpace {
+ AbstractMetaClassCPtr nameSpace;
+ AbstractMetaClassCList classes;
+};
+
+static bool operator<(const NameSpace &n1, const NameSpace &n2)
+{
+ return n1.nameSpace->name() < n2.nameSpace->name();
+}
+
+using NameSpaces = QList<NameSpace>;
+
+static qsizetype indexOf(const NameSpaces &nsps, const AbstractMetaClassCPtr &needle)
+{
+ for (qsizetype i = 0, count = nsps.size(); i < count; ++i) {
+ if (nsps.at(i).nameSpace == needle)
+ return i;
}
+ return -1;
+}
- macrosStream << "// Type indices\nenum : int {\n";
- AbstractMetaClassCList classList = api().classes();
+static void writeNamespaceForwardDeclarationRecursion(TextStream &s, qsizetype idx,
+ const NameSpaces &nameSpaces)
+{
+ auto &root = nameSpaces.at(idx);
+ s << '\n';
+ if (root.nameSpace->isInlineNamespace())
+ s << "inline ";
+ s << "namespace " << root.nameSpace->name() << " {\n" << indent;
+ for (const auto &c : root.classes)
+ writeForwardDeclaration(s, c);
+
+ for (qsizetype i = 0, count = nameSpaces.size(); i < count; ++i) {
+ if (i != idx && nameSpaces.at(i).nameSpace->enclosingClass() == root.nameSpace)
+ writeNamespaceForwardDeclarationRecursion(s, i, nameSpaces);
+ }
+ s << outdent << "}\n";
+}
- std::sort(classList.begin(), classList.end(), [](const AbstractMetaClass *a, const AbstractMetaClass *b) {
- return a->typeEntry()->sbkIndex() < b->typeEntry()->sbkIndex();
- });
+static void writeForwardDeclarations(TextStream &s,
+ const AbstractMetaClassCList &classList)
+{
+ NameSpaces nameSpaces;
+
+ s << '\n';
+ auto typeSystemEntry = TypeDatabase::instance()->defaultTypeSystemType();
+ if (!typeSystemEntry->namespaceBegin().isEmpty())
+ s << typeSystemEntry->namespaceBegin() << '\n';
+
+ for (const auto &c : classList) {
+ if (auto encl = c->enclosingClass()) {
+ Q_ASSERT(encl->isNamespace());
+ auto idx = indexOf(nameSpaces, encl);
+ if (idx != -1) {
+ nameSpaces[idx].classes.append(c);
+ } else {
+ nameSpaces.append(NameSpace{encl, {c}});
+ for (auto enclNsp = encl->enclosingClass(); enclNsp;
+ enclNsp = enclNsp->enclosingClass()) {
+ idx = indexOf(nameSpaces, enclNsp);
+ if (idx == -1)
+ nameSpaces.append(NameSpace{enclNsp, {}});
+ }
+ }
+ } else {
+ writeForwardDeclaration(s, c);
+ }
+ }
+
+ std::sort(nameSpaces.begin(), nameSpaces.end());
+
+ // Recursively write out namespaces starting at the root elements.
+ for (qsizetype i = 0, count = nameSpaces.size(); i < count; ++i) {
+ const auto &nsp = nameSpaces.at(i);
+ if (nsp.nameSpace->enclosingClass() == nullptr)
+ writeNamespaceForwardDeclarationRecursion(s, i, nameSpaces);
+ }
+
+ if (!typeSystemEntry->namespaceEnd().isEmpty())
+ s << typeSystemEntry->namespaceEnd() << '\n';
+}
- for (const AbstractMetaClass *metaClass : classList)
- writeTypeIndexValueLines(macrosStream, api(), metaClass);
+// Include parameters required for the module/private module header
+
+using ConditionalIncludeMap = QMap<QString, IncludeGroup>;
+
+static TextStream &operator<<(TextStream &s, const ConditionalIncludeMap &m)
+{
+ for (auto it = m.cbegin(), end = m.cend(); it != end; ++it)
+ s << it.key() << '\n' << it.value() << "#endif\n";
+ return s;
+}
+
+struct ModuleHeaderParameters
+{
+ AbstractMetaClassCList forwardDeclarations;
+ std::set<Include> includes;
+ ConditionalIncludeMap conditionalIncludes;
+ QString typeFunctions;
+};
+
+HeaderGenerator::IndexValues
+ HeaderGenerator::collectTypeIndexes(const AbstractMetaClassCList &classList)
+{
+ IndexValues result;
+
+ for (const auto &metaClass : classList)
+ collectClassTypeIndexes(api(), metaClass, &result);
for (const AbstractMetaEnum &metaEnum : api().globalEnums())
- writeTypeIndexValueLine(macrosStream, api(), metaEnum.typeEntry());
+ collectTypeEntryTypeIndexes(api(), metaEnum.typeEntry(), &result);
// Write the smart pointer define indexes.
int smartPointerCountIndex = getMaxTypeIndex();
int smartPointerCount = 0;
- const AbstractMetaTypeList &instantiatedSmartPtrs = instantiatedSmartPointers();
- for (const AbstractMetaType &metaType : instantiatedSmartPtrs) {
- QString indexName = getTypeIndexVariableName(metaType);
- _writeTypeIndexValue(macrosStream, indexName, smartPointerCountIndex);
- macrosStream << ", // " << metaType.cppSignature() << '\n';
+ for (const auto &smp : api().instantiatedSmartPointers()) {
+ QString indexName = getTypeIndexVariableName(smp.type);
+ result.append({indexName, smartPointerCountIndex, smp.type.cppSignature()});
// 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);
+ const auto ptrName = smp.type.typeEntry()->entryName();
+ const auto 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";
+ indexName.insert(pos + ptrName.size() + 1, u"const"_s);
+ result.append({indexName, smartPointerCountIndex, "(const)"_L1});
}
++smartPointerCountIndex;
++smartPointerCount;
}
+ result.append({"SBK_"_L1 + moduleName() + "_IDX_COUNT"_L1,
+ getMaxTypeIndex() + smartPointerCount, {}});
+ return result;
+}
+
+HeaderGenerator::IndexValues HeaderGenerator::collectConverterIndexes() const
+{
+ IndexValues result;
+ const auto &primitives = primitiveTypes();
+ int pCount = 0;
+ for (const auto &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() != nullptr)
+ result.append({getTypeIndexVariableName(ptype), pCount++, {}});
+ }
+
+ for (const AbstractMetaType &container : api().instantiatedContainers()) {
+ result.append({getTypeIndexVariableName(container),
+ pCount++, container.cppSignature()});
+ }
+
+ // Because on win32 the compiler will not accept a zero length array.
+ if (pCount == 0)
+ pCount++;
+ result.append({"SBK_"_L1 + moduleName() + "_CONVERTERS_IDX_COUNT"_L1,
+ pCount, {}});
+ return result;
+}
- _writeTypeIndexValue(macrosStream,
- QLatin1String("SBK_") + moduleName() + QLatin1String("_IDX_COUNT"),
- getMaxTypeIndex() + smartPointerCount);
- macrosStream << "\n};\n";
+// PYSIDE-2404: Write the enums in unchanged case for reuse in type imports.
+// For conpatibility, we create them in uppercase, too and with
+// doubled index for emulating the former type-only case.
+//
+// FIXME: Remove in PySide 7. (See the note in `parser.py`)
+//
+static IndexValue typeIndexUpper(struct IndexValue const &ti)
+{
+ QString modi = ti.name.toUpper();
+ if (modi == ti.name)
+ modi = u"// "_s + modi;
+ return {modi, ti.value * 2, ti.comment};
+}
+bool HeaderGenerator::finishGeneration()
+{
+ // Generate the main header for this module. This header should be included
+ // by binding modules extending on top of this one.
+ ModuleHeaderParameters parameters;
+ ModuleHeaderParameters privateParameters;
+ StringStream macrosStream(TextStream::Language::Cpp);
+
+ const auto snips = TypeDatabase::instance()->defaultTypeSystemType()->codeSnips();
+ writeModuleCodeSnips(macrosStream, snips, TypeSystem::CodeSnipPositionDeclaration,
+ TypeSystem::TargetLangCode);
+
+ auto classList = api().classes();
+
+ std::sort(classList.begin(), classList.end(),
+ [](const AbstractMetaClassCPtr &a, const AbstractMetaClassCPtr &b) {
+ return a->typeEntry()->sbkIndex() < b->typeEntry()->sbkIndex();
+ });
+
+ const auto typeIndexes = collectTypeIndexes(classList);
+
+ macrosStream << "\n// Type indices\nenum [[deprecated]] : int {\n";
+ for (const auto &ti : typeIndexes)
+ macrosStream << typeIndexUpper(ti);
+ macrosStream << "};\n";
+
+ macrosStream << "\n// Type indices\nenum : int {\n";
+ for (const auto &ti : typeIndexes)
+ macrosStream << ti;
+ macrosStream << "};\n\n";
+
+ // FIXME: Remove backwards compatible variable in PySide 7.
macrosStream << "// This variable stores all Python types exported by this module.\n";
- macrosStream << "extern PyTypeObject **" << cppApiVariableName() << ";\n\n";
+ macrosStream << "extern Shiboken::Module::TypeInitStruct *" << cppApiVariableName() << ";\n\n";
+ macrosStream << "// This variable stores all Python types exported by this module ";
+ macrosStream << "in a backwards compatible way with identical indexing.\n";
+ macrosStream << "[[deprecated]] extern PyTypeObject **" << cppApiVariableNameOld() << ";\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";
@@ -487,33 +716,16 @@ bool HeaderGenerator::finishGeneration()
// 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 AbstractMetaTypeList &containers = instantiatedContainers();
- for (const AbstractMetaType &container : containers) {
- _writeTypeIndexValue(macrosStream, getTypeIndexVariableName(container), pCount);
- macrosStream << ", // " << container.cppSignature() << '\n';
- pCount++;
- }
+ const auto converterIndexes = collectConverterIndexes();
+ macrosStream << "// Converter indices\nenum [[deprecated]] : int {\n";
+ for (const auto &ci : converterIndexes)
+ macrosStream << typeIndexUpper(ci);
+ macrosStream << "};\n\n";
- // 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";
+ macrosStream << "// Converter indices\nenum : int {\n";
+ for (const auto &ci : converterIndexes)
+ macrosStream << ci;
+ macrosStream << "};\n";
formatTypeDefEntries(macrosStream);
@@ -521,36 +733,46 @@ bool HeaderGenerator::finishGeneration()
macrosStream << "// Macros for type check\n";
- StringStream typeFunctions(TextStream::Language::Cpp);
- StringStream privateTypeFunctions(TextStream::Language::Cpp);
- if (usePySideExtensions()) {
- typeFunctions << "QT_WARNING_PUSH\n";
- typeFunctions << "QT_WARNING_DISABLE_DEPRECATED\n";
- }
+ TextStream typeFunctions(&parameters.typeFunctions, TextStream::Language::Cpp);
+ TextStream privateTypeFunctions(&privateParameters.typeFunctions, TextStream::Language::Cpp);
+
for (const AbstractMetaEnum &cppEnum : api().globalEnums()) {
if (!cppEnum.isAnonymous()) {
- includes << cppEnum.typeEntry()->include();
+ const auto te = cppEnum.typeEntry();
+ if (te->hasConfigCondition())
+ parameters.conditionalIncludes[te->configCondition()].append(te->include());
+ else
+ parameters.includes.insert(cppEnum.typeEntry()->include());
writeSbkTypeFunction(typeFunctions, cppEnum);
}
}
StringStream protEnumsSurrogates(TextStream::Language::Cpp);
- for (auto metaClass : classList) {
- if (!shouldGenerate(metaClass))
+ for (const auto &metaClass : classList) {
+ const auto classType = metaClass->typeEntry();
+ if (!shouldGenerate(classType))
continue;
- //Includes
- const TypeEntry *classType = metaClass->typeEntry();
+ // Includes
const bool isPrivate = classType->isPrivate();
- auto &includeList = isPrivate ? privateIncludes : includes;
- includeList << classType->include();
+ auto &par = isPrivate ? privateParameters : parameters;
+ const auto classInclude = classType->include();
+ const bool hasConfigCondition = classType->hasConfigCondition();
+ if (leanHeaders() && canForwardDeclare(metaClass))
+ par.forwardDeclarations.append(metaClass);
+ else if (hasConfigCondition)
+ par.conditionalIncludes[classType->configCondition()].append(classInclude);
+ else
+ par.includes.insert(classInclude);
+
auto &typeFunctionsStr = isPrivate ? privateTypeFunctions : typeFunctions;
+ ConfigurableScope configScope(typeFunctionsStr, classType);
for (const AbstractMetaEnum &cppEnum : metaClass->enums()) {
if (cppEnum.isAnonymous() || cppEnum.isPrivate())
continue;
- EnumTypeEntry *enumType = cppEnum.typeEntry();
- includeList << enumType->include();
+ if (const auto inc = cppEnum.typeEntry()->include(); inc != classInclude)
+ par.includes.insert(inc);
writeProtectedEnumSurrogate(protEnumsSurrogates, cppEnum);
writeSbkTypeFunction(typeFunctionsStr, cppEnum);
}
@@ -559,19 +781,16 @@ bool HeaderGenerator::finishGeneration()
writeSbkTypeFunction(typeFunctionsStr, metaClass);
}
- for (const AbstractMetaType &metaType : instantiatedSmartPtrs) {
- const TypeEntry *classType = metaType.typeEntry();
- includes << classType->include();
- writeSbkTypeFunction(typeFunctions, metaType);
+ for (const auto &smp : api().instantiatedSmartPointers()) {
+ parameters.includes.insert(smp.type.typeEntry()->include());
+ writeSbkTypeFunction(typeFunctions, smp.type);
}
- if (usePySideExtensions())
- typeFunctions << "QT_WARNING_POP\n";
- const QString moduleHeaderDir = outputDirectory() + QLatin1Char('/')
- + subDirectoryForPackage(packageName()) + QLatin1Char('/');
+ const QString moduleHeaderDir = outputDirectory() + u'/'
+ + subDirectoryForPackage(packageName()) + u'/';
const QString moduleHeaderFileName(moduleHeaderDir + getModuleHeaderFileName());
- QString includeShield(QLatin1String("SBK_") + moduleName().toUpper() + QLatin1String("_PYTHON_H"));
+ QString includeShield(u"SBK_"_s + moduleName().toUpper() + u"_PYTHON_H"_s);
FileOut file(moduleHeaderFileName);
TextStream &s = file.stream;
@@ -588,34 +807,40 @@ bool HeaderGenerator::finishGeneration()
}
s << "#include <sbkpython.h>\n";
+ s << "#include <sbkmodule.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))
+ for (const QString &requiredModule : std::as_const(requiredTargetImports))
s << "#include <" << getModuleHeaderFileName(requiredModule) << ">\n";
s<< '\n';
}
s << "// Bound library includes\n";
- for (const Include &include : qAsConst(includes))
+ for (const Include &include : parameters.includes)
s << include;
+ s << parameters.conditionalIncludes;
- if (!primitiveTypes().isEmpty()) {
- s << "// Conversion Includes - Primitive Types\n";
- const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes();
- for (const PrimitiveTypeEntry *ptype : primitiveTypeList)
- s << ptype->include();
- s<< '\n';
- }
+ if (leanHeaders()) {
+ writeForwardDeclarations(s, parameters.forwardDeclarations);
+ } else {
+ if (!primitiveTypes().isEmpty()) {
+ s << "// Conversion Includes - Primitive Types\n";
+ const auto &primitiveTypeList = primitiveTypes();
+ for (const auto &ptype : primitiveTypeList)
+ s << ptype->include();
+ s<< '\n';
+ }
- if (!containerTypes().isEmpty()) {
- s << "// Conversion Includes - Container Types\n";
- const ContainerTypeEntryList &containerTypeList = containerTypes();
- for (const ContainerTypeEntry *ctype : containerTypeList)
- s << ctype->include();
- s<< '\n';
+ if (!containerTypes().isEmpty()) {
+ s << "// Conversion Includes - Container Types\n";
+ const ContainerTypeEntryCList &containerTypeList = containerTypes();
+ for (const auto &ctype : containerTypeList)
+ s << ctype->include();
+ s<< '\n';
+ }
}
s << macrosStream.toString() << '\n';
@@ -625,25 +850,21 @@ bool HeaderGenerator::finishGeneration()
<< protEnumsSurrogates.toString() << '\n';
}
- s << "namespace Shiboken\n{\n\n"
- << "// PyType functions, to get the PyObjectType for a type T\n"
- << typeFunctions.toString() << '\n'
- << "} // namespace Shiboken\n\n"
- << "#endif // " << includeShield << "\n\n";
+ writeTypeFunctions(s, parameters.typeFunctions);
+
+ s << "#endif // " << includeShield << "\n\n";
file.done();
- if (hasPrivateClasses()) {
- writePrivateHeader(moduleHeaderDir, includeShield,
- privateIncludes, privateTypeFunctions.toString());
- }
+ if (hasPrivateClasses())
+ writePrivateHeader(moduleHeaderDir, includeShield, privateParameters);
+
return true;
}
void HeaderGenerator::writePrivateHeader(const QString &moduleHeaderDir,
const QString &publicIncludeShield,
- const QSet<Include> &privateIncludes,
- const QString &privateTypeFunctions)
+ const ModuleHeaderParameters &parameters)
{
// Write includes and type functions of private classes
@@ -651,63 +872,90 @@ void HeaderGenerator::writePrivateHeader(const QString &moduleHeaderDir,
TextStream &ps = privateFile.stream;
ps.setLanguage(TextStream::Language::Cpp);
QString privateIncludeShield =
- publicIncludeShield.left(publicIncludeShield.size() - 2)
- + QStringLiteral("_P_H");
+ publicIncludeShield.left(publicIncludeShield.size() - 2) + "_P_H"_L1;
ps << licenseComment()<< "\n\n";
ps << "#ifndef " << privateIncludeShield << '\n';
ps << "#define " << privateIncludeShield << "\n\n";
- for (const Include &include : qAsConst(privateIncludes))
+ for (const Include &include : parameters.includes)
ps << include;
+ ps << parameters.conditionalIncludes;
ps << '\n';
+ if (leanHeaders())
+ writeForwardDeclarations(ps, parameters.forwardDeclarations);
+
+ writeTypeFunctions(ps, parameters.typeFunctions);
+
+ ps << "#endif\n";
+ privateFile.done();
+}
+
+void HeaderGenerator::writeTypeFunctions(TextStream &s, const QString &typeFunctions)
+{
+ if (typeFunctions.isEmpty())
+ return;
+
if (usePySideExtensions())
- ps << "QT_WARNING_PUSH\nQT_WARNING_DISABLE_DEPRECATED\n";
+ s << "QT_WARNING_PUSH\nQT_WARNING_DISABLE_DEPRECATED\n";
- ps << "namespace Shiboken\n{\n\n"
+ s << "namespace Shiboken\n{\n\n"
<< "// PyType functions, to get the PyObjectType for a type T\n"
- << privateTypeFunctions << '\n'
+ << typeFunctions << '\n'
<< "} // namespace Shiboken\n\n";
if (usePySideExtensions())
- ps << "QT_WARNING_POP\n";
-
- ps << "#endif\n";
- privateFile.done();
+ s << "QT_WARNING_POP\n";
}
-void HeaderGenerator::writeProtectedEnumSurrogate(TextStream &s, const AbstractMetaEnum &cppEnum) const
+void HeaderGenerator::writeProtectedEnumSurrogate(TextStream &s, const AbstractMetaEnum &cppEnum)
{
if (avoidProtectedHack() && cppEnum.isProtected())
s << "enum " << protectedEnumSurrogateName(cppEnum) << " {};\n";
}
-void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaEnum &cppEnum) const
+void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaEnum &cppEnum)
{
const QString enumName = avoidProtectedHack() && cppEnum.isProtected()
? protectedEnumSurrogateName(cppEnum)
: cppEnum.qualifiedCppName();
+ const auto te = cppEnum.typeEntry();
+ ConfigurableScope configScope(s, te);
+ s << "template<> inline PyTypeObject *SbkType< " << m_gsp << enumName << " >() ";
+ s << "{ return " << cpythonTypeNameExt(te) << "; }\n";
- s << "template<> inline PyTypeObject *SbkType< ::" << enumName << " >() ";
- s << "{ return " << cpythonTypeNameExt(cppEnum.typeEntry()) << "; }\n";
-
- FlagsTypeEntry *flag = cppEnum.typeEntry()->flags();
+ const auto flag = cppEnum.typeEntry()->flags();
if (flag) {
- s << "template<> inline PyTypeObject *SbkType< ::" << flag->name() << " >() "
+ s << "template<> inline PyTypeObject *SbkType< " << m_gsp << flag->name() << " >() "
<< "{ return " << cpythonTypeNameExt(flag) << "; }\n";
}
}
-void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaClass *cppClass)
+void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaClassCPtr &cppClass)
{
- s << "template<> inline PyTypeObject *SbkType< ::" << cppClass->qualifiedCppName() << " >() "
- << "{ return reinterpret_cast<PyTypeObject *>(" << cpythonTypeNameExt(cppClass->typeEntry()) << "); }\n";
+ s << "template<> inline PyTypeObject *SbkType< "
+ << getFullTypeName(cppClass) << " >() "
+ << "{ return " << cpythonTypeNameExt(cppClass->typeEntry()) << "; }\n";
}
void HeaderGenerator::writeSbkTypeFunction(TextStream &s, const AbstractMetaType &metaType)
{
- s << "template<> inline PyTypeObject *SbkType< ::" << metaType.cppSignature() << " >() "
- << "{ return reinterpret_cast<PyTypeObject *>(" << cpythonTypeNameExt(metaType) << "); }\n";
+ s << "template<> inline PyTypeObject *SbkType< "
+ << m_gsp << metaType.cppSignature() << " >() "
+ << "{ return " << cpythonTypeNameExt(metaType) << "; }\n";
+}
+
+void HeaderGenerator::writeModuleCodeSnips(TextStream &s, const CodeSnipList &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language) const
+{
+ if (!codeSnips.isEmpty()) {
+ try {
+ writeCodeSnips(s, codeSnips, position, language);
+ } catch (const std::exception &e) {
+ throw Exception(msgSnippetError("module header of "_L1 + moduleName(), e.what()));
+ }
+ }
}
diff --git a/sources/shiboken6/generator/shiboken/headergenerator.h b/sources/shiboken6/generator/shiboken/headergenerator.h
index 3d64158e7..03b98e743 100644
--- a/sources/shiboken6/generator/shiboken/headergenerator.h
+++ b/sources/shiboken6/generator/shiboken/headergenerator.h
@@ -1,39 +1,19 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef HEADERGENERATOR_H
#define HEADERGENERATOR_H
#include "shibokengenerator.h"
+#include "include.h"
+#include "modifications_typedefs.h"
+#include <QtCore/QList>
#include <QtCore/QSet>
+struct IndexValue;
class AbstractMetaFunction;
+struct ModuleHeaderParameters;
/**
* The HeaderGenerator generate the declarations of C++ bindings classes.
@@ -41,36 +21,54 @@ class AbstractMetaFunction;
class HeaderGenerator : public ShibokenGenerator
{
public:
- OptionDescriptions options() const override { return OptionDescriptions(); }
-
const char *name() const override { return "Header generator"; }
+ static const char *protectedHackDefine;
+
protected:
- QString fileNameSuffix() const override;
QString fileNameForContext(const GeneratorContext &context) const override;
void generateClass(TextStream &s, const GeneratorContext &classContext) override;
bool finishGeneration() override;
private:
- void writeCopyCtor(TextStream &s, const AbstractMetaClass *metaClass) const;
- void writeFunction(TextStream &s, const AbstractMetaFunctionCPtr &func);
- void writeSbkTypeFunction(TextStream &s, const AbstractMetaEnum &cppEnum) const;
- static void writeSbkTypeFunction(TextStream &s, const AbstractMetaClass *cppClass) ;
- static void writeSbkTypeFunction(TextStream &s, const AbstractMetaType &metaType) ;
- void writeTypeIndexValueLine(TextStream &s, const ApiExtractorResult &api,
- const TypeEntry *typeEntry);
- void writeTypeIndexValueLines(TextStream &s, const ApiExtractorResult &api,
- const AbstractMetaClass *metaClass);
- void writeProtectedEnumSurrogate(TextStream &s, const AbstractMetaEnum &cppEnum) const;
+ using InheritedOverloadSet = QSet<AbstractMetaFunctionCPtr>;
+ using IndexValues = QList<IndexValue>;
+
+ IndexValues collectTypeIndexes(const AbstractMetaClassCList &classList);
+ IndexValues collectConverterIndexes() const;
+
+ static void writeCopyCtor(TextStream &s, const AbstractMetaClassCPtr &metaClass);
+ void writeFunction(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ InheritedOverloadSet *inheritedOverloads,
+ FunctionGeneration generation) const;
+ static void writeSbkTypeFunction(TextStream &s, const AbstractMetaEnum &cppEnum);
+ static void writeSbkTypeFunction(TextStream &s, const AbstractMetaClassCPtr &cppClass);
+ static void writeSbkTypeFunction(TextStream &s, const AbstractMetaType &metaType);
+ void collectTypeEntryTypeIndexes(const ApiExtractorResult &api,
+ const TypeEntryCPtr &typeEntry,
+ IndexValues *indexValues);
+ void collectClassTypeIndexes(const ApiExtractorResult &api,
+ const AbstractMetaClassCPtr &metaClass,
+ IndexValues *indexValues);
+ static void writeProtectedEnumSurrogate(TextStream &s, const AbstractMetaEnum &cppEnum);
void writeMemberFunctionWrapper(TextStream &s,
const AbstractMetaFunctionCPtr &func,
const QString &postfix = {}) const;
void writePrivateHeader(const QString &moduleHeaderDir,
const QString &publicIncludeShield,
- const QSet<Include> &privateIncludes,
- const QString &privateTypeFunctions);
+ const ModuleHeaderParameters &parameters);
+ static void writeTypeFunctions(TextStream &s, const QString &typeFunctions);
+ void writeWrapperClassDeclaration(TextStream &s,
+ const QString &wrapperName,
+ const GeneratorContext &classContext) const;
+ void writeWrapperClass(TextStream &s, const QString &wrapperName, const GeneratorContext &classContext) const;
+ void writeInheritedWrapperClassDeclaration(TextStream &s,
+ const GeneratorContext &classContext) const;
+ void writeModuleCodeSnips(TextStream &s, const CodeSnipList &codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language) const;
- QSet<AbstractMetaFunctionCPtr> m_inheritedOverloads;
AbstractMetaClassCList m_alternateTemplateIndexes;
};
diff --git a/sources/shiboken6/generator/shiboken/overloaddata.cpp b/sources/shiboken6/generator/shiboken/overloaddata.cpp
index d30335a4a..c28fcdc1a 100644
--- a/sources/shiboken6/generator/shiboken/overloaddata.cpp
+++ b/sources/shiboken6/generator/shiboken/overloaddata.cpp
@@ -1,79 +1,52 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <abstractmetafunction.h>
#include <apiextractorresult.h>
#include <abstractmetalang.h>
+#include <dotview.h>
#include <reporthandler.h>
-#include <typesystem.h>
+#include <complextypeentry.h>
+#include <containertypeentry.h>
+#include <primitivetypeentry.h>
#include <graph.h>
#include "overloaddata.h"
+#include "messages.h"
#include "ctypenames.h"
#include "pytypenames.h"
#include "textstream.h"
+#include "exception.h"
+
+#include "qtcompat.h"
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QTemporaryFile>
#include <algorithm>
+#include <utility>
-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;
-}
+using namespace Qt::StringLiterals;
static QString getTypeName(const AbstractMetaType &type)
{
- const TypeEntry *typeEntry = getReferencedTypeEntry(type.typeEntry());
+ TypeEntryCPtr typeEntry = type.typeEntry();
+ if (typeEntry->isPrimitive())
+ typeEntry = basicReferencedTypeEntry(typeEntry);
QString typeName = typeEntry->name();
if (typeEntry->isContainer()) {
QStringList types;
for (const auto &cType : type.instantiations()) {
- const TypeEntry *typeEntry = getReferencedTypeEntry(cType.typeEntry());
+ TypeEntryCPtr typeEntry = cType.typeEntry();
+ if (typeEntry->isPrimitive())
+ typeEntry = basicReferencedTypeEntry(typeEntry);
types << typeEntry->name();
}
- typeName += QLatin1Char('<') + types.join(QLatin1Char(',')) + QLatin1String(" >");
+ typeName += u'<' + types.join(u',') + u" >"_s;
}
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()) {
@@ -81,7 +54,7 @@ static bool typesAreEqual(const AbstractMetaType &typeA, const AbstractMetaType
if (typeA.instantiations().size() != typeB.instantiations().size())
return false;
- for (int i = 0; i < typeA.instantiations().size(); ++i) {
+ for (qsizetype i = 0; i < typeA.instantiations().size(); ++i) {
if (!typesAreEqual(typeA.instantiations().at(i), typeB.instantiations().at(i)))
return false;
}
@@ -115,48 +88,23 @@ static QString getImplicitConversionTypeName(const AbstractMetaType &containerTy
for (const auto &otherType : containerType.instantiations())
types << (otherType == instantiation ? impConv : getTypeName(otherType));
- return containerType.typeEntry()->qualifiedCppName() + QLatin1Char('<')
- + types.join(QLatin1String(", ")) + QLatin1String(" >");
+ return containerType.typeEntry()->qualifiedCppName() + u'<'
+ + types.join(u", "_s) + u" >"_s;
}
-// overloaddata.cpp
-static QString msgCyclicDependency(const QString &funcName, const QString &graphName,
- const AbstractMetaFunctionCList &cyclic,
- const AbstractMetaFunctionCList &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)
- << "\". Cyclic functions:";
- for (const auto &c : cyclic)
- str << ' ' << c->signature();
- 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;
-}
-
-static inline int overloadNumber(const OverloadData *o)
+static inline int overloadNumber(const OverloadDataNodePtr &o)
{
return o->referenceFunction()->overloadNumber();
}
-bool OverloadData::sortByOverloadNumberModification()
+static bool sortByOverloadNumberModification(OverloadDataList &list)
{
- if (std::all_of(m_nextOverloadData.cbegin(), m_nextOverloadData.cend(),
- [](const OverloadData *o) { return overloadNumber(o) == TypeSystem::OverloadNumberDefault; })) {
+ if (std::all_of(list.cbegin(), list.cend(),
+ [](const OverloadDataNodePtr &o) { return overloadNumber(o) == TypeSystem::OverloadNumberDefault; })) {
return false;
}
- std::stable_sort(m_nextOverloadData.begin(), m_nextOverloadData.end(),
- [] (const OverloadData *o1, const OverloadData *o2) {
+ std::stable_sort(list.begin(), list.end(),
+ [] (const OverloadDataNodePtr &o1, const OverloadDataNodePtr &o2) {
return overloadNumber(o1) < overloadNumber(o2);
});
return true;
@@ -174,9 +122,10 @@ using OverloadGraph = Graph<QString>;
*
* Side effects: Modifies m_nextOverloadData
*/
-void OverloadData::sortNextOverloads()
+void OverloadDataRootNode::sortNextOverloads(const ApiExtractorResult &api)
{
QHash<QString, OverloadDataList> typeToOverloads;
+ using Edge = std::pair<QString, QString>;
bool checkPyObject = false;
bool checkPySequence = false;
@@ -186,16 +135,16 @@ void OverloadData::sortNextOverloads()
// Primitive types that are not int, long, short,
// char and their respective unsigned counterparts.
- static const QStringList nonIntegerPrimitives{floatT(), doubleT(), boolT()};
+ static const QStringList nonIntegerPrimitives{floatT, doubleT, boolT};
// Signed integer primitive types.
- static const QStringList signedIntegerPrimitives{intT(), shortT(), longT(), longLongT()};
+ static const QStringList signedIntegerPrimitives{intT, shortT, longT, longLongT};
// sort the children overloads
- for (OverloadData *ov : qAsConst(m_nextOverloadData))
- ov->sortNextOverloads();
+ for (const auto &ov : std::as_const(m_children))
+ ov->sortNextOverloads(api);
- if (m_nextOverloadData.size() <= 1 || sortByOverloadNumberModification())
+ if (m_children.size() <= 1 || sortByOverloadNumberModification(m_children))
return;
// Populates the OverloadSortData object containing map and reverseMap, to map type names to ids,
@@ -203,8 +152,8 @@ void OverloadData::sortNextOverloads()
// with graph sorting using integers.
OverloadGraph graph;
- for (OverloadData *ov : qAsConst(m_nextOverloadData)) {
- const QString typeName = getTypeName(ov);
+ for (const auto &ov : std::as_const(m_children)) {
+ const QString typeName = getTypeName(ov->modifiedArgType());
auto it = typeToOverloads.find(typeName);
if (it == typeToOverloads.end()) {
typeToOverloads.insert(typeName, {ov});
@@ -213,15 +162,15 @@ void OverloadData::sortNextOverloads()
it.value().append(ov);
}
- if (!checkPyObject && typeName == cPyObjectT())
+ if (!checkPyObject && typeName == cPyObjectT)
checkPyObject = true;
- else if (!checkPySequence && typeName == cPySequenceT())
+ else if (!checkPySequence && typeName == cPySequenceT)
checkPySequence = true;
- else if (!checkPyBuffer && typeName == cPyBufferT())
+ else if (!checkPyBuffer && typeName == cPyBufferT)
checkPyBuffer = true;
- else if (!checkQVariant && typeName == qVariantT())
+ else if (!checkQVariant && typeName == qVariantT)
checkQVariant = true;
- else if (!checkQString && typeName == qStringT())
+ else if (!checkQString && typeName == qStringT)
checkQString = true;
for (const auto &instantiation : ov->argType().instantiations()) {
@@ -234,10 +183,10 @@ void OverloadData::sortNextOverloads()
// 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))
+ for (const QString &primitive : std::as_const(nonIntegerPrimitives))
graph.addNode(getImplicitConversionTypeName(ov->argType(), instantiation, nullptr, primitive));
} else {
- const auto &funcs = m_api.implicitConversions(instantiation);
+ const auto &funcs = api.implicitConversions(instantiation);
for (const auto &function : funcs)
graph.addNode(getImplicitConversionTypeName(ov->argType(), instantiation, function));
}
@@ -247,9 +196,9 @@ void OverloadData::sortNextOverloads()
// Create the graph of type dependencies based on implicit conversions.
// All C++ primitive types, add any forgotten type AT THE END OF THIS LIST!
- static const QStringList primitiveTypes{intT(), unsignedIntT(), longT(), unsignedLongT(),
- shortT(), unsignedShortT(), boolT(), unsignedCharT(), charT(), floatT(),
- doubleT(), constCharPtrT()};
+ static const QStringList primitiveTypes{intT, unsignedIntT, longT, unsignedLongT,
+ shortT, unsignedShortT, boolT, unsignedCharT, charT, floatT,
+ doubleT, constCharPtrT};
QStringList foundPrimitiveTypeIds;
for (const auto &p : primitiveTypes) {
@@ -258,18 +207,18 @@ void OverloadData::sortNextOverloads()
}
if (checkPySequence && checkPyObject)
- graph.addEdge(cPySequenceT(), cPyObjectT());
+ graph.addEdge(cPySequenceT, cPyObjectT);
QStringList classesWithIntegerImplicitConversion;
AbstractMetaFunctionCList involvedConversions;
- for (OverloadData *ov : qAsConst(m_nextOverloadData)) {
+ for (const auto &ov : std::as_const(m_children)) {
const AbstractMetaType &targetType = ov->argType();
- const QString targetTypeEntryName = getTypeName(ov);
+ const QString targetTypeEntryName = getTypeName(ov->modifiedArgType());
// Process implicit conversions
- const auto &functions = m_api.implicitConversions(targetType);
+ const auto &functions = api.implicitConversions(targetType);
for (const auto &function : functions) {
QString convertibleType;
if (function->isConversionOperator())
@@ -277,7 +226,7 @@ void OverloadData::sortNextOverloads()
else
convertibleType = getTypeName(function->arguments().constFirst().type());
- if (convertibleType == intT() || convertibleType == unsignedIntT())
+ if (convertibleType == intT || convertibleType == unsignedIntT)
classesWithIntegerImplicitConversion << targetTypeEntryName;
if (!graph.hasNode(convertibleType))
@@ -292,10 +241,12 @@ void OverloadData::sortNextOverloads()
// Process inheritance relationships
if (targetType.isValue() || targetType.isObject()) {
- auto metaClass = AbstractMetaClass::findClass(m_api.classes(),
- targetType.typeEntry());
- const AbstractMetaClassList &ancestors = metaClass->allTypeSystemAncestors();
- for (const AbstractMetaClass *ancestor : ancestors) {
+ const auto te = targetType.typeEntry();
+ auto metaClass = AbstractMetaClass::findClass(api.classes(), te);
+ if (!metaClass)
+ throw Exception(msgArgumentClassNotFound(m_overloads.constFirst(), te));
+ const auto &ancestors = metaClass->allTypeSystemAncestors();
+ for (const auto &ancestor : ancestors) {
QString ancestorTypeName = ancestor->typeEntry()->name();
if (!graph.hasNode(ancestorTypeName))
continue;
@@ -312,7 +263,7 @@ void OverloadData::sortNextOverloads()
graph.addEdge(convertible, targetTypeEntryName);
if (instantiation.isPrimitive() && (signedIntegerPrimitives.contains(instantiation.name()))) {
- for (const QString &primitive : qAsConst(nonIntegerPrimitives)) {
+ for (const QString &primitive : std::as_const(nonIntegerPrimitives)) {
QString convertibleTypeName =
getImplicitConversionTypeName(ov->argType(), instantiation, nullptr, primitive);
// Avoid cyclic dependency.
@@ -321,7 +272,7 @@ void OverloadData::sortNextOverloads()
}
} else {
- const auto &funcs = m_api.implicitConversions(instantiation);
+ const auto &funcs = api.implicitConversions(instantiation);
for (const auto &function : funcs) {
QString convertibleTypeName =
getImplicitConversionTypeName(ov->argType(), instantiation, function);
@@ -337,28 +288,28 @@ void OverloadData::sortNextOverloads()
if ((checkPySequence || checkPyObject || checkPyBuffer)
- && !targetTypeEntryName.contains(cPyObjectT())
- && !targetTypeEntryName.contains(cPyBufferT())
- && !targetTypeEntryName.contains(cPySequenceT())) {
+ && !targetTypeEntryName.contains(cPyObjectT)
+ && !targetTypeEntryName.contains(cPyBufferT)
+ && !targetTypeEntryName.contains(cPySequenceT)) {
if (checkPySequence) {
// PySequence will be checked after all more specific types, but before PyObject.
- graph.addEdge(targetTypeEntryName, cPySequenceT());
+ graph.addEdge(targetTypeEntryName, cPySequenceT);
} else if (checkPyBuffer) {
// PySequence will be checked after all more specific types, but before PyObject.
- graph.addEdge(targetTypeEntryName, cPyBufferT());
+ graph.addEdge(targetTypeEntryName, cPyBufferT);
} else {
// Add dependency on PyObject, so its check is the last one (too generic).
- graph.addEdge(targetTypeEntryName, cPyObjectT());
+ graph.addEdge(targetTypeEntryName, cPyObjectT);
}
- } else if (checkQVariant && targetTypeEntryName != qVariantT()) {
- if (!graph.containsEdge(qVariantT(), targetTypeEntryName)) // Avoid cyclic dependency.
- graph.addEdge(targetTypeEntryName, qVariantT());
+ } else if (checkQVariant && targetTypeEntryName != qVariantT) {
+ if (!graph.containsEdge(qVariantT, targetTypeEntryName)) // Avoid cyclic dependency.
+ graph.addEdge(targetTypeEntryName, qVariantT);
} else if (checkQString && ov->argType().isPointer()
- && targetTypeEntryName != qStringT()
- && targetTypeEntryName != qByteArrayT()
- && (!checkPyObject || targetTypeEntryName != cPyObjectT())) {
- if (!graph.containsEdge(qStringT(), targetTypeEntryName)) // Avoid cyclic dependency.
- graph.addEdge(targetTypeEntryName, qStringT());
+ && targetTypeEntryName != qStringT
+ && targetTypeEntryName != qByteArrayT
+ && (!checkPyObject || targetTypeEntryName != cPyObjectT)) {
+ if (!graph.containsEdge(qStringT, targetTypeEntryName)) // Avoid cyclic dependency.
+ graph.addEdge(targetTypeEntryName, qStringT);
}
if (targetType.isEnum()) {
@@ -369,25 +320,36 @@ void OverloadData::sortNextOverloads()
}
// QByteArray args need to be checked after QString args
- if (graph.hasNode(qStringT()) && graph.hasNode(qByteArrayT()))
- graph.addEdge(qStringT(), qByteArrayT());
+ if (graph.hasNode(qStringT) && graph.hasNode(qByteArrayT))
+ graph.addEdge(qStringT, qByteArrayT);
+
+ static const Edge rangeOrder[] =
+ {{doubleT, floatT},
+ {longLongT, longT}, {longLongT, intT}, {intT, shortT},
+ {unsignedLongLongT, unsignedLongT}, {unsignedLongLongT, unsignedT},
+ {unsignedLongLongT, unsignedIntT}, {unsignedT, unsignedShortT}
+ };
+ for (const auto &r : rangeOrder) {
+ if (graph.hasNode(r.first) && graph.hasNode(r.second))
+ graph.addEdge(r.first, r.second);
+ }
- for (OverloadData *ov : qAsConst(m_nextOverloadData)) {
+ for (const auto &ov : std::as_const(m_children)) {
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))
+ for (const QString &implicitFromInt : std::as_const(classesWithIntegerImplicitConversion))
graph.addEdge(targetTypeEntryName, implicitFromInt);
}
// Special case for double(int i) (not tracked by m_generator->implicitConversions
- for (const QString &signedIntegerName : qAsConst(signedIntegerPrimitives)) {
+ for (const QString &signedIntegerName : std::as_const(signedIntegerPrimitives)) {
if (graph.hasNode(signedIntegerName)) {
- for (const QString &nonIntegerName : qAsConst(nonIntegerPrimitives)) {
+ for (const QString &nonIntegerName : std::as_const(nonIntegerPrimitives)) {
if (graph.hasNode(nonIntegerName))
graph.addEdge(nonIntegerName, signedIntegerName);
}
@@ -398,11 +360,11 @@ void OverloadData::sortNextOverloads()
const auto unmappedResult = graph.topologicalSort();
if (!unmappedResult.isValid()) {
QString funcName = referenceFunction()->name();
- if (referenceFunction()->ownerClass())
- funcName.prepend(referenceFunction()->ownerClass()->name() + QLatin1Char('.'));
+ if (auto owner = referenceFunction()->ownerClass())
+ funcName.prepend(owner->name() + u'.');
// Dump overload graph
- QString graphName = QDir::tempPath() + QLatin1Char('/') + funcName + QLatin1String(".dot");
+ QString graphName = QDir::tempPath() + u'/' + funcName + u".dot"_s;
graph.dumpDot(graphName, [] (const QString &n) { return n; });
AbstractMetaFunctionCList cyclic;
for (const auto &typeName : unmappedResult.cyclic) {
@@ -413,21 +375,45 @@ void OverloadData::sortNextOverloads()
qCWarning(lcShiboken, "%s", qPrintable(msgCyclicDependency(funcName, graphName, cyclic, involvedConversions)));
}
- m_nextOverloadData.clear();
+ m_children.clear();
for (const auto &typeName : unmappedResult.result) {
const auto oit = typeToOverloads.constFind(typeName);
if (oit != typeToOverloads.cend()) {
std::copy(oit.value().crbegin(), oit.value().crend(),
- std::back_inserter(m_nextOverloadData));
+ std::back_inserter(m_children));
+ }
+ }
+}
+
+// Determine the minimum (first default argument)/maximum arguments (size)
+// of a function (taking into account the removed arguments).
+static std::pair<int, int> getMinMaxArgs(const AbstractMetaFunctionCPtr &func)
+{
+ int defaultValueIndex = -1;
+ const auto &arguments = func->arguments();
+ int argIndex = 0;
+ for (const auto &arg : arguments) {
+ if (!arg.isModifiedRemoved()) {
+ if (defaultValueIndex < 0 && arg.hasDefaultValueExpression())
+ defaultValueIndex = argIndex;
+ ++argIndex;
}
}
+ const int maxArgs = argIndex;
+ const int minArgs = defaultValueIndex >= 0 ? defaultValueIndex : maxArgs;
+ return {minArgs, maxArgs};
+}
+
+const OverloadDataRootNode *OverloadDataNode::parent() const
+{
+ return m_parent;
}
/**
* 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
+ * the graph of OverloadData instances. Each OverloadDataNode instance references an argument/type
* combination.
*
* Example:
@@ -441,86 +427,58 @@ void OverloadData::sortNextOverloads()
*
*/
OverloadData::OverloadData(const AbstractMetaFunctionCList &overloads,
- const ApiExtractorResult &api)
- : m_minArgs(256), m_maxArgs(0), m_argPos(-1), m_argType(nullptr),
- m_headOverloadData(this), m_previousOverloadData(nullptr),
- m_api(api)
+ const ApiExtractorResult &api) :
+ OverloadDataRootNode(overloads)
{
for (const auto &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 auto minMaxArgs = getMinMaxArgs(func);
+ if (minMaxArgs.first < m_minArgs)
+ m_minArgs = minMaxArgs.first;
+ if (minMaxArgs.second > m_maxArgs)
+ m_maxArgs = minMaxArgs.second;
+ OverloadDataRootNode *currentOverloadData = this;
const AbstractMetaArgumentList &arguments = func->arguments();
for (const AbstractMetaArgument &arg : arguments) {
- if (func->argumentRemoved(arg.argumentIndex() + 1))
- continue;
- currentOverloadData = currentOverloadData->addOverloadData(func, arg);
+ if (!arg.isModifiedRemoved())
+ currentOverloadData = currentOverloadData->addOverloadDataNode(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();
+ sortNextOverloads(api);
}
-OverloadData::OverloadData(OverloadData *headOverloadData, const AbstractMetaFunctionCPtr &func,
- const AbstractMetaType &argType, int argPos,
- const ApiExtractorResult &api) :
- m_minArgs(256), m_maxArgs(0), m_argPos(argPos), m_argType(argType),
- m_headOverloadData(headOverloadData), m_previousOverloadData(nullptr), m_api(api)
+OverloadDataNode::OverloadDataNode(const AbstractMetaFunctionCPtr &func,
+ OverloadDataRootNode *parent,
+ const AbstractMetaArgument &argument,
+ int argPos,
+ const QString argTypeReplaced) :
+ m_argument(argument),
+ m_argTypeReplaced(argTypeReplaced),
+ m_parent(parent),
+ m_argPos(argPos)
{
if (func)
this->addOverload(func);
}
-void OverloadData::addOverload(const AbstractMetaFunctionCPtr &func)
+void OverloadDataNode::addOverload(const AbstractMetaFunctionCPtr &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 AbstractMetaFunctionCPtr &func,
- const AbstractMetaArgument &arg)
+OverloadDataNode *OverloadDataRootNode::addOverloadDataNode(const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgument &arg)
{
- const AbstractMetaType &argType = arg.type();
- OverloadData *overloadData = nullptr;
+ OverloadDataNodePtr overloadData;
if (!func->isOperatorOverload()) {
- for (OverloadData *tmp : qAsConst(m_nextOverloadData)) {
+ for (const auto &tmp : std::as_const(m_children)) {
// 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())) {
+ if (typesAreEqual(tmp->modifiedArgType(), arg.modifiedType())) {
tmp->addOverload(func);
overloadData = tmp;
}
@@ -528,34 +486,26 @@ OverloadData *OverloadData::addOverloadData(const AbstractMetaFunctionCPtr &func
}
if (!overloadData) {
- overloadData = new OverloadData(m_headOverloadData, func, argType, m_argPos + 1, m_api);
- overloadData->m_previousOverloadData = this;
- QString typeReplaced = func->typeReplaced(arg.argumentIndex() + 1);
-
- if (!typeReplaced.isEmpty())
- overloadData->m_argTypeReplaced = typeReplaced;
- m_nextOverloadData.append(overloadData);
+ const int argpos = argPos() + 1;
+ overloadData.reset(new OverloadDataNode(func, this, arg, argpos));
+ m_children.append(overloadData);
}
- return overloadData;
+ return overloadData.get();
}
-QStringList OverloadData::returnTypes() const
+bool OverloadData::hasNonVoidReturnType() const
{
- QSet<QString> retTypes;
for (const auto &func : m_overloads) {
- if (!func->typeReplaced(0).isEmpty())
- retTypes << func->typeReplaced(0);
- else if (!func->argumentRemoved(0))
- retTypes << func->type().cppSignature();
+ if (func->isTypeModified()) {
+ if (func->modifiedTypeName() != u"void")
+ return true;
+ } else {
+ if (!func->argumentRemoved(0) && !func->type().isVoid())
+ return true;
+ }
}
- return retTypes.values();
-}
-
-bool OverloadData::hasNonVoidReturnType() const
-{
- QStringList retTypes = returnTypes();
- return !retTypes.contains(QLatin1String("void")) || retTypes.size() > 1;
+ return false;
}
bool OverloadData::hasVarargs() const
@@ -568,28 +518,37 @@ bool OverloadData::hasVarargs() const
return false;
}
-bool OverloadData::hasAllowThread() const
+bool OverloadData::hasStaticFunction(const AbstractMetaFunctionCList &overloads)
+{
+ for (const auto &func : overloads) {
+ if (func->isStatic())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasStaticFunction() const
{
for (const auto &func : m_overloads) {
- if (func->allowThread())
+ if (func->isStatic())
return true;
}
return false;
}
-bool OverloadData::hasStaticFunction(const AbstractMetaFunctionCList &overloads)
+bool OverloadData::hasClassMethod(const AbstractMetaFunctionCList &overloads)
{
for (const auto &func : overloads) {
- if (func->isStatic())
+ if (func->isClassMethod())
return true;
}
return false;
}
-bool OverloadData::hasStaticFunction() const
+bool OverloadData::hasClassMethod() const
{
for (const auto &func : m_overloads) {
- if (func->isStatic())
+ if (func->isClassMethod())
return true;
}
return false;
@@ -623,20 +582,27 @@ bool OverloadData::hasStaticAndInstanceFunctions() const
return OverloadData::hasStaticFunction() && OverloadData::hasInstanceFunction();
}
-AbstractMetaFunctionCPtr OverloadData::referenceFunction() const
+OverloadDataRootNode::OverloadDataRootNode(const AbstractMetaFunctionCList &o) :
+ m_overloads(o)
+{
+}
+
+OverloadDataRootNode::~OverloadDataRootNode() = default;
+
+AbstractMetaFunctionCPtr OverloadDataRootNode::referenceFunction() const
{
return m_overloads.constFirst();
}
-const AbstractMetaArgument *OverloadData::argument(const AbstractMetaFunctionCPtr &func) const
+const AbstractMetaArgument *OverloadDataNode::overloadArgument(const AbstractMetaFunctionCPtr &func) const
{
- if (isHeadOverloadData() || !m_overloads.contains(func))
+ if (isRoot() || !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))
+ if (func->arguments().at(i).isModifiedRemoved())
removed++;
else
argPos++;
@@ -645,89 +611,54 @@ const AbstractMetaArgument *OverloadData::argument(const AbstractMetaFunctionCPt
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
+bool OverloadDataRootNode::nextArgumentHasDefaultValue() const
{
- OverloadDataList overloadDataList;
- overloadDataList += overloadDataOnPosition(m_headOverloadData, argPos);
- return overloadDataList;
-}
-
-bool OverloadData::nextArgumentHasDefaultValue() const
-{
- for (OverloadData *overloadData : m_nextOverloadData) {
- if (!overloadData->getFunctionWithDefaultValue().isNull())
+ for (const auto &overloadData : m_children) {
+ if (overloadData->getFunctionWithDefaultValue())
return true;
}
return false;
}
-static OverloadData *_findNextArgWithDefault(OverloadData *overloadData)
+static const OverloadDataRootNode *_findNextArgWithDefault(const OverloadDataRootNode *overloadData)
{
- if (!overloadData->getFunctionWithDefaultValue().isNull())
+ if (overloadData->getFunctionWithDefaultValue())
return overloadData;
- OverloadData *result = nullptr;
- const OverloadDataList &data = overloadData->nextOverloadData();
- for (OverloadData *odata : data) {
- OverloadData *tmp = _findNextArgWithDefault(odata);
+ const OverloadDataRootNode *result = nullptr;
+ const OverloadDataList &data = overloadData->children();
+ for (const auto &odata : data) {
+ const auto *tmp = _findNextArgWithDefault(odata.get());
if (!result || (tmp && result->argPos() > tmp->argPos()))
result = tmp;
}
return result;
}
-OverloadData *OverloadData::findNextArgWithDefault()
+const OverloadDataRootNode *OverloadDataRootNode::findNextArgWithDefault() const
{
return _findNextArgWithDefault(this);
}
-bool OverloadData::isFinalOccurrence(const AbstractMetaFunctionCPtr &func) const
+bool OverloadDataRootNode::isFinalOccurrence(const AbstractMetaFunctionCPtr &func) const
{
- for (const OverloadData *pd : m_nextOverloadData) {
+ for (const auto &pd : m_children) {
if (pd->overloads().contains(func))
return false;
}
return true;
}
-AbstractMetaFunctionCList OverloadData::overloadsWithoutRepetition() const
-{
- AbstractMetaFunctionCList overloads = m_overloads;
- for (const auto &func : m_overloads) {
- if (func->minimalSignature().endsWith(QLatin1String("const")))
- continue;
- for (const auto &f : qAsConst(overloads)) {
- if ((func->minimalSignature() + QLatin1String("const")) == f->minimalSignature()) {
- overloads.removeOne(f);
- break;
- }
- }
- }
- return overloads;
-}
-
-AbstractMetaFunctionCPtr OverloadData::getFunctionWithDefaultValue() const
+AbstractMetaFunctionCPtr OverloadDataRootNode::getFunctionWithDefaultValue() const
{
+ const qsizetype argpos = argPos();
for (const auto &func : m_overloads) {
- int removedArgs = 0;
- for (int i = 0; i <= m_argPos + removedArgs; i++) {
- if (func->argumentRemoved(i + 1))
+ qsizetype removedArgs = 0;
+ for (qsizetype i = 0; i <= argpos + removedArgs; i++) {
+ if (func->arguments().at(i).isModifiedRemoved())
removedArgs++;
}
- if (func->arguments().at(m_argPos + removedArgs).hasDefaultValueExpression())
+ if (func->arguments().at(argpos + removedArgs).hasDefaultValueExpression())
return func;
}
return {};
@@ -737,11 +668,11 @@ QList<int> OverloadData::invalidArgumentLengths() const
{
QSet<int> validArgLengths;
- for (const auto &func : qAsConst(m_headOverloadData->m_overloads)) {
+ for (const auto &func : m_overloads) {
const AbstractMetaArgumentList args = func->arguments();
int offset = 0;
- for (int i = 0; i < args.size(); ++i) {
- if (func->argumentRemoved(i+1)) {
+ for (qsizetype i = 0; i < args.size(); ++i) {
+ if (func->arguments().at(i).isModifiedRemoved()) {
offset++;
} else {
if (args.at(i).hasDefaultValueExpression())
@@ -752,7 +683,7 @@ QList<int> OverloadData::invalidArgumentLengths() const
}
QList<int> invalidArgLengths;
- for (int i = minArgs() + 1; i < maxArgs(); i++) {
+ for (int i = m_minArgs + 1; i < m_maxArgs; i++) {
if (!validArgLengths.contains(i))
invalidArgLengths.append(i);
}
@@ -760,196 +691,204 @@ QList<int> OverloadData::invalidArgumentLengths() const
return invalidArgLengths;
}
-int OverloadData::numberOfRemovedArguments(const AbstractMetaFunctionCPtr &func, int finalArgPos)
+int OverloadData::numberOfRemovedArguments(const AbstractMetaFunctionCPtr &func)
{
- 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;
+ return std::count_if(func->arguments().cbegin(), func->arguments().cend(),
+ [](const AbstractMetaArgument &a) { return a.isModifiedRemoved(); });
}
-bool OverloadData::isSingleArgument(const AbstractMetaFunctionCList &overloads)
+int OverloadData::numberOfRemovedArguments(const AbstractMetaFunctionCPtr &func, int finalArgPos)
{
- bool singleArgument = true;
- for (const auto &func : overloads) {
- if (func->arguments().size() - numberOfRemovedArguments(func) != 1) {
- singleArgument = false;
- break;
- }
+ Q_ASSERT(finalArgPos >= 0);
+ int removed = 0;
+ const auto size = func->arguments().size();
+ for (qsizetype i = 0; i < qMin(size, qsizetype(finalArgPos + removed)); ++i) {
+ if (func->arguments().at(i).isModifiedRemoved())
+ ++removed;
}
- return singleArgument;
+ return removed;
}
void OverloadData::dumpGraph(const QString &filename) const
{
QFile file(filename);
if (file.open(QFile::WriteOnly)) {
- TextStream s(&file);
- s << m_headOverloadData->dumpGraph();
+ QTextStream s(&file);
+ dumpRootGraph(s, m_minArgs, m_maxArgs);
}
}
+QString OverloadData::dumpGraph() const
+{
+ QString result;
+ QTextStream s(&result);
+ dumpRootGraph(s, m_minArgs, m_maxArgs);
+ return result;
+}
+
+bool OverloadData::showGraph() const
+{
+ return showDotGraph(referenceFunction()->name(), dumpGraph());
+}
+
static inline QString toHtml(QString s)
{
- s.replace(QLatin1Char('<'), QLatin1String("&lt;"));
- s.replace(QLatin1Char('>'), QLatin1String("&gt;"));
- s.replace(QLatin1Char('&'), QLatin1String("&amp;"));
+ s.replace(u'<', u"&lt;"_s);
+ s.replace(u'>', u"&gt;"_s);
+ s.replace(u'&', u"&amp;"_s);
return s;
}
-QString OverloadData::dumpGraph() const
+void OverloadDataRootNode::dumpRootGraph(QTextStream &s, int minArgs, int maxArgs) const
{
- QString result;
- QTextStream s(&result);
- if (m_argPos == -1) {
- const auto rfunc = referenceFunction();
- s << "digraph OverloadedFunction {\n";
- s << " 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 auto &func : m_overloads) {
- s << "f" << functionNumber(func) << " : "
- << toHtml(func->type().cppSignature())
- << ' ' << toHtml(func->minimalSignature()) << "\\l";
- }
- s << "\"];\n";
-
- // Function box title
- s << " \"" << rfunc->name() << "\" [shape=plaintext style=\"filled,bold\" margin=0 fontname=freemono fillcolor=white penwidth=1 ";
- s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">";
- s << "<tr><td bgcolor=\"black\" align=\"center\" cellpadding=\"6\" colspan=\"2\"><font color=\"white\">";
- if (rfunc->ownerClass())
- s << rfunc->ownerClass()->name() << "::";
- s << toHtml(rfunc->name()) << "</font>";
- if (rfunc->isVirtual()) {
- s << "<br/><font color=\"white\" point-size=\"10\">&lt;&lt;";
- if (rfunc->isAbstract())
- s << "pure ";
- s << "virtual&gt;&gt;</font>";
- }
- s << "</td></tr>";
+ const auto rfunc = referenceFunction();
+ s << "digraph OverloadedFunction {\n";
+ s << " graph [fontsize=12 fontname=freemono labelloc=t splines=true overlap=false rankdir=LR];\n";
- // Function return type
- s << "<tr><td bgcolor=\"gray\" align=\"right\">original type</td><td bgcolor=\"gray\" align=\"left\">"
- << toHtml(rfunc->type().cppSignature())
- << "</td></tr>";
+ // Shows all function signatures
+ s << "legend [fontsize=9 fontname=freemono shape=rect label=\"";
+ for (const auto &func : m_overloads) {
+ s << "f" << functionNumber(func) << " : "
+ << toHtml(func->type().cppSignature())
+ << ' ' << toHtml(func->minimalSignature()) << "\\l";
+ }
+ s << "\"];\n";
+
+ // Function box title
+ s << " \"" << rfunc->name() << "\" [shape=plaintext style=\"filled,bold\" margin=0 fontname=freemono fillcolor=white penwidth=1 ";
+ s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">";
+ s << "<tr><td bgcolor=\"black\" align=\"center\" cellpadding=\"6\" colspan=\"2\"><font color=\"white\">";
+ if (rfunc->ownerClass())
+ s << rfunc->ownerClass()->name() << "::";
+ s << toHtml(rfunc->name()) << "</font>";
+ if (rfunc->isVirtual()) {
+ s << "<br/><font color=\"white\" point-size=\"10\">&lt;&lt;";
+ if (rfunc->isAbstract())
+ s << "pure ";
+ s << "virtual&gt;&gt;</font>";
+ }
+ s << "</td></tr>";
+
+ // Function return type
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">original type</td><td bgcolor=\"gray\" align=\"left\">"
+ << toHtml(rfunc->type().cppSignature())
+ << "</td></tr>";
+
+ // Shows type changes for all function signatures
+ for (const auto &func : m_overloads) {
+ if (!func->isTypeModified())
+ continue;
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func);
+ s << "-type</td><td bgcolor=\"gray\" align=\"left\">";
+ s << toHtml(func->modifiedTypeName()) << "</td></tr>";
+ }
- // Shows type changes for all function signatures
- for (const auto &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>";
- // 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>";
- }
+ 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 auto &func : m_overloads)
- s << 'f' << functionNumber(func) << ' ';
- s << "</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 auto &func : m_overloads)
+ s << 'f' << functionNumber(func) << ' ';
+ s << "</td></tr>";
- s << "</table>> ];\n";
+ s << "</table>> ];\n";
- for (const OverloadData *pd : m_nextOverloadData)
- s << " \"" << rfunc->name() << "\" -> " << pd->dumpGraph();
+ for (const auto &pd : m_children) {
+ s << " \"" << rfunc->name() << "\" -> ";
+ pd->dumpNodeGraph(s);
+ }
- s << "}\n";
- } else {
- QString argId = QLatin1String("arg_") + QString::number(quintptr(this));
- s << argId << ";\n";
+ s << "}\n";
+}
- s << " \"" << 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\">";
+void OverloadDataNode::dumpNodeGraph(QTextStream &s) const
+{
+ QString argId = u"arg_"_s + QString::number(quintptr(this));
+ s << argId << ";\n";
- // 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>";
+ s << " \"" << 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 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>";
- }
+ // 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>";
- // Overloads for the signature to present point
- s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">";
- for (const auto &func : m_overloads)
- s << 'f' << functionNumber(func) << ' ';
- s << "</td></tr>";
+ // Argument type information
+ const QString type = modifiedArgType().cppSignature();
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">type</td><td bgcolor=\"gray\" align=\"left\">";
+ s << toHtml(type) << "</td></tr>";
+ if (isTypeModified()) {
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">orig. type</td><td bgcolor=\"gray\" align=\"left\">";
+ s << toHtml(argType().cppSignature()) << "</td></tr>";
+ }
- // Show default values (original and modified) for various functions
- for (const auto &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>";
- }
- }
+ const OverloadDataRootNode *root = this;
+ while (!root->isRoot())
+ root = root->parent();
- s << "</table>>];\n";
+ // Overloads for the signature to present point
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">";
+ for (const auto &func : m_overloads)
+ s << 'f' << root->functionNumber(func) << ' ';
+ s << "</td></tr>";
- for (const OverloadData *pd : m_nextOverloadData)
- s << " " << argId << " -> " << pd->dumpGraph();
+ // Show default values (original and modified) for various functions
+ for (const auto &func : m_overloads) {
+ const AbstractMetaArgument *arg = overloadArgument(func);
+ if (!arg)
+ continue;
+ const int n = root->functionNumber(func);
+ QString argDefault = arg->defaultValueExpression();
+ if (!argDefault.isEmpty() ||
+ argDefault != arg->originalDefaultValueExpression()) {
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << n;
+ s << "-default</td><td bgcolor=\"gray\" align=\"left\">";
+ s << argDefault << "</td></tr>";
+ }
+ if (argDefault != arg->originalDefaultValueExpression()) {
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << n;
+ s << "-orig-default</td><td bgcolor=\"gray\" align=\"left\">";
+ s << arg->originalDefaultValueExpression() << "</td></tr>";
+ }
}
- return result;
-}
-int OverloadData::functionNumber(const AbstractMetaFunctionCPtr &func) const
-{
- return m_headOverloadData->m_overloads.indexOf(func);
-}
+ s << "</table>>];\n";
-OverloadData::~OverloadData()
-{
- while (!m_nextOverloadData.isEmpty())
- delete m_nextOverloadData.takeLast();
+ for (const auto &pd : m_children) {
+ s << " " << argId << " -> ";
+ pd->dumpNodeGraph(s);
+ }
}
-bool OverloadData::hasArgumentTypeReplace() const
+int OverloadDataRootNode::functionNumber(const AbstractMetaFunctionCPtr &func) const
{
- return !m_argTypeReplaced.isEmpty();
+ return m_overloads.indexOf(func);
}
-QString OverloadData::argumentTypeReplaced() const
+bool OverloadData::pythonFunctionWrapperUsesListOfArguments() const
{
- return m_argTypeReplaced;
+ auto referenceFunction = m_overloads.constFirst();
+ if (referenceFunction->isCallOperator())
+ return true;
+ if (referenceFunction->isOperatorOverload())
+ return false;
+ const int maxArgs = this->maxArgs();
+ const int minArgs = this->minArgs();
+ return (minArgs != maxArgs)
+ || (maxArgs > 1)
+ || referenceFunction->isConstructor()
+ || hasArgumentWithDefaultValue();
}
bool OverloadData::hasArgumentWithDefaultValue() const
@@ -967,9 +906,7 @@ bool OverloadData::hasArgumentWithDefaultValue(const AbstractMetaFunctionCPtr &f
{
const AbstractMetaArgumentList &arguments = func->arguments();
for (const AbstractMetaArgument &arg : arguments) {
- if (func->argumentRemoved(arg.argumentIndex() + 1))
- continue;
- if (arg.hasDefaultValueExpression())
+ if (!arg.isModifiedRemoved() && arg.hasDefaultValueExpression())
return true;
}
return false;
@@ -981,7 +918,7 @@ AbstractMetaArgumentList OverloadData::getArgumentsWithDefaultValues(const Abstr
const AbstractMetaArgumentList &arguments = func->arguments();
for (const AbstractMetaArgument &arg : arguments) {
if (!arg.hasDefaultValueExpression()
- || func->argumentRemoved(arg.argumentIndex() + 1))
+ || arg.isModifiedRemoved())
continue;
args << arg;
}
@@ -989,9 +926,9 @@ AbstractMetaArgumentList OverloadData::getArgumentsWithDefaultValues(const Abstr
}
#ifndef QT_NO_DEBUG_STREAM
-void OverloadData::formatDebug(QDebug &d) const
+
+void OverloadDataRootNode::formatReferenceFunction(QDebug &d) const
{
- const qsizetype count = m_overloads.size();
auto refFunc = referenceFunction();
d << '"';
if (auto owner = refFunc->ownerClass())
@@ -999,36 +936,76 @@ void OverloadData::formatDebug(QDebug &d) const
d << refFunc->minimalSignature() << '"';
if (m_overloads.constFirst()->isReverseOperator())
d << " [reverseop]";
- d << ", argType=" << m_argType << ", minArgs=" << m_minArgs << ", maxArgs=" << m_maxArgs
- << ", argPos=" << m_argPos;
- if (!m_argTypeReplaced.isEmpty())
- d << ", argTypeReplaced=\"" << m_argTypeReplaced << '"';
+}
+void OverloadDataRootNode::formatOverloads(QDebug &d) const
+{
+ const qsizetype count = m_overloads.size();
+ d << ", overloads[" << count << ']';
if (count < 2)
return;
- d << "\", 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.setVerbosity(oldVerbosity);
- d << ')';
+ d << "=(";
+ for (qsizetype i = 0; i < count; ++i) {
+ if (i)
+ d << '\n';
+ d << m_overloads.at(i)->signature();
+ }
+ d << ')';
}
-QDebug operator<<(QDebug d, const OverloadData *od)
+void OverloadDataRootNode::formatNextOverloadData(QDebug &d) const
+{
+ const qsizetype count = m_children.size();
+ d << ", next[" << count << ']';
+ if (d.verbosity() >= 3) {
+ d << "=(";
+ for (qsizetype i = 0; i < count; ++i) {
+ if (i)
+ d << '\n';
+ m_children.at(i)->formatDebug(d);
+ }
+ d << ')';
+ }
+}
+
+void OverloadDataRootNode::formatDebug(QDebug &d) const
+{
+ formatReferenceFunction(d);
+ formatOverloads(d);
+ formatNextOverloadData(d);
+}
+
+void OverloadDataNode::formatDebug(QDebug &d) const
+{
+ d << "OverloadDataNode(";
+ formatReferenceFunction(d);
+ d << ", argPos=" << m_argPos;
+ if (m_argument.argumentIndex() != m_argPos)
+ d << ", argIndex=" << m_argument.argumentIndex();
+ d << ", argType=\"" << m_argument.type().cppSignature() << '"';
+ if (isTypeModified())
+ d << ", modifiedArgType=\"" << modifiedArgType().cppSignature() << '"';
+ formatOverloads(d);
+ formatNextOverloadData(d);
+ d << ')';
+}
+
+void OverloadData::formatDebug(QDebug &d) const
+{
+ d << "OverloadData(";
+ formatReferenceFunction(d);
+ d << ", minArgs=" << m_minArgs << ", maxArgs=" << m_maxArgs;
+ formatOverloads(d);
+ formatNextOverloadData(d);
+ d << ')';
+}
+
+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 << ')';
+ od.formatDebug(d);
return d;
}
#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken6/generator/shiboken/overloaddata.h b/sources/shiboken6/generator/shiboken/overloaddata.h
index ecd7a5596..875a5a8b5 100644
--- a/sources/shiboken6/generator/shiboken/overloaddata.h
+++ b/sources/shiboken6/generator/shiboken/overloaddata.h
@@ -1,59 +1,123 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef OVERLOADDATA_H
#define OVERLOADDATA_H
#include <apiextractorresult.h>
+#include <abstractmetaargument.h>
#include <QtCore/QBitArray>
#include <QtCore/QList>
+#include <memory>
+
QT_FORWARD_DECLARE_CLASS(QDebug)
+QT_FORWARD_DECLARE_CLASS(QTextStream)
-class OverloadData;
-using OverloadDataList = QList<OverloadData *>;
+class OverloadDataNode;
+using OverloadDataNodePtr = std::shared_ptr<OverloadDataNode>;
+using OverloadDataList = QList<OverloadDataNodePtr>;
-class OverloadData
+/// The root node of OverloadData. It contains all functions
+class OverloadDataRootNode
{
public:
- OverloadData(const AbstractMetaFunctionCList &overloads,
- const ApiExtractorResult &api);
- ~OverloadData();
+ virtual ~OverloadDataRootNode();
+
+ OverloadDataRootNode(const OverloadDataRootNode &) = delete;
+ OverloadDataRootNode &operator=(const OverloadDataRootNode &) = delete;
+ OverloadDataRootNode(OverloadDataRootNode &&) = delete;
+ OverloadDataRootNode &operator=(OverloadDataRootNode &&) = delete;
+
+ virtual int argPos() const { return -1; }
+ virtual const OverloadDataRootNode *parent() const { return nullptr; }
+
+ bool isRoot() const { return parent() == nullptr; }
+
+ AbstractMetaFunctionCPtr referenceFunction() const;
- int minArgs() const { return m_headOverloadData->m_minArgs; }
- int maxArgs() const { return m_headOverloadData->m_maxArgs; }
- int argPos() const { return m_argPos; }
+ const AbstractMetaFunctionCList &overloads() const { return m_overloads; }
+ const OverloadDataList &children() const { return m_children; }
- const AbstractMetaType &argType() const { return m_argType; }
+ bool nextArgumentHasDefaultValue() const;
+
+ /// Returns the function that has a default value at the current OverloadData argument position, otherwise returns null.
+ AbstractMetaFunctionCPtr getFunctionWithDefaultValue() const;
+
+ /// Returns the nearest occurrence, including this instance, of an argument with a default value.
+ const OverloadDataRootNode *findNextArgWithDefault() const;
+ bool isFinalOccurrence(const AbstractMetaFunctionCPtr &func) const;
+
+ int functionNumber(const AbstractMetaFunctionCPtr &func) const;
+
+#ifndef QT_NO_DEBUG_STREAM
+ virtual void formatDebug(QDebug &d) const;
+#endif
- /// Returns a string list containing all the possible return types (including void) for the current OverloadData.
- QStringList returnTypes() const;
+ OverloadDataNode *addOverloadDataNode(const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgument &arg);
+
+protected:
+ OverloadDataRootNode(const AbstractMetaFunctionCList &o= {});
+
+ void dumpRootGraph(QTextStream &s, int minArgs, int maxArgs) const;
+ void sortNextOverloads(const ApiExtractorResult &api);
+
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatReferenceFunction(QDebug &d) const;
+ void formatOverloads(QDebug &d) const;
+ void formatNextOverloadData(QDebug &d) const;
+#endif
+
+ AbstractMetaFunctionCList m_overloads;
+ OverloadDataList m_children;
+};
+
+/// OverloadDataNode references an argument/type combination.
+class OverloadDataNode : public OverloadDataRootNode
+{
+public:
+ explicit OverloadDataNode(const AbstractMetaFunctionCPtr &func,
+ OverloadDataRootNode *parent,
+ const AbstractMetaArgument &arg, int argPos,
+ const QString argTypeReplaced = {});
+ void addOverload(const AbstractMetaFunctionCPtr &func);
+
+ int argPos() const override { return m_argPos; }
+ const OverloadDataRootNode *parent() const override;
+ void dumpNodeGraph(QTextStream &s) const;
+
+ const AbstractMetaArgument &argument() const
+ { return m_argument; }
+ const AbstractMetaType &argType() const { return m_argument.type(); }
+ const AbstractMetaType &modifiedArgType() const { return m_argument.modifiedType(); }
+
+ bool isTypeModified() const { return m_argument.isTypeModified(); }
+
+ const AbstractMetaArgument *overloadArgument(const AbstractMetaFunctionCPtr &func) const;
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ AbstractMetaArgument m_argument;
+ QString m_argTypeReplaced;
+ OverloadDataRootNode *m_parent = nullptr;
+
+ int m_argPos = -1; // Position excluding modified/removed arguments.
+};
+
+class OverloadData : public OverloadDataRootNode
+{
+public:
+ explicit OverloadData(const AbstractMetaFunctionCList &overloads,
+ const ApiExtractorResult &api);
+
+ int minArgs() const { return m_minArgs; }
+ int maxArgs() const { return m_maxArgs; }
/// Returns true if any of the overloads for the current OverloadData has a return type different from void.
bool hasNonVoidReturnType() const;
@@ -61,15 +125,18 @@ public:
/// 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 AbstractMetaFunctionCList &overloads);
+ /// Returns true if any of the overloads for the current OverloadData is classmethod.
+ bool hasClassMethod() const;
+
+ /// Returns true if any of the overloads passed as argument is classmethod.
+ static bool hasClassMethod(const AbstractMetaFunctionCList &overloads);
+
/// Returns true if any of the overloads for the current OverloadData is not static.
bool hasInstanceFunction() const;
@@ -82,40 +149,17 @@ public:
/// Returns true if among the overloads passed as argument there are static and non-static methods altogether.
static bool hasStaticAndInstanceFunctions(const AbstractMetaFunctionCList &overloads);
- AbstractMetaFunctionCPtr referenceFunction() const;
- const AbstractMetaArgument *argument(const AbstractMetaFunctionCPtr &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.
- AbstractMetaFunctionCPtr getFunctionWithDefaultValue() const;
-
- bool nextArgumentHasDefaultValue() const;
- /// Returns the nearest occurrence, including this instance, of an argument with a default value.
- OverloadData *findNextArgWithDefault();
- bool isFinalOccurrence(const AbstractMetaFunctionCPtr &func) const;
-
- /// Returns the list of overloads removing repeated constant functions (ex.: "foo()" and "foo()const", the second is removed).
- AbstractMetaFunctionCList overloadsWithoutRepetition() const;
- const AbstractMetaFunctionCList &overloads() const { return m_overloads; }
- OverloadDataList nextOverloadData() const { return m_nextOverloadData; }
- OverloadData *previousOverloadData() const { return m_previousOverloadData; }
-
QList<int> invalidArgumentLengths() const;
- static int numberOfRemovedArguments(const AbstractMetaFunctionCPtr &func, int finalArgPos = -1);
- /// Returns true if all overloads have no more than one argument.
- static bool isSingleArgument(const AbstractMetaFunctionCList &overloads);
+ static int numberOfRemovedArguments(const AbstractMetaFunctionCPtr &func);
+ static int numberOfRemovedArguments(const AbstractMetaFunctionCPtr &func, int finalArgPos);
void dumpGraph(const QString &filename) const;
QString dumpGraph() const;
+ bool showGraph() const;
- bool hasArgumentTypeReplace() const;
- QString argumentTypeReplaced() const;
+ /// Returns true if a list of arguments is used (METH_VARARGS)
+ bool pythonFunctionWrapperUsesListOfArguments() const;
bool hasArgumentWithDefaultValue() const;
static bool hasArgumentWithDefaultValue(const AbstractMetaFunctionCPtr &func);
@@ -124,38 +168,16 @@ public:
static AbstractMetaArgumentList getArgumentsWithDefaultValues(const AbstractMetaFunctionCPtr &func);
#ifndef QT_NO_DEBUG_STREAM
- void formatDebug(QDebug &) const;
+ void formatDebug(QDebug &) const override;
#endif
private:
- OverloadData(OverloadData *headOverloadData, const AbstractMetaFunctionCPtr &func,
- const AbstractMetaType &argType, int argPos,
- const ApiExtractorResult &api);
-
- void addOverload(const AbstractMetaFunctionCPtr &func);
- OverloadData *addOverloadData(const AbstractMetaFunctionCPtr &func, const AbstractMetaArgument &arg);
-
- void sortNextOverloads();
- bool sortByOverloadNumberModification();
-
- int functionNumber(const AbstractMetaFunctionCPtr &func) const;
- OverloadDataList overloadDataOnPosition(OverloadData *overloadData, int argPos) const;
-
- int m_minArgs;
- int m_maxArgs;
- int m_argPos;
- AbstractMetaType m_argType;
- QString m_argTypeReplaced;
- AbstractMetaFunctionCList m_overloads;
-
- OverloadData *m_headOverloadData;
- OverloadDataList m_nextOverloadData;
- OverloadData *m_previousOverloadData;
- const ApiExtractorResult m_api;
+ int m_minArgs = 256;
+ int m_maxArgs = 0;
};
#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug, const OverloadData *);
+QDebug operator<<(QDebug, const OverloadData &);
#endif
#endif // OVERLOADDATA_H
diff --git a/sources/shiboken6/generator/shiboken/pytypenames.h b/sources/shiboken6/generator/shiboken/pytypenames.h
index cec7054a0..6c7658ff6 100644
--- a/sources/shiboken6/generator/shiboken/pytypenames.h
+++ b/sources/shiboken6/generator/shiboken/pytypenames.h
@@ -1,55 +1,29 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 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$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef PYTYPENAMES_H
#define PYTYPENAMES_H
#include <QtCore/QString>
-static inline QString pyBoolT() { return QStringLiteral("PyBool"); }
-static inline QString pyFloatT() { return QStringLiteral("PyFloat"); }
-static inline QString pyIntT() { return QStringLiteral("PyInt"); }
-static inline QString pyLongT() { return QStringLiteral("PyLong"); }
-static inline QString pyObjectT() { return QStringLiteral("object"); }
-static inline QString pyStrT() { return QStringLiteral("str"); }
+constexpr auto pyBoolT = QLatin1StringView ("PyBool");
+constexpr auto pyFloatT = QLatin1StringView ("PyFloat");
+constexpr auto pyLongT = QLatin1StringView ("PyLong");
+constexpr auto pyObjectT = QLatin1StringView ("object");
+constexpr auto pyStrT = QLatin1StringView ("str");
// PYSIDE-1499: A custom type determined by existence of an `__fspath__` attribute.
-static inline QString pyPathLikeT() { return QStringLiteral("PyPathLike"); }
+constexpr auto pyPathLikeT = QLatin1StringView ("PyPathLike");
-static inline QString cPyBufferT() { return QStringLiteral("PyBuffer"); }
-static inline QString cPyListT() { return QStringLiteral("PyList"); }
-static inline QString cPyObjectT() { return QStringLiteral("PyObject"); }
-static inline QString cPySequenceT() { return QStringLiteral("PySequence"); }
-static inline QString cPyTypeObjectT() { return QStringLiteral("PyTypeObject"); }
+constexpr auto cPyBufferT = QLatin1StringView ("PyBuffer");
+constexpr auto cPyListT = QLatin1StringView ("PyList");
+constexpr auto cPyObjectT = QLatin1StringView ("PyObject");
+constexpr auto cPySequenceT = QLatin1StringView ("PySequence");
+constexpr auto cPyTypeObjectT = QLatin1StringView ("PyTypeObject");
// numpy
-static inline QString cPyArrayObjectT() { return QStringLiteral("PyArrayObject"); }
+constexpr auto cPyArrayObjectT = QLatin1StringView ("PyArrayObject");
-static inline QString sbkCharT() { return QStringLiteral("SbkChar"); }
+constexpr auto sbkCharT = QLatin1StringView ("SbkChar");
#endif // PYTYPENAMES_H
diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
index 8935fa162..67fd9c994 100644
--- a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
@@ -1,135 +1,119 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "shibokengenerator.h"
+#include "generatorstrings.h"
+#include "generatorargument.h"
+#include "defaultvalue.h"
+#include "generatorcontext.h"
#include "apiextractorresult.h"
+#include "codesnip.h"
+#include "customconversion.h"
#include "ctypenames.h"
+#include <abstractmetabuilder.h>
#include <abstractmetaenum.h>
#include <abstractmetafield.h>
#include <abstractmetafunction.h>
#include <abstractmetalang.h>
+#include <abstractmetalang_helpers.h>
+#include <usingmember.h>
#include <exception.h>
#include <messages.h>
#include <modifications.h>
#include "overloaddata.h"
+#include <optionsparser.h>
#include "propertyspec.h"
#include "pytypenames.h"
#include <reporthandler.h>
#include <textstream.h>
#include <typedatabase.h>
-#include <abstractmetabuilder.h>
+#include <containertypeentry.h>
+#include <customtypenentry.h>
+#include <enumtypeentry.h>
+#include <flagstypeentry.h>
+#include <namespacetypeentry.h>
+#include <primitivetypeentry.h>
+#include <pythontypeentry.h>
+#include <smartpointertypeentry.h>
+#include <valuetypeentry.h>
+
#include <iostream>
+#include "qtcompat.h"
+
#include <QtCore/QDir>
#include <QtCore/QDebug>
#include <QtCore/QRegularExpression>
+
+#include <algorithm>
#include <limits>
#include <memory>
+#include <utility>
-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";
-static const char WRAPPER_DIAGNOSTICS[] = "wrapper-diagnostics";
-
-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";
-
-// 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;
-}
+using namespace Qt::StringLiterals;
+
+static constexpr auto PARENT_CTOR_HEURISTIC = "enable-parent-ctor-heuristic"_L1;
+static constexpr auto RETURN_VALUE_HEURISTIC = "enable-return-value-heuristic"_L1;
+static constexpr auto DISABLE_VERBOSE_ERROR_MESSAGES = "disable-verbose-error-messages"_L1;
+static constexpr auto USE_ISNULL_AS_NB_BOOL = "use-isnull-as-nb-bool"_L1;
+// FIXME PYSIDE 7: Remove USE_ISNULL_AS_NB_NONZERO/USE_OPERATOR_BOOL_AS_NB_NONZERO
+static constexpr auto USE_ISNULL_AS_NB_NONZERO = "use-isnull-as-nb_nonzero"_L1;
+static constexpr auto USE_OPERATOR_BOOL_AS_NB_BOOL = "use-operator-bool-as-nb-bool"_L1;
+static constexpr auto USE_OPERATOR_BOOL_AS_NB_NONZERO = "use-operator-bool-as-nb-nonzero"_L1;
+static constexpr auto WRAPPER_DIAGNOSTICS = "wrapper-diagnostics"_L1;
+static constexpr auto NO_IMPLICIT_CONVERSIONS = "no-implicit-conversions"_L1;
+static constexpr auto LEAN_HEADERS = "lean-headers"_L1;
-static inline QStringList splitClassScope(const AbstractMetaClass *scope)
+QString CPP_ARG_N(int i)
{
- return scope->qualifiedCppName().split(QLatin1String("::"), Qt::SkipEmptyParts);
+ return CPP_ARG + QString::number(i);
}
-static QString resolveScopePrefix(const AbstractMetaClass *scope, const QString &value)
+constexpr auto CPP_ARG_REMOVED_PREFIX = "removed_cppArg"_L1;
+
+QString CPP_ARG_REMOVED(int i)
{
- return scope
- ? resolveScopePrefix(splitClassScope(scope), value)
- : QString();
+ return CPP_ARG_REMOVED_PREFIX + QString::number(i);
}
-static QString resolveScopePrefix(const AbstractMetaEnum &metaEnum,
- const QString &value)
+const char *const METHOD_DEF_SENTINEL = "{nullptr, nullptr, 0, nullptr} // Sentinel\n";
+const char *const PYTHON_TO_CPPCONVERSION_STRUCT = "Shiboken::Conversions::PythonToCppConversion";
+
+const char *const openTargetExternC = R"(
+// Target ---------------------------------------------------------
+
+extern "C" {
+)";
+const char *const closeExternC = "} // extern \"C\"\n\n";
+const char *const richCompareComment =
+ "// PYSIDE-74: By default, we redirect to object's tp_richcompare (which is `==`, `!=`).\n";
+
+struct ShibokenGeneratorOptions
{
- 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);
-}
+ bool useCtorHeuristic = false;
+ bool userReturnValueHeuristic = false;
+ bool verboseErrorMessagesDisabled = false;
+ bool useIsNullAsNbBool = false;
+ // FIXME PYSIDE 7 Flip m_leanHeaders default or remove?
+ bool leanHeaders = false;
+ bool useOperatorBoolAsNbBool = false;
+ // FIXME PYSIDE 7 Flip generateImplicitConversions default or remove?
+ bool generateImplicitConversions = true;
+ bool wrapperDiagnostics = false;
+};
struct GeneratorClassInfoCacheEntry
{
ShibokenGenerator::FunctionGroups functionGroups;
+ QList<AbstractMetaFunctionCList> numberProtocolOperators;
+ BoolCastFunctionOptional boolCastFunctionO;
bool needsGetattroFunction = false;
};
-using GeneratorClassInfoCache = QHash<const AbstractMetaClass *, GeneratorClassInfoCacheEntry>;
+using GeneratorClassInfoCache = QHash<AbstractMetaClassCPtr, GeneratorClassInfoCacheEntry>;
Q_GLOBAL_STATIC(GeneratorClassInfoCache, generatorClassInfoCache)
-using AbstractMetaTypeCache = QHash<QString, AbstractMetaType>;
-
-Q_GLOBAL_STATIC(AbstractMetaTypeCache, metaTypeFromStringCache)
-
static const char CHECKTYPE_REGEX[] = R"(%CHECKTYPE\[([^\[]*)\]\()";
static const char ISCONVERTIBLE_REGEX[] = R"(%ISCONVERTIBLE\[([^\[]*)\]\()";
static const char CONVERTTOPYTHON_REGEX[] = R"(%CONVERTTOPYTHON\[([^\[]*)\]\()";
@@ -142,14 +126,18 @@ const ShibokenGenerator::TypeSystemConverterRegExps &
ShibokenGenerator::typeSystemConvRegExps()
{
static const TypeSystemConverterRegExps result = {
- QRegularExpression(QLatin1String(CHECKTYPE_REGEX)),
- QRegularExpression(QLatin1String(ISCONVERTIBLE_REGEX)),
- QRegularExpression(QLatin1String(CONVERTTOCPP_REGEX)),
- QRegularExpression(QLatin1String(CONVERTTOPYTHON_REGEX))
+ QRegularExpression(QLatin1StringView(CHECKTYPE_REGEX)),
+ QRegularExpression(QLatin1StringView(ISCONVERTIBLE_REGEX)),
+ QRegularExpression(QLatin1StringView(CONVERTTOCPP_REGEX)),
+ QRegularExpression(QLatin1StringView(CONVERTTOPYTHON_REGEX))
};
return result;
}
+// Options are static to avoid duplicated handling since ShibokenGenerator
+// is instantiated for HeaderGenerator and CppGenerator.
+ShibokenGeneratorOptions ShibokenGenerator::m_options;
+
ShibokenGenerator::ShibokenGenerator() = default;
ShibokenGenerator::~ShibokenGenerator() = default;
@@ -158,64 +146,65 @@ ShibokenGenerator::~ShibokenGenerator() = default;
static const QHash<QString, QString> &primitiveTypesCorrespondences()
{
static const QHash<QString, QString> result = {
- {QLatin1String("bool"), pyBoolT()},
- {QLatin1String("char"), sbkCharT()},
- {QLatin1String("signed char"), sbkCharT()},
- {QLatin1String("unsigned char"), sbkCharT()},
- {intT(), pyIntT()},
- {QLatin1String("signed int"), pyIntT()},
- {QLatin1String("uint"), pyIntT()},
- {QLatin1String("unsigned int"), pyIntT()},
- {shortT(), pyIntT()},
- {QLatin1String("ushort"), pyIntT()},
- {QLatin1String("signed short"), pyIntT()},
- {QLatin1String("signed short int"), pyIntT()},
- {unsignedShortT(), pyIntT()},
- {QLatin1String("unsigned short int"), pyIntT()},
- {longT(), pyIntT()},
- {doubleT(), pyFloatT()},
- {floatT(), pyFloatT()},
- {QLatin1String("unsigned long"), pyLongT()},
- {QLatin1String("signed long"), pyLongT()},
- {QLatin1String("ulong"), pyLongT()},
- {QLatin1String("unsigned long int"), pyLongT()},
- {QLatin1String("long long"), pyLongT()},
- {QLatin1String("__int64"), pyLongT()},
- {QLatin1String("unsigned long long"), pyLongT()},
- {QLatin1String("unsigned __int64"), pyLongT()},
- {QLatin1String("size_t"), pyLongT()}
+ {u"bool"_s, pyBoolT},
+ {u"char"_s, sbkCharT},
+ {u"signed char"_s, sbkCharT},
+ {u"unsigned char"_s, sbkCharT},
+ {intT, pyLongT},
+ {u"signed int"_s, pyLongT},
+ {u"uint"_s, pyLongT},
+ {u"unsigned int"_s, pyLongT},
+ {shortT, pyLongT},
+ {u"ushort"_s, pyLongT},
+ {u"signed short"_s, pyLongT},
+ {u"signed short int"_s, pyLongT},
+ {unsignedShortT, pyLongT},
+ {u"unsigned short int"_s, pyLongT},
+ {longT, pyLongT},
+ {doubleT, pyFloatT},
+ {floatT, pyFloatT},
+ {u"unsigned long"_s, pyLongT},
+ {u"signed long"_s, pyLongT},
+ {u"ulong"_s, pyLongT},
+ {u"unsigned long int"_s, pyLongT},
+ {u"long long"_s, pyLongT},
+ {u"__int64"_s, pyLongT},
+ {u"unsigned long long"_s, pyLongT},
+ {u"unsigned __int64"_s, pyLongT},
+ {u"size_t"_s, pyLongT}
};
return result;
}
-// Format units for C++->Python->C++ conversion
-const QHash<QString, QString> &ShibokenGenerator::formatUnits()
-{
- static const QHash<QString, QString> result = {
- {QLatin1String("char"), QLatin1String("b")},
- {QLatin1String("unsigned char"), QLatin1String("B")},
- {intT(), QLatin1String("i")},
- {QLatin1String("unsigned int"), QLatin1String("I")},
- {shortT(), QLatin1String("h")},
- {unsignedShortT(), QLatin1String("H")},
- {longT(), QLatin1String("l")},
- {unsignedLongLongT(), QLatin1String("k")},
- {longLongT(), QLatin1String("L")},
- {QLatin1String("__int64"), QLatin1String("L")},
- {unsignedLongLongT(), QLatin1String("K")},
- {QLatin1String("unsigned __int64"), QLatin1String("K")},
- {doubleT(), QLatin1String("d")},
- {floatT(), QLatin1String("f")},
+const QHash<QString, QChar> &ShibokenGenerator::formatUnits()
+{
+ static const QHash<QString, QChar> result = {
+ {u"char"_s, u'b'},
+ {u"unsigned char"_s, u'B'},
+ {intT, u'i'},
+ {u"unsigned int"_s, u'I'},
+ {shortT, u'h'},
+ {unsignedShortT, u'H'},
+ {longT, u'l'},
+ {unsignedLongLongT, u'k'},
+ {longLongT, u'L'},
+ {u"__int64"_s, u'L'},
+ {unsignedLongLongT, u'K'},
+ {u"unsigned __int64"_s, u'K'},
+ {doubleT, u'd'},
+ {floatT, u'f'},
};
return result;
}
QString ShibokenGenerator::translateTypeForWrapperMethod(const AbstractMetaType &cType,
- const AbstractMetaClass *context,
+ const AbstractMetaClassCPtr &context,
Options options) const
{
- if (cType.isArray())
- return translateTypeForWrapperMethod(*cType.arrayElementType(), context, options) + QLatin1String("[]");
+ if (cType.isArray()) {
+ return translateTypeForWrapperMethod(*cType.arrayElementType(), context, options)
+ + u"[]"_s;
+ }
if (avoidProtectedHack() && cType.isEnum()) {
auto metaEnum = api().findAbstractMetaEnum(cType.typeEntry());
@@ -226,7 +215,7 @@ QString ShibokenGenerator::translateTypeForWrapperMethod(const AbstractMetaType
return translateType(cType, context, options);
}
-bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass *metaClass) const
+bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClassCPtr &metaClass)
{
const auto wrapper = metaClass->cppWrapper();
return wrapper.testFlag(AbstractMetaClass::CppVirtualMethodWrapper)
@@ -234,37 +223,158 @@ bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass *metaCl
&& wrapper.testFlag(AbstractMetaClass::CppProtectedHackWrapper));
}
-bool ShibokenGenerator::shouldWriteVirtualMethodNative(const AbstractMetaFunctionCPtr &func) const
+bool ShibokenGenerator::shouldGenerateMetaObjectFunctions(const AbstractMetaClassCPtr &metaClass)
+{
+ return usePySideExtensions()
+ && (!avoidProtectedHack() || !metaClass->hasPrivateDestructor())
+ && !metaClass->typeEntry()->typeFlags()
+ .testFlag(ComplexTypeEntry::DisableQtMetaObjectFunctions)
+ && isQObject(metaClass);
+}
+
+ShibokenGenerator::FunctionGeneration ShibokenGenerator::functionGeneration(
+ const AbstractMetaFunctionCPtr &func)
+{
+ FunctionGeneration result;
+
+ const auto functionType = func->functionType();
+ switch (functionType) {
+ case AbstractMetaFunction::ConversionOperator:
+ case AbstractMetaFunction::AssignmentOperatorFunction:
+ case AbstractMetaFunction::MoveAssignmentOperatorFunction:
+ case AbstractMetaFunction::DestructorFunction:
+ case AbstractMetaFunction::SignalFunction:
+ case AbstractMetaFunction::GetAttroFunction:
+ case AbstractMetaFunction::SetAttroFunction:
+ return result;
+ default:
+ if (func->isUserAdded() || func->usesRValueReferences() || !func->isWhiteListed())
+ return result;
+ break;
+ }
+
+ const bool notModifiedRemoved = !func->isModifiedRemoved();
+ const bool isPrivate = func->isPrivate() && !func->isVisibilityModifiedToPrivate();
+ switch (functionType) {
+ case AbstractMetaFunction::ConstructorFunction:
+ if (!isPrivate && notModifiedRemoved)
+ result.setFlag(FunctionGenerationFlag::WrapperConstructor);
+ return result;
+ case AbstractMetaFunction::CopyConstructorFunction:
+ if (!isPrivate && notModifiedRemoved)
+ result.setFlag(FunctionGenerationFlag::WrapperSpecialCopyConstructor);
+ return result;
+ case AbstractMetaFunction::NormalFunction:
+ case AbstractMetaFunction::SlotFunction:
+ if (avoidProtectedHack() && func->isProtected())
+ result.setFlag(FunctionGenerationFlag::ProtectedWrapper);
+ break;
+ default:
+ break;
+ }
+
+ // Check on virtuals (including operators).
+ const bool isAbstract = func->isAbstract();
+ if (!(isAbstract || func->isVirtual())
+ || func->cppAttributes().testFlag(FunctionAttribute::Final)
+ || func->isModifiedFinal()) {
+ return result;
+ }
+
+ // MetaObject virtuals only need to be declared; CppGenerator creates a
+ // special implementation.
+ if (functionType == AbstractMetaFunction::NormalFunction
+ && usePySideExtensions() && isQObject(func->ownerClass())) {
+ const QString &name = func->name();
+ if (name == u"metaObject"_s || name == u"qt_metacall") {
+ result.setFlag(FunctionGenerationFlag::QMetaObjectMethod);
+ return result;
+ }
+ }
+
+ // Pure virtual functions need a default implementation even if private.
+ if (isAbstract || (notModifiedRemoved && !isPrivate))
+ result.setFlag(FunctionGenerationFlag::VirtualMethod);
+
+ return result;
+}
+
+AbstractMetaFunctionCList ShibokenGenerator::implicitConversions(const TypeEntryCPtr &t) const
{
- // PYSIDE-803: Extracted this because it is used multiple times.
- const AbstractMetaClass *metaClass = func->ownerClass();
- return (!avoidProtectedHack() || !metaClass->hasPrivateDestructor())
- && ((func->isVirtual() || func->isAbstract())
- && !func->attributes().testFlag(AbstractMetaFunction::FinalCppMethod));
+ if (!generateImplicitConversions() || !t->isValue())
+ return {};
+ auto vte = std::static_pointer_cast<const ValueTypeEntry>(t);
+ auto customConversion = vte->customConversion();
+ if (customConversion && customConversion->replaceOriginalTargetToNativeConversions())
+ return {};
+
+ auto result = api().implicitConversions(t);
+ auto end = std::remove_if(result.begin(), result.end(),
+ [](const AbstractMetaFunctionCPtr &f) {
+ return f->isUserAdded();
+ });
+ result.erase(end, result.end());
+ return result;
}
-QString ShibokenGenerator::wrapperName(const AbstractMetaClass *metaClass) const
+QString ShibokenGenerator::wrapperName(const AbstractMetaClassCPtr &metaClass)
{
Q_ASSERT(shouldGenerateCppWrapper(metaClass));
QString result = metaClass->name();
if (metaClass->enclosingClass()) // is a inner class
- result.replace(QLatin1String("::"), QLatin1String("_"));
- return result + QLatin1String("Wrapper");
+ result.replace(u"::"_s, u"_"_s);
+ return result + u"Wrapper"_s;
}
-QString ShibokenGenerator::fullPythonClassName(const AbstractMetaClass *metaClass)
+QString ShibokenGenerator::fullPythonClassName(const AbstractMetaClassCPtr &metaClass)
{
QString fullClassName = metaClass->name();
- const AbstractMetaClass *enclosing = metaClass->enclosingClass();
+ auto enclosing = metaClass->enclosingClass();
while (enclosing) {
if (NamespaceTypeEntry::isVisibleScope(enclosing->typeEntry()))
- fullClassName.prepend(enclosing->name() + QLatin1Char('.'));
+ fullClassName.prepend(enclosing->name() + u'.');
enclosing = enclosing->enclosingClass();
}
- fullClassName.prepend(packageName() + QLatin1Char('.'));
+ fullClassName.prepend(metaClass->typeEntry()->targetLangPackage() + u'.');
return fullClassName;
}
+QString ShibokenGenerator::headerFileNameForContext(const GeneratorContext &context)
+{
+ return fileNameForContextHelper(context, u"_wrapper.h"_s);
+}
+
+// PYSIDE-500: When avoiding the protected hack, also include the inherited
+// wrapper classes of the *current* module, because without the protected hack,
+// we sometimes need to cast inherited wrappers. Inherited classes
+// of *other* modules are completely regenerated by the header generator
+// since the wrapper headers are not installed.
+
+IncludeGroup ShibokenGenerator::baseWrapperIncludes(const GeneratorContext &classContext) const
+{
+ IncludeGroup result{u"Wrappers"_s, {}};
+ if (!classContext.useWrapper() || !avoidProtectedHack()
+ || classContext.forSmartPointer()) {
+ return result;
+ }
+
+ const auto moduleEntry = TypeDatabase::instance()->defaultTypeSystemType();
+ const auto &baseClasses = allBaseClasses(classContext.metaClass());
+ for (const auto &base : baseClasses) {
+ const auto te = base->typeEntry();
+ if (te->codeGeneration() == TypeEntry::GenerateCode) { // current module
+ const auto context = contextForClass(base);
+ if (context.useWrapper()) {
+ const QString header = headerFileNameForContext(context);
+ const auto type = typeSystemTypeEntry(te) == moduleEntry
+ ? Include::LocalPath : Include::IncludePath;
+ result.append(Include(type, header));
+ }
+ }
+ }
+ return result;
+}
+
QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunctionCPtr &func, bool forceFunc)
{
QString funcName;
@@ -277,24 +387,29 @@ QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunctionCPtr
if (func->isConstructor()) {
funcName = fullClassName;
if (forceFunc)
- funcName.append(QLatin1String(".__init__"));
+ funcName.append(u".__init__"_s);
}
else {
- funcName.prepend(fullClassName + QLatin1Char('.'));
+ funcName.prepend(fullClassName + u'.');
}
}
else {
- funcName = packageName() + QLatin1Char('.') + func->name();
+ funcName = packageName() + u'.' + func->name();
}
return funcName;
}
+bool ShibokenGenerator::wrapperDiagnostics()
+{
+ return m_options.wrapperDiagnostics;
+}
+
QString ShibokenGenerator::protectedEnumSurrogateName(const AbstractMetaEnum &metaEnum)
{
QString result = metaEnum.fullName();
- result.replace(QLatin1Char('.'), QLatin1Char('_'));
- result.replace(QLatin1String("::"), QLatin1String("_"));
- return result + QLatin1String("_Surrogate");
+ result.replace(u'.', u'_');
+ result.replace(u"::"_s, u"_"_s);
+ return result + u"_Surrogate"_s;
}
QString ShibokenGenerator::cpythonFunctionName(const AbstractMetaFunctionCPtr &func)
@@ -306,16 +421,16 @@ QString ShibokenGenerator::cpythonFunctionName(const AbstractMetaFunctionCPtr &f
if (func->implementingClass()) {
result = cpythonBaseName(func->implementingClass()->typeEntry());
if (func->isConstructor()) {
- result += QLatin1String("_Init");
+ result += u"_Init"_s;
} else {
- result += QLatin1String("Func_");
+ result += u"Func_"_s;
if (func->isOperatorOverload())
result += ShibokenGenerator::pythonOperatorFunctionName(func);
else
result += func->name();
}
} else {
- result = QLatin1String("Sbk") + moduleName() + QLatin1String("Module_") + func->name();
+ result = u"Sbk"_s + moduleName() + u"Module_"_s + func->name();
}
return result;
@@ -324,37 +439,37 @@ QString ShibokenGenerator::cpythonFunctionName(const AbstractMetaFunctionCPtr &f
QString ShibokenGenerator::cpythonMethodDefinitionName(const AbstractMetaFunctionCPtr &func)
{
if (!func->ownerClass())
- return QString();
- return cpythonBaseName(func->ownerClass()->typeEntry()) + QLatin1String("Method_")
+ return {};
+ return cpythonBaseName(func->ownerClass()->typeEntry()) + u"Method_"_s
+ func->name();
}
-QString ShibokenGenerator::cpythonGettersSettersDefinitionName(const AbstractMetaClass *metaClass)
+QString ShibokenGenerator::cpythonGettersSettersDefinitionName(const AbstractMetaClassCPtr &metaClass)
{
- return cpythonBaseName(metaClass) + QLatin1String("_getsetlist");
+ return cpythonBaseName(metaClass) + u"_getsetlist"_s;
}
-QString ShibokenGenerator::cpythonSetattroFunctionName(const AbstractMetaClass *metaClass)
+QString ShibokenGenerator::cpythonSetattroFunctionName(const AbstractMetaClassCPtr &metaClass)
{
- return cpythonBaseName(metaClass) + QLatin1String("_setattro");
+ return cpythonBaseName(metaClass) + u"_setattro"_s;
}
-QString ShibokenGenerator::cpythonGetattroFunctionName(const AbstractMetaClass *metaClass)
+QString ShibokenGenerator::cpythonGetattroFunctionName(const AbstractMetaClassCPtr &metaClass)
{
- return cpythonBaseName(metaClass) + QLatin1String("_getattro");
+ return cpythonBaseName(metaClass) + u"_getattro"_s;
}
QString ShibokenGenerator::cpythonGetterFunctionName(const QString &name,
- const AbstractMetaClass *enclosingClass)
+ const AbstractMetaClassCPtr &enclosingClass)
{
- return cpythonBaseName(enclosingClass) + QStringLiteral("_get_") + name;
+ return cpythonBaseName(enclosingClass) + "_get_"_L1 + name;
}
QString ShibokenGenerator::cpythonSetterFunctionName(const QString &name,
- const AbstractMetaClass *enclosingClass)
+ const AbstractMetaClassCPtr &enclosingClass)
{
- return cpythonBaseName(enclosingClass) + QStringLiteral("_set_") + name;
+ return cpythonBaseName(enclosingClass) + "_set_"_L1 + name;
}
QString ShibokenGenerator::cpythonGetterFunctionName(const AbstractMetaField &metaField)
@@ -368,13 +483,13 @@ QString ShibokenGenerator::cpythonSetterFunctionName(const AbstractMetaField &me
}
QString ShibokenGenerator::cpythonGetterFunctionName(const QPropertySpec &property,
- const AbstractMetaClass *metaClass)
+ const AbstractMetaClassCPtr &metaClass)
{
return cpythonGetterFunctionName(property.name(), metaClass);
}
QString ShibokenGenerator::cpythonSetterFunctionName(const QPropertySpec &property,
- const AbstractMetaClass *metaClass)
+ const AbstractMetaClassCPtr &metaClass)
{
return cpythonSetterFunctionName(property.name(), metaClass);
}
@@ -382,159 +497,15 @@ QString ShibokenGenerator::cpythonSetterFunctionName(const QPropertySpec &proper
static QString cpythonEnumFlagsName(const QString &moduleName,
const QString &qualifiedCppName)
{
- QString result = QLatin1String("Sbk") + moduleName + QLatin1Char('_') + qualifiedCppName;
- result.replace(QLatin1String("::"), QLatin1String("_"));
+ QString result = u"Sbk"_s + moduleName + u'_' + qualifiedCppName;
+ result.replace(u"::"_s, u"_"_s);
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();
- for (const AbstractMetaEnum &metaEnum : metaClass->enums()) {
- auto v = metaEnum.findEnumValue(value);
- if (v.has_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 AbstractMetaFunctionCPtr &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 AbstractMetaFunctionCPtr &func,
- const AbstractMetaArgument &arg) const
-{
- QString value = arg.defaultValueExpression();
-
- if (value.isEmpty() || value == QLatin1String("{}")
- || arg.hasModifiedDefaultValueExpression()
- || arg.type().isPointer()) {
- 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()) {
- auto metaEnum = api().findAbstractMetaEnum(arg.type().typeEntry());
- if (metaEnum.has_value())
- prefix = resolveScopePrefix(metaEnum.value(), value);
- } else if (arg.type().isFlags()) {
- value = guessScopeForDefaultFlagsValue(func, arg, value);
- } else if (arg.type().typeEntry()->isValue()) {
- auto metaClass = AbstractMetaClass::findClass(api().classes(),
- arg.type().typeEntry());
- if (enumValueRegEx.match(value).hasMatch() && value != QLatin1String("NULL"))
- prefix = resolveScopePrefix(metaClass, value);
- } else if (arg.type().isPrimitive() && arg.type().name() == intT()) {
- 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()) {
- for (const AbstractMetaField &field : func->implementingClass()->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 ShibokenGenerator::cpythonEnumName(const EnumTypeEntryCPtr &enumEntry)
{
QString p = enumEntry->targetLangPackage();
- p.replace(QLatin1Char('.'), QLatin1Char('_'));
+ p.replace(u'.', u'_');
return cpythonEnumFlagsName(p, enumEntry->qualifiedCppName());
}
@@ -543,27 +514,25 @@ QString ShibokenGenerator::cpythonEnumName(const AbstractMetaEnum &metaEnum)
return cpythonEnumName(metaEnum.typeEntry());
}
-QString ShibokenGenerator::cpythonFlagsName(const FlagsTypeEntry *flagsEntry)
+QString ShibokenGenerator::cpythonFlagsName(const FlagsTypeEntryCPtr &flagsEntry)
{
QString p = flagsEntry->targetLangPackage();
- p.replace(QLatin1Char('.'), QLatin1Char('_'));
+ p.replace(u'.', u'_');
return cpythonEnumFlagsName(p, flagsEntry->originalName());
}
QString ShibokenGenerator::cpythonFlagsName(const AbstractMetaEnum *metaEnum)
{
- const FlagsTypeEntry *flags = metaEnum->typeEntry()->flags();
- if (!flags)
- return QString();
- return cpythonFlagsName(flags);
+ const auto flags = metaEnum->typeEntry()->flags();
+ return flags ? cpythonFlagsName(flags) : QString{};
}
-QString ShibokenGenerator::cpythonSpecialCastFunctionName(const AbstractMetaClass *metaClass)
+QString ShibokenGenerator::cpythonSpecialCastFunctionName(const AbstractMetaClassCPtr &metaClass)
{
- return cpythonBaseName(metaClass->typeEntry()) + QLatin1String("SpecialCastFunction");
+ return cpythonBaseName(metaClass->typeEntry()) + u"SpecialCastFunction"_s;
}
-QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClass *metaClass,
+QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClassCPtr &metaClass,
const QString &argName)
{
return cpythonWrapperCPtr(metaClass->typeEntry(), argName);
@@ -573,57 +542,58 @@ QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType &metaType,
const QString &argName)
{
if (!metaType.isWrapperType())
- return QString();
- return QLatin1String("reinterpret_cast< ::") + metaType.cppSignature()
- + QLatin1String(" *>(Shiboken::Conversions::cppPointer(") + cpythonTypeNameExt(metaType)
- + QLatin1String(", reinterpret_cast<SbkObject *>(") + argName + QLatin1String(")))");
+ return {};
+ return u"reinterpret_cast< ::"_s + metaType.cppSignature()
+ + u" *>(Shiboken::Conversions::cppPointer("_s + cpythonTypeNameExt(metaType)
+ + u", reinterpret_cast<SbkObject *>("_s + argName + u")))"_s;
}
-QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntry *type,
+QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntryCPtr &type,
const QString &argName)
{
if (!type->isWrapperType())
return QString();
- return QLatin1String("reinterpret_cast< ::") + type->qualifiedCppName()
- + QLatin1String(" *>(Shiboken::Conversions::cppPointer(") + cpythonTypeNameExt(type)
- + QLatin1String(", reinterpret_cast<SbkObject *>(") + argName + QLatin1String(")))");
+ return u"reinterpret_cast< "_s + getFullTypeName(type)
+ + u" *>(Shiboken::Conversions::cppPointer("_s + cpythonTypeNameExt(type)
+ + u", reinterpret_cast<SbkObject *>("_s + argName + u")))"_s;
}
void ShibokenGenerator::writeToPythonConversion(TextStream & s, const AbstractMetaType &type,
- const AbstractMetaClass * /* context */,
+ const AbstractMetaClassCPtr & /* context */,
const QString &argumentName)
{
s << cpythonToPythonConversionFunction(type) << argumentName << ')';
}
-void ShibokenGenerator::writeToCppConversion(TextStream &s, const AbstractMetaClass *metaClass,
+void ShibokenGenerator::writeToCppConversion(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass,
const QString &inArgName, const QString &outArgName)
{
s << cpythonToCppConversionFunction(metaClass) << inArgName << ", &" << outArgName << ')';
}
void ShibokenGenerator::writeToCppConversion(TextStream &s, const AbstractMetaType &type,
- const AbstractMetaClass *context, const QString &inArgName,
+ const QString &inArgName,
const QString &outArgName)
{
- s << cpythonToCppConversionFunction(type, context) << inArgName << ", &" << outArgName << ')';
+ s << cpythonToCppConversionFunction(type) << inArgName << ", &" << outArgName << ')';
}
-bool ShibokenGenerator::shouldRejectNullPointerArgument(const ApiExtractorResult &api,
- const AbstractMetaFunctionCPtr &func, int argIndex)
+bool ShibokenGenerator::shouldRejectNullPointerArgument(const AbstractMetaFunctionCPtr &func,
+ int argIndex)
{
- if (argIndex < 0 || argIndex >= func->arguments().count())
+ if (argIndex < 0 || argIndex >= func->arguments().size())
return false;
const AbstractMetaArgument &arg = func->arguments().at(argIndex);
- if (isValueTypeWithCopyConstructorOnly(api, arg.type()))
+ if (arg.type().isValueTypeWithCopyConstructorOnly())
return true;
// Argument type is not a pointer, a None rejection should not be
// necessary because the type checking would handle that already.
if (!arg.type().isPointer())
return false;
- if (func->argumentRemoved(argIndex + 1))
+ if (arg.isModifiedRemoved())
return false;
for (const auto &funcMod : func->modifications()) {
for (const ArgumentModification &argMod : funcMod.argument_mods()) {
@@ -634,192 +604,152 @@ bool ShibokenGenerator::shouldRejectNullPointerArgument(const ApiExtractorResult
return false;
}
-QString ShibokenGenerator::getFormatUnitString(const AbstractMetaFunctionCPtr &func, bool incRef)
-{
- 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;
-
- const auto &type = arg.type();
- if (!func->typeReplaced(arg.argumentIndex() + 1).isEmpty()) {
- result += QLatin1Char(objType);
- } else if (arg.type().isObject()
- || type.isValue()
- || type.isValuePointer()
- || type.isNativePointer()
- || type.isEnum()
- || type.isFlags()
- || type.isContainer()
- || type.isSmartPointer()
- || type.referenceType() == LValueReference) {
- result += QLatin1Char(objType);
- } else if (type.isPrimitive()) {
- const auto *ptype =
- static_cast<const PrimitiveTypeEntry *>(type.typeEntry());
- if (ptype->basicReferencedTypeEntry())
- ptype = ptype->basicReferencedTypeEntry();
- const auto it = formatUnits().constFind(ptype->name());
- if (it != formatUnits().cend())
- result += it.value();
- else
- result += QLatin1Char(objType);
- } else if (type.isCString()) {
- 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 (type.isCString())
- return QLatin1String("PyString");
+ return u"PyString"_s;
return cpythonBaseName(type.typeEntry());
}
-QString ShibokenGenerator::cpythonBaseName(const AbstractMetaClass *metaClass)
+QString ShibokenGenerator::cpythonBaseName(const AbstractMetaClassCPtr &metaClass)
{
return cpythonBaseName(metaClass->typeEntry());
}
-QString ShibokenGenerator::cpythonBaseName(const TypeEntry *type)
+QString ShibokenGenerator::containerCpythonBaseName(const ContainerTypeEntryCPtr &ctype)
+{
+ switch (ctype->containerKind()) {
+ case ContainerTypeEntry::SetContainer:
+ return u"PySet"_s;
+ case ContainerTypeEntry::MapContainer:
+ case ContainerTypeEntry::MultiMapContainer:
+ return u"PyDict"_s;
+ case ContainerTypeEntry::ListContainer:
+ case ContainerTypeEntry::PairContainer:
+ case ContainerTypeEntry::SpanContainer:
+ break;
+ default:
+ Q_ASSERT(false);
+ }
+ return cPySequenceT;
+}
+
+QString ShibokenGenerator::cpythonBaseName(const TypeEntryCPtr &type)
{
QString baseName;
if (type->isWrapperType() || type->isNamespace()) { // && type->referenceType() == NoReference) {
- baseName = QLatin1String("Sbk_") + type->name();
+ baseName = u"Sbk_"_s + 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();
+ const auto ptype = basicReferencedTypeEntry(type);
+ baseName = ptype->hasTargetLangApiType()
+ ? ptype->targetLangApiName() : pythonPrimitiveTypeName(ptype->name());
} else if (type->isEnum()) {
- baseName = cpythonEnumName(static_cast<const EnumTypeEntry *>(type));
+ baseName = cpythonEnumName(std::static_pointer_cast<const EnumTypeEntry>(type));
} else if (type->isFlags()) {
- baseName = cpythonFlagsName(static_cast<const FlagsTypeEntry *>(type));
+ baseName = cpythonFlagsName(std::static_pointer_cast<const FlagsTypeEntry>(type));
} else if (type->isContainer()) {
- const auto *ctype = static_cast<const ContainerTypeEntry *>(type);
- switch (ctype->containerKind()) {
- 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 = cPySequenceT();
- 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);
- }
+ const auto ctype = std::static_pointer_cast<const ContainerTypeEntry>(type);
+ baseName = containerCpythonBaseName(ctype);
} else {
- baseName = cPyObjectT();
+ baseName = cPyObjectT;
}
- return baseName.replace(QLatin1String("::"), QLatin1String("_"));
+ return baseName.replace(u"::"_s, u"_"_s);
}
-QString ShibokenGenerator::cpythonTypeName(const AbstractMetaClass *metaClass)
+QString ShibokenGenerator::cpythonTypeName(const AbstractMetaClassCPtr &metaClass)
{
return cpythonTypeName(metaClass->typeEntry());
}
-QString ShibokenGenerator::cpythonTypeName(const TypeEntry *type)
-{
- return cpythonBaseName(type) + QLatin1String("_TypeF()");
-}
-
-QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntry *type)
+QString ShibokenGenerator::cpythonTypeName(const TypeEntryCPtr &type)
{
- return cppApiVariableName(type->targetLangPackage()) + QLatin1Char('[')
- + getTypeIndexVariableName(type) + QLatin1Char(']');
+ return cpythonBaseName(type) + u"_TypeF()"_s;
}
QString ShibokenGenerator::converterObject(const AbstractMetaType &type)
{
if (type.isCString())
- return QLatin1String("Shiboken::Conversions::PrimitiveTypeConverter<const char *>()");
+ return u"Shiboken::Conversions::PrimitiveTypeConverter<const char *>()"_s;
if (type.isVoidPointer())
- return QLatin1String("Shiboken::Conversions::PrimitiveTypeConverter<void *>()");
+ return u"Shiboken::Conversions::PrimitiveTypeConverter<void *>()"_s;
const AbstractMetaTypeList nestedArrayTypes = type.nestedArrayTypes();
if (!nestedArrayTypes.isEmpty() && nestedArrayTypes.constLast().isCppPrimitive()) {
- return QStringLiteral("Shiboken::Conversions::ArrayTypeConverter<")
+ return "Shiboken::Conversions::ArrayTypeConverter<"_L1
+ nestedArrayTypes.constLast().minimalSignature()
- + QLatin1String(">(") + QString::number(nestedArrayTypes.size())
- + QLatin1Char(')');
+ + u">("_s + QString::number(nestedArrayTypes.size())
+ + u')';
}
auto typeEntry = type.typeEntry();
if (typeEntry->isContainer() || typeEntry->isSmartPointer()) {
return convertersVariableName(typeEntry->targetLangPackage())
- + QLatin1Char('[') + getTypeIndexVariableName(type) + QLatin1Char(']');
+ + u'[' + getTypeIndexVariableName(type) + u']';
}
return converterObject(typeEntry);
}
-QString ShibokenGenerator::converterObject(const TypeEntry *type)
+QString ShibokenGenerator::converterObject(const TypeEntryCPtr &type)
{
- if (type->isExtendedCppPrimitive())
- return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(type->qualifiedCppName());
- if (type->isWrapperType() || type->isEnum() || type->isFlags())
- return QString::fromLatin1("*PepType_SGTP(%1)->converter").arg(cpythonTypeNameExt(type));
+ if (isExtendedCppPrimitive(type))
+ return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()")
+ .arg(type->qualifiedCppName());
+ if (type->isWrapperType())
+ return QString::fromLatin1("PepType_SOTP(reinterpret_cast<PyTypeObject *>(%1))->converter")
+ .arg(cpythonTypeNameExt(type));
+ if (type->isEnum() || type->isFlags())
+ return QString::fromLatin1("PepType_SETP(reinterpret_cast<SbkEnumType *>(%1))->converter")
+ .arg(cpythonTypeNameExt(type));
if (type->isArray()) {
qDebug() << "Warning: no idea how to handle the Qt5 type " << type->qualifiedCppName();
- return QString();
+ return {};
}
/* the typedef'd primitive types case */
- const auto *pte = dynamic_cast<const PrimitiveTypeEntry *>(type);
+ auto pte = std::dynamic_pointer_cast<const PrimitiveTypeEntry>(type);
if (!pte) {
qDebug() << "Warning: the Qt5 primitive type is unknown" << type->qualifiedCppName();
- return QString();
+ return {};
+ }
+ pte = basicReferencedTypeEntry(pte);
+ if (pte->isPrimitive() && !isCppPrimitive(pte) && !pte->customConversion()) {
+ return u"Shiboken::Conversions::PrimitiveTypeConverter<"_s
+ + pte->qualifiedCppName() + u">()"_s;
}
- 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(']');
+ + u'[' + getTypeIndexVariableName(type) + u']';
}
-QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType &type)
+QString ShibokenGenerator::cpythonTypeNameExtSet(const TypeEntryCPtr &type)
+{
+ return cppApiVariableName(type->targetLangPackage()) + u'['
+ + getTypeIndexVariableName(type) + "].type"_L1;
+}
+
+QString ShibokenGenerator::cpythonTypeNameExtSet(const AbstractMetaType &type)
{
- return cppApiVariableName(type.typeEntry()->targetLangPackage()) + QLatin1Char('[')
- + getTypeIndexVariableName(type) + QLatin1Char(']');
+ return cppApiVariableName(type.typeEntry()->targetLangPackage()) + u'['
+ + getTypeIndexVariableName(type) + "].type"_L1;
}
-static inline QString unknownOperator() { return QStringLiteral("__UNKNOWN_OPERATOR__"); }
+QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntryCPtr &type)
+{
+ return "Shiboken::Module::get("_L1 + cppApiVariableName(type->targetLangPackage())
+ + u'[' + getTypeIndexVariableName(type) + "])"_L1;
+}
+
+QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType &type)
+{
+ return u"Shiboken::Module::get("_s + cppApiVariableName(type.typeEntry()->targetLangPackage())
+ + u'[' + getTypeIndexVariableName(type) + "])"_L1;
+}
-QString ShibokenGenerator::fixedCppTypeName(const CustomConversion::TargetToNativeConversion *toNative)
+QString ShibokenGenerator::fixedCppTypeName(const TargetToNativeConversion &toNative)
{
- if (toNative->sourceType())
- return fixedCppTypeName(toNative->sourceType());
- return toNative->sourceTypeName();
+ if (toNative.sourceType())
+ return fixedCppTypeName(toNative.sourceType());
+ return toNative.sourceTypeName();
}
QString ShibokenGenerator::fixedCppTypeName(const AbstractMetaType &type)
{
@@ -828,22 +758,22 @@ QString ShibokenGenerator::fixedCppTypeName(const AbstractMetaType &type)
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"));
+ typeName.remove(u' ');
+ typeName.replace(u'.', u'_');
+ typeName.replace(u',', u'_');
+ typeName.replace(u'<', u'_');
+ typeName.replace(u'>', u'_');
+ typeName.replace(u"::"_s, u"_"_s);
+ typeName.replace(u"*"_s, u"PTR"_s);
+ typeName.replace(u"&"_s, u"REF"_s);
return typeName;
}
-QString ShibokenGenerator::fixedCppTypeName(const TypeEntry *type, QString typeName)
+QString ShibokenGenerator::fixedCppTypeName(const TypeEntryCPtr &type, QString typeName)
{
if (typeName.isEmpty())
typeName = type->qualifiedCppName();
if (!type->generateCode()) {
- typeName.prepend(QLatin1Char('_'));
+ typeName.prepend(u'_');
typeName.prepend(type->targetLangPackage());
}
return _fixedCppTypeName(typeName);
@@ -851,120 +781,66 @@ QString ShibokenGenerator::fixedCppTypeName(const TypeEntry *type, QString typeN
QString ShibokenGenerator::pythonPrimitiveTypeName(const QString &cppTypeName)
{
- QString rv = primitiveTypesCorrespondences().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());
-}
-
-static const QHash<QString, QString> &pythonOperators()
-{
- static const QHash<QString, QString> result = {
- // call operator
- {QLatin1String("operator()"), QLatin1String("call")},
- // Arithmetic operators
- {QLatin1String("operator+"), QLatin1String("add")},
- {QLatin1String("operator-"), QLatin1String("sub")},
- {QLatin1String("operator*"), QLatin1String("mul")},
- {QLatin1String("operator/"), QLatin1String("div")},
- {QLatin1String("operator%"), QLatin1String("mod")},
- // Inplace arithmetic operators
- {QLatin1String("operator+="), QLatin1String("iadd")},
- {QLatin1String("operator-="), QLatin1String("isub")},
- {QLatin1String("operator++"), QLatin1String("iadd")},
- {QLatin1String("operator--"), QLatin1String("isub")},
- {QLatin1String("operator*="), QLatin1String("imul")},
- {QLatin1String("operator/="), QLatin1String("idiv")},
- {QLatin1String("operator%="), QLatin1String("imod")},
- // Bitwise operators
- {QLatin1String("operator&"), QLatin1String("and")},
- {QLatin1String("operator^"), QLatin1String("xor")},
- {QLatin1String("operator|"), QLatin1String("or")},
- {QLatin1String("operator<<"), QLatin1String("lshift")},
- {QLatin1String("operator>>"), QLatin1String("rshift")},
- {QLatin1String("operator~"), QLatin1String("invert")},
- // Inplace bitwise operators
- {QLatin1String("operator&="), QLatin1String("iand")},
- {QLatin1String("operator^="), QLatin1String("ixor")},
- {QLatin1String("operator|="), QLatin1String("ior")},
- {QLatin1String("operator<<="), QLatin1String("ilshift")},
- {QLatin1String("operator>>="), QLatin1String("irshift")},
- // Comparison operators
- {QLatin1String("operator=="), QLatin1String("eq")},
- {QLatin1String("operator!="), QLatin1String("ne")},
- {QLatin1String("operator<"), QLatin1String("lt")},
- {QLatin1String("operator>"), QLatin1String("gt")},
- {QLatin1String("operator<="), QLatin1String("le")},
- {QLatin1String("operator>="), QLatin1String("ge")},
- };
- return result;
-}
-
-QString ShibokenGenerator::pythonOperatorFunctionName(const QString &cppOpFuncName)
-{
- QString value = pythonOperators().value(cppOpFuncName);
- if (value.isEmpty())
- return unknownOperator();
- value.prepend(QLatin1String("__"));
- value.append(QLatin1String("__"));
- return value;
+ const auto &mapping = primitiveTypesCorrespondences();
+ const auto it = mapping.constFind(cppTypeName);
+ if (it == mapping.cend())
+ throw Exception(u"Primitive type not found: "_s + cppTypeName);
+ return it.value();
}
QString ShibokenGenerator::pythonOperatorFunctionName(const AbstractMetaFunctionCPtr &func)
{
- QString op = pythonOperatorFunctionName(func->originalName());
- if (op == unknownOperator())
- qCWarning(lcShiboken).noquote().nospace() << msgUnknownOperator(func.data());
+ QString op = Generator::pythonOperatorFunctionName(func->originalName());
+ if (op.isEmpty()) {
+ qCWarning(lcShiboken).noquote().nospace() << msgUnknownOperator(func.get());
+ return "__UNKNOWN_OPERATOR__"_L1;
+ }
if (func->arguments().isEmpty()) {
- if (op == QLatin1String("__sub__"))
- op = QLatin1String("__neg__");
- else if (op == QLatin1String("__add__"))
- op = QLatin1String("__pos__");
+ if (op == u"__sub__")
+ op = u"__neg__"_s;
+ else if (op == u"__add__")
+ op = u"__pos__"_s;
} 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'));
+ op = op.insert(2, u'r');
}
return op;
}
-QString ShibokenGenerator::pythonRichCompareOperatorId(const QString &cppOpFuncName)
-{
- return QLatin1String("Py_") + pythonOperators().value(cppOpFuncName).toUpper();
-}
-
-QString ShibokenGenerator::pythonRichCompareOperatorId(const AbstractMetaFunctionCPtr &func)
+bool ShibokenGenerator::isNumber(const QString &cpythonApiName)
{
- return pythonRichCompareOperatorId(func->originalName());
+ return cpythonApiName == pyFloatT || cpythonApiName == pyLongT
+ || cpythonApiName == pyBoolT;
}
-bool ShibokenGenerator::isNumber(const QString &cpythonApiName)
+static std::optional<TypeSystem::CPythonType>
+ targetLangApiCPythonType(const PrimitiveTypeEntryCPtr &t)
{
- return cpythonApiName == pyIntT()
- || cpythonApiName == pyFloatT() || cpythonApiName == pyLongT()
- || cpythonApiName == pyBoolT();
+ if (!t->hasTargetLangApiType())
+ return {};
+ const auto cte = t->targetLangApiType();
+ if (cte->type() != TypeEntry::PythonType)
+ return {};
+ return std::static_pointer_cast<const PythonTypeEntry>(cte)->cPythonType();
}
-bool ShibokenGenerator::isNumber(const TypeEntry *type)
+bool ShibokenGenerator::isNumber(const TypeEntryCPtr &type)
{
if (!type->isPrimitive())
return false;
- return isNumber(pythonPrimitiveTypeName(static_cast<const PrimitiveTypeEntry *>(type)));
+ const auto pte = basicReferencedTypeEntry(type);
+ const auto cPythonTypeOpt = targetLangApiCPythonType(pte);
+ // FIXME PYSIDE-1660: Return false here after making primitive types built-in?
+ if (!cPythonTypeOpt.has_value()) {
+ const auto &mapping = primitiveTypesCorrespondences();
+ const auto it = mapping.constFind(pte->name());
+ return it != mapping.cend() && isNumber(it.value());
+ }
+ const auto cPythonType = cPythonTypeOpt.value();
+ return cPythonType == TypeSystem::CPythonType::Bool
+ || cPythonType == TypeSystem::CPythonType::Float
+ || cPythonType == TypeSystem::CPythonType::Integer;
}
bool ShibokenGenerator::isNumber(const AbstractMetaType &type)
@@ -972,12 +848,19 @@ bool ShibokenGenerator::isNumber(const AbstractMetaType &type)
return isNumber(type.typeEntry());
}
-bool ShibokenGenerator::isPyInt(const TypeEntry *type)
+bool ShibokenGenerator::isPyInt(const TypeEntryCPtr &type)
{
if (!type->isPrimitive())
return false;
- return pythonPrimitiveTypeName(static_cast<const PrimitiveTypeEntry *>(type))
- == QLatin1String("PyInt");
+ const auto pte = basicReferencedTypeEntry(type);
+ const auto cPythonTypeOpt = targetLangApiCPythonType(pte);
+ // FIXME PYSIDE-1660: Return false here after making primitive types built-in?
+ if (!cPythonTypeOpt.has_value()) {
+ const auto &mapping = primitiveTypesCorrespondences();
+ const auto it = mapping.constFind(pte->name());
+ return it != mapping.cend() && it.value() == pyLongT;
+ }
+ return cPythonTypeOpt.value() == TypeSystem::CPythonType::Integer;
}
bool ShibokenGenerator::isPyInt(const AbstractMetaType &type)
@@ -985,319 +868,267 @@ bool ShibokenGenerator::isPyInt(const AbstractMetaType &type)
return isPyInt(type.typeEntry());
}
-bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const ApiExtractorResult &api,
- const TypeEntry *type)
-{
- if (!type || !type->isValue())
- return false;
- auto klass = AbstractMetaClass::findClass(api.classes(), type);
- return klass != nullptr && klass->isValueTypeWithCopyConstructorOnly();
-}
-
-bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const ApiExtractorResult &api,
- const AbstractMetaType &type)
-{
- return type.typeEntry()->isValue()
- && isValueTypeWithCopyConstructorOnly(api, type.typeEntry());
-}
-
-bool ShibokenGenerator::valueTypeWithCopyConstructorOnlyPassed(const ApiExtractorResult &api,
- const AbstractMetaType &type)
-{
- return (type.passByValue() || type.passByConstRef())
- && isValueTypeWithCopyConstructorOnly(api, type);
-}
-
bool ShibokenGenerator::isNullPtr(const QString &value)
{
- return value == QLatin1String("0") || value == QLatin1String("nullptr")
- || value == QLatin1String("NULLPTR") || value == QLatin1String("{}");
+ return value == u"0" || value == u"nullptr"
+ || value == u"NULLPTR" || value == u"{}";
}
-QString ShibokenGenerator::cpythonCheckFunction(AbstractMetaType metaType,
- bool genericNumberType) const
+QString ShibokenGenerator::cpythonCheckFunction(AbstractMetaType metaType)
{
- if (metaType.typeEntry()->isCustom()) {
- auto customCheckResult = guessCPythonCheckFunction(metaType.typeEntry()->name());
- if (!customCheckResult.checkFunction.isEmpty())
- return customCheckResult.checkFunction;
- if (customCheckResult.type.has_value())
- metaType = customCheckResult.type.value();
+ const auto typeEntry = metaType.typeEntry();
+ if (typeEntry->isCustom()) {
+ const auto cte = std::static_pointer_cast<const CustomTypeEntry>(typeEntry);
+ if (cte->hasCheckFunction())
+ return cte->checkFunction();
+ throw Exception(msgUnknownCheckFunction(typeEntry));
}
if (metaType.isExtendedCppPrimitive()) {
if (metaType.isCString())
- return QLatin1String("Shiboken::String::check");
+ return u"Shiboken::String::check"_s;
if (metaType.isVoidPointer())
- return QLatin1String("PyObject_Check");
- return cpythonCheckFunction(metaType.typeEntry(), genericNumberType);
+ return u"true"_s;
+ return cpythonCheckFunction(typeEntry);
}
- auto typeEntry = metaType.typeEntry();
+
if (typeEntry->isContainer()) {
- QString typeCheck = QLatin1String("Shiboken::Conversions::");
+ QString typeCheck = u"Shiboken::Conversions::"_s;
ContainerTypeEntry::ContainerKind type =
- static_cast<const ContainerTypeEntry *>(typeEntry)->containerKind();
+ std::static_pointer_cast<const ContainerTypeEntry>(typeEntry)->containerKind();
if (type == ContainerTypeEntry::ListContainer
- || type == ContainerTypeEntry::StringListContainer
- || type == ContainerTypeEntry::LinkedListContainer
- || type == ContainerTypeEntry::VectorContainer
- || type == ContainerTypeEntry::StackContainer
- || type == ContainerTypeEntry::SetContainer
- || type == ContainerTypeEntry::QueueContainer) {
+ || type == ContainerTypeEntry::SetContainer) {
+ const QString containerType = type == ContainerTypeEntry::SetContainer
+ ? u"Iterable"_s : u"Sequence"_s;
const AbstractMetaType &type = metaType.instantiations().constFirst();
if (type.isPointerToWrapperType()) {
- typeCheck += QString::fromLatin1("checkSequenceTypes(%1, ").arg(cpythonTypeNameExt(type));
+ typeCheck += u"check"_s + containerType + u"Types("_s
+ + cpythonTypeNameExt(type) + u", "_s;
} else if (type.isWrapperType()) {
- typeCheck += QLatin1String("convertibleSequenceTypes(reinterpret_cast<SbkObjectType *>(");
- typeCheck += cpythonTypeNameExt(type);
- typeCheck += QLatin1String("), ");
+ typeCheck += u"convertible"_s + containerType
+ + u"Types("_s + cpythonTypeNameExt(type) + u", "_s;
} else {
- typeCheck += QString::fromLatin1("convertibleSequenceTypes(%1, ").arg(converterObject(type));
+ typeCheck += u"convertible"_s + containerType
+ + u"Types("_s + converterObject(type) + u", "_s;
}
} 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");
+
+ QString pyType;
+ if (type == ContainerTypeEntry::PairContainer)
+ pyType = u"Pair"_s;
+ else if (type == ContainerTypeEntry::MultiMapContainer)
+ pyType = u"MultiDict"_s;
+ else
+ pyType = u"Dict"_s;
+
const AbstractMetaType &firstType = metaType.instantiations().constFirst();
const AbstractMetaType &secondType = metaType.instantiations().constLast();
if (firstType.isPointerToWrapperType() && secondType.isPointerToWrapperType()) {
- typeCheck += QString::fromLatin1("check%1Types(%2, %3, ")
- .arg(pyType, cpythonTypeNameExt(firstType), cpythonTypeNameExt(secondType));
+ QTextStream(&typeCheck) << "check" << pyType << "Types("
+ << cpythonTypeNameExt(firstType) << ", "
+ << cpythonTypeNameExt(secondType) << ", ";
} else {
- typeCheck += QString::fromLatin1("convertible%1Types(%2, %3, %4, %5, ")
- .arg(pyType, converterObject(firstType),
- firstType.isPointerToWrapperType() ? QLatin1String("true") : QLatin1String("false"),
- converterObject(secondType),
- secondType.isPointerToWrapperType() ? QLatin1String("true") : QLatin1String("false"));
+ QTextStream(&typeCheck) << "convertible" << pyType << "Types("
+ << converterObject(firstType) << ", "
+ << (firstType.isPointerToWrapperType() ? "true" : "false")
+ << ", " << converterObject(secondType) << ", "
+ << (secondType.isPointerToWrapperType() ? "true" :"false")
+ << ", ";
}
}
return typeCheck;
}
- return cpythonCheckFunction(typeEntry, genericNumberType);
+ return cpythonCheckFunction(typeEntry);
}
-QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry *type, bool genericNumberType) const
+QString ShibokenGenerator::cpythonCheckFunction(TypeEntryCPtr type)
{
if (type->isCustom()) {
- AbstractMetaType metaType;
- auto customCheckResult = guessCPythonCheckFunction(type->name());
- if (customCheckResult.type.has_value())
- return cpythonCheckFunction(customCheckResult.type.value(), genericNumberType);
- return customCheckResult.checkFunction;
+ const auto cte = std::static_pointer_cast<const CustomTypeEntry>(type);
+ if (cte->hasCheckFunction())
+ return cte->checkFunction();
+ throw Exception(msgUnknownCheckFunction(type));
}
if (type->isEnum() || type->isFlags() || type->isWrapperType())
- return QString::fromLatin1("SbkObject_TypeCheck(%1, ").arg(cpythonTypeNameExt(type));
- if (type->isExtendedCppPrimitive()) {
- return pythonPrimitiveTypeName(static_cast<const PrimitiveTypeEntry *>(type))
- + QLatin1String("_Check");
- }
- QString typeCheck;
- if (type->targetLangApiName() == type->name())
- typeCheck = cpythonIsConvertibleFunction(api(), type);
- else if (type->targetLangApiName() == QLatin1String("PyUnicode"))
- typeCheck = QLatin1String("Shiboken::String::check");
- else
- typeCheck = type->targetLangApiName() + QLatin1String("_Check");
- return typeCheck;
-}
-
-ShibokenGenerator::CPythonCheckFunctionResult
- ShibokenGenerator::guessCPythonCheckFunction(const QString &type)
-{
- // PYSIDE-795: We abuse PySequence for iterables.
- // This part handles the overrides in the XML files.
- if (type == cPySequenceT())
- return {QLatin1String("Shiboken::String::checkIterable"), {}};
-
- if (type == cPyTypeObjectT())
- return {QLatin1String("PyType_Check"), {}};
+ return u"SbkObject_TypeCheck("_s + cpythonTypeNameExt(type) + u", "_s;
- if (type == cPyBufferT())
- return {QLatin1String("Shiboken::Buffer::checkType"), {}};
+ if (type->isPrimitive())
+ type = basicReferencedTypeEntry(type);
- if (type == pyStrT())
- return {QLatin1String("Shiboken::String::check"), {}};
-
- if (type == cPyArrayObjectT())
- return {QLatin1String("PyArray_Check"), {}};
-
- // PYSIDE-1499: We replace some strings by path objects.
- if (type == pyPathLikeT())
- return {QLatin1String("Shiboken::String::checkPath"), {}};
+ if (auto tla = type->targetLangApiType()) {
+ if (tla->hasCheckFunction())
+ return tla->checkFunction();
+ }
- CPythonCheckFunctionResult result;
- result.type = buildAbstractMetaTypeFromString(type);
+ if (isExtendedCppPrimitive(type))
+ return pythonPrimitiveTypeName(type->name()) + u"_Check"_s;
- if (!result.type.has_value()) {
- result.checkFunction = type + QLatin1String("_Check");
- } else if (result.type->typeEntry()->isCustom()) {
- auto ct = static_cast<const CustomTypeEntry *>(result.type->typeEntry());
- result.checkFunction = ct->checkFunction();
- if (result.checkFunction.isEmpty())
- result.checkFunction = type + QLatin1String("_Check");
- }
- return result;
+ return cpythonIsConvertibleFunction(type);
}
-QString ShibokenGenerator::cpythonIsConvertibleFunction(const ApiExtractorResult &api, const TypeEntry *type,
- bool /* genericNumberType */,
- bool /* checkExact */)
+QString ShibokenGenerator::cpythonIsConvertibleFunction(const TypeEntryCPtr &type)
{
if (type->isWrapperType()) {
- QString result = QLatin1String("Shiboken::Conversions::");
- result += (type->isValue() && !isValueTypeWithCopyConstructorOnly(api, type))
- ? QLatin1String("isPythonToCppValueConvertible")
- : QLatin1String("isPythonToCppPointerConvertible");
- result += QLatin1String("(reinterpret_cast<SbkObjectType *>(")
- + cpythonTypeNameExt(type) + QLatin1String("), ");
+ QString result = u"Shiboken::Conversions::"_s;
+ bool isValue = false;
+ if (type->isValue()) {
+ const auto cte = std::static_pointer_cast<const ComplexTypeEntry>(type);
+ isValue = !cte->isValueTypeWithCopyConstructorOnly();
+ }
+ result += isValue ? u"isPythonToCppValueConvertible"_s
+ : u"isPythonToCppPointerConvertible"_s;
+ result += u"("_s + cpythonTypeNameExt(type) + u", "_s;
return result;
}
return QString::fromLatin1("Shiboken::Conversions::isPythonToCppConvertible(%1, ")
.arg(converterObject(type));
}
-QString ShibokenGenerator::cpythonIsConvertibleFunction(AbstractMetaType metaType,
- bool /* genericNumberType */) const
+
+QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType &metaType)
{
- if (metaType.typeEntry()->isCustom()) {
- auto customCheckResult = guessCPythonCheckFunction(metaType.typeEntry()->name());
- if (!customCheckResult.checkFunction.isEmpty())
- return customCheckResult.checkFunction;
- if (customCheckResult.type.has_value())
- metaType = customCheckResult.type.value();
+ const auto typeEntry = metaType.typeEntry();
+ if (typeEntry->isCustom()) {
+ const auto cte = std::static_pointer_cast<const CustomTypeEntry>(typeEntry);
+ if (cte->hasCheckFunction())
+ return cte->checkFunction();
+ throw Exception(msgUnknownCheckFunction(typeEntry));
}
- QString result = QLatin1String("Shiboken::Conversions::");
+ QString result = u"Shiboken::Conversions::"_s;
+ if (metaType.generateOpaqueContainer()) {
+ result += u"pythonToCppReferenceConversion("_s
+ + converterObject(metaType) + u", "_s;
+ return result;
+ }
if (metaType.isWrapperType()) {
- if (metaType.isPointer() || isValueTypeWithCopyConstructorOnly(api(), metaType))
- result += QLatin1String("isPythonToCppPointerConvertible");
- else if (metaType.referenceType() == LValueReference)
- result += QLatin1String("isPythonToCppReferenceConvertible");
- else
- result += QLatin1String("isPythonToCppValueConvertible");
- result += QLatin1String("(reinterpret_cast<SbkObjectType *>(")
- + cpythonTypeNameExt(metaType) + QLatin1String("), ");
+ if (metaType.isPointer() || metaType.isValueTypeWithCopyConstructorOnly()) {
+ result += u"pythonToCppPointerConversion"_s;
+ } else if (metaType.referenceType() == LValueReference
+ || (metaType.referenceType() == RValueReference && typeEntry->isObject())) {
+ result += u"pythonToCppReferenceConversion"_s;
+ } else {
+ result += u"pythonToCppValueConversion"_s;
+ }
+ result += u'(' + cpythonTypeNameExt(metaType) + u", "_s;
return result;
}
- result += QLatin1String("isPythonToCppConvertible(") + converterObject(metaType);
+ result += u"pythonToCppConversion("_s + converterObject(metaType);
// Write out array sizes if known
const AbstractMetaTypeList 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 += u", "_s + QString::number(dim1)
+ + u", "_s + QString::number(dim2);
}
- result += QLatin1String(", ");
+ result += u", "_s;
return result;
}
-QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaArgument &metaArg,
- bool genericNumberType) const
+QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaArgument &metaArg)
{
- return cpythonIsConvertibleFunction(metaArg.type(), genericNumberType);
+ return cpythonIsConvertibleFunction(metaArg.type());
}
-QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaClass *metaClass)
+QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaClassCPtr &metaClass)
{
- return QLatin1String("Shiboken::Conversions::pythonToCppPointer(reinterpret_cast<SbkObjectType *>(")
- + cpythonTypeNameExt(metaClass->typeEntry()) + QLatin1String("), ");
+ return u"Shiboken::Conversions::pythonToCppPointer("_s
+ + cpythonTypeNameExt(metaClass->typeEntry()) + u", "_s;
}
-QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaType &type,
- const AbstractMetaClass * /* context */)
+QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaType &type)
{
if (type.isWrapperType()) {
- return QLatin1String("Shiboken::Conversions::pythonToCpp")
- + (type.isPointer() ? QLatin1String("Pointer") : QLatin1String("Copy"))
- + QLatin1String("(reinterpret_cast<SbkObjectType *>(")
- + cpythonTypeNameExt(type) + QLatin1String("), ");
+ return u"Shiboken::Conversions::pythonToCpp"_s
+ + (type.isPointer() ? u"Pointer"_s : u"Copy"_s)
+ + u'(' + cpythonTypeNameExt(type) + u", "_s;
}
- return QStringLiteral("Shiboken::Conversions::pythonToCppCopy(%1, ")
- .arg(converterObject(type));
+ return "Shiboken::Conversions::pythonToCppCopy("_L1
+ + converterObject(type) + ", "_L1;
}
-QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaType &type,
- const AbstractMetaClass * /* context */)
+QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaType &type)
{
if (type.isWrapperType()) {
QString conversion;
if (type.referenceType() == LValueReference
&& !(type.isValue() && type.isConstant()) && !type.isPointer()) {
- conversion = QLatin1String("reference");
+ conversion = u"reference"_s;
} else if (type.isValue() || type.isSmartPointer()) {
- conversion = QLatin1String("copy");
+ conversion = u"copy"_s;
} else {
- conversion = QLatin1String("pointer");
+ conversion = u"pointer"_s;
}
- QString result = QLatin1String("Shiboken::Conversions::") + conversion
- + QLatin1String("ToPython(reinterpret_cast<SbkObjectType *>(")
- + cpythonTypeNameExt(type) + QLatin1String("), ");
- if (conversion != QLatin1String("pointer"))
- result += QLatin1Char('&');
+ QString result = u"Shiboken::Conversions::"_s + conversion
+ + u"ToPython("_s
+ + cpythonTypeNameExt(type) + u", "_s;
+ if (conversion != u"pointer")
+ result += u'&';
return result;
}
- return QStringLiteral("Shiboken::Conversions::copyToPython(%1, %2")
- .arg(converterObject(type),
- (type.isCString() || type.isVoidPointer()) ? QString() : QLatin1String("&"));
+
+ const auto indirections = type.indirections() - 1;
+ return u"Shiboken::Conversions::copyToPython("_s + converterObject(type)
+ + u", "_s + AbstractMetaType::dereferencePrefix(indirections);
}
-QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaClass *metaClass)
+QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaClassCPtr &metaClass)
{
return cpythonToPythonConversionFunction(metaClass->typeEntry());
}
-QString ShibokenGenerator::cpythonToPythonConversionFunction(const TypeEntry *type)
+QString ShibokenGenerator::cpythonToPythonConversionFunction(const TypeEntryCPtr &type)
{
if (type->isWrapperType()) {
- 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('&');
+ const QString conversion = type->isValue() ? u"copy"_s : u"pointer"_s;
+ QString result = u"Shiboken::Conversions::"_s + conversion
+ + u"ToPython("_s + cpythonTypeNameExt(type)
+ + u", "_s;
+ if (conversion != u"pointer")
+ result += u'&';
return result;
}
- return QStringLiteral("Shiboken::Conversions::copyToPython(%1, &").arg(converterObject(type));
+ return u"Shiboken::Conversions::copyToPython("_s
+ + converterObject(type) + u", &"_s;
}
QString ShibokenGenerator::argumentString(const AbstractMetaFunctionCPtr &func,
const AbstractMetaArgument &argument,
Options options) const
{
- QString modified_type;
- if (!(options & OriginalTypeDescription))
- modified_type = func->typeReplaced(argument.argumentIndex() + 1);
- QString arg;
+ auto type = options.testFlag(OriginalTypeDescription)
+ ? argument.type() : argument.modifiedType();
- if (modified_type.isEmpty())
- arg = translateType(argument.type(), func->implementingClass(), options);
- else
- arg = modified_type.replace(QLatin1Char('$'), QLatin1Char('.'));
+
+ QString arg = translateType(type, func->implementingClass(), options);
+
+ if (argument.isTypeModified())
+ arg.replace(u'$', u'.'); // Haehh?
// "int a", "int a[]"
- const int arrayPos = arg.indexOf(QLatin1Char('['));
+ const auto arrayPos = arg.indexOf(u'[');
if (arrayPos != -1)
- arg.insert(arrayPos, QLatin1Char(' ') + argument.name());
+ arg.insert(arrayPos, u' ' + argument.name());
else
- arg.append(QLatin1Char(' ') + argument.name());
+ arg.append(u' ' + 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);
+ if (default_value == u"NULL")
+ default_value = NULL_PTR;
//WORKAROUND: fix this please
- if (default_value.startsWith(QLatin1String("new ")))
+ if (default_value.startsWith(u"new "))
default_value.remove(0, 4);
- arg += QLatin1String(" = ") + default_value;
+ arg += u" = "_s + default_value;
}
return arg;
@@ -1315,21 +1146,23 @@ void ShibokenGenerator::writeFunctionArguments(TextStream &s,
const AbstractMetaFunctionCPtr &func,
Options options) const
{
- AbstractMetaArgumentList arguments = func->arguments();
-
int argUsed = 0;
- for (int i = 0; i < arguments.size(); ++i) {
- if ((options & Generator::SkipRemovedArguments) && func->argumentRemoved(i+1))
+ if (func->isUserAddedPythonOverride()) {
+ s << "Shiboken::GilState &gil, PyObject *" << PYTHON_OVERRIDE_VAR;
+ argUsed += 2;
+ }
+ for (const auto &arg : func->arguments()) {
+ if (options.testFlag(Generator::SkipRemovedArguments) && arg.isModifiedRemoved())
continue;
if (argUsed != 0)
s << ", ";
- writeArgument(s, func, arguments[i], options);
+ writeArgument(s, func, arg, options);
argUsed++;
}
}
-GeneratorContext ShibokenGenerator::contextForClass(const AbstractMetaClass *c) const
+GeneratorContext ShibokenGenerator::contextForClass(const AbstractMetaClassCPtr &c) const
{
GeneratorContext result = Generator::contextForClass(c);
if (shouldGenerateCppWrapper(c)) {
@@ -1341,9 +1174,8 @@ GeneratorContext ShibokenGenerator::contextForClass(const AbstractMetaClass *c)
QString ShibokenGenerator::functionReturnType(const AbstractMetaFunctionCPtr &func, Options options) const
{
- QString modifiedReturnType = QString(func->typeReplaced(0));
- if (!modifiedReturnType.isEmpty() && !(options & OriginalTypeDescription))
- return modifiedReturnType;
+ if (func->isTypeModified() && !options.testFlag(OriginalTypeDescription))
+ return func->modifiedTypeName();
return translateType(func->type(), func->implementingClass(), options);
}
@@ -1355,6 +1187,8 @@ QString ShibokenGenerator::functionSignature(const AbstractMetaFunctionCPtr &fun
{
StringStream s(TextStream::Language::Cpp);
// The actual function
+ if (!options.testFlag(Option::SkipDefaultValues) && func->isStatic()) // Declaration
+ s << "static ";
if (func->isEmptyFunction() || func->needsReturnType())
s << functionReturnType(func, options) << ' ';
else
@@ -1386,14 +1220,18 @@ void ShibokenGenerator::writeArgumentNames(TextStream &s,
int argCount = 0;
for (const auto &argument : arguments) {
const int index = argument.argumentIndex() + 1;
- if ((options & Generator::SkipRemovedArguments) && (func->argumentRemoved(index)))
+ if (options.testFlag(Generator::SkipRemovedArguments) && argument.isModifiedRemoved())
continue;
+ const auto &type = argument.type();
+ if (argCount > 0)
+ s << ", ";
+ const bool isVirtualCall = options.testFlag(Option::VirtualCall);
+ const bool useStdMove = isVirtualCall && type.isUniquePointer() && type.passByValue();
+ s << (useStdMove ? stdMove(argument.name()) : argument.name());
- s << ((argCount > 0) ? ", " : "") << argument.name();
-
- if (((options & Generator::VirtualCall) == 0)
- && (!func->conversionRule(TypeSystem::NativeCode, index).isEmpty()
- || !func->conversionRule(TypeSystem::TargetLangCode, index).isEmpty())
+ if (!isVirtualCall
+ && (func->hasConversionRule(TypeSystem::NativeCode, index)
+ || func->hasConversionRule(TypeSystem::TargetLangCode, index))
&& !func->isConstructor()) {
s << CONV_RULE_OUT_VAR_SUFFIX;
}
@@ -1412,55 +1250,18 @@ void ShibokenGenerator::writeFunctionCall(TextStream &s,
s << ')';
}
-void ShibokenGenerator::writeUnusedVariableCast(TextStream &s, const QString &variableName)
-{
- s << "SBK_UNUSED(" << variableName<< ")\n";
-}
-
-static bool filterFunction(const AbstractMetaFunctionCPtr &func, bool avoidProtectedHack)
-{
- switch (func->functionType()) {
- case AbstractMetaFunction::DestructorFunction:
- case AbstractMetaFunction::SignalFunction:
- case AbstractMetaFunction::GetAttroFunction:
- case AbstractMetaFunction::SetAttroFunction:
- return false;
- default:
- break;
- }
- if (func->usesRValueReferences())
- return false;
- if (func->isModifiedRemoved() && !func->isAbstract()
- && (!avoidProtectedHack || !func->isProtected())) {
- return false;
- }
- return true;
-}
-
-AbstractMetaFunctionCList ShibokenGenerator::filterFunctions(const AbstractMetaClass *metaClass) const
-{
- AbstractMetaFunctionCList result;
- const AbstractMetaFunctionCList &funcs = metaClass->functions();
- result.reserve(funcs.size());
- for (const auto &func : funcs) {
- if (filterFunction(func, avoidProtectedHack()))
- result.append(func);
- }
- return result;
-}
-
ShibokenGenerator::ExtendedConverterData ShibokenGenerator::getExtendedConverters() const
{
ExtendedConverterData extConvs;
- for (auto metaClass : api().classes()) {
+ for (const auto &metaClass : api().classes()) {
// Use only the classes for the current module.
- if (!shouldGenerate(metaClass))
+ if (!shouldGenerate(metaClass->typeEntry()))
continue;
const auto &overloads = metaClass->operatorOverloads(OperatorQueryOption::ConversionOp);
for (const auto &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();
+ const auto convType = convOp->type().typeEntry();
if (convType->generateCode() || !convType->isValue()
|| convOp->isModifiedRemoved())
continue;
@@ -1470,15 +1271,13 @@ ShibokenGenerator::ExtendedConverterData ShibokenGenerator::getExtendedConverter
return extConvs;
}
-QList<const CustomConversion *> ShibokenGenerator::getPrimitiveCustomConversions()
+QList<CustomConversionPtr> ShibokenGenerator::getPrimitiveCustomConversions()
{
- QList<const CustomConversion *> conversions;
- const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes();
- for (const PrimitiveTypeEntry *type : primitiveTypeList) {
- if (!shouldGenerateTypeEntry(type) || !type->isUserPrimitive() || !type->customConversion())
- continue;
-
- conversions << type->customConversion();
+ QList<CustomConversionPtr> conversions;
+ const auto &primitiveTypeList = primitiveTypes();
+ for (const auto &type : primitiveTypeList) {
+ if (type->shouldGenerate() && isUserPrimitive(type) && type->hasCustomConversion())
+ conversions << type->customConversion();
}
return conversions;
}
@@ -1491,20 +1290,20 @@ static QString getArgumentsFromMethodCall(const QString &str)
// 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);
+ auto pos = str.indexOf(funcCall);
if (pos == -1)
return QString();
pos = pos + funcCall.size();
- while (str.at(pos) == QLatin1Char(' ') || str.at(pos) == QLatin1Char('\t'))
+ while (str.at(pos) == u' ' || str.at(pos) == u'\t')
++pos;
- if (str.at(pos) == QLatin1Char('('))
+ if (str.at(pos) == u'(')
++pos;
int begin = pos;
int counter = 1;
while (counter != 0) {
- if (str.at(pos) == QLatin1Char('('))
+ if (str.at(pos) == u'(')
++counter;
- else if (str.at(pos) == QLatin1Char(')'))
+ else if (str.at(pos) == u')')
--counter;
++pos;
}
@@ -1529,14 +1328,13 @@ void ShibokenGenerator::processClassCodeSnip(QString &code, const GeneratorConte
auto metaClass = context.metaClass();
// Replace template variable by the Python Type object
// for the class context in which the variable is used.
- code.replace(QLatin1String("%PYTHONTYPEOBJECT"),
- cpythonTypeName(metaClass) + QLatin1String("->type"));
- const QString className = context.useWrapper()
- ? context.wrapperName() : metaClass->qualifiedCppName();
- code.replace(QLatin1String("%TYPE"), className);
- code.replace(QLatin1String("%CPPTYPE"), metaClass->name());
+ code.replace(u"%PYTHONTYPEOBJECT"_s,
+ u"(*"_s + cpythonTypeName(metaClass) + u')');
+ const QString className = context.effectiveClassName();
+ code.replace(u"%TYPE"_s, className);
+ code.replace(u"%CPPTYPE"_s, metaClass->name());
- processCodeSnip(code);
+ processCodeSnip(code, context.effectiveClassName());
}
void ShibokenGenerator::processCodeSnip(QString &code) const
@@ -1554,6 +1352,15 @@ void ShibokenGenerator::processCodeSnip(QString &code) const
replaceTypeCheckTypeSystemVariable(code);
}
+void ShibokenGenerator::processCodeSnip(QString &code, const QString &context) const
+{
+ try {
+ processCodeSnip(code);
+ } catch (const std::exception &e) {
+ throw Exception(msgSnippetError(context, e.what()));
+ }
+}
+
ShibokenGenerator::ArgumentVarReplacementList
ShibokenGenerator::getArgumentReplacement(const AbstractMetaFunctionCPtr &func,
bool usePyArgs, TypeSystem::Language language,
@@ -1563,38 +1370,30 @@ ShibokenGenerator::ArgumentVarReplacementList
TypeSystem::Language convLang = (language == TypeSystem::TargetLangCode)
? TypeSystem::NativeCode : TypeSystem::TargetLangCode;
int removed = 0;
- for (int i = 0; i < func->arguments().size(); ++i) {
+ for (qsizetype 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);
+ const bool hasConversionRule = func->hasConversionRule(convLang, i + 1);
+ const bool argRemoved = arg.isModifiedRemoved();
if (argRemoved)
++removed;
if (argRemoved && hasConversionRule)
- argValue = arg.name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX);
+ argValue = arg.name() + CONV_RULE_OUT_VAR_SUFFIX;
else if (argRemoved || (lastArg && arg.argumentIndex() > lastArg->argumentIndex()))
- argValue = QLatin1String(CPP_ARG_REMOVED) + QString::number(i);
+ argValue = CPP_ARG_REMOVED(i);
if (!argRemoved && argValue.isEmpty()) {
int argPos = i - removed;
- AbstractMetaType type = arg.type();
- QString typeReplaced = func->typeReplaced(arg.argumentIndex() + 1);
- if (!typeReplaced.isEmpty()) {
- auto builtType = buildAbstractMetaTypeFromString(typeReplaced);
- if (builtType.has_value())
- type = builtType.value();
- }
+ AbstractMetaType type = arg.modifiedType();
if (type.typeEntry()->isCustom()) {
argValue = usePyArgs
- ? pythonArgsAt(argPos) : QLatin1String(PYTHON_ARG);
+ ? pythonArgsAt(argPos) : PYTHON_ARG;
} else {
argValue = hasConversionRule
- ? arg.name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX)
- : QLatin1String(CPP_ARG) + QString::number(argPos);
- if (type.isWrapperType()) {
- if (type.referenceType() == LValueReference && !type.isPointer())
- argValue.prepend(QLatin1Char('*'));
- }
+ ? arg.name() + CONV_RULE_OUT_VAR_SUFFIX
+ : CPP_ARG_N(argPos);
+ const auto generatorArg = GeneratorArgument::fromMetaType(type);
+ AbstractMetaType::applyDereference(&argValue, generatorArg.indirections);
}
}
} else {
@@ -1632,138 +1431,153 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s,
s << "// Begin code injection\n" << code << "// End of code injection\n\n";
}
+static void replacePyArg0(TypeSystem::Language language, QString *code)
+{
+ static constexpr auto pyArg0 = "%PYARG_0"_L1;
+
+ if (!code->contains(pyArg0))
+ return;
+ if (language != TypeSystem::NativeCode) {
+ code->replace(pyArg0, PYTHON_RETURN_VAR);
+ return;
+ }
+
+ // pyResult is an AutoDecRef in overridden methods of wrapper classes which
+ // has a cast operator for PyObject *. This may however not work in all
+ // situations (fex _PyVarObject_CAST(op) defined as ((PyVarObject*)(op))).
+ // Append ".object()" unless it is followed by a '.' indicating explicit
+ // AutoDecRef member invocation.
+ static const QString pyObject = PYTHON_RETURN_VAR + u".object()"_s;
+ qsizetype pos{};
+ while ( (pos = code->indexOf(pyArg0)) >= 0) {
+ const auto next = pos + pyArg0.size();
+ const bool memberInvocation = next < code->size() && code->at(next) == u'.';
+ code->replace(pos, pyArg0.size(),
+ memberInvocation ? PYTHON_RETURN_VAR : pyObject);
+ }
+}
+
void ShibokenGenerator::writeCodeSnips(TextStream &s,
const CodeSnipList &codeSnips,
TypeSystem::CodeSnipPosition position,
TypeSystem::Language language,
const AbstractMetaFunctionCPtr &func,
+ bool usePyArgs,
const AbstractMetaArgument *lastArg) const
{
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()], api());
- bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(od);
-
// Replace %PYARG_# variables.
- code.replace(QLatin1String("%PYARG_0"), QLatin1String(PYTHON_RETURN_VAR));
+ replacePyArg0(language, &code);
- static const QRegularExpression pyArgsRegex(QStringLiteral("%PYARG_(\\d+)"));
+ static const QRegularExpression pyArgsRegex("%PYARG_(\\d+)"_L1);
Q_ASSERT(pyArgsRegex.isValid());
if (language == TypeSystem::TargetLangCode) {
if (usePyArgs) {
- code.replace(pyArgsRegex, QLatin1String(PYTHON_ARGS) + QLatin1String("[\\1-1]"));
+ code.replace(pyArgsRegex, PYTHON_ARGS + u"[\\1-1]"_s);
} else {
- static const QRegularExpression pyArgsRegexCheck(QStringLiteral("%PYARG_([2-9]+)"));
+ static const QRegularExpression pyArgsRegexCheck("%PYARG_([2-9]+)"_L1);
Q_ASSERT(pyArgsRegexCheck.isValid());
const QRegularExpressionMatch match = pyArgsRegexCheck.match(code);
if (match.hasMatch()) {
qCWarning(lcShiboken).noquote().nospace()
- << msgWrongIndex("%PYARG", match.captured(1), func.data());
+ << msgWrongIndex("%PYARG", match.captured(1), func.get());
return;
}
- code.replace(QLatin1String("%PYARG_1"), QLatin1String(PYTHON_ARG));
+ code.replace(u"%PYARG_1"_s, 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*([^;]+)"));
+ static const QRegularExpression pyArgsAttributionRegex("%PYARG_(\\d+)\\s*=[^=]\\s*([^;]+)"_L1);
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)"));
+ code.replace(pyArgsAttributionRegex, u"PyTuple_SET_ITEM("_s
+ + PYTHON_ARGS + u".object(), \\1-1, \\2)"_s);
+ code.replace(pyArgsRegex, u"PyTuple_GET_ITEM("_s
+ + PYTHON_ARGS + u".object(), \\1-1)"_s);
}
// 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 argTypeVar = u"%ARG"_s + QString::number(arg.argumentIndex() + 1)
+ + u"_TYPE"_s;
QString argTypeVal = arg.type().cppSignature();
code.replace(argTypeVar, argTypeVal);
}
- static const QRegularExpression cppArgTypeRegexCheck(QStringLiteral("%ARG(\\d+)_TYPE"));
+ static const QRegularExpression cppArgTypeRegexCheck("%ARG(\\d+)_TYPE"_L1);
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.data());
+ << msgWrongIndex("%ARG#_TYPE", match.captured(1), func.get());
}
// Replace template variable for return variable name.
if (func->isConstructor()) {
- code.replace(QLatin1String("%0."), QLatin1String("cptr->"));
- code.replace(QLatin1String("%0"), QLatin1String("cptr"));
+ code.replace(u"%0."_s, u"cptr->"_s);
+ code.replace(u"%0"_s, u"cptr"_s);
} else if (!func->isVoid()) {
QString returnValueOp = func->type().isPointerToWrapperType()
- ? QLatin1String("%1->") : QLatin1String("%1.");
+ ? u"%1->"_s : u"%1."_s;
if (func->type().isWrapperType())
- code.replace(QLatin1String("%0."), returnValueOp.arg(QLatin1String(CPP_RETURN_VAR)));
- code.replace(QLatin1String("%0"), QLatin1String(CPP_RETURN_VAR));
+ code.replace(u"%0."_s, returnValueOp.arg(CPP_RETURN_VAR));
+ code.replace(u"%0"_s, CPP_RETURN_VAR);
}
// Replace template variable for self Python object.
QString pySelf = language == TypeSystem::NativeCode
- ? QLatin1String("pySelf") : QLatin1String("self");
- code.replace(QLatin1String("%PYSELF"), pySelf);
+ ? u"pySelf"_s : u"self"_s;
+ code.replace(u"%PYSELF"_s, pySelf);
// Replace template variable for a pointer to C++ of this object.
if (func->implementingClass()) {
- QString replacement = func->isStatic() ? QLatin1String("%1::") : QLatin1String("%1->");
+ QString replacement = func->isStatic() ? u"%1::"_s : u"%1->"_s;
QString cppSelf;
if (func->isStatic())
cppSelf = func->ownerClass()->qualifiedCppName();
else if (language == TypeSystem::NativeCode)
- cppSelf = QLatin1String("this");
+ cppSelf = u"this"_s;
else
- cppSelf = QLatin1String(CPP_SELF_VAR);
+ cppSelf = CPP_SELF_VAR;
// On comparison operator CPP_SELF_VAR is always a reference.
if (func->isComparisonOperator())
- replacement = QLatin1String("%1.");
+ replacement = u"%1."_s;
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")) {
+ const QString pattern = u"%CPPSELF.%FUNCTION_NAME("_s + methodCallArgs + u')';
+ QString replacement = u"(Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject *>("_s
+ + pySelf + u")) ? "_s;
+ if (func->name() == u"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));
+ ? u"%CPPSELF"_s
+ : u"reinterpret_cast<"_s + wrapperClassName + u" *>(%CPPSELF)"_s;
+ replacement += cppSelfVar + u"->::"_s + wrapperClassName
+ + u"::%FUNCTION_NAME("_s + methodCallArgs
+ + u") : %CPPSELF.%FUNCTION_NAME("_s + methodCallArgs + u"))"_s;
} 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));
+ replacement += u"%CPPSELF->::%TYPE::%FUNCTION_NAME("_s + methodCallArgs
+ + u") : %CPPSELF.%FUNCTION_NAME("_s + methodCallArgs + u"))"_s;
}
+ code.replace(pattern, replacement);
}
}
- code.replace(QLatin1String("%CPPSELF."), replacement.arg(cppSelf));
- code.replace(QLatin1String("%CPPSELF"), cppSelf);
+ code.replace(u"%CPPSELF."_s, replacement.arg(cppSelf));
+ code.replace(u"%CPPSELF"_s, 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));
+ if (code.indexOf(u"%BEGIN_ALLOW_THREADS") > -1) {
+ if (code.count(u"%BEGIN_ALLOW_THREADS"_s) == code.count(u"%END_ALLOW_THREADS"_s)) {
+ code.replace(u"%BEGIN_ALLOW_THREADS"_s, BEGIN_ALLOW_THREADS);
+ code.replace(u"%END_ALLOW_THREADS"_s, END_ALLOW_THREADS);
} else {
qCWarning(lcShiboken) << "%BEGIN_ALLOW_THREADS and %END_ALLOW_THREADS mismatch";
}
@@ -1772,11 +1586,11 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s,
// 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"));
+ code.replace(u"%PYTHONTYPEOBJECT"_s,
+ u"(*"_s + cpythonTypeName(func->implementingClass()) + u')');
} else {
- code.replace(QLatin1String("%PYTHONTYPEOBJECT."), pySelf + QLatin1String("->ob_type->"));
- code.replace(QLatin1String("%PYTHONTYPEOBJECT"), pySelf + QLatin1String("->ob_type"));
+ code.replace(u"%PYTHONTYPEOBJECT."_s, pySelf + u"->ob_type->"_s);
+ code.replace(u"%PYTHONTYPEOBJECT"_s, pySelf + u"->ob_type"_s);
}
}
@@ -1786,28 +1600,23 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s,
QStringList args;
for (const ArgumentVarReplacementPair &pair : argReplacements) {
- if (pair.second.startsWith(QLatin1String(CPP_ARG_REMOVED)))
+ if (pair.second.startsWith(CPP_ARG_REMOVED_PREFIX))
continue;
args << pair.second;
}
- code.replace(QLatin1String("%ARGUMENT_NAMES"), args.join(QLatin1String(", ")));
+ code.replace(u"%ARGUMENT_NAMES"_s, args.join(u", "_s));
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()) {
- auto builtType = buildAbstractMetaTypeFromString(typeReplaced);
- if (builtType.has_value())
- type = builtType.value();
- }
+ AbstractMetaType type = arg.modifiedType();
if (type.isWrapperType()) {
QString replacement = pair.second;
- if (type.referenceType() == LValueReference && !type.isPointer())
- replacement.remove(0, 1);
+ const auto generatorArg = GeneratorArgument::fromMetaType(type);
+ if (generatorArg.indirections > 0)
+ AbstractMetaType::stripDereference(&replacement);
if (type.referenceType() == LValueReference || type.isPointer())
- code.replace(QString::fromLatin1("%%1.").arg(idx), replacement + QLatin1String("->"));
+ code.replace(u'%' + QString::number(idx) + u'.', replacement + u"->"_s);
}
code.replace(CodeSnipAbstract::placeHolderRegex(idx), pair.second);
}
@@ -1816,11 +1625,11 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s,
// 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));
+ code.replace(u"%PYTHON_ARGUMENTS"_s, 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));
+ code.replace(u"%PYTHON_METHOD_OVERRIDE"_s, PYTHON_OVERRIDE_VAR);
}
if (avoidProtectedHack()) {
@@ -1829,31 +1638,34 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s,
// 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 auto &funcs = getFunctionOverloads(func->ownerClass(), func->name());
- for (const auto &f : funcs)
- hasProtectedOverload |= f->isProtected();
+ bool isProtected = func->isProtected();
+ auto owner = func->ownerClass();
+ if (!isProtected && func->isUserAdded() && owner != nullptr) {
+ const auto &funcs = getFunctionGroups(owner).value(func->name());
+ isProtected = std::any_of(funcs.cbegin(), funcs.cend(),
+ [](const AbstractMetaFunctionCPtr &f) {
+ return 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 (isProtected) {
+ code.replace(u"%TYPE::%FUNCTION_NAME"_s,
+ wrapperName(func->ownerClass()) + "::"_L1
+ + func->originalName() + "_protected"_L1);
+ code.replace(u"%FUNCTION_NAME"_s,
+ func->originalName() + u"_protected"_s);
}
}
if (func->isConstructor() && shouldGenerateCppWrapper(func->ownerClass()))
- code.replace(QLatin1String("%TYPE"), wrapperName(func->ownerClass()));
+ code.replace(u"%TYPE"_s, wrapperName(func->ownerClass()));
if (func->ownerClass())
- code.replace(QLatin1String("%CPPTYPE"), func->ownerClass()->name());
+ code.replace(u"%CPPTYPE"_s, func->ownerClass()->name());
replaceTemplateVariables(code, func);
- processCodeSnip(code);
+ processCodeSnip(code, func->classQualifiedSignature());
s << "// Begin code injection\n" << code << "// End of code injection\n\n";
}
@@ -1861,7 +1673,7 @@ void ShibokenGenerator::writeCodeSnips(TextStream &s,
// 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*(?:\\[[^\\[]+\\])*$"));
+ static const QRegularExpression expr("^\\s*\\*?\\s*[A-Za-z_][A-Za-z_0-9.]*\\s*(?:\\[[^\\[]+\\])*$"_L1);
Q_ASSERT(expr.isValid());
return expr.match(code.trimmed()).hasMatch();
}
@@ -1874,15 +1686,15 @@ static QString miniNormalizer(const QString &varType)
QString normalized = varType.trimmed();
if (normalized.isEmpty())
return normalized;
- if (normalized.startsWith(QLatin1String("::")))
+ if (normalized.startsWith(u"::"))
normalized.remove(0, 2);
QString suffix;
- while (normalized.endsWith(QLatin1Char('*')) || normalized.endsWith(QLatin1Char('&'))) {
- suffix.prepend(normalized.at(normalized.count() - 1));
+ while (normalized.endsWith(u'*') || normalized.endsWith(u'&')) {
+ suffix.prepend(normalized.at(normalized.size() - 1));
normalized.chop(1);
normalized = normalized.trimmed();
}
- const QString result = normalized + QLatin1Char(' ') + suffix;
+ const QString result = normalized + u' ' + suffix;
return result.trimmed();
}
// The position must indicate the first character after the opening '('.
@@ -1893,7 +1705,7 @@ static QString getConverterTypeSystemVariableArgument(const QString &code, int p
QString arg;
int parenthesisDepth = 0;
int count = 0;
- while (pos + count < code.count()) {
+ while (pos + count < code.size()) {
char c = code.at(pos+count).toLatin1(); // toAscii is gone
if (c == '(') {
++parenthesisDepth;
@@ -1914,15 +1726,15 @@ static QString getConverterTypeSystemVariableArgument(const QString &code, int p
const QHash<int, QString> &ShibokenGenerator::typeSystemConvName()
{
static const QHash<int, QString> result = {
- {TypeSystemCheckFunction, QLatin1String("checkType")},
- {TypeSystemIsConvertibleFunction, QLatin1String("isConvertible")},
- {TypeSystemToCppFunction, QLatin1String("toCpp")},
- {TypeSystemToPythonFunction, QLatin1String("toPython")}
+ {TypeSystemCheckFunction, u"checkType"_s},
+ {TypeSystemIsConvertibleFunction, u"isConvertible"_s},
+ {TypeSystemToCppFunction, u"toCpp"_s},
+ {TypeSystemToPythonFunction, u"toPython"_s}
};
return result;
}
-using StringPair = QPair<QString, QString>;
+using StringPair = std::pair<QString, QString>;
void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable,
QString &code) const
@@ -1935,7 +1747,7 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
QString conversionString = list.constFirst();
const QString &conversionTypeName = list.constLast();
QString message;
- const auto conversionTypeO = buildAbstractMetaTypeFromString(conversionTypeName, &message);
+ const auto conversionTypeO = AbstractMetaType::fromString(conversionTypeName, &message);
if (!conversionTypeO.has_value()) {
throw Exception(msgCannotFindType(conversionTypeName,
typeSystemConvName().value(converterVariable),
@@ -1948,7 +1760,7 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
StringStream c(TextStream::Language::Cpp);
int end = match.capturedStart();
int start = end;
- while (start > 0 && code.at(start) != QLatin1Char('\n'))
+ while (start > 0 && code.at(start) != u'\n')
--start;
while (code.at(start).isSpace())
++start;
@@ -1957,21 +1769,13 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
varType = miniNormalizer(varType);
QString varName = list.at(1).trimmed();
if (!varType.isEmpty()) {
- const QString conversionSignature = conversionType.cppSignature();
- if (varType != QLatin1String("auto") && varType != conversionSignature)
- throw Exception(msgConversionTypesDiffer(varType, conversionSignature));
- c << getFullTypeName(conversionType) << ' ' << varName;
- writeMinimalConstructorExpression(c, api(), conversionType);
- c << ";\n";
+ c << getFullTypeName(conversionType) << ' ' << varName
+ << minimalConstructorExpression(api(), conversionType) << ";\n";
}
c << cpythonToCppConversionFunction(conversionType);
QString prefix;
- if (varName.startsWith(QLatin1Char('*'))) {
- varName.remove(0, 1);
- varName = varName.trimmed();
- } else {
- prefix = QLatin1Char('&');
- }
+ if (!AbstractMetaType::stripDereference(&varName))
+ prefix = u'&';
QString arg = getConverterTypeSystemVariableArgument(code, match.capturedEnd());
conversionString += arg;
c << arg << ", " << prefix << '(' << varName << ')';
@@ -1981,8 +1785,8 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
case TypeSystemCheckFunction:
conversion = cpythonCheckFunction(conversionType);
if (conversionType.typeEntry()->isPrimitive()
- && (conversionType.typeEntry()->name() == cPyObjectT()
- || !conversion.endsWith(QLatin1Char(' ')))) {
+ && (conversionType.typeEntry()->name() == cPyObjectT
+ || !conversion.endsWith(u' '))) {
conversion += u'(';
break;
}
@@ -2004,17 +1808,17 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa
<< code << '\'';
throw Exception(m);
}
- if (conversion.contains(QLatin1String("%in"))) {
- conversion.prepend(QLatin1Char('('));
- conversion.replace(QLatin1String("%in"), arg);
+ if (conversion.contains(u"%in")) {
+ conversion.prepend(u'(');
+ conversion.replace(u"%in"_s, arg);
} else {
conversion += arg;
}
}
}
- replacements.append(qMakePair(conversionString, conversion));
+ replacements.append(std::make_pair(conversionString, conversion));
}
- for (const StringPair &rep : qAsConst(replacements))
+ for (const StringPair &rep : std::as_const(replacements))
code.replace(rep.first, rep.second);
}
@@ -2023,9 +1827,9 @@ bool ShibokenGenerator::injectedCodeCallsCppFunction(const GeneratorContext &con
{
if (func->injectedCodeContains(u"%FUNCTION_NAME("))
return true;
- QString funcCall = func->originalName() + QLatin1Char('(');
+ QString funcCall = func->originalName() + u'(';
if (func->isConstructor())
- funcCall.prepend(QLatin1String("new "));
+ funcCall.prepend(u"new "_s);
if (func->injectedCodeContains(funcCall))
return true;
if (!func->isConstructor())
@@ -2035,18 +1839,17 @@ bool ShibokenGenerator::injectedCodeCallsCppFunction(const GeneratorContext &con
const auto owner = func->ownerClass();
if (!owner->isPolymorphic())
return false;
- const QString className = context.useWrapper()
- ? context.wrapperName() : owner->qualifiedCppName();
- const QString wrappedCtorCall = QLatin1String("new ") + className + QLatin1Char('(');
+ const QString wrappedCtorCall = u"new "_s + context.effectiveClassName() + u'(';
return func->injectedCodeContains(wrappedCtorCall);
}
-bool ShibokenGenerator::useOverrideCaching(const AbstractMetaClass *metaClass)
+bool ShibokenGenerator::useOverrideCaching(const AbstractMetaClassCPtr &metaClass)
{
return metaClass->isPolymorphic();
}
-ShibokenGenerator::AttroCheck ShibokenGenerator::checkAttroFunctionNeeds(const AbstractMetaClass *metaClass) const
+ShibokenGenerator::AttroCheck ShibokenGenerator::checkAttroFunctionNeeds(
+ const AbstractMetaClassCPtr &metaClass)
{
AttroCheck result;
if (metaClass->typeEntry()->isSmartPointer()) {
@@ -2058,7 +1861,7 @@ ShibokenGenerator::AttroCheck ShibokenGenerator::checkAttroFunctionNeeds(const A
FunctionQueryOption::GetAttroFunction)) {
result |= AttroCheckFlag::GetattroUser;
}
- if (usePySideExtensions() && metaClass->qualifiedCppName() == qObjectT())
+ if (usePySideExtensions() && metaClass->qualifiedCppName() == qObjectT)
result |= AttroCheckFlag::SetattroQObject;
if (useOverrideCaching(metaClass))
result |= AttroCheckFlag::SetattroMethodOverride;
@@ -2070,14 +1873,14 @@ ShibokenGenerator::AttroCheck ShibokenGenerator::checkAttroFunctionNeeds(const A
// QObject, the property code needs to be generated, too.
if ((result & AttroCheckFlag::SetattroMask) != 0
&& !result.testFlag(AttroCheckFlag::SetattroQObject)
- && metaClass->isQObject()) {
+ && isQObject(metaClass)) {
result |= AttroCheckFlag::SetattroQObject;
}
}
return result;
}
-bool ShibokenGenerator::classNeedsGetattroFunctionImpl(const AbstractMetaClass *metaClass)
+bool ShibokenGenerator::classNeedsGetattroFunctionImpl(const AbstractMetaClassCPtr &metaClass)
{
if (!metaClass)
return false;
@@ -2086,7 +1889,7 @@ bool ShibokenGenerator::classNeedsGetattroFunctionImpl(const AbstractMetaClass *
const auto &functionGroup = getFunctionGroups(metaClass);
for (auto it = functionGroup.cbegin(), end = functionGroup.cend(); it != end; ++it) {
AbstractMetaFunctionCList overloads;
- for (const auto &func : qAsConst(it.value())) {
+ for (const auto &func : std::as_const(it.value())) {
if (func->isAssignmentOperator() || func->isConversionOperator()
|| func->isModifiedRemoved()
|| func->isPrivate() || func->ownerClass() != func->implementingClass()
@@ -2103,14 +1906,14 @@ bool ShibokenGenerator::classNeedsGetattroFunctionImpl(const AbstractMetaClass *
}
AbstractMetaFunctionCList
- ShibokenGenerator::getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass *metaClass)
+ ShibokenGenerator::getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClassCPtr &metaClass)
{
AbstractMetaFunctionCList methods;
if (metaClass) {
const auto &functionGroups = getFunctionGroups(metaClass);
for (auto it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
AbstractMetaFunctionCList overloads;
- for (const auto &func : qAsConst(it.value())) {
+ for (const auto &func : std::as_const(it.value())) {
if (func->isAssignmentOperator() || func->isConversionOperator()
|| func->isModifiedRemoved()
|| func->isPrivate() || func->ownerClass() != func->implementingClass()
@@ -2127,7 +1930,8 @@ AbstractMetaFunctionCList
return methods;
}
-const AbstractMetaClass *ShibokenGenerator::getMultipleInheritingClass(const AbstractMetaClass *metaClass)
+AbstractMetaClassCPtr
+ ShibokenGenerator::getMultipleInheritingClass(const AbstractMetaClassCPtr &metaClass)
{
if (!metaClass || metaClass->baseClassNames().isEmpty())
return nullptr;
@@ -2138,72 +1942,48 @@ const AbstractMetaClass *ShibokenGenerator::getMultipleInheritingClass(const Abs
QString ShibokenGenerator::getModuleHeaderFileBaseName(const QString &moduleName)
{
- return moduleCppPrefix(moduleName).toLower() + QStringLiteral("_python");
+ return moduleCppPrefix(moduleName).toLower() + "_python"_L1;
}
QString ShibokenGenerator::getModuleHeaderFileName(const QString &moduleName)
{
- return getModuleHeaderFileBaseName(moduleName) + QStringLiteral(".h");
+ return getModuleHeaderFileBaseName(moduleName) + ".h"_L1;
}
QString ShibokenGenerator::getPrivateModuleHeaderFileName(const QString &moduleName)
{
- return getModuleHeaderFileBaseName(moduleName) + QStringLiteral("_p.h");
+ return getModuleHeaderFileBaseName(moduleName) + "_p.h"_L1;
}
-std::optional<AbstractMetaType>
- ShibokenGenerator::buildAbstractMetaTypeFromString(QString typeSignature,
- QString *errorMessage)
+IncludeGroupList ShibokenGenerator::classIncludes(const AbstractMetaClassCPtr &metaClass) const
{
- typeSignature = typeSignature.trimmed();
- if (typeSignature.startsWith(QLatin1String("::")))
- typeSignature.remove(0, 2);
+ IncludeGroupList result;
+ const auto typeEntry = metaClass->typeEntry();
+ //Extra includes
+ result.append(IncludeGroup{u"Extra includes"_s,
+ typeEntry->extraIncludes()});
- auto &cache = *metaTypeFromStringCache();
- auto it = cache.find(typeSignature);
- if (it == cache.end()) {
- auto metaType =
- AbstractMetaBuilder::translateType(typeSignature, nullptr, {}, errorMessage);
- if (Q_UNLIKELY(!metaType.has_value())) {
- if (errorMessage)
- errorMessage->prepend(msgCannotBuildMetaType(typeSignature));
- return {};
+ result.append({u"Enum includes"_s, {}});
+ for (const auto &cppEnum : metaClass->enums())
+ result.back().includes.append(cppEnum.typeEntry()->extraIncludes());
+
+ result.append({u"Argument includes"_s, typeEntry->argumentIncludes()});
+ const auto implicitConvs = implicitConversions(typeEntry);
+ for (const auto &f : implicitConvs) {
+ if (f->isConversionOperator()) {
+ const auto source = f->ownerClass();
+ Q_ASSERT(source);
+ result.back().append(source->typeEntry()->include());
}
- it = cache.insert(typeSignature, metaType.value());
}
- return it.value();
-}
-
-AbstractMetaType
- ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(const TypeEntry *typeEntry)
-{
- QString typeName = typeEntry->qualifiedCppName();
- if (typeName.startsWith(QLatin1String("::")))
- typeName.remove(0, 2);
- auto &cache = *metaTypeFromStringCache();
- auto it = cache.find(typeName);
- if (it != cache.end())
- return it.value();
- AbstractMetaType metaType(typeEntry);
- metaType.clearIndirections();
- metaType.setReferenceType(NoReference);
- metaType.setConstant(false);
- metaType.decideUsagePattern();
- cache.insert(typeName, metaType);
- return metaType;
-}
-
-AbstractMetaType
- ShibokenGenerator::buildAbstractMetaTypeFromAbstractMetaClass(const AbstractMetaClass *metaClass)
-{
- return ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(metaClass->typeEntry());
+ return result;
}
/*
static void dumpFunction(AbstractMetaFunctionList lst)
{
qDebug() << "DUMP FUNCTIONS: ";
- for (AbstractMetaFunction *func : qAsConst(lst))
+ for (AbstractMetaFunction *func : std::as_const(lst))
qDebug() << "*" << func->ownerClass()->name()
<< func->signature()
<< "Private: " << func->isPrivate()
@@ -2247,40 +2027,78 @@ ShibokenGenerator::FunctionGroups ShibokenGenerator::getGlobalFunctionGroups() c
{
FunctionGroups results;
insertIntoFunctionGroups(api().globalFunctions(), &results);
- for (auto nsp : invisibleTopNamespaces())
+ for (const auto &nsp : invisibleTopNamespaces())
insertIntoFunctionGroups(nsp->functions(), &results);
return results;
}
-const GeneratorClassInfoCacheEntry &ShibokenGenerator::getGeneratorClassInfo(const AbstractMetaClass *scope)
+const GeneratorClassInfoCacheEntry &
+ ShibokenGenerator::getGeneratorClassInfo(const AbstractMetaClassCPtr &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);
+ auto &entry = it.value();
+ entry.functionGroups = getFunctionGroupsImpl(scope);
+ entry.needsGetattroFunction = classNeedsGetattroFunctionImpl(scope);
+ entry.numberProtocolOperators = getNumberProtocolOperators(scope);
+ entry.boolCastFunctionO = getBoolCast(scope);
}
return it.value();
}
-ShibokenGenerator::FunctionGroups ShibokenGenerator::getFunctionGroups(const AbstractMetaClass *scope)
+ShibokenGenerator::FunctionGroups
+ ShibokenGenerator::getFunctionGroups(const AbstractMetaClassCPtr &scope)
{
Q_ASSERT(scope);
return getGeneratorClassInfo(scope).functionGroups;
}
-ShibokenGenerator::FunctionGroups ShibokenGenerator::getFunctionGroupsImpl(const AbstractMetaClass *scope)
+QList<AbstractMetaFunctionCList>
+ ShibokenGenerator::numberProtocolOperators(const AbstractMetaClassCPtr &scope)
+{
+ Q_ASSERT(scope);
+ return getGeneratorClassInfo(scope).numberProtocolOperators;
+}
+
+BoolCastFunctionOptional ShibokenGenerator::boolCast(const AbstractMetaClassCPtr &scope)
+{
+ Q_ASSERT(scope);
+ return getGeneratorClassInfo(scope).boolCastFunctionO;
+}
+
+// Use non-const overloads only, for example, "foo()" and "foo()const"
+// the second is removed.
+static void removeConstOverloads(AbstractMetaFunctionCList *overloads)
+{
+ for (qsizetype i = overloads->size() - 1; i >= 0; --i) {
+ const auto &f = overloads->at(i);
+ if (f->isConstant()) {
+ for (qsizetype c = 0, size = overloads->size(); c < size; ++c) {
+ if (f->isConstOverloadOf(overloads->at(c).get())) {
+ overloads->removeAt(i);
+ break;
+ }
+ }
+ }
+ }
+}
+
+ShibokenGenerator::FunctionGroups
+ ShibokenGenerator::getFunctionGroupsImpl(const AbstractMetaClassCPtr &scope)
{
AbstractMetaFunctionCList lst = scope->functions();
scope->getFunctionsFromInvisibleNamespacesToBeGenerated(&lst);
FunctionGroups results;
for (const auto &func : lst) {
- if (isGroupable(func)) {
+ if (isGroupable(func)
+ && func->ownerClass() == func->implementingClass()
+ && func->generateBinding()) {
auto it = results.find(func->name());
if (it == results.end()) {
- results.insert(func->name(), AbstractMetaFunctionCList(1, func));
+ it = results.insert(func->name(), AbstractMetaFunctionCList(1, func));
} else {
// If there are virtuals methods in the mix (PYSIDE-570,
// QFileSystemModel::index(QString,int) and
@@ -2292,389 +2110,541 @@ ShibokenGenerator::FunctionGroups ShibokenGenerator::getFunctionGroupsImpl(const
else
it.value().append(func);
}
+ getInheritedOverloads(scope, &it.value());
+ removeConstOverloads(&it.value());
}
}
return results;
}
-AbstractMetaFunctionCList
- ShibokenGenerator::getInheritedOverloads(const AbstractMetaFunctionCPtr &func, QSet<QString> *seen)
-{
- AbstractMetaFunctionCList results;
- AbstractMetaClass *basis;
- if (func->ownerClass() && (basis = func->ownerClass()->baseClass())) {
- for (; basis; basis = basis->baseClass()) {
- const auto inFunc = basis->findFunction(func->name());
- if (!inFunc.isNull() && !seen->contains(inFunc->minimalSignature())) {
- seen->insert(inFunc->minimalSignature());
- AbstractMetaFunction *newFunc = inFunc->copy();
- newFunc->setImplementingClass(func->implementingClass());
- results << AbstractMetaFunctionCPtr(newFunc);
- }
- }
- }
- return results;
+static bool removeNumberProtocolOperator(const AbstractMetaFunctionCPtr &f)
+{
+ return !f->generateBinding()
+ || (f->ownerClass() != f->implementingClass() && !f->isAbstract());
}
-AbstractMetaFunctionCList
- ShibokenGenerator::getFunctionAndInheritedOverloads(const AbstractMetaFunctionCPtr &func,
- QSet<QString> *seen)
+QList<AbstractMetaFunctionCList>
+ ShibokenGenerator::getNumberProtocolOperators(const AbstractMetaClassCPtr &metaClass)
{
- AbstractMetaFunctionCList results;
- seen->insert(func->minimalSignature());
- results << func << getInheritedOverloads(func, seen);
- return results;
+ QList<AbstractMetaFunctionCList> result;
+ if (metaClass->isNamespace())
+ return result;
+ result = filterGroupedOperatorFunctions(
+ metaClass,
+ OperatorQueryOption::ArithmeticOp
+ | OperatorQueryOption::IncDecrementOp
+ | OperatorQueryOption::LogicalOp
+ | OperatorQueryOption::BitwiseOp
+ | OperatorQueryOption::ConversionOp);
+
+ for (auto i = result.size() - 1; i >= 0; --i) {
+ AbstractMetaFunctionCList &l = result[i];
+ auto rend = std::remove_if(l.begin(), l.end(), removeNumberProtocolOperator);
+ l.erase(rend, l.end());
+ if (l.isEmpty())
+ result.removeAt(i);
+ }
+
+ return result;
}
-AbstractMetaFunctionCList ShibokenGenerator::getFunctionOverloads(const AbstractMetaClass *scope,
- const QString &functionName) const
+BoolCastFunctionOptional
+ShibokenGenerator::getBoolCast(const AbstractMetaClassCPtr &metaClass)
{
- const auto &lst = scope ? scope->functions() : api().globalFunctions();
+ if (metaClass->isNamespace())
+ return std::nullopt;
- AbstractMetaFunctionCList results;
- QSet<QString> seenSignatures;
- for (const auto &func : qAsConst(lst)) {
- if (func->name() != functionName)
- continue;
- if (isGroupable(func)) {
- // PYSIDE-331: look also into base classes.
- results << getFunctionAndInheritedOverloads(func, &seenSignatures);
+ const auto te = metaClass->typeEntry();
+ if (te->isSmartPointer()) {
+ auto ste = std::static_pointer_cast<const SmartPointerTypeEntry>(te);
+
+ auto valueCheckMethod = ste->valueCheckMethod();
+ if (!valueCheckMethod.isEmpty()) {
+ const auto func = metaClass->findFunction(valueCheckMethod);
+ if (!func)
+ throw Exception(msgMethodNotFound(metaClass, valueCheckMethod));
+ return BoolCastFunction{func, false};
+ }
+
+ auto nullCheckMethod = ste->nullCheckMethod();
+ if (!nullCheckMethod.isEmpty()) {
+ const auto func = metaClass->findFunction(nullCheckMethod);
+ if (!func)
+ throw Exception(msgMethodNotFound(metaClass, nullCheckMethod));
+ return BoolCastFunction{func, true};
}
}
- return results;
+
+ auto mode = te->operatorBoolMode();
+ if (useOperatorBoolAsNbBool()
+ ? mode != TypeSystem::BoolCast::Disabled : mode == TypeSystem::BoolCast::Enabled) {
+ const auto func = metaClass->findOperatorBool();
+ if (func)
+ return BoolCastFunction{func, false};
+ }
+
+ mode = te->isNullMode();
+ if (useIsNullAsNbBool()
+ ? mode != TypeSystem::BoolCast::Disabled : mode == TypeSystem::BoolCast::Enabled) {
+ const auto func = metaClass->findQtIsNullMethod();
+ if (func)
+ return BoolCastFunction{func, true};
+ }
+ return std::nullopt;
}
-Generator::OptionDescriptions ShibokenGenerator::options() const
+static bool isInplaceAdd(const AbstractMetaFunctionCPtr &func)
{
- return {
- {QLatin1String(AVOID_PROTECTED_HACK),
- QLatin1String("Avoid the use of the '#define protected public' hack.")},
- {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.")},
- {QLatin1String(PARENT_CTOR_HEURISTIC),
- QLatin1String("Enable heuristics to detect parent relationship on constructors.")},
- {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.")},
- {QLatin1String(RETURN_VALUE_HEURISTIC),
- QLatin1String("Enable heuristics to detect parent relationship on return values\n"
- "(USE WITH CAUTION!)")},
- {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")},
- {QLatin1String(WRAPPER_DIAGNOSTICS),
- QLatin1String("Generate diagnostic code around wrappers")}
- };
+ return func->name() == u"operator+=";
}
-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);
- if (key == QLatin1String(WRAPPER_DIAGNOSTICS))
- return (m_wrapperDiagnostics = true);
- return false;
+static bool isIncrementOperator(const AbstractMetaFunctionCPtr &func)
+{
+ return func->functionType() == AbstractMetaFunction::IncrementOperator;
}
-static void getCode(QStringList &code, const CodeSnipList &codeSnips)
+static bool isDecrementOperator(const AbstractMetaFunctionCPtr &func)
{
- for (const CodeSnip &snip : qAsConst(codeSnips))
- code.append(snip.code());
+ return func->functionType() == AbstractMetaFunction::DecrementOperator;
+}
+
+// Filter predicate for operator functions
+static bool skipOperatorFunc(const AbstractMetaFunctionCPtr &func)
+{
+ if (func->isModifiedRemoved() || func->usesRValueReferences())
+ return true;
+ const auto &name = func->name();
+ return name == u"operator[]" || name == u"operator->" || name == u"operator!"
+ || name == u"operator/="; // __idiv__ is not needed in Python3
+}
+
+QList<AbstractMetaFunctionCList>
+ShibokenGenerator::filterGroupedOperatorFunctions(const AbstractMetaClassCPtr &metaClass,
+ OperatorQueryOptions query)
+{
+ // ( func_name, num_args ) => func_list
+ QMap<std::pair<QString, int>, AbstractMetaFunctionCList> results;
+ auto funcs = metaClass->operatorOverloads(query);
+ auto end = std::remove_if(funcs.begin(), funcs.end(), skipOperatorFunc);
+ funcs.erase(end, funcs.end());
+ // If we have operator+=, we remove the operator++/-- which would
+ // otherwise be used for emulating __iadd__, __isub__.
+ if (std::any_of(funcs.cbegin(), funcs.cend(), isInplaceAdd)) {
+ end = std::remove_if(funcs.begin(), funcs.end(),
+ [] (const AbstractMetaFunctionCPtr &func) {
+ return func->isIncDecrementOperator();
+ });
+ funcs.erase(end, funcs.end());
+ } else {
+ // If both prefix/postfix ++/-- are present, remove one
+ if (std::count_if(funcs.begin(), funcs.end(), isIncrementOperator) > 1)
+ funcs.erase(std::find_if(funcs.begin(), funcs.end(), isIncrementOperator));
+ if (std::count_if(funcs.begin(), funcs.end(), isDecrementOperator) > 1)
+ funcs.erase(std::find_if(funcs.begin(), funcs.end(), isDecrementOperator));
+ }
+ for (const auto &func : funcs) {
+ int args;
+ if (func->isComparisonOperator()) {
+ args = -1;
+ } else {
+ args = func->arguments().size();
+ }
+ auto op = std::make_pair(func->name(), args);
+ results[op].append(func);
+ }
+ QList<AbstractMetaFunctionCList> result;
+ result.reserve(results.size());
+ for (auto it = results.cbegin(), end = results.cend(); it != end; ++it)
+ result.append(it.value());
+ return result;
}
-static void getCode(QStringList &code, const TypeEntry *type)
+static bool hidesBaseClassFunctions(const AbstractMetaFunctionCPtr &f)
{
- getCode(code, type->codeSnips());
+ auto attributes = f->cppAttributes();
+ return !attributes.testFlag(FunctionAttribute::Override)
+ && !attributes.testFlag(FunctionAttribute::Final);
+}
- CustomConversion *customConversion = type->customConversion();
- if (!customConversion)
+void ShibokenGenerator::getInheritedOverloads(const AbstractMetaClassCPtr &scope,
+ AbstractMetaFunctionCList *overloads)
+{
+ if (overloads->isEmpty() || scope->isNamespace() || scope->baseClasses().isEmpty())
return;
- if (!customConversion->nativeToTargetConversion().isEmpty())
- code.append(customConversion->nativeToTargetConversion());
+ // PYSIDE-331: look also into base classes. Check for any non-overriding
+ // function hiding the base class functions.
+ const bool hideBaseClassFunctions =
+ std::any_of(overloads->cbegin(), overloads->cend(), hidesBaseClassFunctions);
- const CustomConversion::TargetToNativeConversions &toCppConversions = customConversion->targetToNativeConversions();
- if (toCppConversions.isEmpty())
- return;
+ const QString &functionName = overloads->constFirst()->name();
+ const bool hasUsingDeclarations = scope->hasUsingMemberFor(functionName);
+ if (hideBaseClassFunctions && !hasUsingDeclarations)
+ return; // No base function is visible
- for (CustomConversion::TargetToNativeConversion *toNative : qAsConst(toCppConversions))
- code.append(toNative->conversion());
+ // Collect base candidates by name and signature
+ bool staticEncountered = false;
+ QSet<QString> seenSignatures;
+ for (const auto &func : *overloads) {
+ seenSignatures.insert(func->minimalSignature());
+ staticEncountered |= func->isStatic();
+ }
+
+ AbstractMetaFunctionCList baseCandidates;
+
+ auto basePredicate = [&functionName, &seenSignatures, &baseCandidates]
+ (const AbstractMetaClassCPtr &b) {
+ for (const auto &f : b->functions()) {
+ if (f->generateBinding() && f->name() == functionName) {
+ const QString signature = f->minimalSignature();
+ if (!seenSignatures.contains(signature)) {
+ seenSignatures.insert(signature);
+ baseCandidates.append(f);
+ }
+ }
+ }
+ return false; // Keep going
+ };
+
+ for (const auto &baseClass : scope->baseClasses())
+ recurseClassHierarchy(baseClass, basePredicate);
+
+ // Remove the ones that are not made visible with using declarations
+ if (hideBaseClassFunctions && hasUsingDeclarations) {
+ const auto pred = [scope](const AbstractMetaFunctionCPtr &f) {
+ return !scope->isUsingMember(f->ownerClass(), f->name(), f->access());
+ };
+ auto end = std::remove_if(baseCandidates.begin(), baseCandidates.end(), pred);
+ baseCandidates.erase(end, baseCandidates.end());
+ }
+
+ // 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) {
+ auto end = std::remove_if(baseCandidates.begin(), baseCandidates.end(),
+ [](const AbstractMetaFunctionCPtr &f) { return f->isStatic(); });
+ baseCandidates.erase(end, baseCandidates.end());
+ }
+
+ for (const auto &baseCandidate : baseCandidates) {
+ AbstractMetaFunction *newFunc = baseCandidate->copy();
+ newFunc->setImplementingClass(scope);
+ overloads->append(AbstractMetaFunctionCPtr(newFunc));
+ }
}
-bool ShibokenGenerator::doSetup()
+QList<OptionDescription> ShibokenGenerator::options()
+{
+ return {
+ {DISABLE_VERBOSE_ERROR_MESSAGES,
+ u"Disable verbose error messages. Turn the python code hard to debug\n"
+ "but safe few kB on the generated bindings."_s},
+ {PARENT_CTOR_HEURISTIC,
+ u"Enable heuristics to detect parent relationship on constructors."_s},
+ {RETURN_VALUE_HEURISTIC,
+ u"Enable heuristics to detect parent relationship on return values\n"
+ "(USE WITH CAUTION!)"_s},
+ {USE_ISNULL_AS_NB_BOOL,
+ u"If a class have an isNull() const method, it will be used to compute\n"
+ "the value of boolean casts"_s},
+ {LEAN_HEADERS,
+ u"Forward declare classes in module headers"_s},
+ {USE_OPERATOR_BOOL_AS_NB_BOOL,
+ u"If a class has an operator bool, it will be used to compute\n"
+ "the value of boolean casts"_s},
+ {NO_IMPLICIT_CONVERSIONS,
+ u"Do not generate implicit_conversions for function arguments."_s},
+ {WRAPPER_DIAGNOSTICS,
+ u"Generate diagnostic code around wrappers"_s}
+ };
+}
+
+class ShibokenGeneratorOptionsParser : public OptionsParser
{
- 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);
- for (auto metaClass : api().classes())
- getCode(snips, metaClass->typeEntry());
+public:
+ explicit ShibokenGeneratorOptionsParser(ShibokenGeneratorOptions *o) : m_options(o) {}
- const TypeSystemTypeEntry *moduleEntry = TypeDatabase::instance()->defaultTypeSystemType();
- Q_ASSERT(moduleEntry);
- getCode(snips, moduleEntry);
+ bool handleBoolOption(const QString & key, OptionSource source) override;
- const auto &functionGroups = getGlobalFunctionGroups();
- for (auto it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
- for (const auto &func : it.value())
- getCode(snips, func->injectedCodeSnips());
- }
+private:
+ ShibokenGeneratorOptions *m_options;
+};
- for (const QString &code : qAsConst(snips)) {
- collectContainerTypesFromConverterMacros(code, true);
- collectContainerTypesFromConverterMacros(code, false);
+bool ShibokenGeneratorOptionsParser::handleBoolOption(const QString &key, OptionSource source)
+{
+ if (source == OptionSource::CommandLineSingleDash)
+ return false;
+ if (key == PARENT_CTOR_HEURISTIC)
+ return (m_options->useCtorHeuristic = true);
+ if (key == RETURN_VALUE_HEURISTIC)
+ return (m_options->userReturnValueHeuristic = true);
+ if (key == DISABLE_VERBOSE_ERROR_MESSAGES)
+ return (m_options->verboseErrorMessagesDisabled = true);
+ if (key == USE_ISNULL_AS_NB_BOOL || key == USE_ISNULL_AS_NB_NONZERO) {
+ return (m_options->useIsNullAsNbBool = true);
+ }
+ if (key == LEAN_HEADERS)
+ return (m_options->leanHeaders= true);
+ if (key == USE_OPERATOR_BOOL_AS_NB_BOOL || key == USE_OPERATOR_BOOL_AS_NB_NONZERO) {
+ return (m_options->useOperatorBoolAsNbBool = true);
+ }
+ if (key == NO_IMPLICIT_CONVERSIONS) {
+ m_options->generateImplicitConversions = false;
+ return true;
}
+ if (key == WRAPPER_DIAGNOSTICS)
+ return (m_options->wrapperDiagnostics = true);
+ return false;
+}
+
+std::shared_ptr<OptionsParser> ShibokenGenerator::createOptionsParser()
+{
+ return std::make_shared<ShibokenGeneratorOptionsParser>(&m_options);
+}
+bool ShibokenGenerator::doSetup()
+{
return true;
}
-void ShibokenGenerator::collectContainerTypesFromConverterMacros(const QString &code, bool toPythonMacro)
+bool ShibokenGenerator::useCtorHeuristic()
{
- QString convMacro = toPythonMacro ? QLatin1String("%CONVERTTOPYTHON[") : QLatin1String("%CONVERTTOCPP[");
- int offset = toPythonMacro ? sizeof("%CONVERTTOPYTHON") : sizeof("%CONVERTTOCPP");
- int start = 0;
- QString errorMessage;
- 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);
- auto type = buildAbstractMetaTypeFromString(typeString, &errorMessage);
- if (type.has_value()) {
- addInstantiatedContainersAndSmartPointers(type.value(), type->originalTypeDescription());
- } else {
- QString m;
- QTextStream(&m) << __FUNCTION__ << ": Cannot translate type \""
- << typeString << "\": " << errorMessage;
- throw Exception(m);
- }
- }
- start = end;
- }
+ return m_options.useCtorHeuristic;
}
-bool ShibokenGenerator::useCtorHeuristic() const
+bool ShibokenGenerator::useReturnValueHeuristic()
{
- return m_useCtorHeuristic;
+ return m_options.userReturnValueHeuristic;
}
-bool ShibokenGenerator::useReturnValueHeuristic() const
+bool ShibokenGenerator::useIsNullAsNbBool()
{
- return m_userReturnValueHeuristic;
+ return m_options.useIsNullAsNbBool;
}
-bool ShibokenGenerator::usePySideExtensions() const
+bool ShibokenGenerator::leanHeaders()
{
- return m_usePySideExtensions;
+ return m_options.leanHeaders;
}
-bool ShibokenGenerator::useIsNullAsNbNonZero() const
+bool ShibokenGenerator::useOperatorBoolAsNbBool()
{
- return m_useIsNullAsNbNonZero;
+ return m_options.useOperatorBoolAsNbBool;
}
-bool ShibokenGenerator::avoidProtectedHack() const
+bool ShibokenGenerator::generateImplicitConversions()
{
- return m_avoidProtectedHack;
+ return m_options.generateImplicitConversions;
}
QString ShibokenGenerator::moduleCppPrefix(const QString &moduleName)
{
QString result = moduleName.isEmpty() ? packageName() : moduleName;
- result.replace(QLatin1Char('.'), QLatin1Char('_'));
+ result.replace(u'.', u'_');
return result;
}
+QString ShibokenGenerator::cppApiVariableNameOld(const QString &moduleName)
+{
+ return "Sbk"_L1 + moduleCppPrefix(moduleName) + "Types"_L1;
+}
+
QString ShibokenGenerator::cppApiVariableName(const QString &moduleName)
{
- return QLatin1String("Sbk") + moduleCppPrefix(moduleName)
- + QLatin1String("Types");
+ return "Sbk"_L1 + moduleCppPrefix(moduleName) + "TypeStructs"_L1;
}
QString ShibokenGenerator::pythonModuleObjectName(const QString &moduleName)
{
- return QLatin1String("Sbk") + moduleCppPrefix(moduleName)
- + QLatin1String("ModuleObject");
+ return "Sbk"_L1 + moduleCppPrefix(moduleName) + "ModuleObject"_L1;
}
QString ShibokenGenerator::convertersVariableName(const QString &moduleName)
{
- QString result = cppApiVariableName(moduleName);
+ QString result = cppApiVariableNameOld(moduleName);
result.chop(1);
- result.append(QLatin1String("Converters"));
+ result.append(u"Converters"_s);
return result;
}
static QString processInstantiationsVariableName(const AbstractMetaType &type)
{
- QString res = QLatin1Char('_') + _fixedCppTypeName(type.typeEntry()->qualifiedCppName()).toUpper();
+ QString res = u'_' + _fixedCppTypeName(type.typeEntry()->qualifiedCppName());
for (const auto &instantiation : type.instantiations()) {
res += instantiation.isContainer()
? processInstantiationsVariableName(instantiation)
- : QLatin1Char('_') + _fixedCppTypeName(instantiation.cppSignature()).toUpper();
+ : u'_' + _fixedCppTypeName(instantiation.cppSignature());
}
return res;
}
static void appendIndexSuffix(QString *s)
{
- if (!s->endsWith(QLatin1Char('_')))
- s->append(QLatin1Char('_'));
- s->append(QStringLiteral("IDX"));
+ if (!s->endsWith(u'_'))
+ s->append(u'_');
+ s->append("IDX"_L1);
}
-QString ShibokenGenerator::getTypeAlternateTemplateIndexVariableName(const AbstractMetaClass *metaClass)
+QString
+ ShibokenGenerator::getTypeAlternateTemplateIndexVariableName(const AbstractMetaClassCPtr &metaClass)
{
- const AbstractMetaClass *templateBaseClass = metaClass->templateBaseClass();
+ const auto templateBaseClass = metaClass->templateBaseClass();
Q_ASSERT(templateBaseClass);
- QString result = QLatin1String("SBK_")
- + _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper();
+ QString result = u"SBK_"_s
+ + _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName());
for (const auto &instantiation : metaClass->templateBaseClassInstantiations())
result += processInstantiationsVariableName(instantiation);
appendIndexSuffix(&result);
return result;
}
-QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClass *metaClass)
+QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClassCPtr &metaClass)
{
return getTypeIndexVariableName(metaClass->typeEntry());
}
-QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry *type)
+QString ShibokenGenerator::getTypeIndexVariableName(TypeEntryCPtr type)
{
- if (type->isCppPrimitive()) {
- const auto *trueType = static_cast<const PrimitiveTypeEntry *>(type);
- if (trueType->basicReferencedTypeEntry())
- type = trueType->basicReferencedTypeEntry();
- }
- QString result = QLatin1String("SBK_");
+ if (isCppPrimitive(type))
+ type = basicReferencedTypeEntry(type);
+ QString result = u"SBK_"_s;
// Disambiguate namespaces per module to allow for extending them.
if (type->isNamespace()) {
QString package = type->targetLangPackage();
- const int dot = package.lastIndexOf(QLatin1Char('.'));
+ const int dot = package.lastIndexOf(u'.');
result += QStringView{package}.right(package.size() - (dot + 1));
}
- result += _fixedCppTypeName(type->qualifiedCppName()).toUpper();
+ result += _fixedCppTypeName(type->qualifiedCppName());
appendIndexSuffix(&result);
return result;
}
QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType &type)
{
- QString result = QLatin1String("SBK");
+ QString result = u"SBK"_s;
if (type.typeEntry()->isContainer())
- result += QLatin1Char('_') + moduleName().toUpper();
+ result += u'_' + moduleName();
result += processInstantiationsVariableName(type);
appendIndexSuffix(&result);
return result;
}
-bool ShibokenGenerator::verboseErrorMessagesDisabled() const
+void collectfromTypeEntry(TypeEntryCPtr entry, QStringList &typeNames)
{
- return m_verboseErrorMessagesDisabled;
+ if (entry->shouldGenerate()) {
+ typeNames[entry->sbkIndex()] = entry->qualifiedTargetLangName();
+ if (entry->isEnum()) {
+ auto ete = std::static_pointer_cast<const EnumTypeEntry>(entry);
+ if (ete->flags()) {
+ auto entry = ete->flags();
+ typeNames[entry->sbkIndex()] = entry->qualifiedTargetLangName();
+ }
+ }
+ }
}
-bool ShibokenGenerator::pythonFunctionWrapperUsesListOfArguments(const OverloadData &overloadData)
+void ShibokenGenerator::collectFullTypeNamesArray(QStringList &typeNames)
{
- 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();
+ for (const auto &metaClass : api().classes()) {
+ collectfromTypeEntry(metaClass->typeEntry(), typeNames);
+
+ for (const AbstractMetaEnum &metaEnum : metaClass->enums())
+ collectfromTypeEntry(metaEnum.typeEntry(), typeNames);
+
+ int smartPointerCountIndex = getMaxTypeIndex();
+ for (const auto &smp : api().instantiatedSmartPointers()) {
+ auto entry = smp.type.typeEntry();
+ typeNames[smartPointerCountIndex] =
+ smp.specialized->typeEntry()->qualifiedTargetLangName();
+ ++smartPointerCountIndex;
+ }
+ }
+ for (const AbstractMetaEnum &metaEnum : api().globalEnums())
+ collectfromTypeEntry(metaEnum.typeEntry(), typeNames);
}
-void ShibokenGenerator::writeMinimalConstructorExpression(TextStream &s,
- const ApiExtractorResult &api,
- const AbstractMetaType &type,
- const QString &defaultCtor)
+bool ShibokenGenerator::verboseErrorMessagesDisabled()
+{
+ return m_options.verboseErrorMessagesDisabled;
+}
+
+bool ShibokenGenerator::pythonFunctionWrapperUsesListOfArguments(const AbstractMetaFunctionCPtr &func) const
+{
+ const auto &groups = func->implementingClass()
+ ? getFunctionGroups(func->implementingClass())
+ : getGlobalFunctionGroups();
+ OverloadData od(groups.value(func->name()), api());
+ return od.pythonFunctionWrapperUsesListOfArguments();
+}
+
+QString ShibokenGenerator::minimalConstructorExpression(const ApiExtractorResult &api,
+ const AbstractMetaType &type)
{
- if (!defaultCtor.isEmpty()) {
- s << " = " << defaultCtor;
- return;
- }
if (type.isExtendedCppPrimitive() || type.isSmartPointer())
- return;
+ return {};
QString errorMessage;
const auto ctor = minimalConstructor(api, type, &errorMessage);
- if (ctor.has_value()) {
- s << ctor->initialization();
- } else {
- const QString message =
- msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__),
- type.cppSignature(), errorMessage);
- qCWarning(lcShiboken()).noquote() << message;
- s << ";\n#error " << message << '\n';
- }
+ if (ctor.has_value())
+ return ctor->initialization();
+
+ const QString message =
+ msgCouldNotFindMinimalConstructor(QLatin1StringView(__FUNCTION__),
+ type.cppSignature(), errorMessage);
+ qCWarning(lcShiboken()).noquote() << message;
+ return u";\n#error "_s + message + u'\n';
}
-void ShibokenGenerator::writeMinimalConstructorExpression(TextStream &s,
- const ApiExtractorResult &api,
- const TypeEntry *type,
- const QString &defaultCtor)
+QString ShibokenGenerator::minimalConstructorExpression(const ApiExtractorResult &api,
+ const TypeEntryCPtr &type)
{
- if (!defaultCtor.isEmpty()) {
- s << " = " << defaultCtor;
- return;
- }
- if (type->isExtendedCppPrimitive())
- return;
+ if (isExtendedCppPrimitive(type))
+ return {};
const auto ctor = minimalConstructor(api, type);
- if (ctor.has_value()) {
- s << ctor->initialization();
- } else {
- const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->qualifiedCppName());
- qCWarning(lcShiboken()).noquote() << message;
- s << ";\n#error " << message << '\n';
- }
+ if (ctor.has_value())
+ return ctor->initialization();
+
+ const QString message =
+ msgCouldNotFindMinimalConstructor(QLatin1StringView(__FUNCTION__),
+ type->qualifiedCppName());
+ qCWarning(lcShiboken()).noquote() << message;
+ return u";\n#error "_s + message + u'\n';
}
QString ShibokenGenerator::pythonArgsAt(int i)
{
- return QLatin1String(PYTHON_ARGS) + QLatin1Char('[')
- + QString::number(i) + QLatin1Char(']');
+ return PYTHON_ARGS + u'[' + QString::number(i) + u']';
}
void ShibokenGenerator::replaceTemplateVariables(QString &code,
const AbstractMetaFunctionCPtr &func) const
{
- const AbstractMetaClass *cpp_class = func->ownerClass();
+ const auto cpp_class = func->ownerClass();
if (cpp_class)
- code.replace(QLatin1String("%TYPE"), cpp_class->name());
+ code.replace(u"%TYPE"_s, cpp_class->name());
const AbstractMetaArgumentList &argument = func->arguments();
for (const AbstractMetaArgument &arg : argument)
- code.replace(QLatin1Char('%') + QString::number(arg.argumentIndex() + 1), arg.name());
+ code.replace(u'%' + 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());
+ code.replace(u"%RETURN_TYPE"_s, translateType(func->type(), cpp_class));
+ code.replace(u"%FUNCTION_NAME"_s, func->originalName());
- if (code.contains(QLatin1String("%ARGUMENT_NAMES"))) {
+ if (code.contains(u"%ARGUMENT_NAMES")) {
StringStream aux_stream;
writeArgumentNames(aux_stream, func, Generator::SkipRemovedArguments);
- code.replace(QLatin1String("%ARGUMENT_NAMES"), aux_stream);
+ code.replace(u"%ARGUMENT_NAMES"_s, aux_stream);
}
- if (code.contains(QLatin1String("%ARGUMENTS"))) {
+ if (code.contains(u"%ARGUMENTS")) {
StringStream aux_stream;
writeFunctionArguments(aux_stream, func, Options(SkipDefaultValues) | SkipRemovedArguments);
- code.replace(QLatin1String("%ARGUMENTS"), aux_stream);
+ code.replace(u"%ARGUMENTS"_s, aux_stream);
}
}
+
+QString ShibokenGenerator::stdMove(const QString &c)
+{
+ return u"std::move("_s + c + u')';
+}
diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.h b/sources/shiboken6/generator/shiboken/shibokengenerator.h
index ba904ea49..22ee73fa2 100644
--- a/sources/shiboken6/generator/shiboken/shibokengenerator.h
+++ b/sources/shiboken6/generator/shiboken/shibokengenerator.h
@@ -1,66 +1,42 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#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 "customconversion_typedefs.h"
+#include "abstractmetalang_enums.h"
+#include "typesystem_typedefs.h"
+#include "typesystem_enums.h"
#include <QtCore/QRegularExpression>
#include <array>
+#include <optional>
+class EnumTypeEntry;
+class FlagsTypeEntry;
class DocParser;
class CodeSnip;
class QPropertySpec;
class OverloadData;
-class TextStream;
+class TargetToNativeConversion;
struct GeneratorClassInfoCacheEntry;
+struct IncludeGroup;
+struct ShibokenGeneratorOptions;
-QT_FORWARD_DECLARE_CLASS(TextStream)
+class TextStream;
+
+// Function to be used for implementing nb_bool
+struct BoolCastFunction
+{
+ AbstractMetaFunctionCPtr function;
+ bool invert = false; // Function is "isNull()", (invert result).
+};
+
+using BoolCastFunctionOptional = std::optional<BoolCastFunction>;
/**
* Abstract generator that contains common methods used in CppGenerator and HeaderGenerator.
@@ -68,6 +44,29 @@ QT_FORWARD_DECLARE_CLASS(TextStream)
class ShibokenGenerator : public Generator
{
public:
+ Q_DISABLE_COPY_MOVE(ShibokenGenerator)
+
+ /// Besides the actual bindings (see AbstractMetaFunction::generateBinding(),
+ /// some functions need to be generated into the wrapper class
+ /// (virtual method/avoid protected hack expose).
+ enum class FunctionGenerationFlag
+ {
+ None = 0x0,
+ /// Virtual method overridable in Python
+ VirtualMethod = 0x1,
+ /// Special QObject virtuals
+ QMetaObjectMethod = 0x2,
+ /// Needs a protected wrapper for avoidProtectedHack()
+ /// public "foo_protected()" calling "foo()"
+ ProtectedWrapper = 0x4, //
+ /// Pass through constructor
+ WrapperConstructor = 0x8,
+ /// Generate a special copy constructor
+ /// "FooBar_Wrapper(const Foo&)" for constructing a wrapper from a value
+ WrapperSpecialCopyConstructor = 0x10
+ };
+ Q_DECLARE_FLAGS(FunctionGeneration, FunctionGenerationFlag);
+
enum class AttroCheckFlag
{
None = 0x0,
@@ -90,13 +89,18 @@ public:
const char *name() const override { return "Shiboken"; }
- /// Returns true if the user enabled PySide extensions.
- bool usePySideExtensions() const;
+ static QList<OptionDescription> options();
+ static std::shared_ptr<OptionsParser> createOptionsParser();
+
+ static QString minimalConstructorExpression(const ApiExtractorResult &api,
+ const AbstractMetaType &type);
+ static QString minimalConstructorExpression(const ApiExtractorResult &api,
+ const TypeEntryCPtr &type);
protected:
bool doSetup() override;
- GeneratorContext contextForClass(const AbstractMetaClass *c) const override;
+ GeneratorContext contextForClass(const AbstractMetaClassCPtr &c) const override;
/**
* Returns a map with all functions grouped, the function name is used as key.
@@ -104,7 +108,12 @@ protected:
* \param scope Where to search for functions, null means all global functions.
*/
FunctionGroups getGlobalFunctionGroups() const;
- static FunctionGroups getFunctionGroups(const AbstractMetaClass *scope);
+ static FunctionGroups getFunctionGroups(const AbstractMetaClassCPtr &scope);
+
+ static QList<AbstractMetaFunctionCList>
+ numberProtocolOperators(const AbstractMetaClassCPtr &scope);
+
+ static BoolCastFunctionOptional boolCast(const AbstractMetaClassCPtr &scope);
/**
* Returns all different inherited overloads of func, and includes func as well.
@@ -117,24 +126,26 @@ protected:
/// Write user's custom code snippets at class or module level.
void writeClassCodeSnips(TextStream &s,
- const CodeSnipList &codeSnips,
+ const QList<CodeSnip> &codeSnips,
TypeSystem::CodeSnipPosition position,
TypeSystem::Language language,
const GeneratorContext &context) const;
void writeCodeSnips(TextStream &s,
- const CodeSnipList &codeSnips,
+ const QList<CodeSnip> &codeSnips,
TypeSystem::CodeSnipPosition position,
TypeSystem::Language language) const;
/// Write user's custom code snippets at function level.
void writeCodeSnips(TextStream &s,
- const CodeSnipList &codeSnips,
+ const QList<CodeSnip> &codeSnips,
TypeSystem::CodeSnipPosition position,
TypeSystem::Language language,
const AbstractMetaFunctionCPtr &func,
- const AbstractMetaArgument *lastArg = nullptr) const;
+ bool usePyArgs,
+ const AbstractMetaArgument *lastArg) const;
/// Replaces variables for the user's custom code at global or class level.
void processCodeSnip(QString &code) const;
+ void processCodeSnip(QString &code, const QString &context) const;
void processClassCodeSnip(QString &code, const GeneratorContext &context) const;
/**
@@ -160,211 +171,166 @@ protected:
int arg_count = -1) const;
/// Returns the top-most class that has multiple inheritance in the ancestry.
- static const AbstractMetaClass *getMultipleInheritingClass(const AbstractMetaClass *metaClass);
+ static AbstractMetaClassCPtr
+ getMultipleInheritingClass(const AbstractMetaClassCPtr &metaClass);
- static bool useOverrideCaching(const AbstractMetaClass *metaClass);
- AttroCheck checkAttroFunctionNeeds(const AbstractMetaClass *metaClass) const;
+ static bool useOverrideCaching(const AbstractMetaClassCPtr &metaClass);
+ static AttroCheck checkAttroFunctionNeeds(const AbstractMetaClassCPtr &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.
+ /// 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.
static AbstractMetaFunctionCList
- getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass *metaClass);
+ getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClassCPtr &metaClass);
static void writeToPythonConversion(TextStream &s,
const AbstractMetaType &type,
- const AbstractMetaClass *context,
+ const AbstractMetaClassCPtr &context,
const QString &argumentName);
static void writeToCppConversion(TextStream &s,
const AbstractMetaType &type,
- const AbstractMetaClass *context,
const QString &inArgName,
const QString &outArgName);
static void writeToCppConversion(TextStream &s,
- const AbstractMetaClass *metaClass, const QString &inArgName,
+ const AbstractMetaClassCPtr &metaClass,
+ const QString &inArgName,
const QString &outArgName);
/// Returns true if the argument is a pointer that rejects nullptr values.
- static bool shouldRejectNullPointerArgument(const ApiExtractorResult &api,
- const AbstractMetaFunctionCPtr &func,
+ static bool shouldRejectNullPointerArgument(const AbstractMetaFunctionCPtr &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;
+ /// Verifies if the class should have a C++ wrapper generated for it,
+ /// instead of only a Python wrapper.
+ static bool shouldGenerateCppWrapper(const AbstractMetaClassCPtr &metaClass);
+
+ static bool shouldGenerateMetaObjectFunctions(const AbstractMetaClassCPtr &metaClass);
+
+ /// Returns which functions need to be generated into the wrapper class
+ static FunctionGeneration functionGeneration(const AbstractMetaFunctionCPtr &func);
+
+ // Return a list of implicit conversions if generation is enabled.
+ AbstractMetaFunctionCList implicitConversions(const TypeEntryCPtr &t) const;
- /// Condition to call WriteVirtualMethodNative. Was extracted because also used to count these calls.
- bool shouldWriteVirtualMethodNative(const AbstractMetaFunctionCPtr &func) const;
+ static QString wrapperName(const AbstractMetaClassCPtr &metaClass);
- QString wrapperName(const AbstractMetaClass *metaClass) const;
+ static QString fullPythonClassName(const AbstractMetaClassCPtr &metaClass);
+
+ static QString headerFileNameForContext(const GeneratorContext &context);
+ IncludeGroup baseWrapperIncludes(const GeneratorContext &classContext) const;
- static QString fullPythonClassName(const AbstractMetaClass *metaClass);
static QString fullPythonFunctionName(const AbstractMetaFunctionCPtr &func, bool forceFunc);
- bool wrapperDiagnostics() const { return m_wrapperDiagnostics; }
+ static bool wrapperDiagnostics();
static QString protectedEnumSurrogateName(const AbstractMetaEnum &metaEnum);
static QString pythonPrimitiveTypeName(const QString &cppTypeName);
- static QString pythonPrimitiveTypeName(const PrimitiveTypeEntry *type);
- static QString pythonOperatorFunctionName(const QString &cppOpFuncName);
static QString pythonOperatorFunctionName(const AbstractMetaFunctionCPtr &func);
- static QString pythonRichCompareOperatorId(const QString &cppOpFuncName);
- static QString pythonRichCompareOperatorId(const AbstractMetaFunctionCPtr &func);
+ static QList<AbstractMetaFunctionCList>
+ filterGroupedOperatorFunctions(const AbstractMetaClassCPtr &metaClass,
+ OperatorQueryOptions query);
- static QString fixedCppTypeName(const CustomConversion::TargetToNativeConversion *toNative);
+ static QString fixedCppTypeName(const TargetToNativeConversion &toNative);
static QString fixedCppTypeName(const AbstractMetaType &type);
- static QString fixedCppTypeName(const TypeEntry *type, QString typeName = QString());
+ static QString fixedCppTypeName(const TypeEntryCPtr &type, QString typeName = {});
static bool isNumber(const QString &cpythonApiName);
- static bool isNumber(const TypeEntry *type);
+ static bool isNumber(const TypeEntryCPtr &type);
static bool isNumber(const AbstractMetaType &type);
- static bool isPyInt(const TypeEntry *type);
+ static bool isPyInt(const TypeEntryCPtr &type);
static bool isPyInt(const AbstractMetaType &type);
- /// Returns whether the underlying type is a value type with copy constructor only
- static bool isValueTypeWithCopyConstructorOnly(const ApiExtractorResult &api,
- const TypeEntry *type);
- static bool isValueTypeWithCopyConstructorOnly(const ApiExtractorResult &api,
- const AbstractMetaType &type);
- /// Returns whether the type (function argument) is a value type with
- /// copy constructor only is passed as value or const-ref and thus
- /// no default value can be constructed.
- static bool valueTypeWithCopyConstructorOnlyPassed(const ApiExtractorResult &api,
- const AbstractMetaType &type);
-
static bool isNullPtr(const QString &value);
static QString converterObject(const AbstractMetaType &type) ;
- static QString converterObject(const TypeEntry *type);
+ static QString converterObject(const TypeEntryCPtr &type);
- static QString cpythonBaseName(const AbstractMetaClass *metaClass);
- static QString cpythonBaseName(const TypeEntry *type);
+ static QString cpythonBaseName(const AbstractMetaClassCPtr &metaClass);
+ static QString cpythonBaseName(const TypeEntryCPtr &type);
+ static QString containerCpythonBaseName(const ContainerTypeEntryCPtr &ctype);
static QString cpythonBaseName(const AbstractMetaType &type);
- static QString cpythonTypeName(const AbstractMetaClass *metaClass);
- static QString cpythonTypeName(const TypeEntry *type);
- static QString cpythonTypeNameExt(const TypeEntry *type);
- static QString cpythonTypeNameExt(const AbstractMetaType &type) ;
- QString cpythonCheckFunction(const TypeEntry *type, bool genericNumberType = false) const;
- QString cpythonCheckFunction(AbstractMetaType metaType, bool genericNumberType = false) const;
- /**
- * 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.
- */
- struct CPythonCheckFunctionResult
- {
- QString checkFunction;
- std::optional<AbstractMetaType> type;
- };
- static CPythonCheckFunctionResult guessCPythonCheckFunction(const QString &type);
- static QString cpythonIsConvertibleFunction(const ApiExtractorResult &api,
- const TypeEntry *type,
- bool genericNumberType = false,
- bool checkExact = false);
- QString cpythonIsConvertibleFunction(AbstractMetaType metaType,
- bool genericNumberType = false) const;
- QString cpythonIsConvertibleFunction(const AbstractMetaArgument &metaArg,
- bool genericNumberType = false) const;
-
- static QString cpythonToCppConversionFunction(const AbstractMetaClass *metaClass) ;
- static QString cpythonToCppConversionFunction(const AbstractMetaType &type,
- const AbstractMetaClass *context = nullptr);
- static QString cpythonToPythonConversionFunction(const AbstractMetaType &type,
- const AbstractMetaClass *context = nullptr);
- static QString cpythonToPythonConversionFunction(const AbstractMetaClass *metaClass);
- static QString cpythonToPythonConversionFunction(const TypeEntry *type);
+ static QString cpythonTypeName(const AbstractMetaClassCPtr &metaClass);
+ static QString cpythonTypeName(const TypeEntryCPtr &type);
+ static QString cpythonTypeNameExtSet(const TypeEntryCPtr &type);
+ static QString cpythonTypeNameExtSet(const AbstractMetaType &type);
+ static QString cpythonTypeNameExt(const TypeEntryCPtr &type);
+ static QString cpythonTypeNameExt(const AbstractMetaType &type);
+ static QString cpythonCheckFunction(TypeEntryCPtr type);
+ static QString cpythonCheckFunction(AbstractMetaType metaType);
+ static QString cpythonIsConvertibleFunction(const TypeEntryCPtr &type);
+ static QString cpythonIsConvertibleFunction(const AbstractMetaType &metaType);
+ static QString cpythonIsConvertibleFunction(const AbstractMetaArgument &metaArg);
+
+ static QString cpythonToCppConversionFunction(const AbstractMetaClassCPtr &metaClass) ;
+ static QString cpythonToCppConversionFunction(const AbstractMetaType &type);
+ static QString cpythonToPythonConversionFunction(const AbstractMetaType &type);
+ static QString cpythonToPythonConversionFunction(const AbstractMetaClassCPtr &metaClass);
+ static QString cpythonToPythonConversionFunction(const TypeEntryCPtr &type);
static QString cpythonFunctionName(const AbstractMetaFunctionCPtr &func) ;
static QString cpythonMethodDefinitionName(const AbstractMetaFunctionCPtr &func);
- static QString cpythonGettersSettersDefinitionName(const AbstractMetaClass *metaClass);
- static QString cpythonGetattroFunctionName(const AbstractMetaClass *metaClass);
- static QString cpythonSetattroFunctionName(const AbstractMetaClass *metaClass);
+ static QString cpythonGettersSettersDefinitionName(const AbstractMetaClassCPtr &metaClass);
+ static QString cpythonGetattroFunctionName(const AbstractMetaClassCPtr &metaClass);
+ static QString cpythonSetattroFunctionName(const AbstractMetaClassCPtr &metaClass);
static QString cpythonGetterFunctionName(const AbstractMetaField &metaField);
static QString cpythonSetterFunctionName(const AbstractMetaField &metaField);
static QString cpythonGetterFunctionName(const QPropertySpec &property,
- const AbstractMetaClass *metaClass);
+ const AbstractMetaClassCPtr &metaClass);
static QString cpythonSetterFunctionName(const QPropertySpec &property,
- const AbstractMetaClass *metaClass);
- static QString cpythonWrapperCPtr(const AbstractMetaClass *metaClass,
- const QString &argName = QLatin1String("self"));
- static QString cpythonWrapperCPtr(const AbstractMetaType &metaType,
+ const AbstractMetaClassCPtr &metaClass);
+ static QString cpythonWrapperCPtr(const AbstractMetaClassCPtr &metaClass,
+ const QString &argName = QLatin1StringView("self"));
+ static QString cpythonWrapperCPtr(const AbstractMetaType &metaType,
const QString &argName);
- static QString cpythonWrapperCPtr(const TypeEntry *type, const QString &argName);
-
- /// Guesses the scope to where belongs an argument's default value.
- QString guessScopeForDefaultValue(const AbstractMetaFunctionCPtr &func,
- const AbstractMetaArgument &arg) const;
- QString guessScopeForDefaultFlagsValue(const AbstractMetaFunctionCPtr &func,
- const AbstractMetaArgument &arg,
- const QString &value) const;
+ static QString cpythonWrapperCPtr(const TypeEntryCPtr &type, const QString &argName);
- static QString cpythonEnumName(const EnumTypeEntry *enumEntry);
+ static QString cpythonEnumName(const EnumTypeEntryCPtr &enumEntry);
static QString cpythonEnumName(const AbstractMetaEnum &metaEnum);
- static QString cpythonFlagsName(const FlagsTypeEntry *flagsEntry);
+ static QString cpythonFlagsName(const FlagsTypeEntryCPtr &flagsEntry);
static QString cpythonFlagsName(const AbstractMetaEnum *metaEnum);
- /// Returns the special cast function name, the function used to proper cast class with multiple inheritance.
- static QString cpythonSpecialCastFunctionName(const AbstractMetaClass *metaClass);
+ /// Returns the special cast function name, the function used to proper cast
+ /// class with multiple inheritance.
+ static QString cpythonSpecialCastFunctionName(const AbstractMetaClassCPtr &metaClass);
- static QString getFormatUnitString(const AbstractMetaFunctionCPtr &func, bool incRef = false);
-
- /// Returns the file name for the module global header. If no module name is provided the current will be used.
+ /// Returns the file name for the module global header. If no module name
+ /// is provided the current will be used.
static QString getModuleHeaderFileName(const QString &moduleName = QString());
static QString getPrivateModuleHeaderFileName(const QString &moduleName = QString());
- OptionDescriptions options() const override;
- bool handleOption(const QString &key, const QString &value) override;
+ /// Includes for header (native wrapper class) or binding source
+ QList<IncludeGroup> classIncludes(const AbstractMetaClassCPtr &metaClass) const;
/// Returns true if the user enabled the so called "parent constructor heuristic".
- bool useCtorHeuristic() const;
+ static bool useCtorHeuristic();
/// Returns true if the user enabled the so called "return value heuristic".
- bool useReturnValueHeuristic() const;
+ static bool useReturnValueHeuristic();
/// 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;
+ static bool useIsNullAsNbBool();
+ /// Whether to generate lean module headers
+ static bool leanHeaders();
+ /// Returns true if the generator should use operator bool to compute boolean casts.
+ static bool useOperatorBoolAsNbBool();
+ /// Generate implicit conversions of function arguments
+ static bool generateImplicitConversions();
+ static QString cppApiVariableNameOld(const QString &moduleName = {});
static QString cppApiVariableName(const QString &moduleName = QString());
static QString pythonModuleObjectName(const QString &moduleName = QString());
static QString convertersVariableName(const QString &moduleName = QString());
/// Returns the type index variable name for a given class.
- static QString getTypeIndexVariableName(const AbstractMetaClass *metaClass);
+ static QString getTypeIndexVariableName(const AbstractMetaClassCPtr &metaClass);
/// Returns the type index variable name for a given typedef for a template
/// class instantiation made of the template class and the instantiation values
- static QString getTypeAlternateTemplateIndexVariableName(const AbstractMetaClass *metaClass);
- static QString getTypeIndexVariableName(const TypeEntry *type);
+ static QString getTypeAlternateTemplateIndexVariableName(const AbstractMetaClassCPtr &metaClass);
+ static QString getTypeIndexVariableName(TypeEntryCPtr type);
static QString getTypeIndexVariableName(const AbstractMetaType &type) ;
- /// Returns true if the user don't want verbose error messages on the generated bindings.
- bool verboseErrorMessagesDisabled() const;
+ /// Collect all type names as an array for initializing the type/name struct.
+ void collectFullTypeNamesArray(QStringList &typeNames);
- /**
- * 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.
- */
- static std::optional<AbstractMetaType>
- buildAbstractMetaTypeFromString(QString typeSignature,
- QString *errorMessage = nullptr);
-
- /// Creates an AbstractMetaType object from a TypeEntry.
- static AbstractMetaType
- buildAbstractMetaTypeFromTypeEntry(const TypeEntry *typeEntry);
- /// Creates an AbstractMetaType object from an AbstractMetaClass.
- static AbstractMetaType
- buildAbstractMetaTypeFromAbstractMetaClass(const AbstractMetaClass *metaClass);
-
- static void writeMinimalConstructorExpression(TextStream &s, const ApiExtractorResult &api,
- const AbstractMetaType &type,
- const QString &defaultCtor = QString());
- static void writeMinimalConstructorExpression(TextStream &s, const ApiExtractorResult &api,
- const TypeEntry *type,
- const QString &defaultCtor = QString());
+ /// Returns true if the user don't want verbose error messages on the generated bindings.
+ static bool verboseErrorMessagesDisabled();
void collectContainerTypesFromConverterMacros(const QString &code, bool toPythonMacro);
@@ -372,42 +338,45 @@ protected:
const AbstractMetaFunctionCPtr &metaFunc,
Options options = NoOption);
- static void writeUnusedVariableCast(TextStream &s, const QString &variableName);
-
- AbstractMetaFunctionCList filterFunctions(const AbstractMetaClass *metaClass) const;
-
// 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 *, AbstractMetaClassCList>;
+ using ExtendedConverterData = QHash<TypeEntryCPtr, AbstractMetaClassCList>;
/// 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.
- static QList<const CustomConversion *> getPrimitiveCustomConversions() ;
+ static QList<CustomConversionPtr> getPrimitiveCustomConversions();
/// Returns true if the Python wrapper for the received OverloadData must accept a list of arguments.
- static bool pythonFunctionWrapperUsesListOfArguments(const OverloadData &overloadData);
+ bool pythonFunctionWrapperUsesListOfArguments(const AbstractMetaFunctionCPtr &func) const;
static const QRegularExpression &convertToCppRegEx()
{ return typeSystemConvRegExps()[TypeSystemToCppFunction]; }
static QString pythonArgsAt(int i);
- static const QHash<QString, QString> &formatUnits();
+ /// Return the format character for C++->Python->C++ conversion (Py_BuildValue)
+ static const QHash<QString, QChar> &formatUnits();
+
+ static QString stdMove(const QString &c);
private:
static QString getModuleHeaderFileBaseName(const QString &moduleName = QString());
static QString cpythonGetterFunctionName(const QString &name,
- const AbstractMetaClass *enclosingClass);
+ const AbstractMetaClassCPtr &enclosingClass);
static QString cpythonSetterFunctionName(const QString &name,
- const AbstractMetaClass *enclosingClass);
+ const AbstractMetaClassCPtr &enclosingClass);
- static const GeneratorClassInfoCacheEntry &getGeneratorClassInfo(const AbstractMetaClass *scope);
- static FunctionGroups getFunctionGroupsImpl(const AbstractMetaClass *scope);
- static bool classNeedsGetattroFunctionImpl(const AbstractMetaClass *metaClass);
+ static const GeneratorClassInfoCacheEntry &
+ getGeneratorClassInfo(const AbstractMetaClassCPtr &scope);
+ static FunctionGroups getFunctionGroupsImpl(const AbstractMetaClassCPtr &scope);
+ static QList<AbstractMetaFunctionCList>
+ getNumberProtocolOperators(const AbstractMetaClassCPtr &metaClass);
+ static BoolCastFunctionOptional getBoolCast(const AbstractMetaClassCPtr &metaClass);
+ static bool classNeedsGetattroFunctionImpl(const AbstractMetaClassCPtr &metaClass);
QString translateTypeForWrapperMethod(const AbstractMetaType &cType,
- const AbstractMetaClass *context,
+ const AbstractMetaClassCPtr &context,
Options opt = NoOption) const;
/**
@@ -416,16 +385,10 @@ private:
* \param func the metafunction to be searched in subclasses.
* \param seen the function's minimal signatures already seen.
*/
- static AbstractMetaFunctionCList getInheritedOverloads(const AbstractMetaFunctionCPtr & func,
- QSet<QString> *seen);
+ static void getInheritedOverloads(const AbstractMetaClassCPtr &scope,
+ AbstractMetaFunctionCList *overloads);
+
- /**
- * Returns all overloads for a function named \p functionName.
- * \param scope scope used to search for overloads.
- * \param functionName the function name.
- */
- AbstractMetaFunctionCList getFunctionOverloads(const AbstractMetaClass *scope,
- const QString &functionName) const;
/**
* Write a function argument in the C++ in the text stream \p s.
* This function just call \code s << argumentString(); \endcode
@@ -451,7 +414,7 @@ private:
QString functionReturnType(const AbstractMetaFunctionCPtr &func, Options options = NoOption) const;
/// Utility function for writeCodeSnips.
- using ArgumentVarReplacementPair = QPair<AbstractMetaArgument, QString>;
+ using ArgumentVarReplacementPair = std::pair<AbstractMetaArgument, QString>;
using ArgumentVarReplacementList = QList<ArgumentVarReplacementPair>;
static ArgumentVarReplacementList
getArgumentReplacement(const AbstractMetaFunctionCPtr &func,
@@ -459,7 +422,7 @@ private:
const AbstractMetaArgument *lastArg);
/// Returns a string with the user's custom code snippets that comply with \p position and \p language.
- static QString getCodeSnippets(const CodeSnipList &codeSnips,
+ static QString getCodeSnippets(const QList<CodeSnip> &codeSnips,
TypeSystem::CodeSnipPosition position,
TypeSystem::Language language);
@@ -513,13 +476,7 @@ private:
void replaceTemplateVariables(QString &code,
const AbstractMetaFunctionCPtr &func) 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;
- bool m_wrapperDiagnostics = false;
+ static ShibokenGeneratorOptions m_options;
/// Type system converter variable replacement names and regular expressions.
static const QHash<int, QString> &typeSystemConvName();
@@ -528,6 +485,7 @@ private:
static const TypeSystemConverterRegExps &typeSystemConvRegExps();
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(ShibokenGenerator::FunctionGeneration);
Q_DECLARE_OPERATORS_FOR_FLAGS(ShibokenGenerator::AttroCheck);
#endif // SHIBOKENGENERATOR_H