aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/generator/shiboken2
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2/generator/shiboken2')
-rw-r--r--sources/shiboken2/generator/shiboken2/CMakeLists.txt28
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp5755
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.h370
-rw-r--r--sources/shiboken2/generator/shiboken2/headergenerator.cpp569
-rw-r--r--sources/shiboken2/generator/shiboken2/headergenerator.h67
-rw-r--r--sources/shiboken2/generator/shiboken2/overloaddata.cpp1092
-rw-r--r--sources/shiboken2/generator/shiboken2/overloaddata.h163
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.cpp2728
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.h556
9 files changed, 11328 insertions, 0 deletions
diff --git a/sources/shiboken2/generator/shiboken2/CMakeLists.txt b/sources/shiboken2/generator/shiboken2/CMakeLists.txt
new file mode 100644
index 000000000..5c1b612dd
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/CMakeLists.txt
@@ -0,0 +1,28 @@
+project(shibokengenerator)
+
+set(shiboken_SRC
+../generator.cpp
+cppgenerator.cpp
+headergenerator.cpp
+overloaddata.cpp
+shibokengenerator.cpp
+main.cpp
+)
+
+include_directories(${generators_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${APIEXTRACTOR_INCLUDE_DIR}
+ ${Qt5Core_INCLUDE_DIRS}
+ )
+
+add_executable(shiboken2 ${shiboken_SRC})
+set_target_properties(shiboken2 PROPERTIES OUTPUT_NAME shiboken2${shiboken_SUFFIX})
+target_link_libraries(shiboken2
+ ${APIEXTRACTOR_LIBRARY}
+ ${Qt5Core_LIBRARIES}
+ )
+
+configure_file(shibokenconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/shibokenconfig.h" @ONLY)
+
+install(TARGETS shiboken2 DESTINATION bin)
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
new file mode 100644
index 000000000..6aa2c83df
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -0,0 +1,5755 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <memory>
+
+#include "cppgenerator.h"
+#include "overloaddata.h"
+#include <abstractmetalang.h>
+#include <reporthandler.h>
+#include <typedatabase.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QMetaObject>
+#include <QtCore/QRegularExpression>
+#include <QtCore/QTextStream>
+#include <QtCore/QDebug>
+#include <QMetaType>
+
+QHash<QString, QString> CppGenerator::m_nbFuncs = QHash<QString, QString>();
+QHash<QString, QString> CppGenerator::m_sqFuncs = QHash<QString, QString>();
+QHash<QString, QString> CppGenerator::m_mpFuncs = QHash<QString, QString>();
+QString CppGenerator::m_currentErrorCode(QLatin1String("0"));
+
+// utility functions
+inline AbstractMetaType* getTypeWithoutContainer(AbstractMetaType* arg)
+{
+ if (arg && arg->typeEntry()->isContainer()) {
+ AbstractMetaTypeList lst = arg->instantiations();
+ // only support containers with 1 type
+ if (lst.size() == 1)
+ return lst[0];
+ }
+ return arg;
+}
+
+CppGenerator::CppGenerator()
+{
+ // Number protocol structure members names
+ m_nbFuncs.insert(QLatin1String("__add__"), QLatin1String("nb_add"));
+ m_nbFuncs.insert(QLatin1String("__sub__"), QLatin1String("nb_subtract"));
+ m_nbFuncs.insert(QLatin1String("__mul__"), QLatin1String("nb_multiply"));
+ m_nbFuncs.insert(QLatin1String("__div__"), QLatin1String("nb_divide"));
+ m_nbFuncs.insert(QLatin1String("__mod__"), QLatin1String("nb_remainder"));
+ m_nbFuncs.insert(QLatin1String("__neg__"), QLatin1String("nb_negative"));
+ m_nbFuncs.insert(QLatin1String("__pos__"), QLatin1String("nb_positive"));
+ m_nbFuncs.insert(QLatin1String("__invert__"), QLatin1String("nb_invert"));
+ m_nbFuncs.insert(QLatin1String("__lshift__"), QLatin1String("nb_lshift"));
+ m_nbFuncs.insert(QLatin1String("__rshift__"), QLatin1String("nb_rshift"));
+ m_nbFuncs.insert(QLatin1String("__and__"), QLatin1String("nb_and"));
+ m_nbFuncs.insert(QLatin1String("__xor__"), QLatin1String("nb_xor"));
+ m_nbFuncs.insert(QLatin1String("__or__"), QLatin1String("nb_or"));
+ m_nbFuncs.insert(QLatin1String("__iadd__"), QLatin1String("nb_inplace_add"));
+ m_nbFuncs.insert(QLatin1String("__isub__"), QLatin1String("nb_inplace_subtract"));
+ m_nbFuncs.insert(QLatin1String("__imul__"), QLatin1String("nb_inplace_multiply"));
+ m_nbFuncs.insert(QLatin1String("__idiv__"), QLatin1String("nb_inplace_divide"));
+ m_nbFuncs.insert(QLatin1String("__imod__"), QLatin1String("nb_inplace_remainder"));
+ m_nbFuncs.insert(QLatin1String("__ilshift__"), QLatin1String("nb_inplace_lshift"));
+ m_nbFuncs.insert(QLatin1String("__irshift__"), QLatin1String("nb_inplace_rshift"));
+ m_nbFuncs.insert(QLatin1String("__iand__"), QLatin1String("nb_inplace_and"));
+ m_nbFuncs.insert(QLatin1String("__ixor__"), QLatin1String("nb_inplace_xor"));
+ m_nbFuncs.insert(QLatin1String("__ior__"), QLatin1String("nb_inplace_or"));
+ m_nbFuncs.insert(QLatin1String("bool"), QLatin1String("nb_nonzero"));
+
+ // sequence protocol functions
+ typedef QPair<QString, QString> StrPair;
+ m_sequenceProtocol.insert(QLatin1String("__len__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR), QLatin1String("Py_ssize_t")));
+ m_sequenceProtocol.insert(QLatin1String("__getitem__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i"),
+ QLatin1String("PyObject*")));
+ m_sequenceProtocol.insert(QLatin1String("__setitem__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i, PyObject* _value"),
+ QLatin1String("int")));
+ m_sequenceProtocol.insert(QLatin1String("__getslice__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i1, Py_ssize_t _i2"),
+ QLatin1String("PyObject*")));
+ m_sequenceProtocol.insert(QLatin1String("__setslice__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i1, Py_ssize_t _i2, PyObject* _value"),
+ QLatin1String("int")));
+ m_sequenceProtocol.insert(QLatin1String("__contains__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _value"),
+ QLatin1String("int")));
+ m_sequenceProtocol.insert(QLatin1String("__concat__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _other"),
+ QLatin1String("PyObject*")));
+
+ // Sequence protocol structure members names
+ m_sqFuncs.insert(QLatin1String("__concat__"), QLatin1String("sq_concat"));
+ m_sqFuncs.insert(QLatin1String("__contains__"), QLatin1String("sq_contains"));
+ m_sqFuncs.insert(QLatin1String("__getitem__"), QLatin1String("sq_item"));
+ m_sqFuncs.insert(QLatin1String("__getslice__"), QLatin1String("sq_slice"));
+ m_sqFuncs.insert(QLatin1String("__len__"), QLatin1String("sq_length"));
+ m_sqFuncs.insert(QLatin1String("__setitem__"), QLatin1String("sq_ass_item"));
+ m_sqFuncs.insert(QLatin1String("__setslice__"), QLatin1String("sq_ass_slice"));
+
+ // mapping protocol function
+ m_mappingProtocol.insert(QLatin1String("__mlen__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR),
+ QLatin1String("Py_ssize_t")));
+ m_mappingProtocol.insert(QLatin1String("__mgetitem__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _key"),
+ QLatin1String("PyObject*")));
+ m_mappingProtocol.insert(QLatin1String("__msetitem__"),
+ StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _key, PyObject* _value"),
+ QLatin1String("int")));
+
+ // Sequence protocol structure members names
+ m_mpFuncs.insert(QLatin1String("__mlen__"), QLatin1String("mp_length"));
+ m_mpFuncs.insert(QLatin1String("__mgetitem__"), QLatin1String("mp_subscript"));
+ m_mpFuncs.insert(QLatin1String("__msetitem__"), QLatin1String("mp_ass_subscript"));
+}
+
+QString CppGenerator::fileNamePrefix() const
+{
+ return QLatin1String("_wrapper.cpp");
+}
+
+QString CppGenerator::fileNameForContext(GeneratorContext &context) const
+{
+ const AbstractMetaClass *metaClass = context.metaClass();
+ if (!context.forSmartPointer()) {
+ QString fileNameBase = metaClass->qualifiedCppName().toLower();
+ fileNameBase.replace(QLatin1String("::"), QLatin1String("_"));
+ return fileNameBase + fileNamePrefix();
+ } else {
+ const AbstractMetaType *smartPointerType = context.preciseType();
+ QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass);
+ return fileNameBase + fileNamePrefix();
+ }
+}
+
+QVector<AbstractMetaFunctionList> CppGenerator::filterGroupedOperatorFunctions(const AbstractMetaClass* metaClass,
+ uint queryIn)
+{
+ // ( func_name, num_args ) => func_list
+ typedef QMap<QPair<QString, int >, AbstractMetaFunctionList> ResultMap;
+ ResultMap results;
+ const AbstractMetaClass::OperatorQueryOptions query(queryIn);
+ const AbstractMetaFunctionList &funcs = metaClass->operatorOverloads(query);
+ for (AbstractMetaFunction *func : funcs) {
+ if (func->isModifiedRemoved()
+ || func->usesRValueReferences()
+ || func->name() == QLatin1String("operator[]")
+ || func->name() == QLatin1String("operator->")
+ || func->name() == QLatin1String("operator!")) {
+ continue;
+ }
+ int args;
+ if (func->isComparisonOperator()) {
+ args = -1;
+ } else {
+ args = func->arguments().size();
+ }
+ QPair<QString, int > op(func->name(), args);
+ results[op].append(func);
+ }
+ QVector<AbstractMetaFunctionList> result;
+ result.reserve(results.size());
+ for (ResultMap::const_iterator it = results.cbegin(), end = results.cend(); it != end; ++it)
+ result.append(it.value());
+ return result;
+}
+
+bool CppGenerator::hasBoolCast(const AbstractMetaClass* metaClass) const
+{
+ if (!useIsNullAsNbNonZero())
+ return false;
+ // TODO: This could be configurable someday
+ const AbstractMetaFunction* func = metaClass->findFunction(QLatin1String("isNull"));
+ if (!func || !func->type() || !func->type()->typeEntry()->isPrimitive() || !func->isPublic())
+ return false;
+ const PrimitiveTypeEntry* pte = static_cast<const PrimitiveTypeEntry*>(func->type()->typeEntry());
+ while (pte->referencedTypeEntry())
+ pte = pte->referencedTypeEntry();
+ return func && func->isConstant() && pte->name() == QLatin1String("bool") && func->arguments().isEmpty();
+}
+
+typedef QMap<QString, AbstractMetaFunctionList> FunctionGroupMap;
+typedef FunctionGroupMap::const_iterator FunctionGroupMapIt;
+
+// Prevent ELF symbol qt_version_tag from being generated into the source
+static const char includeQDebug[] =
+"#ifndef QT_NO_VERSION_TAGGING\n"
+"# define QT_NO_VERSION_TAGGING\n"
+"#endif\n"
+"#include <QDebug>\n";
+
+static QString chopType(QString s)
+{
+ if (s.endsWith(QLatin1String("_Type")))
+ s.chop(5);
+ return s;
+}
+
+/*!
+ Function used to write the class generated binding code on the buffer
+ \param s the output buffer
+ \param metaClass the pointer to metaclass information
+*/
+void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
+{
+ AbstractMetaClass *metaClass = classContext.metaClass();
+ if (ReportHandler::isDebug(ReportHandler::SparseDebug))
+ qCDebug(lcShiboken) << "Generating wrapper implementation for " << metaClass->fullName();
+
+ // write license comment
+ s << licenseComment() << endl;
+
+ if (!avoidProtectedHack() && !metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) {
+ s << "//workaround to access protected functions" << endl;
+ s << "#define protected public" << endl << endl;
+ }
+
+ // headers
+ s << "// default includes" << endl;
+ s << "#include <shiboken.h>" << endl;
+ if (usePySideExtensions()) {
+ s << includeQDebug;
+ s << "#include <pysidesignal.h>" << endl;
+ s << "#include <pysideproperty.h>" << endl;
+ s << "#include <pyside.h>" << endl;
+ s << "#include <destroylistener.h>" << endl;
+ }
+
+ s << "#include <typeresolver.h>" << endl;
+ s << "#include <typeinfo>" << endl;
+ if (usePySideExtensions() && metaClass->isQObject()) {
+ s << "#include <signalmanager.h>" << endl;
+ s << "#include <pysidemetafunction.h>" << endl;
+ }
+
+ // The multiple inheritance initialization function
+ // needs the 'set' class from C++ STL.
+ if (hasMultipleInheritanceInAncestry(metaClass))
+ s << "#include <set>" << endl;
+
+ s << endl << "// module include" << endl << "#include \"" << getModuleHeaderFileName() << '"' << endl;
+
+ QString headerfile = fileNameForContext(classContext);
+ headerfile.replace(QLatin1String(".cpp"), QLatin1String(".h"));
+ s << endl << "// main header" << endl << "#include \"" << headerfile << '"' << endl;
+
+ // PYSIDE-500: Use also includes for inherited wrapper classes, because
+ // without the protected hack, we sometimes need to cast inherited wrappers.
+ s << endl << "// inherited wrapper classes" << endl;
+ AbstractMetaClass *basis = metaClass->baseClass();
+ for (; basis; basis = basis->baseClass()) {
+ GeneratorContext basisContext(basis);
+ QString headerfile = fileNameForContext(basisContext);
+ headerfile.replace(QLatin1String(".cpp"), QLatin1String(".h"));
+ s << "#include \"" << headerfile << '"' << endl;
+ }
+
+ s << endl << "// inner classes" << endl;
+ const AbstractMetaClassList &innerClasses = metaClass->innerClasses();
+ for (AbstractMetaClass *innerClass : innerClasses) {
+ GeneratorContext innerClassContext(innerClass);
+ if (shouldGenerate(innerClass)) {
+ QString headerfile = fileNameForContext(innerClassContext);
+ headerfile.replace(QLatin1String(".cpp"), QLatin1String(".h"));
+ s << "#include \"" << headerfile << '"' << endl;
+ }
+ }
+
+ AbstractMetaEnumList classEnums = metaClass->enums();
+ for (AbstractMetaClass *innerClass : innerClasses)
+ lookForEnumsInClassesNotToBeGenerated(classEnums, innerClass);
+
+ //Extra includes
+ s << endl << "// Extra includes" << endl;
+ QVector<Include> includes = metaClass->typeEntry()->extraIncludes();
+ for (AbstractMetaEnum *cppEnum : qAsConst(classEnums))
+ includes.append(cppEnum->typeEntry()->extraIncludes());
+ qSort(includes.begin(), includes.end());
+ for (const Include &inc : qAsConst(includes))
+ s << inc.toString() << endl;
+ s << endl;
+
+ if (metaClass->typeEntry()->typeFlags() & ComplexTypeEntry::Deprecated)
+ s << "#Deprecated" << endl;
+
+ // Use class base namespace
+ {
+ const AbstractMetaClass *context = metaClass->enclosingClass();
+ while (context) {
+ if (context->isNamespace() && !context->enclosingClass()) {
+ s << "using namespace " << context->qualifiedCppName() << ";" << endl;
+ break;
+ }
+ context = context->enclosingClass();
+ }
+ }
+
+ s << endl;
+
+ // Create string literal for smart pointer getter method.
+ if (classContext.forSmartPointer()) {
+ const SmartPointerTypeEntry *typeEntry =
+ static_cast<const SmartPointerTypeEntry *>(classContext.preciseType()
+ ->typeEntry());
+ QString rawGetter = typeEntry->getter();
+ s << "static const char * " SMART_POINTER_GETTER " = \"" << rawGetter << "\";";
+ }
+
+ // class inject-code native/beginning
+ if (!metaClass->typeEntry()->codeSnips().isEmpty()) {
+ writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode, metaClass);
+ s << endl;
+ }
+
+ // python conversion rules
+ if (metaClass->typeEntry()->hasTargetConversionRule()) {
+ s << "// Python Conversion" << endl;
+ s << metaClass->typeEntry()->conversionRule() << endl;
+ }
+
+ if (shouldGenerateCppWrapper(metaClass)) {
+ s << "// Native ---------------------------------------------------------" << endl;
+ s << endl;
+
+ if (avoidProtectedHack() && usePySideExtensions()) {
+ s << "void " << wrapperName(metaClass) << "::pysideInitQtMetaTypes()\n{\n";
+ Indentation indent(INDENT);
+ writeInitQtMetaTypeFunctionBody(s, classContext);
+ s << "}\n\n";
+ }
+
+ const AbstractMetaFunctionList &funcs = filterFunctions(metaClass);
+ for (const AbstractMetaFunction *func : funcs) {
+ if ((func->isPrivate() && !visibilityModifiedToPrivate(func))
+ || (func->isModifiedRemoved() && !func->isAbstract()))
+ continue;
+ if (func->functionType() == AbstractMetaFunction::ConstructorFunction && !func->isUserAdded())
+ writeConstructorNative(s, func);
+ else if ((!avoidProtectedHack() || !metaClass->hasPrivateDestructor())
+ && (func->isVirtual() || func->isAbstract()))
+ writeVirtualMethodNative(s, func);
+ }
+
+ if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor()) {
+ if (usePySideExtensions() && metaClass->isQObject())
+ writeMetaObjectMethod(s, metaClass);
+ writeDestructorNative(s, metaClass);
+ }
+ }
+
+ Indentation indentation(INDENT);
+
+ QString methodsDefinitions;
+ QTextStream md(&methodsDefinitions);
+ QString singleMethodDefinitions;
+ QTextStream smd(&singleMethodDefinitions);
+
+ s << endl << "// Target ---------------------------------------------------------" << endl << endl;
+ s << "extern \"C\" {" << endl;
+ const FunctionGroupMap &functionGroups = getFunctionGroups(metaClass);
+ for (FunctionGroupMapIt it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
+ AbstractMetaFunctionList overloads;
+ QSet<QString> seenSignatures;
+ for (AbstractMetaFunction *func : it.value()) {
+ if (!func->isAssignmentOperator()
+ && !func->usesRValueReferences()
+ && !func->isCastOperator()
+ && !func->isModifiedRemoved()
+ && (!func->isPrivate() || func->functionType() == AbstractMetaFunction::EmptyFunction)
+ && func->ownerClass() == func->implementingClass()
+ && (func->name() != QLatin1String("qt_metacall"))) {
+ // PYSIDE-331: Inheritance works correctly when there are disjoint functions.
+ // But when a function is both in a class and inherited in a subclass,
+ // then we need to search through all subclasses and collect the new signatures.
+ overloads << getFunctionAndInheritedOverloads(func, &seenSignatures);
+ }
+ }
+
+ if (overloads.isEmpty())
+ continue;
+
+ const AbstractMetaFunction* rfunc = overloads.first();
+ if (m_sequenceProtocol.contains(rfunc->name()) || m_mappingProtocol.contains(rfunc->name()))
+ continue;
+
+ if (rfunc->isConstructor()) {
+ // @TODO: Implement constructor support for smart pointers, so that they can be
+ // instantiated in python code.
+ if (classContext.forSmartPointer())
+ continue;
+ writeConstructorWrapper(s, overloads, classContext);
+ }
+ // call operators
+ else if (rfunc->name() == QLatin1String("operator()"))
+ writeMethodWrapper(s, overloads, classContext);
+ else if (!rfunc->isOperatorOverload()) {
+
+ if (classContext.forSmartPointer()) {
+ const SmartPointerTypeEntry *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()->name();
+ QString pointerToInnerTypeName = innerTypeName + QLatin1Char('*');
+ // @TODO: This possibly leaks, but there are a bunch of other places where this
+ // is done, so this will be fixed in bulk with all the other cases, because the
+ // ownership of the pointers is not clear at the moment.
+ AbstractMetaType *pointerToInnerType =
+ buildAbstractMetaTypeFromString(pointerToInnerTypeName);
+
+ AbstractMetaFunction *mutableRfunc = overloads.first();
+ mutableRfunc->replaceType(pointerToInnerType);
+ } else if (smartPointerTypeEntry->refCountMethodName().isEmpty()
+ || smartPointerTypeEntry->refCountMethodName() != rfunc->name()) {
+ // Skip all public methods of the smart pointer except for the raw getter and
+ // the ref count method.
+ continue;
+ }
+ }
+
+ writeMethodWrapper(s, overloads, classContext);
+ if (OverloadData::hasStaticAndInstanceFunctions(overloads)) {
+ QString methDefName = cpythonMethodDefinitionName(rfunc);
+ smd << "static PyMethodDef " << methDefName << " = {" << endl;
+ smd << INDENT;
+ writeMethodDefinitionEntry(smd, overloads);
+ smd << endl << "};" << endl << endl;
+ }
+ writeMethodDefinition(md, overloads);
+ }
+ }
+
+ const QString className = chopType(cpythonTypeName(metaClass));
+
+ if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer())
+ writeCopyFunction(s, classContext);
+
+ // Write single method definitions
+ s << singleMethodDefinitions;
+
+ // Write methods definition
+ s << "static PyMethodDef " << className << "_methods[] = {" << endl;
+ s << methodsDefinitions << endl;
+ if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer())
+ s << INDENT << "{\"__copy__\", (PyCFunction)" << className << "___copy__" << ", METH_NOARGS}," << endl;
+ s << INDENT << "{0} // Sentinel" << endl;
+ s << "};" << endl << endl;
+
+ // Write tp_getattro function
+ if ((usePySideExtensions() && metaClass->qualifiedCppName() == QLatin1String("QObject"))) {
+ writeGetattroFunction(s, classContext);
+ s << endl;
+ writeSetattroFunction(s, classContext);
+ s << endl;
+ } else {
+ if (classNeedsGetattroFunction(metaClass)) {
+ writeGetattroFunction(s, classContext);
+ s << endl;
+ }
+ if (classNeedsSetattroFunction(metaClass)) {
+ writeSetattroFunction(s, classContext);
+ s << endl;
+ }
+ }
+
+ if (hasBoolCast(metaClass)) {
+ ErrorCode errorCode(-1);
+ s << "static int " << cpythonBaseName(metaClass) << "___nb_bool(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << '{' << endl;
+ writeCppSelfDefinition(s, classContext);
+ s << INDENT << "int result;" << endl;
+ s << INDENT << BEGIN_ALLOW_THREADS << endl;
+ s << INDENT << "result = !" CPP_SELF_VAR "->isNull();" << endl;
+ s << INDENT << END_ALLOW_THREADS << endl;
+ s << INDENT << "return result;" << endl;
+ s << '}' << endl << endl;
+ }
+
+ if (supportsNumberProtocol(metaClass) && !metaClass->typeEntry()->isSmartPointer()) {
+ const QVector<AbstractMetaFunctionList> opOverloads = filterGroupedOperatorFunctions(
+ metaClass,
+ AbstractMetaClass::ArithmeticOp
+ | AbstractMetaClass::LogicalOp
+ | AbstractMetaClass::BitwiseOp);
+
+ for (const AbstractMetaFunctionList &allOverloads : opOverloads) {
+ AbstractMetaFunctionList overloads;
+ for (AbstractMetaFunction *func : allOverloads) {
+ if (!func->isModifiedRemoved()
+ && !func->isPrivate()
+ && (func->ownerClass() == func->implementingClass() || func->isAbstract()))
+ overloads.append(func);
+ }
+
+ if (overloads.isEmpty())
+ continue;
+
+ writeMethodWrapper(s, overloads, classContext);
+ }
+ }
+
+ if (supportsSequenceProtocol(metaClass)) {
+ writeSequenceMethods(s, metaClass, classContext);
+ }
+
+ if (supportsMappingProtocol(metaClass)) {
+ writeMappingMethods(s, metaClass, classContext);
+ }
+
+ if (metaClass->hasComparisonOperatorOverload()) {
+ s << "// Rich comparison" << endl;
+ writeRichCompareFunction(s, classContext);
+ }
+
+ if (shouldGenerateGetSetList(metaClass) && !classContext.forSmartPointer()) {
+ const AbstractMetaFieldList &fields = metaClass->fields();
+ for (const AbstractMetaField *metaField : fields) {
+ if (metaField->isStatic())
+ continue;
+ writeGetterFunction(s, metaField, classContext);
+ if (!metaField->type()->isConstant())
+ writeSetterFunction(s, metaField, classContext);
+ s << endl;
+ }
+
+ s << "// Getters and Setters for " << metaClass->name() << endl;
+ s << "static PyGetSetDef " << cpythonGettersSettersDefinitionName(metaClass) << "[] = {" << endl;
+ for (const AbstractMetaField *metaField : fields) {
+ if (metaField->isStatic())
+ continue;
+
+ bool hasSetter = !metaField->type()->isConstant();
+ s << INDENT << "{const_cast<char*>(\"" << metaField->name() << "\"), ";
+ s << cpythonGetterFunctionName(metaField);
+ s << ", " << (hasSetter ? cpythonSetterFunctionName(metaField) : QLatin1String("0"));
+ s << "}," << endl;
+ }
+ s << INDENT << "{0} // Sentinel" << endl;
+ s << "};" << endl << endl;
+ }
+
+ s << "} // extern \"C\"" << endl << endl;
+
+ if (!metaClass->typeEntry()->hashFunction().isEmpty())
+ writeHashFunction(s, classContext);
+
+ // Write tp_traverse and tp_clear functions.
+ writeTpTraverseFunction(s, metaClass);
+ writeTpClearFunction(s, metaClass);
+
+ writeClassDefinition(s, metaClass, classContext);
+ s << endl;
+
+ if (metaClass->isPolymorphic() && metaClass->baseClass())
+ writeTypeDiscoveryFunction(s, metaClass);
+
+
+ for (AbstractMetaEnum *cppEnum : qAsConst(classEnums)) {
+ if (cppEnum->isAnonymous() || cppEnum->isPrivate())
+ continue;
+
+ bool hasFlags = cppEnum->typeEntry()->flags();
+ if (hasFlags) {
+ writeFlagsMethods(s, cppEnum);
+ writeFlagsNumberMethodsDefinition(s, cppEnum);
+ s << endl;
+ }
+ }
+ s << endl;
+
+ writeConverterFunctions(s, metaClass, classContext);
+ writeClassRegister(s, metaClass, classContext);
+
+ // class inject-code native/end
+ if (!metaClass->typeEntry()->codeSnips().isEmpty()) {
+ writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode, metaClass);
+ s << endl;
+ }
+}
+
+void CppGenerator::writeConstructorNative(QTextStream& s, const AbstractMetaFunction* func)
+{
+ Indentation indentation(INDENT);
+ s << functionSignature(func, wrapperName(func->ownerClass()) + QLatin1String("::"), QString(),
+ OriginalTypeDescription | SkipDefaultValues);
+ s << " : ";
+ writeFunctionCall(s, func);
+ s << " {" << endl;
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode, func, lastArg);
+ s << INDENT << "// ... middle" << endl;
+ writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode, func, lastArg);
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeDestructorNative(QTextStream &s, const AbstractMetaClass *metaClass)
+{
+ Indentation indentation(INDENT);
+ s << wrapperName(metaClass) << "::~" << wrapperName(metaClass) << "()" << endl << '{' << endl;
+ // kill pyobject
+ s << INDENT << "SbkObject* wrapper = Shiboken::BindingManager::instance().retrieveWrapper(this);" << endl;
+ s << INDENT << "Shiboken::Object::destroy(wrapper, this);" << endl;
+ s << '}' << endl;
+}
+
+static bool allArgumentsRemoved(const AbstractMetaFunction* func)
+{
+ if (func->arguments().isEmpty())
+ return false;
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument *arg : arguments) {
+ if (!func->argumentRemoved(arg->argumentIndex() + 1))
+ return false;
+ }
+ return true;
+}
+
+QString CppGenerator::getVirtualFunctionReturnTypeName(const AbstractMetaFunction* func)
+{
+ if (!func->type())
+ return QLatin1String("\"\"");
+
+ if (!func->typeReplaced(0).isEmpty())
+ return QLatin1Char('"') + func->typeReplaced(0) + QLatin1Char('"');
+
+ // SbkType would return null when the type is a container.
+ if (func->type()->typeEntry()->isContainer()) {
+ return QLatin1Char('"')
+ + reinterpret_cast<const ContainerTypeEntry*>(func->type()->typeEntry())->typeName()
+ + QLatin1Char('"');
+ }
+
+ if (avoidProtectedHack()) {
+ const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(func->type());
+ if (metaEnum && metaEnum->isProtected())
+ return QLatin1Char('"') + protectedEnumSurrogateName(metaEnum) + QLatin1Char('"');
+ }
+
+ if (func->type()->isPrimitive())
+ return QLatin1Char('"') + func->type()->name() + QLatin1Char('"');
+
+ return QString::fromLatin1("Shiboken::SbkType< %1 >()->tp_name").arg(func->type()->typeEntry()->qualifiedCppName());
+}
+
+void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFunction* func)
+{
+ //skip metaObject function, this will be written manually ahead
+ if (usePySideExtensions() && func->ownerClass() && func->ownerClass()->isQObject() &&
+ ((func->name() == QLatin1String("metaObject")) || (func->name() == QLatin1String("qt_metacall"))))
+ return;
+
+ const TypeEntry* retType = func->type() ? func->type()->typeEntry() : 0;
+ const QString funcName = func->isOperatorOverload() ? pythonOperatorFunctionName(func) : func->name();
+
+ QString prefix = wrapperName(func->ownerClass()) + QLatin1String("::");
+ s << functionSignature(func, prefix, QString(), Generator::SkipDefaultValues|Generator::OriginalTypeDescription)
+ << endl << '{' << endl;
+
+ Indentation indentation(INDENT);
+
+ QString defaultReturnExpr;
+ if (retType) {
+ const FunctionModificationList &mods = func->modifications();
+ for (const FunctionModification &mod : mods) {
+ for (const ArgumentModification &argMod : mod.argument_mods) {
+ if (argMod.index == 0 && !argMod.replacedDefaultExpression.isEmpty()) {
+ static const QRegularExpression regex(QStringLiteral("%(\\d+)"));
+ Q_ASSERT(regex.isValid());
+ defaultReturnExpr = argMod.replacedDefaultExpression;
+ for (int offset = 0; ; ) {
+ const QRegularExpressionMatch match = regex.match(defaultReturnExpr, offset);
+ if (!match.hasMatch())
+ break;
+ const int argId = match.capturedRef(1).toInt() - 1;
+ if (argId < 0 || argId > func->arguments().count()) {
+ qCWarning(lcShiboken) << "The expression used in return value contains an invalid index.";
+ break;
+ }
+ defaultReturnExpr.replace(match.captured(0), func->arguments()[argId]->name());
+ offset = match.capturedStart(1);
+ }
+ }
+ }
+ }
+ if (defaultReturnExpr.isEmpty())
+ defaultReturnExpr = minimalConstructor(func->type());
+ if (defaultReturnExpr.isEmpty()) {
+ QString errorMsg = QLatin1String(__FUNCTION__) + QLatin1String(": ");
+ if (const AbstractMetaClass *c = func->implementingClass())
+ errorMsg += c->qualifiedCppName() + QLatin1String("::");
+ errorMsg += func->signature();
+ errorMsg = ShibokenGenerator::msgCouldNotFindMinimalConstructor(errorMsg, func->type()->cppSignature());
+ qCWarning(lcShiboken).noquote().nospace() << errorMsg;
+ s << endl << INDENT << "#error " << errorMsg << endl;
+ }
+ }
+
+ if (func->isAbstract() && func->isModifiedRemoved()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QString::fromLatin1("Pure virtual method '%1::%2' must be implement but was "\
+ "completely removed on type system.")
+ .arg(func->ownerClass()->name(), func->minimalSignature());
+ s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ s << '}' << endl << endl;
+ return;
+ }
+
+ //Write declaration/native injected code
+ if (func->hasInjectedCode()) {
+ CodeSnipList snips = func->injectedCodeSnips();
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionDeclaration, TypeSystem::NativeCode, func, lastArg);
+ s << endl;
+ }
+
+ s << INDENT << "Shiboken::GilState gil;" << endl;
+
+ // Get out of virtual method call if someone already threw an error.
+ s << INDENT << "if (PyErr_Occurred())" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ }
+
+ s << INDENT << "Shiboken::AutoDecRef " PYTHON_OVERRIDE_VAR "(Shiboken::BindingManager::instance().getOverride(this, \"";
+ s << funcName << "\"));" << endl;
+
+ s << INDENT << "if (" PYTHON_OVERRIDE_VAR ".isNull()) {" << endl;
+ {
+ Indentation indentation(INDENT);
+ CodeSnipList snips;
+ if (func->hasInjectedCode()) {
+ snips = func->injectedCodeSnips();
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::ShellCode, func, lastArg);
+ s << endl;
+ }
+
+ if (func->isAbstract()) {
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '";
+ s << func->ownerClass()->name() << '.' << funcName;
+ s << "()' not implemented.\");" << endl;
+ s << INDENT << "return " << (retType ? defaultReturnExpr : QString());
+ } else {
+ s << INDENT << "gil.release();" << endl;
+ s << INDENT;
+ if (retType)
+ s << "return ";
+ s << "this->::" << func->implementingClass()->qualifiedCppName() << "::";
+ writeFunctionCall(s, func, Generator::VirtualCall);
+ if (!retType)
+ s << ";\n" << INDENT << "return";
+ }
+ }
+ s << ';' << endl;
+ s << INDENT << '}' << endl << endl;
+
+ writeConversionRule(s, func, TypeSystem::TargetLangCode);
+
+ s << INDENT << "Shiboken::AutoDecRef " PYTHON_ARGS "(";
+
+ if (func->arguments().isEmpty() || allArgumentsRemoved(func)) {
+ s << "PyTuple_New(0));" << endl;
+ } else {
+ QStringList argConversions;
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument *arg : arguments) {
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+
+ QString argConv;
+ QTextStream ac(&argConv);
+ const PrimitiveTypeEntry* argType = (const PrimitiveTypeEntry*) arg->type()->typeEntry();
+ bool convert = argType->isObject()
+ || arg->type()->isQObject()
+ || argType->isValue()
+ || arg->type()->isValuePointer()
+ || arg->type()->isNativePointer()
+ || argType->isFlags()
+ || argType->isEnum()
+ || argType->isContainer()
+ || arg->type()->referenceType() == LValueReference;
+
+ if (!convert && argType->isPrimitive()) {
+ if (argType->basicReferencedTypeEntry())
+ argType = argType->basicReferencedTypeEntry();
+ convert = !m_formatUnits.contains(argType->name());
+ }
+
+ Indentation indentation(INDENT);
+ ac << INDENT;
+ if (!func->conversionRule(TypeSystem::TargetLangCode, arg->argumentIndex() + 1).isEmpty()) {
+ // Has conversion rule.
+ ac << arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX);
+ } else {
+ QString argName = arg->name();
+ if (convert)
+ writeToPythonConversion(ac, arg->type(), func->ownerClass(), argName);
+ else
+ ac << argName;
+ }
+
+ argConversions << argConv;
+ }
+
+ s << "Py_BuildValue(\"(" << getFormatUnitString(func, false) << ")\"," << endl;
+ s << argConversions.join(QLatin1String(",\n")) << endl;
+ s << INDENT << "));" << endl;
+ }
+
+ bool invalidateReturn = false;
+ QSet<int> invalidateArgs;
+ const FunctionModificationList &mods = func->modifications();
+ for (const FunctionModification &funcMod : mods) {
+ for (const ArgumentModification &argMod : funcMod.argument_mods) {
+ if (argMod.resetAfterUse && !invalidateArgs.contains(argMod.index)) {
+ invalidateArgs.insert(argMod.index);
+ s << INDENT << "bool invalidateArg" << argMod.index;
+ s << " = PyTuple_GET_ITEM(" PYTHON_ARGS ", " << argMod.index - 1 << ")->ob_refcnt == 1;" << endl;
+ } else if (argMod.index == 0 && argMod.ownerships[TypeSystem::TargetLangCode] == TypeSystem::CppOwnership) {
+ invalidateReturn = true;
+ }
+ }
+ }
+ s << endl;
+
+ CodeSnipList snips;
+ if (func->hasInjectedCode()) {
+ snips = func->injectedCodeSnips();
+
+ if (injectedCodeUsesPySelf(func))
+ s << INDENT << "PyObject* pySelf = BindingManager::instance().retrieveWrapper(this);" << endl;
+
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode, func, lastArg);
+ s << endl;
+ }
+
+ if (!injectedCodeCallsPythonOverride(func)) {
+ s << INDENT;
+ s << "Shiboken::AutoDecRef " PYTHON_RETURN_VAR "(PyObject_Call(" PYTHON_OVERRIDE_VAR ", " PYTHON_ARGS ", NULL));" << endl;
+
+ s << INDENT << "// An error happened in python code!" << endl;
+ s << INDENT << "if (" PYTHON_RETURN_VAR ".isNull()) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_Print();" << endl;
+ s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ if (retType) {
+ if (invalidateReturn)
+ s << INDENT << "bool invalidateArg0 = " PYTHON_RETURN_VAR "->ob_refcnt == 1;" << endl;
+
+ if (func->typeReplaced(0) != QLatin1String("PyObject")) {
+
+ s << INDENT << "// Check return type" << endl;
+ s << INDENT;
+ if (func->typeReplaced(0).isEmpty()) {
+ s << "PythonToCppFunc " PYTHON_TO_CPP_VAR " = " << cpythonIsConvertibleFunction(func->type());
+ s << PYTHON_RETURN_VAR ");" << endl;
+ s << INDENT << "if (!" PYTHON_TO_CPP_VAR ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\
+ "\"Invalid return value in function %s, expected %s, got %s.\", \"";
+ s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func);
+ s << ", " PYTHON_RETURN_VAR "->ob_type->tp_name);" << endl;
+ s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ } else {
+
+ s << INDENT << "// Check return type" << endl;
+ s << INDENT << "bool typeIsValid = ";
+ writeTypeCheck(s, func->type(), QLatin1String(PYTHON_RETURN_VAR),
+ isNumber(func->type()->typeEntry()), func->typeReplaced(0));
+ s << ';' << endl;
+ s << INDENT << "if (!typeIsValid";
+ s << (isPointerToWrapperType(func->type()) ? " && " PYTHON_RETURN_VAR " != Py_None" : "");
+ s << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "Shiboken::warning(PyExc_RuntimeWarning, 2, "\
+ "\"Invalid return value in function %s, expected %s, got %s.\", \"";
+ s << func->ownerClass()->name() << '.' << funcName << "\", " << getVirtualFunctionReturnTypeName(func);
+ s << ", " PYTHON_RETURN_VAR "->ob_type->tp_name);" << endl;
+ s << INDENT << "return " << defaultReturnExpr << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ }
+ }
+
+ if (!func->conversionRule(TypeSystem::NativeCode, 0).isEmpty()) {
+ // Has conversion rule.
+ writeConversionRule(s, func, TypeSystem::NativeCode, QLatin1String(CPP_RETURN_VAR));
+ } else if (!injectedCodeHasReturnValueAttribution(func, TypeSystem::NativeCode)) {
+ writePythonToCppTypeConversion(s, func->type(), QLatin1String(PYTHON_RETURN_VAR),
+ QLatin1String(CPP_RETURN_VAR), func->implementingClass());
+ }
+ }
+ }
+
+ if (invalidateReturn) {
+ s << INDENT << "if (invalidateArg0)" << endl;
+ Indentation indentation(INDENT);
+ s << INDENT << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR ".object());" << endl;
+ }
+ for (int argIndex : qAsConst(invalidateArgs)) {
+ s << INDENT << "if (invalidateArg" << argIndex << ')' << endl;
+ Indentation indentation(INDENT);
+ s << INDENT << "Shiboken::Object::invalidate(PyTuple_GET_ITEM(" PYTHON_ARGS ", ";
+ s << (argIndex - 1) << "));" << endl;
+ }
+
+
+ const FunctionModificationList &funcMods = func->modifications();
+ for (const FunctionModification &funcMod : funcMods) {
+ for (const ArgumentModification &argMod : funcMod.argument_mods) {
+ if (argMod.ownerships.contains(TypeSystem::NativeCode)
+ && argMod.index == 0 && argMod.ownerships[TypeSystem::NativeCode] == TypeSystem::CppOwnership) {
+ s << INDENT << "if (Shiboken::Object::checkType(" PYTHON_RETURN_VAR "))" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "Shiboken::Object::releaseOwnership(" PYTHON_RETURN_VAR ");" << endl;
+ }
+ }
+ }
+
+ if (func->hasInjectedCode()) {
+ s << endl;
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode, func, lastArg);
+ }
+
+ if (retType) {
+ s << INDENT << "return ";
+ if (avoidProtectedHack() && retType->isEnum()) {
+ const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(retType);
+ bool isProtectedEnum = metaEnum && metaEnum->isProtected();
+ if (isProtectedEnum) {
+ QString typeCast;
+ if (metaEnum->enclosingClass())
+ typeCast += QLatin1String("::") + metaEnum->enclosingClass()->qualifiedCppName();
+ typeCast += QLatin1String("::") + metaEnum->name();
+ s << '(' << typeCast << ')';
+ }
+ }
+ if (func->type()->referenceType() == LValueReference && !isPointer(func->type()))
+ s << '*';
+ s << CPP_RETURN_VAR ";" << endl;
+ }
+
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeMetaObjectMethod(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ Indentation indentation(INDENT);
+ QString wrapperClassName = wrapperName(metaClass);
+ s << "const QMetaObject* " << wrapperClassName << "::metaObject() const" << endl;
+ s << '{' << endl;
+ s << INDENT << "if (QObject::d_ptr->metaObject)" << endl
+ << INDENT << INDENT << "return QObject::d_ptr->dynamicMetaObject();" << endl;
+ s << INDENT << "SbkObject* pySelf = Shiboken::BindingManager::instance().retrieveWrapper(this);" << endl;
+ s << INDENT << "if (pySelf == NULL)" << endl;
+ s << INDENT << INDENT << "return " << metaClass->qualifiedCppName() << "::metaObject();" << endl;
+ s << INDENT << "return PySide::SignalManager::retriveMetaObject(reinterpret_cast<PyObject*>(pySelf));" << endl;
+ s << '}' << endl << endl;
+
+ // qt_metacall function
+ s << "int " << wrapperClassName << "::qt_metacall(QMetaObject::Call call, int id, void** args)" << endl;
+ s << "{" << endl;
+
+ AbstractMetaFunction *func = NULL;
+ AbstractMetaFunctionList list = metaClass->queryFunctionsByName(QLatin1String("qt_metacall"));
+ if (list.size() == 1)
+ func = list[0];
+
+ CodeSnipList snips;
+ if (func) {
+ snips = func->injectedCodeSnips();
+ if (func->isUserAdded()) {
+ CodeSnipList snips = func->injectedCodeSnips();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::NativeCode, func);
+ }
+ }
+
+ s << INDENT << "int result = " << metaClass->qualifiedCppName() << "::qt_metacall(call, id, args);" << endl;
+ s << INDENT << "return result < 0 ? result : PySide::SignalManager::qt_metacall(this, call, id, args);" << endl;
+ s << "}" << endl << endl;
+
+ // qt_metacast function
+ writeMetaCast(s, metaClass);
+}
+
+void CppGenerator::writeMetaCast(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ Indentation indentation(INDENT);
+ QString wrapperClassName = wrapperName(metaClass);
+ s << "void* " << wrapperClassName << "::qt_metacast(const char* _clname)" << endl;
+ s << '{' << endl;
+ s << INDENT << "if (!_clname) return 0;" << endl;
+ s << INDENT << "SbkObject* pySelf = Shiboken::BindingManager::instance().retrieveWrapper(this);" << endl;
+ s << INDENT << "if (pySelf && PySide::inherits(Py_TYPE(pySelf), _clname))" << endl;
+ s << INDENT << INDENT << "return static_cast<void*>(const_cast< " << wrapperClassName << "* >(this));" << endl;
+ s << INDENT << "return " << metaClass->qualifiedCppName() << "::qt_metacast(_clname);" << endl;
+ s << "}" << endl << endl;
+}
+
+void CppGenerator::writeEnumConverterFunctions(QTextStream& s, const AbstractMetaEnum* metaEnum)
+{
+ if (metaEnum->isPrivate() || metaEnum->isAnonymous())
+ return;
+ writeEnumConverterFunctions(s, metaEnum->typeEntry());
+}
+
+void CppGenerator::writeEnumConverterFunctions(QTextStream& s, const TypeEntry* enumType)
+{
+ if (!enumType)
+ return;
+ QString enumFlagName = enumType->isFlags() ? QLatin1String("flag") : QLatin1String("enum");
+ QString typeName = fixedCppTypeName(enumType);
+ QString enumPythonType = cpythonTypeNameExt(enumType);
+ QString cppTypeName = getFullTypeName(enumType).trimmed();
+ if (avoidProtectedHack()) {
+ const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(enumType);
+ if (metaEnum && metaEnum->isProtected())
+ cppTypeName = protectedEnumSurrogateName(metaEnum);
+ }
+ QString code;
+ QTextStream c(&code);
+ c << INDENT << "*((" << cppTypeName << "*)cppOut) = ";
+ if (enumType->isFlags())
+ c << cppTypeName << "(QFlag((int)PySide::QFlags::getValue(reinterpret_cast<PySideQFlagsObject*>(pyIn))))";
+ else
+ c << "(" << cppTypeName << ") Shiboken::Enum::getValue(pyIn)";
+ c << ';' << endl;
+ writePythonToCppFunction(s, code, typeName, typeName);
+
+ QString pyTypeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, %1)").arg(enumPythonType);
+ writeIsPythonConvertibleToCppFunction(s, typeName, typeName, pyTypeCheck);
+
+ code.clear();
+
+ c << INDENT << "int castCppIn = *((" << cppTypeName << "*)cppIn);" << endl;
+ c << INDENT;
+ c << "return ";
+ if (enumType->isFlags())
+ c << "reinterpret_cast<PyObject*>(PySide::QFlags::newObject(castCppIn, " << enumPythonType << "))";
+
+ else
+ c << "Shiboken::Enum::newItem(" << enumPythonType << ", castCppIn)";
+ c << ';' << endl;
+ writeCppToPythonFunction(s, code, typeName, typeName);
+ s << endl;
+
+ if (enumType->isFlags())
+ return;
+
+ const FlagsTypeEntry* flags = reinterpret_cast<const EnumTypeEntry*>(enumType)->flags();
+ if (!flags)
+ return;
+
+ // QFlags part.
+
+ writeEnumConverterFunctions(s, flags);
+
+ code.clear();
+ cppTypeName = getFullTypeName(flags).trimmed();
+ c << INDENT << "*((" << cppTypeName << "*)cppOut) = " << cppTypeName;
+ c << "(QFlag((int)Shiboken::Enum::getValue(pyIn)));" << endl;
+
+ QString flagsTypeName = fixedCppTypeName(flags);
+ writePythonToCppFunction(s, code, typeName, flagsTypeName);
+ writeIsPythonConvertibleToCppFunction(s, typeName, flagsTypeName, pyTypeCheck);
+
+ code.clear();
+ c << INDENT << "Shiboken::AutoDecRef pyLong(PyNumber_Long(pyIn));" << endl;
+ c << INDENT << "*((" << cppTypeName << "*)cppOut) = " << cppTypeName;
+ c << "(QFlag((int)PyLong_AsLong(pyLong.object())));" << endl;
+ writePythonToCppFunction(s, code, QLatin1String("number"), flagsTypeName);
+ writeIsPythonConvertibleToCppFunction(s, QLatin1String("number"), flagsTypeName,
+ QLatin1String("PyNumber_Check(pyIn)"));
+}
+
+void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaClass *metaClass,
+ GeneratorContext &classContext)
+{
+ s << "// Type conversion functions." << endl << endl;
+
+ AbstractMetaEnumList classEnums = metaClass->enums();
+ const AbstractMetaClassList &innerClasses = metaClass->innerClasses();
+ for (AbstractMetaClass *innerClass : innerClasses)
+ lookForEnumsInClassesNotToBeGenerated(classEnums, innerClass);
+ if (!classEnums.isEmpty())
+ s << "// Python to C++ enum conversion." << endl;
+ for (const AbstractMetaEnum *metaEnum : qAsConst(classEnums))
+ writeEnumConverterFunctions(s, metaEnum);
+
+ if (metaClass->isNamespace())
+ return;
+
+ QString typeName;
+ if (!classContext.forSmartPointer())
+ typeName = getFullTypeName(metaClass);
+ else
+ typeName = getFullTypeName(classContext.preciseType());
+
+ QString cpythonType = cpythonTypeName(metaClass);
+
+ // Returns the C++ pointer of the Python wrapper.
+ s << "// Python to C++ pointer conversion - returns the C++ object of the Python wrapper (keeps object identity)." << endl;
+
+ QString sourceTypeName = metaClass->name();
+ QString targetTypeName = metaClass->name() + QLatin1String("_PTR");
+ QString code;
+ QTextStream c(&code);
+ c << INDENT << "Shiboken::Conversions::pythonToCppPointer(&" << cpythonType << ", pyIn, cppOut);";
+ writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
+
+ // "Is convertible" function for the Python object to C++ pointer conversion.
+ QString pyTypeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, (PyTypeObject*)&%1)").arg(cpythonType);
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, pyTypeCheck, QString(), true);
+ s << endl;
+
+ // C++ pointer to a Python wrapper, keeping identity.
+ s << "// C++ to Python pointer conversion - tries to find the Python wrapper for the C++ object (keeps object identity)." << endl;
+ code.clear();
+ if (usePySideExtensions() && metaClass->isQObject())
+ {
+ c << INDENT << "return PySide::getWrapperForQObject((" << typeName << "*)cppIn, &" << cpythonType << ");" << endl;
+ } else {
+ c << INDENT << "PyObject* pyOut = (PyObject*)Shiboken::BindingManager::instance().retrieveWrapper(cppIn);" << endl;
+ c << INDENT << "if (pyOut) {" << endl;
+ {
+ Indentation indent(INDENT);
+ c << INDENT << "Py_INCREF(pyOut);" << endl;
+ c << INDENT << "return pyOut;" << endl;
+ }
+ c << INDENT << '}' << endl;
+ c << INDENT << "const char* typeName = typeid(*((" << typeName << "*)cppIn)).name();" << endl;
+ c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType;
+ c << ", const_cast<void*>(cppIn), false, false, typeName);";
+ }
+ std::swap(targetTypeName, sourceTypeName);
+ writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName);
+
+ // The conversions for an Object Type end here.
+ if (!metaClass->typeEntry()->isValue() && !metaClass->typeEntry()->isSmartPointer()) {
+ s << endl;
+ return;
+ }
+
+ // Always copies C++ value (not pointer, and not reference) to a new Python wrapper.
+ s << endl << "// C++ to Python copy conversion." << endl;
+ if (!classContext.forSmartPointer())
+ targetTypeName = metaClass->name();
+ else
+ targetTypeName = classContext.preciseType()->name();
+
+ sourceTypeName = targetTypeName + QLatin1String("_COPY");
+
+ code.clear();
+
+ QString computedWrapperName;
+ if (!classContext.forSmartPointer())
+ computedWrapperName = wrapperName(metaClass);
+ else
+ computedWrapperName = wrapperName(classContext.preciseType());
+
+ c << INDENT << "return Shiboken::Object::newObject(&" << cpythonType << ", new ::" << computedWrapperName;
+ c << "(*((" << typeName << "*)cppIn)), true, true);";
+ writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName);
+ s << endl;
+
+ // Python to C++ copy conversion.
+ s << "// Python to C++ copy conversion." << endl;
+ if (!classContext.forSmartPointer())
+ sourceTypeName = metaClass->name();
+ else
+ sourceTypeName = classContext.preciseType()->name();
+
+ targetTypeName = QStringLiteral("%1_COPY").arg(sourceTypeName);
+ code.clear();
+
+ QString pyInVariable = QLatin1String("pyIn");
+ QString wrappedCPtrExpression;
+ if (!classContext.forSmartPointer())
+ wrappedCPtrExpression = cpythonWrapperCPtr(metaClass->typeEntry(), pyInVariable);
+ else
+ wrappedCPtrExpression = cpythonWrapperCPtr(classContext.preciseType(), pyInVariable);
+
+ c << INDENT << "*((" << typeName << "*)cppOut) = *"
+ << wrappedCPtrExpression << ';';
+ writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
+
+ // "Is convertible" function for the Python object to C++ value copy conversion.
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, pyTypeCheck);
+ s << endl;
+
+ // User provided implicit conversions.
+ CustomConversion* customConversion = metaClass->typeEntry()->customConversion();
+
+ // Implicit conversions.
+ AbstractMetaFunctionList implicitConvs;
+ if (!customConversion || !customConversion->replaceOriginalTargetToNativeConversions()) {
+ const AbstractMetaFunctionList &allImplicitConvs = implicitConversions(metaClass->typeEntry());
+ for (AbstractMetaFunction *func : allImplicitConvs) {
+ if (!func->isUserAdded())
+ implicitConvs << func;
+ }
+ }
+
+ if (!implicitConvs.isEmpty())
+ s << "// Implicit conversions." << endl;
+
+ AbstractMetaType* targetType = buildAbstractMetaTypeFromAbstractMetaClass(metaClass);
+ for (const AbstractMetaFunction* conv : qAsConst(implicitConvs)) {
+ if (conv->isModifiedRemoved())
+ continue;
+
+ QString typeCheck;
+ QString toCppConv;
+ QString toCppPreConv;
+ if (conv->isConversionOperator()) {
+ const AbstractMetaClass* sourceClass = conv->ownerClass();
+ typeCheck = QStringLiteral("PyObject_TypeCheck(pyIn, %1)").arg(cpythonTypeNameExt(sourceClass->typeEntry()));
+ toCppConv = QLatin1Char('*') + cpythonWrapperCPtr(sourceClass->typeEntry(), QLatin1String("pyIn"));
+ } else {
+ // Constructor that does implicit conversion.
+ if (!conv->typeReplaced(1).isEmpty())
+ continue;
+ const AbstractMetaType* sourceType = conv->arguments().first()->type();
+ typeCheck = cpythonCheckFunction(sourceType);
+ bool isUserPrimitiveWithoutTargetLangName = isUserPrimitive(sourceType)
+ && sourceType->typeEntry()->targetLangApiName() == sourceType->typeEntry()->name();
+ if (!isWrapperType(sourceType)
+ && !isUserPrimitiveWithoutTargetLangName
+ && !sourceType->typeEntry()->isEnum()
+ && !sourceType->typeEntry()->isFlags()
+ && !sourceType->typeEntry()->isContainer()) {
+ typeCheck += QLatin1Char('(');
+ }
+ if (isWrapperType(sourceType)) {
+ typeCheck += QLatin1String("pyIn)");
+ toCppConv = (sourceType->referenceType() == LValueReference || !isPointerToWrapperType(sourceType))
+ ? QLatin1String("*") : QString();
+ toCppConv += cpythonWrapperCPtr(sourceType->typeEntry(), QLatin1String("pyIn"));
+ } else if (typeCheck.contains(QLatin1String("%in"))) {
+ typeCheck.replace(QLatin1String("%in"), QLatin1String("pyIn"));
+ typeCheck.append(QLatin1Char(')'));
+ } else {
+ typeCheck += QLatin1String("pyIn)");
+ }
+
+ if (isUserPrimitive(sourceType)
+ || isCppPrimitive(sourceType)
+ || sourceType->typeEntry()->isContainer()
+ || sourceType->typeEntry()->isEnum()
+ || sourceType->typeEntry()->isFlags()) {
+ QTextStream pc(&toCppPreConv);
+ pc << INDENT << getFullTypeNameWithoutModifiers(sourceType) << " cppIn";
+ writeMinimalConstructorExpression(pc, sourceType);
+ pc << ';' << endl;
+ writeToCppConversion(pc, sourceType, 0, QLatin1String("pyIn"), QLatin1String("cppIn"));
+ pc << ';';
+ toCppConv.append(QLatin1String("cppIn"));
+ } else if (!isWrapperType(sourceType)) {
+ QTextStream tcc(&toCppConv);
+ writeToCppConversion(tcc, sourceType, metaClass, QLatin1String("pyIn"), QLatin1String("/*BOZO-1061*/"));
+ }
+
+
+ }
+ const AbstractMetaType* sourceType = conv->isConversionOperator()
+ ? buildAbstractMetaTypeFromAbstractMetaClass(conv->ownerClass())
+ : conv->arguments().first()->type();
+ writePythonToCppConversionFunctions(s, sourceType, targetType, typeCheck, toCppConv, toCppPreConv);
+ }
+
+ writeCustomConverterFunctions(s, customConversion);
+}
+
+void CppGenerator::writeCustomConverterFunctions(QTextStream& s, const CustomConversion* customConversion)
+{
+ if (!customConversion)
+ return;
+ const CustomConversion::TargetToNativeConversions& toCppConversions = customConversion->targetToNativeConversions();
+ if (toCppConversions.isEmpty())
+ return;
+ s << "// Python to C++ conversions for type '" << customConversion->ownerType()->qualifiedCppName() << "'." << endl;
+ for (CustomConversion::TargetToNativeConversion *toNative : toCppConversions)
+ writePythonToCppConversionFunctions(s, toNative, customConversion->ownerType());
+ s << endl;
+}
+
+void CppGenerator::writeConverterRegister(QTextStream &s, const AbstractMetaClass *metaClass,
+ GeneratorContext &classContext)
+{
+ if (metaClass->isNamespace())
+ return;
+ s << INDENT << "// Register Converter" << endl;
+ s << INDENT << "SbkConverter* converter = Shiboken::Conversions::createConverter(&";
+ s << cpythonTypeName(metaClass) << ',' << endl;
+ {
+ Indentation indent(INDENT);
+ QString sourceTypeName = metaClass->name();
+ QString targetTypeName = sourceTypeName + QLatin1String("_PTR");
+ s << INDENT << pythonToCppFunctionName(sourceTypeName, targetTypeName) << ',' << endl;
+ s << INDENT << convertibleToCppFunctionName(sourceTypeName, targetTypeName) << ',' << endl;
+ std::swap(targetTypeName, sourceTypeName);
+ s << INDENT << cppToPythonFunctionName(sourceTypeName, targetTypeName);
+ if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) {
+ s << ',' << endl;
+ sourceTypeName = metaClass->name() + QLatin1String("_COPY");
+ s << INDENT << cppToPythonFunctionName(sourceTypeName, targetTypeName);
+ }
+ }
+ s << ");" << endl;
+
+ s << endl;
+
+ QStringList cppSignature;
+ if (!classContext.forSmartPointer()) {
+ cppSignature = metaClass->qualifiedCppName().split(QLatin1String("::"),
+ QString::SkipEmptyParts);
+ } else {
+ cppSignature = classContext.preciseType()->cppSignature().split(QLatin1String("::"),
+ QString::SkipEmptyParts);
+ }
+ while (!cppSignature.isEmpty()) {
+ QString signature = cppSignature.join(QLatin1String("::"));
+ s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "\");" << endl;
+ s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "*\");" << endl;
+ s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" << signature << "&\");" << endl;
+ cppSignature.removeFirst();
+ }
+
+ s << INDENT << "Shiboken::Conversions::registerConverterName(converter, typeid(::";
+ QString qualifiedCppNameInvocation;
+ if (!classContext.forSmartPointer())
+ qualifiedCppNameInvocation = metaClass->qualifiedCppName();
+ else
+ qualifiedCppNameInvocation = classContext.preciseType()->cppSignature();
+
+ s << qualifiedCppNameInvocation << ").name());" << endl;
+
+ if (shouldGenerateCppWrapper(metaClass)) {
+ s << INDENT << "Shiboken::Conversions::registerConverterName(converter, typeid(::";
+ s << wrapperName(metaClass) << ").name());" << endl;
+ }
+
+ s << endl;
+
+ if (!metaClass->typeEntry()->isValue() && !metaClass->typeEntry()->isSmartPointer())
+ return;
+
+ // Python to C++ copy (value, not pointer neither reference) conversion.
+ s << INDENT << "// Add Python to C++ copy (value, not pointer neither reference) conversion to type converter." << endl;
+ QString sourceTypeName = metaClass->name();
+ QString targetTypeName = sourceTypeName + QLatin1String("_COPY");
+ QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName);
+ QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName);
+ writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
+
+ // User provided implicit conversions.
+ CustomConversion* customConversion = metaClass->typeEntry()->customConversion();
+
+ // Add implicit conversions.
+ AbstractMetaFunctionList implicitConvs;
+ if (!customConversion || !customConversion->replaceOriginalTargetToNativeConversions()) {
+ const AbstractMetaFunctionList &allImplicitConvs = implicitConversions(metaClass->typeEntry());
+ for (AbstractMetaFunction *func : allImplicitConvs) {
+ if (!func->isUserAdded())
+ implicitConvs << func;
+ }
+ }
+
+ if (!implicitConvs.isEmpty())
+ s << INDENT << "// Add implicit conversions to type converter." << endl;
+
+ AbstractMetaType* targetType = buildAbstractMetaTypeFromAbstractMetaClass(metaClass);
+ for (const AbstractMetaFunction *conv : qAsConst(implicitConvs)) {
+ if (conv->isModifiedRemoved())
+ continue;
+ const AbstractMetaType* sourceType;
+ if (conv->isConversionOperator()) {
+ sourceType = buildAbstractMetaTypeFromAbstractMetaClass(conv->ownerClass());
+ } else {
+ // Constructor that does implicit conversion.
+ if (!conv->typeReplaced(1).isEmpty())
+ continue;
+ sourceType = conv->arguments().first()->type();
+ }
+ QString toCpp = pythonToCppFunctionName(sourceType, targetType);
+ QString isConv = convertibleToCppFunctionName(sourceType, targetType);
+ writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
+ }
+
+ writeCustomConverterRegister(s, customConversion, QLatin1String("converter"));
+}
+
+void CppGenerator::writeCustomConverterRegister(QTextStream& s, const CustomConversion* customConversion, const QString& converterVar)
+{
+ if (!customConversion)
+ return;
+ const CustomConversion::TargetToNativeConversions& toCppConversions = customConversion->targetToNativeConversions();
+ if (toCppConversions.isEmpty())
+ return;
+ s << INDENT << "// Add user defined implicit conversions to type converter." << endl;
+ for (CustomConversion::TargetToNativeConversion *toNative : toCppConversions) {
+ QString toCpp = pythonToCppFunctionName(toNative, customConversion->ownerType());
+ QString isConv = convertibleToCppFunctionName(toNative, customConversion->ownerType());
+ writeAddPythonToCppConversion(s, converterVar, toCpp, isConv);
+ }
+}
+
+void CppGenerator::writeContainerConverterRegister(QTextStream& s, const AbstractMetaType* container, const QString& converterVar)
+{
+ s << INDENT << "// Add user defined container conversion to type converter." << endl;
+ QString typeName = fixedCppTypeName(container);
+ QString toCpp = pythonToCppFunctionName(typeName, typeName);
+ QString isConv = convertibleToCppFunctionName(typeName, typeName);
+ writeAddPythonToCppConversion(s, converterVar, toCpp, isConv);
+}
+
+void CppGenerator::writeContainerConverterFunctions(QTextStream& s, const AbstractMetaType* containerType)
+{
+ writeCppToPythonFunction(s, containerType);
+ writePythonToCppConversionFunctions(s, containerType);
+}
+
+void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &overloadData,
+ GeneratorContext &context)
+{
+ const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
+ const AbstractMetaClass* ownerClass = rfunc->ownerClass();
+ int minArgs = overloadData.minArgs();
+ int maxArgs = overloadData.maxArgs();
+ bool initPythonArguments;
+ bool usesNamedArguments;
+
+ // If method is a constructor...
+ if (rfunc->isConstructor()) {
+ // Check if the right constructor was called.
+ if (!ownerClass->hasPrivateDestructor()) {
+ s << INDENT;
+ s << "if (Shiboken::Object::isUserType(" PYTHON_SELF_VAR ") && !Shiboken::ObjectType::canCallConstructor(" PYTHON_SELF_VAR "->ob_type, Shiboken::SbkType< ::";
+ QString qualifiedCppName;
+ if (!context.forSmartPointer())
+ qualifiedCppName = ownerClass->qualifiedCppName();
+ else
+ qualifiedCppName = context.preciseType()->cppSignature();
+
+ s << qualifiedCppName << " >()))" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl;
+ }
+ // Declare pointer for the underlying C++ object.
+ s << INDENT << "::";
+ if (!context.forSmartPointer()) {
+ s << (shouldGenerateCppWrapper(ownerClass) ? wrapperName(ownerClass)
+ : ownerClass->qualifiedCppName());
+ } else {
+ s << context.preciseType()->cppSignature();
+ }
+ s << "* cptr = 0;" << endl;
+
+ initPythonArguments = maxArgs > 0;
+ usesNamedArguments = !ownerClass->isQObject() && overloadData.hasArgumentWithDefaultValue();
+
+ } else {
+ if (rfunc->implementingClass() &&
+ (!rfunc->implementingClass()->isNamespace() && overloadData.hasInstanceFunction())) {
+ writeCppSelfDefinition(s, rfunc, context, overloadData.hasStaticFunction());
+ }
+ if (!rfunc->isInplaceOperator() && overloadData.hasNonVoidReturnType())
+ s << INDENT << "PyObject* " PYTHON_RETURN_VAR " = 0;" << endl;
+
+ initPythonArguments = minArgs != maxArgs || maxArgs > 1;
+ usesNamedArguments = rfunc->isCallOperator() || overloadData.hasArgumentWithDefaultValue();
+ }
+
+ if (maxArgs > 0) {
+ s << INDENT << "int overloadId = -1;" << endl;
+ s << INDENT << "PythonToCppFunc " PYTHON_TO_CPP_VAR;
+ if (pythonFunctionWrapperUsesListOfArguments(overloadData))
+ s << "[] = { 0" << QString::fromLatin1(", 0").repeated(maxArgs-1) << " }";
+ s << ';' << endl;
+ writeUnusedVariableCast(s, QLatin1String(PYTHON_TO_CPP_VAR));
+ }
+
+ if (usesNamedArguments && !rfunc->isCallOperator())
+ s << INDENT << "int numNamedArgs = (kwds ? PyDict_Size(kwds) : 0);" << endl;
+
+ if (initPythonArguments) {
+ s << INDENT << "int numArgs = ";
+ if (minArgs == 0 && maxArgs == 1 && !rfunc->isConstructor() && !pythonFunctionWrapperUsesListOfArguments(overloadData))
+ s << "(" PYTHON_ARG " == 0 ? 0 : 1);" << endl;
+ else
+ writeArgumentsInitializer(s, overloadData);
+ }
+}
+
+void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFunctionList overloads,
+ GeneratorContext &classContext)
+{
+ ErrorCode errorCode(-1);
+ OverloadData overloadData(overloads, this);
+
+ const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
+ const AbstractMetaClass* metaClass = rfunc->ownerClass();
+
+ s << "static int" << endl;
+ s << cpythonFunctionName(rfunc) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* args, PyObject* kwds)" << endl;
+ s << '{' << endl;
+
+ QSet<QString> argNamesSet;
+ if (usePySideExtensions() && metaClass->isQObject()) {
+ // Write argNames variable with all known argument names.
+ const OverloadData::MetaFunctionList &overloads = overloadData.overloads();
+ for (const AbstractMetaFunction *func : overloads) {
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument *arg : arguments) {
+ if (arg->defaultValueExpression().isEmpty() || func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+ argNamesSet << arg->name();
+ }
+ }
+ QStringList argNamesList = argNamesSet.toList();
+ qSort(argNamesList.begin(), argNamesList.end());
+ if (argNamesList.isEmpty()) {
+ s << INDENT << "const char** argNames = 0;" << endl;
+ } else {
+ s << INDENT << "const char* argNames[] = {\""
+ << argNamesList.join(QLatin1String("\", \"")) << "\"};" << endl;
+ }
+ s << INDENT << "const QMetaObject* metaObject;" << endl;
+ }
+
+ s << INDENT << "SbkObject* sbkSelf = reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ");" << endl;
+
+ if (metaClass->isAbstract() || metaClass->baseClassNames().size() > 1) {
+ s << INDENT << "SbkObjectType* type = reinterpret_cast<SbkObjectType*>(" PYTHON_SELF_VAR "->ob_type);" << endl;
+ s << INDENT << "SbkObjectType* myType = reinterpret_cast<SbkObjectType*>(" << cpythonTypeNameExt(metaClass->typeEntry()) << ");" << endl;
+ }
+
+ if (metaClass->isAbstract()) {
+ s << INDENT << "if (type == myType) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError," << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "\"'" << metaClass->qualifiedCppName();
+ }
+ s << "' represents a C++ abstract class and cannot be instantiated\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}' << endl << endl;
+ }
+
+ if (metaClass->baseClassNames().size() > 1) {
+ if (!metaClass->isAbstract()) {
+ s << INDENT << "if (type != myType) {" << endl;
+ }
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "Shiboken::ObjectType::copyMultimpleheritance(type, myType);" << endl;
+ }
+ if (!metaClass->isAbstract())
+ s << INDENT << '}' << endl << endl;
+ }
+
+ writeMethodWrapperPreamble(s, overloadData, classContext);
+
+ s << endl;
+
+ if (overloadData.maxArgs() > 0)
+ writeOverloadedFunctionDecisor(s, overloadData);
+
+ writeFunctionCalls(s, overloadData, classContext);
+ s << endl;
+
+ s << INDENT << "if (PyErr_Occurred() || !Shiboken::Object::setCppPointer(sbkSelf, Shiboken::SbkType< ::" << metaClass->qualifiedCppName() << " >(), cptr)) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "delete cptr;" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+ if (overloadData.maxArgs() > 0) {
+ s << INDENT << "if (!cptr) goto " << cpythonFunctionName(rfunc) << "_TypeError;" << endl;
+ s << endl;
+ }
+
+ s << INDENT << "Shiboken::Object::setValidCpp(sbkSelf, true);" << endl;
+ // If the created C++ object has a C++ wrapper the ownership is assigned to Python
+ // (first "1") and the flag indicating that the Python wrapper holds an C++ wrapper
+ // is marked as true (the second "1"). Otherwise the default values apply:
+ // Python owns it and C++ wrapper is false.
+ if (shouldGenerateCppWrapper(overloads.first()->ownerClass()))
+ s << INDENT << "Shiboken::Object::setHasCppWrapper(sbkSelf, true);" << endl;
+ // Need to check if a wrapper for same pointer is already registered
+ // Caused by bug PYSIDE-217, where deleted objects' wrappers are not released
+ s << INDENT << "if (Shiboken::BindingManager::instance().hasWrapper(cptr)) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "Shiboken::BindingManager::instance().releaseWrapper(Shiboken::BindingManager::instance().retrieveWrapper(cptr));" << endl;
+ }
+ s << INDENT << "}" << endl;
+ s << INDENT << "Shiboken::BindingManager::instance().registerWrapper(sbkSelf, cptr);" << endl;
+
+ // Create metaObject and register signal/slot
+ if (metaClass->isQObject() && usePySideExtensions()) {
+ s << endl << INDENT << "// QObject setup" << endl;
+ s << INDENT << "PySide::Signal::updateSourceObject(" PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "metaObject = cptr->metaObject(); // <- init python qt properties" << endl;
+ s << INDENT << "if (kwds && !PySide::fillQtProperties(" PYTHON_SELF_VAR ", metaObject, kwds, argNames, " << argNamesSet.count() << "))" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ }
+
+ // Constructor code injections, position=end
+ bool hasCodeInjectionsAtEnd = false;
+ for (AbstractMetaFunction *func : overloads) {
+ const CodeSnipList &injectedCodeSnips = func->injectedCodeSnips();
+ for (const CodeSnip &cs : injectedCodeSnips) {
+ if (cs.position == TypeSystem::CodeSnipPositionEnd) {
+ hasCodeInjectionsAtEnd = true;
+ break;
+ }
+ }
+ }
+ if (hasCodeInjectionsAtEnd) {
+ // FIXME: C++ arguments are not available in code injection on constructor when position = end.
+ s << INDENT << "switch(overloadId) {" << endl;
+ for (AbstractMetaFunction *func : overloads) {
+ Indentation indent(INDENT);
+ const CodeSnipList &injectedCodeSnips = func->injectedCodeSnips();
+ for (const CodeSnip &cs : injectedCodeSnips) {
+ if (cs.position == TypeSystem::CodeSnipPositionEnd) {
+ s << INDENT << "case " << metaClass->functions().indexOf(func) << ':' << endl;
+ s << INDENT << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode, func);
+ }
+ s << INDENT << '}' << endl;
+ break;
+ }
+ }
+ }
+ s << '}' << endl;
+ }
+
+ s << endl;
+ s << endl << INDENT << "return 1;" << endl;
+ if (overloadData.maxArgs() > 0)
+ writeErrorSection(s, overloadData);
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunctionList overloads,
+ GeneratorContext &classContext)
+{
+ OverloadData overloadData(overloads, this);
+ const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
+
+ int maxArgs = overloadData.maxArgs();
+
+ s << "static PyObject* ";
+ s << cpythonFunctionName(rfunc) << "(PyObject* " PYTHON_SELF_VAR;
+ if (maxArgs > 0) {
+ s << ", PyObject* " << (pythonFunctionWrapperUsesListOfArguments(overloadData) ? "args" : PYTHON_ARG);
+ if (overloadData.hasArgumentWithDefaultValue() || rfunc->isCallOperator())
+ s << ", PyObject* kwds";
+ }
+ s << ')' << endl << '{' << endl;
+
+ writeMethodWrapperPreamble(s, overloadData, classContext);
+
+ s << endl;
+
+ /*
+ * Make sure reverse <</>> operators defined in other classes (specially from other modules)
+ * are called. A proper and generic solution would require an reengineering in the operator
+ * system like the extended converters.
+ *
+ * Solves #119 - QDataStream <</>> operators not working for QPixmap
+ * http://bugs.openbossa.org/show_bug.cgi?id=119
+ */
+ bool hasReturnValue = overloadData.hasNonVoidReturnType();
+ bool callExtendedReverseOperator = hasReturnValue
+ && !rfunc->isInplaceOperator()
+ && !rfunc->isCallOperator()
+ && rfunc->isOperatorOverload();
+ if (callExtendedReverseOperator) {
+ QString revOpName = ShibokenGenerator::pythonOperatorFunctionName(rfunc).insert(2, QLatin1Char('r'));
+ if (rfunc->isBinaryOperator()) {
+ s << INDENT << "if (!isReverse" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "&& Shiboken::Object::checkType(" PYTHON_ARG ")" << endl;
+ s << INDENT << "&& !PyObject_TypeCheck(" PYTHON_ARG ", " PYTHON_SELF_VAR "->ob_type)" << endl;
+ s << INDENT << "&& PyObject_HasAttrString(" PYTHON_ARG ", const_cast<char*>(\"" << revOpName << "\"))) {" << endl;
+
+ // This PyObject_CallMethod call will emit lots of warnings like
+ // "deprecated conversion from string constant to char *" during compilation
+ // due to the method name argument being declared as "char*" instead of "const char*"
+ // issue 6952 http://bugs.python.org/issue6952
+ s << INDENT << "PyObject* revOpMethod = PyObject_GetAttrString(" PYTHON_ARG ", const_cast<char*>(\"" << revOpName << "\"));" << endl;
+ s << INDENT << "if (revOpMethod && PyCallable_Check(revOpMethod)) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << PYTHON_RETURN_VAR " = PyObject_CallFunction(revOpMethod, const_cast<char*>(\"O\"), " PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "if (PyErr_Occurred() && (PyErr_ExceptionMatches(PyExc_NotImplementedError)";
+ s << " || PyErr_ExceptionMatches(PyExc_AttributeError))) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_Clear();" << endl;
+ s << INDENT << "Py_XDECREF(" PYTHON_RETURN_VAR ");" << endl;
+ s << INDENT << PYTHON_RETURN_VAR " = 0;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ }
+ s << INDENT << "}" << endl;
+ s << INDENT << "Py_XDECREF(revOpMethod);" << endl << endl;
+ }
+ s << INDENT << "}" << endl;
+ }
+ s << INDENT << "// Do not enter here if other object has implemented a reverse operator." << endl;
+ s << INDENT << "if (!" PYTHON_RETURN_VAR ") {" << endl << endl;
+ }
+
+ if (maxArgs > 0)
+ writeOverloadedFunctionDecisor(s, overloadData);
+
+ writeFunctionCalls(s, overloadData, classContext);
+
+ if (callExtendedReverseOperator)
+ s << endl << INDENT << "} // End of \"if (!" PYTHON_RETURN_VAR ")\"" << endl;
+
+ s << endl;
+
+ writeFunctionReturnErrorCheckSection(s, hasReturnValue && !rfunc->isInplaceOperator());
+
+ if (hasReturnValue) {
+ if (rfunc->isInplaceOperator()) {
+ s << INDENT << "Py_INCREF(" PYTHON_SELF_VAR ");\n";
+ s << INDENT << "return " PYTHON_SELF_VAR ";\n";
+ } else {
+ s << INDENT << "return " PYTHON_RETURN_VAR ";\n";
+ }
+ } else {
+ s << INDENT << "Py_RETURN_NONE;" << endl;
+ }
+
+ if (maxArgs > 0)
+ writeErrorSection(s, overloadData);
+
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overloadData)
+{
+ const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
+ s << "PyTuple_GET_SIZE(args);" << endl;
+
+ int minArgs = overloadData.minArgs();
+ int maxArgs = overloadData.maxArgs();
+
+ s << INDENT << "PyObject* ";
+ s << PYTHON_ARGS "[] = {"
+ << QString(maxArgs, QLatin1Char('0')).split(QLatin1String(""), QString::SkipEmptyParts).join(QLatin1String(", "))
+ << "};" << endl;
+ s << endl;
+
+ if (overloadData.hasVarargs()) {
+ maxArgs--;
+ if (minArgs > maxArgs)
+ minArgs = maxArgs;
+
+ s << INDENT << "PyObject* nonvarargs = PyTuple_GetSlice(args, 0, " << maxArgs << ");" << endl;
+ s << INDENT << "Shiboken::AutoDecRef auto_nonvarargs(nonvarargs);" << endl;
+ s << INDENT << PYTHON_ARGS "[" << maxArgs << "] = PyTuple_GetSlice(args, " << maxArgs << ", numArgs);" << endl;
+ s << INDENT << "Shiboken::AutoDecRef auto_varargs(" PYTHON_ARGS "[" << maxArgs << "]);" << endl;
+ s << endl;
+ }
+
+ bool usesNamedArguments = overloadData.hasArgumentWithDefaultValue();
+
+ s << INDENT << "// invalid argument lengths" << endl;
+ bool ownerClassIsQObject = rfunc->ownerClass() && rfunc->ownerClass()->isQObject() && rfunc->isConstructor();
+ if (usesNamedArguments) {
+ if (!ownerClassIsQObject) {
+ s << INDENT << "if (numArgs" << (overloadData.hasArgumentWithDefaultValue() ? " + numNamedArgs" : "") << " > " << maxArgs << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): too many arguments\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}';
+ }
+ if (minArgs > 0) {
+ if (ownerClassIsQObject)
+ s << INDENT;
+ else
+ s << " else ";
+ s << "if (numArgs < " << minArgs << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): not enough arguments\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}';
+ }
+ }
+ const QVector<int> invalidArgsLength = overloadData.invalidArgumentLengths();
+ if (!invalidArgsLength.isEmpty()) {
+ QStringList invArgsLen;
+ for (int i : qAsConst(invalidArgsLength))
+ invArgsLen << QStringLiteral("numArgs == %1").arg(i);
+ if (usesNamedArguments && (!ownerClassIsQObject || minArgs > 0))
+ s << " else ";
+ else
+ s << INDENT;
+ s << "if (" << invArgsLen.join(QLatin1String(" || ")) << ")" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "goto " << cpythonFunctionName(rfunc) << "_TypeError;";
+ }
+ s << endl << endl;
+
+ QString funcName;
+ if (rfunc->isOperatorOverload())
+ funcName = ShibokenGenerator::pythonOperatorFunctionName(rfunc);
+ else
+ funcName = rfunc->name();
+
+ QString argsVar = overloadData.hasVarargs() ? QLatin1String("nonvarargs") : QLatin1String("args");
+ s << INDENT << "if (!";
+ if (usesNamedArguments)
+ s << "PyArg_ParseTuple(" << argsVar << ", \"|" << QByteArray(maxArgs, 'O') << ':' << funcName << '"';
+ else
+ s << "PyArg_UnpackTuple(" << argsVar << ", \"" << funcName << "\", " << minArgs << ", " << maxArgs;
+ QStringList palist;
+ for (int i = 0; i < maxArgs; i++)
+ palist << QString::fromLatin1("&(" PYTHON_ARGS "[%1])").arg(i);
+ s << ", " << palist.join(QLatin1String(", ")) << "))" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << endl;
+}
+
+void CppGenerator::writeCppSelfDefinition(QTextStream &s,
+ GeneratorContext &context,
+ bool hasStaticOverload,
+ bool cppSelfAsReference)
+{
+ const AbstractMetaClass *metaClass = context.metaClass();
+ bool useWrapperClass = avoidProtectedHack() && metaClass->hasProtectedMembers();
+ QString className;
+ if (!context.forSmartPointer()) {
+ className = useWrapperClass
+ ? wrapperName(metaClass)
+ : (QLatin1String("::") + metaClass->qualifiedCppName());
+ } else {
+ className = context.preciseType()->cppSignature();
+ }
+
+ QString cppSelfAttribution;
+ QString pythonSelfVar = QLatin1String(PYTHON_SELF_VAR);
+ QString cpythonWrapperCPtrResult;
+ if (!context.forSmartPointer())
+ cpythonWrapperCPtrResult = cpythonWrapperCPtr(metaClass, pythonSelfVar);
+ else
+ cpythonWrapperCPtrResult = cpythonWrapperCPtr(context.preciseType(), pythonSelfVar);
+
+ if (cppSelfAsReference) {
+ QString cast = useWrapperClass ? QString::fromLatin1("(%1*)").arg(className) : QString();
+ cppSelfAttribution = QString::fromLatin1("%1& %2 = *(%3%4)")
+ .arg(className, QLatin1String(CPP_SELF_VAR), cast,
+ cpythonWrapperCPtrResult);
+ } else {
+ s << INDENT << className << "* " CPP_SELF_VAR " = 0;" << endl;
+ writeUnusedVariableCast(s, QLatin1String(CPP_SELF_VAR));
+ cppSelfAttribution = QString::fromLatin1("%1 = %2%3")
+ .arg(QLatin1String(CPP_SELF_VAR),
+ (useWrapperClass ? QString::fromLatin1("(%1*)").arg(className) : QString()),
+ cpythonWrapperCPtrResult);
+ }
+
+ // Checks if the underlying C++ object is valid.
+ if (hasStaticOverload && !cppSelfAsReference) {
+ s << INDENT << "if (" PYTHON_SELF_VAR ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR));
+ s << INDENT << cppSelfAttribution << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+ return;
+ }
+
+ writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR));
+ s << INDENT << cppSelfAttribution << ';' << endl;
+}
+
+void CppGenerator::writeCppSelfDefinition(QTextStream &s,
+ const AbstractMetaFunction *func,
+ GeneratorContext &context,
+ bool hasStaticOverload)
+{
+ if (!func->ownerClass() || func->isConstructor())
+ return;
+
+ if (func->isOperatorOverload() && func->isBinaryOperator()) {
+ QString checkFunc = cpythonCheckFunction(func->ownerClass()->typeEntry());
+ s << INDENT << "bool isReverse = " << checkFunc << PYTHON_ARG ")" << endl;
+ {
+ Indentation indent1(INDENT);
+ Indentation indent2(INDENT);
+ Indentation indent3(INDENT);
+ Indentation indent4(INDENT);
+ s << INDENT << "&& !" << checkFunc << PYTHON_SELF_VAR ");" << endl;
+ }
+ s << INDENT << "if (isReverse)" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "std::swap(" PYTHON_SELF_VAR ", " PYTHON_ARG ");" << endl;
+ }
+
+ writeCppSelfDefinition(s, context, hasStaticOverload);
+}
+
+void CppGenerator::writeErrorSection(QTextStream& s, OverloadData& overloadData)
+{
+ const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
+ s << endl << INDENT << cpythonFunctionName(rfunc) << "_TypeError:" << endl;
+ Indentation indentation(INDENT);
+ QString funcName = fullPythonFunctionName(rfunc);
+
+ QString argsVar = pythonFunctionWrapperUsesListOfArguments(overloadData)
+ ? QLatin1String("args") : QLatin1String(PYTHON_ARG);
+ if (verboseErrorMessagesDisabled()) {
+ s << INDENT << "Shiboken::setErrorAboutWrongArguments(" << argsVar << ", \"" << funcName << "\", 0);" << endl;
+ } else {
+ QStringList overloadSignatures;
+ const OverloadData::MetaFunctionList &overloads = overloadData.overloads();
+ for (const AbstractMetaFunction *f : overloads) {
+ QStringList args;
+ const AbstractMetaArgumentList &arguments = f->arguments();
+ for (AbstractMetaArgument *arg : arguments) {
+ QString strArg;
+ AbstractMetaType* argType = arg->type();
+ if (isCString(argType)) {
+ strArg = QLatin1String("\" SBK_STR_NAME \"");
+ } else if (argType->isPrimitive()) {
+ const PrimitiveTypeEntry* ptp = reinterpret_cast<const PrimitiveTypeEntry*>(argType->typeEntry());
+ while (ptp->referencedTypeEntry())
+ ptp = ptp->referencedTypeEntry();
+ strArg = ptp->name();
+ if (strArg == QLatin1String("QString")) {
+ strArg = QLatin1String("unicode");
+ } else if (strArg == QLatin1String("QChar")) {
+ strArg = QLatin1String("1-unicode");
+ } else {
+ strArg = ptp->name();
+ static const QRegularExpression regex(QStringLiteral("^signed\\s+"));
+ Q_ASSERT(regex.isValid());
+ strArg.remove(regex);
+ if (strArg == QLatin1String("double"))
+ strArg = QLatin1String("float");
+ }
+ } else if (argType->typeEntry()->isContainer()) {
+ strArg = argType->fullName();
+ if (strArg == QLatin1String("QList") || strArg == QLatin1String("QVector")
+ || strArg == QLatin1String("QLinkedList") || strArg == QLatin1String("QStack")
+ || strArg == QLatin1String("QQueue")) {
+ strArg = QLatin1String("list");
+ } else if (strArg == QLatin1String("QMap") || strArg == QLatin1String("QHash")
+ || strArg == QLatin1String("QMultiMap") || strArg == QLatin1String("QMultiHash")) {
+ strArg = QLatin1String("dict");
+ } else if (strArg == QLatin1String("QPair")) {
+ strArg = QLatin1String("2-tuple");
+ }
+ } else {
+ strArg = argType->fullName();
+ if (strArg == QLatin1String("PyUnicode"))
+ strArg = QLatin1String("unicode");
+ else if (strArg == QLatin1String("PyString"))
+ strArg = QLatin1String("str");
+ else if (strArg == QLatin1String("PyBytes"))
+ strArg = QLatin1String("\" SBK_STR_NAME \"");
+ else if (strArg == QLatin1String("PySequece"))
+ strArg = QLatin1String("list");
+ else if (strArg == QLatin1String("PyTuple"))
+ strArg = QLatin1String("tuple");
+ else if (strArg == QLatin1String("PyDict"))
+ strArg = QLatin1String("dict");
+ else if (strArg == QLatin1String("PyObject"))
+ strArg = QLatin1String("object");
+ else if (strArg == QLatin1String("PyCallable"))
+ strArg = QLatin1String("callable");
+ else if (strArg == QLatin1String("uchar"))
+ strArg = QLatin1String("buffer"); // This depends on an inject code to be true, but if it's not true
+ // the function wont work at all, so it must be true.
+ }
+ if (!arg->defaultValueExpression().isEmpty()) {
+ strArg += QLatin1String(" = ");
+ if ((isCString(argType) || isPointerToWrapperType(argType))
+ && arg->defaultValueExpression() == QLatin1String("0")) {
+ strArg += QLatin1String("None");
+ } else {
+ QString e = arg->defaultValueExpression();
+ e.replace(QLatin1String("::"), QLatin1String("."));
+ e.replace(QLatin1String("\""), QLatin1String("\\\""));
+ strArg += e;
+ }
+ }
+ args << strArg;
+ }
+ overloadSignatures << QLatin1Char('"') + args.join(QLatin1String(", ")) + QLatin1Char('"');
+ }
+ s << INDENT << "const char* overloads[] = {" << overloadSignatures.join(QLatin1String(", "))
+ << ", 0};" << endl;
+ s << INDENT << "Shiboken::setErrorAboutWrongArguments(" << argsVar << ", \"" << funcName << "\", overloads);" << endl;
+ }
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+}
+
+void CppGenerator::writeFunctionReturnErrorCheckSection(QTextStream& s, bool hasReturnValue)
+{
+ s << INDENT << "if (PyErr_Occurred()" << (hasReturnValue ? " || !" PYTHON_RETURN_VAR : "") << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ if (hasReturnValue)
+ s << INDENT << "Py_XDECREF(" PYTHON_RETURN_VAR ");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+}
+
+void CppGenerator::writeInvalidPyObjectCheck(QTextStream& s, const QString& pyObj)
+{
+ s << INDENT << "if (!Shiboken::Object::isValid(" << pyObj << "))" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+}
+
+static QString pythonToCppConverterForArgumentName(const QString& argumentName)
+{
+ static const QRegularExpression pyArgsRegex(QLatin1String(PYTHON_ARGS"(\\[\\d+[-]?\\d*\\])"));
+ Q_ASSERT(pyArgsRegex.isValid());
+ const QRegularExpressionMatch match = pyArgsRegex.match(argumentName);
+ QString result = QLatin1String(PYTHON_TO_CPP_VAR);
+ if (match.hasMatch())
+ result += match.captured(1);
+ return result;
+}
+
+void CppGenerator::writeTypeCheck(QTextStream& s, const AbstractMetaType* argType, QString argumentName, bool isNumber, QString customType, bool rejectNull)
+{
+ QString customCheck;
+ if (!customType.isEmpty()) {
+ AbstractMetaType* metaType;
+ customCheck = guessCPythonCheckFunction(customType, &metaType);
+ if (metaType)
+ argType = metaType;
+ }
+
+ // TODO-CONVERTER: merge this with the code below.
+ QString typeCheck;
+ if (customCheck.isEmpty())
+ typeCheck = cpythonIsConvertibleFunction(argType, argType->isEnum() ? false : isNumber);
+ else
+ typeCheck = customCheck;
+ typeCheck.append(QString::fromLatin1("(%1)").arg(argumentName));
+
+ // TODO-CONVERTER -----------------------------------------------------------------------
+ if (customCheck.isEmpty() && !argType->typeEntry()->isCustom()) {
+ typeCheck = QString::fromLatin1("(%1 = %2))").arg(pythonToCppConverterForArgumentName(argumentName), typeCheck);
+ if (!isNumber && argType->typeEntry()->isCppPrimitive())
+ typeCheck.prepend(QString::fromLatin1("%1(%2) && ").arg(cpythonCheckFunction(argType), argumentName));
+ }
+ // TODO-CONVERTER -----------------------------------------------------------------------
+
+ if (rejectNull)
+ typeCheck = QString::fromLatin1("(%1 != Py_None && %2)").arg(argumentName, typeCheck);
+
+ s << typeCheck;
+}
+
+static void checkTypeViability(const AbstractMetaFunction* func, const AbstractMetaType* type, int argIdx)
+{
+ if (!type
+ || !type->typeEntry()->isPrimitive()
+ || type->indirections() == 0
+ || ShibokenGenerator::isCString(type)
+ || func->argumentRemoved(argIdx)
+ || !func->typeReplaced(argIdx).isEmpty()
+ || !func->conversionRule(TypeSystem::All, argIdx).isEmpty()
+ || func->hasInjectedCode())
+ return;
+ QString prefix;
+ if (func->ownerClass())
+ prefix = func->ownerClass()->qualifiedCppName() + QLatin1String("::");
+ qCWarning(lcShiboken).noquote().nospace()
+ << QString::fromLatin1("There's no user provided way (conversion rule, argument removal, custom code, etc) "
+ "to handle the primitive %1 type '%2' in function '%3%4'.")
+ .arg(argIdx == 0 ? QStringLiteral("return") : QStringLiteral("argument"),
+ type->cppSignature(), prefix, func->signature());
+}
+
+static void checkTypeViability(const AbstractMetaFunction* func)
+{
+ if (func->isUserAdded())
+ return;
+ const AbstractMetaType* type = func->type();
+ checkTypeViability(func, type, 0);
+ for (int i = 0; i < func->arguments().count(); ++i)
+ checkTypeViability(func, func->arguments().at(i)->type(), i + 1);
+}
+
+void CppGenerator::writeTypeCheck(QTextStream& s, const OverloadData* overloadData, QString argumentName)
+{
+ QSet<const TypeEntry*> numericTypes;
+ const OverloadDataList &overloads = overloadData->previousOverloadData()->nextOverloadData();
+ for (OverloadData *od : overloads) {
+ const OverloadData::MetaFunctionList &odOverloads = od->overloads();
+ for (const AbstractMetaFunction *func : odOverloads) {
+ checkTypeViability(func);
+ const AbstractMetaType* argType = od->argument(func)->type();
+ if (!argType->isPrimitive())
+ continue;
+ if (ShibokenGenerator::isNumber(argType->typeEntry()))
+ numericTypes << argType->typeEntry();
+ }
+ }
+
+ // This condition trusts that the OverloadData object will arrange for
+ // PyInt type to come after the more precise numeric types (e.g. float and bool)
+ const AbstractMetaType* argType = overloadData->argType();
+ bool numberType = numericTypes.count() == 1 || ShibokenGenerator::isPyInt(argType);
+ QString customType = (overloadData->hasArgumentTypeReplace() ? overloadData->argumentTypeReplaced() : QString());
+ bool rejectNull = shouldRejectNullPointerArgument(overloadData->referenceFunction(), overloadData->argPos());
+ writeTypeCheck(s, argType, argumentName, numberType, customType, rejectNull);
+}
+
+void CppGenerator::writeArgumentConversion(QTextStream& s,
+ const AbstractMetaType* argType,
+ const QString& argName, const QString& pyArgName,
+ const AbstractMetaClass* context,
+ const QString& defaultValue,
+ bool castArgumentAsUnused)
+{
+ if (argType->typeEntry()->isCustom() || argType->typeEntry()->isVarargs())
+ return;
+ if (isWrapperType(argType))
+ writeInvalidPyObjectCheck(s, pyArgName);
+ writePythonToCppTypeConversion(s, argType, pyArgName, argName, context, defaultValue);
+ if (castArgumentAsUnused)
+ writeUnusedVariableCast(s, argName);
+}
+
+const AbstractMetaType* CppGenerator::getArgumentType(const AbstractMetaFunction* func, int argPos)
+{
+ if (argPos < 0 || argPos > func->arguments().size()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("Argument index for function '%1' out of range.").arg(func->signature());
+ return 0;
+ }
+
+ const AbstractMetaType* argType = 0;
+ QString typeReplaced = func->typeReplaced(argPos);
+ if (typeReplaced.isEmpty())
+ argType = (argPos == 0) ? func->type() : func->arguments().at(argPos-1)->type();
+ else
+ argType = buildAbstractMetaTypeFromString(typeReplaced);
+ if (!argType && !m_knownPythonTypes.contains(typeReplaced)) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QString::fromLatin1("Unknown type '%1' used as argument type replacement "\
+ "in function '%2', the generated code may be broken.")
+ .arg(typeReplaced, func->signature());
+ }
+ return argType;
+}
+
+void CppGenerator::writePythonToCppTypeConversion(QTextStream& s,
+ const AbstractMetaType* type,
+ const QString& pyIn,
+ const QString& cppOut,
+ const AbstractMetaClass* /* context */,
+ const QString& defaultValue)
+{
+ const TypeEntry* typeEntry = type->typeEntry();
+ if (typeEntry->isCustom() || typeEntry->isVarargs())
+ return;
+
+ QString cppOutAux = cppOut + QLatin1String("_local");
+
+ bool treatAsPointer = isValueTypeWithCopyConstructorOnly(type);
+ bool isPointerOrObjectType = (isObjectType(type) || isPointer(type)) && !isUserPrimitive(type) && !isCppPrimitive(type);
+ bool isNotContainerEnumOrFlags = !typeEntry->isContainer() && !typeEntry->isEnum() && !typeEntry->isFlags();
+ bool mayHaveImplicitConversion = type->referenceType() == LValueReference
+ && !isUserPrimitive(type)
+ && !isCppPrimitive(type)
+ && isNotContainerEnumOrFlags
+ && !(treatAsPointer || isPointerOrObjectType);
+ QString typeName = getFullTypeNameWithoutModifiers(type);
+
+ bool isProtectedEnum = false;
+
+ if (mayHaveImplicitConversion) {
+ s << INDENT << typeName << ' ' << cppOutAux;
+ writeMinimalConstructorExpression(s, type, defaultValue);
+ s << ';' << endl;
+ } else if (avoidProtectedHack() && type->typeEntry()->isEnum()) {
+ const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(type);
+ if (metaEnum && metaEnum->isProtected()) {
+ typeName = QLatin1String("long");
+ isProtectedEnum = true;
+ }
+ }
+
+ s << INDENT << typeName;
+ if (treatAsPointer || isPointerOrObjectType) {
+ s << "* " << cppOut;
+ if (!defaultValue.isEmpty())
+ s << " = " << defaultValue;
+ } else if (type->referenceType() == LValueReference && !typeEntry->isPrimitive() && isNotContainerEnumOrFlags) {
+ s << "* " << cppOut << " = &" << cppOutAux;
+ } else {
+ s << ' ' << cppOut;
+ if (isProtectedEnum && avoidProtectedHack()) {
+ s << " = ";
+ if (defaultValue.isEmpty())
+ s << "0";
+ else
+ s << "(long)" << defaultValue;
+ } else if (isUserPrimitive(type) || typeEntry->isEnum() || typeEntry->isFlags()) {
+ writeMinimalConstructorExpression(s, typeEntry, defaultValue);
+ } else if (!type->isContainer() && !type->isSmartPointer()) {
+ writeMinimalConstructorExpression(s, type, defaultValue);
+ }
+ }
+ s << ';' << endl;
+
+ QString pythonToCppFunc = pythonToCppConverterForArgumentName(pyIn);
+
+ s << INDENT;
+ if (!defaultValue.isEmpty())
+ s << "if (" << pythonToCppFunc << ") ";
+
+ QString pythonToCppCall = QString::fromLatin1("%1(%2, &%3)").arg(pythonToCppFunc, pyIn, cppOut);
+ if (!mayHaveImplicitConversion) {
+ s << pythonToCppCall << ';' << endl;
+ return;
+ }
+
+ if (!defaultValue.isEmpty())
+ s << '{' << endl << INDENT;
+
+ s << "if (Shiboken::Conversions::isImplicitConversion(reinterpret_cast<const SbkObjectType *>("
+ << cpythonTypeNameExt(type) << "), " << pythonToCppFunc << "))" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << pythonToCppFunc << '(' << pyIn << ", &" << cppOutAux << ");" << endl;
+ }
+ s << INDENT << "else" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << pythonToCppCall << ';' << endl;
+ }
+
+ if (!defaultValue.isEmpty())
+ s << INDENT << '}';
+ s << endl;
+}
+
+static void addConversionRuleCodeSnippet(CodeSnipList& snippetList, QString& rule,
+ TypeSystem::Language /* conversionLanguage */,
+ TypeSystem::Language snippetLanguage,
+ QString outputName = QString(),
+ QString inputName = QString())
+{
+ if (rule.isEmpty())
+ return;
+ if (snippetLanguage == TypeSystem::TargetLangCode) {
+ rule.replace(QLatin1String("%in"), inputName);
+ rule.replace(QLatin1String("%out"), outputName + QLatin1String("_out"));
+ } else {
+ rule.replace(QLatin1String("%out"), outputName);
+ }
+ CodeSnip snip(0, snippetLanguage);
+ snip.position = (snippetLanguage == TypeSystem::NativeCode) ? TypeSystem::CodeSnipPositionAny : TypeSystem::CodeSnipPositionBeginning;
+ snip.addCode(rule);
+ snippetList << snip;
+}
+
+void CppGenerator::writeConversionRule(QTextStream& s, const AbstractMetaFunction* func, TypeSystem::Language language)
+{
+ CodeSnipList snippets;
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (AbstractMetaArgument *arg : arguments) {
+ QString rule = func->conversionRule(language, arg->argumentIndex() + 1);
+ addConversionRuleCodeSnippet(snippets, rule, language, TypeSystem::TargetLangCode,
+ arg->name(), arg->name());
+ }
+ writeCodeSnips(s, snippets, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode, func);
+}
+
+void CppGenerator::writeConversionRule(QTextStream& s, const AbstractMetaFunction* func, TypeSystem::Language language, const QString& outputVar)
+{
+ CodeSnipList snippets;
+ QString rule = func->conversionRule(language, 0);
+ addConversionRuleCodeSnippet(snippets, rule, language, language, outputVar);
+ writeCodeSnips(s, snippets, TypeSystem::CodeSnipPositionAny, language, func);
+}
+
+void CppGenerator::writeNoneReturn(QTextStream& s, const AbstractMetaFunction* func, bool thereIsReturnValue)
+{
+ if (thereIsReturnValue && (!func->type() || func->argumentRemoved(0)) && !injectedCodeHasReturnValueAttribution(func)) {
+ s << INDENT << PYTHON_RETURN_VAR " = Py_None;" << endl;
+ s << INDENT << "Py_INCREF(Py_None);" << endl;
+ }
+}
+
+void CppGenerator::writeOverloadedFunctionDecisor(QTextStream& s, const OverloadData& overloadData)
+{
+ s << INDENT << "// Overloaded function decisor" << endl;
+ const AbstractMetaFunction* rfunc = overloadData.referenceFunction();
+ const OverloadData::MetaFunctionList &functionOverloads = overloadData.overloadsWithoutRepetition();
+ for (int i = 0; i < functionOverloads.count(); i++)
+ s << INDENT << "// " << i << ": " << functionOverloads.at(i)->minimalSignature() << endl;
+ writeOverloadedFunctionDecisorEngine(s, &overloadData);
+ s << endl;
+
+ // Ensure that the direct overload that called this reverse
+ // is called.
+ if (rfunc->isOperatorOverload() && !rfunc->isCallOperator()) {
+ s << INDENT << "if (isReverse && overloadId == -1) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"reverse operator not implemented.\");" << endl;
+ s << INDENT << "return 0;" << endl;
+ }
+ s << INDENT << "}" << endl << endl;
+ }
+
+ s << INDENT << "// Function signature not found." << endl;
+ s << INDENT << "if (overloadId == -1) goto " << cpythonFunctionName(overloadData.referenceFunction()) << "_TypeError;" << endl;
+ s << endl;
+}
+
+void CppGenerator::writeOverloadedFunctionDecisorEngine(QTextStream& s, const OverloadData* parentOverloadData)
+{
+ bool hasDefaultCall = parentOverloadData->nextArgumentHasDefaultValue();
+ const AbstractMetaFunction* referenceFunction = parentOverloadData->referenceFunction();
+
+ // If the next argument has not an argument with a default value, it is still possible
+ // that one of the overloads for the current overload data has its final occurrence here.
+ // If found, the final occurrence of a method is attributed to the referenceFunction
+ // variable to be used further on this method on the conditional that identifies default
+ // method calls.
+ if (!hasDefaultCall) {
+ const OverloadData::MetaFunctionList &overloads = parentOverloadData->overloads();
+ for (const AbstractMetaFunction *func : overloads) {
+ if (parentOverloadData->isFinalOccurrence(func)) {
+ referenceFunction = func;
+ hasDefaultCall = true;
+ break;
+ }
+ }
+ }
+
+ int maxArgs = parentOverloadData->maxArgs();
+ // Python constructors always receive multiple arguments.
+ bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(*parentOverloadData);
+
+ // Functions without arguments are identified right away.
+ if (maxArgs == 0) {
+ s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(referenceFunction);
+ s << "; // " << referenceFunction->minimalSignature() << endl;
+ return;
+
+ // To decide if a method call is possible at this point the current overload
+ // data object cannot be the head, since it is just an entry point, or a root,
+ // for the tree of arguments and it does not represent a valid method call.
+ } else if (!parentOverloadData->isHeadOverloadData()) {
+ bool isLastArgument = parentOverloadData->nextOverloadData().isEmpty();
+ bool signatureFound = parentOverloadData->overloads().size() == 1;
+
+ // The current overload data describes the last argument of a signature,
+ // so the method can be identified right now.
+ if (isLastArgument || (signatureFound && !hasDefaultCall)) {
+ const AbstractMetaFunction* func = parentOverloadData->referenceFunction();
+ s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(func);
+ s << "; // " << func->minimalSignature() << endl;
+ return;
+ }
+ }
+
+ bool isFirst = true;
+
+ // If the next argument has a default value the decisor can perform a method call;
+ // it just need to check if the number of arguments received from Python are equal
+ // to the number of parameters preceding the argument with the default value.
+ const OverloadDataList &overloads = parentOverloadData->nextOverloadData();
+ if (hasDefaultCall) {
+ isFirst = false;
+ int numArgs = parentOverloadData->argPos() + 1;
+ s << INDENT << "if (numArgs == " << numArgs << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ const AbstractMetaFunction* func = referenceFunction;
+ for (OverloadData *overloadData : overloads) {
+ const AbstractMetaFunction* defValFunc = overloadData->getFunctionWithDefaultValue();
+ if (defValFunc) {
+ func = defValFunc;
+ break;
+ }
+ }
+ s << INDENT << "overloadId = " << parentOverloadData->headOverloadData()->overloads().indexOf(func);
+ s << "; // " << func->minimalSignature() << endl;
+ }
+ s << INDENT << '}';
+ }
+
+ for (OverloadData *overloadData : overloads) {
+ bool signatureFound = overloadData->overloads().size() == 1
+ && !overloadData->getFunctionWithDefaultValue()
+ && !overloadData->findNextArgWithDefault();
+
+ const AbstractMetaFunction* refFunc = overloadData->referenceFunction();
+
+ QStringList typeChecks;
+ QString pyArgName = (usePyArgs && maxArgs > 1)
+ ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(overloadData->argPos())
+ : QLatin1String(PYTHON_ARG);
+ OverloadData* od = overloadData;
+ int startArg = od->argPos();
+ int sequenceArgCount = 0;
+ while (od && !od->argType()->isVarargs()) {
+ bool typeReplacedByPyObject = od->argumentTypeReplaced() == QLatin1String("PyObject");
+ if (!typeReplacedByPyObject) {
+ if (usePyArgs)
+ pyArgName = QString::fromLatin1(PYTHON_ARGS "[%1]").arg(od->argPos());
+ QString typeCheck;
+ QTextStream tck(&typeCheck);
+ const AbstractMetaFunction* func = od->referenceFunction();
+
+ if (func->isConstructor() && func->arguments().count() == 1) {
+ const AbstractMetaClass* ownerClass = func->ownerClass();
+ const ComplexTypeEntry* baseContainerType = ownerClass->typeEntry()->baseContainerType();
+ if (baseContainerType && baseContainerType == func->arguments().first()->type()->typeEntry() && isCopyable(ownerClass)) {
+ tck << '!' << cpythonCheckFunction(ownerClass->typeEntry()) << pyArgName << ')' << endl;
+ Indentation indent(INDENT);
+ tck << INDENT << "&& ";
+ }
+ }
+ writeTypeCheck(tck, od, pyArgName);
+ typeChecks << typeCheck;
+ }
+
+ sequenceArgCount++;
+
+ if (od->nextOverloadData().isEmpty()
+ || od->nextArgumentHasDefaultValue()
+ || od->nextOverloadData().size() != 1
+ || od->overloads().size() != od->nextOverloadData().first()->overloads().size()) {
+ overloadData = od;
+ od = 0;
+ } else {
+ od = od->nextOverloadData().first();
+ }
+ }
+
+ if (usePyArgs && signatureFound) {
+ AbstractMetaArgumentList args = refFunc->arguments();
+ int lastArgIsVarargs = (int) (args.size() > 1 && args.last()->type()->isVarargs());
+ int numArgs = args.size() - OverloadData::numberOfRemovedArguments(refFunc) - lastArgIsVarargs;
+ typeChecks.prepend(QString::fromLatin1("numArgs %1 %2").arg(lastArgIsVarargs ? QLatin1String(">=") : QLatin1String("==")).arg(numArgs));
+ } else if (sequenceArgCount > 1) {
+ typeChecks.prepend(QString::fromLatin1("numArgs >= %1").arg(startArg + sequenceArgCount));
+ } else if (refFunc->isOperatorOverload() && !refFunc->isCallOperator()) {
+ typeChecks.prepend(QString::fromLatin1("%1isReverse").arg(refFunc->isReverseOperator() ? QString() : QLatin1String("!")));
+ }
+
+ if (isFirst) {
+ isFirst = false;
+ s << INDENT;
+ } else {
+ s << " else ";
+ }
+ s << "if (";
+ if (typeChecks.isEmpty()) {
+ s << "true";
+ } else {
+ Indentation indent(INDENT);
+ QString separator;
+ QTextStream sep(&separator);
+ sep << endl << INDENT << "&& ";
+ s << typeChecks.join(separator);
+ }
+ s << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ writeOverloadedFunctionDecisorEngine(s, overloadData);
+ }
+ s << INDENT << "}";
+ }
+ s << endl;
+}
+
+void CppGenerator::writeFunctionCalls(QTextStream &s, const OverloadData &overloadData,
+ GeneratorContext &context)
+{
+ const OverloadData::MetaFunctionList &overloads = overloadData.overloadsWithoutRepetition();
+ s << INDENT << "// Call function/method" << endl;
+ s << INDENT << (overloads.count() > 1 ? "switch (overloadId) " : "") << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ if (overloads.count() == 1) {
+ writeSingleFunctionCall(s, overloadData, overloads.first(), context);
+ } else {
+ for (int i = 0; i < overloads.count(); i++) {
+ const AbstractMetaFunction* func = overloads.at(i);
+ s << INDENT << "case " << i << ": // " << func->signature() << endl;
+ s << INDENT << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ writeSingleFunctionCall(s, overloadData, func, context);
+ s << INDENT << "break;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ }
+ }
+ }
+ s << INDENT << '}' << endl;
+}
+
+void CppGenerator::writeSingleFunctionCall(QTextStream &s,
+ const OverloadData &overloadData,
+ const AbstractMetaFunction *func,
+ GeneratorContext &context)
+{
+ if (func->isDeprecated()) {
+ s << INDENT << "Shiboken::warning(PyExc_DeprecationWarning, 1, \"Function: '"
+ << func->signature().replace(QLatin1String("::"), QLatin1String("."))
+ << "' is marked as deprecated, please check the documentation for more information.\");" << endl;
+ }
+
+ if (func->functionType() == AbstractMetaFunction::EmptyFunction) {
+ s << INDENT << "PyErr_Format(PyExc_TypeError, \"%s is a private method.\", \""
+ << func->signature().replace(QLatin1String("::"), QLatin1String("."))
+ << "\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ return;
+ }
+
+ bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(overloadData);
+
+ // Handle named arguments.
+ writeNamedArgumentResolution(s, func, usePyArgs);
+
+ bool injectCodeCallsFunc = injectedCodeCallsCppFunction(func);
+ bool mayHaveUnunsedArguments = !func->isUserAdded() && func->hasInjectedCode() && injectCodeCallsFunc;
+ int removedArgs = 0;
+ for (int argIdx = 0; argIdx < func->arguments().count(); ++argIdx) {
+ bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, argIdx + 1).isEmpty();
+ const AbstractMetaArgument* arg = func->arguments().at(argIdx);
+ if (func->argumentRemoved(argIdx + 1)) {
+ if (!arg->defaultValueExpression().isEmpty()) {
+ QString cppArgRemoved = QString::fromLatin1(CPP_ARG_REMOVED "%1").arg(argIdx);
+ s << INDENT << getFullTypeName(arg->type()) << ' ' << cppArgRemoved;
+ s << " = " << guessScopeForDefaultValue(func, arg) << ';' << endl;
+ writeUnusedVariableCast(s, cppArgRemoved);
+ } else if (!injectCodeCallsFunc && !func->isUserAdded() && !hasConversionRule) {
+ // When an argument is removed from a method signature and no other means of calling
+ // the method are provided (as with code injection) the generator must abort.
+ qFatal(qPrintable(QString::fromLatin1("No way to call '%1::%2' with the modifications described in the type system.")
+ .arg(func->ownerClass()->name(), func->signature())), NULL);
+ }
+ removedArgs++;
+ continue;
+ }
+ if (hasConversionRule)
+ continue;
+ const AbstractMetaType* argType = getArgumentType(func, argIdx + 1);
+ if (!argType || (mayHaveUnunsedArguments && !injectedCodeUsesArgument(func, argIdx)))
+ continue;
+ int argPos = argIdx - removedArgs;
+ QString argName = QString::fromLatin1(CPP_ARG"%1").arg(argPos);
+ QString pyArgName = usePyArgs ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(argPos) : QLatin1String(PYTHON_ARG);
+ QString defaultValue = guessScopeForDefaultValue(func, arg);
+ writeArgumentConversion(s, argType, argName, pyArgName, func->implementingClass(), defaultValue, func->isUserAdded());
+ }
+
+ s << endl;
+
+ int numRemovedArgs = OverloadData::numberOfRemovedArguments(func);
+
+ s << INDENT << "if (!PyErr_Occurred()) {" << endl;
+ {
+ Indentation indentation(INDENT);
+ writeMethodCall(s, func, context, func->arguments().size() - numRemovedArgs);
+ if (!func->isConstructor())
+ writeNoneReturn(s, func, overloadData.hasNonVoidReturnType());
+ }
+ s << INDENT << '}' << endl;
+}
+
+QString CppGenerator::cppToPythonFunctionName(const QString& sourceTypeName, QString targetTypeName)
+{
+ if (targetTypeName.isEmpty())
+ targetTypeName = sourceTypeName;
+ return QString::fromLatin1("%1_CppToPython_%2").arg(sourceTypeName, targetTypeName);
+}
+
+QString CppGenerator::pythonToCppFunctionName(const QString& sourceTypeName, const QString& targetTypeName)
+{
+ return QString::fromLatin1("%1_PythonToCpp_%2").arg(sourceTypeName, targetTypeName);
+}
+QString CppGenerator::pythonToCppFunctionName(const AbstractMetaType* sourceType, const AbstractMetaType* targetType)
+{
+ return pythonToCppFunctionName(fixedCppTypeName(sourceType), fixedCppTypeName(targetType));
+}
+QString CppGenerator::pythonToCppFunctionName(const CustomConversion::TargetToNativeConversion* toNative,
+ const TypeEntry* targetType)
+{
+ return pythonToCppFunctionName(fixedCppTypeName(toNative), fixedCppTypeName(targetType));
+}
+
+QString CppGenerator::convertibleToCppFunctionName(const QString& sourceTypeName, const QString& targetTypeName)
+{
+ return QString::fromLatin1("is_%1_PythonToCpp_%2_Convertible").arg(sourceTypeName, targetTypeName);
+}
+QString CppGenerator::convertibleToCppFunctionName(const AbstractMetaType* sourceType, const AbstractMetaType* targetType)
+{
+ return convertibleToCppFunctionName(fixedCppTypeName(sourceType), fixedCppTypeName(targetType));
+}
+QString CppGenerator::convertibleToCppFunctionName(const CustomConversion::TargetToNativeConversion* toNative,
+ const TypeEntry* targetType)
+{
+ return convertibleToCppFunctionName(fixedCppTypeName(toNative), fixedCppTypeName(targetType));
+}
+
+void CppGenerator::writeCppToPythonFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, QString targetTypeName)
+{
+ QString prettyCode;
+ QTextStream c(&prettyCode);
+ formatCode(c, code, INDENT);
+ processCodeSnip(prettyCode);
+
+ s << "static PyObject* " << cppToPythonFunctionName(sourceTypeName, targetTypeName);
+ s << "(const void* cppIn) {" << endl;
+ s << prettyCode;
+ s << '}' << endl;
+}
+
+static void replaceCppToPythonVariables(QString& code, const QString& typeName)
+{
+ code.prepend(QString::fromLatin1("%1& cppInRef = *((%1*)cppIn);\n").arg(typeName));
+ code.replace(QLatin1String("%INTYPE"), typeName);
+ code.replace(QLatin1String("%OUTTYPE"), QLatin1String("PyObject*"));
+ code.replace(QLatin1String("%in"), QLatin1String("cppInRef"));
+ code.replace(QLatin1String("%out"), QLatin1String("pyOut"));
+}
+void CppGenerator::writeCppToPythonFunction(QTextStream& s, const CustomConversion* customConversion)
+{
+ QString code = customConversion->nativeToTargetConversion();
+ replaceCppToPythonVariables(code, getFullTypeName(customConversion->ownerType()));
+ writeCppToPythonFunction(s, code, fixedCppTypeName(customConversion->ownerType()));
+}
+void CppGenerator::writeCppToPythonFunction(QTextStream& s, const AbstractMetaType* containerType)
+{
+ const CustomConversion* customConversion = containerType->typeEntry()->customConversion();
+ if (!customConversion) {
+ qFatal(qPrintable(QString::fromLatin1("Can't write the C++ to Python conversion function for container type '%1' - "\
+ "no conversion rule was defined for it in the type system.")
+ .arg(containerType->typeEntry()->qualifiedCppName())), NULL);
+ }
+ if (!containerType->typeEntry()->isContainer()) {
+ writeCppToPythonFunction(s, customConversion);
+ return;
+ }
+ QString code = customConversion->nativeToTargetConversion();
+ for (int i = 0; i < containerType->instantiations().count(); ++i) {
+ AbstractMetaType* type = containerType->instantiations().at(i);
+ QString typeName = getFullTypeName(type);
+ if (type->isConstant())
+ typeName = QLatin1String("const ") + typeName;
+ code.replace(QString::fromLatin1("%INTYPE_%1").arg(i), typeName);
+ }
+ replaceCppToPythonVariables(code, getFullTypeNameWithoutModifiers(containerType));
+ processCodeSnip(code);
+ writeCppToPythonFunction(s, code, fixedCppTypeName(containerType));
+}
+
+void CppGenerator::writePythonToCppFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, const QString& targetTypeName)
+{
+ QString prettyCode;
+ QTextStream c(&prettyCode);
+ formatCode(c, code, INDENT);
+ processCodeSnip(prettyCode);
+ s << "static void " << pythonToCppFunctionName(sourceTypeName, targetTypeName);
+ s << "(PyObject* pyIn, void* cppOut) {" << endl;
+ s << prettyCode;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeIsPythonConvertibleToCppFunction(QTextStream& s,
+ const QString& sourceTypeName,
+ const QString& targetTypeName,
+ const QString& condition,
+ QString pythonToCppFuncName,
+ bool acceptNoneAsCppNull)
+{
+ if (pythonToCppFuncName.isEmpty())
+ pythonToCppFuncName = pythonToCppFunctionName(sourceTypeName, targetTypeName);
+
+ s << "static PythonToCppFunc " << convertibleToCppFunctionName(sourceTypeName, targetTypeName);
+ s << "(PyObject* pyIn) {" << endl;
+ if (acceptNoneAsCppNull) {
+ s << INDENT << "if (pyIn == Py_None)" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return Shiboken::Conversions::nonePythonToCppNullPtr;" << endl;
+ }
+ s << INDENT << "if (" << condition << ')' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return " << pythonToCppFuncName << ';' << endl;
+ }
+ s << INDENT << "return 0;" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s,
+ const AbstractMetaType* sourceType,
+ const AbstractMetaType* targetType,
+ QString typeCheck,
+ QString conversion,
+ QString preConversion)
+{
+ QString sourcePyType = cpythonTypeNameExt(sourceType);
+
+ // Python to C++ conversion function.
+ QString code;
+ QTextStream c(&code);
+ if (conversion.isEmpty())
+ conversion = QLatin1Char('*') + cpythonWrapperCPtr(sourceType->typeEntry(), QLatin1String("pyIn"));
+ if (!preConversion.isEmpty())
+ c << INDENT << preConversion << endl;
+ c << INDENT << QString::fromLatin1("*((%1*)cppOut) = %1(%2);")
+ .arg(getFullTypeName(targetType->typeEntry()), conversion);
+ QString sourceTypeName = fixedCppTypeName(sourceType);
+ QString targetTypeName = fixedCppTypeName(targetType);
+ writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
+
+ // Python to C++ convertible check function.
+ if (typeCheck.isEmpty())
+ typeCheck = QString::fromLatin1("PyObject_TypeCheck(pyIn, %1)").arg(sourcePyType);
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck);
+ s << endl;
+}
+
+void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s,
+ const CustomConversion::TargetToNativeConversion* toNative,
+ const TypeEntry* targetType)
+{
+ // Python to C++ conversion function.
+ QString code = toNative->conversion();
+ QString inType;
+ if (toNative->sourceType())
+ inType = cpythonTypeNameExt(toNative->sourceType());
+ else
+ inType = QString::fromLatin1("(&%1_Type)").arg(toNative->sourceTypeName());
+ code.replace(QLatin1String("%INTYPE"), inType);
+ code.replace(QLatin1String("%OUTTYPE"), targetType->qualifiedCppName());
+ code.replace(QLatin1String("%in"), QLatin1String("pyIn"));
+ code.replace(QLatin1String("%out"), QString::fromLatin1("*((%1*)cppOut)").arg(getFullTypeName(targetType)));
+
+ QString sourceTypeName = fixedCppTypeName(toNative);
+ QString targetTypeName = fixedCppTypeName(targetType);
+ writePythonToCppFunction(s, code, sourceTypeName, targetTypeName);
+
+ // Python to C++ convertible check function.
+ QString typeCheck = toNative->sourceTypeCheck();
+ if (typeCheck.isEmpty()) {
+ QString pyTypeName = toNative->sourceTypeName();
+ if (pyTypeName == QLatin1String("Py_None") || pyTypeName == QLatin1String("PyNone"))
+ typeCheck = QLatin1String("%in == Py_None");
+ else if (pyTypeName == QLatin1String("SbkEnumType"))
+ typeCheck = QLatin1String("Shiboken::isShibokenEnum(%in)");
+ else if (pyTypeName == QLatin1String("SbkObject"))
+ typeCheck = QLatin1String("Shiboken::Object::checkType(%in)");
+ else if (pyTypeName == QLatin1String("PyTypeObject"))
+ typeCheck = QLatin1String("PyType_Check(%in)");
+ else if (pyTypeName == QLatin1String("PyObject"))
+ typeCheck = QLatin1String("PyObject_TypeCheck(%in, &PyBaseObject_Type)");
+ else if (pyTypeName.startsWith(QLatin1String("Py")))
+ typeCheck = pyTypeName + QLatin1String("_Check(%in)");
+ }
+ if (typeCheck.isEmpty()) {
+ if (!toNative->sourceType() || toNative->sourceType()->isPrimitive()) {
+ qFatal(qPrintable(QString::fromLatin1("User added implicit conversion for C++ type '%1' must provide either an input "\
+ "type check function or a non primitive type entry.")
+ .arg(targetType->qualifiedCppName())), NULL);
+
+ }
+ typeCheck = QString::fromLatin1("PyObject_TypeCheck(%in, %1)").arg(cpythonTypeNameExt(toNative->sourceType()));
+ }
+ typeCheck.replace(QLatin1String("%in"), QLatin1String("pyIn"));
+ processCodeSnip(typeCheck);
+ writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck);
+}
+
+void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s, const AbstractMetaType* containerType)
+{
+ const CustomConversion* customConversion = containerType->typeEntry()->customConversion();
+ if (!customConversion) {
+ //qFatal
+ return;
+ }
+ const CustomConversion::TargetToNativeConversions& toCppConversions = customConversion->targetToNativeConversions();
+ if (toCppConversions.isEmpty()) {
+ //qFatal
+ return;
+ }
+ // Python to C++ conversion function.
+ QString cppTypeName = getFullTypeNameWithoutModifiers(containerType);
+ QString code;
+ QTextStream c(&code);
+ c << INDENT << QString::fromLatin1("%1& cppOutRef = *((%1*)cppOut);").arg(cppTypeName) << endl;
+ code.append(toCppConversions.first()->conversion());
+ for (int i = 0; i < containerType->instantiations().count(); ++i) {
+ const AbstractMetaType* type = containerType->instantiations().at(i);
+ QString typeName = getFullTypeName(type);
+ if (type->isValue() && isValueTypeWithCopyConstructorOnly(type)) {
+ static const QRegularExpression regex(QLatin1String(CONVERTTOCPP_REGEX));
+ Q_ASSERT(regex.isValid());
+ for (int pos = 0; ; ) {
+ const QRegularExpressionMatch match = regex.match(code, pos);
+ if (!match.hasMatch())
+ break;
+ pos = match.capturedEnd();
+ const QString varName = match.captured(1);
+ QString rightCode = code.mid(pos);
+ rightCode.replace(varName, QLatin1Char('*') + varName);
+ code.replace(pos, code.size() - pos, rightCode);
+ }
+ typeName.append(QLatin1Char('*'));
+ }
+ code.replace(QString::fromLatin1("%OUTTYPE_%1").arg(i), typeName);
+ }
+ code.replace(QLatin1String("%OUTTYPE"), cppTypeName);
+ code.replace(QLatin1String("%in"), QLatin1String("pyIn"));
+ code.replace(QLatin1String("%out"), QLatin1String("cppOutRef"));
+ QString typeName = fixedCppTypeName(containerType);
+ writePythonToCppFunction(s, code, typeName, typeName);
+
+ // Python to C++ convertible check function.
+ QString typeCheck = cpythonCheckFunction(containerType);
+ if (typeCheck.isEmpty())
+ typeCheck = QLatin1String("false");
+ else
+ typeCheck = QString::fromLatin1("%1pyIn)").arg(typeCheck);
+ writeIsPythonConvertibleToCppFunction(s, typeName, typeName, typeCheck);
+ s << endl;
+}
+
+void CppGenerator::writeAddPythonToCppConversion(QTextStream& s, const QString& converterVar, const QString& pythonToCppFunc, const QString& isConvertibleFunc)
+{
+ s << INDENT << "Shiboken::Conversions::addPythonToCppValueConversion(" << converterVar << ',' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << pythonToCppFunc << ',' << endl;
+ s << INDENT << isConvertibleFunc;
+ }
+ s << ");" << endl;
+}
+
+void CppGenerator::writeNamedArgumentResolution(QTextStream& s, const AbstractMetaFunction* func, bool usePyArgs)
+{
+ const AbstractMetaArgumentList &args = OverloadData::getArgumentsWithDefaultValues(func);
+ if (args.isEmpty())
+ return;
+
+ QString pyErrString(QLatin1String("PyErr_SetString(PyExc_TypeError, \"") + fullPythonFunctionName(func)
+ + QLatin1String("(): got multiple values for keyword argument '%1'.\");"));
+
+ s << INDENT << "if (kwds) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyObject* ";
+ for (const AbstractMetaArgument *arg : args) {
+ int pyArgIndex = arg->argumentIndex() - OverloadData::numberOfRemovedArguments(func, arg->argumentIndex());
+ QString pyArgName = usePyArgs
+ ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(pyArgIndex)
+ : QLatin1String(PYTHON_ARG);
+ s << "value = PyDict_GetItemString(kwds, \"" << arg->name() << "\");" << endl;
+ s << INDENT << "if (value && " << pyArgName << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << pyErrString.arg(arg->name()) << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << "} else if (value) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << pyArgName << " = value;" << endl;
+ s << INDENT << "if (!";
+ writeTypeCheck(s, arg->type(), pyArgName, isNumber(arg->type()->typeEntry()), func->typeReplaced(arg->argumentIndex() + 1));
+ s << ')' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "goto " << cpythonFunctionName(func) << "_TypeError;" << endl;
+ }
+ }
+ s << INDENT << '}' << endl;
+ if (arg != args.last())
+ s << INDENT;
+ }
+ }
+ s << INDENT << '}' << endl;
+}
+
+QString CppGenerator::argumentNameFromIndex(const AbstractMetaFunction* func, int argIndex, const AbstractMetaClass** wrappedClass)
+{
+ *wrappedClass = 0;
+ QString pyArgName;
+ if (argIndex == -1) {
+ pyArgName = QLatin1String(PYTHON_SELF_VAR);
+ *wrappedClass = func->implementingClass();
+ } else if (argIndex == 0) {
+ AbstractMetaType *funcType = func->type();
+ AbstractMetaType *returnType = getTypeWithoutContainer(funcType);
+ if (returnType) {
+ pyArgName = QLatin1String(PYTHON_RETURN_VAR);
+ *wrappedClass = AbstractMetaClass::findClass(classes(), returnType->typeEntry()->name());
+ } else {
+ QString message = QLatin1String("Invalid Argument index (0, return value) on function modification: ")
+ + (funcType ? funcType->name() : QLatin1String("void")) + QLatin1Char(' ');
+ if (const AbstractMetaClass *declaringClass = func->declaringClass())
+ message += declaringClass->name() + QLatin1String("::");
+ message += func->name() + QLatin1String("()");
+ qCWarning(lcShiboken).noquote().nospace() << message;
+ }
+ } else {
+ int realIndex = argIndex - 1 - OverloadData::numberOfRemovedArguments(func, argIndex - 1);
+ AbstractMetaType* argType = getTypeWithoutContainer(func->arguments().at(realIndex)->type());
+
+ if (argType) {
+ *wrappedClass = AbstractMetaClass::findClass(classes(), argType->typeEntry()->name());
+ if (argIndex == 1
+ && !func->isConstructor()
+ && OverloadData::isSingleArgument(getFunctionGroups(func->implementingClass())[func->name()]))
+ pyArgName = QLatin1String(PYTHON_ARG);
+ else
+ pyArgName = QString::fromLatin1(PYTHON_ARGS "[%1]").arg(argIndex - 1);
+ }
+ }
+ return pyArgName;
+}
+
+void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *func,
+ GeneratorContext &context, int maxArgs)
+{
+ s << INDENT << "// " << func->minimalSignature() << (func->isReverseOperator() ? " [reverse operator]": "") << endl;
+ if (func->isConstructor()) {
+ const CodeSnipList &snips = func->injectedCodeSnips();
+ for (const CodeSnip &cs : snips) {
+ if (cs.position == TypeSystem::CodeSnipPositionEnd) {
+ s << INDENT << "overloadId = " << func->ownerClass()->functions().indexOf(const_cast<AbstractMetaFunction* const>(func)) << ';' << endl;
+ break;
+ }
+ }
+ }
+
+ if (func->isAbstract()) {
+ s << INDENT << "if (Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "))) {\n";
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '";
+ s << func->ownerClass()->name() << '.' << func->name() << "()' not implemented.\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << "}\n";
+ }
+
+ // Used to provide contextual information to custom code writer function.
+ const AbstractMetaArgument* lastArg = 0;
+
+ CodeSnipList snips;
+ if (func->hasInjectedCode()) {
+ snips = func->injectedCodeSnips();
+
+ // Find the last argument available in the method call to provide
+ // the injected code writer with information to avoid invalid replacements
+ // on the %# variable.
+ if (maxArgs > 0 && maxArgs < func->arguments().size() - OverloadData::numberOfRemovedArguments(func)) {
+ int removedArgs = 0;
+ for (int i = 0; i < maxArgs + removedArgs; i++) {
+ lastArg = func->arguments().at(i);
+ if (func->argumentRemoved(i + 1))
+ removedArgs++;
+ }
+ } else if (maxArgs != 0 && !func->arguments().isEmpty()) {
+ lastArg = func->arguments().last();
+ }
+
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode, func, lastArg);
+ s << endl;
+ }
+
+ writeConversionRule(s, func, TypeSystem::NativeCode);
+
+ if (!func->isUserAdded()) {
+ QStringList userArgs;
+ if (func->functionType() != AbstractMetaFunction::CopyConstructorFunction) {
+ int removedArgs = 0;
+ for (int i = 0; i < maxArgs + removedArgs; i++) {
+ const AbstractMetaArgument* arg = func->arguments().at(i);
+ bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, arg->argumentIndex() + 1).isEmpty();
+ if (func->argumentRemoved(i + 1)) {
+ // If some argument with default value is removed from a
+ // method signature, the said value must be explicitly
+ // added to the method call.
+ removedArgs++;
+
+ // If have conversion rules I will use this for removed args
+ if (hasConversionRule)
+ userArgs << arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX);
+ else if (!arg->defaultValueExpression().isEmpty())
+ userArgs << QString::fromLatin1(CPP_ARG_REMOVED "%1").arg(i);
+ } else {
+ int idx = arg->argumentIndex() - removedArgs;
+ bool deRef = isValueTypeWithCopyConstructorOnly(arg->type())
+ || isObjectTypeUsedAsValueType(arg->type())
+ || (arg->type()->referenceType() == LValueReference && isWrapperType(arg->type()) && !isPointer(arg->type()));
+ QString argName = hasConversionRule
+ ? arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX)
+ : QString::fromLatin1("%1" CPP_ARG "%2").arg(deRef ? QLatin1String("*") : QString()).arg(idx);
+ userArgs << argName;
+ }
+ }
+
+ // If any argument's default value was modified the method must be called
+ // with this new value whenever the user doesn't pass an explicit value to it.
+ // Also, any unmodified default value coming after the last user specified
+ // argument and before the modified argument must be explicitly stated.
+ QStringList otherArgs;
+ bool otherArgsModified = false;
+ bool argsClear = true;
+ for (int i = func->arguments().size() - 1; i >= maxArgs + removedArgs; i--) {
+ const AbstractMetaArgument* arg = func->arguments().at(i);
+ bool defValModified = arg->defaultValueExpression() != arg->originalDefaultValueExpression();
+ bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, arg->argumentIndex() + 1).isEmpty();
+ if (argsClear && !defValModified && !hasConversionRule)
+ continue;
+ else
+ argsClear = false;
+ otherArgsModified |= defValModified || hasConversionRule || func->argumentRemoved(i + 1);
+ if (hasConversionRule)
+ otherArgs.prepend(arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX));
+ else
+ otherArgs.prepend(QString::fromLatin1(CPP_ARG_REMOVED "%1").arg(i));
+ }
+ if (otherArgsModified)
+ userArgs << otherArgs;
+ }
+
+ bool isCtor = false;
+ QString methodCall;
+ QTextStream mc(&methodCall);
+ QString useVAddr;
+ QTextStream uva(&useVAddr);
+ if (func->isOperatorOverload() && !func->isCallOperator()) {
+ QString firstArg = QLatin1String("(*" CPP_SELF_VAR ")");
+ if (func->isPointerOperator())
+ firstArg.remove(1, 1); // remove the de-reference operator
+
+ QString secondArg = QLatin1String(CPP_ARG0);
+ if (!func->isUnaryOperator() && shouldDereferenceArgumentPointer(func->arguments().first())) {
+ secondArg.prepend(QLatin1String("(*"));
+ secondArg.append(QLatin1Char(')'));
+ }
+
+ if (func->isUnaryOperator())
+ std::swap(firstArg, secondArg);
+
+ QString op = func->originalName();
+ op = op.right(op.size() - (sizeof("operator")/sizeof(char)-1));
+
+ if (func->isBinaryOperator()) {
+ if (func->isReverseOperator())
+ std::swap(firstArg, secondArg);
+
+ if (((op == QLatin1String("++")) || (op == QLatin1String("--"))) && !func->isReverseOperator()) {
+ s << endl << INDENT << "for(int i=0; i < " << secondArg << "; i++, " << firstArg << op << ");" << endl;
+ mc << firstArg;
+ } else {
+ mc << firstArg << ' ' << op << ' ' << secondArg;
+ }
+ } else {
+ mc << op << ' ' << secondArg;
+ }
+ } else if (!injectedCodeCallsCppFunction(func)) {
+ if (func->isConstructor()) {
+ isCtor = true;
+ QString className = wrapperName(func->ownerClass());
+
+ if (func->functionType() == AbstractMetaFunction::CopyConstructorFunction && maxArgs == 1) {
+ mc << "new ::" << className << "(*" << CPP_ARG0 << ')';
+ } else {
+ QString ctorCall = className + QLatin1Char('(') + userArgs.join(QLatin1String(", ")) + QLatin1Char(')');
+ if (usePySideExtensions() && func->ownerClass()->isQObject()) {
+ s << INDENT << "void* addr = PySide::nextQObjectMemoryAddr();" << endl;
+ uva << "if (addr) {" << endl;
+ {
+ Indentation indent(INDENT);
+
+ uva << INDENT << "cptr = " << "new (addr) ::"
+ << ctorCall << ';' << endl
+ << INDENT
+ << "PySide::setNextQObjectMemoryAddr(0);"
+ << endl;
+ }
+ uva << INDENT << "} else {" << endl;
+ {
+ Indentation indent(INDENT);
+
+ uva << INDENT << "cptr = " << "new ::"
+ << ctorCall << ';' << endl;
+ }
+ uva << INDENT << "}" << endl;
+ } else {
+ mc << "new ::" << ctorCall;
+ }
+ }
+ } else {
+ QString methodCallClassName;
+ if (context.forSmartPointer())
+ methodCallClassName = context.preciseType()->cppSignature();
+ else if (func->ownerClass())
+ methodCallClassName = func->ownerClass()->qualifiedCppName();
+
+ if (func->ownerClass()) {
+ if (!avoidProtectedHack() || !func->isProtected()) {
+ if (func->isStatic()) {
+ mc << "::" << methodCallClassName << "::";
+ } else {
+ const QString selfVarCast = func->ownerClass() == func->implementingClass()
+ ? QLatin1String(CPP_SELF_VAR)
+ : QLatin1String("reinterpret_cast<") + methodCallClassName + QLatin1String(" *>(" CPP_SELF_VAR ")");
+ if (func->isConstant()) {
+ if (avoidProtectedHack()) {
+ mc << "const_cast<const ::";
+ if (func->ownerClass()->hasProtectedMembers()) {
+ // PYSIDE-500: Need a special wrapper cast when inherited
+ const QString selfWrapCast = func->ownerClass() == func->implementingClass()
+ ? QLatin1String(CPP_SELF_VAR)
+ : QLatin1String("reinterpret_cast<") + wrapperName(func->ownerClass()) + QLatin1String(" *>(" CPP_SELF_VAR ")");
+ mc << wrapperName(func->ownerClass());
+ mc << "*>(" << selfWrapCast << ")->";
+ }
+ else {
+ mc << methodCallClassName;
+ mc << "*>(" << selfVarCast << ")->";
+ }
+ } else {
+ mc << "const_cast<const ::" << methodCallClassName;
+ mc << "*>(" << selfVarCast << ")->";
+ }
+ } else {
+ mc << selfVarCast << "->";
+ }
+ }
+
+ if (!func->isAbstract() && func->isVirtual())
+ mc << "::%CLASS_NAME::";
+
+ mc << func->originalName();
+ } else {
+ if (!func->isStatic())
+ mc << "((::" << wrapperName(func->ownerClass()) << "*) " << CPP_SELF_VAR << ")->";
+
+ if (!func->isAbstract())
+ mc << (func->isProtected() ? wrapperName(func->ownerClass()) :
+ QLatin1String("::")
+ + methodCallClassName) << "::";
+ mc << func->originalName() << "_protected";
+ }
+ } else {
+ mc << func->originalName();
+ }
+ mc << '(' << userArgs.join(QLatin1String(", ")) << ')';
+ if (!func->isAbstract() && func->isVirtual()) {
+ mc.flush();
+ if (!avoidProtectedHack() || !func->isProtected()) {
+ QString virtualCall(methodCall);
+ QString normalCall(methodCall);
+ virtualCall = virtualCall.replace(QLatin1String("%CLASS_NAME"),
+ methodCallClassName);
+ normalCall.remove(QLatin1String("::%CLASS_NAME::"));
+ methodCall.clear();
+ mc << "Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ")) ? ";
+ mc << virtualCall << " : " << normalCall;
+ }
+ }
+ }
+ }
+
+ if (!injectedCodeCallsCppFunction(func)) {
+ s << INDENT << BEGIN_ALLOW_THREADS << endl << INDENT;
+ if (isCtor) {
+ s << (useVAddr.isEmpty() ?
+ QString::fromLatin1("cptr = %1;").arg(methodCall) : useVAddr) << endl;
+ } else if (func->type() && !func->isInplaceOperator()) {
+ bool writeReturnType = true;
+ if (avoidProtectedHack()) {
+ const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(func->type());
+ if (metaEnum) {
+ QString enumName;
+ if (metaEnum->isProtected())
+ enumName = protectedEnumSurrogateName(metaEnum);
+ else
+ enumName = func->type()->cppSignature();
+ methodCall.prepend(enumName + QLatin1Char('('));
+ methodCall.append(QLatin1Char(')'));
+ s << enumName;
+ writeReturnType = false;
+ }
+ }
+ if (writeReturnType) {
+ s << func->type()->cppSignature();
+ if (isObjectTypeUsedAsValueType(func->type())) {
+ s << '*';
+ methodCall.prepend(QString::fromLatin1("new %1(").arg(func->type()->typeEntry()->qualifiedCppName()));
+ methodCall.append(QLatin1Char(')'));
+ }
+ }
+ s << " " CPP_RETURN_VAR " = ";
+ s << methodCall << ';' << endl;
+ } else {
+ s << methodCall << ';' << endl;
+ }
+ s << INDENT << END_ALLOW_THREADS << endl;
+
+ if (!func->conversionRule(TypeSystem::TargetLangCode, 0).isEmpty()) {
+ writeConversionRule(s, func, TypeSystem::TargetLangCode, QLatin1String(PYTHON_RETURN_VAR));
+ } else if (!isCtor && !func->isInplaceOperator() && func->type()
+ && !injectedCodeHasReturnValueAttribution(func, TypeSystem::TargetLangCode)) {
+ s << INDENT << PYTHON_RETURN_VAR " = ";
+ if (isObjectTypeUsedAsValueType(func->type())) {
+ s << "Shiboken::Object::newObject(reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(func->type()->typeEntry())
+ << "), " << CPP_RETURN_VAR << ", true, true)";
+ } else {
+ writeToPythonConversion(s, func->type(), func->ownerClass(), QLatin1String(CPP_RETURN_VAR));
+ }
+ s << ';' << endl;
+ }
+ }
+ }
+
+ if (func->hasInjectedCode() && !func->isConstructor()) {
+ s << endl;
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode, func, lastArg);
+ }
+
+ bool hasReturnPolicy = false;
+
+ // Ownership transference between C++ and Python.
+ QVector<ArgumentModification> ownership_mods;
+ // Python object reference management.
+ QVector<ArgumentModification> refcount_mods;
+ const FunctionModificationList &funcMods = func->modifications();
+ for (const FunctionModification &func_mod : funcMods) {
+ for (const ArgumentModification &arg_mod : func_mod.argument_mods) {
+ if (!arg_mod.ownerships.isEmpty() && arg_mod.ownerships.contains(TypeSystem::TargetLangCode))
+ ownership_mods.append(arg_mod);
+ else if (!arg_mod.referenceCounts.isEmpty())
+ refcount_mods.append(arg_mod);
+ }
+ }
+
+ // If there's already a setParent(return, me), don't use the return heuristic!
+ if (func->argumentOwner(func->ownerClass(), -1).index == 0)
+ hasReturnPolicy = true;
+
+ if (!ownership_mods.isEmpty()) {
+ s << endl << INDENT << "// Ownership transferences." << endl;
+ for (const ArgumentModification &arg_mod : qAsConst(ownership_mods)) {
+ const AbstractMetaClass* wrappedClass = 0;
+ QString pyArgName = argumentNameFromIndex(func, arg_mod.index, &wrappedClass);
+ if (!wrappedClass) {
+ s << "#error Invalid ownership modification for argument " << arg_mod.index << '(' << pyArgName << ')' << endl << endl;
+ break;
+ }
+
+ if (arg_mod.index == 0 || arg_mod.owner.index == 0)
+ hasReturnPolicy = true;
+
+ // The default ownership does nothing. This is useful to avoid automatic heuristically
+ // based generation of code defining parenting.
+ if (arg_mod.ownerships[TypeSystem::TargetLangCode] == TypeSystem::DefaultOwnership)
+ continue;
+
+ s << INDENT << "Shiboken::Object::";
+ if (arg_mod.ownerships[TypeSystem::TargetLangCode] == TypeSystem::TargetLangOwnership) {
+ s << "getOwnership(" << pyArgName << ");";
+ } else if (wrappedClass->hasVirtualDestructor()) {
+ if (arg_mod.index == 0)
+ s << "releaseOwnership(" PYTHON_RETURN_VAR ");";
+ else
+ s << "releaseOwnership(" << pyArgName << ");";
+ } else {
+ s << "invalidate(" << pyArgName << ");";
+ }
+ s << endl;
+ }
+
+ } else if (!refcount_mods.isEmpty()) {
+ for (const ArgumentModification &arg_mod : qAsConst(refcount_mods)) {
+ ReferenceCount refCount = arg_mod.referenceCounts.first();
+ if (refCount.action != ReferenceCount::Set
+ && refCount.action != ReferenceCount::Remove
+ && refCount.action != ReferenceCount::Add) {
+ qCWarning(lcShiboken) << "\"set\", \"add\" and \"remove\" are the only values supported by Shiboken for action attribute of reference-count tag.";
+ continue;
+ }
+ const AbstractMetaClass* wrappedClass = 0;
+
+ QString pyArgName;
+ if (refCount.action == ReferenceCount::Remove) {
+ pyArgName = QLatin1String("Py_None");
+ } else {
+ pyArgName = argumentNameFromIndex(func, arg_mod.index, &wrappedClass);
+ if (pyArgName.isEmpty()) {
+ s << "#error Invalid reference count modification for argument " << arg_mod.index << endl << endl;
+ break;
+ }
+ }
+
+ if (refCount.action == ReferenceCount::Add || refCount.action == ReferenceCount::Set)
+ s << INDENT << "Shiboken::Object::keepReference(";
+ else
+ s << INDENT << "Shiboken::Object::removeReference(";
+
+ s << "reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "), \"";
+ QString varName = arg_mod.referenceCounts.first().varName;
+ if (varName.isEmpty())
+ varName = func->minimalSignature() + QString().number(arg_mod.index);
+
+ s << varName << "\", " << pyArgName
+ << (refCount.action == ReferenceCount::Add ? ", true" : "")
+ << ");" << endl;
+
+ if (arg_mod.index == 0)
+ hasReturnPolicy = true;
+ }
+ }
+ writeParentChildManagement(s, func, !hasReturnPolicy);
+}
+
+QStringList CppGenerator::getAncestorMultipleInheritance(const AbstractMetaClass* metaClass)
+{
+ QStringList result;
+ const AbstractMetaClassList &baseClases = getBaseClasses(metaClass);
+ if (!baseClases.isEmpty()) {
+ for (const AbstractMetaClass *baseClass : baseClases) {
+ result.append(QString::fromLatin1("((size_t) static_cast<const %1*>(class_ptr)) - base")
+ .arg(baseClass->qualifiedCppName()));
+ result.append(QString::fromLatin1("((size_t) static_cast<const %1*>((%2*)((void*)class_ptr))) - base")
+ .arg(baseClass->qualifiedCppName(), metaClass->qualifiedCppName()));
+ }
+ for (const AbstractMetaClass *baseClass : baseClases)
+ result.append(getAncestorMultipleInheritance(baseClass));
+ }
+ return result;
+}
+
+void CppGenerator::writeMultipleInheritanceInitializerFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString className = metaClass->qualifiedCppName();
+ const QStringList ancestors = getAncestorMultipleInheritance(metaClass);
+ s << "static int mi_offsets[] = { ";
+ for (int i = 0; i < ancestors.size(); i++)
+ s << "-1, ";
+ s << "-1 };" << endl;
+ s << "int*" << endl;
+ s << multipleInheritanceInitializerFunctionName(metaClass) << "(const void* cptr)" << endl;
+ s << '{' << endl;
+ s << INDENT << "if (mi_offsets[0] == -1) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "std::set<int> offsets;" << endl;
+ s << INDENT << "std::set<int>::iterator it;" << endl;
+ s << INDENT << "const " << className << "* class_ptr = reinterpret_cast<const " << className << "*>(cptr);" << endl;
+ s << INDENT << "size_t base = (size_t) class_ptr;" << endl;
+
+ for (const QString &ancestor : ancestors)
+ s << INDENT << "offsets.insert(" << ancestor << ");" << endl;
+
+ s << endl;
+ s << INDENT << "offsets.erase(0);" << endl;
+ s << endl;
+
+ s << INDENT << "int i = 0;" << endl;
+ s << INDENT << "for (it = offsets.begin(); it != offsets.end(); it++) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "mi_offsets[i] = *it;" << endl;
+ s << INDENT << "i++;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ }
+ s << INDENT << '}' << endl;
+ s << INDENT << "return mi_offsets;" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeSpecialCastFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString className = metaClass->qualifiedCppName();
+ s << "static void* " << cpythonSpecialCastFunctionName(metaClass) << "(void* obj, SbkObjectType* desiredType)\n";
+ s << "{\n";
+ s << INDENT << className << "* me = reinterpret_cast< ::" << className << "*>(obj);\n";
+ bool firstClass = true;
+ const AbstractMetaClassList &allAncestors = getAllAncestors(metaClass);
+ for (const AbstractMetaClass *baseClass : allAncestors) {
+ s << INDENT << (!firstClass ? "else " : "") << "if (desiredType == reinterpret_cast<SbkObjectType*>(" << cpythonTypeNameExt(baseClass->typeEntry()) << "))\n";
+ Indentation indent(INDENT);
+ s << INDENT << "return static_cast< ::" << baseClass->qualifiedCppName() << "*>(me);\n";
+ firstClass = false;
+ }
+ s << INDENT << "return me;\n";
+ s << "}\n\n";
+}
+
+void CppGenerator::writePrimitiveConverterInitialization(QTextStream& s, const CustomConversion* customConversion)
+{
+ const TypeEntry* type = customConversion->ownerType();
+ QString converter = converterObject(type);
+ s << INDENT << "// Register converter for type '" << type->qualifiedTargetLangName() << "'." << endl;
+ s << INDENT << converter << " = Shiboken::Conversions::createConverter(";
+ if (type->targetLangApiName() == type->name())
+ s << '0';
+ else if (type->targetLangApiName() == QLatin1String("PyObject"))
+ s << "&PyBaseObject_Type";
+ else
+ s << '&' << type->targetLangApiName() << "_Type";
+ QString typeName = fixedCppTypeName(type);
+ s << ", " << cppToPythonFunctionName(typeName, typeName) << ");" << endl;
+ s << INDENT << "Shiboken::Conversions::registerConverterName(" << converter << ", \"" << type->qualifiedCppName() << "\");" << endl;
+ writeCustomConverterRegister(s, customConversion, converter);
+}
+
+void CppGenerator::writeEnumConverterInitialization(QTextStream& s, const AbstractMetaEnum* metaEnum)
+{
+ if (metaEnum->isPrivate() || metaEnum->isAnonymous())
+ return;
+ writeEnumConverterInitialization(s, metaEnum->typeEntry());
+}
+
+void CppGenerator::writeEnumConverterInitialization(QTextStream& s, const TypeEntry* enumType)
+{
+ if (!enumType)
+ return;
+ QString enumFlagName = enumType->isFlags() ? QLatin1String("flag") : QLatin1String("enum");
+ QString enumPythonType = cpythonTypeNameExt(enumType);
+
+ const FlagsTypeEntry* flags = 0;
+ if (enumType->isFlags())
+ flags = reinterpret_cast<const FlagsTypeEntry*>(enumType);
+
+ s << INDENT << "// Register converter for " << enumFlagName << " '" << enumType->qualifiedCppName() << "'." << endl;
+ s << INDENT << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ QString typeName = fixedCppTypeName(enumType);
+ s << INDENT << "SbkConverter* converter = Shiboken::Conversions::createConverter(" << enumPythonType << ',' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << cppToPythonFunctionName(typeName, typeName) << ");" << endl;
+ }
+
+ if (flags) {
+ QString enumTypeName = fixedCppTypeName(flags->originator());
+ QString toCpp = pythonToCppFunctionName(enumTypeName, typeName);
+ QString isConv = convertibleToCppFunctionName(enumTypeName, typeName);
+ writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
+ }
+
+ QString toCpp = pythonToCppFunctionName(typeName, typeName);
+ QString isConv = convertibleToCppFunctionName(typeName, typeName);
+ writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
+
+ if (flags) {
+ QString toCpp = pythonToCppFunctionName(QLatin1String("number"), typeName);
+ QString isConv = convertibleToCppFunctionName(QLatin1String("number"), typeName);
+ writeAddPythonToCppConversion(s, QLatin1String("converter"), toCpp, isConv);
+ }
+
+ s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", converter);" << endl;
+ s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", converter);" << endl;
+ QStringList cppSignature = enumType->qualifiedCppName().split(QLatin1String("::"), QString::SkipEmptyParts);
+ while (!cppSignature.isEmpty()) {
+ QString signature = cppSignature.join(QLatin1String("::"));
+ s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"";
+ if (flags)
+ s << "QFlags<";
+ s << signature << "\");" << endl;
+ cppSignature.removeFirst();
+ }
+ }
+ s << INDENT << '}' << endl;
+
+ if (!flags)
+ writeEnumConverterInitialization(s, reinterpret_cast<const EnumTypeEntry*>(enumType)->flags());
+}
+
+void CppGenerator::writeContainerConverterInitialization(QTextStream& s, const AbstractMetaType* type)
+{
+ QByteArray cppSignature = QMetaObject::normalizedSignature(type->cppSignature().toUtf8());
+ s << INDENT << "// Register converter for type '" << cppSignature << "'." << endl;
+ QString converter = converterObject(type);
+ s << INDENT << converter << " = Shiboken::Conversions::createConverter(";
+ if (type->typeEntry()->targetLangApiName() == QLatin1String("PyObject")) {
+ s << "&PyBaseObject_Type";
+ } else {
+ QString baseName = cpythonBaseName(type->typeEntry());
+ if (baseName == QLatin1String("PySequence"))
+ baseName = QLatin1String("PyList");
+ s << '&' << baseName << "_Type";
+ }
+ QString typeName = fixedCppTypeName(type);
+ s << ", " << cppToPythonFunctionName(typeName, typeName) << ");" << endl;
+ QString toCpp = pythonToCppFunctionName(typeName, typeName);
+ QString isConv = convertibleToCppFunctionName(typeName, typeName);
+ s << INDENT << "Shiboken::Conversions::registerConverterName(" << converter << ", \"" << cppSignature << "\");" << endl;
+ if (usePySideExtensions() && cppSignature.startsWith("const ") && cppSignature.endsWith("&")) {
+ cppSignature.chop(1);
+ cppSignature.remove(0, sizeof("const ") / sizeof(char) - 1);
+ s << INDENT << "Shiboken::Conversions::registerConverterName(" << converter << ", \"" << cppSignature << "\");" << endl;
+ }
+ writeAddPythonToCppConversion(s, converterObject(type), toCpp, isConv);
+}
+
+void CppGenerator::writeExtendedConverterInitialization(QTextStream& s, const TypeEntry* externalType,
+ const QVector<const AbstractMetaClass*>& conversions)
+{
+ s << INDENT << "// Extended implicit conversions for " << externalType->qualifiedTargetLangName() << '.' << endl;
+ for (const AbstractMetaClass *sourceClass : conversions) {
+ const QString converterVar = QLatin1String("reinterpret_cast<SbkObjectType *>(")
+ + cppApiVariableName(externalType->targetLangPackage()) + QLatin1Char('[')
+ + getTypeIndexVariableName(externalType) + QLatin1String("])");
+ QString sourceTypeName = fixedCppTypeName(sourceClass->typeEntry());
+ QString targetTypeName = fixedCppTypeName(externalType);
+ QString toCpp = pythonToCppFunctionName(sourceTypeName, targetTypeName);
+ QString isConv = convertibleToCppFunctionName(sourceTypeName, targetTypeName);
+ writeAddPythonToCppConversion(s, converterVar, toCpp, isConv);
+ }
+}
+
+QString CppGenerator::multipleInheritanceInitializerFunctionName(const AbstractMetaClass* metaClass)
+{
+ if (!hasMultipleInheritanceInAncestry(metaClass))
+ return QString();
+ return cpythonBaseName(metaClass->typeEntry()) + QLatin1String("_mi_init");
+}
+
+typedef QHash<QString, QPair<QString, QString> >::const_iterator ProtocolIt;
+
+bool CppGenerator::supportsMappingProtocol(const AbstractMetaClass* metaClass)
+{
+ for (ProtocolIt it = m_mappingProtocol.cbegin(), end = m_mappingProtocol.cend(); it != end; ++it) {
+ if (metaClass->hasFunction(it.key()))
+ return true;
+ }
+
+ return false;
+}
+
+bool CppGenerator::supportsNumberProtocol(const AbstractMetaClass* metaClass)
+{
+ return metaClass->hasArithmeticOperatorOverload()
+ || metaClass->hasLogicalOperatorOverload()
+ || metaClass->hasBitwiseOperatorOverload()
+ || hasBoolCast(metaClass);
+}
+
+bool CppGenerator::supportsSequenceProtocol(const AbstractMetaClass* metaClass)
+{
+ for (ProtocolIt it = m_sequenceProtocol.cbegin(), end = m_sequenceProtocol.cend(); it != end; ++it) {
+ if (metaClass->hasFunction(it.key()))
+ return true;
+ }
+
+ const ComplexTypeEntry* baseType = metaClass->typeEntry()->baseContainerType();
+ if (baseType && baseType->isContainer())
+ return true;
+
+ return false;
+}
+
+bool CppGenerator::shouldGenerateGetSetList(const AbstractMetaClass* metaClass)
+{
+ const AbstractMetaFieldList &fields = metaClass->fields();
+ for (const AbstractMetaField *f : fields) {
+ if (!f->isStatic())
+ return true;
+ }
+ return false;
+}
+
+void CppGenerator::writeClassDefinition(QTextStream &s,
+ const AbstractMetaClass *metaClass,
+ GeneratorContext &classContext)
+{
+ QString tp_flags;
+ QString tp_init;
+ QString tp_new;
+ QString tp_dealloc;
+ QString tp_hash(QLatin1Char('0'));
+ QString tp_call = tp_hash;
+ QString cppClassName = metaClass->qualifiedCppName();
+ const QString className = chopType(cpythonTypeName(metaClass));
+ QString baseClassName(QLatin1Char('0'));
+ AbstractMetaFunctionList ctors;
+ const AbstractMetaFunctionList &allCtors = metaClass->queryFunctions(AbstractMetaClass::Constructors);
+ for (AbstractMetaFunction *f : allCtors) {
+ if (!f->isPrivate() && !f->isModifiedRemoved() && !classContext.forSmartPointer())
+ ctors.append(f);
+ }
+
+ if (!metaClass->baseClass())
+ baseClassName = QLatin1String("reinterpret_cast<PyTypeObject*>(&SbkObject_Type)");
+
+ bool onlyPrivCtor = !metaClass->hasNonPrivateConstructor();
+
+ if (metaClass->isNamespace() || metaClass->hasPrivateDestructor()) {
+ tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_GC");
+ tp_dealloc = metaClass->hasPrivateDestructor() ?
+ QLatin1String("SbkDeallocWrapperWithPrivateDtor") : QLatin1String("0");
+ tp_init = QLatin1String("0");
+ } else {
+ if (onlyPrivCtor)
+ tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_GC");
+ else
+ tp_flags = QLatin1String("Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_GC");
+
+ QString deallocClassName;
+ if (shouldGenerateCppWrapper(metaClass))
+ deallocClassName = wrapperName(metaClass);
+ else
+ deallocClassName = cppClassName;
+ tp_dealloc = QLatin1String("&SbkDeallocWrapper");
+ // avoid constFirst to stay Qt 5.5 compatible
+ tp_init = (onlyPrivCtor || ctors.isEmpty()) ? QLatin1String("0") : cpythonFunctionName(ctors.first());
+ }
+
+ QString tp_getattro(QLatin1Char('0'));
+ QString tp_setattro = tp_getattro;
+ if (usePySideExtensions() && (metaClass->qualifiedCppName() == QLatin1String("QObject"))) {
+ tp_getattro = cpythonGetattroFunctionName(metaClass);
+ tp_setattro = cpythonSetattroFunctionName(metaClass);
+ } else {
+ if (classNeedsGetattroFunction(metaClass))
+ tp_getattro = cpythonGetattroFunctionName(metaClass);
+ if (classNeedsSetattroFunction(metaClass))
+ tp_setattro = cpythonSetattroFunctionName(metaClass);
+ }
+
+ if (metaClass->hasPrivateDestructor() || onlyPrivCtor)
+ tp_new = QLatin1String("0");
+ else
+ tp_new = QLatin1String("SbkObjectTpNew");
+
+ QString tp_richcompare = QString(QLatin1Char('0'));
+ if (metaClass->hasComparisonOperatorOverload())
+ tp_richcompare = cpythonBaseName(metaClass) + QLatin1String("_richcompare");
+
+ QString tp_getset = QString(QLatin1Char('0'));
+ if (shouldGenerateGetSetList(metaClass) && !classContext.forSmartPointer())
+ tp_getset = cpythonGettersSettersDefinitionName(metaClass);
+
+ // search for special functions
+ ShibokenGenerator::clearTpFuncs();
+ const AbstractMetaFunctionList &funcs = metaClass->functions();
+ for (AbstractMetaFunction *func : funcs) {
+ if (m_tpFuncs.contains(func->name()))
+ m_tpFuncs[func->name()] = cpythonFunctionName(func);
+ }
+ if (m_tpFuncs[QLatin1String("__repr__")] == QLatin1String("0")
+ && !metaClass->isQObject()
+ && metaClass->hasToStringCapability()) {
+ m_tpFuncs[QLatin1String("__repr__")] = writeReprFunction(s, classContext);
+ }
+
+ // class or some ancestor has multiple inheritance
+ const AbstractMetaClass* miClass = getMultipleInheritingClass(metaClass);
+ if (miClass) {
+ if (metaClass == miClass)
+ writeMultipleInheritanceInitializerFunction(s, metaClass);
+ writeSpecialCastFunction(s, metaClass);
+ s << endl;
+ }
+
+ if (!metaClass->typeEntry()->hashFunction().isEmpty())
+ tp_hash = QLatin1Char('&') + cpythonBaseName(metaClass) + QLatin1String("_HashFunc");
+
+ const AbstractMetaFunction* callOp = metaClass->findFunction(QLatin1String("operator()"));
+ if (callOp && !callOp->isModifiedRemoved())
+ tp_call = QLatin1Char('&') + cpythonFunctionName(callOp);
+
+ s << "// Class Definition -----------------------------------------------" << endl;
+ s << "extern \"C\" {" << endl;
+
+ if (supportsNumberProtocol(metaClass)) {
+ s << "static PyNumberMethods " << className + QLatin1String("_TypeAsNumber") << ";" << endl;
+ s << endl;
+ }
+
+ if (supportsSequenceProtocol(metaClass)) {
+ s << "static PySequenceMethods " << className + QLatin1String("_TypeAsSequence") << ";" << endl;
+ s << endl;
+ }
+
+ if (supportsMappingProtocol(metaClass)) {
+ s << "static PyMappingMethods " << className + QLatin1String("_TypeAsMapping") << ";" << endl;
+ s << endl;
+ }
+
+ s << "static SbkObjectType " << className + QLatin1String("_Type") << " = { { {" << endl;
+ s << INDENT << "PyVarObject_HEAD_INIT(&SbkObjectType_Type, 0)" << endl;
+ QString computedClassTargetFullName;
+ if (!classContext.forSmartPointer())
+ computedClassTargetFullName = getClassTargetFullName(metaClass);
+ else
+ computedClassTargetFullName = getClassTargetFullName(classContext.preciseType());
+
+ s << INDENT << "/*tp_name*/ \"" << computedClassTargetFullName << "\"," << endl;
+ s << INDENT << "/*tp_basicsize*/ sizeof(SbkObject)," << endl;
+ s << INDENT << "/*tp_itemsize*/ 0," << endl;
+ s << INDENT << "/*tp_dealloc*/ " << tp_dealloc << ',' << endl;
+ s << INDENT << "/*tp_print*/ 0," << endl;
+ s << INDENT << "/*tp_getattr*/ 0," << endl;
+ s << INDENT << "/*tp_setattr*/ 0," << endl;
+ s << INDENT << "/*tp_compare*/ 0," << endl;
+ s << INDENT << "/*tp_repr*/ " << m_tpFuncs[QLatin1String("__repr__")] << "," << endl;
+ s << INDENT << "/*tp_as_number*/ 0," << endl;
+ s << INDENT << "/*tp_as_sequence*/ 0," << endl;
+ s << INDENT << "/*tp_as_mapping*/ 0," << endl;
+ s << INDENT << "/*tp_hash*/ " << tp_hash << ',' << endl;
+ s << INDENT << "/*tp_call*/ " << tp_call << ',' << endl;
+ s << INDENT << "/*tp_str*/ " << m_tpFuncs[QLatin1String("__str__")] << ',' << endl;
+ s << INDENT << "/*tp_getattro*/ " << tp_getattro << ',' << endl;
+ s << INDENT << "/*tp_setattro*/ " << tp_setattro << ',' << endl;
+ s << INDENT << "/*tp_as_buffer*/ 0," << endl;
+ s << INDENT << "/*tp_flags*/ " << tp_flags << ',' << endl;
+ s << INDENT << "/*tp_doc*/ 0," << endl;
+ s << INDENT << "/*tp_traverse*/ " << className << "_traverse," << endl;
+ s << INDENT << "/*tp_clear*/ " << className << "_clear," << endl;
+ s << INDENT << "/*tp_richcompare*/ " << tp_richcompare << ',' << endl;
+ s << INDENT << "/*tp_weaklistoffset*/ 0," << endl;
+ s << INDENT << "/*tp_iter*/ " << m_tpFuncs[QLatin1String("__iter__")] << ',' << endl;
+ s << INDENT << "/*tp_iternext*/ " << m_tpFuncs[QLatin1String("__next__")] << ',' << endl;
+ s << INDENT << "/*tp_methods*/ " << className << "_methods," << endl;
+ s << INDENT << "/*tp_members*/ 0," << endl;
+ s << INDENT << "/*tp_getset*/ " << tp_getset << ',' << endl;
+ s << INDENT << "/*tp_base*/ " << baseClassName << ',' << endl;
+ s << INDENT << "/*tp_dict*/ 0," << endl;
+ s << INDENT << "/*tp_descr_get*/ 0," << endl;
+ s << INDENT << "/*tp_descr_set*/ 0," << endl;
+ s << INDENT << "/*tp_dictoffset*/ 0," << endl;
+ s << INDENT << "/*tp_init*/ " << tp_init << ',' << endl;
+ s << INDENT << "/*tp_alloc*/ 0," << endl;
+ s << INDENT << "/*tp_new*/ " << tp_new << ',' << endl;
+ s << INDENT << "/*tp_free*/ 0," << endl;
+ s << INDENT << "/*tp_is_gc*/ 0," << endl;
+ s << INDENT << "/*tp_bases*/ 0," << endl;
+ s << INDENT << "/*tp_mro*/ 0," << endl;
+ s << INDENT << "/*tp_cache*/ 0," << endl;
+ s << INDENT << "/*tp_subclasses*/ 0," << endl;
+ s << INDENT << "/*tp_weaklist*/ 0" << endl;
+ s << "}, }," << endl;
+ s << INDENT << "/*priv_data*/ 0" << endl;
+ s << "};" << endl;
+ QString suffix;
+ if (isObjectType(metaClass))
+ suffix = QLatin1String("*");
+ s << "} //extern" << endl;
+}
+
+void CppGenerator::writeMappingMethods(QTextStream &s,
+ const AbstractMetaClass *metaClass,
+ GeneratorContext &context)
+{
+
+ QMap<QString, QString> funcs;
+
+ QHash< QString, QPair< QString, QString > >::const_iterator it = m_mappingProtocol.begin();
+ for (; it != m_mappingProtocol.end(); ++it) {
+ const AbstractMetaFunction* func = metaClass->findFunction(it.key());
+ if (!func)
+ continue;
+ QString funcName = cpythonFunctionName(func);
+ QString funcArgs = it.value().first;
+ QString funcRetVal = it.value().second;
+
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
+ s << funcRetVal << ' ' << funcName << '(' << funcArgs << ')' << endl << '{' << endl;
+ writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR));
+
+ writeCppSelfDefinition(s, func, context);
+
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, lastArg);
+ s << '}' << endl << endl;
+ }
+}
+
+void CppGenerator::writeSequenceMethods(QTextStream &s,
+ const AbstractMetaClass *metaClass,
+ GeneratorContext &context)
+{
+
+ QMap<QString, QString> funcs;
+ bool injectedCode = false;
+
+ QHash< QString, QPair< QString, QString > >::const_iterator it = m_sequenceProtocol.begin();
+ for (; it != m_sequenceProtocol.end(); ++it) {
+ const AbstractMetaFunction* func = metaClass->findFunction(it.key());
+ if (!func)
+ continue;
+ injectedCode = true;
+ QString funcName = cpythonFunctionName(func);
+ QString funcArgs = it.value().first;
+ QString funcRetVal = it.value().second;
+
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
+ s << funcRetVal << ' ' << funcName << '(' << funcArgs << ')' << endl << '{' << endl;
+ writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR));
+
+ writeCppSelfDefinition(s, func, context);
+
+ const AbstractMetaArgument* lastArg = func->arguments().isEmpty() ? 0 : func->arguments().last();
+ writeCodeSnips(s, snips,TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, lastArg);
+ s << '}' << endl << endl;
+ }
+
+ if (!injectedCode)
+ writeStdListWrapperMethods(s, context);
+}
+
+void CppGenerator::writeTypeAsSequenceDefinition(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ bool hasFunctions = false;
+ QMap<QString, QString> funcs;
+ for (ProtocolIt it = m_sequenceProtocol.cbegin(), end = m_sequenceProtocol.cend(); it != end; ++it) {
+ const QString &funcName = it.key();
+ const AbstractMetaFunction* func = metaClass->findFunction(funcName);
+ funcs[funcName] = func ? cpythonFunctionName(func).prepend(QLatin1Char('&')) : QString();
+ if (!hasFunctions && func)
+ hasFunctions = true;
+ }
+
+ QString baseName = cpythonBaseName(metaClass);
+
+ //use default implementation
+ if (!hasFunctions) {
+ funcs[QLatin1String("__len__")] = baseName + QLatin1String("__len__");
+ funcs[QLatin1String("__getitem__")] = baseName + QLatin1String("__getitem__");
+ funcs[QLatin1String("__setitem__")] = baseName + QLatin1String("__setitem__");
+ }
+
+ s << INDENT << "memset(&" << baseName << "_TypeAsSequence, 0, sizeof(PySequenceMethods));" << endl;
+ for (QHash<QString, QString>::const_iterator it = m_sqFuncs.cbegin(), end = m_sqFuncs.cend(); it != end; ++it) {
+ const QString& sqName = it.key();
+ if (funcs[sqName].isEmpty())
+ continue;
+ if (it.value() == QLatin1String("sq_slice"))
+ s << "#ifndef IS_PY3K" << endl;
+ s << INDENT << baseName << "_TypeAsSequence." << it.value() << " = " << funcs[sqName] << ';' << endl;
+ if (it.value() == QLatin1String("sq_slice"))
+ s << "#endif" << endl;
+ }
+}
+
+void CppGenerator::writeTypeAsMappingDefinition(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ bool hasFunctions = false;
+ QMap<QString, QString> funcs;
+ for (ProtocolIt it = m_mappingProtocol.cbegin(), end = m_mappingProtocol.cend(); it != end; ++it) {
+ const QString &funcName = it.key();
+ const AbstractMetaFunction* func = metaClass->findFunction(funcName);
+ funcs[funcName] = func ? cpythonFunctionName(func).prepend(QLatin1Char('&')) : QLatin1String("0");
+ if (!hasFunctions && func)
+ hasFunctions = true;
+ }
+
+ //use default implementation
+ if (!hasFunctions) {
+ funcs.insert(QLatin1String("__mlen__"), QString());
+ funcs.insert(QLatin1String("__mgetitem__"), QString());
+ funcs.insert(QLatin1String("__msetitem__"), QString());
+ }
+
+ QString baseName = cpythonBaseName(metaClass);
+ s << INDENT << "memset(&" << baseName << "_TypeAsMapping, 0, sizeof(PyMappingMethods));" << endl;
+ for (QHash<QString, QString>::const_iterator it = m_mpFuncs.cbegin(), end = m_mpFuncs.end(); it != end; ++it) {
+ const QString &mpName = it.key();
+ if (funcs[mpName].isEmpty())
+ continue;
+ s << INDENT << baseName << "_TypeAsMapping." << it.value() << " = " << funcs[mpName] << ';' << endl;
+ }
+}
+
+void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QMap<QString, QString> nb;
+
+ nb.insert(QLatin1String("__add__"), QString());
+ nb.insert(QLatin1String("__sub__"), QString());
+ nb.insert(QLatin1String("__mul__"), QString());
+ nb.insert(QLatin1String("__div__"), QString());
+ nb.insert(QLatin1String("__mod__"), QString());
+ nb.insert(QLatin1String("__neg__"), QString());
+ nb.insert(QLatin1String("__pos__"), QString());
+ nb.insert(QLatin1String("__invert__"), QString());
+ nb.insert(QLatin1String("__lshift__"), QString());
+ nb.insert(QLatin1String("__rshift__"), QString());
+ nb.insert(QLatin1String("__and__"), QString());
+ nb.insert(QLatin1String("__xor__"), QString());
+ nb.insert(QLatin1String("__or__"), QString());
+ nb.insert(QLatin1String("__iadd__"), QString());
+ nb.insert(QLatin1String("__isub__"), QString());
+ nb.insert(QLatin1String("__imul__"), QString());
+ nb.insert(QLatin1String("__idiv__"), QString());
+ nb.insert(QLatin1String("__imod__"), QString());
+ nb.insert(QLatin1String("__ilshift__"), QString());
+ nb.insert(QLatin1String("__irshift__"), QString());
+ nb.insert(QLatin1String("__iand__"), QString());
+ nb.insert(QLatin1String("__ixor__"), QString());
+ nb.insert(QLatin1String("__ior__"), QString());
+
+ const QVector<AbstractMetaFunctionList> opOverloads =
+ filterGroupedOperatorFunctions(metaClass,
+ AbstractMetaClass::ArithmeticOp
+ | AbstractMetaClass::LogicalOp
+ | AbstractMetaClass::BitwiseOp);
+
+ for (const AbstractMetaFunctionList &opOverload : opOverloads) {
+ const AbstractMetaFunction* rfunc = opOverload[0];
+ QString opName = ShibokenGenerator::pythonOperatorFunctionName(rfunc);
+ nb[opName] = cpythonFunctionName(rfunc);
+ }
+
+ QString baseName = cpythonBaseName(metaClass);
+
+ nb[QLatin1String("bool")] = hasBoolCast(metaClass) ? baseName + QLatin1String("___nb_bool") : QString();
+
+ s << INDENT << "memset(&" << baseName << "_TypeAsNumber, 0, sizeof(PyNumberMethods));" << endl;
+ for (QHash<QString, QString>::const_iterator it = m_nbFuncs.cbegin(), end = m_nbFuncs.cend(); it != end; ++it) {
+ const QString &nbName = it.key();
+ if (nb[nbName].isEmpty())
+ continue;
+
+ // bool is special because the field name differs on Python 2 and 3 (nb_nonzero vs nb_bool)
+ // so a shiboken macro is used.
+ if (nbName == QLatin1String("bool")) {
+ s << INDENT << "SBK_NB_BOOL(" << baseName << "_TypeAsNumber) = " << nb[nbName] << ';' << endl;
+ } else {
+ bool excludeFromPy3K = nbName == QLatin1String("__div__") || nbName == QLatin1String("__idiv__");
+ if (excludeFromPy3K) {
+ s << "#ifdef IS_PY3K" << endl;
+ s << INDENT << "SBK_UNUSED(&" << nb[nbName] << ");" << endl;
+ s << "#else" << endl;
+ }
+ s << INDENT << baseName << "_TypeAsNumber." << it.value() << " = " << nb[nbName] << ';' << endl;
+ if (excludeFromPy3K)
+ s << "#endif" << endl;
+ }
+ }
+ if (!nb[QLatin1String("__div__")].isEmpty())
+ s << INDENT << baseName << "_TypeAsNumber.nb_true_divide = " << nb[QLatin1String("__div__")] << ';' << endl;
+}
+
+void CppGenerator::writeTpTraverseFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString baseName = cpythonBaseName(metaClass);
+ s << "static int ";
+ s << baseName << "_traverse(PyObject* " PYTHON_SELF_VAR ", visitproc visit, void* arg)" << endl;
+ s << '{' << endl;
+ s << INDENT << "return reinterpret_cast<PyTypeObject*>(&SbkObject_Type)->tp_traverse(" PYTHON_SELF_VAR ", visit, arg);" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeTpClearFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString baseName = cpythonBaseName(metaClass);
+ s << "static int ";
+ s << baseName << "_clear(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << '{' << endl;
+ s << INDENT << "return reinterpret_cast<PyTypeObject*>(&SbkObject_Type)->tp_clear(" PYTHON_SELF_VAR ");" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeCopyFunction(QTextStream &s, GeneratorContext &context)
+{
+ const AbstractMetaClass *metaClass = context.metaClass();
+ const QString className = chopType(cpythonTypeName(metaClass));
+ s << "static PyObject* " << className << "___copy__(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << "{" << endl;
+ writeCppSelfDefinition(s, context, false, true);
+ QString conversionCode;
+ if (!context.forSmartPointer())
+ conversionCode = cpythonToPythonConversionFunction(metaClass);
+ else
+ conversionCode = cpythonToPythonConversionFunction(context.preciseType());
+
+ s << INDENT << "PyObject* " << PYTHON_RETURN_VAR << " = " << conversionCode;
+ s << CPP_SELF_VAR ");" << endl;
+ writeFunctionReturnErrorCheckSection(s);
+ s << INDENT << "return " PYTHON_RETURN_VAR ";" << endl;
+ s << "}" << endl;
+ s << endl;
+}
+
+void CppGenerator::writeGetterFunction(QTextStream &s,
+ const AbstractMetaField *metaField,
+ GeneratorContext &context)
+{
+ ErrorCode errorCode(0);
+ s << "static PyObject* " << cpythonGetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", void*)" << endl;
+ s << '{' << endl;
+
+ writeCppSelfDefinition(s, context);
+
+ AbstractMetaType* fieldType = metaField->type();
+ // Force use of pointer to return internal variable memory
+ bool newWrapperSameObject = !fieldType->isConstant() && isWrapperType(fieldType) && !isPointer(fieldType);
+
+ QString cppField;
+ if (avoidProtectedHack() && metaField->isProtected()) {
+ cppField = QString::fromLatin1("((%1*)%2)->%3()")
+ .arg(wrapperName(metaField->enclosingClass()), QLatin1String(CPP_SELF_VAR),
+ protectedFieldGetterName(metaField));
+ } else {
+ cppField = QLatin1String(CPP_SELF_VAR) + QLatin1String("->") + metaField->name();
+ if (newWrapperSameObject) {
+ cppField.prepend(QLatin1String("&("));
+ cppField.append(QLatin1Char(')'));
+ }
+ }
+ if (isCppIntegralPrimitive(fieldType) || fieldType->isEnum()) {
+ s << INDENT << getFullTypeNameWithoutModifiers(fieldType) << " cppOut_local = " << cppField << ';' << endl;
+ cppField = QLatin1String("cppOut_local");
+ } else if (avoidProtectedHack() && metaField->isProtected()) {
+ s << INDENT << getFullTypeNameWithoutModifiers(fieldType);
+ if (fieldType->isContainer() || fieldType->isFlags() || fieldType->isSmartPointer()) {
+ s << '&';
+ cppField.prepend(QLatin1Char('*'));
+ } else if ((!fieldType->isConstant() && !fieldType->isEnum() && !fieldType->isPrimitive()) || fieldType->indirections() == 1) {
+ s << '*';
+ }
+ s << " fieldValue = " << cppField << ';' << endl;
+ cppField = QLatin1String("fieldValue");
+ }
+
+ s << INDENT << "PyObject* pyOut = 0;\n";
+ if (newWrapperSameObject) {
+ // Special case colocated field with same address (first field in a struct)
+ s << INDENT << "if (reinterpret_cast<void *>("
+ << cppField
+ << ") == reinterpret_cast<void *>("
+ << CPP_SELF_VAR << ")) {\n";
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "pyOut = reinterpret_cast<PyObject *>(Shiboken::Object::findColocatedChild("
+ << "reinterpret_cast<SbkObject *>(self), reinterpret_cast<const SbkObjectType *>("
+ << cpythonTypeNameExt(fieldType)
+ << ")));\n";
+ s << INDENT << "if (pyOut) {Py_IncRef(pyOut); return pyOut;}\n";
+ }
+ s << INDENT << "}\n";
+ // Check if field wrapper has already been created.
+ s << INDENT << "else if (Shiboken::BindingManager::instance().hasWrapper(" << cppField << ")) {" << "\n";
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "pyOut = (PyObject*)Shiboken::BindingManager::instance().retrieveWrapper(" << cppField << ");" << "\n";
+ s << INDENT << "Py_IncRef(pyOut);" << "\n";
+ s << INDENT << "return pyOut;" << "\n";
+ }
+ s << INDENT << "}\n";
+ // Create and register new wrapper
+ s << INDENT << "pyOut = ";
+ s << "Shiboken::Object::newObject(reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(fieldType)
+ << "), " << cppField << ", false, true);" << endl;
+ s << INDENT << "Shiboken::Object::setParent(" PYTHON_SELF_VAR ", pyOut)";
+ } else {
+ s << INDENT << "pyOut = ";
+ writeToPythonConversion(s, fieldType, metaField->enclosingClass(), cppField);
+ }
+ s << ';' << endl;
+
+ s << INDENT << "return pyOut;" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeSetterFunction(QTextStream &s,
+ const AbstractMetaField *metaField,
+ GeneratorContext &context)
+{
+ ErrorCode errorCode(0);
+ s << "static int " << cpythonSetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* pyIn, void*)" << endl;
+ s << '{' << endl;
+
+ writeCppSelfDefinition(s, context);
+
+ s << INDENT << "if (pyIn == 0) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_TypeError, \"'";
+ s << metaField->name() << "' may not be deleted\");" << endl;
+ s << INDENT << "return -1;" << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ AbstractMetaType* fieldType = metaField->type();
+
+ s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ';' << endl;
+ s << INDENT << "if (!";
+ writeTypeCheck(s, fieldType, QLatin1String("pyIn"), isNumber(fieldType->typeEntry()));
+ s << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_TypeError, \"wrong type attributed to '";
+ s << metaField->name() << "', '" << fieldType->name() << "' or convertible type expected\");" << endl;
+ s << INDENT << "return -1;" << endl;
+ }
+ s << INDENT << '}' << endl << endl;
+
+ QString cppField = QString::fromLatin1("%1->%2").arg(QLatin1String(CPP_SELF_VAR), metaField->name());
+ s << INDENT;
+ if (avoidProtectedHack() && metaField->isProtected()) {
+ s << getFullTypeNameWithoutModifiers(fieldType);
+ s << (fieldType->indirections() == 1 ? "*" : "") << " cppOut;" << endl;
+ s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut);" << endl;
+ s << INDENT << QString::fromLatin1("((%1*)%2)->%3(cppOut)")
+ .arg(wrapperName(metaField->enclosingClass()),
+ QLatin1String(CPP_SELF_VAR), protectedFieldSetterName(metaField));
+ } else if (isCppIntegralPrimitive(fieldType) || fieldType->typeEntry()->isEnum() || fieldType->typeEntry()->isFlags()) {
+ s << getFullTypeNameWithoutModifiers(fieldType) << " cppOut_local = " << cppField << ';' << endl;
+ s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut_local);" << endl;
+ s << INDENT << cppField << " = cppOut_local";
+ } else {
+ s << getFullTypeNameWithoutModifiers(fieldType);
+ s << QString::fromLatin1("*").repeated(fieldType->indirections()) << "& cppOut_ptr = ";
+ s << cppField << ';' << endl;
+ s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut_ptr)";
+ }
+ s << ';' << endl << endl;
+
+ if (isPointerToWrapperType(fieldType)) {
+ s << INDENT << "Shiboken::Object::keepReference(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "), \"";
+ s << metaField->name() << "\", pyIn);" << endl;
+ }
+
+ s << INDENT << "return 0;" << endl;
+ s << '}' << endl;
+}
+
+void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &context)
+{
+ const AbstractMetaClass *metaClass = context.metaClass();
+ QString baseName = cpythonBaseName(metaClass);
+ s << "static PyObject* ";
+ s << baseName << "_richcompare(PyObject* " PYTHON_SELF_VAR ", PyObject* " PYTHON_ARG ", int op)" << endl;
+ s << '{' << endl;
+ writeCppSelfDefinition(s, context, false, true);
+ writeUnusedVariableCast(s, QLatin1String(CPP_SELF_VAR));
+ s << INDENT << "PyObject* " PYTHON_RETURN_VAR " = 0;" << endl;
+ s << INDENT << "PythonToCppFunc " PYTHON_TO_CPP_VAR << ';' << endl;
+ writeUnusedVariableCast(s, QLatin1String(PYTHON_TO_CPP_VAR));
+ s << endl;
+
+ s << INDENT << "switch (op) {" << endl;
+ {
+ Indentation indent(INDENT);
+ const QVector<AbstractMetaFunctionList> &groupedFuncs = filterGroupedOperatorFunctions(metaClass, AbstractMetaClass::ComparisonOp);
+ for (const AbstractMetaFunctionList &overloads : groupedFuncs) {
+ const AbstractMetaFunction* rfunc = overloads[0];
+
+ QString operatorId = ShibokenGenerator::pythonRichCompareOperatorId(rfunc);
+ s << INDENT << "case " << operatorId << ':' << endl;
+
+ Indentation indent(INDENT);
+
+ QString op = rfunc->originalName();
+ op = op.right(op.size() - QLatin1String("operator").size());
+
+ int alternativeNumericTypes = 0;
+ for (const AbstractMetaFunction *func : overloads) {
+ if (!func->isStatic() &&
+ ShibokenGenerator::isNumber(func->arguments()[0]->type()->typeEntry()))
+ alternativeNumericTypes++;
+ }
+
+ bool first = true;
+ OverloadData overloadData(overloads, this);
+ const OverloadDataList &nextOverloads = overloadData.nextOverloadData();
+ for (OverloadData *od : nextOverloads) {
+ const AbstractMetaFunction* func = od->referenceFunction();
+ if (func->isStatic())
+ continue;
+ const AbstractMetaType* argType = getArgumentType(func, 1);
+ if (!argType)
+ continue;
+ if (!first) {
+ s << " else ";
+ } else {
+ first = false;
+ s << INDENT;
+ }
+ s << "if (";
+ writeTypeCheck(s, argType, QLatin1String(PYTHON_ARG), alternativeNumericTypes == 1 || isPyInt(argType));
+ s << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "// " << func->signature() << endl;
+ writeArgumentConversion(s, argType, QLatin1String(CPP_ARG0),
+ QLatin1String(PYTHON_ARG), metaClass,
+ QString(), func->isUserAdded());
+
+ // If the function is user added, use the inject code
+ if (func->isUserAdded()) {
+ CodeSnipList snips = func->injectedCodeSnips();
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, func->arguments().last());
+ } else {
+ QString expression = QString::fromLatin1("%1%2 %3 (%4" CPP_ARG0 ")")
+ .arg(func->isPointerOperator() ? QLatin1String("&") : QString(),
+ QLatin1String(CPP_SELF_VAR), op,
+ shouldDereferenceAbstractMetaTypePointer(argType) ? QLatin1String("*") : QString());
+ s << INDENT;
+ if (func->type())
+ s << func->type()->cppSignature() << " " CPP_RETURN_VAR " = ";
+ s << expression << ';' << endl;
+ s << INDENT << PYTHON_RETURN_VAR " = ";
+ if (func->type())
+ writeToPythonConversion(s, func->type(), metaClass, QLatin1String(CPP_RETURN_VAR));
+ else
+ s << "Py_None;" << endl << INDENT << "Py_INCREF(Py_None)";
+ s << ';' << endl;
+ }
+ }
+ s << INDENT << '}';
+ }
+
+ s << " else {" << endl;
+ if (operatorId == QLatin1String("Py_EQ") || operatorId == QLatin1String("Py_NE")) {
+ Indentation indent(INDENT);
+ s << INDENT << PYTHON_RETURN_VAR " = "
+ << (operatorId == QLatin1String("Py_EQ") ? "Py_False" : "Py_True") << ';' << endl;
+ s << INDENT << "Py_INCREF(" PYTHON_RETURN_VAR ");" << endl;
+ } else {
+ Indentation indent(INDENT);
+ s << INDENT << "goto " << baseName << "_RichComparison_TypeError;" << endl;
+ }
+ s << INDENT << '}' << endl << endl;
+
+ s << INDENT << "break;" << endl;
+ }
+ s << INDENT << "default:" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "goto " << baseName << "_RichComparison_TypeError;" << endl;
+ }
+ }
+ s << INDENT << '}' << endl << endl;
+
+ s << INDENT << "if (" PYTHON_RETURN_VAR " && !PyErr_Occurred())" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return " PYTHON_RETURN_VAR ";" << endl;
+ }
+ s << INDENT << baseName << "_RichComparison_TypeError:" << endl;
+ s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"operator not implemented.\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl;
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList overloads)
+{
+ Q_ASSERT(!overloads.isEmpty());
+ OverloadData overloadData(overloads, this);
+ bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(overloadData);
+ const AbstractMetaFunction* func = overloadData.referenceFunction();
+ int min = overloadData.minArgs();
+ int max = overloadData.maxArgs();
+
+ s << '"' << func->name() << "\", (PyCFunction)" << cpythonFunctionName(func) << ", ";
+ if ((min == max) && (max < 2) && !usePyArgs) {
+ if (max == 0)
+ s << "METH_NOARGS";
+ else
+ s << "METH_O";
+ } else {
+ s << "METH_VARARGS";
+ if (overloadData.hasArgumentWithDefaultValue())
+ s << "|METH_KEYWORDS";
+ }
+ if (func->ownerClass() && overloadData.hasStaticFunction())
+ s << "|METH_STATIC";
+}
+
+void CppGenerator::writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads)
+{
+ Q_ASSERT(!overloads.isEmpty());
+ const AbstractMetaFunction* func = overloads.first();
+ if (m_tpFuncs.contains(func->name()))
+ return;
+
+ s << INDENT;
+ if (OverloadData::hasStaticAndInstanceFunctions(overloads)) {
+ s << cpythonMethodDefinitionName(func);
+ } else {
+ s << '{';
+ writeMethodDefinitionEntry(s, overloads);
+ s << '}';
+ }
+ s << ',' << endl;
+}
+
+void CppGenerator::writeEnumsInitialization(QTextStream& s, AbstractMetaEnumList& enums)
+{
+ if (enums.isEmpty())
+ return;
+ s << INDENT << "// Initialization of enums." << endl << endl;
+ for (const AbstractMetaEnum *cppEnum : qAsConst(enums)) {
+ if (cppEnum->isPrivate())
+ continue;
+ writeEnumInitialization(s, cppEnum);
+ }
+}
+
+void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ const AbstractMetaClass* enclosingClass = getProperEnclosingClassForEnum(cppEnum);
+ const AbstractMetaClass* upper = enclosingClass ? enclosingClass->enclosingClass() : 0;
+ bool hasUpperEnclosingClass = upper && upper->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass;
+ QString enclosingObjectVariable;
+ if (enclosingClass)
+ enclosingObjectVariable = QLatin1Char('&') + cpythonTypeName(enclosingClass);
+ else if (hasUpperEnclosingClass)
+ enclosingObjectVariable = QLatin1String("enclosingClass");
+ else
+ enclosingObjectVariable = QLatin1String("module");
+
+ s << INDENT << "// Initialization of ";
+ s << (cppEnum->isAnonymous() ? "anonymous enum identified by enum value" : "enum");
+ s << " '" << cppEnum->name() << "'." << endl;
+
+ if (!cppEnum->isAnonymous()) {
+ FlagsTypeEntry* flags = cppEnum->typeEntry()->flags();
+ if (flags) {
+ s << INDENT << cpythonTypeNameExt(flags) << " = PySide::QFlags::create(\"" << flags->flagsName() << "\", &"
+ << cpythonEnumName(cppEnum) << "_as_number);" << endl;
+ }
+
+ s << INDENT << cpythonTypeNameExt(cppEnum->typeEntry()) << " = Shiboken::Enum::";
+ s << ((enclosingClass || hasUpperEnclosingClass) ? "createScopedEnum" : "createGlobalEnum");
+ s << '(' << enclosingObjectVariable << ',' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << '"' << cppEnum->name() << "\"," << endl;
+ s << INDENT << '"' << getClassTargetFullName(cppEnum) << "\"," << endl;
+ s << INDENT << '"' << (cppEnum->enclosingClass() ? (cppEnum->enclosingClass()->qualifiedCppName() + QLatin1String("::")) : QString());
+ s << cppEnum->name() << '"';
+ if (flags)
+ s << ',' << endl << INDENT << cpythonTypeNameExt(flags);
+ s << ");" << endl;
+ }
+ s << INDENT << "if (!" << cpythonTypeNameExt(cppEnum->typeEntry()) << ')' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl;
+ }
+ }
+
+ const AbstractMetaEnumValueList &enumValues = cppEnum->values();
+ for (const AbstractMetaEnumValue *enumValue : enumValues) {
+ if (cppEnum->typeEntry()->isEnumValueRejected(enumValue->name()))
+ continue;
+
+ QString enumValueText;
+ if (!avoidProtectedHack() || !cppEnum->isProtected()) {
+ enumValueText = QLatin1String("(long) ");
+ if (cppEnum->enclosingClass())
+ enumValueText += cppEnum->enclosingClass()->qualifiedCppName() + QLatin1String("::");
+ enumValueText += enumValue->name();
+ } else {
+ enumValueText += QString::number(enumValue->value());
+ }
+
+ if (cppEnum->isAnonymous()) {
+ if (enclosingClass || hasUpperEnclosingClass) {
+ s << INDENT << '{' << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyObject* anonEnumItem = PyInt_FromLong(" << enumValueText << ");" << endl;
+ s << INDENT << "if (PyDict_SetItemString(reinterpret_cast<SbkObjectType *>(" << enclosingObjectVariable
+ << ")->super.ht_type.tp_dict, \"" << enumValue->name() << "\", anonEnumItem) < 0)" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << "Py_DECREF(anonEnumItem);" << endl;
+ }
+ s << INDENT << '}' << endl;
+ } else {
+ s << INDENT << "if (PyModule_AddIntConstant(module, \"" << enumValue->name() << "\", ";
+ s << enumValueText << ") < 0)" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ }
+ } else {
+ s << INDENT << "if (!Shiboken::Enum::";
+ s << ((enclosingClass || hasUpperEnclosingClass) ? "createScopedEnumItem" : "createGlobalEnumItem");
+ s << '(' << cpythonTypeNameExt(cppEnum->typeEntry()) << ',' << endl;
+ Indentation indent(INDENT);
+ s << INDENT << enclosingObjectVariable << ", \"" << enumValue->name() << "\", ";
+ s << enumValueText << "))" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ }
+
+ writeEnumConverterInitialization(s, cppEnum);
+
+ s << INDENT << "// End of '" << cppEnum->name() << "' enum";
+ if (cppEnum->typeEntry()->flags())
+ s << "/flags";
+ s << '.' << endl << endl;
+}
+
+void CppGenerator::writeSignalInitialization(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ // Try to check something and print some warnings
+ const AbstractMetaFunctionList &signalFuncs = metaClass->cppSignalFunctions();
+ for (const AbstractMetaFunction *cppSignal : signalFuncs) {
+ if (cppSignal->declaringClass() != metaClass)
+ continue;
+ const AbstractMetaArgumentList &arguments = cppSignal->arguments();
+ for (AbstractMetaArgument *arg : arguments) {
+ AbstractMetaType* metaType = arg->type();
+ const QByteArray origType =
+ QMetaObject::normalizedType(qPrintable(metaType->originalTypeDescription()));
+ const QByteArray cppSig =
+ QMetaObject::normalizedType(qPrintable(metaType->cppSignature()));
+ if ((origType != cppSig) && (!metaType->isFlags())) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Typedef used on signal " << metaClass->qualifiedCppName() << "::"
+ << cppSignal->signature();
+ }
+ }
+ }
+
+ s << INDENT << "PySide::Signal::registerSignals(&" << cpythonTypeName(metaClass) << ", &::"
+ << metaClass->qualifiedCppName() << "::staticMetaObject);" << endl;
+}
+
+void CppGenerator::writeFlagsToLong(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
+ if (!flagsEntry)
+ return;
+ s << "static PyObject* " << cpythonEnumName(cppEnum) << "_long(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << "{" << endl;
+ s << INDENT << "int val;" << endl;
+ AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
+ s << INDENT << cpythonToCppConversionFunction(flagsType) << PYTHON_SELF_VAR << ", &val);" << endl;
+ s << INDENT << "return Shiboken::Conversions::copyToPython(Shiboken::Conversions::PrimitiveTypeConverter<int>(), &val);" << endl;
+ s << "}" << endl;
+}
+
+void CppGenerator::writeFlagsNonZero(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
+ if (!flagsEntry)
+ return;
+ s << "static int " << cpythonEnumName(cppEnum) << "__nonzero(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << "{" << endl;
+
+ s << INDENT << "int val;" << endl;
+ AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
+ s << INDENT << cpythonToCppConversionFunction(flagsType) << PYTHON_SELF_VAR << ", &val);" << endl;
+ s << INDENT << "return val != 0;" << endl;
+ s << "}" << endl;
+}
+
+void CppGenerator::writeFlagsMethods(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ writeFlagsBinaryOperator(s, cppEnum, 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 << endl;
+}
+
+void CppGenerator::writeFlagsNumberMethodsDefinition(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ QString cpythonName = cpythonEnumName(cppEnum);
+
+ s << "static PyNumberMethods " << cpythonName << "_as_number = {" << endl;
+ s << INDENT << "/*nb_add*/ 0," << endl;
+ s << INDENT << "/*nb_subtract*/ 0," << endl;
+ s << INDENT << "/*nb_multiply*/ 0," << endl;
+ s << INDENT << "#ifndef IS_PY3K" << endl;
+ s << INDENT << "/* nb_divide */ 0," << endl;
+ s << INDENT << "#endif" << endl;
+ s << INDENT << "/*nb_remainder*/ 0," << endl;
+ s << INDENT << "/*nb_divmod*/ 0," << endl;
+ s << INDENT << "/*nb_power*/ 0," << endl;
+ s << INDENT << "/*nb_negative*/ 0," << endl;
+ s << INDENT << "/*nb_positive*/ 0," << endl;
+ s << INDENT << "/*nb_absolute*/ 0," << endl;
+ s << INDENT << "/*nb_nonzero*/ " << cpythonName << "__nonzero," << endl;
+ s << INDENT << "/*nb_invert*/ (unaryfunc)" << cpythonName << "___invert__," << endl;
+ s << INDENT << "/*nb_lshift*/ 0," << endl;
+ s << INDENT << "/*nb_rshift*/ 0," << endl;
+ s << INDENT << "/*nb_and*/ (binaryfunc)" << cpythonName << "___and__," << endl;
+ s << INDENT << "/*nb_xor*/ (binaryfunc)" << cpythonName << "___xor__," << endl;
+ s << INDENT << "/*nb_or*/ (binaryfunc)" << cpythonName << "___or__," << endl;
+ s << INDENT << "#ifndef IS_PY3K" << endl;
+ s << INDENT << "/* nb_coerce */ 0," << endl;
+ s << INDENT << "#endif" << endl;
+ s << INDENT << "/*nb_int*/ " << cpythonName << "_long," << endl;
+ s << INDENT << "#ifdef IS_PY3K" << endl;
+ s << INDENT << "/*nb_reserved*/ 0," << endl;
+ s << INDENT << "/*nb_float*/ 0," << endl;
+ s << INDENT << "#else" << endl;
+ s << INDENT << "/*nb_long*/ " << cpythonName << "_long," << endl;
+ s << INDENT << "/*nb_float*/ 0," << endl;
+ s << INDENT << "/*nb_oct*/ 0," << endl;
+ s << INDENT << "/*nb_hex*/ 0," << endl;
+ s << INDENT << "#endif" << endl;
+ s << INDENT << "/*nb_inplace_add*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_subtract*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_multiply*/ 0," << endl;
+ s << INDENT << "#ifndef IS_PY3K" << endl;
+ s << INDENT << "/*nb_inplace_divide*/ 0," << endl;
+ s << INDENT << "#endif" << endl;
+ s << INDENT << "/*nb_inplace_remainder*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_power*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_lshift*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_rshift*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_and*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_xor*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_or*/ 0," << endl;
+ s << INDENT << "/*nb_floor_divide*/ 0," << endl;
+ s << INDENT << "/*nb_true_divide*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_floor_divide*/ 0," << endl;
+ s << INDENT << "/*nb_inplace_true_divide*/ 0," << endl;
+ s << INDENT << "/*nb_index*/ 0" << endl;
+ s << "};" << endl << endl;
+}
+
+void CppGenerator::writeFlagsBinaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
+ QString pyOpName, QString cppOpName)
+{
+ FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
+ Q_ASSERT(flagsEntry);
+
+ s << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* " PYTHON_SELF_VAR ", PyObject* " PYTHON_ARG ")" << endl;
+ s << '{' << endl;
+
+ AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
+ s << INDENT << "::" << flagsEntry->originalName() << " cppResult, " CPP_SELF_VAR ", cppArg;" << endl;
+ s << "#ifdef IS_PY3K" << endl;
+ s << INDENT << CPP_SELF_VAR " = (::" << flagsEntry->originalName() << ")(int)PyLong_AsLong(" PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "cppArg = (" << flagsEntry->originalName() << ")(int)PyLong_AsLong(" PYTHON_ARG ");" << endl;
+ s << "#else" << endl;
+ s << INDENT << CPP_SELF_VAR " = (::" << flagsEntry->originalName() << ")(int)PyInt_AsLong(" PYTHON_SELF_VAR ");" << endl;
+ s << INDENT << "cppArg = (" << flagsEntry->originalName() << ")(int)PyInt_AsLong(" PYTHON_ARG ");" << endl;
+ s << "#endif" << endl << endl;
+ s << INDENT << "cppResult = " CPP_SELF_VAR " " << cppOpName << " cppArg;" << endl;
+ s << INDENT << "return ";
+ writeToPythonConversion(s, flagsType, 0, QLatin1String("cppResult"));
+ s << ';' << endl;
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeFlagsUnaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
+ QString pyOpName, QString cppOpName, bool boolResult)
+{
+ FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags();
+ Q_ASSERT(flagsEntry);
+
+ s << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* " PYTHON_SELF_VAR ", PyObject* " PYTHON_ARG ")" << endl;
+ s << '{' << endl;
+
+ AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry);
+ s << INDENT << "::" << flagsEntry->originalName() << " " CPP_SELF_VAR ";" << endl;
+ s << INDENT << cpythonToCppConversionFunction(flagsType) << PYTHON_SELF_VAR << ", &" CPP_SELF_VAR ");" << endl;
+ s << INDENT;
+ if (boolResult)
+ s << "bool";
+ else
+ s << "::" << flagsEntry->originalName();
+ s << " cppResult = " << cppOpName << CPP_SELF_VAR ";" << endl;
+ s << INDENT << "return ";
+ if (boolResult)
+ s << "PyBool_FromLong(cppResult)";
+ else
+ writeToPythonConversion(s, flagsType, 0, QLatin1String("cppResult"));
+ s << ';' << endl;
+ s << '}' << endl << endl;
+}
+
+QString CppGenerator::getInitFunctionName(GeneratorContext &context) const
+{
+ QString initFunctionName;
+ if (!context.forSmartPointer()) {
+ initFunctionName = context.metaClass()->qualifiedCppName();
+ initFunctionName.replace(QLatin1String("::"), QLatin1String("_"));
+ } else {
+ initFunctionName = getFilteredCppSignatureString(context.preciseType()->cppSignature());
+ }
+ return initFunctionName;
+}
+
+void CppGenerator::writeClassRegister(QTextStream &s,
+ const AbstractMetaClass *metaClass,
+ GeneratorContext &classContext)
+{
+ const ComplexTypeEntry* classTypeEntry = metaClass->typeEntry();
+
+ const AbstractMetaClass* enc = metaClass->enclosingClass();
+ bool hasEnclosingClass = enc && enc->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass;
+ QString enclosingObjectVariable = hasEnclosingClass ? QLatin1String("enclosingClass") : QLatin1String("module");
+
+ QString pyTypeName = cpythonTypeName(metaClass);
+ QString initFunctionName = getInitFunctionName(classContext);
+ s << "void init_" << initFunctionName;
+ s << "(PyObject* " << enclosingObjectVariable << ")" << endl;
+ s << '{' << endl;
+
+ if (supportsNumberProtocol(metaClass)) {
+ s << INDENT << "// type has number operators" << endl;
+ writeTypeAsNumberDefinition(s, metaClass);
+ s << INDENT << pyTypeName << ".super.ht_type.tp_as_number = &" << pyTypeName << "AsNumber;" << endl;
+ s << endl;
+ }
+
+ if (supportsSequenceProtocol(metaClass)) {
+ s << INDENT << "// type supports sequence protocol" << endl;
+ writeTypeAsSequenceDefinition(s, metaClass);
+ s << INDENT << pyTypeName << ".super.ht_type.tp_as_sequence = &" << pyTypeName << "AsSequence;" << endl;
+ s << endl;
+ }
+
+ if (supportsMappingProtocol(metaClass)) {
+ s << INDENT << "// type supports mapping protocol" << endl;
+ writeTypeAsMappingDefinition(s, metaClass);
+ s << INDENT << pyTypeName << ".super.ht_type.tp_as_mapping = &" << pyTypeName << "AsMapping;" << endl;
+ s << endl;
+ }
+
+ if (!classContext.forSmartPointer())
+ s << INDENT << cpythonTypeNameExt(classTypeEntry);
+ else
+ s << INDENT << cpythonTypeNameExt(classContext.preciseType());
+
+ s << " = reinterpret_cast<PyTypeObject*>(&" << pyTypeName << ");" << endl;
+ s << endl;
+
+ // Multiple inheritance
+ QString pyTypeBasesVariable = pyTypeName + QLatin1String("_bases");
+ const AbstractMetaClassList baseClasses = getBaseClasses(metaClass);
+ if (metaClass->baseClassNames().size() > 1) {
+ s << INDENT << "PyObject* " << pyTypeBasesVariable << " = PyTuple_Pack(" << baseClasses.size() << ',' << endl;
+ QStringList bases;
+ for (const AbstractMetaClass *base : baseClasses)
+ bases << QLatin1String("(PyObject*)") + cpythonTypeNameExt(base->typeEntry());
+ Indentation indent(INDENT);
+ QString separator;
+ QTextStream sep(&separator);
+ sep << "," << endl << INDENT;
+ s << INDENT << bases.join(separator) << ");" << endl << endl;
+ }
+
+ // Create type and insert it in the module or enclosing class.
+ s << INDENT << "if (!Shiboken::ObjectType::introduceWrapperType(" << enclosingObjectVariable;
+ QString typeName;
+ if (!classContext.forSmartPointer())
+ typeName = metaClass->name();
+ else
+ typeName = classContext.preciseType()->cppSignature();
+
+ s << ", \"" << typeName << "\", \"";
+
+ // Original name
+ if (!classContext.forSmartPointer())
+ s << metaClass->qualifiedCppName() << (isObjectType(classTypeEntry) ? "*" : "");
+ else
+ s << classContext.preciseType()->cppSignature();
+
+ s << "\"," << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "&" << pyTypeName;
+
+ // Set destructor function
+ if (!metaClass->isNamespace() && !metaClass->hasPrivateDestructor()) {
+ QString dtorClassName = metaClass->qualifiedCppName();
+ if ((avoidProtectedHack() && metaClass->hasProtectedDestructor()) || classTypeEntry->isValue())
+ dtorClassName = wrapperName(metaClass);
+ if (classContext.forSmartPointer())
+ dtorClassName = wrapperName(classContext.preciseType());
+
+ s << ", &Shiboken::callCppDestructor< ::" << dtorClassName << " >";
+ } else if (metaClass->baseClass() || hasEnclosingClass) {
+ s << ", 0";
+ }
+
+ // Base type
+ if (metaClass->baseClass()) {
+ s << ", reinterpret_cast<SbkObjectType *>(" << cpythonTypeNameExt(metaClass->baseClass()->typeEntry()) << ')';
+ // The other base types
+ if (metaClass->baseClassNames().size() > 1)
+ s << ", " << pyTypeBasesVariable;
+ else if (hasEnclosingClass)
+ s << ", 0";
+ } else if (hasEnclosingClass) {
+ s << ", 0, 0";
+ }
+ if (hasEnclosingClass)
+ s << ", true";
+ s << ")) {" << endl;
+ s << INDENT << "return;" << endl;
+ }
+ s << INDENT << '}' << endl << endl;
+
+ // Register conversions for the type.
+ writeConverterRegister(s, metaClass, classContext);
+ s << endl;
+
+ // class inject-code target/beginning
+ if (!classTypeEntry->codeSnips().isEmpty()) {
+ writeCodeSnips(s, classTypeEntry->codeSnips(), TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode, metaClass);
+ s << endl;
+ }
+
+ // Fill multiple inheritance data, if needed.
+ const AbstractMetaClass* miClass = getMultipleInheritingClass(metaClass);
+ if (miClass) {
+ s << INDENT << "MultipleInheritanceInitFunction func = ";
+ if (miClass == metaClass) {
+ s << multipleInheritanceInitializerFunctionName(miClass) << ";" << endl;
+ } else {
+ s << "Shiboken::ObjectType::getMultipleIheritanceFunction(reinterpret_cast<SbkObjectType*>(";
+ s << cpythonTypeNameExt(miClass->typeEntry()) << "));" << endl;
+ }
+ s << INDENT << "Shiboken::ObjectType::setMultipleIheritanceFunction(&";
+ s << cpythonTypeName(metaClass) << ", func);" << endl;
+ s << INDENT << "Shiboken::ObjectType::setCastFunction(&" << cpythonTypeName(metaClass);
+ s << ", &" << cpythonSpecialCastFunctionName(metaClass) << ");" << endl;
+ }
+
+ // Set typediscovery struct or fill the struct of another one
+ if (metaClass->isPolymorphic() && metaClass->baseClass()) {
+ s << INDENT << "Shiboken::ObjectType::setTypeDiscoveryFunctionV2(&" << cpythonTypeName(metaClass);
+ s << ", &" << cpythonBaseName(metaClass) << "_typeDiscovery);" << endl << endl;
+ }
+
+ AbstractMetaEnumList classEnums = metaClass->enums();
+ const AbstractMetaClassList &innerClasses = metaClass->innerClasses();
+ for (AbstractMetaClass *innerClass : innerClasses)
+ lookForEnumsInClassesNotToBeGenerated(classEnums, innerClass);
+
+ ErrorCode errorCode(QString::null);
+ writeEnumsInitialization(s, classEnums);
+
+ if (metaClass->hasSignals())
+ writeSignalInitialization(s, metaClass);
+
+ // Write static fields
+ const AbstractMetaFieldList &fields = metaClass->fields();
+ for (const AbstractMetaField *field : fields) {
+ if (!field->isStatic())
+ continue;
+ s << INDENT << QLatin1String("PyDict_SetItemString(") + cpythonTypeName(metaClass) + QLatin1String(".super.ht_type.tp_dict, \"");
+ s << field->name() << "\", ";
+ writeToPythonConversion(s, field->type(), metaClass, metaClass->qualifiedCppName() + QLatin1String("::") + field->name());
+ s << ");" << endl;
+ }
+ s << endl;
+
+ // class inject-code target/end
+ if (!classTypeEntry->codeSnips().isEmpty()) {
+ s << endl;
+ writeCodeSnips(s, classTypeEntry->codeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode, metaClass);
+ }
+
+ if (usePySideExtensions()) {
+ if (avoidProtectedHack() && shouldGenerateCppWrapper(metaClass))
+ s << INDENT << wrapperName(metaClass) << "::pysideInitQtMetaTypes();\n";
+ else
+ writeInitQtMetaTypeFunctionBody(s, classContext);
+ }
+
+ if (usePySideExtensions() && metaClass->isQObject()) {
+ s << INDENT << "Shiboken::ObjectType::setSubTypeInitHook(&" << pyTypeName << ", &PySide::initQObjectSubType);" << endl;
+ s << INDENT << "PySide::initDynamicMetaObject(&" << pyTypeName << ", &::" << metaClass->qualifiedCppName()
+ << "::staticMetaObject, sizeof(::" << metaClass->qualifiedCppName() << "));" << endl;
+ }
+
+ s << '}' << endl;
+}
+
+void CppGenerator::writeInitQtMetaTypeFunctionBody(QTextStream &s, GeneratorContext &context) const
+{
+ const AbstractMetaClass* metaClass = context.metaClass();
+ // Gets all class name variants used on different possible scopes
+ QStringList nameVariants;
+ if (!context.forSmartPointer())
+ nameVariants << metaClass->name();
+ else
+ nameVariants << context.preciseType()->cppSignature();
+
+ const AbstractMetaClass* enclosingClass = metaClass->enclosingClass();
+ while (enclosingClass) {
+ if (enclosingClass->typeEntry()->generateCode())
+ nameVariants << (enclosingClass->name() + QLatin1String("::") + nameVariants.last());
+ enclosingClass = enclosingClass->enclosingClass();
+ }
+
+ QString className;
+ if (!context.forSmartPointer())
+ className = metaClass->qualifiedCppName();
+ else
+ className = context.preciseType()->cppSignature();
+
+ if (!metaClass->isNamespace() && !metaClass->isAbstract()) {
+ // Qt metatypes are registered only on their first use, so we do this now.
+ bool canBeValue = false;
+ if (!isObjectType(metaClass)) {
+ // check if there's a empty ctor
+ const AbstractMetaFunctionList &funcs = metaClass->functions();
+ for (AbstractMetaFunction *func : funcs) {
+ if (func->isConstructor() && !func->arguments().count()) {
+ canBeValue = true;
+ break;
+ }
+ }
+ }
+
+ if (canBeValue) {
+ for (const QString &name : qAsConst(nameVariants)) {
+ if (name == QLatin1String("iterator")) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QString::fromLatin1("%1:%2 FIXME:\n"
+ " The code tried to qRegisterMetaType the unqualified name "
+ "'iterator'. This is currently fixed by a hack(ct) and needs improvement!")
+ .arg(QFile::decodeName(__FILE__)).arg(__LINE__);
+ continue;
+ }
+ s << INDENT << "qRegisterMetaType< ::" << className << " >(\"" << name << "\");" << endl;
+ }
+ }
+ }
+
+ const AbstractMetaEnumList &enums = metaClass->enums();
+ for (AbstractMetaEnum *metaEnum : enums) {
+ if (!metaEnum->isPrivate() && !metaEnum->isAnonymous()) {
+ for (const QString &name : qAsConst(nameVariants))
+ s << INDENT << "qRegisterMetaType< ::" << metaEnum->typeEntry()->qualifiedCppName() << " >(\"" << name << "::" << metaEnum->name() << "\");" << endl;
+
+ if (metaEnum->typeEntry()->flags()) {
+ QString n = metaEnum->typeEntry()->flags()->originalName();
+ s << INDENT << "qRegisterMetaType< ::" << n << " >(\"" << n << "\");" << endl;
+ }
+ }
+ }
+}
+
+void CppGenerator::writeTypeDiscoveryFunction(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ QString polymorphicExpr = metaClass->typeEntry()->polymorphicIdValue();
+
+ s << "static void* " << cpythonBaseName(metaClass) << "_typeDiscovery(void* cptr, SbkObjectType* instanceType)\n{" << endl;
+
+ if (!polymorphicExpr.isEmpty()) {
+ polymorphicExpr = polymorphicExpr.replace(QLatin1String("%1"),
+ QLatin1String(" reinterpret_cast< ::")
+ + metaClass->qualifiedCppName()
+ + QLatin1String("*>(cptr)"));
+ s << INDENT << " if (" << polymorphicExpr << ")" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return cptr;" << endl;
+ }
+ } else if (metaClass->isPolymorphic()) {
+ const AbstractMetaClassList &ancestors = getAllAncestors(metaClass);
+ for (AbstractMetaClass *ancestor : ancestors) {
+ if (ancestor->baseClass())
+ continue;
+ if (ancestor->isPolymorphic()) {
+ s << INDENT << "if (instanceType == reinterpret_cast<SbkObjectType*>(Shiboken::SbkType< ::"
+ << ancestor->qualifiedCppName() << " >()))" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return dynamic_cast< ::" << metaClass->qualifiedCppName()
+ << "*>(reinterpret_cast< ::"<< ancestor->qualifiedCppName() << "*>(cptr));" << endl;
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << metaClass->qualifiedCppName() << " inherits from a non polymorphic type ("
+ << ancestor->qualifiedCppName() << "), type discovery based on RTTI is "
+ "impossible, write a polymorphic-id-expression for this type.";
+ }
+
+ }
+ }
+ s << INDENT << "return 0;" << endl;
+ s << "}\n\n";
+}
+
+QString CppGenerator::writeSmartPointerGetterCast() {
+ return QLatin1String("const_cast<char *>(" SMART_POINTER_GETTER ")");
+}
+
+void CppGenerator::writeSetattroFunction(QTextStream &s, GeneratorContext &context)
+{
+ const AbstractMetaClass* metaClass = context.metaClass();
+ s << "static int " << cpythonSetattroFunctionName(metaClass) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* name, PyObject* value)" << endl;
+ s << '{' << endl;
+ if (usePySideExtensions()) {
+ s << INDENT << "Shiboken::AutoDecRef pp(reinterpret_cast<PyObject*>(PySide::Property::getObject(" PYTHON_SELF_VAR ", name)));" << endl;
+ s << INDENT << "if (!pp.isNull())" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return PySide::Property::setValue(reinterpret_cast<PySideProperty*>(pp.object()), " PYTHON_SELF_VAR ", value);" << endl;
+ }
+
+ if (context.forSmartPointer()) {
+ s << INDENT << "// Try to find the 'name' attribute, by retrieving the PyObject for the corresponding C++ object held by the smart pointer." << endl;
+ s << INDENT << "PyObject *rawObj = PyObject_CallMethod(" PYTHON_SELF_VAR ", "
+ << writeSmartPointerGetterCast() << ", 0);" << endl;
+ s << INDENT << "if (rawObj) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "int hasAttribute = PyObject_HasAttr(rawObj, name);" << endl;
+ s << INDENT << "if (hasAttribute) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return PyObject_GenericSetAttr(rawObj, name, value);" << endl;
+ }
+ s << INDENT << '}' << endl;
+ s << INDENT << "Py_DECREF(rawObj);" << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ }
+
+ s << INDENT << "return PyObject_GenericSetAttr(" PYTHON_SELF_VAR ", name, value);" << endl;
+ s << '}' << endl;
+}
+
+static inline QString qObjectClassName() { return QStringLiteral("QObject"); }
+static inline QString qMetaObjectClassName() { return QStringLiteral("QMetaObject"); }
+
+void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &context)
+{
+ const AbstractMetaClass* metaClass = context.metaClass();
+ s << "static PyObject* " << cpythonGetattroFunctionName(metaClass) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* name)" << endl;
+ s << '{' << endl;
+
+ QString getattrFunc;
+ if (usePySideExtensions() && metaClass->isQObject()) {
+ AbstractMetaClass *qobjectClass = AbstractMetaClass::findClass(classes(), qObjectClassName());
+ getattrFunc = QString::fromLatin1("PySide::getMetaDataFromQObject(%1, " PYTHON_SELF_VAR ", name)")
+ .arg(cpythonWrapperCPtr(qobjectClass, QLatin1String(PYTHON_SELF_VAR)));
+ } else {
+ getattrFunc = QLatin1String("PyObject_GenericGetAttr(" PYTHON_SELF_VAR ", name)");
+ }
+
+ if (classNeedsGetattroFunction(metaClass)) {
+ s << INDENT << "if (" PYTHON_SELF_VAR ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "// Search the method in the instance dict" << endl;
+ s << INDENT << "if (reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ")->ob_dict) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyObject* meth = PyDict_GetItem(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ")->ob_dict, name);" << endl;
+ s << INDENT << "if (meth) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "Py_INCREF(meth);" << endl;
+ s << INDENT << "return meth;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ }
+ s << INDENT << '}' << endl;
+ s << INDENT << "// Search the method in the type dict" << endl;
+ s << INDENT << "if (Shiboken::Object::isUserType(" PYTHON_SELF_VAR ")) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyObject* meth = PyDict_GetItem(" PYTHON_SELF_VAR "->ob_type->tp_dict, name);" << endl;
+ s << INDENT << "if (meth)" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return PyFunction_Check(meth) ? SBK_PyMethod_New(meth, " PYTHON_SELF_VAR ") : " << getattrFunc << ';' << endl;
+ }
+ }
+ s << INDENT << '}' << endl;
+
+ const AbstractMetaFunctionList &funcs = getMethodsWithBothStaticAndNonStaticMethods(metaClass);
+ for (const AbstractMetaFunction *func : funcs) {
+ QString defName = cpythonMethodDefinitionName(func);
+ s << INDENT << "static PyMethodDef non_static_" << defName << " = {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << defName << ".ml_name," << endl;
+ s << INDENT << defName << ".ml_meth," << endl;
+ s << INDENT << defName << ".ml_flags & (~METH_STATIC)," << endl;
+ s << INDENT << defName << ".ml_doc," << endl;
+ }
+ s << INDENT << "};" << endl;
+ s << INDENT << "if (Shiboken::String::compare(name, \"" << func->name() << "\") == 0)" << endl;
+ Indentation indent(INDENT);
+ s << INDENT << "return PyCFunction_NewEx(&non_static_" << defName << ", " PYTHON_SELF_VAR ", 0);" << endl;
+ }
+ }
+ s << INDENT << '}' << endl;
+ }
+
+ if (context.forSmartPointer()) {
+ s << INDENT << "PyObject *tmp = " << getattrFunc << ';' << endl;
+ s << INDENT << "if (tmp) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return tmp;" << endl;
+ }
+ s << INDENT << "} else {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "if (!PyErr_ExceptionMatches(PyExc_AttributeError)) return NULL;" << endl;
+ s << INDENT << "PyErr_Clear();" << endl;
+
+ s << INDENT << "// Try to find the 'name' attribute, by retrieving the PyObject for "
+ "the corresponding C++ object held by the smart pointer." << endl;
+ s << INDENT << "PyObject *rawObj = PyObject_CallMethod(" PYTHON_SELF_VAR ", "
+ << writeSmartPointerGetterCast() << ", 0);" << endl;
+ s << INDENT << "if (rawObj) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyObject *attribute = PyObject_GetAttr(rawObj, name);" << endl;
+ s << INDENT << "if (attribute) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "tmp = attribute;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ s << INDENT << "Py_DECREF(rawObj);" << endl;
+ }
+ s << INDENT << '}' << endl;
+ s << INDENT << "if (!tmp) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyTypeObject *tp = Py_TYPE(self);" << endl;
+ s << INDENT << "PyErr_Format(PyExc_AttributeError," << endl;
+ s << INDENT << " \"'%.50s' object has no attribute '%.400s'\"," << endl;
+ s << INDENT << " tp->tp_name, PyBytes_AS_STRING(name));" << endl;
+ s << INDENT << "return NULL;" << endl;
+ }
+ s << INDENT << "} else {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return tmp;" << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ }
+ s << INDENT << '}' << endl;
+
+ } else {
+ s << INDENT << "return " << getattrFunc << ';' << endl;
+ }
+ s << '}' << endl;
+}
+
+bool CppGenerator::finishGeneration()
+{
+ //Generate CPython wrapper file
+ QString classInitDecl;
+ QTextStream s_classInitDecl(&classInitDecl);
+ QString classPythonDefines;
+ QTextStream s_classPythonDefines(&classPythonDefines);
+
+ QSet<Include> includes;
+ QString globalFunctionImpl;
+ QTextStream s_globalFunctionImpl(&globalFunctionImpl);
+ QString globalFunctionDecl;
+ QTextStream s_globalFunctionDef(&globalFunctionDecl);
+
+ Indentation indent(INDENT);
+
+ const FunctionGroupMap &functionGroups = getFunctionGroups();
+ for (FunctionGroupMapIt it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
+ AbstractMetaFunctionList overloads;
+ for (AbstractMetaFunction *func : it.value()) {
+ if (!func->isModifiedRemoved()) {
+ overloads.append(func);
+ if (func->typeEntry())
+ includes << func->typeEntry()->include();
+ }
+ }
+
+ if (overloads.isEmpty())
+ continue;
+
+ // Dummy context to satisfy the API.
+ GeneratorContext classContext;
+ writeMethodWrapper(s_globalFunctionImpl, overloads, classContext);
+ writeMethodDefinition(s_globalFunctionDef, overloads);
+ }
+
+ //this is a temporary solution before new type revison implementation
+ //We need move QMetaObject register before QObject
+ Dependencies additionalDependencies;
+ const AbstractMetaClassList &allClasses = classes();
+ if (AbstractMetaClass::findClass(allClasses, qObjectClassName()) != Q_NULLPTR
+ && AbstractMetaClass::findClass(allClasses, qMetaObjectClassName()) != Q_NULLPTR) {
+ Dependency dependency;
+ dependency.parent = qMetaObjectClassName();
+ dependency.child = qObjectClassName();
+ additionalDependencies.append(dependency);
+ }
+ const AbstractMetaClassList lst = classesTopologicalSorted(additionalDependencies);
+
+ for (const AbstractMetaClass *cls : lst){
+ if (!shouldGenerate(cls))
+ continue;
+
+ s_classInitDecl << "void init_" << cls->qualifiedCppName().replace(QLatin1String("::"), QLatin1String("_")) << "(PyObject* module);" << endl;
+
+ QString defineStr = QLatin1String("init_") + cls->qualifiedCppName().replace(QLatin1String("::"), QLatin1String("_"));
+
+ if (cls->enclosingClass() && (cls->enclosingClass()->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass))
+ defineStr += QLatin1Char('(') + cpythonTypeNameExt(cls->enclosingClass()->typeEntry()) + QLatin1String("->tp_dict);");
+ else
+ defineStr += QLatin1String("(module);");
+ s_classPythonDefines << INDENT << defineStr << endl;
+ }
+
+ // Initialize smart pointer types.
+ const QVector<const AbstractMetaType *> &smartPtrs = instantiatedSmartPointers();
+ for (const AbstractMetaType *metaType : smartPtrs) {
+ GeneratorContext context(0, metaType, true);
+ QString initFunctionName = getInitFunctionName(context);
+ s_classInitDecl << "void init_" << initFunctionName << "(PyObject* module);" << endl;
+ QString defineStr = QLatin1String("init_") + initFunctionName;
+ defineStr += QLatin1String("(module);");
+ s_classPythonDefines << INDENT << defineStr << endl;
+ }
+
+ QString moduleFileName(outputDirectory() + QLatin1Char('/') + subDirectoryForPackage(packageName()));
+ moduleFileName += QLatin1Char('/') + moduleName().toLower() + QLatin1String("_module_wrapper.cpp");
+
+ QFile file(moduleFileName);
+ verifyDirectoryFor(file);
+ if (!file.open(QFile::WriteOnly)) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Error writing file: " << QDir::toNativeSeparators(moduleFileName);
+ return false;
+ }
+
+ QTextStream s(&file);
+
+ // write license comment
+ s << licenseComment() << endl;
+
+ s << "#include <sbkpython.h>" << endl;
+ s << "#include <shiboken.h>" << endl;
+ s << "#include <algorithm>" << endl;
+ if (usePySideExtensions()) {
+ s << includeQDebug;
+ s << "#include <pyside.h>" << endl;
+ }
+
+ s << "#include \"" << getModuleHeaderFileName() << '"' << endl << endl;
+ for (const Include &include : qAsConst(includes))
+ s << include;
+ s << endl;
+
+ // Global enums
+ AbstractMetaEnumList globalEnums = this->globalEnums();
+ const AbstractMetaClassList &classList = classes();
+ for (const AbstractMetaClass *metaClass : classList) {
+ const AbstractMetaClass* encClass = metaClass->enclosingClass();
+ if (encClass && encClass->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass)
+ continue;
+ lookForEnumsInClassesNotToBeGenerated(globalEnums, metaClass);
+ }
+
+ TypeDatabase* typeDb = TypeDatabase::instance();
+ TypeSystemTypeEntry* moduleEntry = reinterpret_cast<TypeSystemTypeEntry*>(typeDb->findType(packageName()));
+
+ //Extra includes
+ s << endl << "// Extra includes" << endl;
+ QVector<Include> extraIncludes;
+ if (moduleEntry)
+ extraIncludes = moduleEntry->extraIncludes();
+ for (AbstractMetaEnum *cppEnum : qAsConst(globalEnums))
+ extraIncludes.append(cppEnum->typeEntry()->extraIncludes());
+ qSort(extraIncludes.begin(), extraIncludes.end());
+ for (const Include &inc : qAsConst(extraIncludes))
+ s << inc;
+ s << endl;
+
+ s << "// Current module's type array." << endl;
+ s << "PyTypeObject** " << cppApiVariableName() << ';' << endl;
+
+ s << "// Current module's converter array." << endl;
+ s << "SbkConverter** " << convertersVariableName() << ';' << endl;
+
+ CodeSnipList snips;
+ if (moduleEntry)
+ snips = moduleEntry->codeSnips();
+
+ // module inject-code native/beginning
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode);
+ s << endl;
+ }
+
+ // cleanup staticMetaObject attribute
+ if (usePySideExtensions()) {
+ s << "void cleanTypesAttributes(void) {" << endl;
+ s << INDENT << "for (int i = 0, imax = SBK_" << moduleName() << "_IDX_COUNT; i < imax; i++) {" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "PyObject *pyType = reinterpret_cast<PyObject*>(" << cppApiVariableName() << "[i]);" << endl;
+ s << INDENT << "if (pyType && PyObject_HasAttrString(pyType, \"staticMetaObject\"))"<< endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "PyObject_SetAttrString(pyType, \"staticMetaObject\", Py_None);" << endl;
+ }
+ }
+ s << INDENT << "}" << endl;
+ s << "}" << endl;
+ }
+
+ s << "// Global functions ";
+ s << "------------------------------------------------------------" << endl;
+ s << globalFunctionImpl << endl;
+
+ s << "static PyMethodDef " << moduleName() << "_methods[] = {" << endl;
+ s << globalFunctionDecl;
+ s << INDENT << "{0} // Sentinel" << endl << "};" << endl << endl;
+
+ s << "// Classes initialization functions ";
+ s << "------------------------------------------------------------" << endl;
+ s << classInitDecl << endl;
+
+ if (!globalEnums.isEmpty()) {
+ QString converterImpl;
+ QTextStream convImpl(&converterImpl);
+
+ s << "// Enum definitions ";
+ s << "------------------------------------------------------------" << endl;
+ for (const AbstractMetaEnum *cppEnum : qAsConst(globalEnums)) {
+ if (cppEnum->isAnonymous() || cppEnum->isPrivate())
+ continue;
+ writeEnumConverterFunctions(s, cppEnum);
+ s << endl;
+ }
+
+ if (!converterImpl.isEmpty()) {
+ s << "// Enum converters ";
+ s << "------------------------------------------------------------" << endl;
+ s << "namespace Shiboken" << endl << '{' << endl;
+ s << converterImpl << endl;
+ s << "} // namespace Shiboken" << endl << endl;
+ }
+ }
+
+ const QStringList &requiredModules = typeDb->requiredTargetImports();
+ if (!requiredModules.isEmpty())
+ s << "// Required modules' type and converter arrays." << endl;
+ for (const QString &requiredModule : requiredModules) {
+ s << "PyTypeObject** " << cppApiVariableName(requiredModule) << ';' << endl;
+ s << "SbkConverter** " << convertersVariableName(requiredModule) << ';' << endl;
+ }
+ s << endl;
+
+ s << "// Module initialization ";
+ s << "------------------------------------------------------------" << endl;
+ ExtendedConverterData extendedConverters = getExtendedConverters();
+ if (!extendedConverters.isEmpty()) {
+ s << endl << "// Extended Converters." << endl << endl;
+ for (ExtendedConverterData::const_iterator it = extendedConverters.cbegin(), end = extendedConverters.cend(); it != end; ++it) {
+ const TypeEntry *externalType = it.key();
+ s << "// Extended implicit conversions for " << externalType->qualifiedTargetLangName() << '.' << endl;
+ for (const AbstractMetaClass *sourceClass : it.value()) {
+ AbstractMetaType* sourceType = buildAbstractMetaTypeFromAbstractMetaClass(sourceClass);
+ AbstractMetaType* targetType = buildAbstractMetaTypeFromTypeEntry(externalType);
+ writePythonToCppConversionFunctions(s, sourceType, targetType);
+ }
+ }
+ }
+
+ const QVector<const CustomConversion *> &typeConversions = getPrimitiveCustomConversions();
+ if (!typeConversions.isEmpty()) {
+ s << endl << "// Primitive Type converters." << endl << endl;
+ for (const CustomConversion *conversion : typeConversions) {
+ s << "// C++ to Python conversion for type '" << conversion->ownerType()->qualifiedCppName() << "'." << endl;
+ writeCppToPythonFunction(s, conversion);
+ writeCustomConverterFunctions(s, conversion);
+ }
+ s << endl;
+ }
+
+ const QVector<const AbstractMetaType *> &containers = instantiatedContainers();
+ if (!containers.isEmpty()) {
+ s << "// Container Type converters." << endl << endl;
+ for (const AbstractMetaType *container : containers) {
+ s << "// C++ to Python conversion for type '" << container->cppSignature() << "'." << endl;
+ writeContainerConverterFunctions(s, container);
+ }
+ s << endl;
+ }
+
+ s << "#if defined _WIN32 || defined __CYGWIN__" << endl;
+ s << " #define SBK_EXPORT_MODULE __declspec(dllexport)" << endl;
+ s << "#elif __GNUC__ >= 4" << endl;
+ s << " #define SBK_EXPORT_MODULE __attribute__ ((visibility(\"default\")))" << endl;
+ s << "#else" << endl;
+ s << " #define SBK_EXPORT_MODULE" << endl;
+ s << "#endif" << endl << endl;
+
+ s << "#ifdef IS_PY3K" << endl;
+ s << "static struct PyModuleDef moduledef = {" << endl;
+ s << " /* m_base */ PyModuleDef_HEAD_INIT," << endl;
+ s << " /* m_name */ \"" << moduleName() << "\"," << endl;
+ s << " /* m_doc */ 0," << endl;
+ s << " /* m_size */ -1," << endl;
+ s << " /* m_methods */ " << moduleName() << "_methods," << endl;
+ s << " /* m_reload */ 0," << endl;
+ s << " /* m_traverse */ 0," << endl;
+ s << " /* m_clear */ 0," << endl;
+ s << " /* m_free */ 0" << endl;
+ s << "};" << endl << endl;
+ s << "#endif" << endl;
+ s << "SBK_MODULE_INIT_FUNCTION_BEGIN(" << moduleName() << ")" << endl;
+
+ ErrorCode errorCode(QLatin1String("SBK_MODULE_INIT_ERROR"));
+ // module inject-code target/beginning
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode);
+ s << endl;
+ }
+
+ for (const QString& requiredModule : requiredModules) {
+ s << INDENT << "{" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "Shiboken::AutoDecRef requiredModule(Shiboken::Module::import(\"" << requiredModule << "\"));" << endl;
+ s << INDENT << "if (requiredModule.isNull())" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "return SBK_MODULE_INIT_ERROR;" << endl;
+ }
+ s << INDENT << cppApiVariableName(requiredModule) << " = Shiboken::Module::getTypes(requiredModule);" << endl;
+ s << INDENT << convertersVariableName(requiredModule) << " = Shiboken::Module::getTypeConverters(requiredModule);" << endl;
+ }
+ s << INDENT << "}" << endl << endl;
+ }
+
+ int maxTypeIndex = getMaxTypeIndex() + instantiatedSmartPointers().size();
+ if (maxTypeIndex) {
+ s << INDENT << "// Create an array of wrapper types for the current module." << endl;
+ s << INDENT << "static PyTypeObject* cppApi[SBK_" << moduleName() << "_IDX_COUNT];" << endl;
+ s << INDENT << cppApiVariableName() << " = cppApi;" << endl << endl;
+ }
+
+ s << INDENT << "// Create an array of primitive type converters for the current module." << endl;
+ s << INDENT << "static SbkConverter* sbkConverters[SBK_" << moduleName() << "_CONVERTERS_IDX_COUNT" << "];" << endl;
+ s << INDENT << convertersVariableName() << " = sbkConverters;" << endl << endl;
+
+ s << "#ifdef IS_PY3K" << endl;
+ s << INDENT << "PyObject* module = Shiboken::Module::create(\"" << moduleName() << "\", &moduledef);" << endl;
+ s << "#else" << endl;
+ s << INDENT << "PyObject* module = Shiboken::Module::create(\"" << moduleName() << "\", ";
+ s << moduleName() << "_methods);" << endl;
+ s << "#endif" << endl << endl;
+
+ //s << INDENT << "// Initialize converters for primitive types." << endl;
+ //s << INDENT << "initConverters();" << endl << endl;
+
+ s << INDENT << "// Initialize classes in the type system" << endl;
+ s << classPythonDefines;
+
+ if (!typeConversions.isEmpty()) {
+ s << endl;
+ for (const CustomConversion *conversion : typeConversions) {
+ writePrimitiveConverterInitialization(s, conversion);
+ s << endl;
+ }
+ }
+
+ if (!containers.isEmpty()) {
+ s << endl;
+ for (const AbstractMetaType *container : containers) {
+ writeContainerConverterInitialization(s, container);
+ s << endl;
+ }
+ }
+
+ if (!extendedConverters.isEmpty()) {
+ s << endl;
+ for (ExtendedConverterData::const_iterator it = extendedConverters.cbegin(), end = extendedConverters.cend(); it != end; ++it) {
+ writeExtendedConverterInitialization(s, it.key(), it.value());
+ s << endl;
+ }
+ }
+
+ writeEnumsInitialization(s, globalEnums);
+
+ s << INDENT << "// Register primitive types converters." << endl;
+ const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes();
+ for (const PrimitiveTypeEntry *pte : primitiveTypeList) {
+ if (!pte->generateCode() || !pte->isCppPrimitive())
+ continue;
+ const TypeEntry *referencedType = pte->basicReferencedTypeEntry();
+ if (!referencedType)
+ continue;
+ QString converter = converterObject(referencedType);
+ QStringList cppSignature = pte->qualifiedCppName().split(QLatin1String("::"), QString::SkipEmptyParts);
+ while (!cppSignature.isEmpty()) {
+ QString signature = cppSignature.join(QLatin1String("::"));
+ s << INDENT << "Shiboken::Conversions::registerConverterName(" << converter << ", \"" << signature << "\");" << endl;
+ cppSignature.removeFirst();
+ }
+ }
+ // Register type resolver for all containers found in signals.
+ QSet<QByteArray> typeResolvers;
+
+ for (AbstractMetaClass *metaClass : classList) {
+ if (!metaClass->isQObject() || !metaClass->typeEntry()->generateCode())
+ continue;
+ const AbstractMetaFunctionList &functions = metaClass->functions();
+ for (AbstractMetaFunction *func : functions) {
+ if (func->isSignal()) {
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (AbstractMetaArgument *arg : arguments) {
+ if (arg->type()->isContainer()) {
+ QString value = translateType(arg->type(), metaClass, ExcludeConst | ExcludeReference);
+ if (value.startsWith(QLatin1String("::")))
+ value.remove(0, 2);
+ typeResolvers << QMetaObject::normalizedType(value.toUtf8().constData());
+ }
+ }
+ }
+ }
+ }
+
+ s << endl;
+ if (maxTypeIndex)
+ s << INDENT << "Shiboken::Module::registerTypes(module, " << cppApiVariableName() << ");" << endl;
+ s << INDENT << "Shiboken::Module::registerTypeConverters(module, " << convertersVariableName() << ");" << endl;
+
+ s << endl << INDENT << "if (PyErr_Occurred()) {" << endl;
+ {
+ Indentation indentation(INDENT);
+ s << INDENT << "PyErr_Print();" << endl;
+ s << INDENT << "Py_FatalError(\"can't initialize module " << moduleName() << "\");" << endl;
+ }
+ s << INDENT << '}' << endl;
+
+ // module inject-code target/end
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode);
+ s << endl;
+ }
+
+ // module inject-code native/end
+ if (!snips.isEmpty()) {
+ writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode);
+ s << endl;
+ }
+
+ if (usePySideExtensions()) {
+ for (AbstractMetaEnum *metaEnum : qAsConst(globalEnums))
+ if (!metaEnum->isAnonymous()) {
+ s << INDENT << "qRegisterMetaType< ::" << metaEnum->typeEntry()->qualifiedCppName() << " >(\"" << metaEnum->name() << "\");" << endl;
+ }
+
+ // cleanup staticMetaObject attribute
+ s << INDENT << "PySide::registerCleanupFunction(cleanTypesAttributes);" << endl;
+ }
+
+ s << "SBK_MODULE_INIT_FUNCTION_END" << endl;
+
+ return true;
+}
+
+static ArgumentOwner getArgumentOwner(const AbstractMetaFunction* func, int argIndex)
+{
+ ArgumentOwner argOwner = func->argumentOwner(func->ownerClass(), argIndex);
+ if (argOwner.index == ArgumentOwner::InvalidIndex)
+ argOwner = func->argumentOwner(func->declaringClass(), argIndex);
+ return argOwner;
+}
+
+bool CppGenerator::writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, int argIndex, bool useHeuristicPolicy)
+{
+ const int numArgs = func->arguments().count();
+ bool ctorHeuristicEnabled = func->isConstructor() && useCtorHeuristic() && useHeuristicPolicy;
+
+ bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(OverloadData(getFunctionGroups(func->implementingClass())[func->name()], this));
+
+ ArgumentOwner argOwner = getArgumentOwner(func, argIndex);
+ ArgumentOwner::Action action = argOwner.action;
+ int parentIndex = argOwner.index;
+ int childIndex = argIndex;
+ if (ctorHeuristicEnabled && argIndex > 0 && numArgs) {
+ AbstractMetaArgument* arg = func->arguments().at(argIndex-1);
+ if (arg->name() == QLatin1String("parent") && isObjectType(arg->type())) {
+ action = ArgumentOwner::Add;
+ parentIndex = argIndex;
+ childIndex = -1;
+ }
+ }
+
+ QString parentVariable;
+ QString childVariable;
+ if (action != ArgumentOwner::Invalid) {
+ if (!usePyArgs && argIndex > 1)
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Argument index for parent tag out of bounds: " << func->signature();
+
+ if (action == ArgumentOwner::Remove) {
+ parentVariable = QLatin1String("Py_None");
+ } else {
+ if (parentIndex == 0) {
+ parentVariable = QLatin1String(PYTHON_RETURN_VAR);
+ } else if (parentIndex == -1) {
+ parentVariable = QLatin1String(PYTHON_SELF_VAR);
+ } else {
+ parentVariable = usePyArgs
+ ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(parentIndex - 1)
+ : QLatin1String(PYTHON_ARG);
+ }
+ }
+
+ if (childIndex == 0) {
+ childVariable = QLatin1String(PYTHON_RETURN_VAR);
+ } else if (childIndex == -1) {
+ childVariable = QLatin1String(PYTHON_SELF_VAR);
+ } else {
+ childVariable = usePyArgs
+ ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(childIndex - 1)
+ : QLatin1String(PYTHON_ARG);
+ }
+
+ s << INDENT << "Shiboken::Object::setParent(" << parentVariable << ", " << childVariable << ");\n";
+ return true;
+ }
+
+ return false;
+}
+
+void CppGenerator::writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, bool useHeuristicForReturn)
+{
+ const int numArgs = func->arguments().count();
+
+ // -1 = return value
+ // 0 = self
+ // 1..n = func. args.
+ for (int i = -1; i <= numArgs; ++i)
+ writeParentChildManagement(s, func, i, useHeuristicForReturn);
+
+ if (useHeuristicForReturn)
+ writeReturnValueHeuristics(s, func);
+}
+
+void CppGenerator::writeReturnValueHeuristics(QTextStream& s, const AbstractMetaFunction* func, const QString& self)
+{
+ AbstractMetaType *type = func->type();
+ if (!useReturnValueHeuristic()
+ || !func->ownerClass()
+ || !type
+ || func->isStatic()
+ || func->isConstructor()
+ || !func->typeReplaced(0).isEmpty()) {
+ return;
+ }
+
+ ArgumentOwner argOwner = getArgumentOwner(func, ArgumentOwner::ReturnIndex);
+ if (argOwner.action == ArgumentOwner::Invalid || argOwner.index != ArgumentOwner::ThisIndex) {
+ if (isPointerToWrapperType(type))
+ s << INDENT << "Shiboken::Object::setParent(" << self << ", " PYTHON_RETURN_VAR ");" << endl;
+ }
+}
+
+void CppGenerator::writeHashFunction(QTextStream &s, GeneratorContext &context)
+{
+ const AbstractMetaClass *metaClass = context.metaClass();
+ s << "static Py_hash_t " << cpythonBaseName(metaClass) << "_HashFunc(PyObject* self) {" << endl;
+ writeCppSelfDefinition(s, context);
+ s << INDENT << "return " << metaClass->typeEntry()->hashFunction() << '(';
+ s << (isObjectType(metaClass) ? "" : "*") << CPP_SELF_VAR << ");" << endl;
+ s << '}' << endl << endl;
+}
+
+void CppGenerator::writeStdListWrapperMethods(QTextStream &s, GeneratorContext &context)
+{
+ const AbstractMetaClass *metaClass = context.metaClass();
+ ErrorCode errorCode(0);
+
+ // __len__
+ s << "Py_ssize_t " << cpythonBaseName(metaClass->typeEntry()) << "__len__(PyObject* " PYTHON_SELF_VAR ")" << endl;
+ s << '{' << endl;
+ writeCppSelfDefinition(s, context);
+ s << INDENT << "return " CPP_SELF_VAR "->size();" << endl;
+ s << '}' << endl;
+
+ // __getitem__
+ s << "PyObject* " << cpythonBaseName(metaClass->typeEntry()) << "__getitem__(PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i)" << endl;
+ s << '{' << endl;
+ writeCppSelfDefinition(s, context);
+ writeIndexError(s, QLatin1String("index out of bounds"));
+
+ s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = " CPP_SELF_VAR "->begin();" << endl;
+ s << INDENT << "for (Py_ssize_t pos = 0; pos < _i; pos++) _item++;" << endl;
+
+ const AbstractMetaType* itemType = metaClass->templateBaseClassInstantiations().first();
+
+ s << INDENT << "return ";
+ writeToPythonConversion(s, itemType, metaClass, QLatin1String("*_item"));
+ s << ';' << endl;
+ s << '}' << endl;
+
+ // __setitem__
+ ErrorCode errorCode2(-1);
+ s << "int " << cpythonBaseName(metaClass->typeEntry()) << "__setitem__(PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i, PyObject* pyArg)" << endl;
+ s << '{' << endl;
+ writeCppSelfDefinition(s, context);
+ writeIndexError(s, QLatin1String("list assignment index out of range"));
+
+ s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ';' << endl;
+ s << INDENT << "if (!";
+ writeTypeCheck(s, itemType, QLatin1String("pyArg"), isNumber(itemType->typeEntry()));
+ s << ") {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_TypeError, \"attributed value with wrong type, '";
+ s << itemType->name() << "' or other convertible type expected\");" << endl;
+ s << INDENT << "return -1;" << endl;
+ }
+ s << INDENT << '}' << endl;
+ writeArgumentConversion(s, itemType, QLatin1String("cppValue"), QLatin1String("pyArg"), metaClass);
+
+ s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = " CPP_SELF_VAR "->begin();" << endl;
+ s << INDENT << "for (Py_ssize_t pos = 0; pos < _i; pos++) _item++;" << endl;
+ s << INDENT << "*_item = cppValue;" << endl;
+ s << INDENT << "return 0;" << endl;
+ s << '}' << endl;
+}
+void CppGenerator::writeIndexError(QTextStream& s, const QString& errorMsg)
+{
+ s << INDENT << "if (_i < 0 || _i >= (Py_ssize_t) " CPP_SELF_VAR "->size()) {" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "PyErr_SetString(PyExc_IndexError, \"" << errorMsg << "\");" << endl;
+ s << INDENT << "return " << m_currentErrorCode << ';' << endl;
+ }
+ s << INDENT << '}' << endl;
+}
+
+QString CppGenerator::writeReprFunction(QTextStream &s, GeneratorContext &context)
+{
+ const AbstractMetaClass *metaClass = context.metaClass();
+ QString funcName = cpythonBaseName(metaClass) + QLatin1String("__repr__");
+ s << "extern \"C\"" << endl;
+ s << '{' << endl;
+ s << "static PyObject* " << funcName << "(PyObject* self)" << endl;
+ s << '{' << endl;
+ writeCppSelfDefinition(s, context);
+ s << INDENT << "QBuffer buffer;" << endl;
+ s << INDENT << "buffer.open(QBuffer::ReadWrite);" << endl;
+ s << INDENT << "QDebug dbg(&buffer);" << endl;
+ s << INDENT << "dbg << " << (metaClass->typeEntry()->isValue() ? "*" : "") << CPP_SELF_VAR ";" << endl;
+ s << INDENT << "buffer.close();" << endl;
+ s << INDENT << "QByteArray str = buffer.data();" << endl;
+ s << INDENT << "int idx = str.indexOf('(');" << endl;
+ s << INDENT << "if (idx >= 0)" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "str.replace(0, idx, Py_TYPE(self)->tp_name);" << endl;
+ }
+ s << INDENT << "PyObject* mod = PyDict_GetItemString(Py_TYPE(self)->tp_dict, \"__module__\");" << endl;
+ s << INDENT << "if (mod)" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return Shiboken::String::fromFormat(\"<%s.%s at %p>\", Shiboken::String::toCString(mod), str.constData(), self);" << endl;
+ }
+ s << INDENT << "else" << endl;
+ {
+ Indentation indent(INDENT);
+ s << INDENT << "return Shiboken::String::fromFormat(\"<%s at %p>\", str.constData(), self);" << endl;
+ }
+ s << '}' << endl;
+ s << "} // extern C" << endl << endl;;
+ return funcName;
+}
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h
new file mode 100644
index 000000000..c3ca48307
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.h
@@ -0,0 +1,370 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CPPGENERATOR_H
+#define CPPGENERATOR_H
+
+#include "shibokengenerator.h"
+
+/**
+ * The CppGenerator generate the implementations of C++ bindings classes.
+ */
+class CppGenerator : public ShibokenGenerator
+{
+public:
+ CppGenerator();
+protected:
+ QString fileNamePrefix() const override;
+ QString fileNameForContext(GeneratorContext &context) const override;
+ QVector<AbstractMetaFunctionList> filterGroupedOperatorFunctions(const AbstractMetaClass* metaClass,
+ uint query);
+ void generateClass(QTextStream& s, GeneratorContext &classContext) override;
+ bool finishGeneration() override;
+
+private:
+ void writeConstructorNative(QTextStream& s, const AbstractMetaFunction* func);
+ void writeDestructorNative(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ QString getVirtualFunctionReturnTypeName(const AbstractMetaFunction* func);
+ void writeVirtualMethodNative(QTextStream& s, const AbstractMetaFunction* func);
+
+ void writeMetaObjectMethod(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeMetaCast(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeEnumConverterFunctions(QTextStream& s, const TypeEntry* enumType);
+ void writeEnumConverterFunctions(QTextStream& s, const AbstractMetaEnum* metaEnum);
+ void writeConverterFunctions(QTextStream &s, const AbstractMetaClass *metaClass,
+ GeneratorContext &classContext);
+ void writeCustomConverterFunctions(QTextStream& s, const CustomConversion* customConversion);
+ void writeConverterRegister(QTextStream &s, const AbstractMetaClass *metaClass,
+ GeneratorContext &classContext);
+ void writeCustomConverterRegister(QTextStream& s, const CustomConversion* customConversion, const QString& converterVar);
+ void writeContainerConverterRegister(QTextStream& s, const AbstractMetaType* container, const QString& converterVar);
+
+ void writeContainerConverterFunctions(QTextStream& s, const AbstractMetaType* containerType);
+
+ void writeMethodWrapperPreamble(QTextStream &s, OverloadData &overloadData,
+ GeneratorContext &context);
+ void writeConstructorWrapper(QTextStream &s, const AbstractMetaFunctionList overloads, GeneratorContext &classContext);
+ void writeDestructorWrapper(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeMethodWrapper(QTextStream &s, const AbstractMetaFunctionList overloads,
+ GeneratorContext &classContext);
+ void writeArgumentsInitializer(QTextStream& s, OverloadData& overloadData);
+ void writeCppSelfDefinition(QTextStream &s,
+ const AbstractMetaFunction *func,
+ GeneratorContext &context,
+ bool hasStaticOverload = false);
+ void writeCppSelfDefinition(QTextStream &s,
+ GeneratorContext &context,
+ bool hasStaticOverload = false,
+ bool cppSelfAsReference = false);
+
+ void writeErrorSection(QTextStream& s, OverloadData& overloadData);
+ void writeFunctionReturnErrorCheckSection(QTextStream& s, bool hasReturnValue = true);
+
+ /// Writes the check section for the validity of wrapped C++ objects.
+ void writeInvalidPyObjectCheck(QTextStream& s, const QString& pyObj);
+
+ void writeTypeCheck(QTextStream& s, const AbstractMetaType* argType, QString argumentName, bool isNumber = false, QString customType = QString(), bool rejectNull = false);
+ void writeTypeCheck(QTextStream& s, const OverloadData* overloadData, QString argumentName);
+
+ void writeTypeDiscoveryFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeSetattroFunction(QTextStream &s, GeneratorContext &context);
+ void writeGetattroFunction(QTextStream &s, GeneratorContext &context);
+ QString writeSmartPointerGetterCast();
+
+ /**
+ * Writes Python to C++ conversions for arguments on Python wrappers.
+ * If implicit conversions, and thus new object allocation, are needed,
+ * code to deallocate a possible new instance is also generated.
+ * \param s text stream to write
+ * \param argType a pointer to the argument type to be converted
+ * \param argName C++ argument name
+ * \param pyArgName Python argument name
+ * \param context the current meta class
+ * \param defaultValue an optional default value to be used instead of the conversion result
+ * \param castArgumentAsUnused if true the converted argument is cast as unused to avoid compiler warnings
+ */
+ void writeArgumentConversion(QTextStream& s, const AbstractMetaType* argType,
+ const QString& argName, const QString& pyArgName,
+ const AbstractMetaClass* context = 0,
+ const QString& defaultValue = QString(),
+ bool castArgumentAsUnused = false);
+
+ /**
+ * Returns the AbstractMetaType for a function argument.
+ * If the argument type was modified in the type system, this method will
+ * try to build a new type based on the type name defined in the type system.
+ * \param func The function which owns the argument.
+ * \param argPos Argument position in the function signature.
+ * Note that the position 0 represents the return value, and the function
+ * parameters start counting on 1.
+ * \param newType It is set to true if the type returned is a new object that must be deallocated.
+ * \return The type of the argument indicated by \p argPos.
+ */
+ const AbstractMetaType* getArgumentType(const AbstractMetaFunction* func, int argPos);
+
+ void writePythonToCppTypeConversion(QTextStream& s,
+ const AbstractMetaType* type,
+ const QString& pyIn,
+ const QString& cppOut,
+ const AbstractMetaClass* context = 0,
+ const QString& defaultValue = QString());
+
+ /// Writes the conversion rule for arguments of regular and virtual methods.
+ void writeConversionRule(QTextStream& s, const AbstractMetaFunction* func, TypeSystem::Language language);
+ /// Writes the conversion rule for the return value of a method.
+ void writeConversionRule(QTextStream& s, const AbstractMetaFunction* func, TypeSystem::Language language, const QString& outputVar);
+
+ /**
+ * Set the Python method wrapper return value variable to Py_None if
+ * there are return types different from void in any of the other overloads
+ * for the function passed as parameter.
+ * \param s text stream to write
+ * \param func a pointer to the function that will possibly return Py_None
+ * \param thereIsReturnValue indicates if the return type of any of the other overloads
+ * for this function is different from 'void'
+ */
+ void writeNoneReturn(QTextStream& s, const AbstractMetaFunction* func, bool thereIsReturnValue);
+
+ /**
+ * Writes the Python function wrapper overload decisor that selects which C++
+ * method/function to call with the received Python arguments.
+ * \param s text stream to write
+ * \param overloadData the overload data describing all the possible overloads for the function/method
+ */
+ void writeOverloadedFunctionDecisor(QTextStream& s, const OverloadData& overloadData);
+ /// Recursive auxiliar method to the other writeOverloadedFunctionDecisor.
+ void writeOverloadedFunctionDecisorEngine(QTextStream& s, const OverloadData* parentOverloadData);
+
+ /// Writes calls to all the possible method/function overloads.
+ void writeFunctionCalls(QTextStream &s,
+ const OverloadData &overloadData,
+ GeneratorContext &context);
+
+ /// Writes the call to a single function usually from a collection of overloads.
+ void writeSingleFunctionCall(QTextStream &s,
+ const OverloadData &overloadData,
+ const AbstractMetaFunction *func,
+ GeneratorContext &context);
+
+ /// Returns the name of a C++ to Python conversion function.
+ static QString cppToPythonFunctionName(const QString& sourceTypeName, QString targetTypeName = QString());
+
+ /// Returns the name of a Python to C++ conversion function.
+ static QString pythonToCppFunctionName(const QString& sourceTypeName, const QString& targetTypeName);
+ static QString pythonToCppFunctionName(const AbstractMetaType* sourceType, const AbstractMetaType* targetType);
+ static QString pythonToCppFunctionName(const CustomConversion::TargetToNativeConversion* toNative, const TypeEntry* targetType);
+
+ /// Returns the name of a Python to C++ convertible check function.
+ static QString convertibleToCppFunctionName(const QString& sourceTypeName, const QString& targetTypeName);
+ static QString convertibleToCppFunctionName(const AbstractMetaType* sourceType, const AbstractMetaType* targetType);
+ static QString convertibleToCppFunctionName(const CustomConversion::TargetToNativeConversion* toNative, const TypeEntry* targetType);
+
+ /// Writes a C++ to Python conversion function.
+ void writeCppToPythonFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, QString targetTypeName = QString());
+ void writeCppToPythonFunction(QTextStream& s, const CustomConversion* customConversion);
+ void writeCppToPythonFunction(QTextStream& s, const AbstractMetaType* containerType);
+
+ /// Writes a Python to C++ conversion function.
+ void writePythonToCppFunction(QTextStream& s, const QString& code, const QString& sourceTypeName, const QString& targetTypeName);
+
+ /// Writes a Python to C++ convertible check function.
+ void writeIsPythonConvertibleToCppFunction(QTextStream& s,
+ const QString& sourceTypeName,
+ const QString& targetTypeName,
+ const QString& condition,
+ QString pythonToCppFuncName = QString(),
+ bool acceptNoneAsCppNull = false);
+
+ /// Writes a pair of Python to C++ conversion and check functions.
+ void writePythonToCppConversionFunctions(QTextStream& s,
+ const AbstractMetaType* sourceType,
+ const AbstractMetaType* targetType,
+ QString typeCheck = QString(),
+ QString conversion = QString(),
+ QString preConversion = QString());
+ /// Writes a pair of Python to C++ conversion and check functions for implicit conversions.
+ void writePythonToCppConversionFunctions(QTextStream& s,
+ const CustomConversion::TargetToNativeConversion* toNative,
+ const TypeEntry* targetType);
+
+ /// Writes a pair of Python to C++ conversion and check functions for instantiated container types.
+ void writePythonToCppConversionFunctions(QTextStream& s, const AbstractMetaType* containerType);
+
+ void writeAddPythonToCppConversion(QTextStream& s, const QString& converterVar, const QString& pythonToCppFunc, const QString& isConvertibleFunc);
+
+ void writeNamedArgumentResolution(QTextStream& s, const AbstractMetaFunction* func, bool usePyArgs);
+
+ /// Returns a string containing the name of an argument for the given function and argument index.
+ QString argumentNameFromIndex(const AbstractMetaFunction* func, int argIndex, const AbstractMetaClass** wrappedClass);
+ void writeMethodCall(QTextStream &s, const AbstractMetaFunction *func,
+ GeneratorContext &context, int maxArgs = 0);
+
+ QString getInitFunctionName(GeneratorContext &context) const;
+
+ void writeClassRegister(QTextStream &s,
+ const AbstractMetaClass *metaClass,
+ GeneratorContext &classContext);
+ void writeClassDefinition(QTextStream &s,
+ const AbstractMetaClass *metaClass,
+ GeneratorContext &classContext);
+ void writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList overloads);
+ void writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads);
+
+ /// Writes the implementation of all methods part of python sequence protocol
+ void writeSequenceMethods(QTextStream &s,
+ const AbstractMetaClass *metaClass,
+ GeneratorContext &context);
+ void writeTypeAsSequenceDefinition(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ /// Writes the PyMappingMethods structure for types that supports the python mapping protocol.
+ void writeTypeAsMappingDefinition(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeMappingMethods(QTextStream &s,
+ const AbstractMetaClass *metaClass,
+ GeneratorContext &context);
+
+ void writeTypeAsNumberDefinition(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeTpTraverseFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeTpClearFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeCopyFunction(QTextStream &s, GeneratorContext &context);
+
+ void writeGetterFunction(QTextStream &s,
+ const AbstractMetaField *metaField,
+ GeneratorContext &context);
+ void writeSetterFunction(QTextStream &s,
+ const AbstractMetaField *metaField,
+ GeneratorContext &context);
+
+ void writeRichCompareFunction(QTextStream &s, GeneratorContext &context);
+ void writeToPythonFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeEnumsInitialization(QTextStream& s, AbstractMetaEnumList& enums);
+ void writeEnumInitialization(QTextStream& s, const AbstractMetaEnum* metaEnum);
+
+ void writeSignalInitialization(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writeFlagsMethods(QTextStream& s, const AbstractMetaEnum* cppEnum);
+ void writeFlagsToLong(QTextStream& s, const AbstractMetaEnum* cppEnum);
+ void writeFlagsNonZero(QTextStream& s, const AbstractMetaEnum* cppEnum);
+ void writeFlagsNumberMethodsDefinition(QTextStream& s, const AbstractMetaEnum* cppEnum);
+ void writeFlagsBinaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
+ QString pyOpName, QString cppOpName);
+ void writeFlagsUnaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum,
+ QString pyOpName, QString cppOpName, bool boolResult = false);
+
+ /// Writes the function that registers the multiple inheritance information for the classes that need it.
+ void writeMultipleInheritanceInitializerFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+ /// Writes the implementation of special cast functions, used when we need to cast a class with multiple inheritance.
+ void writeSpecialCastFunction(QTextStream& s, const AbstractMetaClass* metaClass);
+
+ void writePrimitiveConverterInitialization(QTextStream& s, const CustomConversion* customConversion);
+ void writeEnumConverterInitialization(QTextStream& s, const TypeEntry* enumType);
+ void writeEnumConverterInitialization(QTextStream& s, const AbstractMetaEnum* metaEnum);
+ void writeContainerConverterInitialization(QTextStream& s, const AbstractMetaType* type);
+ void writeExtendedConverterInitialization(QTextStream& s, const TypeEntry* externalType, const QVector<const AbstractMetaClass*>& conversions);
+
+ void writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, bool userHeuristicForReturn);
+ bool writeParentChildManagement(QTextStream& s, const AbstractMetaFunction* func, int argIndex, bool userHeuristicPolicy);
+ void writeReturnValueHeuristics(QTextStream& s, const AbstractMetaFunction* func, const QString& self = QLatin1String(PYTHON_SELF_VAR));
+ void writeInitQtMetaTypeFunctionBody(QTextStream &s, GeneratorContext &context) const;
+
+ /**
+ * Returns the multiple inheritance initializer function for the given class.
+ * \param metaClass the class for whom the function name must be generated.
+ * \return name of the multiple inheritance information initializer function or
+ * an empty string if there is no multiple inheritance in its ancestry.
+ */
+ QString multipleInheritanceInitializerFunctionName(const AbstractMetaClass* metaClass);
+
+ /// Returns a list of all classes to which the given class could be cast.
+ QStringList getAncestorMultipleInheritance(const AbstractMetaClass* metaClass);
+
+ /// Returns true if the given class supports the python number protocol
+ bool supportsNumberProtocol(const AbstractMetaClass* metaClass);
+
+ /// Returns true if the given class supports the python sequence protocol
+ bool supportsSequenceProtocol(const AbstractMetaClass* metaClass);
+
+ /// Returns true if the given class supports the python mapping protocol
+ bool supportsMappingProtocol(const AbstractMetaClass* metaClass);
+
+ /// Returns true if generator should produce getters and setters for the given class.
+ bool shouldGenerateGetSetList(const AbstractMetaClass* metaClass);
+
+ void writeHashFunction(QTextStream &s, GeneratorContext &context);
+
+ /// Write default implementations for sequence protocol
+ void writeStdListWrapperMethods(QTextStream &s, GeneratorContext &context);
+ /// Helper function for writeStdListWrapperMethods.
+ void writeIndexError(QTextStream& s, const QString& errorMsg);
+
+ QString writeReprFunction(QTextStream &s, GeneratorContext &context);
+
+ bool hasBoolCast(const AbstractMetaClass* metaClass) const;
+
+ // Number protocol structure members names.
+ static QHash<QString, QString> m_nbFuncs;
+
+ // Maps special function names to function parameters and return types
+ // used by CPython API in the sequence protocol.
+ QHash<QString, QPair<QString, QString> > m_sequenceProtocol;
+ // Sequence protocol structure members names.
+ static QHash<QString, QString> m_sqFuncs;
+
+ // Maps special function names to function parameters and return types
+ // used by CPython API in the mapping protocol.
+ QHash<QString, QPair<QString, QString> > m_mappingProtocol;
+ // Mapping protocol structure members names.
+ static QHash<QString, QString> m_mpFuncs;
+
+ static QString m_currentErrorCode;
+
+ /// Helper class to set and restore the current error code.
+ class ErrorCode {
+ public:
+ explicit ErrorCode(QString errorCode) {
+ m_savedErrorCode = CppGenerator::m_currentErrorCode;
+ CppGenerator::m_currentErrorCode = errorCode;
+ }
+ explicit ErrorCode(int errorCode) {
+ m_savedErrorCode = CppGenerator::m_currentErrorCode;
+ CppGenerator::m_currentErrorCode = QString::number(errorCode);
+ }
+ ~ErrorCode() {
+ CppGenerator::m_currentErrorCode = m_savedErrorCode;
+ }
+ private:
+ QString m_savedErrorCode;
+ };
+};
+
+#endif // CPPGENERATOR_H
diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.cpp b/sources/shiboken2/generator/shiboken2/headergenerator.cpp
new file mode 100644
index 000000000..6b8185dc9
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/headergenerator.cpp
@@ -0,0 +1,569 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "headergenerator.h"
+#include <abstractmetalang.h>
+#include <typedatabase.h>
+#include <reporthandler.h>
+#include <fileout.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QTextStream>
+#include <QtCore/QVariant>
+#include <QtCore/QDebug>
+
+QString HeaderGenerator::fileNamePrefix() const
+{
+ return QLatin1String("_wrapper.h");
+}
+
+QString HeaderGenerator::fileNameForContext(GeneratorContext &context) const
+{
+ const AbstractMetaClass *metaClass = context.metaClass();
+ if (!context.forSmartPointer()) {
+ QString fileNameBase = metaClass->qualifiedCppName().toLower();
+ fileNameBase.replace(QLatin1String("::"), QLatin1String("_"));
+ return fileNameBase + fileNamePrefix();
+ } else {
+ const AbstractMetaType *smartPointerType = context.preciseType();
+ QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass);
+ return fileNameBase + fileNamePrefix();
+ }
+}
+
+void HeaderGenerator::writeCopyCtor(QTextStream& s, const AbstractMetaClass* metaClass) const
+{
+ s << INDENT << wrapperName(metaClass) << "(const " << metaClass->qualifiedCppName() << "& self)";
+ s << " : " << metaClass->qualifiedCppName() << "(self)" << endl;
+ s << INDENT << "{" << endl;
+ s << INDENT << "}" << endl << endl;
+}
+
+void HeaderGenerator::writeProtectedFieldAccessors(QTextStream& s, const AbstractMetaField* field) const
+{
+ AbstractMetaType *metaType = field->type();
+ QString fieldType = metaType->cppSignature();
+ QString fieldName = field->enclosingClass()->qualifiedCppName() + QLatin1String("::") + field->name();
+
+ // Force use of pointer to return internal variable memory
+ bool useReference = (!metaType->isConstant() &&
+ !metaType->isEnum() &&
+ !metaType->isPrimitive() &&
+ metaType->indirections() == 0);
+
+
+ // Get function
+ s << INDENT << "inline " << fieldType
+ << (useReference ? '*' : ' ')
+ << ' ' << protectedFieldGetterName(field) << "()"
+ << " { return "
+ << (useReference ? '&' : ' ') << "this->" << fieldName << "; }" << endl;
+
+ // Set function
+ s << INDENT << "inline void " << protectedFieldSetterName(field) << '(' << fieldType << " value)"
+ << " { " << fieldName << " = value; }" << endl;
+}
+
+void HeaderGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
+{
+ AbstractMetaClass *metaClass = classContext.metaClass();
+ if (ReportHandler::isDebug(ReportHandler::SparseDebug))
+ qCDebug(lcShiboken) << "Generating header for " << metaClass->fullName();
+ m_inheritedOverloads.clear();
+ Indentation indent(INDENT);
+
+ // write license comment
+ s << licenseComment();
+
+ QString wrapperName;
+ if (!classContext.forSmartPointer()) {
+ wrapperName = HeaderGenerator::wrapperName(metaClass);
+ } else {
+ wrapperName = HeaderGenerator::wrapperName(classContext.preciseType());
+ }
+ QString headerGuard = getFilteredCppSignatureString(wrapperName).toUpper();
+
+ // Header
+ s << "#ifndef SBK_" << headerGuard << "_H" << endl;
+ s << "#define SBK_" << headerGuard << "_H" << endl<< endl;
+
+ if (!avoidProtectedHack())
+ s << "#define protected public" << endl << endl;
+
+ s << "#include <shiboken.h>" << endl << endl;
+
+ //Includes
+ s << metaClass->typeEntry()->include() << endl;
+
+ if (shouldGenerateCppWrapper(metaClass)) {
+
+ if (usePySideExtensions() && metaClass->isQObject())
+ s << "namespace PySide { class DynamicQMetaObject; }\n\n";
+
+ // Class
+ s << "class " << wrapperName;
+ s << " : public " << metaClass->qualifiedCppName();
+
+ s << endl << '{' << endl << "public:" << endl;
+
+ bool hasVirtualFunction = false;
+ const AbstractMetaFunctionList &funcs = filterFunctions(metaClass);
+ for (AbstractMetaFunction *func : funcs) {
+ if (func->isVirtual())
+ hasVirtualFunction = true;
+ writeFunction(s, func);
+ }
+
+ if (avoidProtectedHack() && metaClass->hasProtectedFields()) {
+ const AbstractMetaFieldList &fields = metaClass->fields();
+ for (AbstractMetaField *field : fields) {
+ if (!field->isProtected())
+ continue;
+ writeProtectedFieldAccessors(s, field);
+ }
+ }
+
+ //destructor
+ // PYSIDE-504: When C++ 11 is used, then the destructor must always be written.
+ // See generator.h for further reference.
+ if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor() || alwaysGenerateDestructor) {
+ s << INDENT;
+ if (avoidProtectedHack() && metaClass->hasPrivateDestructor())
+ s << "// C++11: need to declare (unimplemented) destructor because "
+ "the base class destructor is private." << endl;
+ if (metaClass->hasVirtualDestructor() || hasVirtualFunction)
+ s << "virtual ";
+ s << '~' << wrapperName << "();" << endl;
+ }
+
+ writeCodeSnips(s, metaClass->typeEntry()->codeSnips(), TypeSystem::CodeSnipPositionDeclaration, TypeSystem::NativeCode);
+
+ if ((!avoidProtectedHack() || !metaClass->hasPrivateDestructor())
+ && usePySideExtensions() && metaClass->isQObject()) {
+ s << "public:\n";
+ s << INDENT << "virtual int qt_metacall(QMetaObject::Call call, int id, void** args);" << endl;
+ s << INDENT << "virtual void* qt_metacast(const char* _clname);" << endl;
+ }
+
+ if (m_inheritedOverloads.size()) {
+ s << INDENT << "// Inherited overloads, because the using keyword sux" << endl;
+ writeInheritedOverloads(s);
+ }
+
+ if (usePySideExtensions())
+ s << INDENT << "static void pysideInitQtMetaTypes();" << endl;
+
+ s << "};" << endl << endl;
+ }
+
+ s << "#endif // SBK_" << headerGuard << "_H" << endl << endl;
+}
+
+void HeaderGenerator::writeFunction(QTextStream& s, const AbstractMetaFunction* func)
+{
+
+ // do not write copy ctors here.
+ if (!func->isPrivate() && func->functionType() == AbstractMetaFunction::CopyConstructorFunction) {
+ writeCopyCtor(s, func->ownerClass());
+ return;
+ }
+ if (func->isUserAdded())
+ return;
+
+ if (avoidProtectedHack() && func->isProtected() && !func->isConstructor() && !func->isOperatorOverload()) {
+ s << INDENT << "inline " << (func->isStatic() ? "static " : "");
+ s << functionSignature(func, QString(), QLatin1String("_protected"), Generator::EnumAsInts|Generator::OriginalTypeDescription)
+ << " { ";
+ s << (func->type() ? "return " : "");
+ if (!func->isAbstract())
+ s << func->ownerClass()->qualifiedCppName() << "::";
+ s << func->originalName() << '(';
+ QStringList args;
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument *arg : arguments) {
+ QString argName = arg->name();
+ const TypeEntry* enumTypeEntry = 0;
+ if (arg->type()->isFlags())
+ enumTypeEntry = reinterpret_cast<const FlagsTypeEntry*>(arg->type()->typeEntry())->originator();
+ else if (arg->type()->isEnum())
+ enumTypeEntry = arg->type()->typeEntry();
+ if (enumTypeEntry)
+ argName = QString::fromLatin1("%1(%2)").arg(arg->type()->cppSignature(), argName);
+ args << argName;
+ }
+ s << args.join(QLatin1String(", ")) << ')';
+ s << "; }" << endl;
+ }
+
+ // pure virtual functions need a default implementation
+ if ((func->isPrivate() && !visibilityModifiedToPrivate(func))
+ || (func->isModifiedRemoved() && !func->isAbstract()))
+ return;
+
+ if (avoidProtectedHack() && func->ownerClass()->hasPrivateDestructor()
+ && (func->isAbstract() || func->isVirtual()))
+ return;
+
+ if (func->isConstructor() || func->isAbstract() || func->isVirtual()) {
+ s << INDENT;
+ Options virtualOption = Generator::OriginalTypeDescription;
+
+ if (func->isVirtual() || func->isAbstract())
+ s << "virtual ";
+ else if (!func->hasSignatureModifications())
+ virtualOption = Generator::NoOption;
+
+ s << functionSignature(func, QString(), QString(), virtualOption) << ';' << endl;
+
+ // Check if this method hide other methods in base classes
+ const AbstractMetaFunctionList &ownerFuncs = func->ownerClass()->functions();
+ for (const AbstractMetaFunction *f : ownerFuncs) {
+ if (f != func
+ && !f->isConstructor()
+ && !f->isPrivate()
+ && !f->isVirtual()
+ && !f->isAbstract()
+ && !f->isStatic()
+ && f->name() == func->name()) {
+ m_inheritedOverloads << f;
+ }
+ }
+
+ // TODO: when modified an abstract method ceases to be virtual but stays abstract
+ //if (func->isModifiedRemoved() && func->isAbstract()) {
+ //}
+ }
+}
+
+static void _writeTypeIndexDefineLine(QTextStream& s, const QString& variableName, int typeIndex)
+{
+ s << "#define ";
+ s.setFieldWidth(60);
+ s << variableName;
+ s.setFieldWidth(0);
+ s << ' ' << typeIndex << endl;
+}
+void HeaderGenerator::writeTypeIndexDefineLine(QTextStream& s, const TypeEntry* typeEntry)
+{
+ if (!typeEntry || !typeEntry->generateCode())
+ return;
+ s.setFieldAlignment(QTextStream::AlignLeft);
+ int typeIndex = getTypeIndex(typeEntry);
+ _writeTypeIndexDefineLine(s, getTypeIndexVariableName(typeEntry), typeIndex);
+ if (typeEntry->isComplex()) {
+ const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(typeEntry);
+ if (cType->baseContainerType()) {
+ const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes(), cType);
+ if (metaClass->templateBaseClass())
+ _writeTypeIndexDefineLine(s, getTypeIndexVariableName(metaClass, true), typeIndex);
+ }
+ }
+ if (typeEntry->isEnum()) {
+ const EnumTypeEntry* ete = reinterpret_cast<const EnumTypeEntry*>(typeEntry);
+ if (ete->flags())
+ writeTypeIndexDefineLine(s, ete->flags());
+ }
+}
+
+void HeaderGenerator::writeTypeIndexDefine(QTextStream& s, const AbstractMetaClass* metaClass)
+{
+ if (!metaClass->typeEntry()->generateCode())
+ return;
+ writeTypeIndexDefineLine(s, metaClass->typeEntry());
+ const AbstractMetaEnumList &enums = metaClass->enums();
+ for (const AbstractMetaEnum *metaEnum : enums) {
+ if (metaEnum->isPrivate())
+ continue;
+ writeTypeIndexDefineLine(s, metaEnum->typeEntry());
+ }
+}
+
+bool HeaderGenerator::finishGeneration()
+{
+ // Generate the main header for this module.
+ // This header should be included by binding modules
+ // extendind on top of this one.
+ QSet<Include> includes;
+ QString macros;
+ QTextStream macrosStream(&macros);
+ QString sbkTypeFunctions;
+ QTextStream typeFunctions(&sbkTypeFunctions);
+ QString protectedEnumSurrogates;
+ QTextStream protEnumsSurrogates(&protectedEnumSurrogates);
+
+ Indentation indent(INDENT);
+
+ macrosStream << "// Type indices" << endl;
+ AbstractMetaEnumList globalEnums = this->globalEnums();
+ const AbstractMetaClassList &classList = classes();
+ for (const AbstractMetaClass *metaClass : classList) {
+ writeTypeIndexDefine(macrosStream, metaClass);
+ lookForEnumsInClassesNotToBeGenerated(globalEnums, metaClass);
+ }
+
+ for (const AbstractMetaEnum *metaEnum : qAsConst(globalEnums))
+ writeTypeIndexDefineLine(macrosStream, metaEnum->typeEntry());
+
+ // Write the smart pointer define indexes.
+ int smartPointerCountIndex = getMaxTypeIndex();
+ int smartPointerCount = 0;
+ const QVector<const AbstractMetaType *> &instantiatedSmartPtrs = instantiatedSmartPointers();
+ for (const AbstractMetaType *metaType : instantiatedSmartPtrs) {
+ QString variableName = getTypeIndexVariableName(metaType);
+ macrosStream << "#define ";
+ macrosStream.setFieldWidth(60);
+ macrosStream << variableName;
+ macrosStream.setFieldWidth(0);
+ macrosStream << ' ' << smartPointerCountIndex << " // " << metaType->cppSignature()
+ << endl;
+ ++smartPointerCountIndex;
+ ++smartPointerCount;
+ }
+
+
+ macrosStream << "#define ";
+ macrosStream.setFieldWidth(60);
+ macrosStream << QLatin1String("SBK_") + moduleName() + QLatin1String("_IDX_COUNT");
+ macrosStream.setFieldWidth(0);
+ macrosStream << ' ' << getMaxTypeIndex() + smartPointerCount << endl << endl;
+ macrosStream << "// This variable stores all Python types exported by this module." << endl;
+ macrosStream << "extern PyTypeObject** " << cppApiVariableName() << ';' << endl << endl;
+ macrosStream << "// This variable stores all type converters exported by this module." << endl;
+ macrosStream << "extern SbkConverter** " << convertersVariableName() << ';' << endl << endl;
+
+ // TODO-CONVERTER ------------------------------------------------------------------------------
+ // Using a counter would not do, a fix must be made to APIExtractor's getTypeIndex().
+ macrosStream << "// Converter indices" << endl;
+ 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;
+
+ _writeTypeIndexDefineLine(macrosStream, getTypeIndexVariableName(ptype), pCount++);
+ }
+
+ const QVector<const AbstractMetaType *> &containers = instantiatedContainers();
+ for (const AbstractMetaType *container : containers) {
+ //_writeTypeIndexDefineLine(macrosStream, getTypeIndexVariableName(container), pCount);
+ // DEBUG
+ QString variableName = getTypeIndexVariableName(container);
+ macrosStream << "#define ";
+ macrosStream.setFieldWidth(60);
+ macrosStream << variableName;
+ macrosStream.setFieldWidth(0);
+ macrosStream << ' ' << pCount << " // " << container->cppSignature() << endl;
+ // DEBUG
+ pCount++;
+ }
+
+ // Because on win32 the compiler will not accept a zero length array.
+ if (pCount == 0)
+ pCount++;
+ _writeTypeIndexDefineLine(macrosStream, QStringLiteral("SBK_%1_CONVERTERS_IDX_COUNT").arg(moduleName()), pCount);
+ macrosStream << endl;
+ // TODO-CONVERTER ------------------------------------------------------------------------------
+
+ macrosStream << "// Macros for type check" << endl;
+ for (const AbstractMetaEnum *cppEnum : globalEnums) {
+ if (cppEnum->isAnonymous() || cppEnum->isPrivate())
+ continue;
+ includes << cppEnum->typeEntry()->include();
+ writeProtectedEnumSurrogate(protEnumsSurrogates, cppEnum);
+ writeSbkTypeFunction(typeFunctions, cppEnum);
+ }
+
+ for (AbstractMetaClass *metaClass : classList) {
+ if (!shouldGenerate(metaClass))
+ continue;
+
+ //Includes
+ const TypeEntry* classType = metaClass->typeEntry();
+ includes << classType->include();
+
+ const AbstractMetaEnumList &enums = metaClass->enums();
+ for (const AbstractMetaEnum *cppEnum : enums) {
+ if (cppEnum->isAnonymous() || cppEnum->isPrivate())
+ continue;
+ EnumTypeEntry* enumType = cppEnum->typeEntry();
+ includes << enumType->include();
+ writeProtectedEnumSurrogate(protEnumsSurrogates, cppEnum);
+ writeSbkTypeFunction(typeFunctions, cppEnum);
+ }
+
+ if (!metaClass->isNamespace())
+ writeSbkTypeFunction(typeFunctions, metaClass);
+ }
+
+ for (const AbstractMetaType *metaType : instantiatedSmartPtrs) {
+ const TypeEntry *classType = metaType->typeEntry();
+ includes << classType->include();
+ writeSbkTypeFunction(typeFunctions, metaType);
+ }
+
+ QString moduleHeaderFileName(outputDirectory()
+ + QDir::separator() + subDirectoryForPackage(packageName())
+ + QDir::separator() + getModuleHeaderFileName());
+
+ QString includeShield(QLatin1String("SBK_") + moduleName().toUpper() + QLatin1String("_PYTHON_H"));
+
+ FileOut file(moduleHeaderFileName);
+ QTextStream& s = file.stream;
+ // write license comment
+ s << licenseComment() << endl << endl;
+
+ s << "#ifndef " << includeShield << endl;
+ s << "#define " << includeShield << endl<< endl;
+ if (!avoidProtectedHack()) {
+ s << "//workaround to access protected functions" << endl;
+ s << "#define protected public" << endl << endl;
+ }
+
+ s << "#include <sbkpython.h>" << endl;
+ s << "#include <conversions.h>" << endl;
+ s << "#include <sbkenum.h>" << endl;
+ s << "#include <basewrapper.h>" << endl;
+ s << "#include <bindingmanager.h>" << endl;
+ s << "#include <memory>" << endl << endl;
+ if (usePySideExtensions())
+ s << "#include <pysidesignal.h>" << endl;
+
+ QStringList requiredTargetImports = TypeDatabase::instance()->requiredTargetImports();
+ if (!requiredTargetImports.isEmpty()) {
+ s << "// Module Includes" << endl;
+ for (const QString &requiredModule : qAsConst(requiredTargetImports))
+ s << "#include <" << getModuleHeaderFileName(requiredModule) << ">" << endl;
+ s << endl;
+ }
+
+ s << "// Binded library includes" << endl;
+ for (const Include &include : qAsConst(includes))
+ s << include;
+
+ if (!primitiveTypes().isEmpty()) {
+ s << "// Conversion Includes - Primitive Types" << endl;
+ const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes();
+ for (const PrimitiveTypeEntry *ptype : primitiveTypeList)
+ s << ptype->include();
+ s << endl;
+ }
+
+ if (!containerTypes().isEmpty()) {
+ s << "// Conversion Includes - Container Types" << endl;
+ const ContainerTypeEntryList &containerTypeList = containerTypes();
+ for (const ContainerTypeEntry *ctype : containerTypeList)
+ s << ctype->include();
+ s << endl;
+ }
+
+ s << macros << endl;
+
+ if (!protectedEnumSurrogates.isEmpty()) {
+ s << "// Protected enum surrogates" << endl;
+ s << protectedEnumSurrogates << endl;
+ }
+
+ s << "namespace Shiboken" << endl << '{' << endl << endl;
+
+ s << "// PyType functions, to get the PyObjectType for a type T\n";
+ s << sbkTypeFunctions << endl;
+
+ s << "} // namespace Shiboken" << endl << endl;
+
+ s << "#endif // " << includeShield << endl << endl;
+
+ return file.done() != FileOut::Failure;
+}
+
+void HeaderGenerator::writeProtectedEnumSurrogate(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ if (avoidProtectedHack() && cppEnum->isProtected())
+ s << "enum " << protectedEnumSurrogateName(cppEnum) << " {};" << endl;
+}
+
+void HeaderGenerator::writeSbkTypeFunction(QTextStream& s, const AbstractMetaEnum* cppEnum)
+{
+ QString enumName;
+ if (avoidProtectedHack() && cppEnum->isProtected()) {
+ enumName = protectedEnumSurrogateName(cppEnum);
+ } else {
+ enumName = cppEnum->name();
+ if (cppEnum->enclosingClass())
+ enumName = cppEnum->enclosingClass()->qualifiedCppName() + QLatin1String("::") + enumName;
+ }
+
+ s << "template<> inline PyTypeObject* SbkType< ::" << enumName << " >() ";
+ s << "{ return " << cpythonTypeNameExt(cppEnum->typeEntry()) << "; }\n";
+
+ FlagsTypeEntry* flag = cppEnum->typeEntry()->flags();
+ if (flag) {
+ s << "template<> inline PyTypeObject* SbkType< ::" << flag->name() << " >() "
+ << "{ return " << cpythonTypeNameExt(flag) << "; }\n";
+ }
+}
+
+void HeaderGenerator::writeSbkTypeFunction(QTextStream& s, const AbstractMetaClass* cppClass)
+{
+ s << "template<> inline PyTypeObject* SbkType< ::" << cppClass->qualifiedCppName() << " >() "
+ << "{ return reinterpret_cast<PyTypeObject*>(" << cpythonTypeNameExt(cppClass->typeEntry()) << "); }\n";
+}
+
+void HeaderGenerator::writeSbkTypeFunction(QTextStream &s, const AbstractMetaType *metaType)
+{
+ s << "template<> inline PyTypeObject* SbkType< ::" << metaType->cppSignature() << " >() "
+ << "{ return reinterpret_cast<PyTypeObject*>(" << cpythonTypeNameExt(metaType) << "); }\n";
+}
+
+void HeaderGenerator::writeInheritedOverloads(QTextStream& s)
+{
+ for (const AbstractMetaFunction *func : qAsConst(m_inheritedOverloads)) {
+ s << INDENT << "inline ";
+ s << functionSignature(func, QString(), QString(), Generator::EnumAsInts|Generator::OriginalTypeDescription) << " { ";
+ s << (func->type() ? "return " : "");
+ s << func->ownerClass()->qualifiedCppName() << "::" << func->originalName() << '(';
+ QStringList args;
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument *arg : arguments) {
+ QString argName = arg->name();
+ const TypeEntry* enumTypeEntry = 0;
+ if (arg->type()->isFlags())
+ enumTypeEntry = reinterpret_cast<const FlagsTypeEntry*>(arg->type()->typeEntry())->originator();
+ else if (arg->type()->isEnum())
+ enumTypeEntry = arg->type()->typeEntry();
+ if (enumTypeEntry)
+ argName = arg->type()->cppSignature() + QLatin1Char('(') + argName + QLatin1Char(')');
+ args << argName;
+ }
+ s << args.join(QLatin1String(", ")) << ')';
+ s << "; }" << endl;
+ }
+}
diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.h b/sources/shiboken2/generator/shiboken2/headergenerator.h
new file mode 100644
index 000000000..5c1ffec35
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/headergenerator.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef HEADERGENERATOR_H
+#define HEADERGENERATOR_H
+
+#include "shibokengenerator.h"
+
+#include <QtCore/QSet>
+
+class AbstractMetaFunction;
+
+/**
+ * The HeaderGenerator generate the declarations of C++ bindings classes.
+ */
+class HeaderGenerator : public ShibokenGenerator
+{
+public:
+ QMap<QString, QString> options() const override { return QMap<QString, QString>(); }
+protected:
+ QString fileNamePrefix() const override;
+ QString fileNameForContext(GeneratorContext &context) const override;
+ void generateClass(QTextStream& s, GeneratorContext &classContext) override;
+ bool finishGeneration() override;
+
+private:
+ void writeCopyCtor(QTextStream &s, const AbstractMetaClass* metaClass) const;
+ void writeProtectedFieldAccessors(QTextStream& s, const AbstractMetaField* field) const;
+ void writeFunction(QTextStream& s, const AbstractMetaFunction* func);
+ void writeSbkTypeFunction(QTextStream& s, const AbstractMetaEnum* cppEnum);
+ void writeSbkTypeFunction(QTextStream& s, const AbstractMetaClass* cppClass);
+ void writeSbkTypeFunction(QTextStream &s, const AbstractMetaType *metaType);
+ void writeTypeIndexDefineLine(QTextStream& s, const TypeEntry* typeEntry);
+ void writeTypeIndexDefine(QTextStream& s, const AbstractMetaClass* metaClass);
+ void writeProtectedEnumSurrogate(QTextStream& s, const AbstractMetaEnum* cppEnum);
+ void writeInheritedOverloads(QTextStream& s);
+
+ QSet<const AbstractMetaFunction*> m_inheritedOverloads;
+};
+
+#endif // HEADERGENERATOR_H
+
diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.cpp b/sources/shiboken2/generator/shiboken2/overloaddata.cpp
new file mode 100644
index 000000000..876185cbe
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/overloaddata.cpp
@@ -0,0 +1,1092 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <abstractmetalang.h>
+#include <reporthandler.h>
+#include <graph.h>
+#include "overloaddata.h"
+#include "shibokengenerator.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QTemporaryFile>
+
+static const TypeEntry *getReferencedTypeEntry(const TypeEntry *typeEntry)
+{
+ if (typeEntry->isPrimitive()) {
+ const PrimitiveTypeEntry* pte = dynamic_cast<const PrimitiveTypeEntry*>(typeEntry);
+ while (pte->referencedTypeEntry())
+ pte = pte->referencedTypeEntry();
+ typeEntry = pte;
+ }
+ return typeEntry;
+}
+
+static QString getTypeName(const AbstractMetaType* type)
+{
+ const TypeEntry* typeEntry = getReferencedTypeEntry(type->typeEntry());
+ QString typeName = typeEntry->name();
+ if (typeEntry->isContainer()) {
+ QStringList types;
+ const AbstractMetaTypeList &instantiations = type->instantiations();
+ for (const AbstractMetaType *cType : instantiations) {
+ const TypeEntry *typeEntry = getReferencedTypeEntry(cType->typeEntry());
+ types << typeEntry->name();
+ }
+ typeName += QLatin1Char('<') + types.join(QLatin1Char(',')) + QLatin1String(" >");
+ }
+ return typeName;
+}
+
+static QString getTypeName(const OverloadData* ov)
+{
+ return ov->hasArgumentTypeReplace() ? ov->argumentTypeReplaced() : getTypeName(ov->argType());
+}
+
+static bool typesAreEqual(const AbstractMetaType* typeA, const AbstractMetaType* typeB)
+{
+ if (typeA->typeEntry() == typeB->typeEntry()) {
+ if (typeA->isContainer() || typeA->isSmartPointer()) {
+ if (typeA->instantiations().size() != typeB->instantiations().size())
+ return false;
+
+ for (int i = 0; i < typeA->instantiations().size(); ++i) {
+ if (!typesAreEqual(typeA->instantiations().at(i), typeB->instantiations().at(i)))
+ return false;
+ }
+ return true;
+ }
+
+ return !(ShibokenGenerator::isCString(typeA) ^ ShibokenGenerator::isCString(typeB));
+ }
+ return false;
+}
+
+
+/**
+ * OverloadSortData just helps writing clearer code in the
+ * OverloadData::sortNextOverloads method.
+ */
+struct OverloadSortData
+{
+ OverloadSortData() : counter(0) {};
+
+ /**
+ * Adds a typeName into the type map without associating it with
+ * a OverloadData. This is done to express type dependencies that could
+ * or could not appear in overloaded signatures not processed yet.
+ */
+ void mapType(const QString& typeName)
+ {
+ if (map.contains(typeName))
+ return;
+ map[typeName] = counter;
+ if (!reverseMap.contains(counter))
+ reverseMap[counter] = 0;
+ counter++;
+ }
+
+ void mapType(OverloadData* overloadData)
+ {
+ QString typeName = getTypeName(overloadData);
+ map[typeName] = counter;
+ reverseMap[counter] = overloadData;
+ counter++;
+ }
+
+ int lastProcessedItemId() { return counter - 1; }
+
+ int counter;
+ QHash<QString, int> map; // typeName -> id
+ QHash<int, OverloadData*> reverseMap; // id -> OverloadData;
+};
+
+/**
+ * Helper function that returns the name of a container get from containerType argument and
+ * an instantiation taken either from an implicit conversion expressed by the function argument,
+ * or from the string argument implicitConvTypeName.
+ */
+static QString getImplicitConversionTypeName(const AbstractMetaType* containerType,
+ const AbstractMetaType* instantiation,
+ const AbstractMetaFunction* function,
+ const QString& implicitConvTypeName = QString())
+{
+ QString impConv;
+ if (!implicitConvTypeName.isEmpty())
+ impConv = implicitConvTypeName;
+ else if (function->isConversionOperator())
+ impConv = function->ownerClass()->typeEntry()->name();
+ else
+ impConv = getTypeName(function->arguments().first()->type());
+
+ QStringList types;
+ const AbstractMetaTypeList &instantiations = containerType->instantiations();
+ for (const AbstractMetaType *otherType : instantiations)
+ types << (otherType == instantiation ? impConv : getTypeName(otherType));
+
+ const ContainerTypeEntry* containerTypeEntry = dynamic_cast<const ContainerTypeEntry*>(containerType->typeEntry());
+ return containerTypeEntry->qualifiedCppName() + QLatin1Char('<')
+ + types.join(QLatin1String(", ")) + QLatin1String(" >");
+}
+
+static QString msgCyclicDependency(const QString &funcName, const QString &graphName,
+ const OverloadData::MetaFunctionList &involvedConversions)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Cyclic dependency found on overloaddata for \"" << funcName
+ << "\" method! The graph boy saved the graph at \"" << QDir::toNativeSeparators(graphName)
+ << "\".";
+ if (const int count = involvedConversions.size()) {
+ str << " Implicit conversions (" << count << "): ";
+ for (int i = 0; i < count; ++i) {
+ if (i)
+ str << ", \"";
+ str << involvedConversions.at(i)->signature() << '"';
+ if (const AbstractMetaClass *c = involvedConversions.at(i)->implementingClass())
+ str << '(' << c->name() << ')';
+ }
+ }
+ return result;
+}
+
+/**
+ * Topologically sort the overloads by implicit convertion order
+ *
+ * This avoids using an implicit conversion if there's an explicit
+ * overload for the convertible type. So, if there's an implicit convert
+ * like TargetType(ConvertibleType foo) and both are in the overload list,
+ * ConvertibleType is checked before TargetType.
+ *
+ * Side effects: Modifies m_nextOverloadData
+ */
+void OverloadData::sortNextOverloads()
+{
+ OverloadSortData sortData;
+ bool checkPyObject = false;
+ int pyobjectIndex = 0;
+ bool checkPySequence = false;
+ int pySeqIndex = 0;
+ bool checkQString = false;
+ int qstringIndex = 0;
+ bool checkQVariant = false;
+ int qvariantIndex = 0;
+ bool checkPyBuffer = false;
+ int pyBufferIndex = 0;
+
+ // Primitive types that are not int, long, short,
+ // char and their respective unsigned counterparts.
+ QStringList nonIntegerPrimitives;
+ nonIntegerPrimitives << QLatin1String("float") << QLatin1String("double")
+ << QLatin1String("bool");
+
+ // Signed integer primitive types.
+ QStringList signedIntegerPrimitives;
+ signedIntegerPrimitives << QLatin1String("int") << QLatin1String("short")
+ << QLatin1String("long");
+
+ // sort the children overloads
+ for (OverloadData *ov : m_nextOverloadData)
+ ov->sortNextOverloads();
+
+ if (m_nextOverloadData.size() <= 1)
+ return;
+
+ // Populates the OverloadSortData object containing map and reverseMap, to map type names to ids,
+ // these ids will be used by the topological sort algorithm, because is easier and faster to work
+ // with graph sorting using integers.
+ for (OverloadData *ov : m_nextOverloadData) {
+ sortData.mapType(ov);
+
+ const QString typeName(getTypeName(ov));
+
+ if (!checkPyObject && typeName.contains(QLatin1String("PyObject"))) {
+ checkPyObject = true;
+ pyobjectIndex = sortData.lastProcessedItemId();
+ } else if (!checkPySequence && typeName == QLatin1String("PySequence")) {
+ checkPySequence = true;
+ pySeqIndex = sortData.lastProcessedItemId();
+ } else if (!checkPyBuffer && typeName == QLatin1String("PyBuffer")) {
+ checkPyBuffer = true;
+ pyBufferIndex = sortData.lastProcessedItemId();
+ } else if (!checkQVariant && typeName == QLatin1String("QVariant")) {
+ checkQVariant = true;
+ qvariantIndex = sortData.lastProcessedItemId();
+ } else if (!checkQString && typeName == QLatin1String("QString")) {
+ checkQString = true;
+ qstringIndex = sortData.lastProcessedItemId();
+ }
+
+ const AbstractMetaTypeList &instantiations = ov->argType()->instantiations();
+ for (const AbstractMetaType *instantiation : instantiations) {
+ // Add dependencies for type instantiation of container.
+ QString typeName = getTypeName(instantiation);
+ sortData.mapType(typeName);
+
+ // Build dependency for implicit conversion types instantiations for base container.
+ // For example, considering signatures "method(list<PointF>)" and "method(list<Point>)",
+ // and being PointF implicitly convertible from Point, an list<T> instantiation with T
+ // as Point must come before the PointF instantiation, or else list<Point> will never
+ // be called. In the case of primitive types, list<double> must come before list<int>.
+ if (instantiation->isPrimitive() && (signedIntegerPrimitives.contains(instantiation->name()))) {
+ for (const QString &primitive : qAsConst(nonIntegerPrimitives))
+ sortData.mapType(getImplicitConversionTypeName(ov->argType(), instantiation, 0, primitive));
+ } else {
+ const AbstractMetaFunctionList &funcs = m_generator->implicitConversions(instantiation);
+ for (const AbstractMetaFunction *function : funcs)
+ sortData.mapType(getImplicitConversionTypeName(ov->argType(), instantiation, function));
+ }
+ }
+ }
+
+
+ // Create the graph of type dependencies based on implicit conversions.
+ Graph graph(sortData.reverseMap.count());
+ // All C++ primitive types, add any forgotten type AT THE END OF THIS LIST!
+ const char* primitiveTypes[] = {"int",
+ "unsigned int",
+ "long",
+ "unsigned long",
+ "short",
+ "unsigned short",
+ "bool",
+ "unsigned char",
+ "char",
+ "float",
+ "double",
+ "const char*"
+ };
+ const int numPrimitives = sizeof(primitiveTypes)/sizeof(const char*);
+ bool hasPrimitive[numPrimitives];
+ for (int i = 0; i < numPrimitives; ++i)
+ hasPrimitive[i] = sortData.map.contains(QLatin1String(primitiveTypes[i]));
+
+ if (checkPySequence && checkPyObject)
+ graph.addEdge(pySeqIndex, pyobjectIndex);
+
+ QStringList classesWithIntegerImplicitConversion;
+
+ MetaFunctionList involvedConversions;
+
+ for (OverloadData *ov : m_nextOverloadData) {
+ const AbstractMetaType* targetType = ov->argType();
+ const QString targetTypeEntryName(getTypeName(ov));
+ int targetTypeId = sortData.map[targetTypeEntryName];
+
+ // Process implicit conversions
+ const AbstractMetaFunctionList &functions = m_generator->implicitConversions(targetType);
+ for (AbstractMetaFunction *function : functions) {
+ QString convertibleType;
+ if (function->isConversionOperator())
+ convertibleType = function->ownerClass()->typeEntry()->name();
+ else
+ convertibleType = getTypeName(function->arguments().first()->type());
+
+ if (convertibleType == QLatin1String("int") || convertibleType == QLatin1String("unsigned int"))
+ classesWithIntegerImplicitConversion << targetTypeEntryName;
+
+ if (!sortData.map.contains(convertibleType))
+ continue;
+
+ int convertibleTypeId = sortData.map[convertibleType];
+
+ // If a reverse pair already exists, remove it. Probably due to the
+ // container check (This happened to QVariant and QHash)
+ graph.removeEdge(targetTypeId, convertibleTypeId);
+ graph.addEdge(convertibleTypeId, targetTypeId);
+ involvedConversions.append(function);
+ }
+
+ // Process inheritance relationships
+ if (targetType->isValue() || targetType->isObject()) {
+ const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_generator->classes(), targetType->typeEntry());
+ const AbstractMetaClassList &ancestors = m_generator->getAllAncestors(metaClass);
+ for (const AbstractMetaClass *ancestor : ancestors) {
+ QString ancestorTypeName = ancestor->typeEntry()->name();
+ if (!sortData.map.contains(ancestorTypeName))
+ continue;
+ int ancestorTypeId = sortData.map[ancestorTypeName];
+ graph.removeEdge(ancestorTypeId, targetTypeId);
+ graph.addEdge(targetTypeId, ancestorTypeId);
+ }
+ }
+
+ // Process template instantiations
+ const AbstractMetaTypeList &instantiations = targetType->instantiations();
+ for (const AbstractMetaType *instantiation : instantiations) {
+ if (sortData.map.contains(getTypeName(instantiation))) {
+ int convertible = sortData.map[getTypeName(instantiation)];
+
+ if (!graph.containsEdge(targetTypeId, convertible)) // Avoid cyclic dependency.
+ graph.addEdge(convertible, targetTypeId);
+
+ if (instantiation->isPrimitive() && (signedIntegerPrimitives.contains(instantiation->name()))) {
+ for (const QString &primitive : qAsConst(nonIntegerPrimitives)) {
+ QString convertibleTypeName = getImplicitConversionTypeName(ov->argType(), instantiation, 0, primitive);
+ if (!graph.containsEdge(targetTypeId, sortData.map[convertibleTypeName])) // Avoid cyclic dependency.
+ graph.addEdge(sortData.map[convertibleTypeName], targetTypeId);
+ }
+
+ } else {
+ const AbstractMetaFunctionList &funcs = m_generator->implicitConversions(instantiation);
+ for (const AbstractMetaFunction *function : funcs) {
+ QString convertibleTypeName = getImplicitConversionTypeName(ov->argType(), instantiation, function);
+ if (!graph.containsEdge(targetTypeId, sortData.map[convertibleTypeName])) { // Avoid cyclic dependency.
+ graph.addEdge(sortData.map[convertibleTypeName], targetTypeId);
+ involvedConversions.append(function);
+ }
+ }
+ }
+ }
+ }
+
+
+ if ((checkPySequence || checkPyObject || checkPyBuffer)
+ && !targetTypeEntryName.contains(QLatin1String("PyObject"))
+ && !targetTypeEntryName.contains(QLatin1String("PyBuffer"))
+ && !targetTypeEntryName.contains(QLatin1String("PySequence"))) {
+ if (checkPySequence) {
+ // PySequence will be checked after all more specific types, but before PyObject.
+ graph.addEdge(targetTypeId, pySeqIndex);
+ } else if (checkPyBuffer) {
+ // PySequence will be checked after all more specific types, but before PyObject.
+ graph.addEdge(targetTypeId, pyBufferIndex);
+ } else {
+ // Add dependency on PyObject, so its check is the last one (too generic).
+ graph.addEdge(targetTypeId, pyobjectIndex);
+ }
+ } else if (checkQVariant && targetTypeEntryName != QLatin1String("QVariant")) {
+ if (!graph.containsEdge(qvariantIndex, targetTypeId)) // Avoid cyclic dependency.
+ graph.addEdge(targetTypeId, qvariantIndex);
+ } else if (checkQString && ShibokenGenerator::isPointer(ov->argType())
+ && targetTypeEntryName != QLatin1String("QString")
+ && targetTypeEntryName != QLatin1String("QByteArray")
+ && (!checkPyObject || targetTypeId != pyobjectIndex)) {
+ if (!graph.containsEdge(qstringIndex, targetTypeId)) // Avoid cyclic dependency.
+ graph.addEdge(targetTypeId, qstringIndex);
+ }
+
+ if (targetType->isEnum()) {
+ // Enum values must precede primitive types.
+ for (int i = 0; i < numPrimitives; ++i) {
+ if (hasPrimitive[i])
+ graph.addEdge(targetTypeId, sortData.map[QLatin1String(primitiveTypes[i])]);
+ }
+ }
+ }
+
+ // QByteArray args need to be checked after QString args
+ if (sortData.map.contains(QLatin1String("QString")) && sortData.map.contains(QLatin1String("QByteArray")))
+ graph.addEdge(sortData.map[QLatin1String("QString")], sortData.map[QLatin1String("QByteArray")]);
+
+ for (OverloadData *ov : m_nextOverloadData) {
+ const AbstractMetaType* targetType = ov->argType();
+ if (!targetType->isEnum())
+ continue;
+
+ QString targetTypeEntryName = getTypeName(targetType);
+ // Enum values must precede types implicitly convertible from "int" or "unsigned int".
+ for (const QString &implicitFromInt : qAsConst(classesWithIntegerImplicitConversion))
+ graph.addEdge(sortData.map[targetTypeEntryName], sortData.map[implicitFromInt]);
+ }
+
+
+ // Special case for double(int i) (not tracked by m_generator->implicitConversions
+ for (const QString &signedIntegerName : qAsConst(signedIntegerPrimitives)) {
+ if (sortData.map.contains(signedIntegerName)) {
+ for (const QString &nonIntegerName : qAsConst(nonIntegerPrimitives)) {
+ if (sortData.map.contains(nonIntegerName))
+ graph.addEdge(sortData.map[nonIntegerName], sortData.map[signedIntegerName]);
+ }
+ }
+ }
+
+ // sort the overloads topologically based on the dependency graph.
+ const QLinkedList<int> unmappedResult = graph.topologicalSort();
+ if (unmappedResult.isEmpty()) {
+ QString funcName = referenceFunction()->name();
+ if (referenceFunction()->ownerClass())
+ funcName.prepend(referenceFunction()->ownerClass()->name() + QLatin1Char('.'));
+
+ // Dump overload graph
+ QString graphName = QDir::tempPath() + QLatin1Char('/') + funcName + QLatin1String(".dot");
+ QHash<QString, int>::const_iterator it = sortData.map.begin();
+ QHash<int, QString> nodeNames;
+ for (; it != sortData.map.end(); ++it)
+ nodeNames.insert(it.value(), it.key());
+ graph.dumpDot(nodeNames, graphName);
+ qCWarning(lcShiboken).noquote() << qPrintable(msgCyclicDependency(funcName, graphName, involvedConversions));
+ }
+
+ m_nextOverloadData.clear();
+ for (int i : unmappedResult) {
+ if (!sortData.reverseMap[i])
+ continue;
+ m_nextOverloadData << sortData.reverseMap[i];
+ }
+}
+
+/**
+ * Root constructor for OverloadData
+ *
+ * This constructor receives the list of overloads for a given function and iterates generating
+ * the graph of OverloadData instances. Each OverloadData instance references an argument/type
+ * combination.
+ *
+ * Example:
+ * addStuff(double, PyObject *)
+ * addStuff(double, int)
+ *
+ * Given these two overloads, there will be the following graph:
+ *
+ * addStuff - double - PyObject*
+ * \- int
+ *
+ */
+OverloadData::OverloadData(const AbstractMetaFunctionList& overloads, const ShibokenGenerator* generator)
+ : m_minArgs(256), m_maxArgs(0), m_argPos(-1), m_argType(0),
+ m_headOverloadData(this), m_previousOverloadData(0), m_generator(generator)
+{
+ for (const AbstractMetaFunction *func : overloads) {
+ m_overloads.append(func);
+ int argSize = func->arguments().size() - numberOfRemovedArguments(func);
+ if (m_minArgs > argSize)
+ m_minArgs = argSize;
+ else if (m_maxArgs < argSize)
+ m_maxArgs = argSize;
+ OverloadData* currentOverloadData = this;
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument *arg : arguments) {
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+ currentOverloadData = currentOverloadData->addOverloadData(func, arg);
+ }
+ }
+
+ // Sort the overload possibilities so that the overload decisor code goes for the most
+ // important cases first, based on the topological order of the implicit conversions
+ sortNextOverloads();
+
+ // Fix minArgs
+ if (minArgs() > maxArgs())
+ m_headOverloadData->m_minArgs = maxArgs();
+}
+
+OverloadData::OverloadData(OverloadData* headOverloadData, const AbstractMetaFunction* func,
+ const AbstractMetaType* argType, int argPos)
+ : m_minArgs(256), m_maxArgs(0), m_argPos(argPos), m_argType(argType),
+ m_headOverloadData(headOverloadData), m_previousOverloadData(0)
+{
+ if (func)
+ this->addOverload(func);
+}
+
+void OverloadData::addOverload(const AbstractMetaFunction* func)
+{
+ int origNumArgs = func->arguments().size();
+ int removed = numberOfRemovedArguments(func);
+ int numArgs = origNumArgs - removed;
+
+ if (numArgs > m_headOverloadData->m_maxArgs)
+ m_headOverloadData->m_maxArgs = numArgs;
+
+ if (numArgs < m_headOverloadData->m_minArgs)
+ m_headOverloadData->m_minArgs = numArgs;
+
+ for (int i = 0; m_headOverloadData->m_minArgs > 0 && i < origNumArgs; i++) {
+ if (func->argumentRemoved(i + 1))
+ continue;
+ if (!ShibokenGenerator::getDefaultValue(func, func->arguments()[i]).isEmpty()) {
+ int fixedArgIndex = i - removed;
+ if (fixedArgIndex < m_headOverloadData->m_minArgs)
+ m_headOverloadData->m_minArgs = fixedArgIndex;
+ }
+ }
+
+ m_overloads.append(func);
+}
+
+OverloadData* OverloadData::addOverloadData(const AbstractMetaFunction* func,
+ const AbstractMetaArgument* arg)
+{
+ const AbstractMetaType* argType = arg->type();
+ OverloadData* overloadData = 0;
+ if (!func->isOperatorOverload()) {
+ for (OverloadData *tmp : qAsConst(m_nextOverloadData)) {
+ // TODO: 'const char *', 'char *' and 'char' will have the same TypeEntry?
+
+ // If an argument have a type replacement, then we should create a new overloaddata
+ // for it, unless the next argument also have a identical type replacement.
+ QString replacedArg = func->typeReplaced(tmp->m_argPos + 1);
+ bool argsReplaced = !replacedArg.isEmpty() || !tmp->m_argTypeReplaced.isEmpty();
+ if ((!argsReplaced && typesAreEqual(tmp->m_argType, argType))
+ || (argsReplaced && replacedArg == tmp->argumentTypeReplaced())) {
+ tmp->addOverload(func);
+ overloadData = tmp;
+ }
+ }
+ }
+
+ if (!overloadData) {
+ overloadData = new OverloadData(m_headOverloadData, func, argType, m_argPos + 1);
+ overloadData->m_previousOverloadData = this;
+ overloadData->m_generator = this->m_generator;
+ QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1);
+
+ if (!typeReplaced.isEmpty())
+ overloadData->m_argTypeReplaced = typeReplaced;
+ m_nextOverloadData.append(overloadData);
+ }
+
+ return overloadData;
+}
+
+QStringList OverloadData::returnTypes() const
+{
+ QSet<QString> retTypes;
+ for (const AbstractMetaFunction *func : m_overloads) {
+ if (!func->typeReplaced(0).isEmpty())
+ retTypes << func->typeReplaced(0);
+ else if (func->type() && !func->argumentRemoved(0))
+ retTypes << func->type()->cppSignature();
+ else
+ retTypes << QLatin1String("void");
+ }
+ return QStringList(retTypes.toList());
+}
+
+bool OverloadData::hasNonVoidReturnType() const
+{
+ QStringList retTypes = returnTypes();
+ return !retTypes.contains(QLatin1String("void")) || retTypes.size() > 1;
+}
+
+bool OverloadData::hasVarargs() const
+{
+ for (const AbstractMetaFunction *func : m_overloads) {
+ AbstractMetaArgumentList args = func->arguments();
+ if (args.size() > 1 && args.last()->type()->isVarargs())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasAllowThread() const
+{
+ for (const AbstractMetaFunction *func : m_overloads) {
+ if (func->allowThread())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasStaticFunction(const AbstractMetaFunctionList& overloads)
+{
+ for (const AbstractMetaFunction *func : qAsConst(overloads)) {
+ if (func->isStatic())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasStaticFunction() const
+{
+ for (const AbstractMetaFunction *func : m_overloads) {
+ if (func->isStatic())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasInstanceFunction(const AbstractMetaFunctionList& overloads)
+{
+ for (const AbstractMetaFunction *func : qAsConst(overloads)) {
+ if (!func->isStatic())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasInstanceFunction() const
+{
+ for (const AbstractMetaFunction *func : m_overloads) {
+ if (!func->isStatic())
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasStaticAndInstanceFunctions(const AbstractMetaFunctionList& overloads)
+{
+ return OverloadData::hasStaticFunction(overloads) && OverloadData::hasInstanceFunction(overloads);
+}
+
+bool OverloadData::hasStaticAndInstanceFunctions() const
+{
+ return OverloadData::hasStaticFunction() && OverloadData::hasInstanceFunction();
+}
+
+const AbstractMetaFunction* OverloadData::referenceFunction() const
+{
+ return m_overloads.first();
+}
+
+const AbstractMetaArgument* OverloadData::argument(const AbstractMetaFunction* func) const
+{
+ if (isHeadOverloadData() || !m_overloads.contains(func))
+ return 0;
+
+ int argPos = 0;
+ int removed = 0;
+ for (int i = 0; argPos <= m_argPos; i++) {
+ if (func->argumentRemoved(i + 1))
+ removed++;
+ else
+ argPos++;
+ }
+
+ return func->arguments()[m_argPos + removed];
+}
+
+OverloadDataList OverloadData::overloadDataOnPosition(OverloadData* overloadData, int argPos) const
+{
+ OverloadDataList overloadDataList;
+ if (overloadData->argPos() == argPos) {
+ overloadDataList.append(overloadData);
+ } else if (overloadData->argPos() < argPos) {
+ const OverloadDataList &data = overloadData->nextOverloadData();
+ for (OverloadData *pd : data)
+ overloadDataList += overloadDataOnPosition(pd, argPos);
+ }
+ return overloadDataList;
+}
+
+OverloadDataList OverloadData::overloadDataOnPosition(int argPos) const
+{
+ OverloadDataList overloadDataList;
+ overloadDataList += overloadDataOnPosition(m_headOverloadData, argPos);
+ return overloadDataList;
+}
+
+bool OverloadData::nextArgumentHasDefaultValue() const
+{
+ for (OverloadData *overloadData : m_nextOverloadData) {
+ if (overloadData->getFunctionWithDefaultValue())
+ return true;
+ }
+ return false;
+}
+
+static OverloadData* _findNextArgWithDefault(OverloadData* overloadData)
+{
+ if (overloadData->getFunctionWithDefaultValue())
+ return overloadData;
+
+ OverloadData* result = 0;
+ const OverloadDataList &data = overloadData->nextOverloadData();
+ for (OverloadData *odata : data) {
+ OverloadData* tmp = _findNextArgWithDefault(odata);
+ if (!result || (tmp && result->argPos() > tmp->argPos()))
+ result = tmp;
+ }
+ return result;
+}
+
+OverloadData* OverloadData::findNextArgWithDefault()
+{
+ return _findNextArgWithDefault(this);
+}
+
+bool OverloadData::isFinalOccurrence(const AbstractMetaFunction* func) const
+{
+ for (const OverloadData *pd : m_nextOverloadData) {
+ if (pd->overloads().contains(func))
+ return false;
+ }
+ return true;
+}
+
+OverloadData::MetaFunctionList OverloadData::overloadsWithoutRepetition() const
+{
+ MetaFunctionList overloads = m_overloads;
+ for (const AbstractMetaFunction *func : m_overloads) {
+ if (func->minimalSignature().endsWith(QLatin1String("const")))
+ continue;
+ for (const AbstractMetaFunction *f : qAsConst(overloads)) {
+ if ((func->minimalSignature() + QLatin1String("const")) == f->minimalSignature()) {
+ overloads.removeOne(f);
+ break;
+ }
+ }
+ }
+ return overloads;
+}
+
+const AbstractMetaFunction* OverloadData::getFunctionWithDefaultValue() const
+{
+ for (const AbstractMetaFunction *func : m_overloads) {
+ int removedArgs = 0;
+ for (int i = 0; i <= m_argPos + removedArgs; i++) {
+ if (func->argumentRemoved(i + 1))
+ removedArgs++;
+ }
+ if (!ShibokenGenerator::getDefaultValue(func, func->arguments()[m_argPos + removedArgs]).isEmpty())
+ return func;
+ }
+ return 0;
+}
+
+QVector<int> OverloadData::invalidArgumentLengths() const
+{
+ QSet<int> validArgLengths;
+
+ for (const AbstractMetaFunction *func : qAsConst(m_headOverloadData->m_overloads)) {
+ const AbstractMetaArgumentList args = func->arguments();
+ int offset = 0;
+ for (int i = 0; i < args.size(); ++i) {
+ if (func->argumentRemoved(i+1)) {
+ offset++;
+ } else {
+ if (!ShibokenGenerator::getDefaultValue(func, args[i]).isEmpty())
+ validArgLengths << i-offset;
+ }
+ }
+ validArgLengths << args.size() - offset;
+ }
+
+ QVector<int> invalidArgLengths;
+ for (int i = minArgs() + 1; i < maxArgs(); i++) {
+ if (!validArgLengths.contains(i))
+ invalidArgLengths.append(i);
+ }
+
+ return invalidArgLengths;
+}
+
+int OverloadData::numberOfRemovedArguments(const AbstractMetaFunction* func, int finalArgPos)
+{
+ int removed = 0;
+ if (finalArgPos < 0) {
+ for (int i = 0; i < func->arguments().size(); i++) {
+ if (func->argumentRemoved(i + 1))
+ removed++;
+ }
+ } else {
+ for (int i = 0; i < finalArgPos + removed; i++) {
+ if (func->argumentRemoved(i + 1))
+ removed++;
+ }
+ }
+ return removed;
+}
+
+QPair<int, int> OverloadData::getMinMaxArguments(const AbstractMetaFunctionList& overloads)
+{
+ int minArgs = 10000;
+ int maxArgs = 0;
+ for (int i = 0; i < overloads.size(); i++) {
+ const AbstractMetaFunction* func = overloads[i];
+ int origNumArgs = func->arguments().size();
+ int removed = numberOfRemovedArguments(func);
+ int numArgs = origNumArgs - removed;
+ if (maxArgs < numArgs)
+ maxArgs = numArgs;
+ if (minArgs > numArgs)
+ minArgs = numArgs;
+ for (int j = 0; j < origNumArgs; j++) {
+ if (func->argumentRemoved(j + 1))
+ continue;
+ int fixedArgIndex = j - removed;
+ if (fixedArgIndex < minArgs && !ShibokenGenerator::getDefaultValue(func, func->arguments()[j]).isEmpty())
+ minArgs = fixedArgIndex;
+ }
+ }
+ return QPair<int, int>(minArgs, maxArgs);
+}
+
+bool OverloadData::isSingleArgument(const AbstractMetaFunctionList& overloads)
+{
+ bool singleArgument = true;
+ for (const AbstractMetaFunction *func : overloads) {
+ if (func->arguments().size() - numberOfRemovedArguments(func) != 1) {
+ singleArgument = false;
+ break;
+ }
+ }
+ return singleArgument;
+}
+
+void OverloadData::dumpGraph(QString filename) const
+{
+ QFile file(filename);
+ if (file.open(QFile::WriteOnly)) {
+ QTextStream s(&file);
+ s << m_headOverloadData->dumpGraph();
+ }
+}
+
+static inline QString toHtml(QString s)
+{
+ s.replace(QLatin1Char('<'), QLatin1String("&lt;"));
+ s.replace(QLatin1Char('>'), QLatin1String("&gt;"));
+ s.replace(QLatin1Char('&'), QLatin1String("&amp;"));
+ return s;
+}
+
+QString OverloadData::dumpGraph() const
+{
+ QString indent(4, QLatin1Char(' '));
+ QString result;
+ QTextStream s(&result);
+ if (m_argPos == -1) {
+ const AbstractMetaFunction* rfunc = referenceFunction();
+ s << "digraph OverloadedFunction {" << endl;
+ s << indent << "graph [fontsize=12 fontname=freemono labelloc=t splines=true overlap=false rankdir=LR];" << endl;
+
+ // Shows all function signatures
+ s << "legend [fontsize=9 fontname=freemono shape=rect label=\"";
+ for (const AbstractMetaFunction *func : m_overloads) {
+ s << "f" << functionNumber(func) << " : ";
+ if (func->type())
+ s << toHtml(func->type()->cppSignature());
+ else
+ s << "void";
+ s << ' ' << toHtml(func->minimalSignature()) << "\\l";
+ }
+ s << "\"];" << endl;
+
+ // Function box title
+ s << indent << '"' << rfunc->name() << "\" [shape=plaintext style=\"filled,bold\" margin=0 fontname=freemono fillcolor=white penwidth=1 ";
+ s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">";
+ s << "<tr><td bgcolor=\"black\" align=\"center\" cellpadding=\"6\" colspan=\"2\"><font color=\"white\">";
+ if (rfunc->ownerClass())
+ s << rfunc->ownerClass()->name() << "::";
+ s << toHtml(rfunc->name()) << "</font>";
+ if (rfunc->isVirtual()) {
+ s << "<br/><font color=\"white\" point-size=\"10\">&lt;&lt;";
+ if (rfunc->isAbstract())
+ s << "pure ";
+ s << "virtual&gt;&gt;</font>";
+ }
+ s << "</td></tr>";
+
+ // Function return type
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">original type</td><td bgcolor=\"gray\" align=\"left\">";
+ if (rfunc->type())
+ s << toHtml(rfunc->type()->cppSignature());
+ else
+ s << "void";
+ s << "</td></tr>";
+
+ // Shows type changes for all function signatures
+ for (const AbstractMetaFunction *func : m_overloads) {
+ if (func->typeReplaced(0).isEmpty())
+ continue;
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func);
+ s << "-type</td><td bgcolor=\"gray\" align=\"left\">";
+ s << toHtml(func->typeReplaced(0)) << "</td></tr>";
+ }
+
+ // Minimum and maximum number of arguments
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">minArgs</td><td bgcolor=\"gray\" align=\"left\">";
+ s << minArgs() << "</td></tr>";
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">maxArgs</td><td bgcolor=\"gray\" align=\"left\">";
+ s << maxArgs() << "</td></tr>";
+
+ if (rfunc->ownerClass()) {
+ if (rfunc->implementingClass() != rfunc->ownerClass())
+ s << "<tr><td align=\"right\">implementor</td><td align=\"left\">" << rfunc->implementingClass()->name() << "</td></tr>";
+ if (rfunc->declaringClass() != rfunc->ownerClass() && rfunc->declaringClass() != rfunc->implementingClass())
+ s << "<tr><td align=\"right\">declarator</td><td align=\"left\">" << rfunc->declaringClass()->name() << "</td></tr>";
+ }
+
+ // Overloads for the signature to present point
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">";
+ for (const AbstractMetaFunction *func : m_overloads)
+ s << 'f' << functionNumber(func) << ' ';
+ s << "</td></tr>";
+
+ s << "</table>> ];" << endl;
+
+ for (const OverloadData *pd : m_nextOverloadData)
+ s << indent << '"' << rfunc->name() << "\" -> " << pd->dumpGraph();
+
+ s << "}" << endl;
+ } else {
+ QString argId = QLatin1String("arg_") + QString::number(quintptr(this));
+ s << argId << ';' << endl;
+
+ s << indent << '"' << argId << "\" [shape=\"plaintext\" style=\"filled,bold\" margin=\"0\" fontname=\"freemono\" fillcolor=\"white\" penwidth=1 ";
+ s << "label=<<table border=\"0\" cellborder=\"0\" cellpadding=\"3\" bgcolor=\"white\">";
+
+ // Argument box title
+ s << "<tr><td bgcolor=\"black\" align=\"left\" cellpadding=\"2\" colspan=\"2\">";
+ s << "<font color=\"white\" point-size=\"11\">arg #" << argPos() << "</font></td></tr>";
+
+ // Argument type information
+ QString type = hasArgumentTypeReplace() ? argumentTypeReplaced() : argType()->cppSignature();
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">type</td><td bgcolor=\"gray\" align=\"left\">";
+ s << toHtml(type) << "</td></tr>";
+ if (hasArgumentTypeReplace()) {
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">orig. type</td><td bgcolor=\"gray\" align=\"left\">";
+ s << toHtml(argType()->cppSignature()) << "</td></tr>";
+ }
+
+ // Overloads for the signature to present point
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">overloads</td><td bgcolor=\"gray\" align=\"left\">";
+ for (const AbstractMetaFunction *func : m_overloads)
+ s << 'f' << functionNumber(func) << ' ';
+ s << "</td></tr>";
+
+ // Show default values (original and modified) for various functions
+ for (const AbstractMetaFunction *func : m_overloads) {
+ const AbstractMetaArgument* arg = argument(func);
+ if (!arg)
+ continue;
+ QString argDefault = ShibokenGenerator::getDefaultValue(func, arg);
+ if (!argDefault.isEmpty() ||
+ argDefault != arg->originalDefaultValueExpression()) {
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func);
+ s << "-default</td><td bgcolor=\"gray\" align=\"left\">";
+ s << argDefault << "</td></tr>";
+ }
+ if (argDefault != arg->originalDefaultValueExpression()) {
+ s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func);
+ s << "-orig-default</td><td bgcolor=\"gray\" align=\"left\">";
+ s << arg->originalDefaultValueExpression() << "</td></tr>";
+ }
+ }
+
+ s << "</table>>];" << endl;
+
+ for (const OverloadData *pd : m_nextOverloadData)
+ s << indent << argId << " -> " << pd->dumpGraph();
+ }
+ return result;
+}
+
+int OverloadData::functionNumber(const AbstractMetaFunction* func) const
+{
+ return m_headOverloadData->m_overloads.indexOf(func);
+}
+
+OverloadData::~OverloadData()
+{
+ while (!m_nextOverloadData.isEmpty())
+ delete m_nextOverloadData.takeLast();
+}
+
+bool OverloadData::hasArgumentTypeReplace() const
+{
+ return !m_argTypeReplaced.isEmpty();
+}
+
+QString OverloadData::argumentTypeReplaced() const
+{
+ return m_argTypeReplaced;
+}
+
+bool OverloadData::hasArgumentWithDefaultValue(const AbstractMetaFunctionList& overloads)
+{
+ if (OverloadData::getMinMaxArguments(overloads).second == 0)
+ return false;
+ for (const AbstractMetaFunction *func : overloads) {
+ if (hasArgumentWithDefaultValue(func))
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasArgumentWithDefaultValue() const
+{
+ if (maxArgs() == 0)
+ return false;
+ for (const AbstractMetaFunction *func : m_overloads) {
+ if (hasArgumentWithDefaultValue(func))
+ return true;
+ }
+ return false;
+}
+
+bool OverloadData::hasArgumentWithDefaultValue(const AbstractMetaFunction* func)
+{
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument *arg : arguments) {
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+ if (!ShibokenGenerator::getDefaultValue(func, arg).isEmpty())
+ return true;
+ }
+ return false;
+}
+
+AbstractMetaArgumentList OverloadData::getArgumentsWithDefaultValues(const AbstractMetaFunction* func)
+{
+ AbstractMetaArgumentList args;
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (AbstractMetaArgument *arg : arguments) {
+ if (ShibokenGenerator::getDefaultValue(func, arg).isEmpty()
+ || func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+ args << arg;
+ }
+ return args;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void OverloadData::formatDebug(QDebug &d) const
+{
+ const int count = m_overloads.size();
+ d << "argType=" << m_argType << ", minArgs=" << m_minArgs << ", maxArgs=" << m_maxArgs
+ << ", argPos=" << m_argPos << ", argTypeReplaced=\"" << m_argTypeReplaced
+ << "\", overloads[" << count << "]=(";
+ const int oldVerbosity = d.verbosity();
+ d.setVerbosity(3);
+ for (int i = 0; i < count; ++i) {
+ if (i)
+ d << '\n';
+ d << m_overloads.at(i);
+ }
+ d << ')';
+ d.setVerbosity(oldVerbosity);
+}
+
+QDebug operator<<(QDebug d, const OverloadData *od)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "OverloadData(";
+ if (od)
+ od->formatDebug(d);
+ else
+ d << '0';
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.h b/sources/shiboken2/generator/shiboken2/overloaddata.h
new file mode 100644
index 000000000..2d815f6bb
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/overloaddata.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OVERLOADDATA_H
+#define OVERLOADDATA_H
+
+#include <abstractmetalang_typedefs.h>
+#include <QtCore/QBitArray>
+#include <QtCore/QVector>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+class ShibokenGenerator;
+
+class OverloadData;
+typedef QVector<OverloadData *> OverloadDataList;
+
+class OverloadData
+{
+public:
+ typedef QVector<const AbstractMetaFunction *> MetaFunctionList;
+
+ OverloadData(const AbstractMetaFunctionList& overloads, const ShibokenGenerator* generator);
+ ~OverloadData();
+
+ int minArgs() const { return m_headOverloadData->m_minArgs; }
+ int maxArgs() const { return m_headOverloadData->m_maxArgs; }
+ int argPos() const { return m_argPos; }
+
+ const AbstractMetaType* argType() const { return m_argType; }
+
+ /// Returns a string list containing all the possible return types (including void) for the current OverloadData.
+ QStringList returnTypes() const;
+
+ /// Returns true if any of the overloads for the current OverloadData has a return type different from void.
+ bool hasNonVoidReturnType() const;
+
+ /// Returns true if any of the overloads for the current OverloadData has a varargs argument.
+ bool hasVarargs() const;
+
+ /// Returns true if any of the overloads for the current OverloadData allows threads when called.
+ bool hasAllowThread() const;
+
+ /// Returns true if any of the overloads for the current OverloadData is static.
+ bool hasStaticFunction() const;
+
+ /// Returns true if any of the overloads passed as argument is static.
+ static bool hasStaticFunction(const AbstractMetaFunctionList& overloads);
+
+ /// Returns true if any of the overloads for the current OverloadData is not static.
+ bool hasInstanceFunction() const;
+
+ /// Returns true if any of the overloads passed as argument is not static.
+ static bool hasInstanceFunction(const AbstractMetaFunctionList& overloads);
+
+ /// Returns true if among the overloads for the current OverloadData there are static and non-static methods altogether.
+ bool hasStaticAndInstanceFunctions() const;
+
+ /// Returns true if among the overloads passed as argument there are static and non-static methods altogether.
+ static bool hasStaticAndInstanceFunctions(const AbstractMetaFunctionList& overloads);
+
+ const AbstractMetaFunction* referenceFunction() const;
+ const AbstractMetaArgument* argument(const AbstractMetaFunction* func) const;
+ OverloadDataList overloadDataOnPosition(int argPos) const;
+
+ bool isHeadOverloadData() const { return this == m_headOverloadData; }
+
+ /// Returns the root OverloadData object that represents all the overloads.
+ OverloadData* headOverloadData() const { return m_headOverloadData; }
+
+ /// Returns the function that has a default value at the current OverloadData argument position, otherwise returns null.
+ const AbstractMetaFunction* getFunctionWithDefaultValue() const;
+
+ bool nextArgumentHasDefaultValue() const;
+ /// Returns the nearest occurrence, including this instance, of an argument with a default value.
+ OverloadData* findNextArgWithDefault();
+ bool isFinalOccurrence(const AbstractMetaFunction* func) const;
+
+ /// Returns the list of overloads removing repeated constant functions (ex.: "foo()" and "foo()const", the second is removed).
+ MetaFunctionList overloadsWithoutRepetition() const;
+ const MetaFunctionList& overloads() const { return m_overloads; }
+ OverloadDataList nextOverloadData() const { return m_nextOverloadData; }
+ OverloadData* previousOverloadData() const { return m_previousOverloadData; }
+
+ QVector<int> invalidArgumentLengths() const;
+
+ static int numberOfRemovedArguments(const AbstractMetaFunction* func, int finalArgPos = -1);
+ static QPair<int, int> getMinMaxArguments(const AbstractMetaFunctionList& overloads);
+ /// Returns true if all overloads have no more than one argument.
+ static bool isSingleArgument(const AbstractMetaFunctionList& overloads);
+
+ void dumpGraph(QString filename) const;
+ QString dumpGraph() const;
+
+ bool hasArgumentTypeReplace() const;
+ QString argumentTypeReplaced() const;
+
+ bool hasArgumentWithDefaultValue() const;
+ static bool hasArgumentWithDefaultValue(const AbstractMetaFunctionList& overloads);
+ static bool hasArgumentWithDefaultValue(const AbstractMetaFunction* func);
+
+ /// Returns a list of function arguments which have default values and were not removed.
+ static AbstractMetaArgumentList getArgumentsWithDefaultValues(const AbstractMetaFunction* func);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &) const;
+#endif
+
+private:
+ OverloadData(OverloadData* headOverloadData, const AbstractMetaFunction* func,
+ const AbstractMetaType* argType, int argPos);
+
+ void addOverload(const AbstractMetaFunction* func);
+ OverloadData* addOverloadData(const AbstractMetaFunction* func, const AbstractMetaArgument* arg);
+
+ void sortNextOverloads();
+
+ int functionNumber(const AbstractMetaFunction* func) const;
+ OverloadDataList overloadDataOnPosition(OverloadData* overloadData, int argPos) const;
+
+ int m_minArgs;
+ int m_maxArgs;
+ int m_argPos;
+ const AbstractMetaType* m_argType;
+ QString m_argTypeReplaced;
+ MetaFunctionList m_overloads;
+
+ OverloadData* m_headOverloadData;
+ OverloadDataList m_nextOverloadData;
+ OverloadData* m_previousOverloadData;
+ const ShibokenGenerator* m_generator;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug, const OverloadData *);
+#endif
+
+#endif // OVERLOADDATA_H
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
new file mode 100644
index 000000000..4768ddc88
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
@@ -0,0 +1,2728 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "shibokengenerator.h"
+#include <abstractmetalang.h>
+#include "overloaddata.h"
+#include <reporthandler.h>
+#include <typedatabase.h>
+#include <iostream>
+
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtCore/QRegularExpression>
+#include <limits>
+#include <memory>
+
+#define NULL_VALUE "NULL"
+#define AVOID_PROTECTED_HACK "avoid-protected-hack"
+#define PARENT_CTOR_HEURISTIC "enable-parent-ctor-heuristic"
+#define RETURN_VALUE_HEURISTIC "enable-return-value-heuristic"
+#define ENABLE_PYSIDE_EXTENSIONS "enable-pyside-extensions"
+#define DISABLE_VERBOSE_ERROR_MESSAGES "disable-verbose-error-messages"
+#define USE_ISNULL_AS_NB_NONZERO "use-isnull-as-nb_nonzero"
+
+//static void dumpFunction(AbstractMetaFunctionList lst);
+
+QHash<QString, QString> ShibokenGenerator::m_pythonPrimitiveTypeName = QHash<QString, QString>();
+QHash<QString, QString> ShibokenGenerator::m_pythonOperators = QHash<QString, QString>();
+QHash<QString, QString> ShibokenGenerator::m_formatUnits = QHash<QString, QString>();
+QHash<QString, QString> ShibokenGenerator::m_tpFuncs = QHash<QString, QString>();
+QStringList ShibokenGenerator::m_knownPythonTypes = QStringList();
+
+static QRegularExpression placeHolderRegex(int index)
+{
+ return QRegularExpression(QLatin1Char('%') + QString::number(index) + QStringLiteral("\\b"));
+}
+
+static QString resolveScopePrefix(const AbstractMetaClass* scope, const QString& value)
+{
+ if (!scope)
+ return QString();
+
+ QString name;
+ QStringList parts = scope->qualifiedCppName().split(QLatin1String("::"), QString::SkipEmptyParts);
+ for(int i = (parts.size() - 1) ; i >= 0; i--) {
+ if (!value.startsWith(parts[i] + QLatin1String("::")))
+ name = parts[i] + QLatin1String("::") + name;
+ else
+ name.clear();
+ }
+
+ return name;
+}
+ShibokenGenerator::ShibokenGenerator() : Generator()
+{
+ if (m_pythonPrimitiveTypeName.isEmpty())
+ ShibokenGenerator::initPrimitiveTypesCorrespondences();
+
+ if (m_tpFuncs.isEmpty())
+ ShibokenGenerator::clearTpFuncs();
+
+ if (m_knownPythonTypes.isEmpty())
+ ShibokenGenerator::initKnownPythonTypes();
+
+ m_metaTypeFromStringCache = AbstractMetaTypeCache();
+
+ m_typeSystemConvName[TypeSystemCheckFunction] = QLatin1String("checkType");
+ m_typeSystemConvName[TypeSystemIsConvertibleFunction] = QLatin1String("isConvertible");
+ m_typeSystemConvName[TypeSystemToCppFunction] = QLatin1String("toCpp");
+ m_typeSystemConvName[TypeSystemToPythonFunction] = QLatin1String("toPython");
+ m_typeSystemConvRegEx[TypeSystemCheckFunction] = QRegularExpression(QLatin1String(CHECKTYPE_REGEX));
+ m_typeSystemConvRegEx[TypeSystemIsConvertibleFunction] = QRegularExpression(QLatin1String(ISCONVERTIBLE_REGEX));
+ m_typeSystemConvRegEx[TypeSystemToPythonFunction] = QRegularExpression(QLatin1String(CONVERTTOPYTHON_REGEX));
+ m_typeSystemConvRegEx[TypeSystemToCppFunction] = QRegularExpression(QLatin1String(CONVERTTOCPP_REGEX));
+}
+
+ShibokenGenerator::~ShibokenGenerator()
+{
+ // TODO-CONVERTER: it must be caching types that were not created here.
+ //qDeleteAll(m_metaTypeFromStringCache.values());
+}
+
+void ShibokenGenerator::clearTpFuncs()
+{
+ m_tpFuncs.insert(QLatin1String("__str__"), QLatin1String("0"));
+ m_tpFuncs.insert(QLatin1String("__repr__"), QLatin1String("0"));
+ m_tpFuncs.insert(QLatin1String("__iter__"), QLatin1String("0"));
+ m_tpFuncs.insert(QLatin1String("__next__"), QLatin1String("0"));
+}
+
+void ShibokenGenerator::initPrimitiveTypesCorrespondences()
+{
+ // Python primitive types names
+ m_pythonPrimitiveTypeName.clear();
+
+ // PyBool
+ m_pythonPrimitiveTypeName.insert(QLatin1String("bool"), QLatin1String("PyBool"));
+
+ // PyInt
+ m_pythonPrimitiveTypeName.insert(QLatin1String("char"), QLatin1String("SbkChar"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("signed char"), QLatin1String("SbkChar"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned char"), QLatin1String("SbkChar"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("int"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("signed int"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("uint"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned int"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("short"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("ushort"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("signed short"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("signed short int"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned short"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned short int"), QLatin1String("PyInt"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("long"), QLatin1String("PyInt"));
+
+ // PyFloat
+ m_pythonPrimitiveTypeName.insert(QLatin1String("double"), QLatin1String("PyFloat"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("float"), QLatin1String("PyFloat"));
+
+ // PyLong
+ m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned long"), QLatin1String("PyLong"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("signed long"), QLatin1String("PyLong"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("ulong"), QLatin1String("PyLong"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned long int"), QLatin1String("PyLong"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("long long"), QLatin1String("PyLong"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("__int64"), QLatin1String("PyLong"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned long long"), QLatin1String("PyLong"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("unsigned __int64"), QLatin1String("PyLong"));
+ m_pythonPrimitiveTypeName.insert(QLatin1String("size_t"), QLatin1String("PyLong"));
+
+ // Python operators
+ m_pythonOperators.clear();
+
+ // call operator
+ m_pythonOperators.insert(QLatin1String("operator()"), QLatin1String("call"));
+
+ // Arithmetic operators
+ m_pythonOperators.insert(QLatin1String("operator+"), QLatin1String("add"));
+ m_pythonOperators.insert(QLatin1String("operator-"), QLatin1String("sub"));
+ m_pythonOperators.insert(QLatin1String("operator*"), QLatin1String("mul"));
+ m_pythonOperators.insert(QLatin1String("operator/"), QLatin1String("div"));
+ m_pythonOperators.insert(QLatin1String("operator%"), QLatin1String("mod"));
+
+ // Inplace arithmetic operators
+ m_pythonOperators.insert(QLatin1String("operator+="), QLatin1String("iadd"));
+ m_pythonOperators.insert(QLatin1String("operator-="), QLatin1String("isub"));
+ m_pythonOperators.insert(QLatin1String("operator++"), QLatin1String("iadd"));
+ m_pythonOperators.insert(QLatin1String("operator--"), QLatin1String("isub"));
+ m_pythonOperators.insert(QLatin1String("operator*="), QLatin1String("imul"));
+ m_pythonOperators.insert(QLatin1String("operator/="), QLatin1String("idiv"));
+ m_pythonOperators.insert(QLatin1String("operator%="), QLatin1String("imod"));
+
+ // Bitwise operators
+ m_pythonOperators.insert(QLatin1String("operator&"), QLatin1String("and"));
+ m_pythonOperators.insert(QLatin1String("operator^"), QLatin1String("xor"));
+ m_pythonOperators.insert(QLatin1String("operator|"), QLatin1String("or"));
+ m_pythonOperators.insert(QLatin1String("operator<<"), QLatin1String("lshift"));
+ m_pythonOperators.insert(QLatin1String("operator>>"), QLatin1String("rshift"));
+ m_pythonOperators.insert(QLatin1String("operator~"), QLatin1String("invert"));
+
+ // Inplace bitwise operators
+ m_pythonOperators.insert(QLatin1String("operator&="), QLatin1String("iand"));
+ m_pythonOperators.insert(QLatin1String("operator^="), QLatin1String("ixor"));
+ m_pythonOperators.insert(QLatin1String("operator|="), QLatin1String("ior"));
+ m_pythonOperators.insert(QLatin1String("operator<<="), QLatin1String("ilshift"));
+ m_pythonOperators.insert(QLatin1String("operator>>="), QLatin1String("irshift"));
+
+ // Comparison operators
+ m_pythonOperators.insert(QLatin1String("operator=="), QLatin1String("eq"));
+ m_pythonOperators.insert(QLatin1String("operator!="), QLatin1String("ne"));
+ m_pythonOperators.insert(QLatin1String("operator<"), QLatin1String("lt"));
+ m_pythonOperators.insert(QLatin1String("operator>"), QLatin1String("gt"));
+ m_pythonOperators.insert(QLatin1String("operator<="), QLatin1String("le"));
+ m_pythonOperators.insert(QLatin1String("operator>="), QLatin1String("ge"));
+
+ // Initialize format units for C++->Python->C++ conversion
+ m_formatUnits.clear();
+ m_formatUnits.insert(QLatin1String("char"), QLatin1String("b"));
+ m_formatUnits.insert(QLatin1String("unsigned char"), QLatin1String("B"));
+ m_formatUnits.insert(QLatin1String("int"), QLatin1String("i"));
+ m_formatUnits.insert(QLatin1String("unsigned int"), QLatin1String("I"));
+ m_formatUnits.insert(QLatin1String("short"), QLatin1String("h"));
+ m_formatUnits.insert(QLatin1String("unsigned short"), QLatin1String("H"));
+ m_formatUnits.insert(QLatin1String("long"), QLatin1String("l"));
+ m_formatUnits.insert(QLatin1String("unsigned long"), QLatin1String("k"));
+ m_formatUnits.insert(QLatin1String("long long"), QLatin1String("L"));
+ m_formatUnits.insert(QLatin1String("__int64"), QLatin1String("L"));
+ m_formatUnits.insert(QLatin1String("unsigned long long"), QLatin1String("K"));
+ m_formatUnits.insert(QLatin1String("unsigned __int64"), QLatin1String("K"));
+ m_formatUnits.insert(QLatin1String("double"), QLatin1String("d"));
+ m_formatUnits.insert(QLatin1String("float"), QLatin1String("f"));
+}
+
+void ShibokenGenerator::initKnownPythonTypes()
+{
+ m_knownPythonTypes.clear();
+ m_knownPythonTypes << QLatin1String("PyBool") << QLatin1String("PyInt")
+ << QLatin1String("PyFloat") << QLatin1String("PyLong") << QLatin1String("PyObject")
+ << QLatin1String("PyString") << QLatin1String("PyBuffer") << QLatin1String("PySequence")
+ << QLatin1String("PyTuple") << QLatin1String("PyList") << QLatin1String("PyDict")
+ << QLatin1String("PyObject*") << QLatin1String("PyObject *") << QLatin1String("PyTupleObject*");
+}
+
+QString ShibokenGenerator::translateTypeForWrapperMethod(const AbstractMetaType* cType,
+ const AbstractMetaClass* context,
+ Options options) const
+{
+ if (cType->isArray())
+ return translateTypeForWrapperMethod(cType->arrayElementType(), context, options) + QLatin1String("[]");
+
+ if (avoidProtectedHack() && cType->isEnum()) {
+ const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(cType);
+ if (metaEnum && metaEnum->isProtected())
+ return protectedEnumSurrogateName(metaEnum);
+ }
+
+ return translateType(cType, context, options);
+}
+
+bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass* metaClass) const
+{
+ bool result = metaClass->isPolymorphic() || metaClass->hasVirtualDestructor();
+ if (avoidProtectedHack()) {
+ result = result || metaClass->hasProtectedFields() || metaClass->hasProtectedDestructor();
+ if (!result && metaClass->hasProtectedFunctions()) {
+ int protectedFunctions = 0;
+ int protectedOperators = 0;
+ const AbstractMetaFunctionList &funcs = metaClass->functions();
+ for (const AbstractMetaFunction *func : funcs) {
+ if (!func->isProtected() || func->isSignal() || func->isModifiedRemoved())
+ continue;
+ else if (func->isOperatorOverload())
+ protectedOperators++;
+ else
+ protectedFunctions++;
+ }
+ result = result || (protectedFunctions > protectedOperators);
+ }
+ } else {
+ result = result && !metaClass->hasPrivateDestructor();
+ }
+ return result && !metaClass->isNamespace();
+}
+
+void ShibokenGenerator::lookForEnumsInClassesNotToBeGenerated(AbstractMetaEnumList& enumList, const AbstractMetaClass* metaClass)
+{
+ if (!metaClass)
+ return;
+
+ if (metaClass->typeEntry()->codeGeneration() == TypeEntry::GenerateForSubclass) {
+ const AbstractMetaEnumList &enums = metaClass->enums();
+ for (const AbstractMetaEnum *metaEnum : enums) {
+ if (metaEnum->isPrivate() || metaEnum->typeEntry()->codeGeneration() == TypeEntry::GenerateForSubclass)
+ continue;
+ if (!enumList.contains(const_cast<AbstractMetaEnum*>(metaEnum)))
+ enumList.append(const_cast<AbstractMetaEnum*>(metaEnum));
+ }
+ lookForEnumsInClassesNotToBeGenerated(enumList, metaClass->enclosingClass());
+ }
+}
+
+static const AbstractMetaClass* getProperEnclosingClass(const AbstractMetaClass* metaClass)
+{
+ if (!metaClass)
+ return 0;
+
+ if (metaClass->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass)
+ return metaClass;
+
+ return getProperEnclosingClass(metaClass->enclosingClass());
+}
+
+const AbstractMetaClass* ShibokenGenerator::getProperEnclosingClassForEnum(const AbstractMetaEnum* metaEnum)
+{
+ return getProperEnclosingClass(metaEnum->enclosingClass());
+}
+
+QString ShibokenGenerator::wrapperName(const AbstractMetaClass* metaClass) const
+{
+ if (shouldGenerateCppWrapper(metaClass)) {
+ QString result = metaClass->name();
+ if (metaClass->enclosingClass()) // is a inner class
+ result.replace(QLatin1String("::"), QLatin1String("_"));
+
+ result += QLatin1String("Wrapper");
+ return result;
+ } else {
+ return metaClass->qualifiedCppName();
+ }
+}
+
+QString ShibokenGenerator::wrapperName(const AbstractMetaType *metaType) const
+{
+ return metaType->cppSignature();
+}
+
+QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction* func)
+{
+ QString funcName;
+ if (func->isOperatorOverload())
+ funcName = ShibokenGenerator::pythonOperatorFunctionName(func);
+ else
+ funcName = func->name();
+ if (func->ownerClass()) {
+ QString fullName = func->ownerClass()->fullName();
+ if (func->isConstructor())
+ funcName = fullName;
+ else
+ funcName.prepend(fullName + QLatin1Char('.'));
+ }
+ return funcName;
+}
+
+QString ShibokenGenerator::protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum)
+{
+ return metaEnum->fullName().replace(QLatin1Char('.'), QLatin1Char('_')).replace(QLatin1String("::"), QLatin1String("_")) + QLatin1String("_Surrogate");
+}
+
+QString ShibokenGenerator::protectedFieldGetterName(const AbstractMetaField* field)
+{
+ return QStringLiteral("protected_%1_getter").arg(field->name());
+}
+
+QString ShibokenGenerator::protectedFieldSetterName(const AbstractMetaField* field)
+{
+ return QStringLiteral("protected_%1_setter").arg(field->name());
+}
+
+QString ShibokenGenerator::cpythonFunctionName(const AbstractMetaFunction* func)
+{
+ QString result;
+
+ // PYSIDE-331: For inherited functions, we need to find the same labels.
+ // Therefore we use the implementing class.
+ if (func->implementingClass()) {
+ result = cpythonBaseName(func->implementingClass()->typeEntry());
+ if (func->isConstructor()) {
+ result += QLatin1String("_Init");
+ } else {
+ result += QLatin1String("Func_");
+ if (func->isOperatorOverload())
+ result += ShibokenGenerator::pythonOperatorFunctionName(func);
+ else
+ result += func->name();
+ }
+ } else {
+ result = QLatin1String("Sbk") + moduleName() + QLatin1String("Module_") + func->name();
+ }
+
+ return result;
+}
+
+QString ShibokenGenerator::cpythonMethodDefinitionName(const AbstractMetaFunction* func)
+{
+ if (!func->ownerClass())
+ return QString();
+ return QStringLiteral("%1Method_%2").arg(cpythonBaseName(func->ownerClass()->typeEntry()), func->name());
+}
+
+QString ShibokenGenerator::cpythonGettersSettersDefinitionName(const AbstractMetaClass* metaClass)
+{
+ return cpythonBaseName(metaClass) + QLatin1String("_getsetlist");
+}
+
+QString ShibokenGenerator::cpythonSetattroFunctionName(const AbstractMetaClass* metaClass)
+{
+ return cpythonBaseName(metaClass) + QLatin1String("_setattro");
+}
+
+
+QString ShibokenGenerator::cpythonGetattroFunctionName(const AbstractMetaClass* metaClass)
+{
+ return cpythonBaseName(metaClass) + QLatin1String("_getattro");
+}
+
+QString ShibokenGenerator::cpythonGetterFunctionName(const AbstractMetaField* metaField)
+{
+ return QStringLiteral("%1_get_%2").arg(cpythonBaseName(metaField->enclosingClass()), metaField->name());
+}
+
+QString ShibokenGenerator::cpythonSetterFunctionName(const AbstractMetaField* metaField)
+{
+ return QStringLiteral("%1_set_%2").arg(cpythonBaseName(metaField->enclosingClass()), metaField->name());
+}
+
+static QString cpythonEnumFlagsName(QString moduleName, QString qualifiedCppName)
+{
+ QString result = QStringLiteral("Sbk%1_%2").arg(moduleName, qualifiedCppName);
+ result.replace(QLatin1String("::"), QLatin1String("_"));
+ return result;
+}
+
+static QString searchForEnumScope(const AbstractMetaClass* metaClass, const QString& value)
+{
+ QString enumValueName = value.trimmed();
+
+ if (!metaClass)
+ return QString();
+ const AbstractMetaEnumList &enums = metaClass->enums();
+ for (const AbstractMetaEnum* metaEnum : enums) {
+ const AbstractMetaEnumValueList &values = metaEnum->values();
+ for (const AbstractMetaEnumValue *enumValue : values) {
+ if (enumValueName == enumValue->name())
+ return metaClass->qualifiedCppName();
+ }
+ }
+ // PYSIDE-331: We need to also search the base classes.
+ QString ret = searchForEnumScope(metaClass->enclosingClass(), enumValueName);
+ if (ret.isEmpty())
+ ret = searchForEnumScope(metaClass->baseClass(), enumValueName);
+ return ret;
+}
+
+/*
+ * This function uses some heuristics to find out the scope for a given
+ * argument default value. New situations may arise in the future and
+ * this method should be updated, do it with care.
+ */
+QString ShibokenGenerator::guessScopeForDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg)
+{
+ QString value = getDefaultValue(func, arg);
+
+ if (value.isEmpty())
+ return QString();
+
+ if (isPointer(arg->type()))
+ return value;
+
+ static const QRegularExpression enumValueRegEx(QStringLiteral("^([A-Za-z_]\\w*)?$"));
+ Q_ASSERT(enumValueRegEx.isValid());
+ // Do not qualify macros by class name, eg QSGGeometry(..., int t = GL_UNSIGNED_SHORT);
+ static const QRegularExpression macroRegEx(QStringLiteral("^[A-Z_][A-Z0-9_]*$"));
+ Q_ASSERT(macroRegEx.isValid());
+ if (arg->type()->isPrimitive() && macroRegEx.match(value).hasMatch())
+ return value;
+
+ QString prefix;
+ QString suffix;
+
+ if (arg->type()->isEnum()) {
+ const AbstractMetaEnum* metaEnum = findAbstractMetaEnum(arg->type());
+ if (metaEnum)
+ prefix = resolveScopePrefix(metaEnum->enclosingClass(), value);
+ } else if (arg->type()->isFlags()) {
+ static 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;
+ }
+ prefix = typeName + QLatin1Char('(');
+ suffix = QLatin1Char(')');
+ }
+
+ static const QRegularExpression enumCombinationRegEx(QStringLiteral("^([A-Za-z_][\\w:]*)\\(([^,\\(\\)]*)\\)$")); // FlagName(EnumItem|EnumItem|...)
+ Q_ASSERT(enumCombinationRegEx.isValid());
+ const QRegularExpressionMatch match = enumCombinationRegEx.match(value);
+ if (prefix.isEmpty() && match.hasMatch()) {
+ QString flagName = match.captured(1);
+ QStringList enumItems = match.captured(2).split(QLatin1Char('|'));
+ QString scope = searchForEnumScope(func->implementingClass(), enumItems.first());
+ if (!scope.isEmpty())
+ scope.append(QLatin1String("::"));
+
+ QStringList fixedEnumItems;
+ for (const QString &enumItem : qAsConst(enumItems))
+ fixedEnumItems << QString(scope + enumItem);
+
+ if (!fixedEnumItems.isEmpty()) {
+ prefix = flagName + QLatin1Char('(');
+ value = fixedEnumItems.join(QLatin1Char('|'));
+ suffix = QLatin1Char(')');
+ }
+ }
+ } else if (arg->type()->typeEntry()->isValue()) {
+ const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes(), arg->type()->typeEntry());
+ if (enumValueRegEx.match(value).hasMatch() && value != QLatin1String("NULL"))
+ prefix = resolveScopePrefix(metaClass, value);
+ } else if (arg->type()->isPrimitive() && arg->type()->name() == QLatin1String("int")) {
+ if (enumValueRegEx.match(value).hasMatch() && func->implementingClass())
+ prefix = resolveScopePrefix(func->implementingClass(), value);
+ } else if(arg->type()->isPrimitive()) {
+ static const QRegularExpression unknowArgumentRegEx(QStringLiteral("^(?:[A-Za-z_][\\w:]*\\()?([A-Za-z_]\\w*)(?:\\))?$")); // [PrimitiveType(] DESIREDNAME [)]
+ Q_ASSERT(unknowArgumentRegEx.isValid());
+ const QRegularExpressionMatch match = unknowArgumentRegEx.match(value);
+ if (match.hasMatch() && func->implementingClass()) {
+ const AbstractMetaFieldList &fields = func->implementingClass()->fields();
+ for (const AbstractMetaField *field : fields) {
+ if (match.captured(1).trimmed() == field->name()) {
+ QString fieldName = field->name();
+ if (field->isStatic()) {
+ prefix = resolveScopePrefix(func->implementingClass(), value);
+ fieldName.prepend(prefix);
+ prefix.clear();
+ } else {
+ fieldName.prepend(QLatin1String(CPP_SELF_VAR "->"));
+ }
+ value.replace(match.captured(1), fieldName);
+ break;
+ }
+ }
+ }
+ }
+
+ if (!prefix.isEmpty())
+ value.prepend(prefix);
+ if (!suffix.isEmpty())
+ value.append(suffix);
+
+ return value;
+}
+
+QString ShibokenGenerator::cpythonEnumName(const EnumTypeEntry* enumEntry)
+{
+ QString p = enumEntry->targetLangPackage();
+ p.replace(QLatin1Char('.'), QLatin1Char('_'));
+ return cpythonEnumFlagsName(p, enumEntry->qualifiedCppName());
+}
+
+QString ShibokenGenerator::cpythonEnumName(const AbstractMetaEnum *metaEnum)
+{
+ return cpythonEnumName(metaEnum->typeEntry());
+}
+
+QString ShibokenGenerator::cpythonFlagsName(const FlagsTypeEntry* flagsEntry)
+{
+ QString p = flagsEntry->targetLangPackage();
+ p.replace(QLatin1Char('.'), QLatin1Char('_'));
+ return cpythonEnumFlagsName(p, flagsEntry->originalName());
+}
+
+QString ShibokenGenerator::cpythonFlagsName(const AbstractMetaEnum *metaEnum)
+{
+ const FlagsTypeEntry *flags = metaEnum->typeEntry()->flags();
+ if (!flags)
+ return QString();
+ return cpythonFlagsName(flags);
+}
+
+QString ShibokenGenerator::cpythonSpecialCastFunctionName(const AbstractMetaClass* metaClass)
+{
+ return cpythonBaseName(metaClass->typeEntry()) + QLatin1String("SpecialCastFunction");
+}
+
+QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClass* metaClass, QString argName)
+{
+ return cpythonWrapperCPtr(metaClass->typeEntry(), argName);
+}
+
+QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType *metaType, QString argName)
+{
+ if (!ShibokenGenerator::isWrapperType(metaType->typeEntry()))
+ return QString();
+ return QLatin1String("reinterpret_cast< ::") + metaType->cppSignature()
+ + QLatin1String(" *>(Shiboken::Conversions::cppPointer(") + cpythonTypeNameExt(metaType)
+ + QLatin1String(", reinterpret_cast<SbkObject *>(") + argName + QLatin1String(")))");
+}
+
+QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntry* type, QString argName)
+{
+ if (!ShibokenGenerator::isWrapperType(type))
+ return QString();
+ return QLatin1String("reinterpret_cast< ::") + type->qualifiedCppName()
+ + QLatin1String(" *>(Shiboken::Conversions::cppPointer(") + cpythonTypeNameExt(type)
+ + QLatin1String(", reinterpret_cast<SbkObject *>(") + argName + QLatin1String(")))");
+}
+
+QString ShibokenGenerator::getFunctionReturnType(const AbstractMetaFunction* func, Options) const
+{
+ if (func->ownerClass() && func->isConstructor())
+ return func->ownerClass()->qualifiedCppName() + QLatin1Char('*');
+
+ return translateTypeForWrapperMethod(func->type(), func->implementingClass());
+}
+
+void ShibokenGenerator::writeToPythonConversion(QTextStream & s, const AbstractMetaType* type,
+ const AbstractMetaClass * /* context */,
+ const QString& argumentName)
+{
+ s << cpythonToPythonConversionFunction(type) << argumentName << ')';
+}
+
+void ShibokenGenerator::writeToCppConversion(QTextStream& s, const AbstractMetaClass* metaClass,
+ const QString& inArgName, const QString& outArgName)
+{
+ s << cpythonToCppConversionFunction(metaClass) << inArgName << ", &" << outArgName << ')';
+}
+
+void ShibokenGenerator::writeToCppConversion(QTextStream& s, const AbstractMetaType* type, const AbstractMetaClass* context,
+ const QString& inArgName, const QString& outArgName)
+{
+ s << cpythonToCppConversionFunction(type, context) << inArgName << ", &" << outArgName << ')';
+}
+
+bool ShibokenGenerator::shouldRejectNullPointerArgument(const AbstractMetaFunction* func, int argIndex)
+{
+ if (argIndex < 0 || argIndex >= func->arguments().count())
+ return false;
+
+ const AbstractMetaArgument* arg = func->arguments().at(argIndex);
+ if (isValueTypeWithCopyConstructorOnly(arg->type()))
+ return true;
+
+ // Argument type is not a pointer, a None rejection should not be
+ // necessary because the type checking would handle that already.
+ if (!isPointer(arg->type()))
+ return false;
+ if (func->argumentRemoved(argIndex + 1))
+ return false;
+ const FunctionModificationList &mods = func->modifications();
+ for (const FunctionModification &funcMod : mods) {
+ for (const ArgumentModification &argMod : funcMod.argument_mods) {
+ if (argMod.index == argIndex + 1 && argMod.noNullPointers)
+ return true;
+ }
+ }
+ return false;
+}
+
+QString ShibokenGenerator::getFormatUnitString(const AbstractMetaFunction* func, bool incRef) const
+{
+ QString result;
+ const char objType = (incRef ? 'O' : 'N');
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument *arg : arguments) {
+ if (func->argumentRemoved(arg->argumentIndex() + 1))
+ continue;
+
+ if (!func->typeReplaced(arg->argumentIndex() + 1).isEmpty()) {
+ result += QLatin1Char(objType);
+ } else if (arg->type()->isQObject()
+ || arg->type()->isObject()
+ || arg->type()->isValue()
+ || arg->type()->isValuePointer()
+ || arg->type()->isNativePointer()
+ || arg->type()->isEnum()
+ || arg->type()->isFlags()
+ || arg->type()->isContainer()
+ || arg->type()->isSmartPointer()
+ || arg->type()->referenceType() == LValueReference) {
+ result += QLatin1Char(objType);
+ } else if (arg->type()->isPrimitive()) {
+ const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) arg->type()->typeEntry();
+ if (ptype->basicReferencedTypeEntry())
+ ptype = ptype->basicReferencedTypeEntry();
+ if (m_formatUnits.contains(ptype->name()))
+ result += m_formatUnits[ptype->name()];
+ else
+ result += QLatin1Char(objType);
+ } else if (isCString(arg->type())) {
+ result += QLatin1Char('z');
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Method: " << func->ownerClass()->qualifiedCppName()
+ << "::" << func->signature() << " => Arg:"
+ << arg->name() << "index: " << arg->argumentIndex()
+ << " - cannot be handled properly. Use an inject-code to fix it!";
+ result += QLatin1Char('?');
+ }
+ }
+ return result;
+}
+
+QString ShibokenGenerator::cpythonBaseName(const AbstractMetaType* type)
+{
+ if (isCString(type))
+ return QLatin1String("PyString");
+ return cpythonBaseName(type->typeEntry());
+}
+
+QString ShibokenGenerator::cpythonBaseName(const AbstractMetaClass* metaClass)
+{
+ return cpythonBaseName(metaClass->typeEntry());
+}
+
+QString ShibokenGenerator::cpythonBaseName(const TypeEntry* type)
+{
+ QString baseName;
+ if (ShibokenGenerator::isWrapperType(type) || type->isNamespace()) { // && type->referenceType() == NoReference) {
+ baseName = QLatin1String("Sbk_") + type->name();
+ } else if (type->isPrimitive()) {
+ const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) type;
+ while (ptype->basicReferencedTypeEntry())
+ ptype = ptype->basicReferencedTypeEntry();
+ if (ptype->targetLangApiName() == ptype->name())
+ baseName = pythonPrimitiveTypeName(ptype->name());
+ else
+ baseName = ptype->targetLangApiName();
+ } else if (type->isEnum()) {
+ baseName = cpythonEnumName((const EnumTypeEntry*) type);
+ } else if (type->isFlags()) {
+ baseName = cpythonFlagsName((const FlagsTypeEntry*) type);
+ } else if (type->isContainer()) {
+ const ContainerTypeEntry* ctype = (const ContainerTypeEntry*) type;
+ switch (ctype->type()) {
+ case ContainerTypeEntry::ListContainer:
+ case ContainerTypeEntry::StringListContainer:
+ case ContainerTypeEntry::LinkedListContainer:
+ case ContainerTypeEntry::VectorContainer:
+ case ContainerTypeEntry::StackContainer:
+ case ContainerTypeEntry::QueueContainer:
+ //baseName = "PyList";
+ //break;
+ case ContainerTypeEntry::PairContainer:
+ //baseName = "PyTuple";
+ baseName = QLatin1String("PySequence");
+ break;
+ case ContainerTypeEntry::SetContainer:
+ baseName = QLatin1String("PySet");
+ break;
+ case ContainerTypeEntry::MapContainer:
+ case ContainerTypeEntry::MultiMapContainer:
+ case ContainerTypeEntry::HashContainer:
+ case ContainerTypeEntry::MultiHashContainer:
+ baseName = QLatin1String("PyDict");
+ break;
+ default:
+ Q_ASSERT(false);
+ }
+ } else {
+ baseName = QLatin1String("PyObject");
+ }
+ return baseName.replace(QLatin1String("::"), QLatin1String("_"));
+}
+
+QString ShibokenGenerator::cpythonTypeName(const AbstractMetaClass* metaClass)
+{
+ return cpythonTypeName(metaClass->typeEntry());
+}
+
+QString ShibokenGenerator::cpythonTypeName(const TypeEntry* type)
+{
+ return cpythonBaseName(type) + QLatin1String("_Type");
+}
+
+QString ShibokenGenerator::cpythonTypeNameExt(const TypeEntry* type)
+{
+ return cppApiVariableName(type->targetLangPackage()) + QLatin1Char('[')
+ + getTypeIndexVariableName(type) + QLatin1Char(']');
+}
+
+QString ShibokenGenerator::converterObject(const AbstractMetaType* type)
+{
+ if (isCString(type))
+ return QLatin1String("Shiboken::Conversions::PrimitiveTypeConverter<const char*>()");
+ if (isVoidPointer(type))
+ return QLatin1String("Shiboken::Conversions::PrimitiveTypeConverter<void*>()");
+ if (type->typeEntry()->isContainer()) {
+ return convertersVariableName(type->typeEntry()->targetLangPackage())
+ + QLatin1Char('[') + getTypeIndexVariableName(type) + QLatin1Char(']');
+ }
+ return converterObject(type->typeEntry());
+}
+
+QString ShibokenGenerator::converterObject(const TypeEntry* type)
+{
+ if (isCppPrimitive(type))
+ return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(type->qualifiedCppName());
+ if (isWrapperType(type) || type->isEnum() || type->isFlags())
+ return QString::fromLatin1("SBK_CONVERTER(%1)").arg(cpythonTypeNameExt(type));
+
+ if (type->isArray()) {
+ qDebug() << "Warning: no idea how to handle the Qt5 type " << type->qualifiedCppName();
+ return QString::null;
+ }
+
+ /* the typedef'd primitive types case */
+ const PrimitiveTypeEntry* pte = dynamic_cast<const PrimitiveTypeEntry*>(type);
+ if (!pte) {
+ qDebug() << "Warning: the Qt5 primitive type is unknown" << type->qualifiedCppName();
+ return QString::null;
+ }
+ if (pte->basicReferencedTypeEntry())
+ pte = pte->basicReferencedTypeEntry();
+ if (pte->isPrimitive() && !pte->isCppPrimitive() && !pte->customConversion())
+ return QString::fromLatin1("Shiboken::Conversions::PrimitiveTypeConverter<%1>()").arg(pte->qualifiedCppName());
+
+ return convertersVariableName(type->targetLangPackage())
+ + QLatin1Char('[') + getTypeIndexVariableName(type) + QLatin1Char(']');
+}
+
+QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType* type)
+{
+ return cppApiVariableName(type->typeEntry()->targetLangPackage()) + QLatin1Char('[')
+ + getTypeIndexVariableName(type) + QLatin1Char(']');
+}
+
+static QString msgUnknownOperator(const AbstractMetaFunction* func)
+{
+ QString result = QLatin1String("Unknown operator: \"") + func->originalName() + QLatin1Char('"');
+ if (const AbstractMetaClass *c = func->implementingClass())
+ result += QLatin1String(" in class: ") + c->name();
+ return result;
+}
+
+static inline QString unknownOperator() { return QStringLiteral("__UNKNOWN_OPERATOR__"); }
+
+QString ShibokenGenerator::cpythonOperatorFunctionName(const AbstractMetaFunction* func)
+{
+ if (!func->isOperatorOverload())
+ return QString();
+ const QString pythonOp = pythonOperatorFunctionName(func->originalName());
+ if (pythonOp == unknownOperator())
+ qCWarning(lcShiboken).noquote().nospace() << msgUnknownOperator(func);
+ return QLatin1String("Sbk") + func->ownerClass()->name()
+ + QLatin1Char('_') + pythonOp;
+}
+
+QString ShibokenGenerator::fixedCppTypeName(const CustomConversion::TargetToNativeConversion* toNative)
+{
+ if (toNative->sourceType())
+ return fixedCppTypeName(toNative->sourceType());
+ return toNative->sourceTypeName();
+}
+QString ShibokenGenerator::fixedCppTypeName(const AbstractMetaType* type)
+{
+ return fixedCppTypeName(type->typeEntry(), type->cppSignature());
+}
+
+static QString _fixedCppTypeName(QString typeName)
+{
+ typeName.remove(QLatin1Char(' '));
+ typeName.replace(QLatin1Char('.'), QLatin1Char('_'));
+ typeName.replace(QLatin1Char(','), QLatin1Char('_'));
+ typeName.replace(QLatin1Char('<'), QLatin1Char('_'));
+ typeName.replace(QLatin1Char('>'), QLatin1Char('_'));
+ typeName.replace(QLatin1String("::"), QLatin1String("_"));
+ typeName.replace(QLatin1String("*"), QLatin1String("PTR"));
+ typeName.replace(QLatin1String("&"), QLatin1String("REF"));
+ return typeName;
+}
+QString ShibokenGenerator::fixedCppTypeName(const TypeEntry* type, QString typeName)
+{
+ if (typeName.isEmpty())
+ typeName = type->qualifiedCppName();
+ if (!(type->codeGeneration() & TypeEntry::GenerateTargetLang)) {
+ typeName.prepend(QLatin1Char('_'));
+ typeName.prepend(type->targetLangPackage());
+ }
+ return _fixedCppTypeName(typeName);
+}
+
+QString ShibokenGenerator::pythonPrimitiveTypeName(const QString& cppTypeName)
+{
+ QString rv = ShibokenGenerator::m_pythonPrimitiveTypeName.value(cppTypeName, QString());
+ if (rv.isEmpty()) {
+ // activate this when some primitive types are missing,
+ // i.e. when shiboken itself fails to build.
+ // In general, this is valid while just called by isNumeric()
+ // used on Qt5, 2015-09-20
+ if (false) {
+ std::cerr << "primitive type not found: " << qPrintable(cppTypeName) << std::endl;
+ abort();
+ }
+ }
+ return rv;
+}
+
+QString ShibokenGenerator::pythonPrimitiveTypeName(const PrimitiveTypeEntry* type)
+{
+ while (type->basicReferencedTypeEntry())
+ type = type->basicReferencedTypeEntry();
+ return pythonPrimitiveTypeName(type->name());
+}
+
+QString ShibokenGenerator::pythonOperatorFunctionName(QString cppOpFuncName)
+{
+ QString value = m_pythonOperators.value(cppOpFuncName);
+ if (value.isEmpty())
+ return unknownOperator();
+ value.prepend(QLatin1String("__"));
+ value.append(QLatin1String("__"));
+ return value;
+}
+
+QString ShibokenGenerator::pythonOperatorFunctionName(const AbstractMetaFunction* func)
+{
+ QString op = pythonOperatorFunctionName(func->originalName());
+ if (op == unknownOperator())
+ qCWarning(lcShiboken).noquote().nospace() << msgUnknownOperator(func);
+ if (func->arguments().isEmpty()) {
+ if (op == QLatin1String("__sub__"))
+ op = QLatin1String("__neg__");
+ else if (op == QLatin1String("__add__"))
+ op = QLatin1String("__pos__");
+ } else if (func->isStatic() && func->arguments().size() == 2) {
+ // If a operator overload function has 2 arguments and
+ // is static we assume that it is a reverse operator.
+ op = op.insert(2, QLatin1Char('r'));
+ }
+ return op;
+}
+
+QString ShibokenGenerator::pythonRichCompareOperatorId(QString cppOpFuncName)
+{
+ return QLatin1String("Py_") + m_pythonOperators.value(cppOpFuncName).toUpper();
+}
+
+QString ShibokenGenerator::pythonRichCompareOperatorId(const AbstractMetaFunction* func)
+{
+ return pythonRichCompareOperatorId(func->originalName());
+}
+
+bool ShibokenGenerator::isNumber(QString cpythonApiName)
+{
+ return cpythonApiName == QLatin1String("PyInt")
+ || cpythonApiName == QLatin1String("PyFloat")
+ || cpythonApiName == QLatin1String("PyLong")
+ || cpythonApiName == QLatin1String("PyBool");
+}
+
+bool ShibokenGenerator::isNumber(const TypeEntry* type)
+{
+ if (!type->isPrimitive())
+ return false;
+ return isNumber(pythonPrimitiveTypeName((const PrimitiveTypeEntry*) type));
+}
+
+bool ShibokenGenerator::isNumber(const AbstractMetaType* type)
+{
+ return isNumber(type->typeEntry());
+}
+
+bool ShibokenGenerator::isPyInt(const TypeEntry* type)
+{
+ if (!type->isPrimitive())
+ return false;
+ return pythonPrimitiveTypeName((const PrimitiveTypeEntry*) type) == QLatin1String("PyInt");
+}
+
+bool ShibokenGenerator::isPyInt(const AbstractMetaType* type)
+{
+ return isPyInt(type->typeEntry());
+}
+
+bool ShibokenGenerator::isPairContainer(const AbstractMetaType* type)
+{
+ return type->isContainer()
+ && static_cast<const ContainerTypeEntry *>(type->typeEntry())->type() == ContainerTypeEntry::PairContainer;
+}
+
+bool ShibokenGenerator::isWrapperType(const TypeEntry* type)
+{
+ if (type->isComplex())
+ return ShibokenGenerator::isWrapperType((const ComplexTypeEntry*)type);
+ return type->isObject() || type->isValue() || type->isSmartPointer();
+}
+bool ShibokenGenerator::isWrapperType(const ComplexTypeEntry* type)
+{
+ return isObjectType(type) || type->isValue() || type->isSmartPointer();
+}
+bool ShibokenGenerator::isWrapperType(const AbstractMetaType* metaType)
+{
+ return isObjectType(metaType)
+ || metaType->typeEntry()->isValue()
+ || metaType->typeEntry()->isSmartPointer();
+}
+
+bool ShibokenGenerator::isPointerToWrapperType(const AbstractMetaType* type)
+{
+ return (isObjectType(type) && type->indirections() == 1) || type->isValuePointer();
+}
+
+bool ShibokenGenerator::isObjectTypeUsedAsValueType(const AbstractMetaType* type)
+{
+ return type->typeEntry()->isObject() && type->referenceType() == NoReference && type->indirections() == 0;
+}
+
+bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const AbstractMetaClass* metaClass)
+{
+ if (!metaClass || !metaClass->typeEntry()->isValue())
+ return false;
+ AbstractMetaFunctionList ctors = metaClass->queryFunctions(AbstractMetaClass::Constructors);
+ if (ctors.count() != 1)
+ return false;
+ return ctors.first()->functionType() == AbstractMetaFunction::CopyConstructorFunction;
+}
+
+bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const TypeEntry* type) const
+{
+ if (!type || !type->isValue())
+ return false;
+ return isValueTypeWithCopyConstructorOnly(AbstractMetaClass::findClass(classes(), type));
+}
+
+bool ShibokenGenerator::isValueTypeWithCopyConstructorOnly(const AbstractMetaType* type) const
+{
+ if (!type || !type->typeEntry()->isValue())
+ return false;
+ return isValueTypeWithCopyConstructorOnly(type->typeEntry());
+}
+
+bool ShibokenGenerator::isUserPrimitive(const TypeEntry* type)
+{
+ if (!type->isPrimitive())
+ return false;
+ const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type;
+ if (trueType->basicReferencedTypeEntry())
+ trueType = trueType->basicReferencedTypeEntry();
+ return trueType->isPrimitive() && !trueType->isCppPrimitive()
+ && trueType->qualifiedCppName() != QLatin1String("std::string");
+}
+
+bool ShibokenGenerator::isUserPrimitive(const AbstractMetaType* type)
+{
+ if (type->indirections() != 0)
+ return false;
+ return isUserPrimitive(type->typeEntry());
+}
+
+bool ShibokenGenerator::isCppPrimitive(const TypeEntry* type)
+{
+ if (type->isCppPrimitive())
+ return true;
+ if (!type->isPrimitive())
+ return false;
+ const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type;
+ if (trueType->basicReferencedTypeEntry())
+ trueType = trueType->basicReferencedTypeEntry();
+ return trueType->qualifiedCppName() == QLatin1String("std::string");
+}
+
+bool ShibokenGenerator::isCppPrimitive(const AbstractMetaType* type)
+{
+ if (isCString(type) || isVoidPointer(type))
+ return true;
+ if (type->indirections() != 0)
+ return false;
+ return isCppPrimitive(type->typeEntry());
+}
+
+bool ShibokenGenerator::shouldDereferenceArgumentPointer(const AbstractMetaArgument* arg)
+{
+ return shouldDereferenceAbstractMetaTypePointer(arg->type());
+}
+
+bool ShibokenGenerator::shouldDereferenceAbstractMetaTypePointer(const AbstractMetaType* metaType)
+{
+ return metaType->referenceType() == LValueReference && isWrapperType(metaType) && !isPointer(metaType);
+}
+
+bool ShibokenGenerator::visibilityModifiedToPrivate(const AbstractMetaFunction* func)
+{
+ const FunctionModificationList &mods = func->modifications();
+ for (const FunctionModification &mod : mods) {
+ if (mod.modifiers & Modification::Private)
+ return true;
+ }
+ return false;
+}
+
+QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType, bool genericNumberType)
+{
+ QString customCheck;
+ if (metaType->typeEntry()->isCustom()) {
+ AbstractMetaType* type;
+ customCheck = guessCPythonCheckFunction(metaType->typeEntry()->name(), &type);
+ if (type)
+ metaType = type;
+ if (!customCheck.isEmpty())
+ return customCheck;
+ }
+
+ if (isCppPrimitive(metaType)) {
+ if (isCString(metaType))
+ return QLatin1String("Shiboken::String::check");
+ if (isVoidPointer(metaType))
+ return QLatin1String("PyObject_Check");
+ return cpythonCheckFunction(metaType->typeEntry(), genericNumberType);
+ } else if (metaType->typeEntry()->isContainer()) {
+ QString typeCheck = QLatin1String("Shiboken::Conversions::");
+ ContainerTypeEntry::Type type = ((const ContainerTypeEntry*)metaType->typeEntry())->type();
+ if (type == ContainerTypeEntry::ListContainer
+ || type == ContainerTypeEntry::StringListContainer
+ || type == ContainerTypeEntry::LinkedListContainer
+ || type == ContainerTypeEntry::VectorContainer
+ || type == ContainerTypeEntry::StackContainer
+ || type == ContainerTypeEntry::SetContainer
+ || type == ContainerTypeEntry::QueueContainer) {
+ const AbstractMetaType* type = metaType->instantiations().first();
+ if (isPointerToWrapperType(type)) {
+ typeCheck += QString::fromLatin1("checkSequenceTypes(%1, ").arg(cpythonTypeNameExt(type));
+ } else if (isWrapperType(type)) {
+ typeCheck += QLatin1String("convertibleSequenceTypes(reinterpret_cast<const SbkObjectType *>(");
+ typeCheck += cpythonTypeNameExt(type);
+ typeCheck += QLatin1String("), ");
+ } else {
+ typeCheck += QString::fromLatin1("convertibleSequenceTypes(%1, ").arg(converterObject(type));
+ }
+ } else if (type == ContainerTypeEntry::MapContainer
+ || type == ContainerTypeEntry::MultiMapContainer
+ || type == ContainerTypeEntry::HashContainer
+ || type == ContainerTypeEntry::MultiHashContainer
+ || type == ContainerTypeEntry::PairContainer) {
+ QString pyType = (type == ContainerTypeEntry::PairContainer) ? QLatin1String("Pair") : QLatin1String("Dict");
+ const AbstractMetaType* firstType = metaType->instantiations().first();
+ const AbstractMetaType* secondType = metaType->instantiations().last();
+ if (isPointerToWrapperType(firstType) && isPointerToWrapperType(secondType)) {
+ typeCheck += QString::fromLatin1("check%1Types(%2, %3, ").arg(pyType)
+ .arg(cpythonTypeNameExt(firstType), cpythonTypeNameExt(secondType));
+ } else {
+ typeCheck += QString::fromLatin1("convertible%1Types(%2, %3, %4, %5, ")
+ .arg(pyType, converterObject(firstType),
+ isPointerToWrapperType(firstType) ? QLatin1String("true") : QLatin1String("false"),
+ converterObject(secondType),
+ isPointerToWrapperType(secondType) ? QLatin1String("true") : QLatin1String("false"));
+ }
+ }
+ return typeCheck;
+ }
+ return cpythonCheckFunction(metaType->typeEntry(), genericNumberType);
+}
+
+QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry* type, bool genericNumberType)
+{
+ QString customCheck;
+ if (type->isCustom()) {
+ AbstractMetaType* metaType;
+ customCheck = guessCPythonCheckFunction(type->name(), &metaType);
+ if (metaType)
+ return cpythonCheckFunction(metaType, genericNumberType);
+ return customCheck;
+ }
+
+ if (type->isEnum() || type->isFlags() || isWrapperType(type))
+ return QString::fromLatin1("SbkObject_TypeCheck(%1, ").arg(cpythonTypeNameExt(type));
+ else if (isCppPrimitive(type))
+ return pythonPrimitiveTypeName((const PrimitiveTypeEntry*)type) + QLatin1String("_Check");
+ QString typeCheck;
+ if (type->targetLangApiName() == type->name())
+ typeCheck = cpythonIsConvertibleFunction(type);
+ else if (type->targetLangApiName() == QLatin1String("PyUnicode"))
+ typeCheck = QLatin1String("Shiboken::String::check");
+ else
+ typeCheck = type->targetLangApiName() + QLatin1String("_Check");
+ return typeCheck;
+}
+
+QString ShibokenGenerator::guessCPythonCheckFunction(const QString& type, AbstractMetaType** metaType)
+{
+ *metaType = 0;
+ if (type == QLatin1String("PyTypeObject"))
+ return QLatin1String("PyType_Check");
+
+ if (type == QLatin1String("PyBuffer"))
+ return QLatin1String("Shiboken::Buffer::checkType");
+
+ if (type == QLatin1String("str"))
+ return QLatin1String("Shiboken::String::check");
+
+ *metaType = buildAbstractMetaTypeFromString(type);
+ if (*metaType && !(*metaType)->typeEntry()->isCustom())
+ return QString();
+
+ return type + QLatin1String("_Check");
+}
+
+QString ShibokenGenerator::guessCPythonIsConvertible(const QString& type)
+{
+ if (type == QLatin1String("PyTypeObject"))
+ return QLatin1String("PyType_Check");
+
+ AbstractMetaType* metaType = buildAbstractMetaTypeFromString(type);
+ if (metaType && !metaType->typeEntry()->isCustom())
+ return cpythonIsConvertibleFunction(metaType);
+
+ return type + QLatin1String("_Check");
+}
+
+QString ShibokenGenerator::cpythonIsConvertibleFunction(const TypeEntry* type,
+ bool /* genericNumberType */,
+ bool /* checkExact */)
+{
+ if (isWrapperType(type)) {
+ QString result = QLatin1String("Shiboken::Conversions::");
+ result += (type->isValue() && !isValueTypeWithCopyConstructorOnly(type))
+ ? QLatin1String("isPythonToCppValueConvertible")
+ : QLatin1String("isPythonToCppPointerConvertible");
+ result += QLatin1String("(reinterpret_cast<SbkObjectType *>(")
+ + cpythonTypeNameExt(type) + QLatin1String("), ");
+ return result;
+ }
+ return QString::fromLatin1("Shiboken::Conversions::isPythonToCppConvertible(%1, ")
+ .arg(converterObject(type));
+}
+QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaType* metaType,
+ bool /* genericNumberType */)
+{
+ QString customCheck;
+ if (metaType->typeEntry()->isCustom()) {
+ AbstractMetaType* type;
+ customCheck = guessCPythonCheckFunction(metaType->typeEntry()->name(), &type);
+ if (type)
+ metaType = type;
+ if (!customCheck.isEmpty())
+ return customCheck;
+ }
+
+ if (isWrapperType(metaType)) {
+ QString result = QLatin1String("Shiboken::Conversions::");
+ if (isPointer(metaType) || isValueTypeWithCopyConstructorOnly(metaType))
+ result += QLatin1String("isPythonToCppPointerConvertible");
+ else if (metaType->referenceType() == LValueReference)
+ result += QLatin1String("isPythonToCppReferenceConvertible");
+ else
+ result += QLatin1String("isPythonToCppValueConvertible");
+ result += QLatin1String("(reinterpret_cast<const SbkObjectType *>(")
+ + cpythonTypeNameExt(metaType) + QLatin1String("), ");
+ return result;
+ }
+ return QStringLiteral("Shiboken::Conversions::isPythonToCppConvertible(%1, ")
+ .arg(converterObject(metaType));
+}
+
+QString ShibokenGenerator::cpythonIsConvertibleFunction(const AbstractMetaArgument *metaArg, bool genericNumberType)
+{
+ return cpythonIsConvertibleFunction(metaArg->type(), genericNumberType);
+}
+
+QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaClass* metaClass)
+{
+ return QLatin1String("Shiboken::Conversions::pythonToCppPointer(reinterpret_cast<SbkObjectType *>(")
+ + cpythonTypeNameExt(metaClass->typeEntry()) + QLatin1String("), ");
+}
+
+QString ShibokenGenerator::cpythonToCppConversionFunction(const AbstractMetaType *type,
+ const AbstractMetaClass * /* context */)
+{
+ if (isWrapperType(type)) {
+ return QLatin1String("Shiboken::Conversions::pythonToCpp")
+ + (isPointer(type) ? QLatin1String("Pointer") : QLatin1String("Copy"))
+ + QLatin1String("(reinterpret_cast<SbkObjectType *>(")
+ + cpythonTypeNameExt(type) + QLatin1String("), ");
+ }
+ return QStringLiteral("Shiboken::Conversions::pythonToCppCopy(%1, ")
+ .arg(converterObject(type));
+}
+
+QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaType *type,
+ const AbstractMetaClass * /* context */)
+{
+ if (isWrapperType(type)) {
+ QString conversion;
+ if (type->referenceType() == LValueReference && !(type->isValue() && type->isConstant()) && !isPointer(type))
+ conversion = QLatin1String("reference");
+ else if (type->isValue() || type->isSmartPointer())
+ conversion = QLatin1String("copy");
+ else
+ conversion = QLatin1String("pointer");
+ QString result = QLatin1String("Shiboken::Conversions::") + conversion
+ + QLatin1String("ToPython(reinterpret_cast<const SbkObjectType *>(")
+ + cpythonTypeNameExt(type) + QLatin1String("), ");
+ if (conversion != QLatin1String("pointer"))
+ result += QLatin1Char('&');
+ return result;
+ }
+ return QStringLiteral("Shiboken::Conversions::copyToPython(%1, %2")
+ .arg(converterObject(type),
+ (isCString(type) || isVoidPointer(type)) ? QString() : QLatin1String("&"));
+}
+
+QString ShibokenGenerator::cpythonToPythonConversionFunction(const AbstractMetaClass* metaClass)
+{
+ return cpythonToPythonConversionFunction(metaClass->typeEntry());
+}
+
+QString ShibokenGenerator::cpythonToPythonConversionFunction(const TypeEntry* type)
+{
+ if (isWrapperType(type)) {
+ const QString conversion = type->isValue() ? QLatin1String("copy") : QLatin1String("pointer");
+ QString result = QLatin1String("Shiboken::Conversions::") + conversion
+ + QLatin1String("ToPython(reinterpret_cast<const SbkObjectType *>(") + cpythonTypeNameExt(type)
+ + QLatin1String("), ");
+ if (conversion != QLatin1String("pointer"))
+ result += QLatin1Char('&');
+ return result;
+ }
+
+ return QStringLiteral("Shiboken::Conversions::copyToPython(%1, &").arg(converterObject(type));
+}
+
+QString ShibokenGenerator::argumentString(const AbstractMetaFunction *func,
+ const AbstractMetaArgument *argument,
+ Options options) const
+{
+ QString modified_type;
+ if (!(options & OriginalTypeDescription))
+ modified_type = func->typeReplaced(argument->argumentIndex() + 1);
+ QString arg;
+
+ if (modified_type.isEmpty())
+ arg = translateType(argument->type(), func->implementingClass(), options);
+ else
+ arg = modified_type.replace(QLatin1Char('$'), QLatin1Char('.'));
+
+ if (!(options & Generator::SkipName)) {
+ arg += QLatin1Char(' ');
+ arg += 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_VALUE);
+
+ //WORKAROUND: fix this please
+ if (default_value.startsWith(QLatin1String("new ")))
+ default_value.remove(0, 4);
+
+ arg += QLatin1String(" = ") + default_value;
+ }
+
+ return arg;
+}
+
+void ShibokenGenerator::writeArgument(QTextStream &s,
+ const AbstractMetaFunction *func,
+ const AbstractMetaArgument *argument,
+ Options options) const
+{
+ s << argumentString(func, argument, options);
+}
+
+void ShibokenGenerator::writeFunctionArguments(QTextStream &s,
+ const AbstractMetaFunction *func,
+ Options options) const
+{
+ AbstractMetaArgumentList arguments = func->arguments();
+
+ if (options & Generator::WriteSelf) {
+ s << func->implementingClass()->name() << '&';
+ if (!(options & SkipName))
+ s << " " PYTHON_SELF_VAR;
+ }
+
+ int argUsed = 0;
+ for (int i = 0; i < arguments.size(); ++i) {
+ if ((options & Generator::SkipRemovedArguments) && func->argumentRemoved(i+1))
+ continue;
+
+ if ((options & Generator::WriteSelf) || argUsed != 0)
+ s << ", ";
+ writeArgument(s, func, arguments[i], options);
+ argUsed++;
+ }
+}
+
+QString ShibokenGenerator::functionReturnType(const AbstractMetaFunction* func, Options options) const
+{
+ QString modifiedReturnType = QString(func->typeReplaced(0));
+ if (!modifiedReturnType.isNull() && !(options & OriginalTypeDescription))
+ return modifiedReturnType;
+ else
+ return translateType(func->type(), func->implementingClass(), options);
+}
+
+QString ShibokenGenerator::functionSignature(const AbstractMetaFunction *func,
+ QString prepend,
+ QString append,
+ Options options,
+ int /* argCount */) const
+{
+ QString result;
+ QTextStream s(&result);
+ // The actual function
+ if (!(func->isEmptyFunction() ||
+ func->isNormal() ||
+ func->isSignal())) {
+ options |= Generator::SkipReturnType;
+ } else {
+ s << functionReturnType(func, options) << ' ';
+ }
+
+ // name
+ QString name(func->originalName());
+ if (func->isConstructor())
+ name = wrapperName(func->ownerClass());
+
+ s << prepend << name << append << '(';
+ writeFunctionArguments(s, func, options);
+ s << ')';
+
+ if (func->isConstant() && !(options & Generator::ExcludeMethodConst))
+ s << " const";
+
+ return result;
+}
+
+void ShibokenGenerator::writeArgumentNames(QTextStream &s,
+ const AbstractMetaFunction *func,
+ Options options) const
+{
+ AbstractMetaArgumentList arguments = func->arguments();
+ int argCount = 0;
+ for (int j = 0, max = arguments.size(); j < max; j++) {
+
+ if ((options & Generator::SkipRemovedArguments) && (func->argumentRemoved(arguments.at(j)->argumentIndex()+1)))
+ continue;
+
+ s << ((argCount > 0) ? ", " : "") << arguments.at(j)->name();
+
+ if (((options & Generator::VirtualCall) == 0)
+ && (!func->conversionRule(TypeSystem::NativeCode, arguments.at(j)->argumentIndex() + 1).isEmpty()
+ || !func->conversionRule(TypeSystem::TargetLangCode, arguments.at(j)->argumentIndex() + 1).isEmpty())
+ && !func->isConstructor()) {
+ s << CONV_RULE_OUT_VAR_SUFFIX;
+ }
+
+ argCount++;
+ }
+}
+
+void ShibokenGenerator::writeFunctionCall(QTextStream& s,
+ const AbstractMetaFunction* func,
+ Options options) const
+{
+ if (!(options & Generator::SkipName))
+ s << (func->isConstructor() ? func->ownerClass()->qualifiedCppName() : func->originalName());
+ s << '(';
+ writeArgumentNames(s, func, options);
+ s << ')';
+}
+
+void ShibokenGenerator::writeUnusedVariableCast(QTextStream& s, const QString& variableName)
+{
+ s << INDENT << "SBK_UNUSED(" << variableName<< ')' << endl;
+}
+
+AbstractMetaFunctionList ShibokenGenerator::filterFunctions(const AbstractMetaClass* metaClass)
+{
+ AbstractMetaFunctionList result;
+ const AbstractMetaFunctionList &funcs = metaClass->functions();
+ for (AbstractMetaFunction *func : funcs) {
+ if (func->isSignal() || func->isDestructor() || func->usesRValueReferences()
+ || (func->isModifiedRemoved() && !func->isAbstract()
+ && (!avoidProtectedHack() || !func->isProtected())))
+ continue;
+ result << func;
+ }
+ return result;
+}
+
+ShibokenGenerator::ExtendedConverterData ShibokenGenerator::getExtendedConverters() const
+{
+ ExtendedConverterData extConvs;
+ const AbstractMetaClassList &classList = classes();
+ for (const AbstractMetaClass *metaClass : classList) {
+ // Use only the classes for the current module.
+ if (!shouldGenerate(metaClass))
+ continue;
+ const AbstractMetaFunctionList &overloads = metaClass->operatorOverloads(AbstractMetaClass::ConversionOp);
+ for (AbstractMetaFunction *convOp : overloads) {
+ // Get only the conversion operators that return a type from another module,
+ // that are value-types and were not removed in the type system.
+ const TypeEntry* convType = convOp->type()->typeEntry();
+ if ((convType->codeGeneration() & TypeEntry::GenerateTargetLang)
+ || !convType->isValue()
+ || convOp->isModifiedRemoved())
+ continue;
+ extConvs[convType].append(convOp->ownerClass());
+ }
+ }
+ return extConvs;
+}
+
+QVector<const CustomConversion *> ShibokenGenerator::getPrimitiveCustomConversions()
+{
+ QVector<const CustomConversion*> conversions;
+ const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes();
+ for (const PrimitiveTypeEntry *type : primitiveTypeList) {
+ if (!shouldGenerateTypeEntry(type) || !isUserPrimitive(type) || !type->customConversion())
+ continue;
+
+ conversions << type->customConversion();
+ }
+ return conversions;
+}
+
+static QString getArgumentsFromMethodCall(const QString& str)
+{
+ // It would be way nicer to be able to use a Perl like
+ // regular expression that accepts temporary variables
+ // to count the parenthesis.
+ // For more information check this:
+ // http://perl.plover.com/yak/regex/samples/slide083.html
+ static QLatin1String funcCall("%CPPSELF.%FUNCTION_NAME");
+ int pos = str.indexOf(funcCall);
+ if (pos == -1)
+ return QString();
+ pos = pos + funcCall.size();
+ while (str.at(pos) == QLatin1Char(' ') || str.at(pos) == QLatin1Char('\t'))
+ ++pos;
+ if (str.at(pos) == QLatin1Char('('))
+ ++pos;
+ int begin = pos;
+ int counter = 1;
+ while (counter != 0) {
+ if (str.at(pos) == QLatin1Char('('))
+ ++counter;
+ else if (str.at(pos) == QLatin1Char(')'))
+ --counter;
+ ++pos;
+ }
+ return str.mid(begin, pos-begin-1);
+}
+
+QString ShibokenGenerator::getCodeSnippets(const CodeSnipList& codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language)
+{
+ QString code;
+ QTextStream c(&code);
+ for (const CodeSnip &snip : codeSnips) {
+ if ((position != TypeSystem::CodeSnipPositionAny && snip.position != position) || !(snip.language & language))
+ continue;
+ QString snipCode;
+ QTextStream sc(&snipCode);
+ formatCode(sc, snip.code(), INDENT);
+ c << snipCode;
+ }
+ return code;
+}
+void ShibokenGenerator::processCodeSnip(QString& code, const AbstractMetaClass* context)
+{
+ if (context) {
+ // Replace template variable by the Python Type object
+ // for the class context in which the variable is used.
+ code.replace(QLatin1String("%PYTHONTYPEOBJECT"),
+ cpythonTypeName(context) + QLatin1String(".super.ht_type"));
+ code.replace(QLatin1String("%TYPE"), wrapperName(context));
+ code.replace(QLatin1String("%CPPTYPE"), context->name());
+ }
+
+ // replace "toPython" converters
+ replaceConvertToPythonTypeSystemVariable(code);
+
+ // replace "toCpp" converters
+ replaceConvertToCppTypeSystemVariable(code);
+
+ // replace "isConvertible" check
+ replaceIsConvertibleToCppTypeSystemVariable(code);
+
+ // replace "checkType" check
+ replaceTypeCheckTypeSystemVariable(code);
+}
+
+ShibokenGenerator::ArgumentVarReplacementList ShibokenGenerator::getArgumentReplacement(const AbstractMetaFunction* func,
+ bool usePyArgs, TypeSystem::Language language,
+ const AbstractMetaArgument* lastArg)
+{
+ ArgumentVarReplacementList argReplacements;
+ TypeSystem::Language convLang = (language == TypeSystem::TargetLangCode)
+ ? TypeSystem::NativeCode : TypeSystem::TargetLangCode;
+ int removed = 0;
+ for (int i = 0; i < func->arguments().size(); ++i) {
+ const AbstractMetaArgument* arg = func->arguments().at(i);
+ QString argValue;
+ if (language == TypeSystem::TargetLangCode) {
+ bool hasConversionRule = !func->conversionRule(convLang, i+1).isEmpty();
+ bool argRemoved = func->argumentRemoved(i+1);
+ removed = removed + (int) argRemoved;
+ if (argRemoved && hasConversionRule)
+ argValue = arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX);
+ else if (argRemoved || (lastArg && arg->argumentIndex() > lastArg->argumentIndex()))
+ argValue = QLatin1String(CPP_ARG_REMOVED) + QString::number(i);
+ if (!argRemoved && argValue.isEmpty()) {
+ int argPos = i - removed;
+ const AbstractMetaType* type = arg->type();
+ QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1);
+ if (!typeReplaced.isEmpty()) {
+ AbstractMetaType* builtType = buildAbstractMetaTypeFromString(typeReplaced);
+ if (builtType)
+ type = builtType;
+ }
+ if (type->typeEntry()->isCustom()) {
+ argValue = usePyArgs
+ ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(argPos)
+ : QLatin1String(PYTHON_ARG);
+ } else {
+ argValue = hasConversionRule
+ ? arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX)
+ : QLatin1String(CPP_ARG) + QString::number(argPos);
+ if (isWrapperType(type)) {
+ if (type->referenceType() == LValueReference && !isPointer(type))
+ argValue.prepend(QLatin1Char('*'));
+ }
+ }
+ }
+ } else {
+ argValue = arg->name();
+ }
+ if (!argValue.isEmpty())
+ argReplacements << ArgumentVarReplacementPair(arg, argValue);
+
+ }
+ return argReplacements;
+}
+
+void ShibokenGenerator::writeCodeSnips(QTextStream& s,
+ const CodeSnipList& codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language,
+ const AbstractMetaClass* context)
+{
+ QString code = getCodeSnippets(codeSnips, position, language);
+ if (code.isEmpty())
+ return;
+ processCodeSnip(code, context);
+ s << INDENT << "// Begin code injection" << endl;
+ s << code;
+ s << INDENT << "// End of code injection" << endl;
+}
+
+static QString msgWrongIndex(const char *varName, const QString &capture, const AbstractMetaFunction *func)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "Wrong index for " << varName << " variable (" << capture << ") on ";
+ if (const AbstractMetaClass *c = func->implementingClass())
+ str << c->name() << "::";
+ str << func->signature();
+ return result;
+}
+
+void ShibokenGenerator::writeCodeSnips(QTextStream& s,
+ const CodeSnipList& codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language,
+ const AbstractMetaFunction* func,
+ const AbstractMetaArgument* lastArg)
+{
+ QString code = getCodeSnippets(codeSnips, position, language);
+ if (code.isEmpty())
+ return;
+
+ // Calculate the real number of arguments.
+ int argsRemoved = 0;
+ for (int i = 0; i < func->arguments().size(); i++) {
+ if (func->argumentRemoved(i+1))
+ argsRemoved++;
+ }
+
+ OverloadData od(getFunctionGroups(func->implementingClass())[func->name()], this);
+ bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(od);
+
+ // Replace %PYARG_# variables.
+ code.replace(QLatin1String("%PYARG_0"), QLatin1String(PYTHON_RETURN_VAR));
+
+ static const QRegularExpression pyArgsRegex(QStringLiteral("%PYARG_(\\d+)"));
+ Q_ASSERT(pyArgsRegex.isValid());
+ if (language == TypeSystem::TargetLangCode) {
+ if (usePyArgs) {
+ code.replace(pyArgsRegex, QLatin1String(PYTHON_ARGS"[\\1-1]"));
+ } else {
+ static const QRegularExpression pyArgsRegexCheck(QStringLiteral("%PYARG_([2-9]+)"));
+ Q_ASSERT(pyArgsRegexCheck.isValid());
+ const QRegularExpressionMatch match = pyArgsRegexCheck.match(code);
+ if (match.hasMatch()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << msgWrongIndex("%PYARG", match.captured(1), func);
+ return;
+ }
+ code.replace(QLatin1String("%PYARG_1"), QLatin1String(PYTHON_ARG));
+ }
+ } else {
+ // Replaces the simplest case of attribution to a
+ // Python argument on the binding virtual method.
+ static const QRegularExpression pyArgsAttributionRegex(QStringLiteral("%PYARG_(\\d+)\\s*=[^=]\\s*([^;]+)"));
+ Q_ASSERT(pyArgsAttributionRegex.isValid());
+ code.replace(pyArgsAttributionRegex, QLatin1String("PyTuple_SET_ITEM(" PYTHON_ARGS ", \\1-1, \\2)"));
+ code.replace(pyArgsRegex, QLatin1String("PyTuple_GET_ITEM(" PYTHON_ARGS ", \\1-1)"));
+ }
+
+ // Replace %ARG#_TYPE variables.
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument *arg : arguments) {
+ QString argTypeVar = QStringLiteral("%ARG%1_TYPE").arg(arg->argumentIndex() + 1);
+ QString argTypeVal = arg->type()->cppSignature();
+ code.replace(argTypeVar, argTypeVal);
+ }
+
+ static const QRegularExpression cppArgTypeRegexCheck(QStringLiteral("%ARG(\\d+)_TYPE"));
+ Q_ASSERT(cppArgTypeRegexCheck.isValid());
+ QRegularExpressionMatchIterator rit = cppArgTypeRegexCheck.globalMatch(code);
+ while (rit.hasNext()) {
+ QRegularExpressionMatch match = rit.next();
+ qCWarning(lcShiboken).noquote().nospace()
+ << msgWrongIndex("%ARG#_TYPE", match.captured(1), func);
+ }
+
+ // Replace template variable for return variable name.
+ if (func->isConstructor()) {
+ code.replace(QLatin1String("%0."), QLatin1String("cptr->"));
+ code.replace(QLatin1String("%0"), QLatin1String("cptr"));
+ } else if (func->type()) {
+ QString returnValueOp = isPointerToWrapperType(func->type())
+ ? QLatin1String("%1->") : QLatin1String("%1.");
+ if (ShibokenGenerator::isWrapperType(func->type()))
+ code.replace(QLatin1String("%0."), returnValueOp.arg(QLatin1String(CPP_RETURN_VAR)));
+ code.replace(QLatin1String("%0"), QLatin1String(CPP_RETURN_VAR));
+ }
+
+ // Replace template variable for self Python object.
+ QString pySelf = (language == TypeSystem::NativeCode) ? QLatin1String("pySelf") : QLatin1String(PYTHON_SELF_VAR);
+ code.replace(QLatin1String("%PYSELF"), pySelf);
+
+ // Replace template variable for a pointer to C++ of this object.
+ if (func->implementingClass()) {
+ QString replacement = func->isStatic() ? QLatin1String("%1::") : QLatin1String("%1->");
+ QString cppSelf;
+ if (func->isStatic())
+ cppSelf = func->ownerClass()->qualifiedCppName();
+ else if (language == TypeSystem::NativeCode)
+ cppSelf = QLatin1String("this");
+ else
+ cppSelf = QLatin1String(CPP_SELF_VAR);
+
+ // On comparison operator CPP_SELF_VAR is always a reference.
+ if (func->isComparisonOperator())
+ replacement = QLatin1String("%1.");
+
+ if (func->isVirtual() && !func->isAbstract() && (!avoidProtectedHack() || !func->isProtected())) {
+ QString methodCallArgs = getArgumentsFromMethodCall(code);
+ if (!methodCallArgs.isNull()) {
+ const QString pattern = QStringLiteral("%CPPSELF.%FUNCTION_NAME(%1)").arg(methodCallArgs);
+ if (func->name() == QLatin1String("metaObject")) {
+ QString wrapperClassName = wrapperName(func->ownerClass());
+ QString cppSelfVar = avoidProtectedHack()
+ ? QLatin1String("%CPPSELF")
+ : QStringLiteral("reinterpret_cast<%1*>(%CPPSELF)").arg(wrapperClassName);
+ code.replace(pattern,
+ QString::fromLatin1("(Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(%1))"
+ " ? %2->::%3::%FUNCTION_NAME(%4)"
+ " : %CPPSELF.%FUNCTION_NAME(%4))").arg(pySelf, cppSelfVar, wrapperClassName, methodCallArgs));
+ } else {
+ code.replace(pattern,
+ QString::fromLatin1("(Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(%1))"
+ " ? %CPPSELF->::%TYPE::%FUNCTION_NAME(%2)"
+ " : %CPPSELF.%FUNCTION_NAME(%2))").arg(pySelf, methodCallArgs));
+ }
+ }
+ }
+
+ code.replace(QLatin1String("%CPPSELF."), replacement.arg(cppSelf));
+ code.replace(QLatin1String("%CPPSELF"), cppSelf);
+
+ if (code.indexOf(QLatin1String("%BEGIN_ALLOW_THREADS")) > -1) {
+ if (code.count(QLatin1String("%BEGIN_ALLOW_THREADS")) == code.count(QLatin1String("%END_ALLOW_THREADS"))) {
+ code.replace(QLatin1String("%BEGIN_ALLOW_THREADS"), QLatin1String(BEGIN_ALLOW_THREADS));
+ code.replace(QLatin1String("%END_ALLOW_THREADS"), QLatin1String(END_ALLOW_THREADS));
+ } else {
+ qCWarning(lcShiboken) << "%BEGIN_ALLOW_THREADS and %END_ALLOW_THREADS mismatch";
+ }
+ }
+
+ // replace template variable for the Python Type object for the
+ // class implementing the method in which the code snip is written
+ if (func->isStatic()) {
+ code.replace(QLatin1String("%PYTHONTYPEOBJECT"),
+ cpythonTypeName(func->implementingClass()) + QLatin1String(".super.ht_type"));
+ } else {
+ code.replace(QLatin1String("%PYTHONTYPEOBJECT."), pySelf + QLatin1String("->ob_type->"));
+ code.replace(QLatin1String("%PYTHONTYPEOBJECT"), pySelf + QLatin1String("->ob_type"));
+ }
+ }
+
+ // Replaces template %ARGUMENT_NAMES and %# variables by argument variables and values.
+ // Replaces template variables %# for individual arguments.
+ const ArgumentVarReplacementList &argReplacements = getArgumentReplacement(func, usePyArgs, language, lastArg);
+
+ QStringList args;
+ for (const ArgumentVarReplacementPair &pair : argReplacements) {
+ if (pair.second.startsWith(QLatin1String(CPP_ARG_REMOVED)))
+ continue;
+ args << pair.second;
+ }
+ code.replace(QLatin1String("%ARGUMENT_NAMES"), args.join(QLatin1String(", ")));
+
+ for (const ArgumentVarReplacementPair &pair : argReplacements) {
+ const AbstractMetaArgument* arg = pair.first;
+ int idx = arg->argumentIndex() + 1;
+ AbstractMetaType* type = arg->type();
+ QString typeReplaced = func->typeReplaced(arg->argumentIndex() + 1);
+ if (!typeReplaced.isEmpty()) {
+ AbstractMetaType* builtType = buildAbstractMetaTypeFromString(typeReplaced);
+ if (builtType)
+ type = builtType;
+ }
+ if (isWrapperType(type)) {
+ QString replacement = pair.second;
+ if (type->referenceType() == LValueReference && !isPointer(type))
+ replacement.remove(0, 1);
+ if (type->referenceType() == LValueReference || isPointer(type))
+ code.replace(QString::fromLatin1("%%1.").arg(idx), replacement + QLatin1String("->"));
+ }
+ code.replace(placeHolderRegex(idx), pair.second);
+ }
+
+ if (language == TypeSystem::NativeCode) {
+ // Replaces template %PYTHON_ARGUMENTS variable with a pointer to the Python tuple
+ // containing the converted virtual method arguments received from C++ to be passed
+ // to the Python override.
+ code.replace(QLatin1String("%PYTHON_ARGUMENTS"), QLatin1String(PYTHON_ARGS));
+
+ // replace variable %PYTHON_METHOD_OVERRIDE for a pointer to the Python method
+ // override for the C++ virtual method in which this piece of code was inserted
+ code.replace(QLatin1String("%PYTHON_METHOD_OVERRIDE"), QLatin1String(PYTHON_OVERRIDE_VAR));
+ }
+
+ if (avoidProtectedHack()) {
+ // If the function being processed was added by the user via type system,
+ // Shiboken needs to find out if there are other overloads for the same method
+ // name and if any of them is of the protected visibility. This is used to replace
+ // calls to %FUNCTION_NAME on user written custom code for calls to the protected
+ // dispatcher.
+ bool hasProtectedOverload = false;
+ if (func->isUserAdded()) {
+ const AbstractMetaFunctionList &funcs = getFunctionOverloads(func->ownerClass(), func->name());
+ for (const AbstractMetaFunction *f : funcs)
+ hasProtectedOverload |= f->isProtected();
+ }
+
+ if (func->isProtected() || hasProtectedOverload) {
+ code.replace(QLatin1String("%TYPE::%FUNCTION_NAME"),
+ QStringLiteral("%1::%2_protected")
+ .arg(wrapperName(func->ownerClass()), func->originalName()));
+ code.replace(QLatin1String("%FUNCTION_NAME"),
+ func->originalName() + QLatin1String("_protected"));
+ }
+ }
+
+ if (func->isConstructor() && shouldGenerateCppWrapper(func->ownerClass()))
+ code.replace(QLatin1String("%TYPE"), wrapperName(func->ownerClass()));
+
+ if (func->ownerClass())
+ code.replace(QLatin1String("%CPPTYPE"), func->ownerClass()->name());
+
+ replaceTemplateVariables(code, func);
+
+ processCodeSnip(code);
+ s << INDENT << "// Begin code injection" << endl;
+ s << code;
+ s << INDENT << "// End of code injection" << endl;
+}
+
+// Returns true if the string is an expression,
+// and false if it is a variable.
+static bool isVariable(const QString& code)
+{
+ static const QRegularExpression expr(QStringLiteral("^\\s*\\*?\\s*[A-Za-z_][A-Za-z_0-9.]*\\s*(?:\\[[^\\[]+\\])*$"));
+ Q_ASSERT(expr.isValid());
+ return expr.match(code.trimmed()).hasMatch();
+}
+
+// A miniature normalizer that puts a type string into a format
+// suitable for comparison with AbstractMetaType::cppSignature()
+// result.
+static QString miniNormalizer(const QString& varType)
+{
+ QString normalized = varType.trimmed();
+ if (normalized.isEmpty())
+ return normalized;
+ if (normalized.startsWith(QLatin1String("::")))
+ normalized.remove(0, 2);
+ QString suffix;
+ while (normalized.endsWith(QLatin1Char('*')) || normalized.endsWith(QLatin1Char('&'))) {
+ suffix.prepend(normalized.at(normalized.count() - 1));
+ normalized.chop(1);
+ normalized = normalized.trimmed();
+ }
+ const QString result = normalized + QLatin1Char(' ') + suffix;
+ return result.trimmed();
+}
+// The position must indicate the first character after the opening '('.
+// ATTENTION: do not modify this function to trim any resulting string!
+// This must be done elsewhere.
+static QString getConverterTypeSystemVariableArgument(const QString& code, int pos)
+{
+ QString arg;
+ int parenthesisDepth = 0;
+ int count = 0;
+ while (pos + count < code.count()) {
+ char c = code.at(pos+count).toLatin1(); // toAscii is gone
+ if (c == '(') {
+ ++parenthesisDepth;
+ } else if (c == ')') {
+ if (parenthesisDepth == 0) {
+ arg = code.mid(pos, count).trimmed();
+ break;
+ }
+ --parenthesisDepth;
+ }
+ ++count;
+ }
+ if (parenthesisDepth != 0)
+ qFatal("Unbalanced parenthesis on type system converter variable call.");
+ return arg;
+}
+typedef QPair<QString, QString> StringPair;
+void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString& code)
+{
+ QVector<StringPair> replacements;
+ QRegularExpressionMatchIterator rit = m_typeSystemConvRegEx[converterVariable].globalMatch(code);
+ while (rit.hasNext()) {
+ const QRegularExpressionMatch match = rit.next();
+ const QStringList list = match.capturedTexts();
+ QString conversionString = list.first();
+ QString conversionTypeName = list.last();
+ const AbstractMetaType* conversionType = buildAbstractMetaTypeFromString(conversionTypeName);
+ if (!conversionType) {
+ qFatal(qPrintable(QString::fromLatin1("Could not find type '%1' for use in '%2' conversion. "
+ "Make sure to use the full C++ name, e.g. 'Namespace::Class'.")
+ .arg(conversionTypeName).arg(m_typeSystemConvName[converterVariable])), NULL);
+
+ }
+ QString conversion;
+ QTextStream c(&conversion);
+ switch (converterVariable) {
+ case TypeSystemToCppFunction: {
+ int end = match.capturedStart();
+ int start = end;
+ while (start > 0 && code.at(start) != QLatin1Char('\n'))
+ --start;
+ while (code.at(start).isSpace())
+ ++start;
+ QString varType = code.mid(start, end - start);
+ conversionString = varType + list.first();
+ varType = miniNormalizer(varType);
+ QString varName = list.at(1).trimmed();
+ if (!varType.isEmpty()) {
+ if (varType != conversionType->cppSignature()) {
+ qFatal(qPrintable(QString::fromLatin1("Types of receiver variable ('%1') and %CONVERTTOCPP type system variable ('%2') differ.")
+ .arg(varType, conversionType->cppSignature())), NULL);
+ }
+ c << getFullTypeName(conversionType) << ' ' << varName;
+ writeMinimalConstructorExpression(c, conversionType);
+ c << ';' << endl;
+ Indentation indent(INDENT);
+ c << INDENT;
+ }
+ c << cpythonToCppConversionFunction(conversionType);
+ QString prefix;
+ if (varName.startsWith(QLatin1Char('*'))) {
+ varName.remove(0, 1);
+ varName = varName.trimmed();
+ } else {
+ prefix = QLatin1Char('&');
+ }
+ QString arg = getConverterTypeSystemVariableArgument(code, match.capturedEnd());
+ conversionString += arg;
+ c << arg << ", " << prefix << '(' << varName << ')';
+ break;
+ }
+ case TypeSystemCheckFunction:
+ conversion = cpythonCheckFunction(conversionType);
+ if (conversionType->typeEntry()->isPrimitive()
+ && (conversionType->typeEntry()->name() == QLatin1String("PyObject")
+ || !conversion.endsWith(QLatin1Char(' ')))) {
+ c << '(';
+ break;
+ }
+ case TypeSystemIsConvertibleFunction:
+ if (conversion.isEmpty())
+ conversion = cpythonIsConvertibleFunction(conversionType);
+ case TypeSystemToPythonFunction:
+ if (conversion.isEmpty())
+ conversion = cpythonToPythonConversionFunction(conversionType);
+ default: {
+ QString arg = getConverterTypeSystemVariableArgument(code, match.capturedEnd());
+ conversionString += arg;
+ if (converterVariable == TypeSystemToPythonFunction && !isVariable(arg)) {
+ qFatal(qPrintable(QString::fromLatin1("Only variables are acceptable as argument to %%CONVERTTOPYTHON type system variable on code snippet: '%1'")
+ .arg(code)), NULL);
+ }
+ if (conversion.contains(QLatin1String("%in"))) {
+ conversion.prepend(QLatin1Char('('));
+ conversion.replace(QLatin1String("%in"), arg);
+ } else {
+ c << arg;
+ }
+ }
+ }
+ replacements.append(qMakePair(conversionString, conversion));
+ }
+ for (const StringPair &rep : qAsConst(replacements))
+ code.replace(rep.first, rep.second);
+}
+
+bool ShibokenGenerator::injectedCodeUsesCppSelf(const AbstractMetaFunction* func)
+{
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
+ for (const CodeSnip &snip : qAsConst(snips)) {
+ if (snip.code().contains(QLatin1String("%CPPSELF")))
+ return true;
+ }
+ return false;
+}
+
+bool ShibokenGenerator::injectedCodeUsesPySelf(const AbstractMetaFunction* func)
+{
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::NativeCode);
+ for (const CodeSnip &snip : qAsConst(snips)) {
+ if (snip.code().contains(QLatin1String("%PYSELF")))
+ return true;
+ }
+ return false;
+}
+
+bool ShibokenGenerator::injectedCodeCallsCppFunction(const AbstractMetaFunction* func)
+{
+ QString funcCall = func->originalName() + QLatin1Char('(');
+ QString wrappedCtorCall;
+ if (func->isConstructor()) {
+ funcCall.prepend(QLatin1String("new "));
+ wrappedCtorCall = QStringLiteral("new %1(").arg(wrapperName(func->ownerClass()));
+ }
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode);
+ for (const CodeSnip &snip : qAsConst(snips)) {
+ if (snip.code().contains(QLatin1String("%FUNCTION_NAME(")) || snip.code().contains(funcCall)
+ || (func->isConstructor()
+ && ((func->ownerClass()->isPolymorphic() && snip.code().contains(wrappedCtorCall))
+ || snip.code().contains(QLatin1String("new %TYPE("))))
+ )
+ return true;
+ }
+ return false;
+}
+
+bool ShibokenGenerator::injectedCodeCallsPythonOverride(const AbstractMetaFunction* func)
+{
+ static const QRegularExpression overrideCallRegexCheck(QStringLiteral("PyObject_Call\\s*\\(\\s*%PYTHON_METHOD_OVERRIDE\\s*,"));
+ Q_ASSERT(overrideCallRegexCheck.isValid());
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::NativeCode);
+ for (const CodeSnip &snip : qAsConst(snips)) {
+ if (snip.code().contains(overrideCallRegexCheck))
+ return true;
+ }
+ return false;
+}
+
+bool ShibokenGenerator::injectedCodeHasReturnValueAttribution(const AbstractMetaFunction* func, TypeSystem::Language language)
+{
+ static const QRegularExpression retValAttributionRegexCheck_native(QStringLiteral("%0\\s*=[^=]\\s*.+"));
+ Q_ASSERT(retValAttributionRegexCheck_native.isValid());
+ static const QRegularExpression retValAttributionRegexCheck_target(QStringLiteral("%PYARG_0\\s*=[^=]\\s*.+"));
+ Q_ASSERT(retValAttributionRegexCheck_target.isValid());
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, language);
+ for (const CodeSnip &snip : qAsConst(snips)) {
+ if (language == TypeSystem::TargetLangCode) {
+ if (snip.code().contains(retValAttributionRegexCheck_target))
+ return true;
+ } else {
+ if (snip.code().contains(retValAttributionRegexCheck_native))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ShibokenGenerator::injectedCodeUsesArgument(const AbstractMetaFunction* func, int argumentIndex)
+{
+ CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny);
+ const QRegularExpression argRegEx = placeHolderRegex(argumentIndex + 1);
+ for (const CodeSnip &snip : qAsConst(snips)) {
+ QString code = snip.code();
+ if (code.contains(QLatin1String("%ARGUMENT_NAMES")) || code.contains(argRegEx))
+ return true;
+ }
+ return false;
+}
+
+bool ShibokenGenerator::hasMultipleInheritanceInAncestry(const AbstractMetaClass* metaClass)
+{
+ if (!metaClass || metaClass->baseClassNames().isEmpty())
+ return false;
+ if (metaClass->baseClassNames().size() > 1)
+ return true;
+ return hasMultipleInheritanceInAncestry(metaClass->baseClass());
+}
+
+typedef QMap<QString, AbstractMetaFunctionList> FunctionGroupMap;
+typedef FunctionGroupMap::const_iterator FunctionGroupMapIt;
+
+bool ShibokenGenerator::classNeedsGetattroFunction(const AbstractMetaClass* metaClass)
+{
+ if (!metaClass)
+ return false;
+ if (metaClass->typeEntry()->isSmartPointer())
+ return true;
+ const FunctionGroupMap &functionGroup = getFunctionGroups(metaClass);
+ for (FunctionGroupMapIt it = functionGroup.cbegin(), end = functionGroup.cend(); it != end; ++it) {
+ AbstractMetaFunctionList overloads;
+ for (AbstractMetaFunction *func : qAsConst(it.value())) {
+ if (func->isAssignmentOperator() || func->isCastOperator() || func->isModifiedRemoved()
+ || func->isPrivate() || func->ownerClass() != func->implementingClass()
+ || func->isConstructor() || func->isOperatorOverload())
+ continue;
+ overloads.append(func);
+ }
+ if (overloads.isEmpty())
+ continue;
+ if (OverloadData::hasStaticAndInstanceFunctions(overloads))
+ return true;
+ }
+ return false;
+}
+
+bool ShibokenGenerator::classNeedsSetattroFunction(const AbstractMetaClass *metaClass)
+{
+ if (!metaClass)
+ return false;
+ if (metaClass->typeEntry()->isSmartPointer())
+ return true;
+ return false;
+}
+
+AbstractMetaFunctionList ShibokenGenerator::getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass* metaClass)
+{
+ AbstractMetaFunctionList methods;
+ if (metaClass) {
+ const FunctionGroupMap &functionGroups = getFunctionGroups(metaClass);
+ for (FunctionGroupMapIt it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
+ AbstractMetaFunctionList overloads;
+ for (AbstractMetaFunction *func : qAsConst(it.value())) {
+ if (func->isAssignmentOperator() || func->isCastOperator() || func->isModifiedRemoved()
+ || func->isPrivate() || func->ownerClass() != func->implementingClass()
+ || func->isConstructor() || func->isOperatorOverload())
+ continue;
+ overloads.append(func);
+ }
+ if (overloads.isEmpty())
+ continue;
+ if (OverloadData::hasStaticAndInstanceFunctions(overloads))
+ methods.append(overloads.first());
+ }
+ }
+ return methods;
+}
+
+AbstractMetaClassList ShibokenGenerator::getBaseClasses(const AbstractMetaClass* metaClass) const
+{
+ AbstractMetaClassList baseClasses;
+ if (metaClass) {
+ const QStringList &baseClassNames = metaClass->baseClassNames();
+ for (const QString &parent : baseClassNames) {
+ AbstractMetaClass *clazz = AbstractMetaClass::findClass(classes(), parent);
+ if (clazz)
+ baseClasses << clazz;
+ }
+ }
+ return baseClasses;
+}
+
+const AbstractMetaClass* ShibokenGenerator::getMultipleInheritingClass(const AbstractMetaClass* metaClass)
+{
+ if (!metaClass || metaClass->baseClassNames().isEmpty())
+ return 0;
+ if (metaClass->baseClassNames().size() > 1)
+ return metaClass;
+ return getMultipleInheritingClass(metaClass->baseClass());
+}
+
+AbstractMetaClassList ShibokenGenerator::getAllAncestors(const AbstractMetaClass* metaClass) const
+{
+ AbstractMetaClassList result;
+ if (metaClass) {
+ AbstractMetaClassList baseClasses = getBaseClasses(metaClass);
+ for (AbstractMetaClass *base : qAsConst(baseClasses)) {
+ result.append(base);
+ result.append(getAllAncestors(base));
+ }
+ }
+ return result;
+}
+
+QString ShibokenGenerator::getModuleHeaderFileName(const QString& moduleName) const
+{
+ QString result = moduleName.isEmpty() ? packageName() : moduleName;
+ result.replace(QLatin1Char('.'), QLatin1Char('_'));
+ return result.toLower() + QLatin1String("_python.h");
+}
+
+QString ShibokenGenerator::extendedIsConvertibleFunctionName(const TypeEntry* targetType) const
+{
+ QString p = targetType->targetLangPackage();
+ p.replace(QLatin1Char('.'), QLatin1Char('_'));
+ return QStringLiteral("ExtendedIsConvertible_%1_%2").arg(p, targetType->name());
+}
+
+QString ShibokenGenerator::extendedToCppFunctionName(const TypeEntry* targetType) const
+{
+ QString p = targetType->targetLangPackage();
+ p.replace(QLatin1Char('.'), QLatin1Char('_'));
+ return QStringLiteral("ExtendedToCpp_%1_%2").arg(p, targetType->name());
+}
+
+bool ShibokenGenerator::isCopyable(const AbstractMetaClass *metaClass)
+
+{
+ if (metaClass->isNamespace() || isObjectType(metaClass))
+ return false;
+ else if (metaClass->typeEntry()->copyable() == ComplexTypeEntry::Unknown)
+ return metaClass->hasCloneOperator();
+ else
+ return (metaClass->typeEntry()->copyable() == ComplexTypeEntry::CopyableSet);
+
+ return false;
+}
+
+AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromString(QString typeSignature)
+{
+ typeSignature = typeSignature.trimmed();
+ if (typeSignature.startsWith(QLatin1String("::")))
+ typeSignature.remove(0, 2);
+
+ if (m_metaTypeFromStringCache.contains(typeSignature))
+ return m_metaTypeFromStringCache.value(typeSignature);
+
+ QString typeString = typeSignature;
+ bool isConst = typeString.startsWith(QLatin1String("const "));
+ if (isConst)
+ typeString.remove(0, sizeof("const ") / sizeof(char) - 1);
+
+ ReferenceType refType = NoReference;
+ if (typeString.endsWith(QLatin1String("&&"))) {
+ refType = RValueReference;
+ typeString.chop(2);
+ typeString = typeString.trimmed();
+ } else if (typeString.endsWith(QLatin1Char('&'))) {
+ refType = LValueReference;
+ typeString.chop(1);
+ typeString = typeString.trimmed();
+ }
+
+ int indirections = 0;
+ while (typeString.endsWith(QLatin1Char('*'))) {
+ ++indirections;
+ typeString.chop(1);
+ typeString = typeString.trimmed();
+ }
+
+ if (typeString.startsWith(QLatin1String("::")))
+ typeString.remove(0, 2);
+
+ QString adjustedTypeName = typeString;
+ QStringList instantiatedTypes;
+ int lpos = typeString.indexOf(QLatin1Char('<'));
+ if (lpos > -1) {
+ int rpos = typeString.lastIndexOf(QLatin1Char('>'));
+ if ((lpos != -1) && (rpos != -1)) {
+ QString type = typeString.mid(lpos + 1, rpos - lpos - 1);
+ int depth = 0;
+ int start = 0;
+ for (int i = 0; i < type.count(); ++i) {
+ if (type.at(i) == QLatin1Char('<')) {
+ ++depth;
+ } else if (type.at(i) == QLatin1Char('>')) {
+ --depth;
+ } else if (type.at(i) == QLatin1Char(',') && depth == 0) {
+ instantiatedTypes << type.mid(start, i - start).trimmed();
+ start = i + 1;
+ }
+ }
+ instantiatedTypes << type.mid(start).trimmed();
+ adjustedTypeName.truncate(lpos);
+ }
+ }
+
+ TypeEntry* typeEntry = TypeDatabase::instance()->findType(adjustedTypeName);
+
+ AbstractMetaType* metaType = 0;
+ if (typeEntry) {
+ metaType = new AbstractMetaType();
+ metaType->setTypeEntry(typeEntry);
+ metaType->setIndirections(indirections);
+ metaType->setReferenceType(refType);
+ metaType->setConstant(isConst);
+ metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern);
+ for (const QString &instantiation : qAsConst(instantiatedTypes)) {
+ AbstractMetaType* tmplArgType = buildAbstractMetaTypeFromString(instantiation);
+ metaType->addInstantiation(tmplArgType);
+ }
+ metaType->decideUsagePattern();
+ m_metaTypeFromStringCache.insert(typeSignature, metaType);
+ }
+ return metaType;
+}
+
+AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(const TypeEntry* typeEntry)
+{
+ QString typeName = typeEntry->qualifiedCppName();
+ if (typeName.startsWith(QLatin1String("::")))
+ typeName.remove(0, 2);
+ if (m_metaTypeFromStringCache.contains(typeName))
+ return m_metaTypeFromStringCache.value(typeName);
+ AbstractMetaType* metaType = new AbstractMetaType;
+ metaType->setTypeEntry(typeEntry);
+ metaType->setIndirections(0);
+ metaType->setReferenceType(NoReference);
+ metaType->setConstant(false);
+ metaType->decideUsagePattern();
+ m_metaTypeFromStringCache.insert(typeName, metaType);
+ return metaType;
+}
+AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromAbstractMetaClass(const AbstractMetaClass* metaClass)
+{
+ return ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(metaClass->typeEntry());
+}
+
+/*
+static void dumpFunction(AbstractMetaFunctionList lst)
+{
+ qDebug() << "DUMP FUNCTIONS: ";
+ for (AbstractMetaFunction *func : qAsConst(lst))
+ qDebug() << "*" << func->ownerClass()->name()
+ << func->signature()
+ << "Private: " << func->isPrivate()
+ << "Empty: " << func->isEmptyFunction()
+ << "Static:" << func->isStatic()
+ << "Signal:" << func->isSignal()
+ << "ClassImplements: " << (func->ownerClass() != func->implementingClass())
+ << "is operator:" << func->isOperatorOverload()
+ << "is global:" << func->isInGlobalScope();
+}
+*/
+
+static bool isGroupable(const AbstractMetaFunction* func)
+{
+ if (func->isSignal() || func->isDestructor() || (func->isModifiedRemoved() && !func->isAbstract()))
+ return false;
+ // weird operator overloads
+ if (func->name() == QLatin1String("operator[]") || func->name() == QLatin1String("operator->")) // FIXME: what about cast operators?
+ return false;;
+ return true;
+}
+
+QMap< QString, AbstractMetaFunctionList > ShibokenGenerator::getFunctionGroups(const AbstractMetaClass* scope)
+{
+ AbstractMetaFunctionList lst = scope ? scope->functions() : globalFunctions();
+
+ QMap<QString, AbstractMetaFunctionList> results;
+ for (AbstractMetaFunction *func : qAsConst(lst)) {
+ if (isGroupable(func))
+ results[func->name()].append(func);
+ }
+ return results;
+}
+
+AbstractMetaFunctionList ShibokenGenerator::getInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen)
+{
+ AbstractMetaFunctionList results;
+ AbstractMetaClass* basis;
+ if (func->ownerClass() && (basis = func->ownerClass()->baseClass(), basis)) {
+ for (; basis; basis = basis->baseClass()) {
+ const AbstractMetaFunction* inFunc = basis->findFunction(func->name());
+ if (inFunc && !seen->contains(inFunc->minimalSignature())) {
+ seen->insert(inFunc->minimalSignature());
+ AbstractMetaFunction* newFunc = inFunc->copy();
+ newFunc->setImplementingClass(func->implementingClass());
+ results << newFunc;
+ }
+ }
+ }
+ return results;
+}
+
+AbstractMetaFunctionList ShibokenGenerator::getFunctionAndInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen)
+{
+ AbstractMetaFunctionList results;
+ seen->insert(func->minimalSignature());
+ results << const_cast<AbstractMetaFunction *>(func) << getInheritedOverloads(func, seen);
+ return results;
+}
+
+AbstractMetaFunctionList ShibokenGenerator::getFunctionOverloads(const AbstractMetaClass* scope, const QString& functionName)
+{
+ AbstractMetaFunctionList lst = scope ? scope->functions() : globalFunctions();
+
+ AbstractMetaFunctionList results;
+ QSet<QString> seenSignatures;
+ for (AbstractMetaFunction *func : qAsConst(lst)) {
+ if (func->name() != functionName)
+ continue;
+ if (isGroupable(func)) {
+ // PYSIDE-331: look also into base classes.
+ results << getFunctionAndInheritedOverloads(func, &seenSignatures);
+ }
+ }
+ return results;
+}
+
+QPair< int, int > ShibokenGenerator::getMinMaxArguments(const AbstractMetaFunction* metaFunction)
+{
+ AbstractMetaFunctionList overloads = getFunctionOverloads(metaFunction->ownerClass(), metaFunction->name());
+
+ int minArgs = std::numeric_limits<int>::max();
+ int maxArgs = 0;
+ for (const AbstractMetaFunction* func : qAsConst(overloads)) {
+ int numArgs = 0;
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (const AbstractMetaArgument *arg : arguments) {
+ if (!func->argumentRemoved(arg->argumentIndex() + 1))
+ numArgs++;
+ }
+ maxArgs = std::max(maxArgs, numArgs);
+ minArgs = std::min(minArgs, numArgs);
+ }
+ return qMakePair(minArgs, maxArgs);
+}
+
+QMap<QString, QString> ShibokenGenerator::options() const
+{
+ QMap<QString, QString> opts(Generator::options());
+ opts.insert(QLatin1String(AVOID_PROTECTED_HACK),
+ QLatin1String("Avoid the use of the '#define protected public' hack."));
+ opts.insert(QLatin1String(PARENT_CTOR_HEURISTIC),
+ QLatin1String("Enable heuristics to detect parent relationship on constructors."));
+ opts.insert(QLatin1String(RETURN_VALUE_HEURISTIC),
+ QLatin1String("Enable heuristics to detect parent relationship on return values (USE WITH CAUTION!)"));
+ opts.insert(QLatin1String(ENABLE_PYSIDE_EXTENSIONS),
+ QLatin1String("Enable PySide extensions, such as support for signal/slots, use this if you are creating a binding for a Qt-based library."));
+ opts.insert(QLatin1String(DISABLE_VERBOSE_ERROR_MESSAGES),
+ QLatin1String("Disable verbose error messages. Turn the python code hard to debug but safe few kB on the generated bindings."));
+ opts.insert(QLatin1String(USE_ISNULL_AS_NB_NONZERO),
+ QLatin1String("If a class have an isNull()const method, it will be used to compute the value of boolean casts"));
+ return opts;
+}
+
+static void getCode(QStringList& code, const CodeSnipList& codeSnips)
+{
+ for (const CodeSnip &snip : qAsConst(codeSnips))
+ code.append(snip.code());
+}
+
+static void getCode(QStringList& code, const TypeEntry* type)
+{
+ getCode(code, type->codeSnips());
+
+ CustomConversion* customConversion = type->customConversion();
+ if (!customConversion)
+ return;
+
+ if (!customConversion->nativeToTargetConversion().isEmpty())
+ code.append(customConversion->nativeToTargetConversion());
+
+ const CustomConversion::TargetToNativeConversions& toCppConversions = customConversion->targetToNativeConversions();
+ if (toCppConversions.isEmpty())
+ return;
+
+ for (CustomConversion::TargetToNativeConversion *toNative : qAsConst(toCppConversions))
+ code.append(toNative->conversion());
+}
+
+bool ShibokenGenerator::doSetup(const QMap<QString, QString>& args)
+{
+ m_useCtorHeuristic = args.contains(QLatin1String(PARENT_CTOR_HEURISTIC));
+ m_usePySideExtensions = args.contains(QLatin1String(ENABLE_PYSIDE_EXTENSIONS));
+ m_userReturnValueHeuristic = args.contains(QLatin1String(RETURN_VALUE_HEURISTIC));
+ m_verboseErrorMessagesDisabled = args.contains(QLatin1String(DISABLE_VERBOSE_ERROR_MESSAGES));
+ m_useIsNullAsNbNonZero = args.contains(QLatin1String(USE_ISNULL_AS_NB_NONZERO));
+ m_avoidProtectedHack = args.contains(QLatin1String(AVOID_PROTECTED_HACK));
+
+ TypeDatabase* td = TypeDatabase::instance();
+ QStringList snips;
+ const PrimitiveTypeEntryList &primitiveTypeList = primitiveTypes();
+ for (const PrimitiveTypeEntry *type : primitiveTypeList)
+ getCode(snips, type);
+ const ContainerTypeEntryList &containerTypeList = containerTypes();
+ for (const ContainerTypeEntry *type : containerTypeList)
+ getCode(snips, type);
+ const AbstractMetaClassList &classList = classes();
+ for (const AbstractMetaClass *metaClass : classList)
+ getCode(snips, metaClass->typeEntry());
+ getCode(snips, td->findType(packageName()));
+ const FunctionGroupMap &functionGroups = getFunctionGroups();
+ for (FunctionGroupMapIt it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) {
+ for (AbstractMetaFunction *func : it.value())
+ getCode(snips, func->injectedCodeSnips());
+ }
+
+ for (const QString &code : qAsConst(snips)) {
+ collectContainerTypesFromConverterMacros(code, true);
+ collectContainerTypesFromConverterMacros(code, false);
+ }
+
+ return true;
+}
+
+void ShibokenGenerator::collectContainerTypesFromConverterMacros(const QString& code, bool toPythonMacro)
+{
+ QString convMacro = toPythonMacro ? QLatin1String("%CONVERTTOPYTHON[") : QLatin1String("%CONVERTTOCPP[");
+ int offset = toPythonMacro ? sizeof("%CONVERTTOPYTHON") : sizeof("%CONVERTTOCPP");
+ int start = 0;
+ while ((start = code.indexOf(convMacro, start)) != -1) {
+ int end = code.indexOf(QLatin1Char(']'), start);
+ start += offset;
+ if (code.at(start) != QLatin1Char('%')) {
+ QString typeString = code.mid(start, end - start);
+ AbstractMetaType* type = buildAbstractMetaTypeFromString(typeString);
+ addInstantiatedContainersAndSmartPointers(type, type->originalTypeDescription());
+ }
+ start = end;
+ }
+}
+
+bool ShibokenGenerator::useCtorHeuristic() const
+{
+ return m_useCtorHeuristic;
+}
+
+bool ShibokenGenerator::useReturnValueHeuristic() const
+{
+ return m_userReturnValueHeuristic;
+}
+
+bool ShibokenGenerator::usePySideExtensions() const
+{
+ return m_usePySideExtensions;
+}
+
+bool ShibokenGenerator::useIsNullAsNbNonZero() const
+{
+ return m_useIsNullAsNbNonZero;
+}
+
+bool ShibokenGenerator::avoidProtectedHack() const
+{
+ return m_avoidProtectedHack;
+}
+
+QString ShibokenGenerator::cppApiVariableName(const QString& moduleName) const
+{
+ QString result = moduleName.isEmpty() ? ShibokenGenerator::packageName() : moduleName;
+ result.replace(QLatin1Char('.'), QLatin1Char('_'));
+ result.prepend(QLatin1String("Sbk"));
+ result.append(QLatin1String("Types"));
+ return result;
+}
+
+QString ShibokenGenerator::convertersVariableName(const QString& moduleName) const
+{
+ QString result = cppApiVariableName(moduleName);
+ result.chop(1);
+ result.append(QLatin1String("Converters"));
+ return result;
+}
+
+static QString processInstantiationsVariableName(const AbstractMetaType* type)
+{
+ QString res = QLatin1Char('_') + _fixedCppTypeName(type->typeEntry()->qualifiedCppName()).toUpper();
+ const AbstractMetaTypeList &instantiations = type->instantiations();
+ for (const AbstractMetaType *instantiation : instantiations) {
+ res += instantiation->isContainer()
+ ? processInstantiationsVariableName(instantiation)
+ : QLatin1Char('_') + _fixedCppTypeName(instantiation->cppSignature()).toUpper();
+ }
+ return res;
+}
+QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClass* metaClass, bool alternativeTemplateName)
+{
+ if (alternativeTemplateName) {
+ const AbstractMetaClass* templateBaseClass = metaClass->templateBaseClass();
+ if (!templateBaseClass)
+ return QString();
+ QString base = _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper();
+ QString instantiations;
+ const AbstractMetaTypeList &templateBaseClassInstantiations = metaClass->templateBaseClassInstantiations();
+ for (const AbstractMetaType *instantiation : templateBaseClassInstantiations)
+ instantiations += processInstantiationsVariableName(instantiation);
+ return QString::fromLatin1("SBK_%1%2_IDX").arg(base, instantiations);
+ }
+ return getTypeIndexVariableName(metaClass->typeEntry());
+}
+QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry* type)
+{
+ if (type->isCppPrimitive()) {
+ const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type;
+ if (trueType->basicReferencedTypeEntry())
+ type = trueType->basicReferencedTypeEntry();
+ }
+ return QString::fromLatin1("SBK_%1_IDX").arg(_fixedCppTypeName(type->qualifiedCppName()).toUpper());
+}
+QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType* type)
+{
+ return QString::fromLatin1("SBK%1%2_IDX")
+ .arg(type->typeEntry()->isContainer() ? QLatin1Char('_') + moduleName().toUpper() : QString(),
+ processInstantiationsVariableName(type));
+}
+
+bool ShibokenGenerator::verboseErrorMessagesDisabled() const
+{
+ return m_verboseErrorMessagesDisabled;
+}
+
+bool ShibokenGenerator::pythonFunctionWrapperUsesListOfArguments(const OverloadData& overloadData)
+{
+ if (overloadData.referenceFunction()->isCallOperator())
+ return true;
+ if (overloadData.referenceFunction()->isOperatorOverload())
+ return false;
+ int maxArgs = overloadData.maxArgs();
+ int minArgs = overloadData.minArgs();
+ return (minArgs != maxArgs)
+ || (maxArgs > 1)
+ || overloadData.referenceFunction()->isConstructor()
+ || overloadData.hasArgumentWithDefaultValue();
+}
+
+Generator::Options ShibokenGenerator::getConverterOptions(const AbstractMetaType* metaType)
+{
+ // exclude const on Objects
+ Options flags;
+ const TypeEntry* type = metaType->typeEntry();
+ bool isCStr = isCString(metaType);
+ if (metaType->indirections() && !isCStr) {
+ flags = ExcludeConst;
+ } else if (metaType->isContainer()
+ || (type->isPrimitive() && !isCStr)
+ // const refs become just the value, but pure refs must remain pure.
+ || (type->isValue() && metaType->isConstant() && metaType->referenceType() == LValueReference)) {
+ flags = ExcludeConst | ExcludeReference;
+ }
+ return flags;
+}
+
+QString ShibokenGenerator::getDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg)
+{
+ if (!arg->defaultValueExpression().isEmpty())
+ return arg->defaultValueExpression();
+
+ //Check modifications
+ const FunctionModificationList &mods = func->modifications();
+ for (const FunctionModification &m : mods) {
+ for (const ArgumentModification &am : m.argument_mods) {
+ if (am.index == (arg->argumentIndex() + 1))
+ return am.replacedDefaultExpression;
+ }
+ }
+ return QString();
+}
+
+void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const AbstractMetaType* type, const QString& defaultCtor)
+{
+ if (defaultCtor.isEmpty() && isCppPrimitive(type))
+ return;
+ QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor;
+ if (ctor.isEmpty()) {
+ const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->cppSignature());
+ qCWarning(lcShiboken()).noquote() << message;
+ s << ";\n#error " << message << '\n';
+ } else {
+ s << " = " << ctor;
+ }
+}
+
+void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const TypeEntry* type, const QString& defaultCtor)
+{
+ if (defaultCtor.isEmpty() && isCppPrimitive(type))
+ return;
+ QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor;
+
+ if (ctor.isEmpty()) {
+ const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->qualifiedCppName());
+ qCWarning(lcShiboken()).noquote() << message;
+ s << ";\n#error " << message << endl;
+ } else {
+ s << " = " << ctor;
+ }
+}
+
+bool ShibokenGenerator::isCppIntegralPrimitive(const TypeEntry* type)
+{
+ if (!type->isCppPrimitive())
+ return false;
+ const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type;
+ if (trueType->basicReferencedTypeEntry())
+ trueType = trueType->basicReferencedTypeEntry();
+ QString typeName = trueType->qualifiedCppName();
+ return !typeName.contains(QLatin1String("double"))
+ && !typeName.contains(QLatin1String("float"))
+ && !typeName.contains(QLatin1String("wchar"));
+}
+bool ShibokenGenerator::isCppIntegralPrimitive(const AbstractMetaType* type)
+{
+ return isCppIntegralPrimitive(type->typeEntry());
+}
+
+QString ShibokenGenerator::msgCouldNotFindMinimalConstructor(const QString &where, const QString &type)
+{
+ return where + QLatin1String(": Could not find a minimal constructor for type '") + type
+ + QLatin1String("'. This will result in a compilation error.");
+}
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
new file mode 100644
index 000000000..1be56edc8
--- /dev/null
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
@@ -0,0 +1,556 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SHIBOKENGENERATOR_H
+#define SHIBOKENGENERATOR_H
+
+#define CONV_RULE_OUT_VAR_SUFFIX "_out"
+#define CPP_ARG "cppArg"
+#define CPP_ARG0 CPP_ARG"0"
+#define CPP_ARG_REMOVED "removed_" CPP_ARG
+#define CPP_RETURN_VAR "cppResult"
+#define CPP_SELF_VAR "cppSelf"
+#define PYTHON_ARG "pyArg"
+#define PYTHON_ARGS PYTHON_ARG "s"
+#define PYTHON_OVERRIDE_VAR "pyOverride"
+#define PYTHON_RETURN_VAR "pyResult"
+#define PYTHON_SELF_VAR "self"
+#define THREAD_STATE_SAVER_VAR "threadStateSaver"
+#define BEGIN_ALLOW_THREADS "PyThreadState* _save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS"
+#define END_ALLOW_THREADS "PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS"
+#define PYTHON_TO_CPP_VAR "pythonToCpp"
+#define SMART_POINTER_GETTER "kSmartPointerGetter"
+
+#define CHECKTYPE_REGEX "%CHECKTYPE\\[([^\\[]*)\\]\\("
+#define ISCONVERTIBLE_REGEX "%ISCONVERTIBLE\\[([^\\[]*)\\]\\("
+#define CONVERTTOPYTHON_REGEX "%CONVERTTOPYTHON\\[([^\\[]*)\\]\\("
+#define CONVERTTOCPP_REGEX "(\\*?%?[a-zA-Z_][\\w\\.]*(?:\\[[^\\[^<^>]+\\])*)"\
+ "(?:\\s+)=(?:\\s+)%CONVERTTOCPP\\[([^\\[]*)\\]\\("
+
+#include <generator.h>
+
+#include "typesystem.h"
+
+#include <QtCore/QRegularExpression>
+
+class DocParser;
+class CodeSnip;
+class OverloadData;
+
+QT_FORWARD_DECLARE_CLASS(QTextStream)
+
+/**
+ * Abstract generator that contains common methods used in CppGenerator and HeaderGenerator.
+ */
+class ShibokenGenerator : public Generator
+{
+public:
+ ShibokenGenerator();
+ virtual ~ShibokenGenerator();
+
+ QString translateTypeForWrapperMethod(const AbstractMetaType* cType,
+ const AbstractMetaClass* context, Options opt = NoOption) const;
+
+ /**
+ * Returns a map with all functions grouped, the function name is used as key.
+ * Example of return value: { "foo" -> ["foo(int)", "foo(int, long)], "bar" -> "bar(double)"}
+ * \param scope Where to search for functions, null means all global functions.
+ */
+ QMap<QString, AbstractMetaFunctionList> getFunctionGroups(const AbstractMetaClass* scope = 0);
+
+ /**
+ * Returns all different inherited overloads of func.
+ * The function can be called multiple times without duplication.
+ * \param func the metafunction to be searched in subclasses.
+ * \param seen the function's minimal signatures already seen.
+ */
+ AbstractMetaFunctionList getInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen);
+
+ /**
+ * Returns all different inherited overloads of func, and includes func as well.
+ * The function can be called multiple times without duplication.
+ * \param func the metafunction to be searched in subclasses.
+ * \param seen the function's minimal signatures already seen.
+ */
+ AbstractMetaFunctionList getFunctionAndInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen);
+
+ /**
+ * Returns all overloads for a function named \p functionName.
+ * \param scope scope used to search for overloads.
+ * \param functionName the function name.
+ */
+ AbstractMetaFunctionList getFunctionOverloads(const AbstractMetaClass* scope, const QString& functionName);
+ /**
+ * Returns the minimun and maximun number of arguments which this function and all overloads
+ * can accept. Arguments removed by typesystem are considered as well.
+ */
+ QPair<int, int> getMinMaxArguments(const AbstractMetaFunction* metaFunction);
+ /**
+ * Write a function argument in the C++ in the text stream \p s.
+ * This function just call \code s << argumentString(); \endcode
+ * \param s text stream used to write the output.
+ * \param func the current metafunction.
+ * \param argument metaargument information to be parsed.
+ * \param options some extra options.
+ */
+ void writeArgument(QTextStream &s,
+ const AbstractMetaFunction* func,
+ const AbstractMetaArgument* argument,
+ Options options = NoOption) const;
+ /**
+ * Create a QString in the C++ format to an function argument.
+ * \param func the current metafunction.
+ * \param argument metaargument information to be parsed.
+ * \param options some extra options.
+ */
+ QString argumentString(const AbstractMetaFunction* func,
+ const AbstractMetaArgument* argument,
+ Options options = NoOption) const;
+
+ void writeArgumentNames(QTextStream &s,
+ const AbstractMetaFunction* func,
+ Options options = NoOption) const override;
+
+ /**
+ * Function used to write the fucntion arguments on the class buffer.
+ * \param s the class output buffer
+ * \param func the pointer to metafunction information
+ * \param count the number of function arguments
+ * \param options some extra options used during the parser
+ */
+ void writeFunctionArguments(QTextStream &s,
+ const AbstractMetaFunction* func,
+ Options options = NoOption) const override;
+ QString functionReturnType(const AbstractMetaFunction* func, Options options = NoOption) const;
+
+ /// Utility function for writeCodeSnips.
+ typedef QPair<const AbstractMetaArgument*, QString> ArgumentVarReplacementPair;
+ typedef QVector<ArgumentVarReplacementPair> ArgumentVarReplacementList;
+ ArgumentVarReplacementList getArgumentReplacement(const AbstractMetaFunction* func,
+ bool usePyArgs, TypeSystem::Language language,
+ const AbstractMetaArgument* lastArg);
+
+ /// Write user's custom code snippets at class or module level.
+ void writeCodeSnips(QTextStream& s,
+ const QVector<CodeSnip> & codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language,
+ const AbstractMetaClass* context = 0);
+ /// Write user's custom code snippets at function level.
+ void writeCodeSnips(QTextStream& s,
+ const QVector<CodeSnip> & codeSnips,
+ TypeSystem::CodeSnipPosition position,
+ TypeSystem::Language language,
+ const AbstractMetaFunction* func,
+ const AbstractMetaArgument* lastArg = 0);
+
+ /// Returns a string with the user's custom code snippets that comply with \p position and \p language.
+ QString getCodeSnippets(const QVector<CodeSnip> & codeSnips, TypeSystem::CodeSnipPosition position, TypeSystem::Language language);
+
+ /// Replaces variables for the user's custom code at global or class level.
+ void processCodeSnip(QString& code, const AbstractMetaClass* context = 0);
+
+ /// Replaces the %CONVERTTOPYTHON type system variable.
+ inline void replaceConvertToPythonTypeSystemVariable(QString& code)
+ {
+ replaceConverterTypeSystemVariable(TypeSystemToPythonFunction, code);
+ }
+ /// Replaces the %CONVERTTOCPP type system variable.
+ inline void replaceConvertToCppTypeSystemVariable(QString& code)
+ {
+ replaceConverterTypeSystemVariable(TypeSystemToCppFunction, code);
+ }
+ /// Replaces the %ISCONVERTIBLE type system variable.
+ inline void replaceIsConvertibleToCppTypeSystemVariable(QString& code)
+ {
+ replaceConverterTypeSystemVariable(TypeSystemIsConvertibleFunction, code);
+ }
+ /// Replaces the %CHECKTYPE type system variable.
+ inline void replaceTypeCheckTypeSystemVariable(QString& code)
+ {
+ replaceConverterTypeSystemVariable(TypeSystemCheckFunction, code);
+ }
+
+ /**
+ * Verifies if any of the function's code injections of the "target"
+ * type needs the type system variable "%CPPSELF".
+ * \param func the function to check
+ * \return true if the function's target code snippets use "%CPPSELF"
+ */
+ bool injectedCodeUsesCppSelf(const AbstractMetaFunction* func);
+
+ /**
+ * Verifies if any of the function's code injections of the "native"
+ * type needs the type system variable "%PYSELF".
+ * \param func the function to check
+ * \return true if the function's native code snippets use "%PYSELF"
+ */
+ bool injectedCodeUsesPySelf(const AbstractMetaFunction* func);
+
+ /**
+ * Verifies if any of the function's code injections makes a call
+ * to the C++ method. This is used by the generator to avoid writing calls
+ * to C++ when the user custom code already does this.
+ * \param func the function to check
+ * \return true if the function's code snippets call the wrapped C++ function
+ */
+ bool injectedCodeCallsCppFunction(const AbstractMetaFunction* func);
+
+ /**
+ * Verifies if any of the function's code injections of the "native" class makes a
+ * call to the C++ method. This is used by the generator to avoid writing calls to
+ * Python overrides of C++ virtual methods when the user custom code already does this.
+ * \param func the function to check
+ * \return true if the function's code snippets call the Python override for a C++ virtual method
+ */
+ bool injectedCodeCallsPythonOverride(const AbstractMetaFunction* func);
+
+ /**
+ * Verifies if any of the function's code injections attributes values to
+ * the return variable (%0 or %PYARG_0).
+ * \param func the function to check
+ * \param language the kind of code snip
+ * \return true if the function's code attributes values to "%0" or "%PYARG_0"
+ */
+ bool injectedCodeHasReturnValueAttribution(const AbstractMetaFunction* func, TypeSystem::Language language = TypeSystem::TargetLangCode);
+
+ /**
+ * Verifies if any of the function's code injections uses the type system variable
+ * for function arguments of a given index.
+ */
+ bool injectedCodeUsesArgument(const AbstractMetaFunction* func, int argumentIndex);
+
+ /**
+ * Function which parse the metafunction information
+ * \param func the function witch will be parserd
+ * \param option some extra options
+ * \param arg_count the number of function arguments
+ */
+ QString functionSignature(const AbstractMetaFunction* func,
+ QString prepend = QString(),
+ QString append = QString(),
+ Options options = NoOption,
+ int arg_count = -1) const;
+
+ /// Returns true if there are cases of multiple inheritance in any of its ancestors.
+ bool hasMultipleInheritanceInAncestry(const AbstractMetaClass* metaClass);
+
+ /// Returns true if the class needs to have a getattro function.
+ bool classNeedsGetattroFunction(const AbstractMetaClass* metaClass);
+
+ /// Returns true if the class needs to have a setattro function.
+ bool classNeedsSetattroFunction(const AbstractMetaClass *metaClass);
+
+ /// Returns a list of methods of the given class where each one is part of a different overload with both static and non-static method.
+ AbstractMetaFunctionList getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass* metaClass);
+
+ /// Returns a list of parent classes for a given class.
+ AbstractMetaClassList getBaseClasses(const AbstractMetaClass* metaClass) const;
+
+ /// Returns a list of all ancestor classes for the given class.
+ AbstractMetaClassList getAllAncestors(const AbstractMetaClass* metaClass) const;
+
+ const AbstractMetaClass* getMultipleInheritingClass(const AbstractMetaClass* metaClass);
+
+ void writeToPythonConversion(QTextStream& s, const AbstractMetaType* type,
+ const AbstractMetaClass* context, const QString& argumentName);
+ void writeToCppConversion(QTextStream& s, const AbstractMetaType* type, const AbstractMetaClass* context, const QString& inArgName, const QString& outArgName);
+ void writeToCppConversion(QTextStream& s, const AbstractMetaClass* metaClass, const QString& inArgName, const QString& outArgName);
+
+ /// Returns true if the argument is a pointer that rejects NULL values.
+ bool shouldRejectNullPointerArgument(const AbstractMetaFunction* func, int argIndex);
+
+ /// Verifies if the class should have a C++ wrapper generated for it, instead of only a Python wrapper.
+ bool shouldGenerateCppWrapper(const AbstractMetaClass* metaClass) const;
+
+ /// Adds enums eligible for generation from classes/namespaces marked not to be generated.
+ static void lookForEnumsInClassesNotToBeGenerated(AbstractMetaEnumList& enumList, const AbstractMetaClass* metaClass);
+ /// Returns the enclosing class for an enum, or NULL if it should be global.
+ const AbstractMetaClass* getProperEnclosingClassForEnum(const AbstractMetaEnum* metaEnum);
+
+ QString wrapperName(const AbstractMetaClass* metaClass) const;
+ QString wrapperName(const AbstractMetaType *metaType) const;
+
+ static QString fullPythonFunctionName(const AbstractMetaFunction* func);
+ static QString protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum);
+ static QString protectedFieldGetterName(const AbstractMetaField* field);
+ static QString protectedFieldSetterName(const AbstractMetaField* field);
+
+ static QString pythonPrimitiveTypeName(const QString& cppTypeName);
+ static QString pythonPrimitiveTypeName(const PrimitiveTypeEntry* type);
+
+ static QString pythonOperatorFunctionName(QString cppOpFuncName);
+ static QString pythonOperatorFunctionName(const AbstractMetaFunction* func);
+ static QString pythonRichCompareOperatorId(QString cppOpFuncName);
+ static QString pythonRichCompareOperatorId(const AbstractMetaFunction* func);
+
+ static QString cpythonOperatorFunctionName(const AbstractMetaFunction* func);
+
+ static QString fixedCppTypeName(const CustomConversion::TargetToNativeConversion* toNative);
+ static QString fixedCppTypeName(const AbstractMetaType* type);
+ static QString fixedCppTypeName(const TypeEntry* type, QString typeName = QString());
+
+ static bool isNumber(QString cpythonApiName);
+ static bool isNumber(const TypeEntry* type);
+ static bool isNumber(const AbstractMetaType* type);
+ static bool isPyInt(const TypeEntry* type);
+ static bool isPyInt(const AbstractMetaType* type);
+ static bool isPairContainer(const AbstractMetaType* type);
+
+ /**
+ * Returns true if the type passed has a Python wrapper for it.
+ * Although namespace has a Python wrapper, it's not considered a type.
+ */
+ static bool isWrapperType(const TypeEntry* type);
+ static bool isWrapperType(const ComplexTypeEntry* type);
+ static bool isWrapperType(const AbstractMetaType* metaType);
+
+ /**
+ * Checks if the type is an Object/QObject or pointer to Value Type.
+ * In other words, tells if the type is "T*" and T has a Python wrapper.
+ */
+ static bool isPointerToWrapperType(const AbstractMetaType* type);
+
+ /**
+ * Returns true if \p type is an Object Type used as a value.
+ */
+ static bool isObjectTypeUsedAsValueType(const AbstractMetaType* type);
+
+ static bool isValueTypeWithCopyConstructorOnly(const AbstractMetaClass* metaClass);
+ bool isValueTypeWithCopyConstructorOnly(const TypeEntry* type) const;
+ bool isValueTypeWithCopyConstructorOnly(const AbstractMetaType* type) const;
+
+ /// Returns true if the type is a primitive but not a C++ primitive.
+ static bool isUserPrimitive(const TypeEntry* type);
+ static bool isUserPrimitive(const AbstractMetaType* type);
+
+ /// Returns true if the type is a C++ primitive, a void*, a const char*, or a std::string.
+ static bool isCppPrimitive(const TypeEntry* type);
+ static bool isCppPrimitive(const AbstractMetaType* type);
+
+ /// Returns true if the type is a C++ integral primitive, i.e. bool, char, int, long, and their unsigned counterparts.
+ static bool isCppIntegralPrimitive(const TypeEntry* type);
+ static bool isCppIntegralPrimitive(const AbstractMetaType* type);
+
+ /// Checks if an argument type should be dereferenced by the Python method wrapper before calling the C++ method.
+ static bool shouldDereferenceArgumentPointer(const AbstractMetaArgument* arg);
+ /// Checks if a meta type should be dereferenced by the Python method wrapper passing it to C++.
+ static bool shouldDereferenceAbstractMetaTypePointer(const AbstractMetaType* metaType);
+
+ static bool visibilityModifiedToPrivate(const AbstractMetaFunction* func);
+
+ QString converterObject(const AbstractMetaType* type);
+ QString converterObject(const TypeEntry* type);
+
+ QString cpythonBaseName(const AbstractMetaClass* metaClass);
+ QString cpythonBaseName(const TypeEntry* type);
+ QString cpythonBaseName(const AbstractMetaType* type);
+ QString cpythonTypeName(const AbstractMetaClass* metaClass);
+ QString cpythonTypeName(const TypeEntry* type);
+ QString cpythonTypeNameExt(const TypeEntry* type);
+ QString cpythonTypeNameExt(const AbstractMetaType* type);
+ QString cpythonCheckFunction(const TypeEntry* type, bool genericNumberType = false);
+ QString cpythonCheckFunction(const AbstractMetaType* metaType, bool genericNumberType = false);
+ /**
+ * Receives the argument \p type and tries to find the appropriate AbstractMetaType for it
+ * or a custom type check.
+ * \param type A string representing the type to be discovered.
+ * \param metaType A pointer to an AbstractMetaType pointer, to where write a new meta type object
+ * if one is produced from the \p type string. This object must be deallocated by
+ * the caller. It will set the target variable to NULL, is \p type is a Python type.
+ * \return A custom check if \p type is a custom type, or an empty string if \p metaType
+ * receives an existing type object.
+ */
+ QString guessCPythonCheckFunction(const QString& type, AbstractMetaType** metaType);
+ QString cpythonIsConvertibleFunction(const TypeEntry* type, bool genericNumberType = false, bool checkExact = false);
+ QString cpythonIsConvertibleFunction(const AbstractMetaType* metaType, bool genericNumberType = false);
+ QString cpythonIsConvertibleFunction(const AbstractMetaArgument* metaArg, bool genericNumberType = false);
+ QString guessCPythonIsConvertible(const QString& type);
+
+ QString cpythonToCppConversionFunction(const AbstractMetaClass* metaClass);
+ QString cpythonToCppConversionFunction(const AbstractMetaType* type, const AbstractMetaClass* context = 0);
+ QString cpythonToPythonConversionFunction(const AbstractMetaType* type, const AbstractMetaClass* context = 0);
+ QString cpythonToPythonConversionFunction(const AbstractMetaClass* metaClass);
+ QString cpythonToPythonConversionFunction(const TypeEntry* type);
+
+ QString cpythonFunctionName(const AbstractMetaFunction* func);
+ QString cpythonMethodDefinitionName(const AbstractMetaFunction* func);
+ QString cpythonGettersSettersDefinitionName(const AbstractMetaClass* metaClass);
+ QString cpythonGetattroFunctionName(const AbstractMetaClass* metaClass);
+ QString cpythonSetattroFunctionName(const AbstractMetaClass* metaClass);
+ QString cpythonGetterFunctionName(const AbstractMetaField* metaField);
+ QString cpythonSetterFunctionName(const AbstractMetaField* metaField);
+ QString cpythonWrapperCPtr(const AbstractMetaClass* metaClass, QString argName = QLatin1String(PYTHON_SELF_VAR));
+ QString cpythonWrapperCPtr(const AbstractMetaType *metaType, QString argName);
+ QString cpythonWrapperCPtr(const TypeEntry* type, QString argName);
+
+ /// Guesses the scope to where belongs an argument's default value.
+ QString guessScopeForDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg);
+
+ QString cpythonEnumName(const EnumTypeEntry* enumEntry);
+ QString cpythonEnumName(const AbstractMetaEnum* metaEnum);
+
+ QString cpythonFlagsName(const FlagsTypeEntry* flagsEntry);
+ QString cpythonFlagsName(const AbstractMetaEnum* metaEnum);
+ /// Returns the special cast function name, the function used to proper cast class with multiple inheritance.
+ QString cpythonSpecialCastFunctionName(const AbstractMetaClass* metaClass);
+
+ QString getFunctionReturnType(const AbstractMetaFunction* func, Options options = NoOption) const;
+ QString getFormatUnitString(const AbstractMetaFunction* func, bool incRef = false) const;
+
+ /// Returns the file name for the module global header. If no module name is provided the current will be used.
+ QString getModuleHeaderFileName(const QString& moduleName = QString()) const;
+
+ QString extendedIsConvertibleFunctionName(const TypeEntry* targetType) const;
+ QString extendedToCppFunctionName(const TypeEntry* targetType) const;
+
+ QMap< QString, QString > options() const override;
+
+ /// Returns true if the user enabled the so called "parent constructor heuristic".
+ bool useCtorHeuristic() const;
+ /// Returns true if the user enabled the so called "return value heuristic".
+ bool useReturnValueHeuristic() const;
+ /// Returns true if the user enabled PySide extensions.
+ bool usePySideExtensions() const;
+ /// Returns true if the generator should use the result of isNull()const to compute boolean casts.
+ bool useIsNullAsNbNonZero() const;
+ /// Returns true if the generated code should use the "#define protected public" hack.
+ bool avoidProtectedHack() const;
+ QString cppApiVariableName(const QString& moduleName = QString()) const;
+ QString convertersVariableName(const QString& moduleName = QString()) const;
+ /**
+ * Returns the type index variable name for a given class. If \p alternativeTemplateName is true
+ * and the class is a typedef for a template class instantiation, it will return an alternative name
+ * made of the template class and the instantiation values, or an empty string if the class isn't
+ * derived from a template class at all.
+ */
+ QString getTypeIndexVariableName(const AbstractMetaClass* metaClass, bool alternativeTemplateName = false);
+ QString getTypeIndexVariableName(const TypeEntry* type);
+ QString getTypeIndexVariableName(const AbstractMetaType* type);
+
+ /// Returns true if the user don't want verbose error messages on the generated bindings.
+ bool verboseErrorMessagesDisabled() const;
+
+ /**
+ * Builds an AbstractMetaType object from a QString.
+ * Returns NULL if no type could be built from the string.
+ * \param typeSignature The string describing the type to be built.
+ * \return A new AbstractMetaType object that must be deleted by the caller, or a NULL pointer in case of failure.
+ */
+ AbstractMetaType* buildAbstractMetaTypeFromString(QString typeSignature);
+
+ /// Creates an AbstractMetaType object from a TypeEntry.
+ AbstractMetaType* buildAbstractMetaTypeFromTypeEntry(const TypeEntry* typeEntry);
+ /// Creates an AbstractMetaType object from an AbstractMetaClass.
+ AbstractMetaType* buildAbstractMetaTypeFromAbstractMetaClass(const AbstractMetaClass* metaClass);
+
+ void writeMinimalConstructorExpression(QTextStream& s, const AbstractMetaType* type, const QString& defaultCtor = QString());
+ void writeMinimalConstructorExpression(QTextStream& s, const TypeEntry* type, const QString& defaultCtor = QString());
+
+ /**
+ * Helper function to return the flags to be used by a meta type when
+ * it needs to write some converter code.
+ */
+ static Options getConverterOptions(const AbstractMetaType* metaType);
+
+ /**
+ * Helper function to find for argument default value
+ */
+ static QString getDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg);
+protected:
+ bool doSetup(const QMap<QString, QString>& args);
+ void collectContainerTypesFromConverterMacros(const QString& code, bool toPythonMacro);
+ // verify whether the class is copyable
+ bool isCopyable(const AbstractMetaClass* metaClass);
+
+ bool m_native_jump_table;
+ static QHash<QString, QString> m_pythonPrimitiveTypeName;
+ static QHash<QString, QString> m_pythonOperators;
+ static QHash<QString, QString> m_formatUnits;
+ static QHash<QString, QString> m_tpFuncs;
+ static QStringList m_knownPythonTypes;
+
+ void clearTpFuncs();
+
+ const char* name() const { return "Shiboken"; }
+
+ /// Initializes correspondences between primitive and Python types.
+ static void initPrimitiveTypesCorrespondences();
+ /// Initializes a list of Python known type names.
+ static void initKnownPythonTypes();
+
+ void writeFunctionCall(QTextStream& s,
+ const AbstractMetaFunction* metaFunc,
+ Options options = NoOption) const;
+
+ void writeUnusedVariableCast(QTextStream& s, const QString& variableName);
+
+ AbstractMetaFunctionList filterFunctions(const AbstractMetaClass* metaClass);
+
+ // All data about extended converters: the type entries of the target type, and a
+ // list of AbstractMetaClasses accepted as argument for the conversion.
+ typedef QHash<const TypeEntry *, QVector<const AbstractMetaClass *> > ExtendedConverterData;
+ /// Returns all extended conversions for the current module.
+ ExtendedConverterData getExtendedConverters() const;
+
+ /// Returns a list of converters for the non wrapper types of the current module.
+ QVector<const CustomConversion *> getPrimitiveCustomConversions();
+
+ /// Returns true if the Python wrapper for the received OverloadData must accept a list of arguments.
+ static bool pythonFunctionWrapperUsesListOfArguments(const OverloadData& overloadData);
+
+ Indentor INDENT;
+
+ enum TypeSystemConverterVariable {
+ TypeSystemCheckFunction = 0,
+ TypeSystemIsConvertibleFunction,
+ TypeSystemToCppFunction,
+ TypeSystemToPythonFunction,
+ TypeSystemConverterVariables
+ };
+ void replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString& code);
+
+ static QString msgCouldNotFindMinimalConstructor(const QString &where, const QString &type);
+
+private:
+ bool m_useCtorHeuristic;
+ bool m_userReturnValueHeuristic;
+ bool m_usePySideExtensions;
+ bool m_verboseErrorMessagesDisabled;
+ bool m_useIsNullAsNbNonZero;
+ bool m_avoidProtectedHack;
+
+ typedef QHash<QString, AbstractMetaType*> AbstractMetaTypeCache;
+ AbstractMetaTypeCache m_metaTypeFromStringCache;
+
+ /// Type system converter variable replacement names and regular expressions.
+ QString m_typeSystemConvName[TypeSystemConverterVariables];
+ QRegularExpression m_typeSystemConvRegEx[TypeSystemConverterVariables];
+};
+
+#endif // SHIBOKENGENERATOR_H