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.cpp71
1 files changed, 58 insertions, 13 deletions
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index 5697a24e0..9e7b96c7f 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -414,18 +414,17 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
}
const AbstractMetaFunctionList &funcs = filterFunctions(metaClass);
+ int maxOverrides = 0;
+ writeCacheResetNative(s, metaClass);
for (const AbstractMetaFunction *func : funcs) {
const bool notAbstract = !func->isAbstract();
if ((func->isPrivate() && notAbstract && !visibilityModifiedToPrivate(func))
|| (func->isModifiedRemoved() && notAbstract))
continue;
- if (func->functionType() == AbstractMetaFunction::ConstructorFunction && !func->isUserAdded()) {
+ if (func->functionType() == AbstractMetaFunction::ConstructorFunction && !func->isUserAdded())
writeConstructorNative(s, func);
- } else if ((!avoidProtectedHack() || !metaClass->hasPrivateDestructor())
- && ((func->isVirtual() || func->isAbstract())
- && (func->attributes() & AbstractMetaAttributes::FinalCppMethod) == 0)) {
- writeVirtualMethodNative(s, func);
- }
+ else if (shouldWriteVirtualMethodNative(func))
+ writeVirtualMethodNative(s, func, maxOverrides++);
}
if (!avoidProtectedHack() || !metaClass->hasPrivateDestructor()) {
@@ -695,6 +694,14 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext)
}
}
+void CppGenerator::writeCacheResetNative(QTextStream &s, const AbstractMetaClass *metaClass)
+{
+ Indentation indentation(INDENT);
+ s << "void " << wrapperName(metaClass) << "::resetPyMethodCache()\n{\n";
+ s << INDENT << "std::fill_n(m_PyMethodCache, sizeof(m_PyMethodCache) / sizeof(m_PyMethodCache[0]), false);\n";
+ s << "}\n\n";
+}
+
void CppGenerator::writeConstructorNative(QTextStream &s, const AbstractMetaFunction *func)
{
Indentation indentation(INDENT);
@@ -704,6 +711,7 @@ void CppGenerator::writeConstructorNative(QTextStream &s, const AbstractMetaFunc
writeFunctionCall(s, func);
s << "\n{\n";
const AbstractMetaArgument *lastArg = func->arguments().isEmpty() ? nullptr : func->arguments().constLast();
+ s << INDENT << "resetPyMethodCache();\n";
writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionBeginning, TypeSystem::NativeCode, func, lastArg);
s << INDENT << "// ... middle\n";
writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionEnd, TypeSystem::NativeCode, func, lastArg);
@@ -763,7 +771,9 @@ QString CppGenerator::getVirtualFunctionReturnTypeName(const AbstractMetaFunctio
+ typeEntry->qualifiedCppName() + QLatin1String(" >())->tp_name");
}
-void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFunction *func)
+void CppGenerator::writeVirtualMethodNative(QTextStream &s,
+ const AbstractMetaFunction *func,
+ int cacheIndex)
{
//skip metaObject function, this will be written manually ahead
if (usePySideExtensions() && func->ownerClass() && func->ownerClass()->isQObject() &&
@@ -838,6 +848,28 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFu
s << Qt::endl;
}
+ // PYSIDE-803: Build a boolean cache for unused overrides.
+ bool multi_line = retType == nullptr; // set to true when using instrumentation
+ 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";
+ }
+ if (multi_line)
+ s << INDENT << "}\n";
+
s << INDENT << "Shiboken::GilState gil;\n";
// Get out of virtual method call if someone already threw an error.
@@ -870,7 +902,10 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFu
s << ' ' << defaultReturnExpr.returnValue();
} else {
s << INDENT << "gil.release();\n";
- s << INDENT;
+ if (useOverrideCaching(func->ownerClass())) {
+ s << INDENT << "m_PyMethodCache[" << cacheIndex << "] = true;\n";
+ s << INDENT;
+ }
if (retType)
s << "return ";
s << "this->::" << func->implementingClass()->qualifiedCppName() << "::";
@@ -880,7 +915,7 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFu
}
}
s << ";\n";
- s << INDENT<< "}\n\n";
+ s << INDENT << "}\n\n"; //WS
writeConversionRule(s, func, TypeSystem::TargetLangCode);
@@ -1477,10 +1512,10 @@ void CppGenerator::writeConverterRegister(QTextStream &s, const AbstractMetaClas
QStringList cppSignature;
if (!classContext.forSmartPointer()) {
cppSignature = metaClass->qualifiedCppName().split(QLatin1String("::"),
- QString::SkipEmptyParts);
+ Qt::SkipEmptyParts);
} else {
cppSignature = classContext.preciseType()->cppSignature().split(QLatin1String("::"),
- QString::SkipEmptyParts);
+ Qt::SkipEmptyParts);
}
while (!cppSignature.isEmpty()) {
QString signature = cppSignature.join(QLatin1String("::"));
@@ -1928,7 +1963,7 @@ void CppGenerator::writeArgumentsInitializer(QTextStream &s, OverloadData &overl
s << INDENT << "PyObject *";
s << PYTHON_ARGS << "[] = {"
- << QString(maxArgs, QLatin1Char('0')).split(QLatin1String(""), QString::SkipEmptyParts).join(QLatin1String(", "))
+ << QString(maxArgs, QLatin1Char('0')).split(QLatin1String(""), Qt::SkipEmptyParts).join(QLatin1String(", "))
<< "};\n";
s << Qt::endl;
@@ -5238,6 +5273,16 @@ void CppGenerator::writeSetattroFunction(QTextStream &s, AttroCheck attroCheck,
Q_ASSERT(!context.forSmartPointer());
const AbstractMetaClass *metaClass = context.metaClass();
writeSetattroDefinition(s, metaClass);
+ // PYSIDE-803: Detect duck-punching; clear cache if a method is set.
+ if (attroCheck.testFlag(AttroCheckFlag::SetattroMethodOverride)
+ && ShibokenGenerator::shouldGenerateCppWrapper(metaClass)) {
+ s << INDENT << "if (value && PyCallable_Check(value)) {\n";
+ s << INDENT << " auto plain_inst = " << cpythonWrapperCPtr(metaClass, QLatin1String("self")) << ";\n";
+ s << INDENT << " auto inst = dynamic_cast<" << wrapperName(metaClass) << " *>(plain_inst);\n";
+ s << INDENT << " if (inst)\n";
+ s << INDENT << " inst->resetPyMethodCache();\n";
+ s << INDENT << "}\n";
+ }
if (attroCheck.testFlag(AttroCheckFlag::SetattroQObject)) {
s << INDENT << "Shiboken::AutoDecRef pp(reinterpret_cast<PyObject *>(PySide::Property::getObject(self, name)));\n";
s << INDENT << "if (!pp.isNull())\n";
@@ -5771,7 +5816,7 @@ bool CppGenerator::finishGeneration()
if (!referencedType)
continue;
QString converter = converterObject(referencedType);
- QStringList cppSignature = pte->qualifiedCppName().split(QLatin1String("::"), QString::SkipEmptyParts);
+ QStringList cppSignature = pte->qualifiedCppName().split(QLatin1String("::"), Qt::SkipEmptyParts);
while (!cppSignature.isEmpty()) {
QString signature = cppSignature.join(QLatin1String("::"));
s << INDENT << "Shiboken::Conversions::registerConverterName(" << converter << ", \"" << signature << "\");\n";