diff options
Diffstat (limited to 'sources/shiboken2/generator/shiboken2')
8 files changed, 875 insertions, 750 deletions
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index 9e1d6926e..adec70dd7 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -29,8 +29,10 @@ #include <memory> #include "cppgenerator.h" +#include "fileout.h" #include "overloaddata.h" #include <abstractmetalang.h> +#include <messages.h> #include <reporthandler.h> #include <typedatabase.h> @@ -41,6 +43,8 @@ #include <QtCore/QDebug> #include <QMetaType> +static const char CPP_ARG0[] = "cppArg0"; + QHash<QString, QString> CppGenerator::m_nbFuncs = QHash<QString, QString>(); QHash<QString, QString> CppGenerator::m_sqFuncs = QHash<QString, QString>(); QHash<QString, QString> CppGenerator::m_mpFuncs = QHash<QString, QString>(); @@ -58,6 +62,28 @@ inline AbstractMetaType* getTypeWithoutContainer(AbstractMetaType* arg) return arg; } +// A helper for writing C++ return statements for either void ("return;") +// or some return value ("return value;") +class returnStatement +{ +public: + explicit returnStatement(QString s) : m_returnValue(std::move(s)) {} + + friend QTextStream &operator<<(QTextStream &s, const returnStatement &r); + +private: + const QString m_returnValue; +}; + +QTextStream &operator<<(QTextStream &s, const returnStatement &r) +{ + s << "return"; + if (!r.m_returnValue.isEmpty()) + s << ' ' << r.m_returnValue; + s << ';'; + return s; +} + CppGenerator::CppGenerator() { // Number protocol structure members names @@ -87,27 +113,27 @@ CppGenerator::CppGenerator() 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"))); + {QLatin1String("PyObject* self"), + QLatin1String("Py_ssize_t")}); m_sequenceProtocol.insert(QLatin1String("__getitem__"), - StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i"), - QLatin1String("PyObject*"))); + {QLatin1String("PyObject* self, 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"))); + {QLatin1String("PyObject* self, 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*"))); + {QLatin1String("PyObject* self, 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"))); + {QLatin1String("PyObject* self, 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"))); + {QLatin1String("PyObject* self, PyObject* _value"), + QLatin1String("int")}); m_sequenceProtocol.insert(QLatin1String("__concat__"), - StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _other"), - QLatin1String("PyObject*"))); + {QLatin1String("PyObject* self, PyObject* _other"), + QLatin1String("PyObject*")}); // Sequence protocol structure members names m_sqFuncs.insert(QLatin1String("__concat__"), QLatin1String("sq_concat")); @@ -120,14 +146,14 @@ CppGenerator::CppGenerator() // mapping protocol function m_mappingProtocol.insert(QLatin1String("__mlen__"), - StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR), - QLatin1String("Py_ssize_t"))); + {QLatin1String("PyObject* self"), + QLatin1String("Py_ssize_t")}); m_mappingProtocol.insert(QLatin1String("__mgetitem__"), - StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _key"), - QLatin1String("PyObject*"))); + {QLatin1String("PyObject* self, PyObject* _key"), + QLatin1String("PyObject*")}); m_mappingProtocol.insert(QLatin1String("__msetitem__"), - StrPair(QLatin1String("PyObject* " PYTHON_SELF_VAR ", PyObject* _key, PyObject* _value"), - QLatin1String("int"))); + {QLatin1String("PyObject* self, PyObject* _key, PyObject* _value"), + QLatin1String("int")}); // Sequence protocol structure members names m_mpFuncs.insert(QLatin1String("__mlen__"), QLatin1String("mp_length")); @@ -186,18 +212,19 @@ QVector<AbstractMetaFunctionList> CppGenerator::filterGroupedOperatorFunctions(c return result; } -bool CppGenerator::hasBoolCast(const AbstractMetaClass* metaClass) const +const AbstractMetaFunction *CppGenerator::boolCast(const AbstractMetaClass* metaClass) const { if (!useIsNullAsNbNonZero()) - return false; + return nullptr; // TODO: This could be configurable someday const AbstractMetaFunction* func = metaClass->findFunction(QLatin1String("isNull")); if (!func || !func->type() || !func->type()->typeEntry()->isPrimitive() || !func->isPublic()) - return false; + return nullptr; 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(); + return func && func->isConstant() && pte->name() == QLatin1String("bool") + && func->arguments().isEmpty() ? func : nullptr; } typedef QMap<QString, AbstractMetaFunctionList> FunctionGroupMap; @@ -219,6 +246,21 @@ static QString chopType(QString s) return s; } +// Helper for field setters: Check for "const QWidget *" (settable field), +// but not "int *const" (read-only field). +static bool isPointerToConst(const AbstractMetaType *t) +{ + const AbstractMetaType::Indirections &indirections = t->indirectionsV(); + return t->isConstant() && !indirections.isEmpty() + && indirections.constLast() != Indirection::ConstPointer; +} + +static inline bool canGenerateFieldSetter(const AbstractMetaField *field) +{ + const AbstractMetaType *type = field->type(); + return !type->isConstant() || isPointerToConst(type); +} + /*! Function used to write the class generated binding code on the buffer \param s the output buffer @@ -260,6 +302,8 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext) // needs the 'set' class from C++ STL. if (hasMultipleInheritanceInAncestry(metaClass)) s << "#include <set>" << endl; + if (metaClass->generateExceptionHandling()) + s << "#include <exception>" << endl; s << endl << "// module include" << endl << "#include \"" << getModuleHeaderFileName() << '"' << endl; @@ -315,7 +359,7 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext) static_cast<const SmartPointerTypeEntry *>(classContext.preciseType() ->typeEntry()); QString rawGetter = typeEntry->getter(); - s << "static const char * " SMART_POINTER_GETTER " = \"" << rawGetter << "\";"; + s << "static const char * " << SMART_POINTER_GETTER << " = \"" << rawGetter << "\";"; } // class inject-code native/beginning @@ -459,7 +503,7 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext) if (metaClass->typeEntry()->isValue() || metaClass->typeEntry()->isSmartPointer()) { writeCopyFunction(s, classContext); - signatureStream << metaClass->fullName() << ".__copy__()" << endl; + signatureStream << fullPythonClassName(metaClass) << ".__copy__()" << endl; } // Write single method definitions @@ -490,16 +534,20 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext) } } - if (hasBoolCast(metaClass)) { + if (const AbstractMetaFunction *f = boolCast(metaClass)) { ErrorCode errorCode(-1); - s << "static int " << cpythonBaseName(metaClass) << "___nb_bool(PyObject* " PYTHON_SELF_VAR ")" << endl; + s << "static int " << cpythonBaseName(metaClass) << "___nb_bool(PyObject* self)" << 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; + if (f->allowThread()) { + 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; + } else { + s << INDENT << "return !" << CPP_SELF_VAR << "->isNull();" << endl; + } s << '}' << endl << endl; } @@ -546,7 +594,7 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext) if (metaField->isStatic()) continue; writeGetterFunction(s, metaField, classContext); - if (!metaField->type()->isConstant()) + if (canGenerateFieldSetter(metaField)) writeSetterFunction(s, metaField, classContext); s << endl; } @@ -557,10 +605,12 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext) 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 << cpythonGetterFunctionName(metaField) << ", "; + if (canGenerateFieldSetter(metaField)) + s << cpythonSetterFunctionName(metaField); + else + s << '0'; s << "}," << endl; } s << INDENT << "{0} // Sentinel" << endl; @@ -686,7 +736,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun Indentation indentation(INDENT); - QString defaultReturnExpr; + DefaultValue defaultReturnExpr; if (retType) { const FunctionModificationList &mods = func->modifications(); for (const FunctionModification &mod : mods) { @@ -694,9 +744,9 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun if (argMod.index == 0 && !argMod.replacedDefaultExpression.isEmpty()) { static const QRegularExpression regex(QStringLiteral("%(\\d+)")); Q_ASSERT(regex.isValid()); - defaultReturnExpr = argMod.replacedDefaultExpression; + QString expr = argMod.replacedDefaultExpression; for (int offset = 0; ; ) { - const QRegularExpressionMatch match = regex.match(defaultReturnExpr, offset); + const QRegularExpressionMatch match = regex.match(expr, offset); if (!match.hasMatch()) break; const int argId = match.capturedRef(1).toInt() - 1; @@ -704,23 +754,27 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun qCWarning(lcShiboken) << "The expression used in return value contains an invalid index."; break; } - defaultReturnExpr.replace(match.captured(0), func->arguments().at(argId)->name()); + expr.replace(match.captured(0), func->arguments().at(argId)->name()); offset = match.capturedStart(1); } + defaultReturnExpr.setType(DefaultValue::Custom); + defaultReturnExpr.setValue(expr); } } } - if (defaultReturnExpr.isEmpty()) + if (!defaultReturnExpr.isValid()) defaultReturnExpr = minimalConstructor(func->type()); - if (defaultReturnExpr.isEmpty()) { + if (!defaultReturnExpr.isValid()) { 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()); + errorMsg = msgCouldNotFindMinimalConstructor(errorMsg, func->type()->cppSignature()); qCWarning(lcShiboken).noquote().nospace() << errorMsg; s << endl << INDENT << "#error " << errorMsg << endl; } + } else { + defaultReturnExpr.setType(DefaultValue::Void); } if (func->isAbstract() && func->isModifiedRemoved()) { @@ -728,7 +782,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun << 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 << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl; s << '}' << endl << endl; return; } @@ -747,13 +801,13 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun s << INDENT << "if (PyErr_Occurred())" << endl; { Indentation indentation(INDENT); - s << INDENT << "return " << defaultReturnExpr << ';' << endl; + s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl; } - s << INDENT << "Shiboken::AutoDecRef " PYTHON_OVERRIDE_VAR "(Shiboken::BindingManager::instance().getOverride(this, \""; + s << INDENT << "Shiboken::AutoDecRef " << PYTHON_OVERRIDE_VAR << "(Shiboken::BindingManager::instance().getOverride(this, \""; s << funcName << "\"));" << endl; - s << INDENT << "if (" PYTHON_OVERRIDE_VAR ".isNull()) {" << endl; + s << INDENT << "if (" << PYTHON_OVERRIDE_VAR << ".isNull()) {" << endl; { Indentation indentation(INDENT); CodeSnipList snips; @@ -768,7 +822,9 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '"; s << func->ownerClass()->name() << '.' << funcName; s << "()' not implemented.\");" << endl; - s << INDENT << "return " << (retType ? defaultReturnExpr : QString()); + s << INDENT << "return"; + if (retType) + s << ' ' << defaultReturnExpr.returnValue(); } else { s << INDENT << "gil.release();" << endl; s << INDENT; @@ -785,7 +841,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun writeConversionRule(s, func, TypeSystem::TargetLangCode); - s << INDENT << "Shiboken::AutoDecRef " PYTHON_ARGS "("; + s << INDENT << "Shiboken::AutoDecRef " << PYTHON_ARGS << "("; if (func->arguments().isEmpty() || allArgumentsRemoved(func)) { s << "PyTuple_New(0));" << endl; @@ -844,7 +900,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun 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; + 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; } @@ -866,36 +922,36 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun if (!injectedCodeCallsPythonOverride(func)) { s << INDENT; - s << "Shiboken::AutoDecRef " PYTHON_RETURN_VAR "(PyObject_Call(" PYTHON_OVERRIDE_VAR ", " PYTHON_ARGS ", NULL));" << endl; + 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; + s << INDENT << "if (" << PYTHON_RETURN_VAR << ".isNull()) {" << endl; { Indentation indent(INDENT); s << INDENT << "PyErr_Print();" << endl; - s << INDENT << "return " << defaultReturnExpr << ';' << endl; + s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl; } s << INDENT << '}' << endl; if (retType) { if (invalidateReturn) - s << INDENT << "bool invalidateArg0 = " PYTHON_RETURN_VAR "->ob_refcnt == 1;" << endl; + 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; + 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 << ", Py_TYPE(" PYTHON_RETURN_VAR ")->tp_name);" << endl; - s << INDENT << "return " << defaultReturnExpr << ';' << endl; + s << ", Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);" << endl; + s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl; } s << INDENT << '}' << endl; @@ -907,15 +963,16 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun isNumber(func->type()->typeEntry()), func->typeReplaced(0)); s << ';' << endl; s << INDENT << "if (!typeIsValid"; - s << (isPointerToWrapperType(func->type()) ? " && " PYTHON_RETURN_VAR " != Py_None" : ""); + if (isPointerToWrapperType(func->type())) + s << " && " << 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 << ", Py_TYPE(" PYTHON_RETURN_VAR ")->tp_name);" << endl; - s << INDENT << "return " << defaultReturnExpr << ';' << endl; + s << ", Py_TYPE(" << PYTHON_RETURN_VAR << ")->tp_name);" << endl; + s << INDENT << returnStatement(defaultReturnExpr.returnValue()) << endl; } s << INDENT << '}' << endl; @@ -935,12 +992,12 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun if (invalidateReturn) { s << INDENT << "if (invalidateArg0)" << endl; Indentation indentation(INDENT); - s << INDENT << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR ".object());" << endl; + 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 << INDENT << "Shiboken::Object::invalidate(PyTuple_GET_ITEM(" << PYTHON_ARGS << ", "; s << (argIndex - 1) << "));" << endl; } @@ -950,9 +1007,9 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun 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; + s << INDENT << "if (Shiboken::Object::checkType(" << PYTHON_RETURN_VAR << "))" << endl; Indentation indent(INDENT); - s << INDENT << "Shiboken::Object::releaseOwnership(" PYTHON_RETURN_VAR ");" << endl; + s << INDENT << "Shiboken::Object::releaseOwnership(" << PYTHON_RETURN_VAR << ");" << endl; } } } @@ -978,7 +1035,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream&s, const AbstractMetaFun } if (func->type()->referenceType() == LValueReference && !isPointer(func->type())) s << '*'; - s << CPP_RETURN_VAR ";" << endl; + s << CPP_RETURN_VAR << ';' << endl; } s << '}' << endl << endl; @@ -995,7 +1052,7 @@ void CppGenerator::writeMetaObjectMethod(QTextStream& s, const AbstractMetaClass 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 << INDENT << "return PySide::SignalManager::retrieveMetaObject(reinterpret_cast<PyObject*>(pySelf));" << endl; s << '}' << endl << endl; // qt_metacall function @@ -1259,7 +1316,7 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla toCppConv = QLatin1Char('*') + cpythonWrapperCPtr(sourceClass->typeEntry(), QLatin1String("pyIn")); } else { // Constructor that does implicit conversion. - if (!conv->typeReplaced(1).isEmpty()) + if (!conv->typeReplaced(1).isEmpty() || conv->isModifiedToArray(1)) continue; const AbstractMetaType* sourceType = conv->arguments().constFirst()->type(); typeCheck = cpythonCheckFunction(sourceType); @@ -1419,7 +1476,7 @@ void CppGenerator::writeConverterRegister(QTextStream &s, const AbstractMetaClas sourceType = buildAbstractMetaTypeFromAbstractMetaClass(conv->ownerClass()); } else { // Constructor that does implicit conversion. - if (!conv->typeReplaced(1).isEmpty()) + if (!conv->typeReplaced(1).isEmpty() || conv->isModifiedToArray(1)) continue; sourceType = conv->arguments().constFirst()->type(); } @@ -1467,7 +1524,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over // 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< ::"; + s << "if (Shiboken::Object::isUserType(self) && !Shiboken::ObjectType::canCallConstructor(self->ob_type, Shiboken::SbkType< ::"; QString qualifiedCppName; if (!context.forSmartPointer()) qualifiedCppName = ownerClass->qualifiedCppName(); @@ -1476,7 +1533,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over s << qualifiedCppName << " >()))" << endl; Indentation indent(INDENT); - s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl; + s << INDENT << returnStatement(m_currentErrorCode) << endl << endl; } // Declare pointer for the underlying C++ object. s << INDENT << "::"; @@ -1497,7 +1554,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over writeCppSelfDefinition(s, rfunc, context, overloadData.hasStaticFunction()); } if (!rfunc->isInplaceOperator() && overloadData.hasNonVoidReturnType()) - s << INDENT << "PyObject* " PYTHON_RETURN_VAR " = 0;" << endl; + s << INDENT << "PyObject* " << PYTHON_RETURN_VAR << " = 0;" << endl; initPythonArguments = minArgs != maxArgs || maxArgs > 1; usesNamedArguments = rfunc->isCallOperator() || overloadData.hasArgumentWithDefaultValue(); @@ -1505,7 +1562,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over if (maxArgs > 0) { s << INDENT << "int overloadId = -1;" << endl; - s << INDENT << "PythonToCppFunc " PYTHON_TO_CPP_VAR; + s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR; if (pythonFunctionWrapperUsesListOfArguments(overloadData)) s << "[] = { 0" << QString::fromLatin1(", 0").repeated(maxArgs-1) << " }"; s << ';' << endl; @@ -1518,7 +1575,7 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over if (initPythonArguments) { s << INDENT << "int numArgs = "; if (minArgs == 0 && maxArgs == 1 && !rfunc->isConstructor() && !pythonFunctionWrapperUsesListOfArguments(overloadData)) - s << "(" PYTHON_ARG " == 0 ? 0 : 1);" << endl; + s << "(" << PYTHON_ARG << " == 0 ? 0 : 1);" << endl; else writeArgumentsInitializer(s, overloadData); } @@ -1534,7 +1591,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun const AbstractMetaClass* metaClass = rfunc->ownerClass(); s << "static int" << endl; - s << cpythonFunctionName(rfunc) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* args, PyObject* kwds)" << endl; + s << cpythonFunctionName(rfunc) << "(PyObject* self, PyObject* args, PyObject* kwds)" << endl; s << '{' << endl; QSet<QString> argNamesSet; @@ -1560,10 +1617,10 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun s << INDENT << "const QMetaObject* metaObject;" << endl; } - s << INDENT << "SbkObject* sbkSelf = reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ");" << endl; + s << INDENT << "SbkObject* sbkSelf = reinterpret_cast<SbkObject*>(self);" << endl; if (metaClass->isAbstract() || metaClass->baseClassNames().size() > 1) { - s << INDENT << "SbkObjectType* type = reinterpret_cast<SbkObjectType*>(" PYTHON_SELF_VAR "->ob_type);" << endl; + s << INDENT << "SbkObjectType* type = reinterpret_cast<SbkObjectType*>(self->ob_type);" << endl; s << INDENT << "SbkObjectType* myType = reinterpret_cast<SbkObjectType*>(" << cpythonTypeNameExt(metaClass->typeEntry()) << ");" << endl; } @@ -1577,7 +1634,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun s << INDENT << "\"'" << metaClass->qualifiedCppName(); } s << "' represents a C++ abstract class and cannot be instantiated\");" << endl; - s << INDENT << "return " << m_currentErrorCode << ';' << endl; + s << INDENT << returnStatement(m_currentErrorCode) << endl; } s << INDENT << '}' << endl << endl; } @@ -1608,7 +1665,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun { Indentation indent(INDENT); s << INDENT << "delete cptr;" << endl; - s << INDENT << "return " << m_currentErrorCode << ';' << endl; + s << INDENT << returnStatement(m_currentErrorCode) << endl; } s << INDENT << '}' << endl; if (overloadData.maxArgs() > 0) { @@ -1636,12 +1693,12 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun // 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 << "PySide::Signal::updateSourceObject(self);" << 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; + s << INDENT << "if (kwds && !PySide::fillQtProperties(self, metaObject, kwds, argNames, " << argNamesSet.count() << "))" << endl; { Indentation indentation(INDENT); - s << INDENT << "return " << m_currentErrorCode << ';' << endl; + s << INDENT << returnStatement(m_currentErrorCode) << endl; } } @@ -1694,7 +1751,7 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction int maxArgs = overloadData.maxArgs(); s << "static PyObject* "; - s << cpythonFunctionName(rfunc) << "(PyObject* " PYTHON_SELF_VAR; + s << cpythonFunctionName(rfunc) << "(PyObject* self"; if (maxArgs > 0) { s << ", PyObject* " << (pythonFunctionWrapperUsesListOfArguments(overloadData) ? "args" : PYTHON_ARG); if (overloadData.hasArgumentWithDefaultValue() || rfunc->isCallOperator()) @@ -1707,6 +1764,7 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction s << endl; /* + * This code is intended for shift operations only: * Make sure reverse <</>> operators defined in other classes (specially from other modules) * are called. A proper and generic solution would require an reengineering in the operator * system like the extended converters. @@ -1721,30 +1779,32 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction && rfunc->isOperatorOverload(); if (callExtendedReverseOperator) { QString revOpName = ShibokenGenerator::pythonOperatorFunctionName(rfunc).insert(2, QLatin1Char('r')); - if (rfunc->isBinaryOperator()) { + // For custom classes, operations like __radd__ and __rmul__ + // will enter an infinite loop. + if (rfunc->isBinaryOperator() && revOpName.contains(QLatin1String("shift"))) { 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; + s << INDENT << "&& Shiboken::Object::checkType(" << PYTHON_ARG << ")" << endl; + s << INDENT << "&& !PyObject_TypeCheck(" << PYTHON_ARG << ", self->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 << "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 << PYTHON_RETURN_VAR << " = PyObject_CallFunction(revOpMethod, const_cast<char*>(\"O\"), self);" << 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 << "Py_XDECREF(" << PYTHON_RETURN_VAR << ");" << endl; + s << INDENT << PYTHON_RETURN_VAR << " = 0;" << endl; } s << INDENT << '}' << endl; } @@ -1754,7 +1814,7 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction 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; + s << INDENT << "if (!" << PYTHON_RETURN_VAR << ") {" << endl << endl; } if (maxArgs > 0) @@ -1763,7 +1823,7 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction writeFunctionCalls(s, overloadData, classContext); if (callExtendedReverseOperator) - s << endl << INDENT << "} // End of \"if (!" PYTHON_RETURN_VAR ")\"" << endl; + s << endl << INDENT << "} // End of \"if (!" << PYTHON_RETURN_VAR << ")\"" << endl; s << endl; @@ -1771,10 +1831,10 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction if (hasReturnValue) { if (rfunc->isInplaceOperator()) { - s << INDENT << "Py_INCREF(" PYTHON_SELF_VAR ");\n"; - s << INDENT << "return " PYTHON_SELF_VAR ";\n"; + s << INDENT << "Py_INCREF(self);\n"; + s << INDENT << "return self;\n"; } else { - s << INDENT << "return " PYTHON_RETURN_VAR ";\n"; + s << INDENT << "return " << PYTHON_RETURN_VAR << ";\n"; } } else { s << INDENT << "Py_RETURN_NONE;" << endl; @@ -1795,7 +1855,7 @@ void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overl int maxArgs = overloadData.maxArgs(); s << INDENT << "PyObject* "; - s << PYTHON_ARGS "[] = {" + s << PYTHON_ARGS << "[] = {" << QString(maxArgs, QLatin1Char('0')).split(QLatin1String(""), QString::SkipEmptyParts).join(QLatin1String(", ")) << "};" << endl; s << endl; @@ -1807,8 +1867,8 @@ void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overl 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 << INDENT << PYTHON_ARGS << '[' << maxArgs << "] = PyTuple_GetSlice(args, " << maxArgs << ", numArgs);" << endl; + s << INDENT << "Shiboken::AutoDecRef auto_varargs(" << PYTHON_ARGS << "[" << maxArgs << "]);" << endl; s << endl; } @@ -1822,7 +1882,7 @@ void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overl { Indentation indent(INDENT); s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): too many arguments\");" << endl; - s << INDENT << "return " << m_currentErrorCode << ';' << endl; + s << INDENT << returnStatement(m_currentErrorCode) << endl; } s << INDENT << '}'; } @@ -1835,7 +1895,7 @@ void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overl { Indentation indent(INDENT); s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): not enough arguments\");" << endl; - s << INDENT << "return " << m_currentErrorCode << ';' << endl; + s << INDENT << returnStatement(m_currentErrorCode) << endl; } s << INDENT << '}'; } @@ -1867,13 +1927,12 @@ void CppGenerator::writeArgumentsInitializer(QTextStream& s, OverloadData& overl 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; + s << ", &(" << PYTHON_ARGS << '[' << i << "])"; + s << "))" << endl; { Indentation indent(INDENT); - s << INDENT << "return " << m_currentErrorCode << ';' << endl; + s << INDENT << returnStatement(m_currentErrorCode) << endl; } s << endl; } @@ -1895,7 +1954,7 @@ void CppGenerator::writeCppSelfDefinition(QTextStream &s, } QString cppSelfAttribution; - QString pythonSelfVar = QLatin1String(PYTHON_SELF_VAR); + QString pythonSelfVar = QLatin1String("self"); QString cpythonWrapperCPtrResult; if (!context.forSmartPointer()) cpythonWrapperCPtrResult = cpythonWrapperCPtr(metaClass, pythonSelfVar); @@ -1908,7 +1967,7 @@ void CppGenerator::writeCppSelfDefinition(QTextStream &s, .arg(className, QLatin1String(CPP_SELF_VAR), cast, cpythonWrapperCPtrResult); } else { - s << INDENT << className << "* " CPP_SELF_VAR " = 0;" << endl; + 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), @@ -1918,17 +1977,17 @@ void CppGenerator::writeCppSelfDefinition(QTextStream &s, // Checks if the underlying C++ object is valid. if (hasStaticOverload && !cppSelfAsReference) { - s << INDENT << "if (" PYTHON_SELF_VAR ") {" << endl; + s << INDENT << "if (self) {" << endl; { Indentation indent(INDENT); - writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR)); + writeInvalidPyObjectCheck(s, QLatin1String("self")); s << INDENT << cppSelfAttribution << ';' << endl; } s << INDENT << '}' << endl; return; } - writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR)); + writeInvalidPyObjectCheck(s, QLatin1String("self")); s << INDENT << cppSelfAttribution << ';' << endl; } @@ -1942,17 +2001,17 @@ void CppGenerator::writeCppSelfDefinition(QTextStream &s, if (func->isOperatorOverload() && func->isBinaryOperator()) { QString checkFunc = cpythonCheckFunction(func->ownerClass()->typeEntry()); - s << INDENT << "bool isReverse = " << checkFunc << PYTHON_ARG ")" << endl; + 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 << "&& !" << checkFunc << "self);" << endl; } s << INDENT << "if (isReverse)" << endl; Indentation indent(INDENT); - s << INDENT << "std::swap(" PYTHON_SELF_VAR ", " PYTHON_ARG ");" << endl; + s << INDENT << "std::swap(self, " << PYTHON_ARG << ");" << endl; } writeCppSelfDefinition(s, context, hasStaticOverload); @@ -2053,17 +2112,20 @@ void CppGenerator::writeErrorSection(QTextStream& s, OverloadData& overloadData) << ", 0};" << endl; s << INDENT << "Shiboken::setErrorAboutWrongArguments(" << argsVar << ", \"" << funcName << "\", overloads);" << endl; } - s << INDENT << "return " << m_currentErrorCode << ';' << endl; + s << INDENT << returnStatement(m_currentErrorCode) << endl; } void CppGenerator::writeFunctionReturnErrorCheckSection(QTextStream& s, bool hasReturnValue) { - s << INDENT << "if (PyErr_Occurred()" << (hasReturnValue ? " || !" PYTHON_RETURN_VAR : "") << ") {" << endl; + s << INDENT << "if (PyErr_Occurred()"; + if (hasReturnValue) + s << " || !" << PYTHON_RETURN_VAR; + s << ") {" << endl; { Indentation indent(INDENT); if (hasReturnValue) - s << INDENT << "Py_XDECREF(" PYTHON_RETURN_VAR ");" << endl; - s << INDENT << "return " << m_currentErrorCode << ';' << endl; + s << INDENT << "Py_XDECREF(" << PYTHON_RETURN_VAR << ");" << endl; + s << INDENT << returnStatement(m_currentErrorCode) << endl; } s << INDENT << '}' << endl; } @@ -2072,12 +2134,13 @@ void CppGenerator::writeInvalidPyObjectCheck(QTextStream& s, const QString& pyOb { s << INDENT << "if (!Shiboken::Object::isValid(" << pyObj << "))" << endl; Indentation indent(INDENT); - s << INDENT << "return " << m_currentErrorCode << ';' << endl; + s << INDENT << returnStatement(m_currentErrorCode) << endl; } static QString pythonToCppConverterForArgumentName(const QString& argumentName) { - static const QRegularExpression pyArgsRegex(QLatin1String(PYTHON_ARGS"(\\[\\d+[-]?\\d*\\])")); + static const QRegularExpression pyArgsRegex(QLatin1String(PYTHON_ARGS) + + QLatin1String(R"((\[\d+[-]?\d*\]))")); Q_ASSERT(pyArgsRegex.isValid()); const QRegularExpressionMatch match = pyArgsRegex.match(argumentName); QString result = QLatin1String(PYTHON_TO_CPP_VAR); @@ -2379,7 +2442,7 @@ void CppGenerator::writeConversionRule(QTextStream& s, const AbstractMetaFunctio 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 << PYTHON_RETURN_VAR << " = Py_None;" << endl; s << INDENT << "Py_INCREF(Py_None);" << endl; } } @@ -2493,8 +2556,9 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(QTextStream& s, const Ov const AbstractMetaFunction* refFunc = overloadData->referenceFunction(); QStringList typeChecks; + QString pyArgName = (usePyArgs && maxArgs > 1) - ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(overloadData->argPos()) + ? pythonArgsAt(overloadData->argPos()) : QLatin1String(PYTHON_ARG); OverloadData* od = overloadData; int startArg = od->argPos(); @@ -2503,7 +2567,7 @@ void CppGenerator::writeOverloadedFunctionDecisorEngine(QTextStream& s, const Ov bool typeReplacedByPyObject = od->argumentTypeReplaced() == QLatin1String("PyObject"); if (!typeReplacedByPyObject) { if (usePyArgs) - pyArgName = QString::fromLatin1(PYTHON_ARGS "[%1]").arg(od->argPos()); + pyArgName = pythonArgsAt(od->argPos()); QString typeCheck; QTextStream tck(&typeCheck); const AbstractMetaFunction* func = od->referenceFunction(); @@ -2613,7 +2677,7 @@ void CppGenerator::writeSingleFunctionCall(QTextStream &s, s << INDENT << "PyErr_Format(PyExc_TypeError, \"%s is a private method.\", \"" << func->signature().replace(QLatin1String("::"), QLatin1String(".")) << "\");" << endl; - s << INDENT << "return " << m_currentErrorCode << ';' << endl; + s << INDENT << returnStatement(m_currentErrorCode) << endl; return; } @@ -2630,7 +2694,8 @@ void CppGenerator::writeSingleFunctionCall(QTextStream &s, 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); + const QString cppArgRemoved = QLatin1String(CPP_ARG_REMOVED) + + QString::number(argIdx); s << INDENT << getFullTypeName(arg->type()) << ' ' << cppArgRemoved; s << " = " << guessScopeForDefaultValue(func, arg) << ';' << endl; writeUnusedVariableCast(s, cppArgRemoved); @@ -2649,8 +2714,8 @@ void CppGenerator::writeSingleFunctionCall(QTextStream &s, 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 argName = QLatin1String(CPP_ARG) + QString::number(argPos); + QString pyArgName = usePyArgs ? pythonArgsAt(argPos) : QLatin1String(PYTHON_ARG); QString defaultValue = guessScopeForDefaultValue(func, arg); writeArgumentConversion(s, argType, argName, pyArgName, func->implementingClass(), defaultValue, func->isUserAdded()); } @@ -2896,10 +2961,8 @@ void CppGenerator::writePythonToCppConversionFunctions(QTextStream& s, const Abs 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); + const QRegularExpressionMatch match = convertToCppRegEx().match(code, pos); if (!match.hasMatch()) break; pos = match.capturedEnd(); @@ -2954,15 +3017,13 @@ void CppGenerator::writeNamedArgumentResolution(QTextStream& s, const AbstractMe 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); + QString pyArgName = usePyArgs ? pythonArgsAt(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 << returnStatement(m_currentErrorCode) << endl; } s << INDENT << "} else if (value) {" << endl; { @@ -2989,7 +3050,7 @@ QString CppGenerator::argumentNameFromIndex(const AbstractMetaFunction* func, in *wrappedClass = 0; QString pyArgName; if (argIndex == -1) { - pyArgName = QLatin1String(PYTHON_SELF_VAR); + pyArgName = QLatin1String("self"); *wrappedClass = func->implementingClass(); } else if (argIndex == 0) { AbstractMetaType *funcType = func->type(); @@ -3016,12 +3077,23 @@ QString CppGenerator::argumentNameFromIndex(const AbstractMetaFunction* func, in && OverloadData::isSingleArgument(getFunctionGroups(func->implementingClass())[func->name()])) pyArgName = QLatin1String(PYTHON_ARG); else - pyArgName = QString::fromLatin1(PYTHON_ARGS "[%1]").arg(argIndex - 1); + pyArgName = pythonArgsAt(argIndex - 1); } } return pyArgName; } +static QStringList defaultExceptionHandling() +{ + static const QStringList result{ + QLatin1String("} catch (const std::exception &e) {"), + QLatin1String(" PyErr_SetString(PyExc_RuntimeError, e.what());"), + QLatin1String("} catch (...) {"), + QLatin1String(" PyErr_SetString(PyExc_RuntimeError, \"An unknown exception was caught\");"), + QLatin1String("}")}; + return result; +} + void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *func, GeneratorContext &context, int maxArgs) { @@ -3037,12 +3109,12 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f } if (func->isAbstract()) { - s << INDENT << "if (Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "))) {\n"; + s << INDENT << "if (Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(self))) {\n"; { Indentation indent(INDENT); s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '"; s << func->ownerClass()->name() << '.' << func->name() << "()' not implemented.\");" << endl; - s << INDENT << "return " << m_currentErrorCode << ';' << endl; + s << INDENT << returnStatement(m_currentErrorCode) << endl; } s << INDENT << "}\n"; } @@ -3091,16 +3163,21 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f 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); + userArgs.append(QLatin1String(CPP_ARG_REMOVED) + QString::number(i)); } else { int idx = arg->argumentIndex() - removedArgs; bool deRef = isValueTypeWithCopyConstructorOnly(arg->type()) || isObjectTypeUsedAsValueType(arg->type()) || (arg->type()->referenceType() == LValueReference && isWrapperType(arg->type()) && !isPointer(arg->type())); - 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 (hasConversionRule) { + userArgs.append(arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX)); + } else { + QString argName; + if (deRef) + argName += QLatin1Char('*'); + argName += QLatin1String(CPP_ARG) + QString::number(idx); + userArgs.append(argName); + } } } @@ -3113,17 +3190,16 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f 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(); + const bool defValModified = arg->hasModifiedDefaultValueExpression(); bool hasConversionRule = !func->conversionRule(TypeSystem::NativeCode, arg->argumentIndex() + 1).isEmpty(); if (argsClear && !defValModified && !hasConversionRule) continue; - else - argsClear = false; + 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)); + otherArgs.prepend(QLatin1String(CPP_ARG_REMOVED) + QString::number(i)); } if (otherArgsModified) userArgs << otherArgs; @@ -3135,10 +3211,11 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f 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 firstArg(QLatin1Char('(')); + if (!func->isPointerOperator()) // no de-reference operator + firstArg += QLatin1Char('*'); + firstArg += QLatin1String(CPP_SELF_VAR); + firstArg += QLatin1Char(')'); QString secondArg = QLatin1String(CPP_ARG0); if (!func->isUnaryOperator() && shouldDereferenceArgumentPointer(func->arguments().constFirst())) { secondArg.prepend(QLatin1String("(*")); @@ -3211,7 +3288,8 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f } else { const QString selfVarCast = func->ownerClass() == func->implementingClass() ? QLatin1String(CPP_SELF_VAR) - : QLatin1String("reinterpret_cast<") + methodCallClassName + QLatin1String(" *>(" CPP_SELF_VAR ")"); + : QLatin1String("reinterpret_cast<") + methodCallClassName + + QLatin1String(" *>(") + QLatin1String(CPP_SELF_VAR) + QLatin1Char(')'); if (func->isConstant()) { if (avoidProtectedHack()) { mc << "const_cast<const ::"; @@ -3219,7 +3297,8 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f // 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 ")"); + : QLatin1String("reinterpret_cast<") + wrapperName(func->ownerClass()) + + QLatin1String(" *>(") + QLatin1String(CPP_SELF_VAR) + QLatin1Char(')'); mc << wrapperName(func->ownerClass()); mc << "*>(" << selfWrapCast << ")->"; } @@ -3263,7 +3342,7 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f methodCallClassName); normalCall.remove(QLatin1String("::%CLASS_NAME::")); methodCall.clear(); - mc << "Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ")) ? "; + mc << "Shiboken::Object::hasCppWrapper(reinterpret_cast<SbkObject*>(self)) ? "; mc << virtualCall << " : " << normalCall; } } @@ -3271,7 +3350,19 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f } if (!injectedCodeCallsCppFunction(func)) { - s << INDENT << BEGIN_ALLOW_THREADS << endl << INDENT; + const bool allowThread = func->allowThread(); + const bool generateExceptionHandling = func->generateExceptionHandling(); + if (generateExceptionHandling) { + s << INDENT << "try {\n"; + ++INDENT.indent; + if (allowThread) { + s << INDENT << "Shiboken::ThreadStateSaver threadSaver;\n" + << INDENT << "threadSaver.save();\n"; + } + } else if (allowThread) { + s << INDENT << BEGIN_ALLOW_THREADS << endl; + } + s << INDENT; if (isCtor) { s << (useVAddr.isEmpty() ? QString::fromLatin1("cptr = %1;").arg(methodCall) : useVAddr) << endl; @@ -3299,18 +3390,23 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f methodCall.append(QLatin1Char(')')); } } - s << " " CPP_RETURN_VAR " = "; + s << " " << CPP_RETURN_VAR << " = "; s << methodCall << ';' << endl; } else { s << methodCall << ';' << endl; } - s << INDENT << END_ALLOW_THREADS << endl; + if (allowThread) { + s << INDENT << (generateExceptionHandling + ? "threadSaver.restore();" : END_ALLOW_THREADS) << '\n'; + } + + // Convert result if (!func->conversionRule(TypeSystem::TargetLangCode, 0).isEmpty()) { writeConversionRule(s, func, TypeSystem::TargetLangCode, QLatin1String(PYTHON_RETURN_VAR)); } else if (!isCtor && !func->isInplaceOperator() && func->type() && !injectedCodeHasReturnValueAttribution(func, TypeSystem::TargetLangCode)) { - s << INDENT << PYTHON_RETURN_VAR " = "; + 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)"; @@ -3319,6 +3415,13 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f } s << ';' << endl; } + + if (generateExceptionHandling) { // "catch" code + --INDENT.indent; + const QStringList handlingCode = defaultExceptionHandling(); + for (const auto &line : handlingCode) + s << INDENT << line << '\n'; + } } } @@ -3370,7 +3473,7 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f s << "getOwnership(" << pyArgName << ");"; } else if (wrappedClass->hasVirtualDestructor()) { if (arg_mod.index == 0) - s << "releaseOwnership(" PYTHON_RETURN_VAR ");"; + s << "releaseOwnership(" << PYTHON_RETURN_VAR << ");"; else s << "releaseOwnership(" << pyArgName << ");"; } else { @@ -3406,10 +3509,10 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f else s << INDENT << "Shiboken::Object::removeReference("; - s << "reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "), \""; + s << "reinterpret_cast<SbkObject*>(self), \""; QString varName = arg_mod.referenceCounts.constFirst().varName; if (varName.isEmpty()) - varName = func->minimalSignature() + QString().number(arg_mod.index); + varName = func->minimalSignature() + QString::number(arg_mod.index); s << varName << "\", " << pyArgName << (refCount.action == ReferenceCount::Add ? ", true" : "") @@ -3531,7 +3634,7 @@ void CppGenerator::writeEnumConverterInitialization(QTextStream& s, const TypeEn const FlagsTypeEntry* flags = 0; if (enumType->isFlags()) - flags = reinterpret_cast<const FlagsTypeEntry*>(enumType); + flags = static_cast<const FlagsTypeEntry*>(enumType); s << INDENT << "// Register converter for " << enumFlagName << " '" << enumType->qualifiedCppName() << "'." << endl; s << INDENT << '{' << endl; @@ -3575,7 +3678,7 @@ void CppGenerator::writeEnumConverterInitialization(QTextStream& s, const TypeEn s << INDENT << '}' << endl; if (!flags) - writeEnumConverterInitialization(s, reinterpret_cast<const EnumTypeEntry*>(enumType)->flags()); + writeEnumConverterInitialization(s, static_cast<const EnumTypeEntry*>(enumType)->flags()); } void CppGenerator::writeContainerConverterInitialization(QTextStream& s, const AbstractMetaType* type) @@ -3656,10 +3759,7 @@ bool CppGenerator::supportsSequenceProtocol(const AbstractMetaClass* metaClass) } const ComplexTypeEntry* baseType = metaClass->typeEntry()->baseContainerType(); - if (baseType && baseType->isContainer()) - return true; - - return false; + return baseType && baseType->isContainer(); } bool CppGenerator::shouldGenerateGetSetList(const AbstractMetaClass* metaClass) @@ -3872,7 +3972,7 @@ void CppGenerator::writeMappingMethods(QTextStream &s, CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode); s << funcRetVal << ' ' << funcName << '(' << funcArgs << ')' << endl << '{' << endl; - writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR)); + writeInvalidPyObjectCheck(s, QLatin1String("self")); writeCppSelfDefinition(s, func, context); @@ -3899,7 +3999,7 @@ void CppGenerator::writeSequenceMethods(QTextStream &s, CodeSnipList snips = func->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode); s << funcRetVal << ' ' << funcName << '(' << funcArgs << ')' << endl << '{' << endl; - writeInvalidPyObjectCheck(s, QLatin1String(PYTHON_SELF_VAR)); + writeInvalidPyObjectCheck(s, QLatin1String("self")); writeCppSelfDefinition(s, func, context); @@ -3964,7 +4064,6 @@ void CppGenerator::writeTypeAsMappingDefinition(QTextStream& s, const AbstractMe funcs.insert(QLatin1String("__msetitem__"), QString()); } - QString baseName = cpythonBaseName(metaClass); for (auto it = m_mpFuncs.cbegin(), end = m_mpFuncs.cend(); it != end; ++it) { const QString &mpName = it.key(); if (funcs[mpName].isEmpty()) @@ -4015,7 +4114,8 @@ void CppGenerator::writeTypeAsNumberDefinition(QTextStream& s, const AbstractMet QString baseName = cpythonBaseName(metaClass); - nb[QLatin1String("bool")] = hasBoolCast(metaClass) ? baseName + QLatin1String("___nb_bool") : QString(); + if (hasBoolCast(metaClass)) + nb.insert(QLatin1String("bool"), baseName + QLatin1String("___nb_bool")); for (QHash<QString, QString>::const_iterator it = m_nbFuncs.cbegin(), end = m_nbFuncs.cend(); it != end; ++it) { const QString &nbName = it.key(); @@ -4054,9 +4154,9 @@ void CppGenerator::writeTpTraverseFunction(QTextStream& s, const AbstractMetaCla { QString baseName = cpythonBaseName(metaClass); s << "static int "; - s << baseName << "_traverse(PyObject* " PYTHON_SELF_VAR ", visitproc visit, void* arg)" << endl; + s << baseName << "_traverse(PyObject* self, visitproc visit, void* arg)" << endl; s << '{' << endl; - s << INDENT << "return reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())->tp_traverse(" PYTHON_SELF_VAR ", visit, arg);" << endl; + s << INDENT << "return reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())->tp_traverse(self, visit, arg);" << endl; s << '}' << endl; } @@ -4064,9 +4164,9 @@ void CppGenerator::writeTpClearFunction(QTextStream& s, const AbstractMetaClass* { QString baseName = cpythonBaseName(metaClass); s << "static int "; - s << baseName << "_clear(PyObject* " PYTHON_SELF_VAR ")" << endl; + s << baseName << "_clear(PyObject* self)" << endl; s << '{' << endl; - s << INDENT << "return reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())->tp_clear(" PYTHON_SELF_VAR ");" << endl; + s << INDENT << "return reinterpret_cast<PyTypeObject *>(SbkObject_TypeF())->tp_clear(self);" << endl; s << '}' << endl; } @@ -4074,7 +4174,7 @@ 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 << "static PyObject* " << className << "___copy__(PyObject* self)" << endl; s << "{" << endl; writeCppSelfDefinition(s, context, false, true); QString conversionCode; @@ -4084,9 +4184,9 @@ void CppGenerator::writeCopyFunction(QTextStream &s, GeneratorContext &context) conversionCode = cpythonToPythonConversionFunction(context.preciseType()); s << INDENT << "PyObject* " << PYTHON_RETURN_VAR << " = " << conversionCode; - s << CPP_SELF_VAR ");" << endl; + s << CPP_SELF_VAR << ");" << endl; writeFunctionReturnErrorCheckSection(s); - s << INDENT << "return " PYTHON_RETURN_VAR ";" << endl; + s << INDENT << "return " << PYTHON_RETURN_VAR << ";" << endl; s << "}" << endl; s << endl; } @@ -4096,7 +4196,7 @@ void CppGenerator::writeGetterFunction(QTextStream &s, GeneratorContext &context) { ErrorCode errorCode(0); - s << "static PyObject* " << cpythonGetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", void*)" << endl; + s << "static PyObject* " << cpythonGetterFunctionName(metaField) << "(PyObject* self, void*)" << endl; s << '{' << endl; writeCppSelfDefinition(s, context); @@ -4161,7 +4261,7 @@ void CppGenerator::writeGetterFunction(QTextStream &s, 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)"; + s << INDENT << "Shiboken::Object::setParent(self, pyOut)"; } else { s << INDENT << "pyOut = "; writeToPythonConversion(s, fieldType, metaField->enclosingClass(), cppField); @@ -4177,7 +4277,7 @@ void CppGenerator::writeSetterFunction(QTextStream &s, GeneratorContext &context) { ErrorCode errorCode(0); - s << "static int " << cpythonSetterFunctionName(metaField) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* pyIn, void*)" << endl; + s << "static int " << cpythonSetterFunctionName(metaField) << "(PyObject* self, PyObject* pyIn, void*)" << endl; s << '{' << endl; writeCppSelfDefinition(s, context); @@ -4193,7 +4293,7 @@ void CppGenerator::writeSetterFunction(QTextStream &s, AbstractMetaType* fieldType = metaField->type(); - s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << ';' << endl; + s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR << "{nullptr};" << endl; s << INDENT << "if (!"; writeTypeCheck(s, fieldType, QLatin1String("pyIn"), isNumber(fieldType->typeEntry())); s << ") {" << endl; @@ -4219,6 +4319,8 @@ void CppGenerator::writeSetterFunction(QTextStream &s, s << INDENT << PYTHON_TO_CPP_VAR << "(pyIn, &cppOut_local);" << endl; s << INDENT << cppField << " = cppOut_local"; } else { + if (isPointerToConst(fieldType)) + s << "const "; s << getFullTypeNameWithoutModifiers(fieldType); s << QString::fromLatin1("*").repeated(fieldType->indirections()) << "& cppOut_ptr = "; s << cppField << ';' << endl; @@ -4227,7 +4329,7 @@ void CppGenerator::writeSetterFunction(QTextStream &s, s << ';' << endl << endl; if (isPointerToWrapperType(fieldType)) { - s << INDENT << "Shiboken::Object::keepReference(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR "), \""; + s << INDENT << "Shiboken::Object::keepReference(reinterpret_cast<SbkObject*>(self), \""; s << metaField->name() << "\", pyIn);" << endl; } @@ -4240,12 +4342,12 @@ void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &co 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 << baseName << "_richcompare(PyObject* self, 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; + 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; @@ -4302,15 +4404,17 @@ void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &co CodeSnipList snips = func->injectedCodeSnips(); writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode, func, func->arguments().constLast()); } 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 " = "; + s << func->type()->cppSignature() << " " << CPP_RETURN_VAR << " = "; + // expression + if (func->isPointerOperator()) + s << '&'; + s << CPP_SELF_VAR << ' ' << op << '('; + if (shouldDereferenceAbstractMetaTypePointer(argType)) + s << '*'; + s << CPP_ARG0 << ");" << endl; + s << INDENT << PYTHON_RETURN_VAR << " = "; if (func->type()) writeToPythonConversion(s, func->type(), metaClass, QLatin1String(CPP_RETURN_VAR)); else @@ -4324,9 +4428,9 @@ void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &co s << " else {" << endl; if (operatorId == QLatin1String("Py_EQ") || operatorId == QLatin1String("Py_NE")) { Indentation indent(INDENT); - s << INDENT << PYTHON_RETURN_VAR " = " + s << INDENT << PYTHON_RETURN_VAR << " = " << (operatorId == QLatin1String("Py_EQ") ? "Py_False" : "Py_True") << ';' << endl; - s << INDENT << "Py_INCREF(" PYTHON_RETURN_VAR ");" << endl; + s << INDENT << "Py_INCREF(" << PYTHON_RETURN_VAR << ");" << endl; } else { Indentation indent(INDENT); s << INDENT << "goto " << baseName << "_RichComparison_TypeError;" << endl; @@ -4343,18 +4447,18 @@ void CppGenerator::writeRichCompareFunction(QTextStream &s, GeneratorContext &co } s << INDENT << '}' << endl << endl; - s << INDENT << "if (" PYTHON_RETURN_VAR " && !PyErr_Occurred())" << endl; + s << INDENT << "if (" << PYTHON_RETURN_VAR << " && !PyErr_Occurred())" << endl; { Indentation indent(INDENT); - s << INDENT << "return " PYTHON_RETURN_VAR ";" << endl; + 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 << INDENT << returnStatement(m_currentErrorCode) << endl << endl; s << '}' << endl << endl; } -void CppGenerator::writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList overloads) +void CppGenerator::writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList &overloads) { Q_ASSERT(!overloads.isEmpty()); OverloadData overloadData(overloads, this); @@ -4378,7 +4482,7 @@ void CppGenerator::writeMethodDefinitionEntry(QTextStream& s, const AbstractMeta s << "|METH_STATIC"; } -void CppGenerator::writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads) +void CppGenerator::writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList &overloads) { Q_ASSERT(!overloads.isEmpty()); const AbstractMetaFunction* func = overloads.constFirst(); @@ -4510,7 +4614,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu s << INDENT << "if (!" << cpythonTypeNameExt(cppEnum->typeEntry()) << ')' << endl; { Indentation indent(INDENT); - s << INDENT << "return " << m_currentErrorCode << ';' << endl << endl; + s << INDENT << returnStatement(m_currentErrorCode) << endl << endl; } } @@ -4543,7 +4647,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu << "))->tp_dict, \"" << enumValue->name() << "\", anonEnumItem) < 0)" << endl; { Indentation indent(INDENT); - s << INDENT << "return " << m_currentErrorCode << ';' << endl; + s << INDENT << returnStatement(m_currentErrorCode) << endl; } s << INDENT << "Py_DECREF(anonEnumItem);" << endl; } @@ -4553,7 +4657,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu s << enumValueText << ") < 0)" << endl; { Indentation indent(INDENT); - s << INDENT << "return " << m_currentErrorCode << ';' << endl; + s << INDENT << returnStatement(m_currentErrorCode) << endl; } } break; @@ -4564,7 +4668,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu Indentation indent(INDENT); s << INDENT << enclosingObjectVariable << ", \"" << enumValue->name() << "\", "; s << enumValueText << "))" << endl; - s << INDENT << "return " << m_currentErrorCode << ';' << endl; + s << INDENT << returnStatement(m_currentErrorCode) << endl; } break; case EnumClass: { @@ -4573,7 +4677,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu Indentation indent(INDENT); s << INDENT << enumVarTypeObj<< ", \"" << enumValue->name() << "\", " << enumValueText << "))" << endl - << INDENT << "return " << m_currentErrorCode << ';' << endl; + << INDENT << returnStatement(m_currentErrorCode) << endl; } break; } @@ -4618,11 +4722,11 @@ void CppGenerator::writeFlagsToLong(QTextStream& s, const AbstractMetaEnum* cppE FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags(); if (!flagsEntry) return; - s << "static PyObject* " << cpythonEnumName(cppEnum) << "_long(PyObject* " PYTHON_SELF_VAR ")" << endl; + s << "static PyObject* " << cpythonEnumName(cppEnum) << "_long(PyObject* self)" << endl; s << "{" << endl; s << INDENT << "int val;" << endl; AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry); - s << INDENT << cpythonToCppConversionFunction(flagsType) << PYTHON_SELF_VAR << ", &val);" << endl; + s << INDENT << cpythonToCppConversionFunction(flagsType) << "self, &val);" << endl; s << INDENT << "return Shiboken::Conversions::copyToPython(Shiboken::Conversions::PrimitiveTypeConverter<int>(), &val);" << endl; s << "}" << endl; } @@ -4632,12 +4736,12 @@ void CppGenerator::writeFlagsNonZero(QTextStream& s, const AbstractMetaEnum* cpp FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags(); if (!flagsEntry) return; - s << "static int " << cpythonEnumName(cppEnum) << "__nonzero(PyObject* " PYTHON_SELF_VAR ")" << endl; + s << "static int " << cpythonEnumName(cppEnum) << "__nonzero(PyObject* self)" << endl; s << "{" << endl; s << INDENT << "int val;" << endl; AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry); - s << INDENT << cpythonToCppConversionFunction(flagsType) << PYTHON_SELF_VAR << ", &val);" << endl; + s << INDENT << cpythonToCppConversionFunction(flagsType) << "self, &val);" << endl; s << INDENT << "return val != 0;" << endl; s << "}" << endl; } @@ -4679,24 +4783,24 @@ void CppGenerator::writeFlagsNumberMethodsDefinition(QTextStream& s, const Abstr } void CppGenerator::writeFlagsBinaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum, - QString pyOpName, QString cppOpName) + const QString &pyOpName, const QString &cppOpName) { FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags(); Q_ASSERT(flagsEntry); - s << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* " PYTHON_SELF_VAR ", PyObject* " PYTHON_ARG ")" << endl; + s << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* self, PyObject* " << PYTHON_ARG << ")" << endl; s << '{' << endl; AbstractMetaType* flagsType = buildAbstractMetaTypeFromTypeEntry(flagsEntry); - s << INDENT << "::" << flagsEntry->originalName() << " cppResult, " CPP_SELF_VAR ", cppArg;" << endl; + 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 << INDENT << CPP_SELF_VAR << " = (::" << flagsEntry->originalName() << ")(int)PyLong_AsLong(self);" << 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 << INDENT << CPP_SELF_VAR << " = (::" << flagsEntry->originalName() << ")(int)PyInt_AsLong(self);" << 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 << "cppResult = " << CPP_SELF_VAR << " " << cppOpName << " cppArg;" << endl; s << INDENT << "return "; writeToPythonConversion(s, flagsType, 0, QLatin1String("cppResult")); s << ';' << endl; @@ -4704,23 +4808,24 @@ void CppGenerator::writeFlagsBinaryOperator(QTextStream& s, const AbstractMetaEn } void CppGenerator::writeFlagsUnaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum, - QString pyOpName, QString cppOpName, bool boolResult) + const QString &pyOpName, + const 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 << "PyObject* " << cpythonEnumName(cppEnum) << "___" << pyOpName << "__(PyObject* self, 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 << "::" << flagsEntry->originalName() << " " << CPP_SELF_VAR << ";" << endl; + s << INDENT << cpythonToCppConversionFunction(flagsType) << "self, &" << CPP_SELF_VAR << ");" << endl; s << INDENT; if (boolResult) s << "bool"; else s << "::" << flagsEntry->originalName(); - s << " cppResult = " << cppOpName << CPP_SELF_VAR ";" << endl; + s << " cppResult = " << cppOpName << CPP_SELF_VAR << ';' << endl; s << INDENT << "return "; if (boolResult) s << "PyBool_FromLong(cppResult)"; @@ -4846,8 +4951,16 @@ void CppGenerator::writeClassRegister(QTextStream &s, else s << INDENT << "0," << endl; - // 9:isInnerClass - s << INDENT << (hasEnclosingClass ? "true" : "false") << endl; + // 9:wrapperflags + QByteArrayList wrapperFlags; + if (hasEnclosingClass) + wrapperFlags.append(QByteArrayLiteral("Shiboken::ObjectType::WrapperFlags::InnerClass")); + if (metaClass->deleteInMainThread()) + wrapperFlags.append(QByteArrayLiteral("Shiboken::ObjectType::WrapperFlags::DeleteInMainThread")); + if (wrapperFlags.isEmpty()) + s << INDENT << '0'; + else + s << INDENT << wrapperFlags.join(" | "); } s << INDENT << ");" << endl; s << INDENT << endl; @@ -5042,25 +5155,27 @@ void CppGenerator::writeTypeDiscoveryFunction(QTextStream& s, const AbstractMeta s << "}\n\n"; } -QString CppGenerator::writeSmartPointerGetterCast() { - return QLatin1String("const_cast<char *>(" SMART_POINTER_GETTER ")"); +QString CppGenerator::writeSmartPointerGetterCast() +{ + return QLatin1String("const_cast<char *>(") + + QLatin1String(SMART_POINTER_GETTER) + QLatin1Char(')'); } void CppGenerator::writeSetattroFunction(QTextStream &s, GeneratorContext &context) { const AbstractMetaClass* metaClass = context.metaClass(); - s << "static int " << cpythonSetattroFunctionName(metaClass) << "(PyObject* " PYTHON_SELF_VAR ", PyObject* name, PyObject* value)" << endl; + s << "static int " << cpythonSetattroFunctionName(metaClass) << "(PyObject* self, 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 << "Shiboken::AutoDecRef pp(reinterpret_cast<PyObject*>(PySide::Property::getObject(self, 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; + s << INDENT << "return PySide::Property::setValue(reinterpret_cast<PySideProperty*>(pp.object()), self, 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 ", " + s << INDENT << "PyObject *rawObj = PyObject_CallMethod(self, " << writeSmartPointerGetterCast() << ", 0);" << endl; s << INDENT << "if (rawObj) {" << endl; { @@ -5078,7 +5193,7 @@ void CppGenerator::writeSetattroFunction(QTextStream &s, GeneratorContext &conte } - s << INDENT << "return PyObject_GenericSetAttr(" PYTHON_SELF_VAR ", name, value);" << endl; + s << INDENT << "return PyObject_GenericSetAttr(self, name, value);" << endl; s << '}' << endl; } @@ -5088,27 +5203,29 @@ static inline QString qMetaObjectClassName() { return QStringLiteral("QMetaObjec 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 << "static PyObject* " << cpythonGetattroFunctionName(metaClass) << "(PyObject* self, 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))); + QTextStream(&getattrFunc) << "PySide::getMetaDataFromQObject(" + << cpythonWrapperCPtr(qobjectClass, QLatin1String("self")) + << ", self, name)"; } else { - getattrFunc = QLatin1String("PyObject_GenericGetAttr(" PYTHON_SELF_VAR ", name)"); + getattrFunc = QLatin1String("PyObject_GenericGetAttr(") + QLatin1String("self") + + QLatin1String(", name)"); } if (classNeedsGetattroFunction(metaClass)) { - s << INDENT << "if (" PYTHON_SELF_VAR ") {" << endl; + s << INDENT << "if (self) {" << 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; + s << INDENT << "if (reinterpret_cast<SbkObject*>(self)->ob_dict) {" << endl; { Indentation indent(INDENT); - s << INDENT << "PyObject* meth = PyDict_GetItem(reinterpret_cast<SbkObject*>(" PYTHON_SELF_VAR ")->ob_dict, name);" << endl; + s << INDENT << "PyObject* meth = PyDict_GetItem(reinterpret_cast<SbkObject*>(self)->ob_dict, name);" << endl; s << INDENT << "if (meth) {" << endl; { Indentation indent(INDENT); @@ -5119,16 +5236,16 @@ void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &conte } s << INDENT << '}' << endl; s << INDENT << "// Search the method in the type dict" << endl; - s << INDENT << "if (Shiboken::Object::isUserType(" PYTHON_SELF_VAR ")) {" << endl; + s << INDENT << "if (Shiboken::Object::isUserType(self)) {" << endl; { Indentation indent(INDENT); // PYSIDE-772: Perform optimized name mangling. - s << INDENT << "Shiboken::AutoDecRef tmp(_Pep_PrivateMangle(" PYTHON_SELF_VAR ", name));" << endl; - s << INDENT << "PyObject *meth = PyDict_GetItem(Py_TYPE(" PYTHON_SELF_VAR ")->tp_dict, tmp);" << endl; + s << INDENT << "Shiboken::AutoDecRef tmp(_Pep_PrivateMangle(self, name));" << endl; + s << INDENT << "PyObject *meth = PyDict_GetItem(Py_TYPE(self)->tp_dict, tmp);" << 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 << "return PyFunction_Check(meth) ? SBK_PyMethod_New(meth, self) : " << getattrFunc << ';' << endl; } } s << INDENT << '}' << endl; @@ -5147,7 +5264,7 @@ void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &conte 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 << "return PyCFunction_NewEx(&non_static_" << defName << ", self, 0);" << endl; } } s << INDENT << '}' << endl; @@ -5168,7 +5285,7 @@ void CppGenerator::writeGetattroFunction(QTextStream& s, GeneratorContext &conte 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 ", " + s << INDENT << "PyObject *rawObj = PyObject_CallMethod(self, " << writeSmartPointerGetterCast() << ", 0);" << endl; s << INDENT << "if (rawObj) {" << endl; { @@ -5289,15 +5406,11 @@ bool CppGenerator::finishGeneration() 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); + verifyDirectoryFor(moduleFileName); + FileOut file(moduleFileName); + + QTextStream &s = file.stream; // write license comment s << licenseComment() << endl; @@ -5305,10 +5418,10 @@ bool CppGenerator::finishGeneration() s << "#include <sbkpython.h>" << endl; s << "#include <shiboken.h>" << endl; s << "#include <algorithm>" << endl; + s << "#include <signature.h>" << endl; if (usePySideExtensions()) { s << includeQDebug; s << "#include <pyside.h>" << endl; - s << "#include <signature.h>" << endl; s << "#include <qapp_macro.h>" << endl; } @@ -5328,13 +5441,12 @@ bool CppGenerator::finishGeneration() } TypeDatabase* typeDb = TypeDatabase::instance(); - TypeSystemTypeEntry* moduleEntry = reinterpret_cast<TypeSystemTypeEntry*>(typeDb->findType(packageName())); + const TypeSystemTypeEntry *moduleEntry = typeDb->findTypeSystemType(packageName()); + Q_ASSERT(moduleEntry); //Extra includes s << endl << "// Extra includes" << endl; - QVector<Include> extraIncludes; - if (moduleEntry) - extraIncludes = moduleEntry->extraIncludes(); + QVector<Include> extraIncludes = moduleEntry->extraIncludes(); for (AbstractMetaEnum *cppEnum : qAsConst(globalEnums)) extraIncludes.append(cppEnum->typeEntry()->extraIncludes()); qSort(extraIncludes.begin(), extraIncludes.end()); @@ -5343,14 +5455,15 @@ bool CppGenerator::finishGeneration() s << endl; s << "// Current module's type array." << endl; - s << "PyTypeObject** " << cppApiVariableName() << ';' << endl; + s << "PyTypeObject** " << cppApiVariableName() << " = nullptr;" << endl; + + s << "// Current module's PyObject pointer." << endl; + s << "PyObject* " << pythonModuleObjectName() << " = nullptr;" << endl; s << "// Current module's converter array." << endl; - s << "SbkConverter** " << convertersVariableName() << ';' << endl; + s << "SbkConverter** " << convertersVariableName() << " = nullptr;" << endl; - CodeSnipList snips; - if (moduleEntry) - snips = moduleEntry->codeSnips(); + const CodeSnipList snips = moduleEntry->codeSnips(); // module inject-code native/beginning if (!snips.isEmpty()) { @@ -5519,6 +5632,9 @@ bool CppGenerator::finishGeneration() s << moduleName() << "_methods);" << endl; s << "#endif" << endl << endl; + s << INDENT << "// Make module available from global scope" << endl; + s << INDENT << pythonModuleObjectName() << " = module;" << endl << endl; + //s << INDENT << "// Initialize converters for primitive types." << endl; //s << INDENT << "initConverters();" << endl << endl; @@ -5601,25 +5717,28 @@ bool CppGenerator::finishGeneration() // cleanup staticMetaObject attribute s << INDENT << "PySide::registerCleanupFunction(cleanTypesAttributes);" << endl << endl; + } - // PYSIDE-510: Create a signatures string for the introspection feature. - s << "// The signatures string for the global functions." << endl; - s << "// Multiple signatures have their index \"n:\" in front." << endl; - s << "const char " << moduleName() << "_SignaturesString[] = \"\"" << endl; - QString line; - while (signatureStream.readLineInto(&line)) - s << INDENT << '"' << line << "\\n\"" << endl; - s << ';' << endl; - // finish the rest of __signature__ initialization. - s << INDENT << "FinishSignatureInitialization(module, " << moduleName() - << "_SignaturesString);" << endl; + // PYSIDE-510: Create a signatures string for the introspection feature. + s << "// The signatures string for the global functions." << endl; + s << "// Multiple signatures have their index \"n:\" in front." << endl; + s << "const char " << moduleName() << "_SignaturesString[] = \"\"" << endl; + QString line; + while (signatureStream.readLineInto(&line)) + s << INDENT << '"' << line << "\\n\"" << endl; + s << ';' << endl; + // finish the rest of __signature__ initialization. + s << INDENT << "FinishSignatureInitialization(module, " << moduleName() + << "_SignaturesString);" << endl; + + if (usePySideExtensions()) { // initialize the qApp module. - s << INDENT << "NotifyModuleForQApp(module);" << endl << endl; + s << INDENT << "NotifyModuleForQApp(module);" << endl; } - + s << endl; s << "SBK_MODULE_INIT_FUNCTION_END" << endl; - return true; + return file.done() != FileOut::Failure; } static ArgumentOwner getArgumentOwner(const AbstractMetaFunction* func, int argIndex) @@ -5663,22 +5782,20 @@ bool CppGenerator::writeParentChildManagement(QTextStream& s, const AbstractMeta if (parentIndex == 0) { parentVariable = QLatin1String(PYTHON_RETURN_VAR); } else if (parentIndex == -1) { - parentVariable = QLatin1String(PYTHON_SELF_VAR); + parentVariable = QLatin1String("self"); } else { parentVariable = usePyArgs - ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(parentIndex - 1) - : QLatin1String(PYTHON_ARG); + ? pythonArgsAt(parentIndex - 1) : QLatin1String(PYTHON_ARG); } } if (childIndex == 0) { childVariable = QLatin1String(PYTHON_RETURN_VAR); } else if (childIndex == -1) { - childVariable = QLatin1String(PYTHON_SELF_VAR); + childVariable = QLatin1String("self"); } else { childVariable = usePyArgs - ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(childIndex - 1) - : QLatin1String(PYTHON_ARG); + ? pythonArgsAt(childIndex - 1) : QLatin1String(PYTHON_ARG); } s << INDENT << "Shiboken::Object::setParent(" << parentVariable << ", " << childVariable << ");\n"; @@ -5717,7 +5834,7 @@ void CppGenerator::writeReturnValueHeuristics(QTextStream& s, const AbstractMeta 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; + s << INDENT << "Shiboken::Object::setParent(self, " << PYTHON_RETURN_VAR << ");" << endl; } } @@ -5737,19 +5854,19 @@ void CppGenerator::writeStdListWrapperMethods(QTextStream &s, GeneratorContext & ErrorCode errorCode(0); // __len__ - s << "Py_ssize_t " << cpythonBaseName(metaClass->typeEntry()) << "__len__(PyObject* " PYTHON_SELF_VAR ")" << endl; + s << "Py_ssize_t " << cpythonBaseName(metaClass->typeEntry()) << "__len__(PyObject* self)" << endl; s << '{' << endl; writeCppSelfDefinition(s, context); - s << INDENT << "return " CPP_SELF_VAR "->size();" << endl; + 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 << "PyObject* " << cpythonBaseName(metaClass->typeEntry()) << "__getitem__(PyObject* self, 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 << 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().constFirst(); @@ -5761,7 +5878,7 @@ void CppGenerator::writeStdListWrapperMethods(QTextStream &s, GeneratorContext & // __setitem__ ErrorCode errorCode2(-1); - s << "int " << cpythonBaseName(metaClass->typeEntry()) << "__setitem__(PyObject* " PYTHON_SELF_VAR ", Py_ssize_t _i, PyObject* pyArg)" << endl; + s << "int " << cpythonBaseName(metaClass->typeEntry()) << "__setitem__(PyObject* self, Py_ssize_t _i, PyObject* pyArg)" << endl; s << '{' << endl; writeCppSelfDefinition(s, context); writeIndexError(s, QLatin1String("list assignment index out of range")); @@ -5779,7 +5896,7 @@ void CppGenerator::writeStdListWrapperMethods(QTextStream &s, GeneratorContext & s << INDENT << '}' << endl; writeArgumentConversion(s, itemType, QLatin1String("cppValue"), QLatin1String("pyArg"), metaClass); - s << INDENT << metaClass->qualifiedCppName() << "::iterator _item = " CPP_SELF_VAR "->begin();" << endl; + 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; @@ -5787,11 +5904,11 @@ void CppGenerator::writeStdListWrapperMethods(QTextStream &s, GeneratorContext & } void CppGenerator::writeIndexError(QTextStream& s, const QString& errorMsg) { - s << INDENT << "if (_i < 0 || _i >= (Py_ssize_t) " CPP_SELF_VAR "->size()) {" << endl; + 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 << returnStatement(m_currentErrorCode) << endl; } s << INDENT << '}' << endl; } @@ -5808,7 +5925,10 @@ QString CppGenerator::writeReprFunction(QTextStream &s, GeneratorContext &contex 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 << "dbg << "; + if (metaClass->typeEntry()->isValue()) + s << '*'; + s << CPP_SELF_VAR << ';' << endl; s << INDENT << "buffer.close();" << endl; s << INDENT << "QByteArray str = buffer.data();" << endl; s << INDENT << "int idx = str.indexOf('(');" << endl; diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h index 1b59bcda7..55a1c265d 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.h +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.h @@ -234,8 +234,8 @@ private: void writeClassDefinition(QTextStream &s, const AbstractMetaClass *metaClass, GeneratorContext &classContext); - void writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList overloads); - void writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList overloads); + void writeMethodDefinitionEntry(QTextStream& s, const AbstractMetaFunctionList &overloads); + void writeMethodDefinition(QTextStream& s, const AbstractMetaFunctionList &overloads); void writeSignatureInfo(QTextStream &s, const AbstractMetaFunctionList &overloads); /// Writes the implementation of all methods part of python sequence protocol void writeSequenceMethods(QTextStream &s, @@ -275,9 +275,10 @@ private: 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); + const QString &pyOpName, const QString &cppOpName); void writeFlagsUnaryOperator(QTextStream& s, const AbstractMetaEnum* cppEnum, - QString pyOpName, QString cppOpName, bool boolResult = false); + const QString &pyOpName, const QString &cppOpName, + bool boolResult = false); /// Writes the function that registers the multiple inheritance information for the classes that need it. void writeMultipleInheritanceInitializerFunction(QTextStream& s, const AbstractMetaClass* metaClass); @@ -292,7 +293,7 @@ private: 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 writeReturnValueHeuristics(QTextStream& s, const AbstractMetaFunction* func, const QString& self = QLatin1String("self")); void writeInitQtMetaTypeFunctionBody(QTextStream &s, GeneratorContext &context) const; /** @@ -327,7 +328,9 @@ private: QString writeReprFunction(QTextStream &s, GeneratorContext &context); - bool hasBoolCast(const AbstractMetaClass* metaClass) const; + const AbstractMetaFunction *boolCast(const AbstractMetaClass* metaClass) const; + bool hasBoolCast(const AbstractMetaClass* metaClass) const + { return boolCast(metaClass) != nullptr; } // Number protocol structure members names. static QHash<QString, QString> m_nbFuncs; diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.cpp b/sources/shiboken2/generator/shiboken2/headergenerator.cpp index 8fde3cd31..8881d71f4 100644 --- a/sources/shiboken2/generator/shiboken2/headergenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/headergenerator.cpp @@ -32,6 +32,8 @@ #include <reporthandler.h> #include <fileout.h> +#include <algorithm> + #include <QtCore/QDir> #include <QtCore/QTextStream> #include <QtCore/QVariant> @@ -49,11 +51,10 @@ QString HeaderGenerator::fileNameForContext(GeneratorContext &context) const QString fileNameBase = metaClass->qualifiedCppName().toLower(); fileNameBase.replace(QLatin1String("::"), QLatin1String("_")); return fileNameBase + fileNameSuffix(); - } else { - const AbstractMetaType *smartPointerType = context.preciseType(); - QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass); - return fileNameBase + fileNameSuffix(); } + const AbstractMetaType *smartPointerType = context.preciseType(); + QString fileNameBase = getFileNameBaseForSmartPointer(smartPointerType, metaClass); + return fileNameBase + fileNameSuffix(); } void HeaderGenerator::writeCopyCtor(QTextStream& s, const AbstractMetaClass* metaClass) const @@ -116,8 +117,6 @@ void HeaderGenerator::generateClass(QTextStream &s, GeneratorContext &classConte if (!avoidProtectedHack()) s << "#define protected public" << endl << endl; - s << "#include <shiboken.h>" << endl << endl; - //Includes s << metaClass->typeEntry()->include() << endl; @@ -173,7 +172,7 @@ void HeaderGenerator::generateClass(QTextStream &s, GeneratorContext &classConte s << INDENT << "void* qt_metacast(const char* _clname) override;" << endl; } - if (m_inheritedOverloads.size()) { + if (!m_inheritedOverloads.isEmpty()) { s << INDENT << "// Inherited overloads, because the using keyword sux" << endl; writeInheritedOverloads(s); m_inheritedOverloads.clear(); @@ -230,7 +229,7 @@ void HeaderGenerator::writeFunction(QTextStream& s, const AbstractMetaFunction* QString argName = arg->name(); const TypeEntry* enumTypeEntry = 0; if (arg->type()->isFlags()) - enumTypeEntry = reinterpret_cast<const FlagsTypeEntry*>(arg->type()->typeEntry())->originator(); + enumTypeEntry = static_cast<const FlagsTypeEntry*>(arg->type()->typeEntry())->originator(); else if (arg->type()->isEnum()) enumTypeEntry = arg->type()->typeEntry(); if (enumTypeEntry) @@ -284,49 +283,86 @@ void HeaderGenerator::writeFunction(QTextStream& s, const AbstractMetaFunction* } } -static void _writeTypeIndexDefineLine(QTextStream& s, const QString& variableName, int typeIndex) +static void _writeTypeIndexValue(QTextStream& s, const QString& variableName, + int typeIndex) { - s << "#define "; - s.setFieldWidth(60); + s << " "; + s.setFieldWidth(56); s << variableName; s.setFieldWidth(0); - s << ' ' << typeIndex << endl; + s << " = " << typeIndex; +} + +static inline void _writeTypeIndexValueLine(QTextStream& s, + const QString& variableName, + int typeIndex) +{ + _writeTypeIndexValue(s, variableName, typeIndex); + s << ",\n"; } -void HeaderGenerator::writeTypeIndexDefineLine(QTextStream& s, const TypeEntry* typeEntry) + +void HeaderGenerator::writeTypeIndexValueLine(QTextStream& s, const TypeEntry* typeEntry) { if (!typeEntry || !typeEntry->generateCode()) return; s.setFieldAlignment(QTextStream::AlignLeft); - int typeIndex = getTypeIndex(typeEntry); - _writeTypeIndexDefineLine(s, getTypeIndexVariableName(typeEntry), typeIndex); + const int typeIndex = typeEntry->sbkIndex(); + _writeTypeIndexValueLine(s, getTypeIndexVariableName(typeEntry), typeIndex); if (typeEntry->isComplex()) { - const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(typeEntry); + const ComplexTypeEntry* cType = static_cast<const ComplexTypeEntry*>(typeEntry); if (cType->baseContainerType()) { const AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes(), cType); if (metaClass->templateBaseClass()) - _writeTypeIndexDefineLine(s, getTypeIndexVariableName(metaClass, true), typeIndex); + _writeTypeIndexValueLine(s, getTypeIndexVariableName(metaClass, true), typeIndex); } } if (typeEntry->isEnum()) { - const EnumTypeEntry* ete = reinterpret_cast<const EnumTypeEntry*>(typeEntry); + const EnumTypeEntry* ete = static_cast<const EnumTypeEntry*>(typeEntry); if (ete->flags()) - writeTypeIndexDefineLine(s, ete->flags()); + writeTypeIndexValueLine(s, ete->flags()); } } -void HeaderGenerator::writeTypeIndexDefine(QTextStream& s, const AbstractMetaClass* metaClass) +void HeaderGenerator::writeTypeIndexValueLines(QTextStream& s, const AbstractMetaClass* metaClass) { if (!metaClass->typeEntry()->generateCode()) return; - writeTypeIndexDefineLine(s, metaClass->typeEntry()); + writeTypeIndexValueLine(s, metaClass->typeEntry()); const AbstractMetaEnumList &enums = metaClass->enums(); for (const AbstractMetaEnum *metaEnum : enums) { if (metaEnum->isPrivate()) continue; - writeTypeIndexDefineLine(s, metaEnum->typeEntry()); + writeTypeIndexValueLine(s, metaEnum->typeEntry()); } } +// Format the typedefs for the typedef entries to be generated +static void formatTypeDefEntries(QTextStream &s) +{ + QVector<const TypedefEntry *> entries; + const auto typeDbEntries = TypeDatabase::instance()->typedefEntries(); + for (auto it = typeDbEntries.cbegin(), end = typeDbEntries.cend(); it != end; ++it) { + if (it.value()->generateCode() != 0) + entries.append(it.value()); + } + if (entries.isEmpty()) + return; + s << "\n// typedef entries\n"; + for (const auto e : entries) { + const QString name = e->qualifiedCppName(); + // Fixme: simplify by using nested namespaces in C++ 17. + const auto components = name.splitRef(QLatin1String("::")); + const int nameSpaceCount = components.size() - 1; + for (int n = 0; n < nameSpaceCount; ++n) + s << "namespace " << components.at(n) << " {\n"; + s << "using " << components.constLast() << " = " << e->sourceType() << ";\n"; + for (int n = 0; n < nameSpaceCount; ++n) + s << "}\n"; + } + s << '\n'; +} + + bool HeaderGenerator::finishGeneration() { // Generate the main header for this module. @@ -342,47 +378,49 @@ bool HeaderGenerator::finishGeneration() Indentation indent(INDENT); - macrosStream << "// Type indices" << endl; + macrosStream << "// Type indices\nenum : int {\n"; AbstractMetaEnumList globalEnums = this->globalEnums(); - const AbstractMetaClassList &classList = classes(); + AbstractMetaClassList classList = classes(); + + std::sort(classList.begin(), classList.end(), [](AbstractMetaClass *a, AbstractMetaClass* b) { + return a->typeEntry()->sbkIndex() < b->typeEntry()->sbkIndex(); + }); + for (const AbstractMetaClass *metaClass : classList) { - writeTypeIndexDefine(macrosStream, metaClass); + writeTypeIndexValueLines(macrosStream, metaClass); lookForEnumsInClassesNotToBeGenerated(globalEnums, metaClass); } for (const AbstractMetaEnum *metaEnum : qAsConst(globalEnums)) - writeTypeIndexDefineLine(macrosStream, metaEnum->typeEntry()); + writeTypeIndexValueLine(macrosStream, metaEnum->typeEntry()); // Write the smart pointer define indexes. int smartPointerCountIndex = getMaxTypeIndex(); int smartPointerCount = 0; const QVector<const AbstractMetaType *> &instantiatedSmartPtrs = instantiatedSmartPointers(); for (const AbstractMetaType *metaType : instantiatedSmartPtrs) { - QString variableName = getTypeIndexVariableName(metaType); - macrosStream << "#define "; - macrosStream.setFieldWidth(60); - macrosStream << variableName; - macrosStream.setFieldWidth(0); - macrosStream << ' ' << smartPointerCountIndex << " // " << metaType->cppSignature() - << endl; + _writeTypeIndexValue(macrosStream, getTypeIndexVariableName(metaType), + smartPointerCountIndex); + macrosStream << ", // " << metaType->cppSignature() << endl; ++smartPointerCountIndex; ++smartPointerCount; } + _writeTypeIndexValue(macrosStream, + QLatin1String("SBK_") + moduleName() + QLatin1String("_IDX_COUNT"), + getMaxTypeIndex() + smartPointerCount); + macrosStream << "\n};\n"; - 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 the Python module object exported by this module." << endl; + macrosStream << "extern PyObject* " << pythonModuleObjectName() << ';' << 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; + macrosStream << "// Converter indices\nenum : int {\n"; const PrimitiveTypeEntryList &primitives = primitiveTypes(); int pCount = 0; for (const PrimitiveTypeEntry *ptype : primitives) { @@ -393,28 +431,25 @@ bool HeaderGenerator::finishGeneration() if (!ptype->generateCode() || !ptype->customConversion()) continue; - _writeTypeIndexDefineLine(macrosStream, getTypeIndexVariableName(ptype), pCount++); + _writeTypeIndexValueLine(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 + _writeTypeIndexValue(macrosStream, getTypeIndexVariableName(container), pCount); + macrosStream << ", // " << container->cppSignature() << endl; 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; + _writeTypeIndexValue(macrosStream, QStringLiteral("SBK_%1_CONVERTERS_IDX_COUNT") + .arg(moduleName()), pCount); + macrosStream << "\n};\n"; + + formatTypeDefEntries(macrosStream); + // TODO-CONVERTER ------------------------------------------------------------------------------ macrosStream << "// Macros for type check" << endl; @@ -474,12 +509,6 @@ bool HeaderGenerator::finishGeneration() s << "#include <sbkpython.h>" << endl; s << "#include <sbkconverter.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()) { @@ -580,7 +609,7 @@ void HeaderGenerator::writeInheritedOverloads(QTextStream& s) QString argName = arg->name(); const TypeEntry* enumTypeEntry = 0; if (arg->type()->isFlags()) - enumTypeEntry = reinterpret_cast<const FlagsTypeEntry*>(arg->type()->typeEntry())->originator(); + enumTypeEntry = static_cast<const FlagsTypeEntry*>(arg->type()->typeEntry())->originator(); else if (arg->type()->isEnum()) enumTypeEntry = arg->type()->typeEntry(); if (enumTypeEntry) diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.h b/sources/shiboken2/generator/shiboken2/headergenerator.h index acf0448a7..821531aab 100644 --- a/sources/shiboken2/generator/shiboken2/headergenerator.h +++ b/sources/shiboken2/generator/shiboken2/headergenerator.h @@ -55,8 +55,8 @@ private: 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 writeTypeIndexValueLine(QTextStream& s, const TypeEntry* typeEntry); + void writeTypeIndexValueLines(QTextStream& s, const AbstractMetaClass* metaClass); void writeProtectedEnumSurrogate(QTextStream& s, const AbstractMetaEnum* cppEnum); void writeInheritedOverloads(QTextStream& s); diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.cpp b/sources/shiboken2/generator/shiboken2/overloaddata.cpp index 73198ba12..a95603754 100644 --- a/sources/shiboken2/generator/shiboken2/overloaddata.cpp +++ b/sources/shiboken2/generator/shiboken2/overloaddata.cpp @@ -94,8 +94,6 @@ static bool typesAreEqual(const AbstractMetaType* typeA, const AbstractMetaType* */ 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 @@ -121,7 +119,7 @@ struct OverloadSortData int lastProcessedItemId() { return counter - 1; } - int counter; + int counter = 0; QHash<QString, int> map; // typeName -> id QHash<int, OverloadData*> reverseMap; // id -> OverloadData; }; @@ -149,11 +147,11 @@ static QString getImplicitConversionTypeName(const AbstractMetaType* containerTy for (const AbstractMetaType *otherType : instantiations) types << (otherType == instantiation ? impConv : getTypeName(otherType)); - const ContainerTypeEntry* containerTypeEntry = dynamic_cast<const ContainerTypeEntry*>(containerType->typeEntry()); - return containerTypeEntry->qualifiedCppName() + QLatin1Char('<') + return containerType->typeEntry()->qualifiedCppName() + QLatin1Char('<') + types.join(QLatin1String(", ")) + QLatin1String(" >"); } +// overloaddata.cpp static QString msgCyclicDependency(const QString &funcName, const QString &graphName, const OverloadData::MetaFunctionList &involvedConversions) { @@ -499,7 +497,8 @@ OverloadData::OverloadData(const AbstractMetaFunctionList& overloads, const Shib 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) + m_headOverloadData(headOverloadData), m_previousOverloadData(nullptr), + m_generator(nullptr) { if (func) this->addOverload(func); @@ -808,8 +807,7 @@ QPair<int, int> OverloadData::getMinMaxArguments(const AbstractMetaFunctionList& { int minArgs = 10000; int maxArgs = 0; - for (int i = 0; i < overloads.size(); i++) { - const AbstractMetaFunction* func = overloads[i]; + for (const AbstractMetaFunction *func : overloads) { int origNumArgs = func->arguments().size(); int removed = numberOfRemovedArguments(func); int numArgs = origNumArgs - removed; @@ -825,7 +823,7 @@ QPair<int, int> OverloadData::getMinMaxArguments(const AbstractMetaFunctionList& minArgs = fixedArgIndex; } } - return QPair<int, int>(minArgs, maxArgs); + return {minArgs, maxArgs}; } bool OverloadData::isSingleArgument(const AbstractMetaFunctionList& overloads) @@ -840,7 +838,7 @@ bool OverloadData::isSingleArgument(const AbstractMetaFunctionList& overloads) return singleArgument; } -void OverloadData::dumpGraph(QString filename) const +void OverloadData::dumpGraph(const QString &filename) const { QFile file(filename); if (file.open(QFile::WriteOnly)) { diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.h b/sources/shiboken2/generator/shiboken2/overloaddata.h index 435c19aa2..4759ca9c3 100644 --- a/sources/shiboken2/generator/shiboken2/overloaddata.h +++ b/sources/shiboken2/generator/shiboken2/overloaddata.h @@ -114,7 +114,7 @@ public: /// Returns true if all overloads have no more than one argument. static bool isSingleArgument(const AbstractMetaFunctionList& overloads); - void dumpGraph(QString filename) const; + void dumpGraph(const QString &filename) const; QString dumpGraph() const; bool hasArgumentTypeReplace() const; diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp index 80096cbf2..b9eea7529 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -28,9 +28,11 @@ #include "shibokengenerator.h" #include <abstractmetalang.h> +#include <messages.h> #include "overloaddata.h" #include <reporthandler.h> #include <typedatabase.h> +#include <abstractmetabuilder.h> #include <iostream> #include <QtCore/QDir> @@ -39,13 +41,29 @@ #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 const char NULL_VALUE[] = "NULL"; +static const char AVOID_PROTECTED_HACK[] = "avoid-protected-hack"; +static const char PARENT_CTOR_HEURISTIC[] = "enable-parent-ctor-heuristic"; +static const char RETURN_VALUE_HEURISTIC[] = "enable-return-value-heuristic"; +static const char ENABLE_PYSIDE_EXTENSIONS[] = "enable-pyside-extensions"; +static const char DISABLE_VERBOSE_ERROR_MESSAGES[] = "disable-verbose-error-messages"; +static const char USE_ISNULL_AS_NB_NONZERO[] = "use-isnull-as-nb_nonzero"; + +const char *CPP_ARG = "cppArg"; +const char *CPP_ARG_REMOVED = "removed_cppArg"; +const char *CPP_RETURN_VAR = "cppResult"; +const char *CPP_SELF_VAR = "cppSelf"; +const char *PYTHON_ARG = "pyArg"; +const char *PYTHON_ARGS = "pyArgs"; +const char *PYTHON_OVERRIDE_VAR = "pyOverride"; +const char *PYTHON_RETURN_VAR = "pyResult"; +const char *PYTHON_TO_CPP_VAR = "pythonToCpp"; +const char *SMART_POINTER_GETTER = "kSmartPointerGetter"; + +const char *CONV_RULE_OUT_VAR_SUFFIX = "_out"; +const char *BEGIN_ALLOW_THREADS = + "PyThreadState* _save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS"; +const char *END_ALLOW_THREADS = "PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS"; //static void dumpFunction(AbstractMetaFunctionList lst); @@ -100,7 +118,7 @@ static QString resolveScopePrefix(const AbstractMetaEnum *metaEnum, return resolveScopePrefix(parts, value); } -ShibokenGenerator::ShibokenGenerator() : Generator() +ShibokenGenerator::ShibokenGenerator() { if (m_pythonPrimitiveTypeName.isEmpty()) ShibokenGenerator::initPrimitiveTypesCorrespondences(); @@ -117,17 +135,19 @@ ShibokenGenerator::ShibokenGenerator() : Generator() m_typeSystemConvName[TypeSystemIsConvertibleFunction] = QLatin1String("isConvertible"); m_typeSystemConvName[TypeSystemToCppFunction] = QLatin1String("toCpp"); m_typeSystemConvName[TypeSystemToPythonFunction] = QLatin1String("toPython"); + + const char CHECKTYPE_REGEX[] = R"(%CHECKTYPE\[([^\[]*)\]\()"; + const char ISCONVERTIBLE_REGEX[] = R"(%ISCONVERTIBLE\[([^\[]*)\]\()"; + const char CONVERTTOPYTHON_REGEX[] = R"(%CONVERTTOPYTHON\[([^\[]*)\]\()"; + const char CONVERTTOCPP_REGEX[] = + R"((\*?%?[a-zA-Z_][\w\.]*(?:\[[^\[^<^>]+\])*)(?:\s+)=(?:\s+)%CONVERTTOCPP\[([^\[]*)\]\()"; m_typeSystemConvRegEx[TypeSystemCheckFunction] = QRegularExpression(QLatin1String(CHECKTYPE_REGEX)); m_typeSystemConvRegEx[TypeSystemIsConvertibleFunction] = QRegularExpression(QLatin1String(ISCONVERTIBLE_REGEX)); m_typeSystemConvRegEx[TypeSystemToPythonFunction] = QRegularExpression(QLatin1String(CONVERTTOPYTHON_REGEX)); m_typeSystemConvRegEx[TypeSystemToCppFunction] = QRegularExpression(QLatin1String(CONVERTTOCPP_REGEX)); } -ShibokenGenerator::~ShibokenGenerator() -{ - // TODO-CONVERTER: it must be caching types that were not created here. - //qDeleteAll(m_metaTypeFromStringCache.values()); -} +ShibokenGenerator::~ShibokenGenerator() = default; void ShibokenGenerator::clearTpFuncs() { @@ -277,7 +297,7 @@ bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass* metaCl for (const AbstractMetaFunction *func : funcs) { if (!func->isProtected() || func->isSignal() || func->isModifiedRemoved()) continue; - else if (func->isOperatorOverload()) + if (func->isOperatorOverload()) protectedOperators++; else protectedFunctions++; @@ -332,9 +352,8 @@ QString ShibokenGenerator::wrapperName(const AbstractMetaClass* metaClass) const result += QLatin1String("Wrapper"); return result; - } else { - return metaClass->qualifiedCppName(); } + return metaClass->qualifiedCppName(); } QString ShibokenGenerator::wrapperName(const AbstractMetaType *metaType) const @@ -342,7 +361,19 @@ QString ShibokenGenerator::wrapperName(const AbstractMetaType *metaType) const return metaType->cppSignature(); } -QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction* func) +QString ShibokenGenerator::fullPythonClassName(const AbstractMetaClass *metaClass) +{ + QString fullClassName = metaClass->name(); + const AbstractMetaClass *enclosing = metaClass->enclosingClass(); + while (enclosing) { + fullClassName.prepend(enclosing->name() + QLatin1Char('.')); + enclosing = enclosing->enclosingClass(); + } + fullClassName.prepend(packageName() + QLatin1Char('.')); + return fullClassName; +} + +QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction *func) //WS { QString funcName; if (func->isOperatorOverload()) @@ -350,11 +381,11 @@ QString ShibokenGenerator::fullPythonFunctionName(const AbstractMetaFunction* fu else funcName = func->name(); if (func->ownerClass()) { - QString fullName = func->ownerClass()->fullName(); + QString fullClassName = fullPythonClassName(func->ownerClass()); if (func->isConstructor()) - funcName = fullName; + funcName = fullClassName; else - funcName.prepend(fullName + QLatin1Char('.')); + funcName.prepend(fullClassName + QLatin1Char('.')); } else { funcName = packageName() + QLatin1Char('.') + func->name(); @@ -434,7 +465,8 @@ QString ShibokenGenerator::cpythonSetterFunctionName(const AbstractMetaField* me return QStringLiteral("%1_set_%2").arg(cpythonBaseName(metaField->enclosingClass()), metaField->name()); } -static QString cpythonEnumFlagsName(QString moduleName, QString qualifiedCppName) +static QString cpythonEnumFlagsName(const QString &moduleName, + const QString &qualifiedCppName) { QString result = QStringLiteral("Sbk%1_%2").arg(moduleName, qualifiedCppName); result.replace(QLatin1String("::"), QLatin1String("_")); @@ -570,7 +602,7 @@ QString ShibokenGenerator::guessScopeForDefaultValue(const AbstractMetaFunction fieldName.prepend(prefix); prefix.clear(); } else { - fieldName.prepend(QLatin1String(CPP_SELF_VAR "->")); + fieldName.prepend(QLatin1String(CPP_SELF_VAR) + QLatin1String("->")); } value.replace(match.captured(1), fieldName); break; @@ -616,12 +648,14 @@ QString ShibokenGenerator::cpythonSpecialCastFunctionName(const AbstractMetaClas return cpythonBaseName(metaClass->typeEntry()) + QLatin1String("SpecialCastFunction"); } -QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClass* metaClass, QString argName) +QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaClass* metaClass, + const QString &argName) { return cpythonWrapperCPtr(metaClass->typeEntry(), argName); } -QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType *metaType, QString argName) +QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType *metaType, + const QString &argName) { if (!ShibokenGenerator::isWrapperType(metaType->typeEntry())) return QString(); @@ -630,7 +664,8 @@ QString ShibokenGenerator::cpythonWrapperCPtr(const AbstractMetaType *metaType, + QLatin1String(", reinterpret_cast<SbkObject *>(") + argName + QLatin1String(")))"); } -QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntry* type, QString argName) +QString ShibokenGenerator::cpythonWrapperCPtr(const TypeEntry* type, + const QString &argName) { if (!ShibokenGenerator::isWrapperType(type)) return QString(); @@ -706,7 +741,8 @@ QString ShibokenGenerator::getFormatUnitString(const AbstractMetaFunction* func, || arg->type()->referenceType() == LValueReference) { result += QLatin1Char(objType); } else if (arg->type()->isPrimitive()) { - const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) arg->type()->typeEntry(); + const PrimitiveTypeEntry *ptype = + static_cast<const PrimitiveTypeEntry *>(arg->type()->typeEntry()); if (ptype->basicReferencedTypeEntry()) ptype = ptype->basicReferencedTypeEntry(); if (m_formatUnits.contains(ptype->name())) @@ -745,7 +781,7 @@ QString ShibokenGenerator::cpythonBaseName(const TypeEntry* type) if (ShibokenGenerator::isWrapperType(type) || type->isNamespace()) { // && type->referenceType() == NoReference) { baseName = QLatin1String("Sbk_") + type->name(); } else if (type->isPrimitive()) { - const PrimitiveTypeEntry* ptype = (const PrimitiveTypeEntry*) type; + const PrimitiveTypeEntry *ptype = static_cast<const PrimitiveTypeEntry *>(type); while (ptype->basicReferencedTypeEntry()) ptype = ptype->basicReferencedTypeEntry(); if (ptype->targetLangApiName() == ptype->name()) @@ -753,11 +789,11 @@ QString ShibokenGenerator::cpythonBaseName(const TypeEntry* type) else baseName = ptype->targetLangApiName(); } else if (type->isEnum()) { - baseName = cpythonEnumName((const EnumTypeEntry*) type); + baseName = cpythonEnumName(static_cast<const EnumTypeEntry *>(type)); } else if (type->isFlags()) { - baseName = cpythonFlagsName((const FlagsTypeEntry*) type); + baseName = cpythonFlagsName(static_cast<const FlagsTypeEntry *>(type)); } else if (type->isContainer()) { - const ContainerTypeEntry* ctype = (const ContainerTypeEntry*) type; + const ContainerTypeEntry *ctype = static_cast<const ContainerTypeEntry *>(type); switch (ctype->type()) { case ContainerTypeEntry::ListContainer: case ContainerTypeEntry::StringListContainer: @@ -858,14 +894,6 @@ QString ShibokenGenerator::cpythonTypeNameExt(const AbstractMetaType* type) + 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::fixedCppTypeName(const CustomConversion::TargetToNativeConversion* toNative) @@ -925,7 +953,7 @@ QString ShibokenGenerator::pythonPrimitiveTypeName(const PrimitiveTypeEntry* typ return pythonPrimitiveTypeName(type->name()); } -QString ShibokenGenerator::pythonOperatorFunctionName(QString cppOpFuncName) +QString ShibokenGenerator::pythonOperatorFunctionName(const QString &cppOpFuncName) { QString value = m_pythonOperators.value(cppOpFuncName); if (value.isEmpty()) @@ -953,7 +981,7 @@ QString ShibokenGenerator::pythonOperatorFunctionName(const AbstractMetaFunction return op; } -QString ShibokenGenerator::pythonRichCompareOperatorId(QString cppOpFuncName) +QString ShibokenGenerator::pythonRichCompareOperatorId(const QString &cppOpFuncName) { return QLatin1String("Py_") + m_pythonOperators.value(cppOpFuncName).toUpper(); } @@ -963,7 +991,7 @@ QString ShibokenGenerator::pythonRichCompareOperatorId(const AbstractMetaFunctio return pythonRichCompareOperatorId(func->originalName()); } -bool ShibokenGenerator::isNumber(QString cpythonApiName) +bool ShibokenGenerator::isNumber(const QString &cpythonApiName) { return cpythonApiName == QLatin1String("PyInt") || cpythonApiName == QLatin1String("PyFloat") @@ -975,7 +1003,7 @@ bool ShibokenGenerator::isNumber(const TypeEntry* type) { if (!type->isPrimitive()) return false; - return isNumber(pythonPrimitiveTypeName((const PrimitiveTypeEntry*) type)); + return isNumber(pythonPrimitiveTypeName(static_cast<const PrimitiveTypeEntry *>(type))); } bool ShibokenGenerator::isNumber(const AbstractMetaType* type) @@ -987,7 +1015,8 @@ bool ShibokenGenerator::isPyInt(const TypeEntry* type) { if (!type->isPrimitive()) return false; - return pythonPrimitiveTypeName((const PrimitiveTypeEntry*) type) == QLatin1String("PyInt"); + return pythonPrimitiveTypeName(static_cast<const PrimitiveTypeEntry *>(type)) + == QLatin1String("PyInt"); } bool ShibokenGenerator::isPyInt(const AbstractMetaType* type) @@ -998,7 +1027,7 @@ bool ShibokenGenerator::isPyInt(const AbstractMetaType* type) bool ShibokenGenerator::isWrapperType(const TypeEntry* type) { if (type->isComplex()) - return ShibokenGenerator::isWrapperType((const ComplexTypeEntry*)type); + return ShibokenGenerator::isWrapperType(static_cast<const ComplexTypeEntry *>(type)); return type->isObject() || type->isValue() || type->isSmartPointer(); } bool ShibokenGenerator::isWrapperType(const ComplexTypeEntry* type) @@ -1052,7 +1081,7 @@ bool ShibokenGenerator::isUserPrimitive(const TypeEntry* type) { if (!type->isPrimitive()) return false; - const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type; + const PrimitiveTypeEntry *trueType = static_cast<const PrimitiveTypeEntry *>(type); if (trueType->basicReferencedTypeEntry()) trueType = trueType->basicReferencedTypeEntry(); return trueType->isPrimitive() && !trueType->isCppPrimitive() @@ -1072,7 +1101,7 @@ bool ShibokenGenerator::isCppPrimitive(const TypeEntry* type) return true; if (!type->isPrimitive()) return false; - const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type; + const PrimitiveTypeEntry *trueType = static_cast<const PrimitiveTypeEntry *>(type); if (trueType->basicReferencedTypeEntry()) trueType = trueType->basicReferencedTypeEntry(); return trueType->qualifiedCppName() == QLatin1String("std::string"); @@ -1125,9 +1154,11 @@ QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType if (isVoidPointer(metaType)) return QLatin1String("PyObject_Check"); return cpythonCheckFunction(metaType->typeEntry(), genericNumberType); - } else if (metaType->typeEntry()->isContainer()) { + } + if (metaType->typeEntry()->isContainer()) { QString typeCheck = QLatin1String("Shiboken::Conversions::"); - ContainerTypeEntry::Type type = ((const ContainerTypeEntry*)metaType->typeEntry())->type(); + ContainerTypeEntry::Type type = + static_cast<const ContainerTypeEntry *>(metaType->typeEntry())->type(); if (type == ContainerTypeEntry::ListContainer || type == ContainerTypeEntry::StringListContainer || type == ContainerTypeEntry::LinkedListContainer @@ -1154,8 +1185,8 @@ QString ShibokenGenerator::cpythonCheckFunction(const AbstractMetaType* metaType const AbstractMetaType* firstType = metaType->instantiations().constFirst(); const AbstractMetaType* secondType = metaType->instantiations().constLast(); if (isPointerToWrapperType(firstType) && isPointerToWrapperType(secondType)) { - typeCheck += QString::fromLatin1("check%1Types(%2, %3, ").arg(pyType) - .arg(cpythonTypeNameExt(firstType), cpythonTypeNameExt(secondType)); + typeCheck += QString::fromLatin1("check%1Types(%2, %3, ") + .arg(pyType, cpythonTypeNameExt(firstType), cpythonTypeNameExt(secondType)); } else { typeCheck += QString::fromLatin1("convertible%1Types(%2, %3, %4, %5, ") .arg(pyType, converterObject(firstType), @@ -1182,8 +1213,10 @@ QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry* type, bool gene 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"); + if (isCppPrimitive(type)) { + return pythonPrimitiveTypeName(static_cast<const PrimitiveTypeEntry *>(type)) + + QLatin1String("_Check"); + } QString typeCheck; if (type->targetLangApiName() == type->name()) typeCheck = cpythonIsConvertibleFunction(type); @@ -1392,7 +1425,7 @@ void ShibokenGenerator::writeFunctionArguments(QTextStream &s, if (options & Generator::WriteSelf) { s << func->implementingClass()->name() << '&'; if (!(options & SkipName)) - s << " " PYTHON_SELF_VAR; + s << " self"; } int argUsed = 0; @@ -1412,13 +1445,12 @@ QString ShibokenGenerator::functionReturnType(const AbstractMetaFunction* func, QString modifiedReturnType = QString(func->typeReplaced(0)); if (!modifiedReturnType.isNull() && !(options & OriginalTypeDescription)) return modifiedReturnType; - else - return translateType(func->type(), func->implementingClass(), options); + return translateType(func->type(), func->implementingClass(), options); } QString ShibokenGenerator::functionSignature(const AbstractMetaFunction *func, - QString prepend, - QString append, + const QString &prepend, + const QString &append, Options options, int /* argCount */) const { @@ -1619,8 +1651,9 @@ ShibokenGenerator::ArgumentVarReplacementList ShibokenGenerator::getArgumentRepl QString argValue; if (language == TypeSystem::TargetLangCode) { bool hasConversionRule = !func->conversionRule(convLang, i+1).isEmpty(); - bool argRemoved = func->argumentRemoved(i+1); - removed = removed + (int) argRemoved; + const bool argRemoved = func->argumentRemoved(i+1); + if (argRemoved) + ++removed; if (argRemoved && hasConversionRule) argValue = arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX); else if (argRemoved || (lastArg && arg->argumentIndex() > lastArg->argumentIndex())) @@ -1636,8 +1669,7 @@ ShibokenGenerator::ArgumentVarReplacementList ShibokenGenerator::getArgumentRepl } if (type->typeEntry()->isCustom()) { argValue = usePyArgs - ? QString::fromLatin1(PYTHON_ARGS "[%1]").arg(argPos) - : QLatin1String(PYTHON_ARG); + ? pythonArgsAt(argPos) : QLatin1String(PYTHON_ARG); } else { argValue = hasConversionRule ? arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX) @@ -1673,17 +1705,6 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s, 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, @@ -1712,7 +1733,7 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s, Q_ASSERT(pyArgsRegex.isValid()); if (language == TypeSystem::TargetLangCode) { if (usePyArgs) { - code.replace(pyArgsRegex, QLatin1String(PYTHON_ARGS"[\\1-1]")); + code.replace(pyArgsRegex, QLatin1String(PYTHON_ARGS) + QLatin1String("[\\1-1]")); } else { static const QRegularExpression pyArgsRegexCheck(QStringLiteral("%PYARG_([2-9]+)")); Q_ASSERT(pyArgsRegexCheck.isValid()); @@ -1729,8 +1750,10 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s, // 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)")); + code.replace(pyArgsAttributionRegex, QLatin1String("PyTuple_SET_ITEM(") + + QLatin1String(PYTHON_ARGS) + QLatin1String(", \\1-1, \\2)")); + code.replace(pyArgsRegex, QLatin1String("PyTuple_GET_ITEM(") + + QLatin1String(PYTHON_ARGS) + QLatin1String(", \\1-1)")); } // Replace %ARG#_TYPE variables. @@ -1763,7 +1786,8 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s, } // Replace template variable for self Python object. - QString pySelf = (language == TypeSystem::NativeCode) ? QLatin1String("pySelf") : QLatin1String(PYTHON_SELF_VAR); + QString pySelf = language == TypeSystem::NativeCode + ? QLatin1String("pySelf") : QLatin1String("self"); code.replace(QLatin1String("%PYSELF"), pySelf); // Replace template variable for a pointer to C++ of this object. @@ -1960,16 +1984,6 @@ static QString getConverterTypeSystemVariableArgument(const QString& code, int p } typedef QPair<QString, QString> StringPair; -static QString msgCannotFindType(const QString &type, const QString &variable, - const QString &why) -{ - QString result; - QTextStream(&result) << "Could not find type '" - << type << "' for use in '" << variable << "' conversion: " << why - << "\nMake sure to use the full C++ name, e.g. 'Namespace::Class'."; - return result; -} - void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString& code) { QVector<StringPair> replacements; @@ -1978,7 +1992,7 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa const QRegularExpressionMatch match = rit.next(); const QStringList list = match.capturedTexts(); QString conversionString = list.constFirst(); - QString conversionTypeName = list.constLast(); + const QString &conversionTypeName = list.constLast(); QString message; const AbstractMetaType *conversionType = buildAbstractMetaTypeFromString(conversionTypeName, &message); if (!conversionType) { @@ -2002,8 +2016,8 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa 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); + qFatal("Types of receiver variable ('%s') and %%CONVERTTOCPP type system variable ('%s') differ.", + qPrintable(varType), qPrintable(conversionType->cppSignature())); } c << getFullTypeName(conversionType) << ' ' << varName; writeMinimalConstructorExpression(c, conversionType); @@ -2032,18 +2046,21 @@ void ShibokenGenerator::replaceConverterTypeSystemVariable(TypeSystemConverterVa c << '('; break; } + Q_FALLTHROUGH(); case TypeSystemIsConvertibleFunction: if (conversion.isEmpty()) conversion = cpythonIsConvertibleFunction(conversionType); + Q_FALLTHROUGH(); case TypeSystemToPythonFunction: if (conversion.isEmpty()) conversion = cpythonToPythonConversionFunction(conversionType); + Q_FALLTHROUGH(); default: { QString arg = getConverterTypeSystemVariableArgument(code, match.capturedEnd()); conversionString += arg; if (converterVariable == TypeSystemToPythonFunction && !isVariable(arg)) { - qFatal(qPrintable(QString::fromLatin1("Only variables are acceptable as argument to %%CONVERTTOPYTHON type system variable on code snippet: '%1'") - .arg(code)), NULL); + qFatal("Only variables are acceptable as argument to %%CONVERTTOPYTHON type system variable on code snippet: '%s'", + qPrintable(code)); } if (conversion.contains(QLatin1String("%in"))) { conversion.prepend(QLatin1Char('(')); @@ -2172,9 +2189,7 @@ bool ShibokenGenerator::classNeedsSetattroFunction(const AbstractMetaClass *meta { if (!metaClass) return false; - if (metaClass->typeEntry()->isSmartPointer()) - return true; - return false; + return metaClass->typeEntry()->isSmartPointer(); } AbstractMetaFunctionList ShibokenGenerator::getMethodsWithBothStaticAndNonStaticMethods(const AbstractMetaClass* metaClass) @@ -2244,9 +2259,7 @@ AbstractMetaClassList ShibokenGenerator::getAllAncestors(const AbstractMetaClass QString ShibokenGenerator::getModuleHeaderFileName(const QString& moduleName) const { - QString result = moduleName.isEmpty() ? packageName() : moduleName; - result.replace(QLatin1Char('.'), QLatin1Char('_')); - return result.toLower() + QLatin1String("_python.h"); + return moduleCppPrefix(moduleName).toLower() + QLatin1String("_python.h"); } bool ShibokenGenerator::isCopyable(const AbstractMetaClass *metaClass) @@ -2254,12 +2267,10 @@ bool ShibokenGenerator::isCopyable(const AbstractMetaClass *metaClass) { if (metaClass->isNamespace() || isObjectType(metaClass)) return false; - else if (metaClass->typeEntry()->copyable() == ComplexTypeEntry::Unknown) + if (metaClass->typeEntry()->copyable() == ComplexTypeEntry::Unknown) return metaClass->hasCloneOperator(); - else - return (metaClass->typeEntry()->copyable() == ComplexTypeEntry::CopyableSet); - return false; + return metaClass->typeEntry()->copyable() == ComplexTypeEntry::CopyableSet; } AbstractMetaType *ShibokenGenerator::buildAbstractMetaTypeFromString(QString typeSignature, @@ -2269,110 +2280,18 @@ AbstractMetaType *ShibokenGenerator::buildAbstractMetaTypeFromString(QString typ 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; - AbstractMetaTypeList instantiations; - int lpos = typeString.indexOf(QLatin1Char('<')); - if (lpos > -1) { - QStringList instantiatedTypes; - 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); - } - for (const QString &instantiatedType : qAsConst(instantiatedTypes)) { - AbstractMetaType *tmplArgType = buildAbstractMetaTypeFromString(instantiatedType); - if (!tmplArgType) { - if (errorMessage) { - QTextStream(errorMessage) << "Cannot find template type \"" - << instantiatedType << "\" for \"" << typeSignature << "\"."; - } - return nullptr; - } - instantiations.append(tmplArgType); - } - } - - TypeEntry *typeEntry = nullptr; - AbstractMetaType::TypeUsagePattern pattern = AbstractMetaType::InvalidPattern; - - if (instantiations.size() == 1 - && instantiations.at(0)->typeUsagePattern() == AbstractMetaType::EnumPattern - && adjustedTypeName == QLatin1String("QFlags")) { - pattern = AbstractMetaType::FlagsPattern; - typeEntry = TypeDatabase::instance()->findType(typeSignature); - } else { - typeEntry = TypeDatabase::instance()->findType(adjustedTypeName); - } - - if (!typeEntry) { - if (errorMessage) { - QTextStream(errorMessage) << "Cannot find type \"" << adjustedTypeName - << "\" for \"" << typeSignature << "\"."; + auto it = m_metaTypeFromStringCache.find(typeSignature); + if (it == m_metaTypeFromStringCache.end()) { + AbstractMetaType *metaType = + AbstractMetaBuilder::translateType(typeSignature, nullptr, true, errorMessage); + if (Q_UNLIKELY(!metaType)) { + if (errorMessage) + errorMessage->prepend(msgCannotBuildMetaType(typeSignature)); + return nullptr; } - return nullptr; + it = m_metaTypeFromStringCache.insert(typeSignature, metaType); } - - AbstractMetaType *metaType = new AbstractMetaType(); - metaType->setTypeEntry(typeEntry); - metaType->setIndirections(indirections); - metaType->setReferenceType(refType); - metaType->setConstant(isConst); - metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern); - switch (pattern) { - case AbstractMetaType::FlagsPattern: - metaType->setTypeUsagePattern(pattern); - break; - default: - metaType->setInstantiations(instantiations); - metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern); - metaType->decideUsagePattern(); - break; - } - - m_metaTypeFromStringCache.insert(typeSignature, metaType); - return metaType; + return it.value(); } AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(const TypeEntry* typeEntry) @@ -2384,7 +2303,7 @@ AbstractMetaType* ShibokenGenerator::buildAbstractMetaTypeFromTypeEntry(const Ty return m_metaTypeFromStringCache.value(typeName); AbstractMetaType* metaType = new AbstractMetaType; metaType->setTypeEntry(typeEntry); - metaType->setIndirections(0); + metaType->clearIndirections(); metaType->setReferenceType(NoReference); metaType->setConstant(false); metaType->decideUsagePattern(); @@ -2449,7 +2368,7 @@ AbstractMetaFunctionList ShibokenGenerator::getInheritedOverloads(const Abstract { AbstractMetaFunctionList results; AbstractMetaClass* basis; - if (func->ownerClass() && (basis = func->ownerClass()->baseClass(), basis)) { + if (func->ownerClass() && (basis = func->ownerClass()->baseClass())) { for (; basis; basis = basis->baseClass()) { const AbstractMetaFunction* inFunc = basis->findFunction(func->name()); if (inFunc && !seen->contains(inFunc->minimalSignature())) { @@ -2509,6 +2428,23 @@ Generator::OptionDescriptions ShibokenGenerator::options() const "the value of boolean casts")); } +bool ShibokenGenerator::handleOption(const QString &key, const QString & /* value */) +{ + if (key == QLatin1String(PARENT_CTOR_HEURISTIC)) + return (m_useCtorHeuristic = true); + if (key == QLatin1String(ENABLE_PYSIDE_EXTENSIONS)) + return (m_usePySideExtensions = true); + if (key == QLatin1String(RETURN_VALUE_HEURISTIC)) + return (m_userReturnValueHeuristic = true); + if (key == QLatin1String(DISABLE_VERBOSE_ERROR_MESSAGES)) + return (m_verboseErrorMessagesDisabled = true); + if (key == QLatin1String(USE_ISNULL_AS_NB_NONZERO)) + return (m_useIsNullAsNbNonZero = true); + if (key == QLatin1String(AVOID_PROTECTED_HACK)) + return (m_avoidProtectedHack = true); + return false; +} + static void getCode(QStringList& code, const CodeSnipList& codeSnips) { for (const CodeSnip &snip : qAsConst(codeSnips)) @@ -2534,15 +2470,8 @@ static void getCode(QStringList& code, const TypeEntry* type) code.append(toNative->conversion()); } -bool ShibokenGenerator::doSetup(const QMap<QString, QString>& args) +bool ShibokenGenerator::doSetup() { - 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(); @@ -2554,7 +2483,11 @@ bool ShibokenGenerator::doSetup(const QMap<QString, QString>& args) const AbstractMetaClassList &classList = classes(); for (const AbstractMetaClass *metaClass : classList) getCode(snips, metaClass->typeEntry()); - getCode(snips, td->findType(packageName())); + + const TypeSystemTypeEntry *moduleEntry = td->findTypeSystemType(packageName()); + Q_ASSERT(moduleEntry); + getCode(snips, moduleEntry); + const FunctionGroupMap &functionGroups = getFunctionGroups(); for (FunctionGroupMapIt it = functionGroups.cbegin(), end = functionGroups.cend(); it != end; ++it) { for (AbstractMetaFunction *func : it.value()) @@ -2611,15 +2544,25 @@ bool ShibokenGenerator::avoidProtectedHack() const return m_avoidProtectedHack; } -QString ShibokenGenerator::cppApiVariableName(const QString& moduleName) const -{ - QString result = moduleName.isEmpty() ? ShibokenGenerator::packageName() : moduleName; +QString ShibokenGenerator::moduleCppPrefix(const QString& moduleName) const + { + QString result = moduleName.isEmpty() ? packageName() : moduleName; result.replace(QLatin1Char('.'), QLatin1Char('_')); - result.prepend(QLatin1String("Sbk")); - result.append(QLatin1String("Types")); return result; } +QString ShibokenGenerator::cppApiVariableName(const QString& moduleName) const +{ + return QLatin1String("Sbk") + moduleCppPrefix(moduleName) + + QLatin1String("Types"); +} + +QString ShibokenGenerator::pythonModuleObjectName(const QString& moduleName) const +{ + return QLatin1String("Sbk") + moduleCppPrefix(moduleName) + + QLatin1String("ModuleObject"); +} + QString ShibokenGenerator::convertersVariableName(const QString& moduleName) const { QString result = cppApiVariableName(moduleName); @@ -2639,35 +2582,50 @@ static QString processInstantiationsVariableName(const AbstractMetaType* type) } return res; } + +static void appendIndexSuffix(QString *s) +{ + if (!s->endsWith(QLatin1Char('_'))) + s->append(QLatin1Char('_')); + s->append(QStringLiteral("IDX")); +} + QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaClass* metaClass, bool alternativeTemplateName) { if (alternativeTemplateName) { const AbstractMetaClass* templateBaseClass = metaClass->templateBaseClass(); if (!templateBaseClass) return QString(); - QString base = _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper(); - QString instantiations; + QString result = QLatin1String("SBK_") + + _fixedCppTypeName(templateBaseClass->typeEntry()->qualifiedCppName()).toUpper(); const AbstractMetaTypeList &templateBaseClassInstantiations = metaClass->templateBaseClassInstantiations(); for (const AbstractMetaType *instantiation : templateBaseClassInstantiations) - instantiations += processInstantiationsVariableName(instantiation); - return QString::fromLatin1("SBK_%1%2_IDX").arg(base, instantiations); + result += processInstantiationsVariableName(instantiation); + appendIndexSuffix(&result); + return result; } return getTypeIndexVariableName(metaClass->typeEntry()); } QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry* type) { if (type->isCppPrimitive()) { - const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type; + const PrimitiveTypeEntry *trueType = static_cast<const PrimitiveTypeEntry*>(type); if (trueType->basicReferencedTypeEntry()) type = trueType->basicReferencedTypeEntry(); } - return QString::fromLatin1("SBK_%1_IDX").arg(_fixedCppTypeName(type->qualifiedCppName()).toUpper()); + QString result = QLatin1String("SBK_") + + _fixedCppTypeName(type->qualifiedCppName()).toUpper(); + appendIndexSuffix(&result); + return result; } QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType* type) { - return QString::fromLatin1("SBK%1%2_IDX") - .arg(type->typeEntry()->isContainer() ? QLatin1Char('_') + moduleName().toUpper() : QString(), - processInstantiationsVariableName(type)); + QString result = QLatin1String("SBK"); + if (type->typeEntry()->isContainer()) + result += QLatin1Char('_') + moduleName().toUpper(); + result += processInstantiationsVariableName(type); + appendIndexSuffix(&result); + return result; } bool ShibokenGenerator::verboseErrorMessagesDisabled() const @@ -2707,30 +2665,37 @@ QString ShibokenGenerator::getDefaultValue(const AbstractMetaFunction* func, co void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const AbstractMetaType* type, const QString& defaultCtor) { - if (defaultCtor.isEmpty() && isCppPrimitive(type)) + if (!defaultCtor.isEmpty()) { + s << " = " << defaultCtor; + return; + } + if (isCppPrimitive(type)) return; - QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor; - if (ctor.isEmpty()) { + const auto ctor = minimalConstructor(type); + if (ctor.isValid()) { + s << ctor.initialization(); + } else { const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->cppSignature()); qCWarning(lcShiboken()).noquote() << message; s << ";\n#error " << message << '\n'; - } else { - s << " = " << ctor; } } void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream& s, const TypeEntry* type, const QString& defaultCtor) { - if (defaultCtor.isEmpty() && isCppPrimitive(type)) + if (!defaultCtor.isEmpty()) { + s << " = " << defaultCtor; + return; + } + if (isCppPrimitive(type)) return; - QString ctor = defaultCtor.isEmpty() ? minimalConstructor(type) : defaultCtor; - - if (ctor.isEmpty()) { + const auto ctor = minimalConstructor(type); + if (ctor.isValid()) { + s << ctor.initialization(); + } else { const QString message = msgCouldNotFindMinimalConstructor(QLatin1String(__FUNCTION__), type->qualifiedCppName()); qCWarning(lcShiboken()).noquote() << message; s << ";\n#error " << message << endl; - } else { - s << " = " << ctor; } } @@ -2738,7 +2703,7 @@ bool ShibokenGenerator::isCppIntegralPrimitive(const TypeEntry* type) { if (!type->isCppPrimitive()) return false; - const PrimitiveTypeEntry* trueType = (const PrimitiveTypeEntry*) type; + const PrimitiveTypeEntry *trueType = static_cast<const PrimitiveTypeEntry *>(type); if (trueType->basicReferencedTypeEntry()) trueType = trueType->basicReferencedTypeEntry(); QString typeName = trueType->qualifiedCppName(); @@ -2751,8 +2716,8 @@ bool ShibokenGenerator::isCppIntegralPrimitive(const AbstractMetaType* type) return isCppIntegralPrimitive(type->typeEntry()); } -QString ShibokenGenerator::msgCouldNotFindMinimalConstructor(const QString &where, const QString &type) +QString ShibokenGenerator::pythonArgsAt(int i) { - return where + QLatin1String(": Could not find a minimal constructor for type '") + type - + QLatin1String("'. This will result in a compilation error."); + return QLatin1String(PYTHON_ARGS) + QLatin1Char('[') + + QString::number(i) + QLatin1Char(']'); } diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h index cb1bdd11f..60e31a99b 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.h +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.h @@ -29,28 +29,20 @@ #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\\[([^\\[]*)\\]\\(" +extern const char *CPP_ARG; +extern const char *CPP_ARG_REMOVED; +extern const char *CPP_RETURN_VAR; +extern const char *CPP_SELF_VAR; +extern const char *PYTHON_ARG; +extern const char *PYTHON_ARGS; +extern const char *PYTHON_OVERRIDE_VAR; +extern const char *PYTHON_RETURN_VAR; +extern const char *PYTHON_TO_CPP_VAR; +extern const char *SMART_POINTER_GETTER; + +extern const char *CONV_RULE_OUT_VAR_SUFFIX; +extern const char *BEGIN_ALLOW_THREADS; +extern const char *END_ALLOW_THREADS; #include <generator.h> @@ -71,61 +63,20 @@ class ShibokenGenerator : public Generator { public: ShibokenGenerator(); - virtual ~ShibokenGenerator(); + ~ShibokenGenerator() override; - QString translateTypeForWrapperMethod(const AbstractMetaType* cType, - const AbstractMetaClass* context, Options opt = NoOption) const; + const char *name() const override { return "Shiboken"; } /** - * 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); + * Helper function to find for argument default value + */ + static QString getDefaultValue(const AbstractMetaFunction* func, const AbstractMetaArgument* arg); - /** - * 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 a list of all ancestor classes for the given class. + AbstractMetaClassList getAllAncestors(const AbstractMetaClass* metaClass) const; - /** - * Returns all overloads for a function named \p functionName. - * \param scope scope used to search for overloads. - * \param functionName the function name. - */ - AbstractMetaFunctionList getFunctionOverloads(const AbstractMetaClass* scope, const QString& functionName); - /** - * Write a function argument in the C++ in the text stream \p s. - * This function just call \code s << argumentString(); \endcode - * \param s text stream used to write the output. - * \param func the current metafunction. - * \param argument metaargument information to be parsed. - * \param options some extra options. - */ - void writeArgument(QTextStream &s, - const AbstractMetaFunction* func, - const AbstractMetaArgument* argument, - Options options = NoOption) const; - /** - * Create a QString in the C++ format to an function argument. - * \param func the current metafunction. - * \param argument metaargument information to be parsed. - * \param options some extra options. - */ - QString argumentString(const AbstractMetaFunction* func, - const AbstractMetaArgument* argument, - Options options = NoOption) const; +protected: + bool doSetup() override; void writeArgumentNames(QTextStream &s, const AbstractMetaFunction* func, @@ -141,14 +92,21 @@ public: 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); + /** + * 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, and includes func as well. + * The function can be called multiple times without duplication. + * \param func the metafunction to be searched in subclasses. + * \param seen the function's minimal signatures already seen. + */ + AbstractMetaFunctionList getFunctionAndInheritedOverloads(const AbstractMetaFunction *func, QSet<QString> *seen); /// Write user's custom code snippets at class or module level. void writeCodeSnips(QTextStream& s, @@ -164,33 +122,9 @@ public: 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 "native" * type needs the type system variable "%PYSELF". @@ -239,8 +173,8 @@ public: * \param arg_count the number of function arguments */ QString functionSignature(const AbstractMetaFunction* func, - QString prepend = QString(), - QString append = QString(), + const QString &prepend = QString(), + const QString &append = QString(), Options options = NoOption, int arg_count = -1) const; @@ -259,9 +193,6 @@ public: /// 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, @@ -283,7 +214,8 @@ public: QString wrapperName(const AbstractMetaClass* metaClass) const; QString wrapperName(const AbstractMetaType *metaType) const; - QString fullPythonFunctionName(const AbstractMetaFunction* func); + QString fullPythonClassName(const AbstractMetaClass *metaClass); + QString fullPythonFunctionName(const AbstractMetaFunction *func); //WS static QString protectedEnumSurrogateName(const AbstractMetaEnum* metaEnum); static QString protectedFieldGetterName(const AbstractMetaField* field); @@ -292,16 +224,16 @@ public: static QString pythonPrimitiveTypeName(const QString& cppTypeName); static QString pythonPrimitiveTypeName(const PrimitiveTypeEntry* type); - static QString pythonOperatorFunctionName(QString cppOpFuncName); + static QString pythonOperatorFunctionName(const QString &cppOpFuncName); static QString pythonOperatorFunctionName(const AbstractMetaFunction* func); - static QString pythonRichCompareOperatorId(QString cppOpFuncName); + static QString pythonRichCompareOperatorId(const QString &cppOpFuncName); static QString pythonRichCompareOperatorId(const AbstractMetaFunction* func); static QString fixedCppTypeName(const CustomConversion::TargetToNativeConversion* toNative); static QString fixedCppTypeName(const AbstractMetaType* type); static QString fixedCppTypeName(const TypeEntry* type, QString typeName = QString()); - static bool isNumber(QString cpythonApiName); + static bool isNumber(const QString &cpythonApiName); static bool isNumber(const TypeEntry* type); static bool isNumber(const AbstractMetaType* type); static bool isPyInt(const TypeEntry* type); @@ -389,9 +321,10 @@ public: 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); + QString cpythonWrapperCPtr(const AbstractMetaClass* metaClass, + const QString &argName = QLatin1String("self")); + QString cpythonWrapperCPtr(const AbstractMetaType *metaType, const QString &argName); + QString cpythonWrapperCPtr(const TypeEntry* type, const QString &argName); /// Guesses the scope to where belongs an argument's default value. QString guessScopeForDefaultValue(const AbstractMetaFunction *func, @@ -414,6 +347,7 @@ public: QString getModuleHeaderFileName(const QString& moduleName = QString()) const; OptionDescriptions options() const override; + bool handleOption(const QString &key, const QString &value) override; /// Returns true if the user enabled the so called "parent constructor heuristic". bool useCtorHeuristic() const; @@ -426,6 +360,7 @@ public: /// Returns true if the generated code should use the "#define protected public" hack. bool avoidProtectedHack() const; QString cppApiVariableName(const QString& moduleName = QString()) const; + QString pythonModuleObjectName(const QString& moduleName = QString()) const; QString convertersVariableName(const QString& moduleName = QString()) const; /** * Returns the type index variable name for a given class. If \p alternativeTemplateName is true @@ -457,26 +392,12 @@ public: 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 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(); @@ -505,6 +426,74 @@ protected: Indentor INDENT; + const QRegularExpression &convertToCppRegEx() const + { return m_typeSystemConvRegEx[TypeSystemToCppFunction]; } + + static QString pythonArgsAt(int i); + + static QHash<QString, QString> m_pythonPrimitiveTypeName; + static QHash<QString, QString> m_pythonOperators; + static QHash<QString, QString> m_formatUnits; + static QHash<QString, QString> m_tpFuncs; + static QStringList m_knownPythonTypes; + +private: + QString translateTypeForWrapperMethod(const AbstractMetaType* cType, + const AbstractMetaClass* context, + Options opt = NoOption) const; + + /** + * Returns all different inherited overloads of func. + * The function can be called multiple times without duplication. + * \param func the metafunction to be searched in subclasses. + * \param seen the function's minimal signatures already seen. + */ + AbstractMetaFunctionList getInheritedOverloads(const AbstractMetaFunction *func, + QSet<QString> *seen); + + /** + * Returns all overloads for a function named \p functionName. + * \param scope scope used to search for overloads. + * \param functionName the function name. + */ + AbstractMetaFunctionList getFunctionOverloads(const AbstractMetaClass* scope, + const QString& functionName); + /** + * Write a function argument in the C++ in the text stream \p s. + * This function just call \code s << argumentString(); \endcode + * \param s text stream used to write the output. + * \param func the current metafunction. + * \param argument metaargument information to be parsed. + * \param options some extra options. + */ + void writeArgument(QTextStream &s, + const AbstractMetaFunction* func, + const AbstractMetaArgument* argument, + Options options = NoOption) const; + /** + * Create a QString in the C++ format to an function argument. + * \param func the current metafunction. + * \param argument metaargument information to be parsed. + * \param options some extra options. + */ + QString argumentString(const AbstractMetaFunction* func, + const AbstractMetaArgument* argument, + Options options = NoOption) const; + + QString functionReturnType(const AbstractMetaFunction* func, Options options = NoOption) const; + + /// Utility function for writeCodeSnips. + typedef QPair<const AbstractMetaArgument*, QString> ArgumentVarReplacementPair; + typedef QVector<ArgumentVarReplacementPair> ArgumentVarReplacementList; + ArgumentVarReplacementList getArgumentReplacement(const AbstractMetaFunction* func, + bool usePyArgs, TypeSystem::Language language, + const AbstractMetaArgument* lastArg); + + /// Returns a string with the user's custom code snippets that comply with \p position and \p language. + QString getCodeSnippets(const QVector<CodeSnip> & codeSnips, + TypeSystem::CodeSnipPosition position, + TypeSystem::Language language); + enum TypeSystemConverterVariable { TypeSystemCheckFunction = 0, TypeSystemIsConvertibleFunction, @@ -514,15 +503,36 @@ protected: }; void replaceConverterTypeSystemVariable(TypeSystemConverterVariable converterVariable, QString& code); - static QString msgCouldNotFindMinimalConstructor(const QString &where, const QString &type); + /// 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); + } -private: - bool m_useCtorHeuristic; - bool m_userReturnValueHeuristic; - bool m_usePySideExtensions; - bool m_verboseErrorMessagesDisabled; - bool m_useIsNullAsNbNonZero; - bool m_avoidProtectedHack; + /// Return a prefix with '_' suitable for names in C++ + QString moduleCppPrefix(const QString& moduleName = QString()) const; + + bool m_useCtorHeuristic = false; + bool m_userReturnValueHeuristic = false; + bool m_usePySideExtensions = false; + bool m_verboseErrorMessagesDisabled = false; + bool m_useIsNullAsNbNonZero = false; + bool m_avoidProtectedHack = false; typedef QHash<QString, AbstractMetaType*> AbstractMetaTypeCache; AbstractMetaTypeCache m_metaTypeFromStringCache; |