From 0aa52375886138693caf395238fcd3baf3489dec Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 28 Feb 2019 10:42:30 +0100 Subject: shiboken: Fix exception handling when specified in base class Class-level exception specifications on a base class were not working so far. This requires a larger refactoring, since the base classes are not yet known at the point where class functions were traversed (AbstractMetaBuilder::setupInheritance() is called at a later stage). To fix this, store the actual type system modification in the AbstractMetaFunction and move the logic determining whether to generate exception handling into AbstractMetaFunction::generateExceptionHandling(). In this function, recurse down the base classes if the function does not have a modification set. This is a preparation for giving the allow-thread attribute, which can currently only be used at a function level, a similar handling. Task-number: PYSIDE-62 Change-Id: I28597559511d330cf860c6f6e21ffea229bfab3e Reviewed-by: Cristian Maureira-Fredes --- .../shiboken2/ApiExtractor/abstractmetabuilder.cpp | 39 +---------- .../shiboken2/ApiExtractor/abstractmetalang.cpp | 77 ++++++++++++++++++++-- sources/shiboken2/ApiExtractor/abstractmetalang.h | 9 ++- .../ApiExtractor/tests/testmodifyfunction.cpp | 11 ++++ 4 files changed, 91 insertions(+), 45 deletions(-) diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index 15700e91e..41ae5d7f1 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -1871,40 +1871,12 @@ bool AbstractMetaBuilderPrivate::setArrayArgumentType(AbstractMetaFunction *func return true; } -static bool generateExceptionHandling(const AbstractMetaFunction *func, - ExceptionSpecification spec, - TypeSystem::ExceptionHandling handling) -{ - switch (func->functionType()) { - case AbstractMetaFunction::CopyConstructorFunction: - case AbstractMetaFunction::MoveConstructorFunction: - case AbstractMetaFunction::AssignmentOperatorFunction: - case AbstractMetaFunction::MoveAssignmentOperatorFunction: - case AbstractMetaFunction::DestructorFunction: - return false; - default: - break; - } - switch (handling) { - case TypeSystem::ExceptionHandling::On: - return true; - case TypeSystem::ExceptionHandling::AutoDefaultToOn: - return spec != ExceptionSpecification::NoExcept; - case TypeSystem::ExceptionHandling::AutoDefaultToOff: - return spec == ExceptionSpecification::Throws; - default: - break; - } - return false; -} - AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const FunctionModelItem &functionItem) { if (functionItem->isDeleted() || !functionItem->templateParameters().isEmpty()) return nullptr; QString functionName = functionItem->name(); QString className; - TypeSystem::ExceptionHandling exceptionHandling = TypeSystem::ExceptionHandling::Unspecified; if (m_currentClass) { // Clang: Skip qt_metacast(), qt_metacall(), expanded from Q_OBJECT // and overridden metaObject(), QGADGET helpers @@ -1913,7 +1885,6 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio return nullptr; } className = m_currentClass->typeEntry()->qualifiedCppName(); - exceptionHandling = m_currentClass->typeEntry()->exceptionHandling(); if (functionName == QLatin1String("metaObject") && className != QLatin1String("QObject")) return nullptr; } @@ -2085,16 +2056,10 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio const FunctionModificationList functionMods = metaFunction->modifications(m_currentClass); for (const FunctionModification &mod : functionMods) { - if (mod.exceptionHandling() != TypeSystem::ExceptionHandling::Unspecified) { - exceptionHandling = mod.exceptionHandling(); - break; - } + if (mod.exceptionHandling() != TypeSystem::ExceptionHandling::Unspecified) + metaFunction->setExceptionHandlingModification(mod.exceptionHandling()); } - metaFunction->setGenerateExceptionHandling(generateExceptionHandling(metaFunction, - functionItem->exceptionSpecification(), - exceptionHandling)); - // Find the correct default values for (int i = 0, size = metaArguments.size(); i < size; ++i) { const ArgumentModelItem &arg = arguments.at(i); diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp index 73f1bf621..660bbdff1 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp @@ -72,6 +72,26 @@ MetaClass *findByName(QVector haystack, QStringView needle) return nullptr; } +// Helper for recursing the base classes of an AbstractMetaClass. +// Returns the class for which the predicate is true. +template +const AbstractMetaClass *recurseClassHierarchy(const AbstractMetaClass *klass, + Predicate pred) +{ + if (pred(klass)) + return klass; + if (auto base = klass->baseClass()) { + if (auto r = recurseClassHierarchy(base, pred)) + return r; + } + const auto interfaces = klass->interfaces(); + for (auto i : interfaces) { + if (auto r = recurseClassHierarchy(i, pred)) + return r; + } + return nullptr; +} + /******************************************************************************* * AbstractMetaVariable */ @@ -411,8 +431,7 @@ AbstractMetaFunction::AbstractMetaFunction() m_userAdded(false), m_explicit(false), m_pointerOperator(false), - m_isCallOperator(false), - m_generateExceptionHandling(false) + m_isCallOperator(false) { } @@ -531,7 +550,7 @@ AbstractMetaFunction *AbstractMetaFunction::copy() const cpy->setType(type()->copy()); cpy->setConstant(isConstant()); cpy->setExceptionSpecification(m_exceptionSpecification); - cpy->setGenerateExceptionHandling(m_generateExceptionHandling); + cpy->setExceptionHandlingModification(m_exceptionHandlingModification); for (AbstractMetaArgument *arg : m_arguments) cpy->addArgument(arg->copy()); @@ -975,6 +994,54 @@ void AbstractMetaFunction::setExceptionSpecification(ExceptionSpecification e) m_exceptionSpecification = e; } +static inline TypeSystem::ExceptionHandling exceptionMod(const AbstractMetaClass *klass) +{ + return klass->typeEntry()->exceptionHandling(); +} + +static inline bool hasExceptionMod(const AbstractMetaClass *klass) +{ + return exceptionMod(klass) != TypeSystem::ExceptionHandling::Unspecified; +} + +bool AbstractMetaFunction::generateExceptionHandling() const +{ + switch (m_functionType) { + case AbstractMetaFunction::CopyConstructorFunction: + case AbstractMetaFunction::MoveConstructorFunction: + case AbstractMetaFunction::AssignmentOperatorFunction: + case AbstractMetaFunction::MoveAssignmentOperatorFunction: + case AbstractMetaFunction::DestructorFunction: + return false; + default: + break; + } + + auto exceptionHandlingModification = m_exceptionHandlingModification; + // If there is no modification on the function, check for a base class. + if (m_class && exceptionHandlingModification == TypeSystem::ExceptionHandling::Unspecified) { + if (auto base = recurseClassHierarchy(m_class, hasExceptionMod)) + exceptionHandlingModification = exceptionMod(base); + } + + bool result = false; + switch (exceptionHandlingModification) { + case TypeSystem::ExceptionHandling::On: + result = true; + break; + case TypeSystem::ExceptionHandling::AutoDefaultToOn: + result = m_exceptionSpecification != ExceptionSpecification::NoExcept; + break; + case TypeSystem::ExceptionHandling::AutoDefaultToOff: + result = m_exceptionSpecification == ExceptionSpecification::Throws; + break; + case TypeSystem::ExceptionHandling::Unspecified: + case TypeSystem::ExceptionHandling::Off: + break; + } + return result; +} + bool AbstractMetaFunction::isOperatorOverload(const QString& funcName) { if (isConversionOperator(funcName)) @@ -1159,8 +1226,8 @@ void AbstractMetaFunction::formatDebugVerbose(QDebug &d) const d << " throw(...)"; break; } - if (m_generateExceptionHandling) - d << "[generate-exception-handling]"; + if (m_exceptionHandlingModification != TypeSystem::ExceptionHandling::Unspecified) + d << " exeption-mod " << int(m_exceptionHandlingModification); d << '('; for (int i = 0, count = m_arguments.size(); i < count; ++i) { if (i) diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h index 1ab3049b2..56b36b638 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.h +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h @@ -851,8 +851,7 @@ public: ExceptionSpecification exceptionSpecification() const; void setExceptionSpecification(ExceptionSpecification e); - bool generateExceptionHandling() const { return m_generateExceptionHandling; } - void setGenerateExceptionHandling(bool g) { m_generateExceptionHandling = g; } + bool generateExceptionHandling() const; bool isConversionOperator() const { @@ -1096,6 +1095,10 @@ public: static AbstractMetaFunction * find(const AbstractMetaFunctionList &haystack, const QString &needle); + // for the meta builder only + void setExceptionHandlingModification(TypeSystem::ExceptionHandling em) + { m_exceptionHandlingModification = em; } + #ifndef QT_NO_DEBUG_STREAM void formatDebugVerbose(QDebug &d) const; #endif @@ -1123,9 +1126,9 @@ private: uint m_explicit : 1; uint m_pointerOperator : 1; uint m_isCallOperator : 1; - uint m_generateExceptionHandling: 1; mutable int m_cachedAllowThread = -1; ExceptionSpecification m_exceptionSpecification = ExceptionSpecification::Unknown; + TypeSystem::ExceptionHandling m_exceptionHandlingModification = TypeSystem::ExceptionHandling::Unspecified; }; Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaFunction::CompareResult) diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp index 5016f38c5..88e0c500d 100644 --- a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp +++ b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp @@ -394,6 +394,17 @@ struct A : public Base { )XML") << true << false << true; + // Activate on base class level + QTest::newRow("baseclass-on") + << cppCode + << QByteArray(R"XML( + + + + +)XML") + << true << false << true; + // Override value on class level QTest::newRow("override-class-on") << cppCode -- cgit v1.2.3