diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2018-03-06 07:58:51 +0100 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2018-03-06 12:43:06 +0100 |
commit | df7c72e63c6b7aecee156db2eff726bcfb89977e (patch) | |
tree | b9cecf87e2cd75d11813cd06ef1f2a5ab28384de /sources/shiboken2 | |
parent | e621f81115cec5089f30755e09b9a59ece39660c (diff) | |
parent | f3139399b273fdf405f20cba32a08262cd933d6e (diff) |
Merge remote-tracking branch 'origin/5.9' into dev
Change-Id: I071f33063db6bf1175b017d65ac77bc95fe518df
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 | 106 | ||||
-rw-r--r-- | sources/shiboken2/ApiExtractor/typesystem.h | 41 | ||||
-rw-r--r-- | sources/shiboken2/ApiExtractor/typesystem_p.h | 1 | ||||
-rw-r--r-- | sources/shiboken2/CMakeLists.txt | 60 | ||||
-rw-r--r-- | sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp | 71 | ||||
-rw-r--r-- | sources/shiboken2/generator/qtdoc/qtdocgenerator.h | 9 | ||||
-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/shiboken_version.py | 49 | ||||
-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 |
14 files changed, 273 insertions, 125 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 4a8d3063d..69dccbb86 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.cpp +++ b/sources/shiboken2/ApiExtractor/typesystem.cpp @@ -58,6 +58,12 @@ 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"); } +static inline QString trueAttributeValue() { return QStringLiteral("true"); } +static inline QString falseAttributeValue() { return QStringLiteral("false"); } static QVector<CustomConversion *> customConversionsForReview; @@ -534,21 +540,22 @@ bool Handler::importFileElement(const QXmlStreamAttributes &atts) return true; } -bool Handler::convertBoolean(const QString &_value, const QString &attributeName, bool defaultValue) +static bool convertBoolean(const QString &value, const QString &attributeName, bool defaultValue) { - QString value = _value.toLower(); - if (value == QLatin1String("true") || value == QLatin1String("yes")) + if (value.compare(trueAttributeValue(), Qt::CaseInsensitive) == 0 + || value.compare(yesAttributeValue(), Qt::CaseInsensitive) == 0) { return true; - else if (value == QLatin1String("false") || value == QLatin1String("no")) + } + if (value.compare(falseAttributeValue(), Qt::CaseInsensitive) == 0 + || value.compare(noAttributeValue(), Qt::CaseInsensitive) == 0) { return false; - else { - QString warn = QStringLiteral("Boolean value '%1' not supported in attribute '%2'. Use 'yes' or 'no'. Defaulting to '%3'.") + } + const QString warn = QStringLiteral("Boolean value '%1' not supported in attribute '%2'. Use 'yes' or 'no'. Defaulting to '%3'.") .arg(value, attributeName, - defaultValue ? QLatin1String("yes") : QLatin1String("no")); + defaultValue ? yesAttributeValue() : noAttributeValue()); - qCWarning(lcShiboken).noquote().nospace() << warn; - return defaultValue; - } + qCWarning(lcShiboken).noquote().nospace() << warn; + return defaultValue; } static bool convertRemovalAttribute(const QString& removalAttribute, Modification& mod, QString& errorMsg) @@ -733,8 +740,8 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts case StackElement::PrimitiveTypeEntry: attributes.insert(QLatin1String("target-lang-name"), QString()); attributes.insert(QLatin1String("target-lang-api-name"), QString()); - attributes.insert(QLatin1String("preferred-conversion"), QLatin1String("yes")); - attributes.insert(QLatin1String("preferred-target-lang-type"), QLatin1String("yes")); + attributes.insert(QLatin1String("preferred-conversion"), yesAttributeValue()); + attributes.insert(QLatin1String("preferred-target-lang-type"), yesAttributeValue()); attributes.insert(QLatin1String("default-constructor"), QString()); break; case StackElement::ContainerTypeEntry: @@ -750,23 +757,24 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts attributes.insert(QLatin1String("flags-revision"), QString()); attributes.insert(QLatin1String("upper-bound"), QString()); attributes.insert(QLatin1String("lower-bound"), QString()); - attributes.insert(QLatin1String("force-integer"), QLatin1String("no")); - attributes.insert(QLatin1String("extensible"), QLatin1String("no")); - attributes.insert(QLatin1String("identified-by-value"), QString()); + attributes.insert(QLatin1String("force-integer"), noAttributeValue()); + attributes.insert(QLatin1String("extensible"), noAttributeValue()); + attributes.insert(enumIdentifiedByValueAttribute(), QString()); + attributes.insert(classAttribute(), falseAttributeValue()); break; case StackElement::ValueTypeEntry: attributes.insert(QLatin1String("default-constructor"), QString()); Q_FALLTHROUGH(); case StackElement::ObjectTypeEntry: - attributes.insert(QLatin1String("force-abstract"), QLatin1String("no")); - attributes.insert(QLatin1String("deprecated"), QLatin1String("no")); + attributes.insert(QLatin1String("force-abstract"), noAttributeValue()); + attributes.insert(QLatin1String("deprecated"), noAttributeValue()); attributes.insert(QLatin1String("hash-function"), QString()); - attributes.insert(QLatin1String("stream"), QLatin1String("no")); + attributes.insert(QLatin1String("stream"), noAttributeValue()); Q_FALLTHROUGH(); case StackElement::InterfaceTypeEntry: attributes[QLatin1String("default-superclass")] = m_defaultSuperclass; attributes.insert(QLatin1String("polymorphic-id-expression"), QString()); - attributes.insert(QLatin1String("delete-in-main-thread"), QLatin1String("no")); + attributes.insert(QLatin1String("delete-in-main-thread"), noAttributeValue()); attributes.insert(QLatin1String("held-type"), QString()); attributes.insert(QLatin1String("copyable"), QString()); Q_FALLTHROUGH(); @@ -775,10 +783,10 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts attributes[QLatin1String("package")] = m_defaultPackage; attributes.insert(QLatin1String("expense-cost"), QLatin1String("1")); attributes.insert(QLatin1String("expense-limit"), QLatin1String("none")); - attributes.insert(QLatin1String("polymorphic-base"), QLatin1String("no")); - attributes.insert(QLatin1String("generate"), QLatin1String("yes")); + attributes.insert(QLatin1String("polymorphic-base"), noAttributeValue()); + attributes.insert(QLatin1String("generate"), yesAttributeValue()); attributes.insert(QLatin1String("target-type"), QString()); - attributes.insert(QLatin1String("generic-class"), QLatin1String("no")); + attributes.insert(QLatin1String("generic-class"), noAttributeValue()); break; case StackElement::FunctionTypeEntry: attributes.insert(QLatin1String("signature"), QString()); @@ -846,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; } @@ -933,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); @@ -988,7 +1001,7 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts if (!element->entry) element->entry = new ObjectTypeEntry(name, since); - element->entry->setStream(attributes[QLatin1String("stream")] == QLatin1String("yes")); + element->entry->setStream(attributes[QLatin1String("stream")] == yesAttributeValue()); ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(element->entry); ctype->setTargetLangPackage(attributes[QLatin1String("package")]); @@ -1174,7 +1187,7 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts break; case StackElement::LoadTypesystem: attributes.insert(nameAttribute(), QString()); - attributes.insert(QLatin1String("generate"), QLatin1String("yes")); + attributes.insert(QLatin1String("generate"), yesAttributeValue()); break; case StackElement::NoNullPointers: attributes.insert(QLatin1String("default-value"), QString()); @@ -1193,28 +1206,28 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts attributes.insert(QLatin1String("signature"), QString()); attributes.insert(QLatin1String("return-type"), QLatin1String("void")); attributes.insert(QLatin1String("access"), QLatin1String("public")); - attributes.insert(QLatin1String("static"), QLatin1String("no")); + attributes.insert(QLatin1String("static"), noAttributeValue()); break; case StackElement::ModifyFunction: attributes.insert(QLatin1String("signature"), QString()); attributes.insert(QLatin1String("access"), QString()); attributes.insert(QLatin1String("remove"), QString()); attributes.insert(QLatin1String("rename"), QString()); - attributes.insert(QLatin1String("deprecated"), QLatin1String("no")); + attributes.insert(QLatin1String("deprecated"), noAttributeValue()); attributes.insert(QLatin1String("associated-to"), QString()); - attributes.insert(QLatin1String("virtual-slot"), QLatin1String("no")); - attributes.insert(QLatin1String("thread"), QLatin1String("no")); - attributes.insert(QLatin1String("allow-thread"), QLatin1String("no")); + attributes.insert(QLatin1String("virtual-slot"), noAttributeValue()); + attributes.insert(QLatin1String("thread"), noAttributeValue()); + attributes.insert(QLatin1String("allow-thread"), noAttributeValue()); break; case StackElement::ModifyArgument: attributes.insert(QLatin1String("index"), QString()); attributes.insert(QLatin1String("replace-value"), QString()); - attributes.insert(QLatin1String("invalidate-after-use"), QLatin1String("no")); + attributes.insert(QLatin1String("invalidate-after-use"), noAttributeValue()); break; case StackElement::ModifyField: attributes.insert(nameAttribute(), QString()); - attributes.insert(QLatin1String("write"), QLatin1String("true")); - attributes.insert(QLatin1String("read"), QLatin1String("true")); + attributes.insert(QLatin1String("write"), trueAttributeValue()); + attributes.insert(QLatin1String("read"), trueAttributeValue()); attributes.insert(QLatin1String("remove"), QString()); break; case StackElement::Access: @@ -1245,7 +1258,7 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts attributes.insert(QLatin1String("file"), QString()); break; case StackElement::TargetToNative: - attributes.insert(QLatin1String("replace"), QLatin1String("yes")); + attributes.insert(QLatin1String("replace"), yesAttributeValue()); break; case StackElement::AddConversion: attributes.insert(QLatin1String("type"), QString()); @@ -1429,7 +1442,7 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts m_error = QLatin1String("Target to Native conversions can only be specified for custom conversion rules."); return false; } - bool replace = attributes[QLatin1String("replace")] == QLatin1String("yes"); + bool replace = attributes[QLatin1String("replace")] == yesAttributeValue(); static_cast<TypeEntry*>(m_current->entry)->customConversion()->setReplaceOriginalTargetToNativeConversions(replace); } break; @@ -1679,8 +1692,8 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts QString read = attributes[QLatin1String("read")]; QString write = attributes[QLatin1String("write")]; - if (read == QLatin1String("true")) fm.modifiers |= FieldModification::Readable; - if (write == QLatin1String("true")) fm.modifiers |= FieldModification::Writable; + if (read == trueAttributeValue()) fm.modifiers |= FieldModification::Readable; + if (write == trueAttributeValue()) fm.modifiers |= FieldModification::Writable; m_contextStack.top()->fieldMods << fm; } @@ -1706,7 +1719,7 @@ bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts } AddedFunction func(signature, attributes[QLatin1String("return-type")], since); - func.setStatic(attributes[QLatin1String("static")] == QLatin1String("yes")); + func.setStatic(attributes[QLatin1String("static")] == yesAttributeValue()); if (!signature.contains(QLatin1Char('('))) signature += QLatin1String("()"); m_currentSignature = signature; @@ -2273,19 +2286,6 @@ QString FlagsTypeEntry::targetLangPackage() const return m_enum->targetLangPackage(); } -void EnumTypeEntry::addEnumValueRedirection(const QString &rejected, const QString &usedValue) -{ - m_enumRedirections << EnumValueRedirection(rejected, usedValue); -} - -QString EnumTypeEntry::enumValueRedirection(const QString &value) const -{ - for (int i = 0; i < m_enumRedirections.size(); ++i) - if (m_enumRedirections.at(i).rejected == value) - return m_enumRedirections.at(i).used; - return QString(); -} - QString FlagsTypeEntry::qualifiedTargetLangName() const { return targetLangPackage() + QLatin1Char('.') + m_enum->targetLangQualifier() diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h index c8a1c88fa..62d348f69 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.h +++ b/sources/shiboken2/ApiExtractor/typesystem.h @@ -1042,21 +1042,15 @@ private: PrimitiveTypeEntry* m_referencedTypeEntry = nullptr; }; -struct EnumValueRedirection -{ - EnumValueRedirection() {} - EnumValueRedirection(const QString &rej, const QString &us) - : rejected(rej), - used(us) - { - } - QString rejected; - QString used; -}; - 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; @@ -1077,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 @@ -1120,7 +1117,7 @@ public: m_extensible = is; } - bool isEnumValueRejected(const QString &name) + bool isEnumValueRejected(const QString &name) const { return m_rejectedEnums.contains(name); } @@ -1133,9 +1130,6 @@ public: return m_rejectedEnums; } - void addEnumValueRedirection(const QString &rejected, const QString &usedValue); - QString enumValueRedirection(const QString &value) const; - bool forceInteger() const { return m_forceInteger; @@ -1145,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; @@ -1163,15 +1150,17 @@ private: QString m_upperBound; QStringList m_rejectedEnums; - QVector<EnumValueRedirection> m_enumRedirections; 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 +// like array<EnumValue>. class EnumValueTypeEntry : public TypeEntry { public: diff --git a/sources/shiboken2/ApiExtractor/typesystem_p.h b/sources/shiboken2/ApiExtractor/typesystem_p.h index fd67ef49b..d3485726e 100644 --- a/sources/shiboken2/ApiExtractor/typesystem_p.h +++ b/sources/shiboken2/ApiExtractor/typesystem_p.h @@ -153,7 +153,6 @@ private: QHash<QString, QString> *acceptedAttributes); bool importFileElement(const QXmlStreamAttributes &atts); - bool convertBoolean(const QString &, const QString &, bool); void addFlags(const QString &name, QString flagName, const QHash<QString, QString> &attributes, double since); diff --git a/sources/shiboken2/CMakeLists.txt b/sources/shiboken2/CMakeLists.txt index 006924ad9..ccabc72e3 100644 --- a/sources/shiboken2/CMakeLists.txt +++ b/sources/shiboken2/CMakeLists.txt @@ -11,12 +11,6 @@ find_package(Qt5 REQUIRED COMPONENTS Core Xml XmlPatterns) add_definitions(${Qt5Core_DEFINITIONS}) -set(shiboken_MAJOR_VERSION "2") -set(shiboken_MINOR_VERSION "0") -set(shiboken_MICRO_VERSION "0") -set(shiboken2_VERSION "${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}.${shiboken_MICRO_VERSION}") -set(shiboken2_library_so_version "${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}") - option(BUILD_TESTS "Build tests." TRUE) option(USE_PYTHON_VERSION "Use specific python version to build shiboken2." "") @@ -126,6 +120,31 @@ message(STATUS "CLANG builtins includes directory chosen: ${CLANG_BUILTIN_INCLUD set(CLANG_EXTRA_INCLUDES ${CLANG_DIR}/include) set(CLANG_EXTRA_LIBRARIES ${CLANG_LIBRARY}) +set(SHIBOKEN_VERSION_FILE_PATH "${CMAKE_SOURCE_DIR}/shiboken_version.py") +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS + ${SHIBOKEN_VERSION_FILE_PATH} +) +execute_process( + COMMAND ${PYTHON_EXECUTABLE} "${SHIBOKEN_VERSION_FILE_PATH}" + OUTPUT_VARIABLE SHIBOKEN_VERSION_OUTPUT + ERROR_VARIABLE SHIBOKEN_VERSION_OUTPUT_ERROR + OUTPUT_STRIP_TRAILING_WHITESPACE) +if (NOT SHIBOKEN_VERSION_OUTPUT) + message(FATAL_ERROR "Could not identify shiboken version. \ + Error: ${SHIBOKEN_VERSION_OUTPUT_ERROR}") +endif() + +list(GET SHIBOKEN_VERSION_OUTPUT 0 shiboken_MAJOR_VERSION) +list(GET SHIBOKEN_VERSION_OUTPUT 1 shiboken_MINOR_VERSION) +list(GET SHIBOKEN_VERSION_OUTPUT 2 shiboken_MICRO_VERSION) +# a - alpha, b - beta, rc - rc +list(GET SHIBOKEN_VERSION_OUTPUT 3 shiboken_PRE_RELEASE_VERSION_TYPE) +# the number of the pre release (alpha1, beta3, rc7, etc.) +list(GET SHIBOKEN_VERSION_OUTPUT 4 shiboken_PRE_RELEASE_VERSION) + +set(shiboken2_VERSION "${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}.${shiboken_MICRO_VERSION}") +set(shiboken2_library_so_version "${shiboken_MAJOR_VERSION}.${shiboken_MINOR_VERSION}") + ## For debugging the PYTHON* variables message("PYTHONLIBS_FOUND: " ${PYTHONLIBS_FOUND}) message("PYTHON_LIBRARIES: " ${PYTHON_LIBRARIES}) @@ -247,6 +266,22 @@ if(CMAKE_HOST_APPLE) endif() endif() +# Build with Address sanitizer enabled if requested. This may break things, so use at your own risk. +if (SANITIZE_ADDRESS AND NOT MSVC) + # Currently this does not check that the clang / gcc version used supports Address sanitizer, + # so once again, use at your own risk. + add_compile_options("-fsanitize=address" "-g" "-fno-omit-frame-pointer") + # We need to add the sanitize address option to all linked executables / shared libraries + # so that proper sanitizer symbols are linked in. + # + # Note that when running tests, you may need to set an additional environment variable + # in set_tests_properties for shiboken2 / pyside tests, or exported in your shell. Address + # sanitizer will tell you what environment variable needs to be exported. For example: + # export DYLD_INSERT_LIBRARIES=/Applications/Xcode.app/Contents/Developer/Toolchains/ + # ./XcodeDefault.xctoolchain/usr/lib/clang/8.1.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib + set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_STANDARD_LIBRARIES} -fsanitize=address") +endif() + add_subdirectory(ApiExtractor) set(generator_plugin_DIR ${LIB_INSTALL_DIR}/generatorrunner${generator_SUFFIX}) @@ -366,16 +401,3 @@ else() endif() add_subdirectory(data) - -# dist target -set(ARCHIVE_NAME ${CMAKE_PROJECT_NAME}-${shiboken2_VERSION}) -add_custom_target(dist - COMMAND mkdir -p "${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}" && - git log > "${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}/ChangeLog" && - git archive --prefix=${ARCHIVE_NAME}/ HEAD --format=tar --output="${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar" && - tar -C "${CMAKE_BINARY_DIR}" --owner=root --group=root -r "${ARCHIVE_NAME}/ChangeLog" -f "${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar" && - bzip2 -f9 "${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar" && - echo "Source package created at ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.bz2." - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - - diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp index fb4de46d2..7cce97ae1 100644 --- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp +++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp @@ -111,9 +111,14 @@ static int writeEscapedRstText(QTextStream &str, const String &s) { int escaped = 0; for (const QChar &c : s) { - if (c == QLatin1Char('*') || c == QLatin1Char('_')) { + switch (c.unicode()) { + case '*': + case '`': + case '_': + case '\\': str << '\\'; ++escaped; + break; } str << c; } @@ -199,7 +204,7 @@ QtXmlToSphinx::QtXmlToSphinx(QtDocGenerator* generator, const QString& doc, cons m_handlerMap.insert(QLatin1String("argument"), &QtXmlToSphinx::handleArgumentTag); m_handlerMap.insert(QLatin1String("teletype"), &QtXmlToSphinx::handleArgumentTag); m_handlerMap.insert(QLatin1String("link"), &QtXmlToSphinx::handleLinkTag); - m_handlerMap.insert(QLatin1String("inlineimage"), &QtXmlToSphinx::handleImageTag); + m_handlerMap.insert(QLatin1String("inlineimage"), &QtXmlToSphinx::handleInlineImageTag); m_handlerMap.insert(QLatin1String("image"), &QtXmlToSphinx::handleImageTag); m_handlerMap.insert(QLatin1String("list"), &QtXmlToSphinx::handleListTag); m_handlerMap.insert(QLatin1String("term"), &QtXmlToSphinx::handleTermTag); @@ -365,6 +370,16 @@ QString QtXmlToSphinx::transform(const QString& doc) m_lastTagName = reader.name().toString(); } } + + if (!m_inlineImages.isEmpty()) { + // Write out inline image definitions stored in handleInlineImageTag(). + m_output << endl; + for (const InlineImage &img : qAsConst(m_inlineImages)) + m_output << ".. |" << img.tag << "| image:: " << img.href << endl; + m_output << endl; + m_inlineImages.clear(); + } + m_output.flush(); QString retval = popOutputBuffer(); Q_ASSERT(m_buffers.isEmpty()); @@ -936,22 +951,46 @@ static bool copyImage(const QString &href, const QString &docDataDir, return true; } +bool QtXmlToSphinx::copyImage(const QString &href) const +{ + QString errorMessage; + const bool result = + ::copyImage(href, m_generator->docDataDir(), m_context, + m_generator->outputDirectory(), &errorMessage); + if (!result) + qCWarning(lcShiboken, "%s", qPrintable(errorMessage)); + return result; +} + void QtXmlToSphinx::handleImageTag(QXmlStreamReader& reader) { - QXmlStreamReader::TokenType token = reader.tokenType(); - if (token == QXmlStreamReader::StartElement) { - QString href = reader.attributes().value(QLatin1String("href")).toString(); - QString errorMessage; - if (!copyImage(href,m_generator->docDataDir(), m_context, - m_generator->outputDirectory(), &errorMessage)) { - qCWarning(lcShiboken, "%s", qPrintable(errorMessage)); - } + if (reader.tokenType() != QXmlStreamReader::StartElement) + return; + const QString href = reader.attributes().value(QLatin1String("href")).toString(); + if (copyImage(href)) + m_output << INDENT << ".. image:: " << href << endl << endl; +} - if (reader.name() == QLatin1String("image")) - m_output << INDENT << ".. image:: " << href << endl << endl; - else - m_output << ".. image:: " << href << ' '; - } +void QtXmlToSphinx::handleInlineImageTag(QXmlStreamReader& reader) +{ + if (reader.tokenType() != QXmlStreamReader::StartElement) + return; + const QString href = reader.attributes().value(QLatin1String("href")).toString(); + if (!copyImage(href)) + return; + // Handle inline images by substitution references. Insert a unique tag + // enclosed by '|' and define it further down. Determine tag from the base + //file name with number. + QString tag = href; + int pos = tag.lastIndexOf(QLatin1Char('/')); + if (pos != -1) + tag.remove(0, pos + 1); + pos = tag.indexOf(QLatin1Char('.')); + if (pos != -1) + tag.truncate(pos); + tag += QString::number(m_inlineImages.size() + 1); + m_inlineImages.append(InlineImage{tag, href}); + m_output << '|' << tag << '|' << ' '; } void QtXmlToSphinx::handleRawTag(QXmlStreamReader& reader) @@ -1323,7 +1362,7 @@ void QtDocGenerator::generateClass(QTextStream &s, GeneratorContext &classContex s << className << endl; s << Pad('*', className.count()) << endl << endl; - s << ".. inheritance-diagram:: " << className << endl + s << ".. inheritance-diagram:: " << getClassTargetFullName(metaClass, true) << endl << " :parts: 2" << endl << endl; // TODO: This would be a parameter in the future... diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.h b/sources/shiboken2/generator/qtdoc/qtdocgenerator.h index 1977f3019..af26b7fab 100644 --- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.h +++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.h @@ -49,6 +49,12 @@ class QtDocGenerator; class QtXmlToSphinx { public: + struct InlineImage + { + QString tag; + QString href; + }; + struct TableCell { short rowSpan; @@ -127,6 +133,7 @@ private: void handleDotsTag(QXmlStreamReader& reader); void handleLinkTag(QXmlStreamReader& reader); void handleImageTag(QXmlStreamReader& reader); + void handleInlineImageTag(QXmlStreamReader& reader); void handleListTag(QXmlStreamReader& reader); void handleTermTag(QXmlStreamReader& reader); void handleSuperScriptTag(QXmlStreamReader& reader); @@ -168,6 +175,7 @@ private: bool m_insideItalic; QString m_lastTagName; QString m_opened_anchor; + QVector<InlineImage> m_inlineImages; QString readFromLocations(const QStringList &locations, const QString &path, const QString &identifier, QString *errorMessage); @@ -176,6 +184,7 @@ private: void pushOutputBuffer(); QString popOutputBuffer(); void writeTable(Table& table); + bool copyImage(const QString &href) const; }; inline QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx& xmlToSphinx) 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/shiboken_version.py b/sources/shiboken2/shiboken_version.py new file mode 100644 index 000000000..3a678cd14 --- /dev/null +++ b/sources/shiboken2/shiboken_version.py @@ -0,0 +1,49 @@ +############################################################################# +## +## Copyright (C) 2018 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of PySide2. +## +## $QT_BEGIN_LICENSE:LGPL$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 3 as published by the Free Software +## Foundation and appearing in the file LICENSE.LGPL3 included in the +## packaging of this file. Please review the following information to +## ensure the GNU Lesser General Public License version 3 requirements +## will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +## +## GNU General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 2.0 or (at your option) the GNU General +## Public license version 3 or any later version approved by the KDE Free +## Qt Foundation. The licenses are as published by the Free Software +## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +## included in the packaging of this file. Please review the following +## information to ensure the GNU General Public License requirements will +## be met: https://www.gnu.org/licenses/gpl-2.0.html and +## https://www.gnu.org/licenses/gpl-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +major_version = "5" +minor_version = "11" +patch_version = "0" +pre_release_version_type = "a" # e.g. "a", "b", "rc". +pre_release_version = "1" # e.g "1", "2", (which means "beta1", "beta2", if type is "b") + +if __name__ == '__main__': + # Used by CMake. + print('{0};{1};{2};{3};{4}'.format(major_version, minor_version, patch_version, + pre_release_version_type, pre_release_version)) 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"> |