aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2/generator/shiboken2/cppgenerator.cpp')
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp130
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;