diff options
Diffstat (limited to 'sources')
19 files changed, 220 insertions, 25 deletions
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp index 19a4c7849..b07ea0f0e 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp @@ -1861,12 +1861,8 @@ const AbstractMetaFunction *AbstractMetaField::setter() const const AbstractMetaClass *EnclosingClassMixin::targetLangEnclosingClass() const { auto result = m_enclosingClass; - while (result) { - auto typeEntry = result->typeEntry(); - if (typeEntry->codeGeneration() != TypeEntry::GenerateForSubclass) - break; + while (result && !NamespaceTypeEntry::isVisibleScope(result->typeEntry())) result = result->enclosingClass(); - } return result; } diff --git a/sources/shiboken2/ApiExtractor/typedatabase.cpp b/sources/shiboken2/ApiExtractor/typedatabase.cpp index 014f4dadc..8d489c65e 100644 --- a/sources/shiboken2/ApiExtractor/typedatabase.cpp +++ b/sources/shiboken2/ApiExtractor/typedatabase.cpp @@ -848,6 +848,7 @@ void NamespaceTypeEntry::formatDebug(QDebug &d) const ComplexTypeEntry::formatDebug(d); auto pattern = m_filePattern.pattern(); FORMAT_NONEMPTY_STRING("pattern", pattern) + d << ",visibility=" << m_visibility; } void ContainerTypeEntry::formatDebug(QDebug &d) const diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp index abd2bfb07..02c553a3b 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.cpp +++ b/sources/shiboken2/ApiExtractor/typesystem.cpp @@ -704,11 +704,13 @@ QString TypeEntry::buildTargetLangName() const { QString result = m_entryName; for (auto p = parent(); p && p->type() != TypeEntry::TypeSystemType; p = p->parent()) { - if (!result.isEmpty()) - result.prepend(QLatin1Char('.')); - QString n = p->m_entryName; - n.replace(QLatin1String("::"), QLatin1String(".")); // Primitive types may have "std::" - result.prepend(n); + if (NamespaceTypeEntry::isVisibleScope(p)) { + if (!result.isEmpty()) + result.prepend(QLatin1Char('.')); + QString n = p->m_entryName; + n.replace(QLatin1String("::"), QLatin1String(".")); // Primitive types may have "std::" + result.prepend(n); + } } return result; } @@ -959,6 +961,18 @@ bool NamespaceTypeEntry::matchesFile(const QString &needle) const return m_filePattern.match(needle).hasMatch(); } +bool NamespaceTypeEntry::isVisible() const +{ + return m_visibility == TypeSystem::Visibility::Visible + || m_visibility == TypeSystem::Visibility::Auto; +} + +bool NamespaceTypeEntry::isVisibleScope(const TypeEntry *e) +{ + return e->type() != TypeEntry::NamespaceType + || static_cast<const NamespaceTypeEntry *>(e)->isVisible(); +} + ValueTypeEntry::ValueTypeEntry(const QString &entryName, const QVersionNumber &vr, const TypeEntry *parent) : ComplexTypeEntry(entryName, BasicValueType, vr, parent) diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h index 4d0a23ca1..89618d5be 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.h +++ b/sources/shiboken2/ApiExtractor/typesystem.h @@ -1535,6 +1535,11 @@ public: bool matchesFile(const QString &needle) const; + bool isVisible() const; + void setVisibility(TypeSystem::Visibility v) { m_visibility = v; } + + static bool isVisibleScope(const TypeEntry *e); + #ifndef QT_NO_DEBUG_STREAM void formatDebug(QDebug &d) const override; #endif @@ -1545,6 +1550,7 @@ protected: private: QRegularExpression m_filePattern; const NamespaceTypeEntry *m_extends = nullptr; + TypeSystem::Visibility m_visibility = TypeSystem::Visibility::Auto; bool m_hasPattern = false; }; diff --git a/sources/shiboken2/ApiExtractor/typesystem_enums.h b/sources/shiboken2/ApiExtractor/typesystem_enums.h index df83429d0..120c9417f 100644 --- a/sources/shiboken2/ApiExtractor/typesystem_enums.h +++ b/sources/shiboken2/ApiExtractor/typesystem_enums.h @@ -98,6 +98,13 @@ enum class ExceptionHandling { On }; +enum Visibility { // For namespaces + Unspecified, + Visible, + Invisible, + Auto +}; + } // namespace TypeSystem #endif // TYPESYSTEM_ENUMS_H diff --git a/sources/shiboken2/ApiExtractor/typesystemparser.cpp b/sources/shiboken2/ApiExtractor/typesystemparser.cpp index 7388b07fc..77c36df9a 100644 --- a/sources/shiboken2/ApiExtractor/typesystemparser.cpp +++ b/sources/shiboken2/ApiExtractor/typesystemparser.cpp @@ -93,6 +93,7 @@ static inline QString sourceAttribute() { return QStringLiteral("source"); } static inline QString streamAttribute() { return QStringLiteral("stream"); } static inline QString xPathAttribute() { return QStringLiteral("xpath"); } static inline QString virtualSlotAttribute() { return QStringLiteral("virtual-slot"); } +static inline QString visibleAttribute() { return QStringLiteral("visible"); } static inline QString enumIdentifiedByValueAttribute() { return QStringLiteral("identified-by-value"); } static inline QString noAttributeValue() { return QStringLiteral("no"); } @@ -389,6 +390,17 @@ ENUM_LOOKUP_BEGIN(StackElement::ElementType, Qt::CaseInsensitive, }; ENUM_LOOKUP_BINARY_SEARCH() +ENUM_LOOKUP_BEGIN(TypeSystem::Visibility, Qt::CaseSensitive, + visibilityFromAttribute, TypeSystem::Visibility::Unspecified) +{ + {u"no", TypeSystem::Visibility::Invisible}, + {u"false", TypeSystem::Visibility::Invisible}, + {u"auto", TypeSystem::Visibility::Auto}, + {u"yes", TypeSystem::Visibility::Visible}, + {u"true", TypeSystem::Visibility::Visible}, +}; +ENUM_LOOKUP_LINEAR_SEARCH() + static int indexOfAttribute(const QXmlStreamAttributes &atts, QStringView name) { @@ -1304,8 +1316,8 @@ NamespaceTypeEntry * if (!checkRootElement()) return nullptr; QScopedPointer<NamespaceTypeEntry> result(new NamespaceTypeEntry(name, since, currentParentTypeEntry())); + auto visibility = TypeSystem::Visibility::Unspecified; applyCommonAttributes(result.data(), attributes); - applyComplexTypeAttributes(reader, result.data(), attributes); for (int i = attributes->size() - 1; i >= 0; --i) { const QStringRef attributeName = attributes->at(i).qualifiedName(); if (attributeName == QLatin1String("files")) { @@ -1328,9 +1340,24 @@ NamespaceTypeEntry * return nullptr; } result->setExtends(*extendsIt); + } else if (attributeName == visibleAttribute()) { + const auto attribute = attributes->takeAt(i); + visibility = visibilityFromAttribute(attribute.value()); + if (visibility == TypeSystem::Visibility::Unspecified) { + qCWarning(lcShiboken, "%s", + qPrintable(msgInvalidAttributeValue(attribute))); + } + } else if (attributeName == generateAttribute()) { + if (!convertBoolean(attributes->takeAt(i).value(), generateAttribute(), true)) + visibility = TypeSystem::Visibility::Invisible; } } + if (visibility != TypeSystem::Visibility::Unspecified) + result->setVisibility(visibility); + // Handle legacy "generate" before the common handling + applyComplexTypeAttributes(reader, result.data(), attributes); + if (result->extends() && !result->hasPattern()) { m_error = msgExtendingNamespaceRequiresPattern(name); return nullptr; diff --git a/sources/shiboken2/doc/typesystem_specifying_types.rst b/sources/shiboken2/doc/typesystem_specifying_types.rst index ac1121461..2eb78335a 100644 --- a/sources/shiboken2/doc/typesystem_specifying_types.rst +++ b/sources/shiboken2/doc/typesystem_specifying_types.rst @@ -148,6 +148,7 @@ namespace-type <typesystem> <namespace-type name="..." + visible="true | auto | false" generate="yes | no" package="..." since="..." @@ -156,8 +157,16 @@ namespace-type The **name** attribute is the name of the namespace, e.g., "Qt". - The *optional* **generate** attribute is used to inform if you need to prepend - the given namespace into each generated class. Its default value is **yes**. + The *optional* **visible** attribute is used specify whether the + namespace is visible in the target language name. Its default value is + **auto**. It means that normal namespaces are visible, but inline namespaces + (as introduced in C++ 11) will not be visible. + + The detection of inline namespaces requires shiboken to be built + using LLVM 9.0. + + The *optional* **generate** is a legacy attribute. Specifying + **no** is equivalent to **visible="false"**. The **package** attribute can be used to override the package of the type system. diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp index 484b1f641..2c480eba8 100644 --- a/sources/shiboken2/generator/generator.cpp +++ b/sources/shiboken2/generator/generator.cpp @@ -449,7 +449,8 @@ bool Generator::generate() bool Generator::shouldGenerateTypeEntry(const TypeEntry *type) const { - return type->codeGeneration() & TypeEntry::GenerateTargetLang; + return (type->codeGeneration() & TypeEntry::GenerateTargetLang) + && NamespaceTypeEntry::isVisibleScope(type); } bool Generator::shouldGenerate(const AbstractMetaClass *metaClass) const @@ -893,8 +894,12 @@ static QString getClassTargetFullName_(const T *t, bool includePackageName) QString name = t->name(); const AbstractMetaClass *context = t->enclosingClass(); while (context) { - name.prepend(QLatin1Char('.')); - name.prepend(context->name()); + // If the type was marked as 'visible=false' we should not use it in + // the type name + if (NamespaceTypeEntry::isVisibleScope(context->typeEntry())) { + name.prepend(QLatin1Char('.')); + name.prepend(context->name()); + } context = context->enclosingClass(); } if (includePackageName) { diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index 6d41a7c4d..589e1ef94 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -5511,9 +5511,8 @@ bool CppGenerator::finishGeneration() const AbstractMetaClassList &classList = classes(); for (const AbstractMetaClass *metaClass : classList) { const AbstractMetaClass *encClass = metaClass->enclosingClass(); - if (encClass && encClass->typeEntry()->codeGeneration() != TypeEntry::GenerateForSubclass) - continue; - lookForEnumsInClassesNotToBeGenerated(globalEnums, metaClass); + if (!encClass || !NamespaceTypeEntry::isVisibleScope(encClass->typeEntry())) + lookForEnumsInClassesNotToBeGenerated(globalEnums, metaClass); } TypeDatabase *typeDb = TypeDatabase::instance(); diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.cpp b/sources/shiboken2/generator/shiboken2/headergenerator.cpp index e47c37523..ca6ac4068 100644 --- a/sources/shiboken2/generator/shiboken2/headergenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/headergenerator.cpp @@ -326,7 +326,8 @@ void HeaderGenerator::writeTypeIndexValueLine(QTextStream &s, const TypeEntry *t void HeaderGenerator::writeTypeIndexValueLines(QTextStream &s, const AbstractMetaClass *metaClass) { - if (!metaClass->typeEntry()->generateCode()) + auto typeEntry = metaClass->typeEntry(); + if (!typeEntry->generateCode() || !NamespaceTypeEntry::isVisibleScope(typeEntry)) return; writeTypeIndexValueLine(s, metaClass->typeEntry()); const AbstractMetaEnumList &enums = metaClass->enums(); diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp index 07c031d9b..b9a7d087d 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -326,7 +326,7 @@ void ShibokenGenerator::lookForEnumsInClassesNotToBeGenerated(AbstractMetaEnumLi { Q_ASSERT(metaClass); // if a scope is not to be generated, collect its enums into the parent scope - if (metaClass->typeEntry()->codeGeneration() == TypeEntry::GenerateForSubclass) { + if (!NamespaceTypeEntry::isVisibleScope(metaClass->typeEntry())) { const AbstractMetaEnumList &enums = metaClass->enums(); for (AbstractMetaEnum *metaEnum : enums) { if (!metaEnum->isPrivate() && metaEnum->typeEntry()->generateCode() @@ -360,7 +360,8 @@ QString ShibokenGenerator::fullPythonClassName(const AbstractMetaClass *metaClas QString fullClassName = metaClass->name(); const AbstractMetaClass *enclosing = metaClass->enclosingClass(); while (enclosing) { - fullClassName.prepend(enclosing->name() + QLatin1Char('.')); + if (NamespaceTypeEntry::isVisibleScope(enclosing->typeEntry())) + fullClassName.prepend(enclosing->name() + QLatin1Char('.')); enclosing = enclosing->enclosingClass(); } fullClassName.prepend(packageName() + QLatin1Char('.')); diff --git a/sources/shiboken2/tests/helper.py b/sources/shiboken2/tests/helper.py new file mode 100644 index 000000000..2564c91d4 --- /dev/null +++ b/sources/shiboken2/tests/helper.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2019 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of Qt for Python. +## +## $QT_BEGIN_LICENSE:GPL-EXCEPT$ +## 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 General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3 as published by the Free Software +## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +## 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-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + + +def objectFullname(t): + module = t.__module__ + if module is None or module == str.__class__.__module__: + return t.__name__ + else: + return module + '.' + t.__name__ diff --git a/sources/shiboken2/tests/libother/otherobjecttype.cpp b/sources/shiboken2/tests/libother/otherobjecttype.cpp index ca356ce94..1f782ecd8 100644 --- a/sources/shiboken2/tests/libother/otherobjecttype.cpp +++ b/sources/shiboken2/tests/libother/otherobjecttype.cpp @@ -34,3 +34,13 @@ operator<<(Collector& collector, const OtherObjectType& obj) collector << obj.identifier()*2; return collector; } + +int OtherObjectType::enumAsInt(SampleNamespace::SomeClass::PublicScopedEnum value) +{ + return static_cast<int>(value); +} + +int OtherObjectType::enumAsIntForInvisibleNamespace(Invisible::EnumOnNamespace value) +{ + return static_cast<int>(value); +} diff --git a/sources/shiboken2/tests/libother/otherobjecttype.h b/sources/shiboken2/tests/libother/otherobjecttype.h index 22687c8bd..efd394347 100644 --- a/sources/shiboken2/tests/libother/otherobjecttype.h +++ b/sources/shiboken2/tests/libother/otherobjecttype.h @@ -35,11 +35,14 @@ #include "libothermacros.h" #include "objecttype.h" #include "collector.h" +#include "samplenamespace.h" -class OtherObjectType : public ObjectType + +class LIBOTHER_API OtherObjectType : public ObjectType { public: - + static int enumAsInt(SampleNamespace::SomeClass::PublicScopedEnum value); + static int enumAsIntForInvisibleNamespace(Invisible::EnumOnNamespace value); }; diff --git a/sources/shiboken2/tests/libsample/samplenamespace.h b/sources/shiboken2/tests/libsample/samplenamespace.h index 6868b5f0a..9e46b2ad6 100644 --- a/sources/shiboken2/tests/libsample/samplenamespace.h +++ b/sources/shiboken2/tests/libsample/samplenamespace.h @@ -51,6 +51,13 @@ enum EnumOnNamespace { Option3 = 3 }; +struct ObjectOnInvisibleNamespace +{ + bool exists() const { return true; } + static int toInt(EnumOnNamespace e) { return static_cast<int>(e); } + static ObjectOnInvisibleNamespace consume(const ObjectOnInvisibleNamespace &other) { return other; } +}; + }; namespace SampleNamespace @@ -137,6 +144,8 @@ protected: PublicScopedEnum protectedMethodReturningPublicScopedEnum() const; }; +LIBSAMPLE_API inline int enumAsInt(SomeClass::PublicScopedEnum value) { return static_cast<int>(value); } + class DerivedFromNamespace : public SomeClass::SomeInnerClass::OkThisIsRecursiveEnough { public: diff --git a/sources/shiboken2/tests/otherbinding/signature_test.py b/sources/shiboken2/tests/otherbinding/signature_test.py new file mode 100644 index 000000000..e9fcff860 --- /dev/null +++ b/sources/shiboken2/tests/otherbinding/signature_test.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +############################################################################# +## +## Copyright (C) 2019 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the test suite of Qt for Python. +## +## $QT_BEGIN_LICENSE:GPL-EXCEPT$ +## 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 General Public License Usage +## Alternatively, this file may be used under the terms of the GNU +## General Public License version 3 as published by the Free Software +## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +## 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-3.0.html. +## +## $QT_END_LICENSE$ +## +############################################################################# + +'''Test cases for functions signature''' + +import unittest + +from other import OtherObjectType +from helper import objectFullname + +class SignatureTest(unittest.TestCase): + + # Check if the argument of 'OtherObjectType::enumAsInt(SampleNamespace::SomeClass::PublicScopedEnum value)' + # has the correct representation + def testNamespaceFromOtherModule(self): + argType = OtherObjectType.enumAsInt.__signature__.parameters['value'].annotation + self.assertEqual(objectFullname(argType), 'sample.SampleNamespace.SomeClass.PublicScopedEnum') + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/CMakeLists.txt b/sources/shiboken2/tests/samplebinding/CMakeLists.txt index a5df86246..b65068dc3 100644 --- a/sources/shiboken2/tests/samplebinding/CMakeLists.txt +++ b/sources/shiboken2/tests/samplebinding/CMakeLists.txt @@ -125,6 +125,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/filter_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/data_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/intersection_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/sample/union_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/invisible_objectoninvisiblenamespace_wrapper.cpp ) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sample-binding.txt.in" diff --git a/sources/shiboken2/tests/samplebinding/namespace_test.py b/sources/shiboken2/tests/samplebinding/namespace_test.py index 5fcdab974..67f0974a7 100644 --- a/sources/shiboken2/tests/samplebinding/namespace_test.py +++ b/sources/shiboken2/tests/samplebinding/namespace_test.py @@ -33,12 +33,17 @@ import unittest from sample import * +from helper import objectFullname class TestEnumUnderNamespace(unittest.TestCase): def testInvisibleNamespace(self): o1 = EnumOnNamespace.Option1 self.assertEqual(o1, 1) + def testTpNames(self): + self.assertEqual(objectFullname(EnumOnNamespace), "sample.EnumOnNamespace") + self.assertEqual(str(EnumOnNamespace.Option1), + "sample.EnumOnNamespace.Option1") class TestClassesUnderNamespace(unittest.TestCase): def testIt(self): @@ -65,5 +70,19 @@ class TestClassesUnderNamespace(unittest.TestCase): self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum), "<class 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum'>") + # Test if enum inside of class is correct represented + self.assertEqual(objectFullname(SampleNamespace.enumInEnumOut.__signature__.parameters['in_'].annotation), + "sample.SampleNamespace.InValue") + self.assertEqual(objectFullname(SampleNamespace.enumAsInt.__signature__.parameters['value'].annotation), + "sample.SampleNamespace.SomeClass.PublicScopedEnum") + self.assertEqual(objectFullname(ObjectOnInvisibleNamespace.toInt.__signature__.parameters['e'].annotation), + "sample.EnumOnNamespace") + + # Test if enum on namespace that was marked as not gerenated does not appear on type name + self.assertEqual(objectFullname(ObjectOnInvisibleNamespace), + "sample.ObjectOnInvisibleNamespace") + self.assertEqual(objectFullname(ObjectOnInvisibleNamespace.consume.__signature__.parameters['other'].annotation), + "sample.ObjectOnInvisibleNamespace") + if __name__ == '__main__': unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml index e8b0c9d71..c3db91324 100644 --- a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml +++ b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml @@ -543,8 +543,9 @@ <enum-type identified-by-value="AnonymousGlobalEnum_Value0"/> - <namespace-type name="Invisible" generate="no"> + <namespace-type name="Invisible" visible="no"> <enum-type name="EnumOnNamespace" /> + <value-type name="ObjectOnInvisibleNamespace" /> </namespace-type> <namespace-type name="SampleNamespace"> |