diff options
Diffstat (limited to 'sources/shiboken2')
-rw-r--r-- | sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst | 5 | ||||
-rw-r--r-- | sources/shiboken2/ApiExtractor/typesystem.cpp | 15 | ||||
-rw-r--r-- | sources/shiboken2/ApiExtractor/typesystem.h | 23 | ||||
-rw-r--r-- | sources/shiboken2/generator/shiboken2/cppgenerator.cpp | 29 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/sbkenum.cpp | 13 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/sbkenum.h | 2 | ||||
-rw-r--r-- | sources/shiboken2/tests/libsample/objecttype.h | 6 | ||||
-rw-r--r-- | sources/shiboken2/tests/samplebinding/enum_test.py | 5 | ||||
-rw-r--r-- | sources/shiboken2/tests/samplebinding/typesystem_sample.xml | 1 |
9 files changed, 75 insertions, 24 deletions
diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst index 0d24a6d52..646e76043 100644 --- a/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst +++ b/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst @@ -150,6 +150,7 @@ enum-type <typesystem> <enum-type name="..." identified-by-value="..." + class="yes | no" since="..." flags="yes | no" flags-revision="..." @@ -179,6 +180,10 @@ enum-type Notice that the **enum-type** tag can either have **name** or **identified-by-value** but not both. + The *optional* boolean attribute **class** specifies whether the underlying + enumeration is a C++ 11 enumeration class. In that case, the enumeration values + need to be qualified by the enumeration name to match the C++ Syntax. + The **revision** attribute can be used to specify a revision for each type, easing the production of ABI compatible bindings. diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp index 749ce2f71..69dccbb86 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.cpp +++ b/sources/shiboken2/ApiExtractor/typesystem.cpp @@ -58,6 +58,7 @@ static inline QString enumNameAttribute() { return QStringLiteral("enum-name"); static inline QString argumentTypeAttribute() { return QStringLiteral("argument-type"); } static inline QString returnTypeAttribute() { return QStringLiteral("return-type"); } static inline QString xPathAttribute() { return QStringLiteral("xpath"); } +static inline QString enumIdentifiedByValueAttribute() { return QStringLiteral("identified-by-value"); } static inline QString noAttributeValue() { return QStringLiteral("no"); } static inline QString yesAttributeValue() { return QStringLiteral("yes"); } @@ -758,7 +759,8 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts attributes.insert(QLatin1String("lower-bound"), QString()); attributes.insert(QLatin1String("force-integer"), noAttributeValue()); attributes.insert(QLatin1String("extensible"), noAttributeValue()); - attributes.insert(QLatin1String("identified-by-value"), QString()); + attributes.insert(enumIdentifiedByValueAttribute(), QString()); + attributes.insert(classAttribute(), falseAttributeValue()); break; case StackElement::ValueTypeEntry: attributes.insert(QLatin1String("default-constructor"), QString()); @@ -852,9 +854,10 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts } if (element->type == StackElement::EnumTypeEntry) { + const QString identifiedByValue = attributes.value(enumIdentifiedByValueAttribute()); if (name.isEmpty()) { - name = attributes[QLatin1String("identified-by-value")]; - } else if (!attributes[QLatin1String("identified-by-value")].isEmpty()) { + name = identifiedByValue; + } else if (!identifiedByValue.isEmpty()) { m_error = QLatin1String("can't specify both 'name' and 'identified-by-value' attributes"); return false; } @@ -939,7 +942,11 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts m_currentEnum = new EnumTypeEntry(QStringList(names.mid(0, names.size() - 1)).join(colonColon()), names.constLast(), since); - m_currentEnum->setAnonymous(!attributes[QLatin1String("identified-by-value")].isEmpty()); + if (!attributes.value(enumIdentifiedByValueAttribute()).isEmpty()) { + m_currentEnum->setEnumKind(EnumTypeEntry::AnonymousEnum); + } else if (convertBoolean(attributes.value(classAttribute()), classAttribute(), false)) { + m_currentEnum->setEnumKind(EnumTypeEntry::EnumClass); + } element->entry = m_currentEnum; m_currentEnum->setCodeGeneration(m_generate); m_currentEnum->setTargetLangPackage(m_defaultPackage); diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h index f2b5a9320..62d348f69 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.h +++ b/sources/shiboken2/ApiExtractor/typesystem.h @@ -1045,6 +1045,12 @@ private: class EnumTypeEntry : public TypeEntry { public: + enum EnumKind { + CEnum, // Standard C: enum Foo { value1, value2 } + AnonymousEnum, // enum { value1, value2 } + EnumClass // C++ 11 : enum class Foo { value1, value2 } + }; + explicit EnumTypeEntry(const QString &nspace, const QString &enumName, double vr); QString targetLangPackage() const override; @@ -1065,6 +1071,9 @@ public: m_qualifier = q; } + EnumKind enumKind() const { return m_enumKind; } + void setEnumKind(EnumKind kind) { m_enumKind = kind; } + bool preferredConversion() const override; bool isBoundsChecked() const @@ -1108,7 +1117,7 @@ public: m_extensible = is; } - bool isEnumValueRejected(const QString &name) + bool isEnumValueRejected(const QString &name) const { return m_rejectedEnums.contains(name); } @@ -1130,14 +1139,7 @@ public: m_forceInteger = force; } - bool isAnonymous() const - { - return m_anonymous; - } - void setAnonymous(bool anonymous) - { - m_anonymous = anonymous; - } + bool isAnonymous() const { return m_enumKind == AnonymousEnum; } private: QString m_packageName; @@ -1151,9 +1153,10 @@ private: FlagsTypeEntry *m_flags = nullptr; + EnumKind m_enumKind = CEnum; + bool m_extensible = false; bool m_forceInteger = false; - bool m_anonymous = false; }; // EnumValueTypeEntry is used for resolving integer type templates diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index 7a688d1da..be42adb0f 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -4471,6 +4471,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu const AbstractMetaClass* enclosingClass = getProperEnclosingClassForEnum(cppEnum); const AbstractMetaClass* upper = enclosingClass ? enclosingClass->enclosingClass() : 0; bool hasUpperEnclosingClass = upper && upper->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass; + const EnumTypeEntry *enumTypeEntry = cppEnum->typeEntry(); QString enclosingObjectVariable; if (enclosingClass) enclosingObjectVariable = QLatin1Char('&') + cpythonTypeName(enclosingClass); @@ -4483,14 +4484,17 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu s << (cppEnum->isAnonymous() ? "anonymous enum identified by enum value" : "enum"); s << " '" << cppEnum->name() << "'." << endl; + QString enumVarTypeObj; if (!cppEnum->isAnonymous()) { - FlagsTypeEntry* flags = cppEnum->typeEntry()->flags(); + FlagsTypeEntry* flags = enumTypeEntry->flags(); if (flags) { s << INDENT << cpythonTypeNameExt(flags) << " = PySide::QFlags::create(\"" << flags->flagsName() << "\", &" << cpythonEnumName(cppEnum) << "_as_number);" << endl; } - s << INDENT << cpythonTypeNameExt(cppEnum->typeEntry()) << " = Shiboken::Enum::"; + enumVarTypeObj = cpythonTypeNameExt(enumTypeEntry); + + s << INDENT << enumVarTypeObj << " = Shiboken::Enum::"; s << ((enclosingClass || hasUpperEnclosingClass) ? "createScopedEnum" : "createGlobalEnum"); s << '(' << enclosingObjectVariable << ',' << endl; { @@ -4512,7 +4516,7 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu const AbstractMetaEnumValueList &enumValues = cppEnum->values(); for (const AbstractMetaEnumValue *enumValue : enumValues) { - if (cppEnum->typeEntry()->isEnumValueRejected(enumValue->name())) + if (enumTypeEntry->isEnumValueRejected(enumValue->name())) continue; QString enumValueText; @@ -4528,7 +4532,8 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu enumValueText += QString::number(enumValue->value()); } - if (cppEnum->isAnonymous()) { + switch (enumTypeEntry->enumKind()) { + case EnumTypeEntry::AnonymousEnum: if (enclosingClass || hasUpperEnclosingClass) { s << INDENT << '{' << endl; { @@ -4551,15 +4556,27 @@ void CppGenerator::writeEnumInitialization(QTextStream& s, const AbstractMetaEnu s << INDENT << "return " << m_currentErrorCode << ';' << endl; } } - } else { + break; + case EnumTypeEntry::CEnum: { s << INDENT << "if (!Shiboken::Enum::"; s << ((enclosingClass || hasUpperEnclosingClass) ? "createScopedEnumItem" : "createGlobalEnumItem"); - s << '(' << cpythonTypeNameExt(cppEnum->typeEntry()) << ',' << endl; + s << '(' << enumVarTypeObj << ',' << endl; Indentation indent(INDENT); s << INDENT << enclosingObjectVariable << ", \"" << enumValue->name() << "\", "; s << enumValueText << "))" << endl; s << INDENT << "return " << m_currentErrorCode << ';' << endl; } + break; + case EnumTypeEntry::EnumClass: { + s << INDENT << "if (!Shiboken::Enum::createScopedEnumItem(" + << enumVarTypeObj << ',' << endl; + Indentation indent(INDENT); + s << INDENT << enumVarTypeObj<< ", \"" << enumValue->name() << "\", " + << enumValueText << "))" << endl + << INDENT << "return " << m_currentErrorCode << ';' << endl; + } + break; + } } writeEnumConverterInitialization(s, cppEnum); diff --git a/sources/shiboken2/libshiboken/sbkenum.cpp b/sources/shiboken2/libshiboken/sbkenum.cpp index a62448aa6..c817a21de 100644 --- a/sources/shiboken2/libshiboken/sbkenum.cpp +++ b/sources/shiboken2/libshiboken/sbkenum.cpp @@ -492,11 +492,11 @@ bool createGlobalEnumItem(PyTypeObject* enumType, PyObject* module, const char* return false; } -bool createScopedEnumItem(PyTypeObject* enumType, SbkObjectType* scope, const char* itemName, long itemValue) +bool createScopedEnumItem(PyTypeObject *enumType, PyTypeObject *scope, + const char *itemName, long itemValue) { - PyObject* enumItem = createEnumItem(enumType, itemName, itemValue); - if (enumItem) { - if (PyDict_SetItemString(scope->super.ht_type.tp_dict, itemName, enumItem) < 0) + if (PyObject *enumItem = createEnumItem(enumType, itemName, itemValue)) { + if (PyDict_SetItemString(scope->tp_dict, itemName, enumItem) < 0) return false; Py_DECREF(enumItem); return true; @@ -504,6 +504,11 @@ bool createScopedEnumItem(PyTypeObject* enumType, SbkObjectType* scope, const ch return false; } +bool createScopedEnumItem(PyTypeObject* enumType, SbkObjectType* scope, const char* itemName, long itemValue) +{ + return createScopedEnumItem(enumType, &scope->super.ht_type, itemName, itemValue); +} + PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName) { bool newValue = true; diff --git a/sources/shiboken2/libshiboken/sbkenum.h b/sources/shiboken2/libshiboken/sbkenum.h index 4b572dbcc..b01114ba6 100644 --- a/sources/shiboken2/libshiboken/sbkenum.h +++ b/sources/shiboken2/libshiboken/sbkenum.h @@ -95,6 +95,8 @@ namespace Enum */ LIBSHIBOKEN_API bool createGlobalEnumItem(PyTypeObject* enumType, PyObject* module, const char* itemName, long itemValue); /// This function does the same as createGlobalEnumItem, but adds the enum to a Shiboken type or namespace. + LIBSHIBOKEN_API bool createScopedEnumItem(PyTypeObject *enumType, PyTypeObject *scope, + const char *itemName, long itemValue); LIBSHIBOKEN_API bool createScopedEnumItem(PyTypeObject* enumType, SbkObjectType* scope, const char* itemName, long itemValue); LIBSHIBOKEN_API PyObject* newItem(PyTypeObject* enumType, long itemValue, const char* itemName = 0); diff --git a/sources/shiboken2/tests/libsample/objecttype.h b/sources/shiboken2/tests/libsample/objecttype.h index 752659488..91fb45515 100644 --- a/sources/shiboken2/tests/libsample/objecttype.h +++ b/sources/shiboken2/tests/libsample/objecttype.h @@ -45,6 +45,12 @@ struct Event SOME_EVENT, ANY_EVENT }; + + enum class EventTypeClass { + Value1, + Value2 + }; + Event(EventType eventType) : m_eventType(eventType) {} EventType eventType() { return m_eventType; } private: diff --git a/sources/shiboken2/tests/samplebinding/enum_test.py b/sources/shiboken2/tests/samplebinding/enum_test.py index 6468d3cc4..711215c35 100644 --- a/sources/shiboken2/tests/samplebinding/enum_test.py +++ b/sources/shiboken2/tests/samplebinding/enum_test.py @@ -110,6 +110,11 @@ class EnumTest(unittest.TestCase): self.assertEqual(SampleNamespace.AnonymousClassEnum_Value0, 0) self.assertEqual(SampleNamespace.AnonymousClassEnum_Value1, 1) + def testEnumClasses(self): + # C++ 11: values of enum classes need to be fully qualified to match C++ + sum = Event.EventTypeClass.Value1 + Event.EventTypeClass.Value2 + self.assertEqual(sum, 1) + def testEnumTpPrintImplementation(self): '''Without SbkEnum.tp_print 'print' returns the enum represented as an int.''' tmpfile = createTempFile() diff --git a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml index ffb5c976f..5a12eeccd 100644 --- a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml +++ b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml @@ -798,6 +798,7 @@ <value-type name="Event"> <enum-type name="EventType"/> + <enum-type name="EventTypeClass" class="yes"/> </value-type> <value-type name="BlackBox"> |