aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cppgenerator.cpp29
-rw-r--r--doc/codeinjectionsemantics.rst13
-rw-r--r--doc/typesystemvariables.rst9
-rw-r--r--shibokengenerator.cpp24
-rw-r--r--shibokengenerator.h9
5 files changed, 62 insertions, 22 deletions
diff --git a/cppgenerator.cpp b/cppgenerator.cpp
index a3954f6dc..395fe1470 100644
--- a/cppgenerator.cpp
+++ b/cppgenerator.cpp
@@ -304,10 +304,10 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFu
if (func->allowThread())
s << INDENT << "// how to say to Python to allow threads?" << endl;
- s << INDENT << "PyObject* method = BindingManager::instance().getOverride(this, \"";
+ s << INDENT << "PyObject* py_override = BindingManager::instance().getOverride(this, \"";
s << func->name() << "\");" << endl;
- s << INDENT << "if (!method) {" << endl;
+ s << INDENT << "if (!py_override) {" << endl;
{
Indentation indentation(INDENT);
s << INDENT;
@@ -376,13 +376,14 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFu
s << endl;
}
- s << INDENT << "PyGILState_STATE gil_state = PyGILState_Ensure();" << endl;
-
- s << INDENT;
- if (!returnKeyword.isEmpty())
- s << "PyObject* " << retvalVariableName() << " = ";
- s << "PyObject_Call(method, pyargs, NULL);" << endl;
- s << INDENT << "PyGILState_Release(gil_state);" << endl << endl;
+ if (!injectedCodeCallsPythonOverride(func)) {
+ s << INDENT << "PyGILState_STATE gil_state = PyGILState_Ensure();" << endl;
+ s << INDENT;
+ if (!returnKeyword.isEmpty())
+ s << "PyObject* " << retvalVariableName() << " = ";
+ s << "PyObject_Call(py_override, pyargs, NULL);" << endl;
+ s << INDENT << "PyGILState_Release(gil_state);" << endl << endl;
+ }
foreach (FunctionModification func_mod, functionModifications(func)) {
foreach (ArgumentModification arg_mod, func_mod.argument_mods) {
@@ -393,16 +394,16 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFu
}
}
- s << INDENT << "Py_XDECREF(pyargs);" << endl;
- s << INDENT << "Py_XDECREF(method);" << endl;
-
- s << endl << INDENT << "// check and set Python error here..." << endl;
-
if (func->hasInjectedCode()) {
s << endl;
writeCodeSnips(s, snips, CodeSnip::End, TypeSystem::NativeCode, func);
}
+ s << INDENT << "Py_XDECREF(pyargs);" << endl;
+ s << INDENT << "Py_XDECREF(py_override);" << endl;
+
+ s << endl << INDENT << "// check and set Python error here..." << endl;
+
if (!returnKeyword.isEmpty()) {
s << INDENT << returnKeyword;
writeToCppConversion(s, func->type(), func->implementingClass(), retvalVariableName());
diff --git a/doc/codeinjectionsemantics.rst b/doc/codeinjectionsemantics.rst
index c0d6fa2d7..aaa965fea 100644
--- a/doc/codeinjectionsemantics.rst
+++ b/doc/codeinjectionsemantics.rst
@@ -71,9 +71,9 @@ The following table describes the semantics of ``inject-code`` tag as used on
| | | |Python override, if there is any), right after the C++ |
| | | |arguments have been converted but before the Python call. |
| | +---------+--------------------------------------------------------------+
- | | |end |This code injection goes to the end of a virtual method |
- | | | |override on the C++ wrapper class, right before the return |
- | | | |statement (if any). |
+ | | |end |This code injection is put in a virtual method override on the|
+ | | | |C++ wrapper class, after the call to Python and before |
+ | | | |dereferencing the Python method and tuple of arguments. |
| +------+---------+--------------------------------------------------------------+
| |target|beginning|This code is injected on the Python method wrapper |
| | | |(``PyCLASS_METHOD(...)``), right after the decisor have found |
@@ -186,6 +186,9 @@ instead of
Code Injection for Functions/Methods
====================================
+
+.. _codeinjecting_method_native:
+
On The Native Side
------------------
@@ -197,7 +200,7 @@ class is polymorphic.
int InjectCodeWrapper::virtualMethod(int arg)
{
PyObject* method = BindingManager::instance().getOverride(this, "virtualMethod");
- if (!method)
+ if (!py_override)
return this->InjectCode::virtualMethod(arg);
(... here C++ arguments are converted to Python ...)
@@ -212,6 +215,8 @@ class is polymorphic.
// Uses: post method call custom code, modify the result before delivering
// it to C++ caller.
+ (... Python method and argument tuple are dereferenced here ...)
+
return Shiboken::Converter<int>::toCpp(method_result);
}
diff --git a/doc/typesystemvariables.rst b/doc/typesystemvariables.rst
index dbfc29350..9966cfc55 100644
--- a/doc/typesystemvariables.rst
+++ b/doc/typesystemvariables.rst
@@ -206,6 +206,15 @@ Variables
C++ parent's one.
+.. _python_method_override:
+
+**%PYTHON_METHOD_OVERRIDE**
+
+ This variable is used only on :ref:`native method code injections
+ <codeinjecting_method_native>`, i.e. on the binding overrides for C++ virtual
+ methods. It is replaced by a pointer to the Python method override.
+
+
.. _pythontypeobject:
**%PYTHONTYPEOBJECT**
diff --git a/shibokengenerator.cpp b/shibokengenerator.cpp
index 624c0c2eb..b30a85aca 100644
--- a/shibokengenerator.cpp
+++ b/shibokengenerator.cpp
@@ -978,12 +978,17 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s,
}
code.replace("%ARGUMENT_NAMES", argumentNames.join(", "));
- // replace template %PYTHON_ARGUMENTS variable for a pointer to the Python tuple
- // containing the converted virtual method arguments received from C++ to be passed
- // to the Python override
- if (snip.language == TypeSystem::NativeCode)
+ if (snip.language == TypeSystem::NativeCode) {
+ // replace template %PYTHON_ARGUMENTS variable for a pointer to the Python tuple
+ // containing the converted virtual method arguments received from C++ to be passed
+ // to the Python override
code.replace("%PYTHON_ARGUMENTS", "pyargs");
+ // replace variable %PYTHON_METHOD_OVERRIDE for a pointer to the Python method
+ // override for the C++ virtual method in which this piece of code was inserted
+ code.replace("%PYTHON_METHOD_OVERRIDE", "py_override");
+ }
+
replaceTemplateVariables(code, func);
}
@@ -1029,6 +1034,17 @@ bool ShibokenGenerator::injectedCodeCallsCppFunction(const AbstractMetaFunction*
return false;
}
+bool ShibokenGenerator::injectedCodeCallsPythonOverride(const AbstractMetaFunction* func)
+{
+ static QRegExp overrideCallRegexCheck("PyObject_Call\\s*\\(\\s*%PYTHON_METHOD_OVERRIDE\\s*,");
+ CodeSnipList snips = func->injectedCodeSnips(CodeSnip::Any, TypeSystem::NativeCode);
+ foreach (CodeSnip snip, snips) {
+ if (overrideCallRegexCheck.indexIn(snip.code()) != -1)
+ return true;
+ }
+ return false;
+}
+
bool ShibokenGenerator::injectedCodeHasReturnValueAttribution(const AbstractMetaFunction* func)
{
static QRegExp retValAttributionRegexCheck("%0\\s*=[^=]\\s*.+");
diff --git a/shibokengenerator.h b/shibokengenerator.h
index 6c6f372fe..2b53f7298 100644
--- a/shibokengenerator.h
+++ b/shibokengenerator.h
@@ -146,6 +146,15 @@ public:
bool injectedCodeCallsCppFunction(const AbstractMetaFunction* func);
/**
+ * Verifies if any of the function's code injections of the "native" class makes a
+ * call to the C++ method. This is used by the generator to avoid writing calls to
+ * Python overrides of C++ virtual methods when the user custom code already does this.
+ * \param func the function to check
+ * \return true if the function's code snippets call the Python override for a C++ virtual method
+ */
+ bool injectedCodeCallsPythonOverride(const AbstractMetaFunction* func);
+
+ /**
* Verifies if any of the function's code injections attributes values to
* the return variable (%0).
* \param func the function to check