aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/generator/shiboken
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6/generator/shiboken')
-rw-r--r--sources/shiboken6/generator/shiboken/configurablescope.h33
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator.cpp6594
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator.h550
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator_container.cpp272
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp486
-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.cpp961
-rw-r--r--sources/shiboken6/generator/shiboken/headergenerator.h84
-rw-r--r--sources/shiboken6/generator/shiboken/overloaddata.cpp867
-rw-r--r--sources/shiboken6/generator/shiboken/overloaddata.h208
-rw-r--r--sources/shiboken6/generator/shiboken/pytypenames.h56
-rw-r--r--sources/shiboken6/generator/shiboken/shibokengenerator.cpp2525
-rw-r--r--sources/shiboken6/generator/shiboken/shibokengenerator.h403
16 files changed, 7322 insertions, 5995 deletions
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 51c6d051d..6c9cc5fec 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,114 @@
#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;
-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 +164,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,157 +181,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 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)
+// Return name of function to create PyObject wrapping a container
+static QString opaqueContainerCreationFunc(const AbstractMetaType &type)
{
- // ( 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)
{
- const auto *te = metaClass->typeEntry();
- auto mode = te->operatorBoolMode();
- if (useOperatorBoolAsNbNonZero()
- ? mode != TypeSystem::BoolCast::Disabled : mode == TypeSystem::BoolCast::Enabled) {
- const auto func = metaClass->findOperatorBool();
- if (!func.isNull())
- return func;
- }
-
- mode = te->isNullMode();
- if (useIsNullAsNbNonZero()
- ? mode != TypeSystem::BoolCast::Disabled : mode == TypeSystem::BoolCast::Enabled) {
- const auto func = metaClass->findQtIsNullMethod();
- if (!func.isNull())
- return func;
- }
- return {};
+ 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
@@ -322,13 +253,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;
}
@@ -336,133 +267,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();
+}
- s << "\n#include <cctype>\n#include <cstring>\n";
+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';
+ }
+ }
+ }
+}
- if (metaClass->typeEntry()->typeFlags() & ComplexTypeEntry::Deprecated)
+/// 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;
+ }
+
+ 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;
}
@@ -470,172 +582,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->ownerClass() == func->implementingClass()
- && func->generateBinding()) {
- // 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;
@@ -651,79 +700,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);
-
- const bool allowThread = f->allowThread();
- if (allowThread)
- s << "int result;\n" << BEGIN_ALLOW_THREADS << "\nresult = ";
- else
- s << "return ";
+ if ((attroCheck & AttroCheckFlag::GetattroMask) != 0)
+ writeGetattroFunction(s, attroCheck, classContext);
+ if ((attroCheck & AttroCheckFlag::SetattroMask) != 0)
+ writeSetattroFunction(s, attroCheck, classContext);
- if (f->isOperatorBool())
- s << '*' << CPP_SELF_VAR << " ? 1 : 0;\n";
- else
- s << CPP_SELF_VAR << "->isNull() ? 0 : 1;\n";
-
- if (allowThread)
- s << END_ALLOW_THREADS << "\nreturn result;\n";
- s << outdent << "}\n\n";
- }
+ if (const auto f = boolCast(metaClass) ; f.has_value())
+ writeNbBoolFunction(classContext, f.value(), s);
- 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;
-
- 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);
}
}
@@ -735,12 +749,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())
@@ -783,13 +797,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.
@@ -799,27 +813,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()
@@ -831,7 +856,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 << " : ";
@@ -841,14 +866,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;
@@ -860,64 +887,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()) {
- const auto *cte = static_cast<const ContainerTypeEntry *>(typeEntry);
+ 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")"_qs;
+ return uR"("set")"_s;
break;
case ContainerTypeEntry::MapContainer:
case ContainerTypeEntry::MultiMapContainer:
- return uR"("dict")"_qs;
+ return uR"("dict")"_s;
break;
case ContainerTypeEntry::PairContainer:
- return uR"("tuple")"_qs;
+ return uR"("tuple")"_s;
break;
}
- return uR"("list")"_qs;
+ 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
@@ -927,22 +941,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() << "::";
@@ -952,23 +970,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; ; ) {
@@ -976,7 +1001,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;
}
@@ -984,57 +1009,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()};
}
- if (returnType.referenceType() == LValueReference) {
- s << "static " << returnType.typeEntry()->qualifiedCppName()
- << " result;\n";
- return QLatin1String("return result;");
+
+ // 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";
}
- return QLatin1String("return ") + defaultReturnExpr->returnValue()
- + QLatin1Char(';');
+}
+
+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;
+ }
+
+ 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;
}
@@ -1043,10 +1189,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()) {
@@ -1058,240 +1204,269 @@ 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::storeErrorOrPrint();\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
{
@@ -1299,19 +1474,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) {
@@ -1319,12 +1496,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
@@ -1337,108 +1517,111 @@ 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;
-
- auto flags = reinterpret_cast<const EnumTypeEntry *>(enumType)->flags();
- if (!flags)
- 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";
+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 *tCppIn = reinterpret_cast<const " << typeName << R"( *>(cppIn);
+const char *typeName = )";
- QString flagsTypeName = fixedCppTypeName(flags);
- writePythonToCppFunction(s, c.toString(), typeName, flagsTypeName);
- writeIsPythonConvertibleToCppFunction(s, typeName, flagsTypeName, pyTypeCheck);
+ const QString nameFunc = metaClass->typeEntry()->polymorphicNameFunction();
+ 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())
@@ -1456,123 +1639,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;
@@ -1580,35 +1742,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()
@@ -1617,81 +1774,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();
}
@@ -1704,18 +1861,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();
@@ -1725,70 +1882,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);
@@ -1802,38 +1955,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();
@@ -1843,33 +1983,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(),
- overloadData.hasClassMethod());
+ 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";
@@ -1877,80 +2015,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";
}
@@ -1963,63 +2104,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) {
@@ -2030,125 +2175,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()) {
@@ -2160,24 +2284,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()) {
@@ -2196,47 +2317,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())
@@ -2244,8 +2352,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 << '"';
@@ -2255,187 +2363,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 hasClassMethodOverload,
- 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) {
- if (!hasClassMethodOverload) {
+ if (!flags.testFlag(HasStaticOverload)) {
+ if (!flags.testFlag(HasClassMethodOverload)) {
// PYSIDE-131: The single case of a class method for now: tr().
- s << "auto " << CPP_SELF_VAR << " = ";
+ writeCppSelfVarDef(s, flags);
writeCppSelfConversion(s, context, className, useWrapperClass);
- s << ";\n";
- writeUnusedVariableCast(s, QLatin1String(CPP_SELF_VAR));
+ 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,
- bool hasClassMethodOverload) 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, hasClassMethodOverload);
+ 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;
}
@@ -2443,14 +2551,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;
@@ -2474,19 +2588,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()))
@@ -2495,140 +2610,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)
@@ -2641,9 +2755,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 << " = ";
@@ -2651,43 +2765,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,
@@ -2699,10 +2818,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;
@@ -2711,7 +2830,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;
@@ -2721,7 +2840,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,
@@ -2730,7 +2850,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,
@@ -2743,45 +2864,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.
@@ -2789,8 +2911,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;
@@ -2798,13 +2920,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;
@@ -2812,15 +2934,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;
}
@@ -2831,58 +2953,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);
@@ -2891,14 +3009,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();
}
}
@@ -2908,14 +3026,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));
+ QString check = (isVarargs ? u"numArgs >= "_s : u"numArgs == "_s)
+ + QString::number(numArgs);
+ typeChecks.prepend(check);
} else if (usePyArgs && sequenceArgCount > 0) {
- typeChecks.prepend(QString::fromLatin1("numArgs >= %1").arg(startArg + sequenceArgCount));
+ 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);
}
@@ -2928,88 +3048,87 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(TextStream &s,
if (typeChecks.isEmpty()) {
s << "true";
} else {
- Indentation indent(s);
- s << typeChecks.join(QLatin1String("\n&& "));
+ s << indent << typeChecks.join(u"\n&& "_s) << outdent;
}
- s << ") {\n";
- {
- Indentation indent(s);
- writeOverloadedFunctionDecisorEngine(s, overloadData);
- }
- 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.
@@ -3024,24 +3143,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";
@@ -3051,34 +3172,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));
}
@@ -3088,9 +3209,10 @@ 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";
}
@@ -3113,53 +3235,66 @@ static void replaceCppToPythonVariables(QString &code, const QString &typeName,
bool constRef = false)
{
CodeSnipAbstract::prependCode(&code, writeCppInRef(typeName, constRef));
- code.replace(QLatin1String("%INTYPE"), typeName);
- code.replace(QLatin1String("%OUTTYPE"), QLatin1String("PyObject *"));
- code.replace(QLatin1String("%in"), QLatin1String("cppInRef"));
- code.replace(QLatin1String("%out"), QLatin1String("pyOut"));
+ 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 CustomConversion *customConversion) const
+void CppGenerator::writeCppToPythonFunction(TextStream &s,
+ const CustomConversionPtr &customConversion) const
{
QString code = customConversion->nativeToTargetConversion();
- auto *ownerType = 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), true);
- processCodeSnip(code);
- writeCppToPythonFunction(s, code, fixedCppTypeName(containerType));
+ 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";
}
@@ -3177,16 +3312,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,
@@ -3201,102 +3335,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())
@@ -3304,171 +3433,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();
}
- return pyArgName;
+
+ if (type.typeEntry()->isContainer()) {
+ // only support containers with 1 type
+ if (type.instantiations().size() == 1)
+ type = type.instantiations().constFirst();
+ }
+
+ 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()) {
@@ -3485,14 +3663,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.
@@ -3508,18 +3682,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;
@@ -3527,9 +3703,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.
@@ -3537,25 +3713,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
@@ -3565,19 +3742,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;
@@ -3588,17 +3765,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);
@@ -3611,7 +3785,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;
@@ -3626,31 +3800,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 {
@@ -3664,21 +3830,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 << ")->";
}
@@ -3687,7 +3854,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 {
@@ -3703,26 +3870,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'
@@ -3734,9 +3901,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";
@@ -3756,13 +3923,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;
@@ -3774,9 +3941,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";
@@ -3786,21 +3953,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";
}
@@ -3808,11 +3983,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;
@@ -3835,25 +4011,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
@@ -3865,11 +4027,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 << ");";
}
@@ -3877,7 +4037,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
@@ -3885,28 +4045,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(";
@@ -3916,25 +4057,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";
@@ -3947,248 +4091,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);
-
- 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";
- }
+ static const char enumPythonVar[] = "EType";
- if (flags) {
- QString enumTypeName = fixedCppTypeName(flags->originator());
- QString toCpp = pythonToCppFunctionName(enumTypeName, typeName);
- QString isConv = convertibleToCppFunctionName(enumTypeName, typeName);
- writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
- }
+ s << "// Register converter for enum '" << enumType->qualifiedCppName()
+ << "'.\n{\n" << indent;
- QString toCpp = pythonToCppFunctionName(typeName, typeName);
- QString isConv = convertibleToCppFunctionName(typeName, 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;
- if (flags) {
- QString toCpp = pythonToCppFunctionName(QLatin1String("number"), typeName);
- QString isConv = convertibleToCppFunctionName(QLatin1String("number"), typeName);
- writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
- }
+ 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";
- s << "Shiboken::Enum::setTypeConverter(" << enumPythonType
- << ", converter, " << (enumType->isFlags() ? "true" : "false") << ");\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();
- }
- }
+ 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
- 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";
-
- 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";
- }
- 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";
+ s << '&' << targetTypeName << "_Type";
}
- 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;
+}
+
+QString CppGenerator::typeInitStruct(const TypeEntryCPtr &te)
+{
+ return cppApiVariableName(te->targetLangPackage()) + u'['
+ + getTypeIndexVariableName(te) + u']';
}
-void CppGenerator::writeExtendedConverterInitialization(TextStream &s, const TypeEntry *externalType,
+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))
@@ -4198,7 +4297,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()
@@ -4207,18 +4306,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())
@@ -4236,63 +4335,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());
}
@@ -4304,53 +4397,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);
@@ -4361,39 +4460,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");
-
- const auto callOp = metaClass->findFunction(QLatin1String("operator()"));
- if (!callOp.isNull() && !callOp->isModifiedRemoved())
- tp_call = QLatin1Char('&') + cpythonFunctionName(callOp);
+ if (hasHashFunction(metaClass))
+ tp_hash = u'&' + cpythonBaseName(metaClass) + u"_HashFunc"_s;
- 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);
@@ -4406,63 +4499,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";
}
@@ -4474,26 +4566,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;
}
}
@@ -4502,46 +4594,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());
}
}
@@ -4549,106 +4637,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, 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);
@@ -4657,19 +4742,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);
@@ -4683,9 +4770,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);
@@ -4696,6 +4782,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')');
@@ -4703,44 +4800,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 = ";
@@ -4750,57 +4844,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);
@@ -4831,220 +4920,182 @@ 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, 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))) {
+ && !invisibleTopNamespaces().contains(std::const_pointer_cast<AbstractMetaClass>(ownerClass))) {
if (overloadData.hasStaticFunction())
- s << "|METH_STATIC";
+ result.append(QByteArrayLiteral("METH_STATIC"));
if (overloadData.hasClassMethod())
- s << "|METH_CLASS";
+ 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 << '}';
- }
-}
-void CppGenerator::writeMethodDefinition(TextStream &s, const AbstractMetaFunctionCList &overloads) const
-{
- Q_ASSERT(!overloads.isEmpty());
- const auto func = overloads.constFirst();
- if (m_tpFuncs.contains(func->name()))
- return;
+ const QStringList names = overloadData.referenceFunction()->definitionNames();
+ const QString funcName = cpythonFunctionName(overloadData.referenceFunction());
+ const QByteArrayList parameters = methodDefinitionParameters(overloadData);
- if (OverloadData::hasStaticAndInstanceFunctions(overloads)) {
- s << cpythonMethodDefinitionName(func);
- } else {
- writeMethodDefinitionEntries(s, overloads);
- }
- s << ',' << '\n';
+ QList<PyMethodDefEntry> result;
+ result.reserve(names.size());
+ for (const auto &name : names)
+ result.append({name, funcName, parameters, {}});
+ return result;
}
// Format the type signature of a function parameter
@@ -5082,204 +5133,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 = f->type().pythonSignature();
+ 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();
@@ -5301,151 +5377,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,
@@ -5459,7 +5415,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";
@@ -5468,13 +5424,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)
@@ -5486,125 +5442,154 @@ 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);
@@ -5619,14 +5604,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"
@@ -5635,15 +5620,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())
@@ -5664,26 +5653,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()
@@ -5692,12 +5695,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())
@@ -5705,10 +5755,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();
}
@@ -5718,69 +5768,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 ("
@@ -5793,7 +5848,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;
@@ -5803,7 +5859,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";
@@ -5813,7 +5869,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.
@@ -5823,62 +5879,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;
@@ -5888,11 +5918,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;
}
@@ -5901,68 +5931,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;
}
}
@@ -5970,106 +5981,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 TypeEntryCPtr &enclosingEntry,
+ const QString &pythonName, bool lazy)
{
- const bool hasParent =
- enclosingEntry && enclosingEntry->type() != TypeEntry::TypeSystemType;
- declStr << "void init_" << initFunctionName << "(PyObject *"
+ const QString functionName = "init_"_L1 + initFunctionName;
+ const bool hasParent = enclosingEntry && enclosingEntry->type() != TypeEntry::TypeSystemType;
+ declStr << "PyTypeObject *" << functionName << "(PyObject *"
<< (hasParent ? "enclosingClass" : "module") << ");\n";
- callStr << "init_" << initFunctionName;
- if (hasParent) {
- callStr << "(reinterpret_cast<PyTypeObject *>("
- << cpythonTypeNameExt(enclosingEntry) << ")->tp_dict);\n";
+
+ 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);
+ callStr << "Shiboken::Module::AddTypeCreationFunction("
+ << "module, \"" << pythonName << "\", " << functionName << ", \"";
+ for (qsizetype i = 0; i < parts.size(); ++i) {
+ if (i > 0)
+ callStr << "\", \"";
+ callStr << parts.at(i);
+ }
+ callStr << "\");\n";
} else {
- callStr << "(module);\n";
+ callStr << "Shiboken::Module::AddTypeCreationFunction("
+ << "module, \"" << pythonName << "\", "
+ << "init_" << initFunctionName << ");\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())
@@ -6077,36 +6100,73 @@ 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)) {
+ 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';
+ }
writeInitFunc(s_classInitDecl, s_classPythonDefines,
getSimpleClassInitFunctionName(cls),
- cls->typeEntry()->targetLangEnclosingEntry());
+ 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);
+ for (const auto &smp : api().instantiatedSmartPointers()) {
+ GeneratorContext context = contextForSmartPointer(smp.specialized, smp.type);
+ const auto enclosingClass = context.metaClass()->enclosingClass();
+ auto enclosingTypeEntry = enclosingClass
+ ? enclosingClass->typeEntry()
+ : targetLangEnclosingEntry(smp.type.typeEntry());
+
writeInitFunc(s_classInitDecl, s_classPythonDefines,
getInitFunctionName(context),
- metaType.typeEntry()->targetLangEnclosingEntry());
+ enclosingTypeEntry, smp.type.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());
+ }
+
+ 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() + QLatin1Char('/') + subDirectoryForPackage(packageName()));
- moduleFileName += QLatin1Char('/') + moduleName().toLower() + QLatin1String("_module_wrapper.cpp");
+ QString moduleFileName(outputDirectory() + u'/' + subDirectoryForPackage(packageName()));
+ moduleFileName += u'/' + moduleName().toLower() + u"_module_wrapper.cpp"_s;
FileOut file(moduleFileName);
@@ -6120,60 +6180,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 "
@@ -6181,7 +6259,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';
@@ -6191,12 +6269,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 "
@@ -6206,7 +6280,6 @@ bool CppGenerator::finishGeneration()
<< "} // namespace Shiboken\n\n";
}
- writeFlagsNumberMethodsDefinitions(s, globalEnums);
s << '\n';
}
@@ -6214,31 +6287,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);
@@ -6246,23 +6317,32 @@ 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);
+ if (container.generateOpaqueContainer()) {
+ auto data = writeOpaqueContainerConverterFunctions(s, container,
+ &valueConverters);
+ opaqueContainers.insert(container, data);
+ }
}
s << '\n';
}
// Implicit smart pointers conversions
- const auto smartPointersList = instantiatedSmartPointers();
+ const auto &smartPointersList = api().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);
+ for (const auto &smp : smartPointersList) {
+ s << "// C++ to Python conversion for smart pointer type '"
+ << smp.type.cppSignature() << "'.\n";
+ writeSmartPointerConverterFunctions(s, smp.type);
}
s << '\n';
}
@@ -6281,6 +6361,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_"
@@ -6289,10 +6371,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
@@ -6306,11 +6387,27 @@ 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"
+ << "// The backward compatible alias with upper case indexes.\n"
+ << cppApiVariableNameOld() << " = reinterpret_cast<PyTypeObject **>(cppApi);\n\n";
}
s << "// Create an array of primitive type converters for the current module.\n"
@@ -6320,13 +6417,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';
}
@@ -6335,15 +6437,29 @@ 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 (!opaqueContainers.isEmpty()) {
+ s << "\n// Opaque container type registration\n"
+ << "PyObject *ob_type{};\n";
+ for (const auto &d : opaqueContainers)
+ s << d.registrationCode;
+ s << '\n';
+ }
+
if (!smartPointersList.isEmpty()) {
s << '\n';
- for (const AbstractMetaType &smartPointer : smartPointersList) {
- writeSmartPointerConverterInitialization(s, smartPointer);
+ for (const auto &smp : smartPointersList) {
+ writeSmartPointerConverterInitialization(s, smp.type);
s << '\n';
}
}
@@ -6359,21 +6475,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';
@@ -6385,27 +6494,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";
}
@@ -6413,19 +6524,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;
}
@@ -6438,16 +6541,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;
@@ -6455,10 +6577,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;
}
}
@@ -6470,28 +6594,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;
}
@@ -6499,15 +6627,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);
@@ -6521,27 +6650,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";
@@ -6550,21 +6692,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"
@@ -6581,29 +6724,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"
@@ -6612,25 +6751,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);
@@ -6641,27 +6783,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 00035c5ae..a31c2ca14 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,105 +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:
+ 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 writeInitFunc(TextStream &declStr, TextStream &callStr,
const QString &initFunctionName,
- const TypeEntry *enclosingEntry = nullptr);
+ 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,
- bool hasClassMethodOverload = false) const;
- void writeCppSelfDefinition(TextStream &s,
- const GeneratorContext &context,
- bool hasStaticOverload = false,
- bool hasClassMethodOverload = 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,
@@ -149,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;
@@ -201,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());
@@ -223,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,
@@ -257,135 +348,152 @@ 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;
/// 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);
@@ -395,63 +503,65 @@ 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(); }
+ 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(); }
std::optional<AbstractMetaType>
- findSmartPointerInstantiation(const TypeEntry *entry) const;
-
+ findSmartPointerInstantiation(const SmartPointerTypeEntryCPtr &pointer,
+ const TypeEntryCPtr &pointee) const;
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..1b893640a
--- /dev/null
+++ b/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp
@@ -0,0 +1,486 @@
+// 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;
+}
+
+std::optional<AbstractMetaType>
+ CppGenerator::findSmartPointerInstantiation(const SmartPointerTypeEntryCPtr &pointer,
+ const TypeEntryCPtr &pointee) const
+{
+ for (const auto &smp : api().instantiatedSmartPointers()) {
+ const auto &i = smp.type;
+ if (i.typeEntry() == pointer && i.instantiations().at(0).typeEntry() == pointee)
+ return i;
+ }
+ return {};
+}
+
+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);
+ 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 = findSmartPointerInstantiation(smartPointerTypeEntry, baseTe)) {
+ const auto smartTargetType = opt.value();
+ 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 = findSmartPointerInstantiation(smartPointerTypeEntry, baseTe)) {
+ const auto smartTargetType = opt.value();
+ 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..1f574b47c 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,181 @@ 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;
+
+ // write license comment
+ s << licenseComment();
+
+ // 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';
+ }
+
+ 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, metaClass->typeEntry()->codeSnips(),
- TypeSystem::CodeSnipPositionDeclaration, TypeSystem::NativeCode,
- classContext);
+ 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 +293,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 +312,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"));
- }
- // pure virtual functions need a default implementation
- const bool notAbstract = !func->isAbstract();
- if ((func->isPrivate() && notAbstract && !func->isVisibilityModifiedToPrivate())
- || (func->isModifiedRemoved() && notAbstract))
- return;
+ if (generation.testFlag(FunctionGenerationFlag::ProtectedWrapper))
+ writeMemberFunctionWrapper(s, func, u"_protected"_s);
- if (avoidProtectedHack() && func->ownerClass()->hasPrivateDestructor()
- && (func->isAbstract() || func->isVirtual()))
+ if (generation.testFlag(FunctionGenerationFlag::WrapperConstructor)) {
+ Options option = func->hasSignatureModifications()
+ ? Generator::OriginalTypeDescription : Generator::NoOption;
+ s << functionSignature(func, {}, {}, option) << ";\n";
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 +366,7 @@ void HeaderGenerator::writeFunction(TextStream &s, const AbstractMetaFunctionCPt
&& !f->isAbstract()
&& !f->isStatic()
&& f->name() == func->name()) {
- m_inheritedOverloads << f;
+ inheritedOverloads->insert(f);
}
}
@@ -318,28 +376,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 +393,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 +416,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 +438,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 +456,258 @@ 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";
+}
+
+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';
+}
+
+// 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;
+}
- std::sort(classList.begin(), classList.end(), [](const AbstractMetaClass *a, const AbstractMetaClass *b) {
- return a->typeEntry()->sbkIndex() < b->typeEntry()->sbkIndex();
- });
+struct ModuleHeaderParameters
+{
+ AbstractMetaClassCList forwardDeclarations;
+ std::set<Include> includes;
+ ConditionalIncludeMap conditionalIncludes;
+ QString typeFunctions;
+};
+
+HeaderGenerator::IndexValues
+ HeaderGenerator::collectTypeIndexes(const AbstractMetaClassCList &classList)
+{
+ IndexValues result;
- for (const AbstractMetaClass *metaClass : classList)
- writeTypeIndexValueLines(macrosStream, api(), metaClass);
+ 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;
+}
+
+// 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";
- _writeTypeIndexValue(macrosStream,
- QLatin1String("SBK_") + moduleName() + QLatin1String("_IDX_COUNT"),
- getMaxTypeIndex() + smartPointerCount);
- macrosStream << "\n};\n";
+ macrosStream << "\n// Type indices\nenum : int {\n";
+ for (const auto &ti : typeIndexes)
+ macrosStream << ti;
+ macrosStream << "};\n\n";
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 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 +715,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 +732,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 +780,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 +806,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 +849,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 +871,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 468906d37..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(" >");
-}
-
-// 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;
+ return containerType.typeEntry()->qualifiedCppName() + u'<'
+ + types.join(u", "_s) + u" >"_s;
}
-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);
- for (OverloadData *ov : qAsConst(m_nextOverloadData)) {
+ 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 (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,15 +518,6 @@ bool OverloadData::hasVarargs() const
return false;
}
-bool OverloadData::hasAllowThread() const
-{
- for (const auto &func : m_overloads) {
- if (func->allowThread())
- return true;
- }
- return false;
-}
-
bool OverloadData::hasStaticFunction(const AbstractMetaFunctionCList &overloads)
{
for (const auto &func : overloads) {
@@ -641,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++;
@@ -663,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
+AbstractMetaFunctionCPtr OverloadDataRootNode::getFunctionWithDefaultValue() const
{
- AbstractMetaFunctionCList overloads = m_overloads;
+ const qsizetype argpos = argPos();
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
-{
- 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 {};
@@ -755,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())
@@ -770,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);
}
@@ -778,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
@@ -985,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;
@@ -999,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;
}
@@ -1007,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())
@@ -1017,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).data();
- }
- 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 89e56caa4..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 OverloadDataNode;
+using OverloadDataNodePtr = std::shared_ptr<OverloadDataNode>;
+using OverloadDataList = QList<OverloadDataNodePtr>;
+
+/// The root node of OverloadData. It contains all functions
+class OverloadDataRootNode
+{
+public:
+ 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;
+
+ const AbstractMetaFunctionCList &overloads() const { return m_overloads; }
+ const OverloadDataList &children() const { return m_children; }
+
+ 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
+
+ OverloadDataNode *addOverloadDataNode(const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgument &arg);
+
+protected:
+ OverloadDataRootNode(const AbstractMetaFunctionCList &o= {});
-class OverloadData;
-using OverloadDataList = QList<OverloadData *>;
+ void dumpRootGraph(QTextStream &s, int minArgs, int maxArgs) const;
+ void sortNextOverloads(const ApiExtractorResult &api);
-class OverloadData
+
+#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:
- OverloadData(const AbstractMetaFunctionCList &overloads,
- const ApiExtractorResult &api);
- ~OverloadData();
+ 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;
- int minArgs() const { return m_headOverloadData->m_minArgs; }
- int maxArgs() const { return m_headOverloadData->m_maxArgs; }
- int argPos() const { return m_argPos; }
+ const AbstractMetaArgument &argument() const
+ { return m_argument; }
+ const AbstractMetaType &argType() const { return m_argument.type(); }
+ const AbstractMetaType &modifiedArgType() const { return m_argument.modifiedType(); }
- const AbstractMetaType &argType() const { return m_argType; }
+ bool isTypeModified() const { return m_argument.isTypeModified(); }
- /// Returns a string list containing all the possible return types (including void) for the current OverloadData.
- QStringList returnTypes() const;
+ 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,9 +125,6 @@ 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;
@@ -88,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);
@@ -130,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 d52f4fb50..a1417e5d9 100644
--- a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
@@ -1,136 +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 USE_OPERATOR_BOOL_AS_NB_NONZERO[] = "use-operator-bool-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\[([^\[]*)\]\()";
@@ -143,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;
@@ -159,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());
@@ -227,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)
@@ -235,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;
@@ -278,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)
@@ -307,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;
@@ -325,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)
@@ -369,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);
}
@@ -383,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());
}
@@ -544,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);
@@ -574,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()) {
@@ -635,193 +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:
- //baseName = "PyList";
- //break;
- case ContainerTypeEntry::PairContainer:
- //baseName = "PyTuple";
- baseName = cPySequenceT();
- break;
- case ContainerTypeEntry::SetContainer:
- baseName = QLatin1String("PySet");
- break;
- case ContainerTypeEntry::MapContainer:
- case ContainerTypeEntry::MultiMapContainer:
- 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())
+ if (isExtendedCppPrimitive(type))
return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()")
.arg(type->qualifiedCppName());
if (type->isWrapperType())
- return QString::fromLatin1("PepType_SOTP(reinterpret_cast<SbkObjectType *>(%1))->converter")
+ return QString::fromLatin1("PepType_SOTP(reinterpret_cast<PyTypeObject *>(%1))->converter")
.arg(cpythonTypeNameExt(type));
- if (type->isEnum())
+ if (type->isEnum() || type->isFlags())
return QString::fromLatin1("PepType_SETP(reinterpret_cast<SbkEnumType *>(%1))->converter")
.arg(cpythonTypeNameExt(type));
- if (type->isFlags())
- return QString::fromLatin1("PepType_PFTP(reinterpret_cast<PySideQFlagsType *>(%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()) + u'['
+ + getTypeIndexVariableName(type) + "].type"_L1;
+}
+
+QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntryCPtr &type)
{
- return cppApiVariableName(type.typeEntry()->targetLangPackage()) + QLatin1Char('[')
- + getTypeIndexVariableName(type) + QLatin1Char(']');
+ return "Shiboken::Module::get("_L1 + cppApiVariableName(type->targetLangPackage())
+ + u'[' + getTypeIndexVariableName(type) + "])"_L1;
}
-static inline QString unknownOperator() { return QStringLiteral("__UNKNOWN_OPERATOR__"); }
+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)
{
@@ -830,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);
@@ -853,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)
@@ -974,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)
@@ -987,69 +868,48 @@ 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::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
@@ -1057,250 +917,218 @@ QString ShibokenGenerator::cpythonCheckFunction(AbstractMetaType metaType,
QString pyType;
if (type == ContainerTypeEntry::PairContainer)
- pyType = u"Pair"_qs;
+ pyType = u"Pair"_s;
else if (type == ContainerTypeEntry::MultiMapContainer)
- pyType = u"MultiDict"_qs;
+ pyType = u"MultiDict"_s;
else
- pyType = u"Dict"_qs;
+ 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"), {}};
-
- if (type == cPyBufferT())
- return {QLatin1String("Shiboken::Buffer::checkType"), {}};
-
- if (type == pyStrT())
- return {QLatin1String("Shiboken::String::check"), {}};
+ return u"SbkObject_TypeCheck("_s + cpythonTypeNameExt(type) + u", "_s;
- if (type == cPyArrayObjectT())
- return {QLatin1String("PyArray_Check"), {}};
+ if (type->isPrimitive())
+ type = basicReferencedTypeEntry(type);
- // 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;
@@ -1318,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)) {
@@ -1344,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);
}
@@ -1358,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
@@ -1389,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;
}
@@ -1415,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;
@@ -1473,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;
}
@@ -1494,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;
}
@@ -1532,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
@@ -1557,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,
@@ -1566,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 {
@@ -1635,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";
}
@@ -1775,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);
}
}
@@ -1789,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);
}
@@ -1819,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()) {
@@ -1832,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";
}
@@ -1864,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();
}
@@ -1877,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 '('.
@@ -1896,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;
@@ -1917,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
@@ -1938,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),
@@ -1951,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;
@@ -1960,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 << ')';
@@ -1984,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;
}
@@ -2007,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);
}
@@ -2026,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())
@@ -2038,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()) {
@@ -2061,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;
@@ -2073,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;
@@ -2089,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()
@@ -2106,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()
@@ -2130,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;
@@ -2141,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()});
+
+ result.append({u"Enum includes"_s, {}});
+ for (const auto &cppEnum : metaClass->enums())
+ result.back().includes.append(cppEnum.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"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()
@@ -2250,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
@@ -2295,402 +2110,540 @@ 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 inFunctions = basis->findFunctions(func->name());
- for (const auto &inFunc : inFunctions) {
- if (inFunc->generateBinding()
- && !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(USE_OPERATOR_BOOL_AS_NB_NONZERO),
- QLatin1String("If a class has an operator bool, 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(USE_OPERATOR_BOOL_AS_NB_NONZERO))
- return (m_useOperatorBoolAsNbNonZero = 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();
+ }
-bool ShibokenGenerator::doSetup()
-{
- QStringList snips;
- const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes();
- for (const PrimitiveTypeEntry *type : primitiveTypeList)
- getCode(snips, type);
- const ContainerTypeEntryList &containerTypeList = containerTypes();
- for (const ContainerTypeEntry *type : containerTypeList)
- getCode(snips, type);
- for (auto metaClass : api().classes())
- getCode(snips, metaClass->typeEntry());
+ AbstractMetaFunctionCList baseCandidates;
- const TypeSystemTypeEntry *moduleEntry = TypeDatabase::instance()->defaultTypeSystemType();
- Q_ASSERT(moduleEntry);
- getCode(snips, moduleEntry);
+ 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);
- 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());
+ // 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());
}
- for (const QString &code : qAsConst(snips)) {
- collectContainerTypesFromConverterMacros(code, true);
- collectContainerTypesFromConverterMacros(code, false);
+ // 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());
}
- return true;
+ for (const auto &baseCandidate : baseCandidates) {
+ AbstractMetaFunction *newFunc = baseCandidate->copy();
+ newFunc->setImplementingClass(scope);
+ overloads->append(AbstractMetaFunctionCPtr(newFunc));
+ }
}
-void ShibokenGenerator::collectContainerTypesFromConverterMacros(const QString &code, bool toPythonMacro)
+QList<OptionDescription> ShibokenGenerator::options()
{
- 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 {
+ {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
+{
+public:
+ explicit ShibokenGeneratorOptionsParser(ShibokenGeneratorOptions *o) : m_options(o) {}
+
+ bool handleBoolOption(const QString & key, OptionSource source) override;
+
+private:
+ ShibokenGeneratorOptions *m_options;
+};
+
+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;
}
-bool ShibokenGenerator::useCtorHeuristic() const
+bool ShibokenGenerator::useCtorHeuristic()
{
- return m_useCtorHeuristic;
+ return m_options.useCtorHeuristic;
}
-bool ShibokenGenerator::useReturnValueHeuristic() const
+bool ShibokenGenerator::useReturnValueHeuristic()
{
- return m_userReturnValueHeuristic;
+ return m_options.userReturnValueHeuristic;
}
-bool ShibokenGenerator::usePySideExtensions() const
+bool ShibokenGenerator::useIsNullAsNbBool()
{
- return m_usePySideExtensions;
+ return m_options.useIsNullAsNbBool;
}
-bool ShibokenGenerator::useIsNullAsNbNonZero() const
+bool ShibokenGenerator::leanHeaders()
{
- return m_useIsNullAsNbNonZero;
+ return m_options.leanHeaders;
}
-bool ShibokenGenerator::useOperatorBoolAsNbNonZero() const
+bool ShibokenGenerator::useOperatorBoolAsNbBool()
{
- return m_useOperatorBoolAsNbNonZero;
+ 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] = entry->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 c4c93a600..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,213 +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;
+ 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.
- bool useOperatorBoolAsNbNonZero() const;
- /// Returns true if the generated code should use the "#define protected public" hack.
- bool avoidProtectedHack() const;
+ 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);
@@ -374,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;
/**
@@ -418,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
@@ -453,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,
@@ -461,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);
@@ -515,14 +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_useOperatorBoolAsNbNonZero = 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();
@@ -531,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