diff options
10 files changed, 141 insertions, 9 deletions
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index f16a142b3..6b230f1f4 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -1613,7 +1613,12 @@ AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFu metaFunction->setFunctionType(AbstractMetaFunction::CopyConstructorFunction); } } else { - metaFunction->setFunctionType(AbstractMetaFunction::NormalFunction); + auto type = AbstractMetaFunction::NormalFunction; + if (metaFunction->name() == QLatin1String("__getattro__")) + type = AbstractMetaFunction::GetAttroFunction; + else if (metaFunction->name() == QLatin1String("__setattro__")) + type = AbstractMetaFunction::SetAttroFunction; + metaFunction->setFunctionType(type); } metaFunction->setDeclaringClass(metaClass); diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp index 1b2ee5568..390143cda 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp @@ -2065,6 +2065,16 @@ bool AbstractMetaClass::queryFunction(const AbstractMetaFunction *f, FunctionQue if ((query & GenerateExceptionHandling) && !f->generateExceptionHandling()) return false; + if (query.testFlag(GetAttroFunction) + && f->functionType() != AbstractMetaFunction::GetAttroFunction) { + return false; + } + + if (query.testFlag(SetAttroFunction) + && f->functionType() != AbstractMetaFunction::SetAttroFunction) { + return false; + } + return true; } diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h index 7db5ec1bd..00f137100 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.h +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h @@ -763,7 +763,9 @@ public: SignalFunction, EmptyFunction, SlotFunction, - GlobalScopeFunction + GlobalScopeFunction, + GetAttroFunction, + SetAttroFunction }; Q_ENUM(FunctionType) @@ -1271,7 +1273,9 @@ public: VirtualInTargetLangFunctions = 0x0080000, // Only functions which are virtual in TargetLang NotRemovedFromTargetLang = 0x0400000, // Only functions that have not been removed from TargetLang OperatorOverloads = 0x2000000, // Only functions that are operator overloads - GenerateExceptionHandling = 0x4000000 + GenerateExceptionHandling = 0x4000000, + GetAttroFunction = 0x8000000, + SetAttroFunction = 0x10000000 }; Q_DECLARE_FLAGS(FunctionQueryOptions, FunctionQueryOption) Q_FLAG(FunctionQueryOption) diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index 724b390e0..166a31dfd 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -5308,6 +5308,22 @@ void CppGenerator::writeSetattroFunction(QTextStream &s, AttroCheck attroCheck, Indentation indent(INDENT); s << INDENT << "return PySide::Property::setValue(reinterpret_cast<PySideProperty *>(pp.object()), self, value);\n"; } + + if (attroCheck.testFlag(AttroCheckFlag::SetattroUser)) { + auto func = AbstractMetaClass::queryFirstFunction(metaClass->functions(), + AbstractMetaClass::SetAttroFunction); + Q_ASSERT(func); + s << INDENT << "{\n"; + { + Indentation indent(INDENT); + s << INDENT << "auto " << CPP_SELF_VAR << " = " + << cpythonWrapperCPtr(metaClass, QLatin1String("self")) << ";\n"; + writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionAny, + TypeSystem::TargetLangCode, metaClass); + } + s << INDENT << "}\n"; + } + writeSetattroDefaultReturn(s); } @@ -5412,6 +5428,21 @@ void CppGenerator::writeGetattroFunction(QTextStream &s, AttroCheck attroCheck, } } + if (attroCheck.testFlag(AttroCheckFlag::GetattroUser)) { + auto func = AbstractMetaClass::queryFirstFunction(metaClass->functions(), + AbstractMetaClass::GetAttroFunction); + Q_ASSERT(func); + s << INDENT << "{\n"; + { + Indentation indent(INDENT); + s << INDENT << "auto " << CPP_SELF_VAR << " = " + << cpythonWrapperCPtr(metaClass, QLatin1String("self")) << ";\n"; + writeCodeSnips(s, func->injectedCodeSnips(), TypeSystem::CodeSnipPositionAny, + TypeSystem::TargetLangCode, metaClass); + } + s << INDENT << "}\n"; + } + s << INDENT << "return " << getattrFunc << ";\n}\n\n"; } diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp index 90ae4299d..47cca8173 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -1555,16 +1555,34 @@ void ShibokenGenerator::writeUnusedVariableCast(QTextStream &s, const QString &v s << INDENT << "SBK_UNUSED(" << variableName<< ")\n"; } +static bool filterFunction(const AbstractMetaFunction *func, bool avoidProtectedHack) +{ + switch (func->functionType()) { + case AbstractMetaFunction::DestructorFunction: + case AbstractMetaFunction::SignalFunction: + case AbstractMetaFunction::GetAttroFunction: + case AbstractMetaFunction::SetAttroFunction: + return false; + default: + break; + } + if (func->usesRValueReferences()) + return false; + if (func->isModifiedRemoved() && !func->isAbstract() + && (!avoidProtectedHack || !func->isProtected())) { + return false; + } + return true; +} + AbstractMetaFunctionList ShibokenGenerator::filterFunctions(const AbstractMetaClass *metaClass) { AbstractMetaFunctionList result; const AbstractMetaFunctionList &funcs = metaClass->functions(); + result.reserve(funcs.size()); for (AbstractMetaFunction *func : funcs) { - if (func->isSignal() || func->isDestructor() || func->usesRValueReferences() - || (func->isModifiedRemoved() && !func->isAbstract() - && (!avoidProtectedHack() || !func->isProtected()))) - continue; - result << func; + if (filterFunction(func, avoidProtectedHack())) + result.append(func); } return result; } @@ -2199,10 +2217,18 @@ ShibokenGenerator::AttroCheck ShibokenGenerator::checkAttroFunctionNeeds(const A } else { if (getGeneratorClassInfo(metaClass).needsGetattroFunction) result |= AttroCheckFlag::GetattroOverloads; + if (metaClass->queryFirstFunction(metaClass->functions(), + AbstractMetaClass::GetAttroFunction)) { + result |= AttroCheckFlag::GetattroUser; + } if (usePySideExtensions() && metaClass->qualifiedCppName() == QLatin1String("QObject")) result |= AttroCheckFlag::SetattroQObject; if (useOverrideCaching(metaClass)) result |= AttroCheckFlag::SetattroMethodOverride; + if (metaClass->queryFirstFunction(metaClass->functions(), + AbstractMetaClass::SetAttroFunction)) { + result |= AttroCheckFlag::SetattroUser; + } // PYSIDE-1255: If setattro is generated for a class inheriting // QObject, the property code needs to be generated, too. if ((result & AttroCheckFlag::SetattroMask) != 0 @@ -2380,7 +2406,16 @@ static void dumpFunction(AbstractMetaFunctionList lst) static bool isGroupable(const AbstractMetaFunction *func) { - if (func->isSignal() || func->isDestructor() || (func->isModifiedRemoved() && !func->isAbstract())) + switch (func->functionType()) { + case AbstractMetaFunction::DestructorFunction: + case AbstractMetaFunction::SignalFunction: + case AbstractMetaFunction::GetAttroFunction: + case AbstractMetaFunction::SetAttroFunction: + return false; + default: + break; + } + if (func->isModifiedRemoved() && !func->isAbstract()) return false; // weird operator overloads if (func->name() == QLatin1String("operator[]") || func->name() == QLatin1String("operator->")) // FIXME: what about cast operators? diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h index 2ad5ffbdf..0d4b1344a 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.h +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.h @@ -69,10 +69,12 @@ public: None = 0x0, GetattroOverloads = 0x01, GetattroSmartPointer = 0x02, + GetattroUser = 0x04, // Injected code GetattroMask = 0x0F, SetattroQObject = 0x10, SetattroSmartPointer = 0x20, SetattroMethodOverride = 0x40, + SetattroUser = 0x80, // Injected code SetattroMask = 0xF0, }; Q_DECLARE_FLAGS(AttroCheck, AttroCheckFlag); diff --git a/sources/shiboken2/tests/libsample/modifications.cpp b/sources/shiboken2/tests/libsample/modifications.cpp index 56ba81875..627d17b45 100644 --- a/sources/shiboken2/tests/libsample/modifications.cpp +++ b/sources/shiboken2/tests/libsample/modifications.cpp @@ -165,3 +165,22 @@ Modifications::TestEnum Modifications::defaultEnumValue() const return TestEnumValue2; } +bool Modifications::wasGetAttroCalled() const +{ + return m_getAttroCalled; +} + +void Modifications::notifyGetAttroCalled() +{ + m_getAttroCalled = true; +} + +bool Modifications::wasSetAttroCalled() const +{ + return m_setAttroCalled; +} + +void Modifications::notifySetAttroCalled() +{ + m_setAttroCalled = true; +} diff --git a/sources/shiboken2/tests/libsample/modifications.h b/sources/shiboken2/tests/libsample/modifications.h index 674a05f27..888c66d18 100644 --- a/sources/shiboken2/tests/libsample/modifications.h +++ b/sources/shiboken2/tests/libsample/modifications.h @@ -132,9 +132,17 @@ public: TestEnum enumValue() const; TestEnum defaultEnumValue() const; + bool wasGetAttroCalled() const; + void notifyGetAttroCalled(); + + bool wasSetAttroCalled() const; + void notifySetAttroCalled(); + private: ObjectType* m_object; TestEnum m_enumValue = TestEnumValue1; + bool m_getAttroCalled = false; + bool m_setAttroCalled = false; }; class LIBSAMPLE_API AbstractModifications : public Modifications diff --git a/sources/shiboken2/tests/samplebinding/modifications_test.py b/sources/shiboken2/tests/samplebinding/modifications_test.py index e6e9c5626..763ba04e5 100644 --- a/sources/shiboken2/tests/samplebinding/modifications_test.py +++ b/sources/shiboken2/tests/samplebinding/modifications_test.py @@ -235,6 +235,14 @@ class ModificationsTest(unittest.TestCase): modifications.setEnumValue() self.assertEqual(modifications.enumValue(), Modifications.TestEnumValue2) + def testSetGetAttro(self): + modifications = Modifications() + self.assertFalse(modifications.wasSetAttroCalled()) + setattr(modifications, 'Foo', 'Bar') + self.assertTrue(modifications.wasSetAttroCalled()) + self.assertEqual(getattr(modifications, 'Foo'), 'Bar') + self.assertTrue(modifications.wasGetAttroCalled()) + if __name__ == '__main__': unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml index c3db91324..32df8fd7b 100644 --- a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml +++ b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml @@ -1293,6 +1293,16 @@ <replace-default-expression with="cppSelf->defaultEnumValue()"/> </modify-argument> </modify-function> + <add-function signature="__getattro__" return-type="PyObject *"> + <inject-code class="target" position="beginning"> + cppSelf->notifyGetAttroCalled(); + </inject-code> + </add-function> + <add-function signature="__setattro__" return-type="int"> + <inject-code class="target" position="beginning"> + cppSelf->notifySetAttroCalled(); + </inject-code> + </add-function> </object-type> <object-type name="AbstractModifications"> |
