summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2019-02-28 10:42:30 +0100
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2019-02-28 15:48:07 +0000
commit0aa52375886138693caf395238fcd3baf3489dec (patch)
treefc24d91372e071e41db65831f919b505cb898083
parente9c89837f91bf608371a7e39903ecd4038f769c1 (diff)
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 <cristian.maureira-fredes@qt.io>
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp39
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.cpp77
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.h9
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp11
4 files changed, 91 insertions, 45 deletions
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
index 15700e91..41ae5d7f 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 73f1bf62..660bbdff 100644
--- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
@@ -72,6 +72,26 @@ MetaClass *findByName(QVector<MetaClass *> haystack, QStringView needle)
return nullptr;
}
+// Helper for recursing the base classes of an AbstractMetaClass.
+// Returns the class for which the predicate is true.
+template <class Predicate>
+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 1ab3049b..56b36b63 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 5016f38c..88e0c500 100644
--- a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp
+++ b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp
@@ -394,6 +394,17 @@ struct A : public Base {
</typesystem>)XML")
<< true << false << true;
+ // Activate on base class level
+ QTest::newRow("baseclass-on")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base' exception-handling='auto-on'/>
+ <object-type name='A'/>
+</typesystem>)XML")
+ << true << false << true;
+
// Override value on class level
QTest::newRow("override-class-on")
<< cppCode