aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/generator
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2020-03-04 08:27:14 +0100
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2020-03-04 08:27:14 +0100
commit98d9a82d4a94b91012c9e9cbc7f7c57ddacceac9 (patch)
tree10920682a82713a4579a94e51f54755707af805a /sources/shiboken2/generator
parent7ef372b13fb6393b76029b9b62ebcb4166fa5f70 (diff)
parentcc19c439a64ddc42bc333ee5df7b651a789d6da5 (diff)
Merge remote-tracking branch 'origin/5.14' into 5.15
Diffstat (limited to 'sources/shiboken2/generator')
-rw-r--r--sources/shiboken2/generator/main.cpp2
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp71
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.h3
-rw-r--r--sources/shiboken2/generator/shiboken2/headergenerator.cpp13
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.cpp29
-rw-r--r--sources/shiboken2/generator/shiboken2/shibokengenerator.h6
6 files changed, 107 insertions, 17 deletions
diff --git a/sources/shiboken2/generator/main.cpp b/sources/shiboken2/generator/main.cpp
index 089ecb48f..e4d86f489 100644
--- a/sources/shiboken2/generator/main.cpp
+++ b/sources/shiboken2/generator/main.cpp
@@ -370,7 +370,7 @@ static void parseIncludePathOption(const QString &option, HeaderType headerType,
const CommandArgumentMap::iterator it = args.find(option);
if (it != args.end()) {
const QStringList includePathListList =
- it.value().split(pathSplitter, QString::SkipEmptyParts);
+ it.value().split(pathSplitter, Qt::SkipEmptyParts);
args.erase(it);
for (const QString &s : includePathListList) {
auto path = QFile::encodeName(QDir::cleanPath(s));
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";
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.h b/sources/shiboken2/generator/shiboken2/cppgenerator.h
index 4b7c80ee4..aee1fb7d4 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.h
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.h
@@ -53,11 +53,12 @@ private:
void writeInitFunc(QTextStream &declStr, QTextStream &callStr,
const Indentor &indent, const QString &initFunctionName,
const TypeEntry *enclosingEntry = nullptr);
+ void writeCacheResetNative(QTextStream &s, const AbstractMetaClass *metaClass);
void writeConstructorNative(QTextStream &s, const AbstractMetaFunction *func);
void writeDestructorNative(QTextStream &s, const AbstractMetaClass *metaClass);
QString getVirtualFunctionReturnTypeName(const AbstractMetaFunction *func);
- void writeVirtualMethodNative(QTextStream &s, const AbstractMetaFunction *func);
+ void writeVirtualMethodNative(QTextStream &s, const AbstractMetaFunction *func, int cacheIndex);
void writeMetaObjectMethod(QTextStream &s, const AbstractMetaClass *metaClass);
void writeMetaCast(QTextStream &s, const AbstractMetaClass *metaClass);
diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.cpp b/sources/shiboken2/generator/shiboken2/headergenerator.cpp
index a565659de..af56d944a 100644
--- a/sources/shiboken2/generator/shiboken2/headergenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/headergenerator.cpp
@@ -139,10 +139,17 @@ void HeaderGenerator::generateClass(QTextStream &s, GeneratorContext &classConte
s << "\n{\npublic:\n";
const AbstractMetaFunctionList &funcs = filterFunctions(metaClass);
+ int maxOverrides = 0;
for (AbstractMetaFunction *func : funcs) {
- if ((func->attributes() & AbstractMetaAttributes::FinalCppMethod) == 0)
+ if ((func->attributes() & AbstractMetaAttributes::FinalCppMethod) == 0) {
writeFunction(s, func);
+ // PYSIDE-803: Build a boolean cache for unused overrides.
+ if (shouldWriteVirtualMethodNative(func))
+ maxOverrides++;
+ }
}
+ if (!maxOverrides)
+ maxOverrides = 1;
if (avoidProtectedHack() && metaClass->hasProtectedFields()) {
const AbstractMetaFieldList &fields = metaClass->fields();
@@ -182,6 +189,10 @@ void HeaderGenerator::generateClass(QTextStream &s, GeneratorContext &classConte
if (usePySideExtensions())
s << INDENT << "static void pysideInitQtMetaTypes();\n";
+ s << INDENT << "void resetPyMethodCache();\n";
+ s << "private:\n";
+ s << INDENT << "mutable bool m_PyMethodCache[" << maxOverrides << "];\n";
+
s << "};\n\n";
if (!innerHeaderGuard.isEmpty())
s << "# endif // SBK_" << innerHeaderGuard << "_H\n\n";
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
index 9793998b9..170cbd74e 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp
@@ -96,7 +96,7 @@ static QString resolveScopePrefix(const QStringList &scopeList, const QString &v
static inline QStringList splitClassScope(const AbstractMetaClass *scope)
{
- return scope->qualifiedCppName().split(QLatin1String("::"), QString::SkipEmptyParts);
+ return scope->qualifiedCppName().split(QLatin1String("::"), Qt::SkipEmptyParts);
}
static QString resolveScopePrefix(const AbstractMetaClass *scope, const QString &value)
@@ -322,6 +322,15 @@ bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass *metaCl
return result;
}
+bool ShibokenGenerator::shouldWriteVirtualMethodNative(const AbstractMetaFunction *func)
+{
+ // PYSIDE-803: Extracted this because it is used multiple times.
+ const AbstractMetaClass *metaClass = func->ownerClass();
+ return (!avoidProtectedHack() || !metaClass->hasPrivateDestructor())
+ && ((func->isVirtual() || func->isAbstract())
+ && (func->attributes() & AbstractMetaAttributes::FinalCppMethod) == 0);
+}
+
void ShibokenGenerator::lookForEnumsInClassesNotToBeGenerated(AbstractMetaEnumList &enumList, const AbstractMetaClass *metaClass)
{
Q_ASSERT(metaClass);
@@ -355,6 +364,15 @@ QString ShibokenGenerator::wrapperName(const AbstractMetaType *metaType) const
return metaType->cppSignature();
}
+QString ShibokenGenerator::wrapperName(const TypeEntry *type) const
+{
+ QString name = type->name();
+ int pos = name.lastIndexOf(QLatin1String("::"));
+ if (pos >= 0)
+ name = name.remove(0, pos + 2);
+ return name + QLatin1String("Wrapper");
+}
+
QString ShibokenGenerator::fullPythonClassName(const AbstractMetaClass *metaClass)
{
QString fullClassName = metaClass->name();
@@ -2167,6 +2185,13 @@ bool ShibokenGenerator::injectedCodeUsesArgument(const AbstractMetaFunction *fun
return false;
}
+bool ShibokenGenerator::useOverrideCaching(const AbstractMetaClass *metaClass)
+{
+ return metaClass->isPolymorphic()
+ && !metaClass->typeEntry()->typeFlags().testFlag(ComplexTypeEntry::NoOverrideCaching);
+
+}
+
ShibokenGenerator::AttroCheck ShibokenGenerator::checkAttroFunctionNeeds(const AbstractMetaClass *metaClass) const
{
AttroCheck result;
@@ -2177,6 +2202,8 @@ ShibokenGenerator::AttroCheck ShibokenGenerator::checkAttroFunctionNeeds(const A
result |= AttroCheckFlag::GetattroOverloads;
if (usePySideExtensions() && metaClass->qualifiedCppName() == QLatin1String("QObject"))
result |= AttroCheckFlag::SetattroQObject;
+ if (useOverrideCaching(metaClass))
+ result |= AttroCheckFlag::SetattroMethodOverride;
}
return result;
}
diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
index 55622b7c2..d0e9073c8 100644
--- a/sources/shiboken2/generator/shiboken2/shibokengenerator.h
+++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.h
@@ -72,6 +72,7 @@ public:
GetattroMask = 0x0F,
SetattroQObject = 0x10,
SetattroSmartPointer = 0x20,
+ SetattroMethodOverride = 0x40,
SetattroMask = 0xF0,
};
Q_DECLARE_FLAGS(AttroCheck, AttroCheckFlag);
@@ -193,6 +194,7 @@ protected:
/// Returns the top-most class that has multiple inheritance in the ancestry.
static const AbstractMetaClass *getMultipleInheritingClass(const AbstractMetaClass *metaClass);
+ static bool useOverrideCaching(const AbstractMetaClass *metaClass);
AttroCheck checkAttroFunctionNeeds(const AbstractMetaClass *metaClass) const;
/// Returns a list of methods of the given class where each one is part of a different overload with both static and non-static method.
@@ -212,11 +214,15 @@ protected:
/// Verifies if the class should have a C++ wrapper generated for it, instead of only a Python wrapper.
bool shouldGenerateCppWrapper(const AbstractMetaClass *metaClass) const;
+ /// Condition to call WriteVirtualMethodNative. Was extracted because also used to count these calls.
+ bool shouldWriteVirtualMethodNative(const AbstractMetaFunction *func);
+
/// Adds enums eligible for generation from classes/namespaces marked not to be generated.
static void lookForEnumsInClassesNotToBeGenerated(AbstractMetaEnumList &enumList, const AbstractMetaClass *metaClass);
QString wrapperName(const AbstractMetaClass *metaClass) const;
QString wrapperName(const AbstractMetaType *metaType) const;
+ QString wrapperName(const TypeEntry *type) const;
QString fullPythonClassName(const AbstractMetaClass *metaClass);
QString fullPythonFunctionName(const AbstractMetaFunction *func);