diff options
Diffstat (limited to 'sources/shiboken2/generator/shiboken2/cppgenerator.cpp')
-rw-r--r-- | sources/shiboken2/generator/shiboken2/cppgenerator.cpp | 130 |
1 files changed, 82 insertions, 48 deletions
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index 30430c01f..ff44db955 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -1831,6 +1831,11 @@ void CppGenerator::writeMethodWrapperPreamble(QTextStream &s, OverloadData &over usesNamedArguments = rfunc->isCallOperator() || overloadData.hasArgumentWithDefaultValue(); } + s << INDENT << "PyObject *errInfo{};\n"; + s << INDENT << "SBK_UNUSED(errInfo)\n"; + s << INDENT << "static const char *fullName = \"" + << fullPythonFunctionName(rfunc, true) << "\";\n"; + s << INDENT << "SBK_UNUSED(fullName)\n"; if (maxArgs > 0) { s << INDENT << "int overloadId = -1;\n"; s << INDENT << "PythonToCppFunc " << PYTHON_TO_CPP_VAR; @@ -1866,28 +1871,8 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun s << "static int\n"; s << cpythonFunctionName(rfunc) << "(PyObject *self, PyObject *args, PyObject *kwds)\n{\n"; - QSet<QString> argNamesSet; - if (usePySideExtensions() && metaClass->isQObject()) { - // Write argNames variable with all known argument names. - const OverloadData::MetaFunctionList &overloads = overloadData.overloads(); - for (const AbstractMetaFunction *func : overloads) { - const AbstractMetaArgumentList &arguments = func->arguments(); - for (const AbstractMetaArgument *arg : arguments) { - if (arg->defaultValueExpression().isEmpty() || func->argumentRemoved(arg->argumentIndex() + 1)) - continue; - argNamesSet << arg->name(); - } - } - QStringList argNamesList = argNamesSet.values(); - std::sort(argNamesList.begin(), argNamesList.end()); - if (argNamesList.isEmpty()) { - s << INDENT << "const char **argNames{};\n"; - } else { - s << INDENT << "const char *argNames[] = {\"" - << argNamesList.join(QLatin1String("\", \"")) << "\"};\n"; - } + if (usePySideExtensions() && metaClass->isQObject()) s << INDENT << "const QMetaObject *metaObject;\n"; - } s << INDENT << "SbkObject *sbkSelf = reinterpret_cast<SbkObject *>(self);\n"; @@ -1927,6 +1912,8 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun { Indentation indent(INDENT); s << INDENT << "delete cptr;\n"; + if (overloadData.maxArgs() > 0) + s << INDENT << "Py_XDECREF(errInfo);\n"; s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl; } s << INDENT << "}\n"; @@ -1947,19 +1934,24 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun s << INDENT << "if (Shiboken::BindingManager::instance().hasWrapper(cptr)) {\n"; { Indentation indent(INDENT); - s << INDENT << "Shiboken::BindingManager::instance().releaseWrapper(Shiboken::BindingManager::instance().retrieveWrapper(cptr));\n"; + s << INDENT << "Shiboken::BindingManager::instance().releaseWrapper(" + "Shiboken::BindingManager::instance().retrieveWrapper(cptr));\n"; } s << INDENT << "}\n"; s << INDENT << "Shiboken::BindingManager::instance().registerWrapper(sbkSelf, cptr);\n"; // Create metaObject and register signal/slot + bool errHandlerNeeded = overloadData.maxArgs() > 0; if (metaClass->isQObject() && usePySideExtensions()) { + errHandlerNeeded = true; s << Qt::endl << INDENT << "// QObject setup\n"; s << INDENT << "PySide::Signal::updateSourceObject(self);\n"; s << INDENT << "metaObject = cptr->metaObject(); // <- init python qt properties\n"; - s << INDENT << "if (kwds && !PySide::fillQtProperties(self, metaObject, kwds, argNames, " - << argNamesSet.count() << "))\n" << indent(INDENT) - << INDENT << returnStatement(m_currentErrorCode) << '\n' << outdent(INDENT); + s << INDENT << "if (errInfo && PyDict_Check(errInfo)) {\n" << indent(INDENT) + << INDENT << "if (!PySide::fillQtProperties(self, metaObject, errInfo))\n" << indent(INDENT) + << INDENT << "goto " << cpythonFunctionName(rfunc) << "_TypeError;\n" << outdent(INDENT) + << INDENT << "Py_DECREF(errInfo);\n" << outdent(INDENT) + << INDENT << "};\n"; } // Constructor code injections, position=end @@ -1997,7 +1989,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun s << Qt::endl; s << Qt::endl << INDENT << "return 1;\n"; - if (overloadData.maxArgs() > 0) + if (errHandlerNeeded) writeErrorSection(s, overloadData); s<< "}\n\n"; } @@ -2149,8 +2141,11 @@ void CppGenerator::writeArgumentsInitializer(QTextStream &s, OverloadData &overl s << INDENT << "if (numArgs > " << maxArgs << ") {\n"; { Indentation indent(INDENT); - s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): too many arguments\");\n"; - s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl; + s << INDENT << "static PyObject *const too_many = " + "Shiboken::String::createStaticString(\">\");\n"; + s << INDENT << "errInfo = too_many;\n"; + s << INDENT << "Py_INCREF(errInfo);\n"; + s << INDENT << "goto " << cpythonFunctionName(rfunc) << "_TypeError;\n"; } s << INDENT << '}'; } @@ -2162,8 +2157,11 @@ void CppGenerator::writeArgumentsInitializer(QTextStream &s, OverloadData &overl s << "if (numArgs < " << minArgs << ") {\n"; { Indentation indent(INDENT); - s << INDENT << "PyErr_SetString(PyExc_TypeError, \"" << fullPythonFunctionName(rfunc) << "(): not enough arguments\");\n"; - s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl; + s << INDENT << "static PyObject *const too_few = " + "Shiboken::String::createStaticString(\"<\");\n"; + s << INDENT << "errInfo = too_few;\n"; + s << INDENT << "Py_INCREF(errInfo);\n"; + s << INDENT << "goto " << cpythonFunctionName(rfunc) << "_TypeError;\n"; } s << INDENT << '}'; } @@ -2297,11 +2295,13 @@ void CppGenerator::writeErrorSection(QTextStream &s, OverloadData &overloadData) const AbstractMetaFunction *rfunc = overloadData.referenceFunction(); s << Qt::endl << INDENT << cpythonFunctionName(rfunc) << "_TypeError:\n"; Indentation indentation(INDENT); - QString funcName = fullPythonFunctionName(rfunc); + QString funcName = fullPythonFunctionName(rfunc, true); QString argsVar = pythonFunctionWrapperUsesListOfArguments(overloadData) ? QLatin1String("args") : QLatin1String(PYTHON_ARG); - s << INDENT << "Shiboken::setErrorAboutWrongArguments(" << argsVar << ", \"" << funcName << "\");\n"; + s << INDENT << "Shiboken::setErrorAboutWrongArguments(" << argsVar + << ", fullName, errInfo);\n"; + s << INDENT << "Py_XDECREF(errInfo);\n"; s << INDENT << "return " << m_currentErrorCode << ";\n"; } @@ -2905,7 +2905,7 @@ void CppGenerator::writeSingleFunctionCall(QTextStream &s, bool usePyArgs = pythonFunctionWrapperUsesListOfArguments(overloadData); // Handle named arguments. - writeNamedArgumentResolution(s, func, usePyArgs); + writeNamedArgumentResolution(s, func, usePyArgs, overloadData); bool injectCodeCallsFunc = injectedCodeCallsCppFunction(context, func); bool mayHaveUnunsedArguments = !func->isUserAdded() && func->hasInjectedCode() && injectCodeCallsFunc; @@ -3228,33 +3228,46 @@ void CppGenerator::writeAddPythonToCppConversion(QTextStream &s, const QString & s << ");\n"; } -void CppGenerator::writeNamedArgumentResolution(QTextStream &s, const AbstractMetaFunction *func, bool usePyArgs) +void CppGenerator::writeNamedArgumentResolution(QTextStream &s, const AbstractMetaFunction *func, + bool usePyArgs, const OverloadData &overloadData) { const AbstractMetaArgumentList &args = OverloadData::getArgumentsWithDefaultValues(func); - if (args.isEmpty()) + if (args.isEmpty()) { + if (overloadData.hasArgumentWithDefaultValue()) { + s << INDENT << "if (kwds) {\n"; + { + Indentation indent(INDENT); + s << INDENT << "errInfo = kwds;\n"; + s << INDENT << "Py_INCREF(errInfo);\n"; + s << INDENT << "goto " << cpythonFunctionName(func) << "_TypeError;\n"; + } + s << INDENT << "}\n"; + } return; - - QString pyErrString(QLatin1String("PyErr_SetString(PyExc_TypeError, \"") + fullPythonFunctionName(func) - + QLatin1String("(): got multiple values for keyword argument '%1'.\");")); + } s << INDENT << "if (kwds) {\n"; { Indentation indent(INDENT); - s << INDENT << "PyObject *keyName = nullptr;\n"; - s << INDENT << "PyObject *value = nullptr;\n"; + s << INDENT << "PyObject *value{};\n"; + s << INDENT << "PyObject *kwds_dup = PyDict_Copy(kwds);\n"; for (const AbstractMetaArgument *arg : args) { - int pyArgIndex = arg->argumentIndex() - OverloadData::numberOfRemovedArguments(func, arg->argumentIndex()); + const int pyArgIndex = arg->argumentIndex() + - OverloadData::numberOfRemovedArguments(func, arg->argumentIndex()); QString pyArgName = usePyArgs ? pythonArgsAt(pyArgIndex) : QLatin1String(PYTHON_ARG); - s << INDENT << "keyName = Py_BuildValue(\"s\",\"" << arg->name() << "\");\n"; - s << INDENT << "if (PyDict_Contains(kwds, keyName)) {\n"; + QString pyKeyName = QLatin1String("key_") + arg->name(); + s << INDENT << "static PyObject *const " << pyKeyName + << " = Shiboken::String::createStaticString(\"" << arg->name() << "\");\n"; + s << INDENT << "if (PyDict_Contains(kwds, " << pyKeyName << ")) {\n"; { Indentation indent(INDENT); - s << INDENT << "value = PyDict_GetItem(kwds, keyName);\n"; + s << INDENT << "value = PyDict_GetItem(kwds, " << pyKeyName << ");\n"; s << INDENT << "if (value && " << pyArgName << ") {\n"; { Indentation indent(INDENT); - s << INDENT << pyErrString.arg(arg->name()) << Qt::endl; - s << INDENT << returnStatement(m_currentErrorCode) << Qt::endl; + s << INDENT << "errInfo = " << pyKeyName << ";\n"; + s << INDENT << "Py_INCREF(errInfo);\n"; + s << INDENT << "goto " << cpythonFunctionName(func) << "_TypeError;\n"; } s << INDENT << "}\n"; s << INDENT << "if (value) {\n"; @@ -3262,7 +3275,8 @@ void CppGenerator::writeNamedArgumentResolution(QTextStream &s, const AbstractMe Indentation indent(INDENT); s << INDENT << pyArgName << " = value;\n"; s << INDENT << "if (!"; - writeTypeCheck(s, arg->type(), pyArgName, isNumber(arg->type()->typeEntry()), func->typeReplaced(arg->argumentIndex() + 1)); + writeTypeCheck(s, arg->type(), pyArgName, isNumber(arg->type()->typeEntry()), + func->typeReplaced(arg->argumentIndex() + 1)); s << ")\n"; { Indentation indent(INDENT); @@ -3270,9 +3284,29 @@ void CppGenerator::writeNamedArgumentResolution(QTextStream &s, const AbstractMe } } s << INDENT << "}\n"; + s << INDENT << "PyDict_DelItem(kwds_dup, " << pyKeyName << ");\n"; } s << INDENT << "}\n"; } + // PYSIDE-1305: Handle keyword args correctly. + // Normal functions handle their parameters immediately. + // For constructors that are QObject, we need to delay that + // until extra keyword signals and properties are handled. + s << INDENT << "if (PyDict_Size(kwds_dup) > 0) {\n"; + { + Indentation indent(INDENT); + s << INDENT << "errInfo = kwds_dup;\n"; + if (!(func->isConstructor() && func->ownerClass()->isQObject())) + s << INDENT << "goto " << cpythonFunctionName(func) << "_TypeError;\n"; + else + s << INDENT << "// fall through to handle extra keyword signals and properties\n"; + } + s << INDENT << "} else {\n"; + { + Indentation indent(INDENT); + s << INDENT << "Py_DECREF(kwds_dup);\n"; + } + s << INDENT << "}\n"; } s << INDENT << "}\n"; } @@ -4892,7 +4926,7 @@ void CppGenerator::writeSignatureInfo(QTextStream &s, const AbstractMetaFunction { OverloadData overloadData(overloads, this); const AbstractMetaFunction *rfunc = overloadData.referenceFunction(); - QString funcName = fullPythonFunctionName(rfunc); + QString funcName = fullPythonFunctionName(rfunc, false); int idx = overloads.length() - 1; bool multiple = idx > 0; |