diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2018-02-28 10:30:27 +0100 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2018-02-28 14:01:37 +0000 |
commit | 44cb6c51e6c3b43376f284941454dc8c13b81c3f (patch) | |
tree | 7e9fda1ba3788a3b9ed051e853b08926d325df6f /sources/shiboken2 | |
parent | 7c83f2ebc1ac55c6e2556c8c852716502dcdba5a (diff) |
Type system: Add attribute indicating C++ 11 enum classes
Introduce enumeration for the type to EnumTypeEntry which can be specified
by the boolean "class" attribute. For the enum classes, the value names
need to be qualified by the enum name to match the C++ API.
For the C++ generator, add an overload to
Shiboken::createScopedEnumItem() that takes a PyTypeObject and add the enum
items to the enum so that the name is in the enum scope.
Change-Id: Ia0e469d13b08c196b9ddd965b9cf3cc62a38630b
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
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"> |