diff options
Diffstat (limited to 'sources/shiboken2/generator/shiboken2/cppgenerator.cpp')
-rw-r--r-- | sources/shiboken2/generator/shiboken2/cppgenerator.cpp | 251 |
1 files changed, 127 insertions, 124 deletions
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index 4c637e701..0ad4fff3b 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -312,6 +312,7 @@ void CppGenerator::generateClass(QTextStream &s, const GeneratorContext &classCo s << "#include <pysidesignal.h>\n" << "#include <pysideproperty.h>\n" << "#include <pyside.h>\n" + << "#include <pysideqenum.h>\n" << "#include <qapp_macro.h>\n\n" << "QT_WARNING_DISABLE_DEPRECATED\n\n"; } @@ -784,6 +785,47 @@ QString CppGenerator::getVirtualFunctionReturnTypeName(const AbstractMetaFunctio + typeEntry->qualifiedCppName() + QLatin1String(" >())->tp_name"); } +// When writing an overridden method of a wrapper class, write the part +// calling the C++ function in case no overload in Python exists. +void CppGenerator::writeVirtualMethodCppCall(QTextStream &s, + const AbstractMetaFunction *func, + const QString &funcName, + const CodeSnipList &snips, + const AbstractMetaArgument *lastArg, + const TypeEntry *retType, + const DefaultValue &defaultReturnExpr) +{ + if (!snips.isEmpty()) { + writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, + TypeSystem::ShellCode, func, lastArg); + } + + if (func->isAbstract()) { + s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '" + << func->ownerClass()->name() << '.' << funcName + << "()' not implemented.\");\n"; + s << INDENT << "return"; + if (retType) + s << ' ' << defaultReturnExpr.returnValue(); + s << ";\n"; + return; + } + + s << INDENT; + if (retType) + s << "return "; + s << "this->::" << func->implementingClass()->qualifiedCppName() << "::"; + writeFunctionCall(s, func, Generator::VirtualCall); + s << ";\n"; + if (retType) + return; + if (!snips.isEmpty()) { + writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, + TypeSystem::ShellCode, func, lastArg); + } + s << INDENT << "return;\n"; +} + void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFunction *func, int cacheIndex) @@ -802,10 +844,10 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, Indentation indentation(INDENT); + const FunctionModificationList &functionModifications = func->modifications(); DefaultValue defaultReturnExpr; if (retType) { - const FunctionModificationList &mods = func->modifications(); - for (const FunctionModification &mod : mods) { + for (const FunctionModification &mod : functionModifications) { for (const ArgumentModification &argMod : mod.argument_mods) { if (argMod.index == 0 && !argMod.replacedDefaultExpression.isEmpty()) { static const QRegularExpression regex(QStringLiteral("%(\\d+)")); @@ -853,16 +895,17 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, return; } + const CodeSnipList snips = func->hasInjectedCode() + ? func->injectedCodeSnips() : CodeSnipList(); + const AbstractMetaArgument *lastArg = func->arguments().isEmpty() + ? nullptr : func->arguments().constLast(); + //Write declaration/native injected code - if (func->hasInjectedCode()) { - CodeSnipList snips = func->injectedCodeSnips(); - const AbstractMetaArgument *lastArg = func->arguments().isEmpty() ? nullptr : func->arguments().constLast(); - writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionDeclaration, TypeSystem::NativeCode, func, lastArg); - s << Qt::endl; + if (!snips.isEmpty()) { + writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionDeclaration, + TypeSystem::ShellCode, func, lastArg); } - // PYSIDE-803: Build a boolean cache for unused overrides. - bool multi_line = retType == nullptr; // set to true when using instrumentation if (wrapperDiagnostics()) { s << INDENT << "std::cerr << "; #ifndef Q_CC_MSVC // g++ outputs __FUNCTION__ unqualified @@ -872,22 +915,13 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, << cacheIndex << R"( << "]=" << m_PyMethodCache[)" << cacheIndex << R"(] << '\n';)" << '\n'; } + // PYSIDE-803: Build a boolean cache for unused overrides. + const bool multi_line = retType == nullptr || !snips.isEmpty() || func->isAbstract(); s << INDENT << "if (m_PyMethodCache[" << cacheIndex << "])" << (multi_line ? " {\n" : "\n"); { Indentation indentation(INDENT); - s << INDENT; - if (retType) - s << "return "; - if (!func->isAbstract()) { - s << "this->::" << func->implementingClass()->qualifiedCppName() << "::"; - writeFunctionCall(s, func, Generator::VirtualCall); - } else { - if (retType) - s << ' ' << defaultReturnExpr.returnValue(); - } - if (!retType) - s << ";\n" << INDENT << "return"; - s << ";\n"; + writeVirtualMethodCppCall(s, func, funcName, snips, lastArg, retType, + defaultReturnExpr); } if (multi_line) s << INDENT << "}\n"; @@ -907,36 +941,12 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, s << INDENT << "if (" << PYTHON_OVERRIDE_VAR << ".isNull()) {\n"; { Indentation indentation(INDENT); - CodeSnipList snips; - if (func->hasInjectedCode()) { - snips = func->injectedCodeSnips(); - const AbstractMetaArgument *lastArg = func->arguments().isEmpty() ? nullptr : func->arguments().constLast(); - writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::ShellCode, func, lastArg); - s << Qt::endl; - } - - if (func->isAbstract()) { - s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"pure virtual method '"; - s << func->ownerClass()->name() << '.' << funcName; - s << "()' not implemented.\");\n"; - s << INDENT << "return"; - if (retType) - s << ' ' << defaultReturnExpr.returnValue(); - } else { - s << INDENT << "gil.release();\n"; - if (useOverrideCaching(func->ownerClass())) { - s << INDENT << "m_PyMethodCache[" << cacheIndex << "] = true;\n"; - s << INDENT; - } - if (retType) - s << "return "; - s << "this->::" << func->implementingClass()->qualifiedCppName() << "::"; - writeFunctionCall(s, func, Generator::VirtualCall); - if (!retType) - s << ";\n" << INDENT << "return"; - } + s << INDENT << "gil.release();\n"; + if (useOverrideCaching(func->ownerClass())) + s << INDENT << "m_PyMethodCache[" << cacheIndex << "] = true;\n"; + writeVirtualMethodCppCall(s, func, funcName, snips, lastArg, retType, + defaultReturnExpr); } - s << ";\n"; s << INDENT << "}\n\n"; //WS writeConversionRule(s, func, TypeSystem::TargetLangCode); @@ -970,8 +980,9 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, convert = !m_formatUnits.contains(argType->name()); } - Indentation indentation(INDENT); - ac << INDENT; + Indentor nested; + Indentation indentation(nested); + ac << nested; if (!func->conversionRule(TypeSystem::TargetLangCode, arg->argumentIndex() + 1).isEmpty()) { // Has conversion rule. ac << arg->name() + QLatin1String(CONV_RULE_OUT_VAR_SUFFIX); @@ -993,8 +1004,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, bool invalidateReturn = false; QSet<int> invalidateArgs; - const FunctionModificationList &mods = func->modifications(); - for (const FunctionModification &funcMod : mods) { + for (const FunctionModification &funcMod : functionModifications) { for (const ArgumentModification &argMod : funcMod.argument_mods) { if (argMod.resetAfterUse && !invalidateArgs.contains(argMod.index)) { invalidateArgs.insert(argMod.index); @@ -1007,16 +1017,12 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, } s << Qt::endl; - CodeSnipList snips; - if (func->hasInjectedCode()) { - snips = func->injectedCodeSnips(); - + if (!snips.isEmpty()) { if (injectedCodeUsesPySelf(func)) s << INDENT << "PyObject *pySelf = BindingManager::instance().retrieveWrapper(this);\n"; const AbstractMetaArgument *lastArg = func->arguments().isEmpty() ? nullptr : func->arguments().constLast(); writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode, func, lastArg); - s << Qt::endl; } if (!injectedCodeCallsPythonOverride(func)) { @@ -1102,8 +1108,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, } - const FunctionModificationList &funcMods = func->modifications(); - for (const FunctionModification &funcMod : funcMods) { + for (const FunctionModification &funcMod : functionModifications) { for (const ArgumentModification &argMod : funcMod.argument_mods) { if (argMod.ownerships.contains(TypeSystem::NativeCode) && argMod.index == 0 && argMod.ownerships[TypeSystem::NativeCode] == TypeSystem::CppOwnership) { @@ -1217,8 +1222,9 @@ void CppGenerator::writeEnumConverterFunctions(QTextStream &s, const TypeEntry * } QString code; QTextStream c(&code); - c << INDENT << "*reinterpret_cast<" << cppTypeName << " *>(cppOut) =\n" - << INDENT << " "; + Indentor nested; + c << nested << "*reinterpret_cast<" << cppTypeName << " *>(cppOut) =\n" + << nested << " "; if (enumType->isFlags()) c << cppTypeName << "(QFlag(int(PySide::QFlags::getValue(reinterpret_cast<PySideQFlagsObject *>(pyIn)))))"; else @@ -1231,9 +1237,9 @@ void CppGenerator::writeEnumConverterFunctions(QTextStream &s, const TypeEntry * code.clear(); - c << INDENT << "const int castCppIn = int(*reinterpret_cast<const " + c << nested << "const int castCppIn = int(*reinterpret_cast<const " << cppTypeName << " *>(cppIn));\n"; - c << INDENT; + c << nested; c << "return "; if (enumType->isFlags()) { c << "reinterpret_cast<PyObject *>(PySide::QFlags::newObject(castCppIn, " @@ -1258,8 +1264,8 @@ void CppGenerator::writeEnumConverterFunctions(QTextStream &s, const TypeEntry * code.clear(); cppTypeName = getFullTypeName(flags).trimmed(); - c << INDENT << "*reinterpret_cast<" << cppTypeName << " *>(cppOut) =\n" - << INDENT << " " << cppTypeName + c << nested << "*reinterpret_cast<" << cppTypeName << " *>(cppOut) =\n" + << nested << " " << cppTypeName << "(QFlag(int(Shiboken::Enum::getValue(pyIn))));\n"; QString flagsTypeName = fixedCppTypeName(flags); @@ -1267,9 +1273,9 @@ void CppGenerator::writeEnumConverterFunctions(QTextStream &s, const TypeEntry * writeIsPythonConvertibleToCppFunction(s, typeName, flagsTypeName, pyTypeCheck); code.clear(); - c << INDENT << "Shiboken::AutoDecRef pyLong(PyNumber_Long(pyIn));\n"; - c << INDENT << "*reinterpret_cast<" << cppTypeName << " *>(cppOut) =\n" - << INDENT << " " << cppTypeName + c << nested << "Shiboken::AutoDecRef pyLong(PyNumber_Long(pyIn));\n"; + c << nested << "*reinterpret_cast<" << cppTypeName << " *>(cppOut) =\n" + << nested << " " << cppTypeName << "(QFlag(int(PyLong_AsLong(pyLong.object()))));\n"; // PYSIDE-898: Include an additional condition to detect if the type of the // enum corresponds to the object that is being evaluated. @@ -1316,7 +1322,8 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla QString targetTypeName = metaClass->name() + QLatin1String("_PTR"); QString code; QTextStream c(&code); - c << INDENT << "Shiboken::Conversions::pythonToCppPointer(" << cpythonType << ", pyIn, cppOut);"; + Indentor nested; + c << nested << "Shiboken::Conversions::pythonToCppPointer(" << cpythonType << ", pyIn, cppOut);"; writePythonToCppFunction(s, code, sourceTypeName, targetTypeName); // "Is convertible" function for the Python object to C++ pointer conversion. @@ -1330,30 +1337,30 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla code.clear(); if (usePySideExtensions() && metaClass->isQObject()) { - c << INDENT << "return PySide::getWrapperForQObject(reinterpret_cast<" + c << nested << "return PySide::getWrapperForQObject(reinterpret_cast<" << typeName << " *>(const_cast<void *>(cppIn)), " << cpythonType << ");\n"; } else { - c << INDENT << "auto pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(cppIn));\n"; - c << INDENT << "if (pyOut) {\n"; + c << nested << "auto pyOut = reinterpret_cast<PyObject *>(Shiboken::BindingManager::instance().retrieveWrapper(cppIn));\n"; + c << nested << "if (pyOut) {\n"; { - Indentation indent(INDENT); - c << INDENT << "Py_INCREF(pyOut);\n"; - c << INDENT << "return pyOut;\n"; - } - c << INDENT << "}\n"; - c << INDENT << "bool changedTypeName = false;\n" - << INDENT << "auto tCppIn = reinterpret_cast<const " << typeName << " *>(cppIn);\n" - << INDENT << "const char *typeName = typeid(*tCppIn).name();\n" - << INDENT << "auto sbkType = Shiboken::ObjectType::typeForTypeName(typeName);\n" - << INDENT << "if (sbkType && Shiboken::ObjectType::hasSpecialCastFunction(sbkType)) {\n" - << INDENT << " typeName = typeNameOf(tCppIn);\n" - << INDENT << " changedTypeName = true;\n" - << INDENT << " }\n" - << INDENT << "PyObject *result = Shiboken::Object::newObject(" << cpythonType + Indentation indent(nested); + c << nested << "Py_INCREF(pyOut);\n"; + c << nested << "return pyOut;\n"; + } + c << nested << "}\n"; + c << nested << "bool changedTypeName = false;\n" + << nested << "auto tCppIn = reinterpret_cast<const " << typeName << " *>(cppIn);\n" + << nested << "const char *typeName = typeid(*tCppIn).name();\n" + << nested << "auto sbkType = Shiboken::ObjectType::typeForTypeName(typeName);\n" + << nested << "if (sbkType && Shiboken::ObjectType::hasSpecialCastFunction(sbkType)) {\n" + << nested << " typeName = typeNameOf(tCppIn);\n" + << nested << " changedTypeName = true;\n" + << nested << "}\n" + << nested << "PyObject *result = Shiboken::Object::newObject(" << cpythonType << ", const_cast<void *>(cppIn), false, /* exactType */ changedTypeName, typeName);\n" - << INDENT << "if (changedTypeName)\n" - << INDENT << " delete [] typeName;\n" - << INDENT << "return result;"; + << nested << "if (changedTypeName)\n" + << nested << " delete [] typeName;\n" + << nested << "return result;"; } std::swap(targetTypeName, sourceTypeName); writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName); @@ -1383,7 +1390,7 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla computedWrapperName = classContext.smartPointerWrapperName(); } - c << INDENT << "return Shiboken::Object::newObject(" << cpythonType + c << nested << "return Shiboken::Object::newObject(" << cpythonType << ", new ::" << computedWrapperName << "(*reinterpret_cast<const " << typeName << " *>(cppIn)), true, true);"; writeCppToPythonFunction(s, code, sourceTypeName, targetTypeName); @@ -1406,7 +1413,7 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla else wrappedCPtrExpression = cpythonWrapperCPtr(classContext.preciseType(), pyInVariable); - c << INDENT << "*reinterpret_cast<" << typeName << " *>(cppOut) = *" + c << nested << "*reinterpret_cast<" << typeName << " *>(cppOut) = *" << wrappedCPtrExpression << ';'; writePythonToCppFunction(s, code, sourceTypeName, targetTypeName); @@ -1475,7 +1482,7 @@ void CppGenerator::writeConverterFunctions(QTextStream &s, const AbstractMetaCla || sourceType->typeEntry()->isEnum() || sourceType->typeEntry()->isFlags()) { QTextStream pc(&toCppPreConv); - pc << INDENT << getFullTypeNameWithoutModifiers(sourceType) << " cppIn"; + pc << nested << getFullTypeNameWithoutModifiers(sourceType) << " cppIn"; writeMinimalConstructorExpression(pc, sourceType); pc << ";\n"; writeToCppConversion(pc, sourceType, nullptr, QLatin1String("pyIn"), QLatin1String("cppIn")); @@ -1703,10 +1710,10 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over } if (usesNamedArguments && !rfunc->isCallOperator()) - s << INDENT << "int numNamedArgs = (kwds ? PyDict_Size(kwds) : 0);\n"; + s << INDENT << "const Py_ssize_t numNamedArgs = (kwds ? PyDict_Size(kwds) : 0);\n"; if (initPythonArguments) { - s << INDENT << "int numArgs = "; + s << INDENT << "const Py_ssize_t numArgs = "; if (minArgs == 0 && maxArgs == 1 && !rfunc->isConstructor() && !pythonFunctionWrapperUsesListOfArguments(overloadData)) s << "(" << PYTHON_ARG << " == 0 ? 0 : 1);\n"; else @@ -2859,8 +2866,9 @@ void CppGenerator::writeCppToPythonFunction(QTextStream &s, const QString &code, static void replaceCppToPythonVariables(QString &code, const QString &typeName) { - code.prepend(QLatin1String("auto &cppInRef = *reinterpret_cast<") - + typeName + QLatin1String(" *>(const_cast<void *>(cppIn));\n")); + const QString line = QLatin1String("auto &cppInRef = *reinterpret_cast<") + + typeName + QLatin1String(" *>(const_cast<void *>(cppIn));"); + CodeSnipAbstract::prependCode(&code, line); code.replace(QLatin1String("%INTYPE"), typeName); code.replace(QLatin1String("%OUTTYPE"), QLatin1String("PyObject *")); code.replace(QLatin1String("%in"), QLatin1String("cppInRef")); @@ -2947,12 +2955,13 @@ void CppGenerator::writePythonToCppConversionFunctions(QTextStream &s, // Python to C++ conversion function. QString code; QTextStream c(&code); + Indentor nested; if (conversion.isEmpty()) conversion = QLatin1Char('*') + cpythonWrapperCPtr(sourceType->typeEntry(), QLatin1String("pyIn")); if (!preConversion.isEmpty()) - c << INDENT << preConversion << Qt::endl; + c << nested << preConversion << Qt::endl; const QString fullTypeName = getFullTypeName(targetType->typeEntry()); - c << INDENT << "*reinterpret_cast<" << fullTypeName << " *>(cppOut) = " + c << nested << "*reinterpret_cast<" << fullTypeName << " *>(cppOut) = " << fullTypeName << '(' << conversion << ");"; QString sourceTypeName = fixedCppTypeName(sourceType); QString targetTypeName = fixedCppTypeName(targetType); @@ -3034,11 +3043,10 @@ void CppGenerator::writePythonToCppConversionFunctions(QTextStream &s, const Abs } // Python to C++ conversion function. QString cppTypeName = getFullTypeNameWithoutModifiers(containerType); - QString code; - QTextStream c(&code); - c << INDENT << "auto &cppOutRef = *reinterpret_cast<" - << cppTypeName << " *>(cppOut);\n"; - code.append(toCppConversions.constFirst()->conversion()); + QString code = toCppConversions.constFirst()->conversion(); + const QString line = QLatin1String("auto &cppOutRef = *reinterpret_cast<") + + cppTypeName + QLatin1String(" *>(cppOut);"); + CodeSnipAbstract::prependCode(&code, line); for (int i = 0; i < containerType->instantiations().count(); ++i) { const AbstractMetaType *type = containerType->instantiations().at(i); QString typeName = getFullTypeName(type); @@ -3232,7 +3240,6 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f } writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode, func, lastArg); - s << Qt::endl; } writeConversionRule(s, func, TypeSystem::NativeCode); @@ -3523,10 +3530,8 @@ void CppGenerator::writeMethodCall(QTextStream &s, const AbstractMetaFunction *f } } - if (func->hasInjectedCode() && !func->isConstructor()) { - s << Qt::endl; + if (func->hasInjectedCode() && !func->isConstructor()) writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode, func, lastArg); - } bool hasReturnPolicy = false; @@ -4983,8 +4988,13 @@ void CppGenerator::writeSignatureStrings(QTextStream &s, s << "// Multiple signatures have their index \"n:\" in front.\n"; s << "static const char *" << arrayName << "_SignatureStrings[] = {\n"; QString line; - while (signatureStream.readLineInto(&line)) - s << INDENT << "R\"CPP(" << line << ")CPP\",\n"; + while (signatureStream.readLineInto(&line)) { + // must anything be escaped? + if (line.contains(QLatin1Char('"')) || line.contains(QLatin1Char('\\'))) + s << INDENT << "R\"CPP(" << line << ")CPP\",\n"; + else + s << INDENT << '"' << line << "\",\n"; + } s << INDENT << NULL_PTR << "}; // Sentinel\n\n"; } @@ -5637,6 +5647,7 @@ bool CppGenerator::finishGeneration() if (usePySideExtensions()) { s << includeQDebug; s << "#include <pyside.h>\n"; + s << "#include <pysideqenum.h>\n"; s << "#include <qapp_macro.h>\n"; } @@ -5680,10 +5691,8 @@ bool CppGenerator::finishGeneration() const CodeSnipList snips = moduleEntry->codeSnips(); // module inject-code native/beginning - if (!snips.isEmpty()) { + if (!snips.isEmpty()) writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode); - s << Qt::endl; - } // cleanup staticMetaObject attribute if (usePySideExtensions()) { @@ -5814,10 +5823,8 @@ bool CppGenerator::finishGeneration() ErrorCode errorCode(QLatin1String("SBK_MODULE_INIT_ERROR")); // module inject-code target/beginning - if (!snips.isEmpty()) { + if (!snips.isEmpty()) writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionBeginning, TypeSystem::TargetLangCode); - s << Qt::endl; - } for (const QString &requiredModule : requiredModules) { s << INDENT << "{\n"; @@ -5919,16 +5926,12 @@ bool CppGenerator::finishGeneration() s << INDENT << "}\n"; // module inject-code target/end - if (!snips.isEmpty()) { + if (!snips.isEmpty()) writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::TargetLangCode); - s << Qt::endl; - } // module inject-code native/end - if (!snips.isEmpty()) { + if (!snips.isEmpty()) writeCodeSnips(s, snips, TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode); - s << Qt::endl; - } if (usePySideExtensions()) { for (AbstractMetaEnum *metaEnum : qAsConst(globalEnums)) |