diff options
Diffstat (limited to 'sources/shiboken2')
43 files changed, 1303 insertions, 615 deletions
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index 84721968d..ae3cdd86b 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -1607,8 +1607,13 @@ void AbstractMetaBuilderPrivate::traverseEnums(const ScopeModelItem &scopeItem, const QStringList &enumsDeclarations) { const EnumList &enums = scopeItem->enums(); +#if QT_VERSION >= 0x050E00 + const QSet<QString> enumsDeclarationSet(enumsDeclarations.cbegin(), enumsDeclarations.cend()); +#else + const QSet<QString> enumsDeclarationSet = QSet<QString>::fromList(enumsDeclarations); +#endif for (const EnumModelItem &enumItem : enums) { - AbstractMetaEnum* metaEnum = traverseEnum(enumItem, metaClass, QSet<QString>::fromList(enumsDeclarations)); + AbstractMetaEnum* metaEnum = traverseEnum(enumItem, metaClass, enumsDeclarationSet); if (metaEnum) { metaClass->addEnum(metaEnum); metaEnum->setEnclosingClass(metaClass); @@ -1616,6 +1621,26 @@ void AbstractMetaBuilderPrivate::traverseEnums(const ScopeModelItem &scopeItem, } } +static void applyDefaultExpressionModifications(const FunctionModificationList &functionMods, + int i, AbstractMetaArgument *metaArg) +{ + // use replace/remove-default-expression for set default value + for (const auto &modification : functionMods) { + for (const auto &argumentModification : modification.argument_mods) { + if (argumentModification.index == i + 1) { + if (argumentModification.removedDefaultExpression) { + metaArg->setDefaultValueExpression(QString()); + break; + } + if (!argumentModification.replacedDefaultExpression.isEmpty()) { + metaArg->setDefaultValueExpression(argumentModification.replacedDefaultExpression); + break; + } + } + } + } +} + AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFunctionPtr &addedFunc) { return traverseFunction(addedFunc, nullptr); @@ -1674,20 +1699,13 @@ AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFu // Find the correct default values + const FunctionModificationList functionMods = metaFunction->modifications(metaClass); for (int i = 0; i < metaArguments.size(); ++i) { AbstractMetaArgument* metaArg = metaArguments.at(i); - //use relace-default-expression for set default value - QString replacedExpression; - if (metaClass) - replacedExpression = metaFunction->replacedDefaultExpression(metaClass, i + 1); - - if (!replacedExpression.isEmpty()) { - if (!metaFunction->removedDefaultExpression(metaClass, i + 1)) { - metaArg->setDefaultValueExpression(replacedExpression); - metaArg->setOriginalDefaultValueExpression(replacedExpression); - } - } + // use replace-default-expression for set default value + applyDefaultExpressionModifications(functionMods, i, metaArg); + metaArg->setOriginalDefaultValueExpression(metaArg->defaultValueExpression()); // appear unmodified } metaFunction->setOriginalAttributes(metaFunction->attributes()); @@ -1919,7 +1937,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio AbstractMetaType *type = nullptr; if (!returnType.isVoid()) { - type = translateType(returnType, currentClass, true, &errorMessage); + type = translateType(returnType, currentClass, {}, &errorMessage); if (!type) { const QString reason = msgUnmatchedReturnType(functionItem, errorMessage); qCWarning(lcShiboken, "%s", @@ -1955,7 +1973,7 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio return nullptr; } - AbstractMetaType *metaType = translateType(arg->type(), currentClass, true, &errorMessage); + AbstractMetaType *metaType = translateType(arg->type(), currentClass, {}, &errorMessage); if (!metaType) { // If an invalid argument has a default value, simply remove it if (arg->defaultValue()) { @@ -2006,35 +2024,16 @@ AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(const Functio const ArgumentModelItem &arg = arguments.at(i); AbstractMetaArgument* metaArg = metaArguments.at(i); - //use relace-default-expression for set default value - QString replacedExpression; - if (currentClass) { - replacedExpression = metaFunction->replacedDefaultExpression(currentClass, i + 1); - } else { - if (!functionMods.isEmpty()) { - QVector<ArgumentModification> argMods = functionMods.constFirst().argument_mods; - if (!argMods.isEmpty()) - replacedExpression = argMods.constFirst().replacedDefaultExpression; - } - } + const QString originalDefaultExpression = + fixDefaultValue(arg, metaArg->type(), metaFunction, currentClass, i); - bool hasDefaultValue = false; - if (arg->defaultValue() || !replacedExpression.isEmpty()) { - QString expr = arg->defaultValueExpression(); - expr = fixDefaultValue(arg, metaArg->type(), metaFunction, currentClass, i); - metaArg->setOriginalDefaultValueExpression(expr); + metaArg->setOriginalDefaultValueExpression(originalDefaultExpression); + metaArg->setDefaultValueExpression(originalDefaultExpression); - if (metaFunction->removedDefaultExpression(currentClass, i + 1)) { - expr.clear(); - } else if (!replacedExpression.isEmpty()) { - expr = replacedExpression; - } - metaArg->setDefaultValueExpression(expr); - hasDefaultValue = !expr.isEmpty(); - } + applyDefaultExpressionModifications(functionMods, i, metaArg); //Check for missing argument name - if (hasDefaultValue + if (!metaArg->defaultValueExpression().isEmpty() && !metaArg->hasName() && !metaFunction->isOperatorOverload() && !metaFunction->isSignal() @@ -2159,22 +2158,27 @@ static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaC AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typei, AbstractMetaClass *currentClass, - bool resolveType, + TranslateTypeFlags flags, QString *errorMessage) { - return translateTypeStatic(_typei, currentClass, this, resolveType, errorMessage); + return translateTypeStatic(_typei, currentClass, this, flags, errorMessage); } AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo &_typei, AbstractMetaClass *currentClass, AbstractMetaBuilderPrivate *d, - bool resolveType, + TranslateTypeFlags flags, QString *errorMessageIn) { // 1. Test the type info without resolving typedefs in case this is present in the // type system + const bool resolveType = !flags.testFlag(AbstractMetaBuilder::DontResolveType); if (resolveType) { - if (AbstractMetaType *resolved = translateTypeStatic(_typei, currentClass, d, false, errorMessageIn)) + AbstractMetaType *resolved = + translateTypeStatic(_typei, currentClass, d, + flags | AbstractMetaBuilder::DontResolveType, + errorMessageIn); + if (resolved) return resolved; } @@ -2233,7 +2237,7 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo newInfo.setReferenceType(typeInfo.referenceType()); newInfo.setVolatile(typeInfo.isVolatile()); - AbstractMetaType *elementType = translateTypeStatic(newInfo, currentClass, d, true, &errorMessage); + AbstractMetaType *elementType = translateTypeStatic(newInfo, currentClass, d, flags, &errorMessage); if (!elementType) { if (errorMessageIn) { errorMessage.prepend(QLatin1String("Unable to translate array element: ")); @@ -2344,7 +2348,7 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo const auto &templateArguments = typeInfo.instantiations(); for (int t = 0, size = templateArguments.size(); t < size; ++t) { const TypeInfo &ti = templateArguments.at(t); - AbstractMetaType *targType = translateTypeStatic(ti, currentClass, d, true, &errorMessage); + AbstractMetaType *targType = translateTypeStatic(ti, currentClass, d, flags, &errorMessage); if (!targType) { if (errorMessageIn) *errorMessageIn = msgCannotTranslateTemplateArgument(t, ti, errorMessage); @@ -2366,17 +2370,17 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo AbstractMetaType *AbstractMetaBuilder::translateType(const TypeInfo &_typei, AbstractMetaClass *currentClass, - bool resolveType, + TranslateTypeFlags flags, QString *errorMessage) { return AbstractMetaBuilderPrivate::translateTypeStatic(_typei, currentClass, - nullptr, resolveType, + nullptr, flags, errorMessage); } AbstractMetaType *AbstractMetaBuilder::translateType(const QString &t, AbstractMetaClass *currentClass, - bool resolveType, + TranslateTypeFlags flags, QString *errorMessageIn) { QString errorMessage; @@ -2389,7 +2393,7 @@ AbstractMetaType *AbstractMetaBuilder::translateType(const QString &t, qCWarning(lcShiboken, "%s", qPrintable(errorMessage)); return nullptr; } - return translateType(typeInfo, currentClass, resolveType, errorMessageIn); + return translateType(typeInfo, currentClass, flags, errorMessageIn); } qint64 AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringValue, bool &ok) @@ -2435,10 +2439,10 @@ QString AbstractMetaBuilderPrivate::fixDefaultValue(const ArgumentModelItem &ite AbstractMetaClass *implementingClass, int /* argumentIndex */) { - QString functionName = fnc->name(); - QString className = implementingClass ? implementingClass->qualifiedCppName() : QString(); - QString expr = item->defaultValueExpression(); + if (expr.isEmpty()) + return expr; + if (type) { if (type->isPrimitive()) { if (type->name() == QLatin1String("boolean")) { @@ -2512,11 +2516,12 @@ QString AbstractMetaBuilderPrivate::fixDefaultValue(const ArgumentModelItem &ite } } } else { + const QString className = implementingClass ? implementingClass->qualifiedCppName() : QString(); qCWarning(lcShiboken).noquote().nospace() << QStringLiteral("undefined type for default value '%3' of argument in function '%1', class '%2'") - .arg(functionName, className, item->defaultValueExpression()); + .arg(fnc->name(), className, item->defaultValueExpression()); - expr = QString(); + expr.clear(); } return expr; diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h index 1789ca2aa..93b9d9fd2 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h @@ -90,13 +90,18 @@ public: void setSkipDeprecated(bool value); + enum TranslateTypeFlag { + DontResolveType = 0x1 + }; + Q_DECLARE_FLAGS(TranslateTypeFlags, TranslateTypeFlag); + static AbstractMetaType *translateType(const TypeInfo &_typei, AbstractMetaClass *currentClass = nullptr, - bool resolveType = true, + TranslateTypeFlags flags = {}, QString *errorMessage = nullptr); static AbstractMetaType *translateType(const QString &t, AbstractMetaClass *currentClass = nullptr, - bool resolveType = true, + TranslateTypeFlags flags = {}, QString *errorMessage = nullptr); @@ -109,6 +114,8 @@ private: AbstractMetaBuilderPrivate *d; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaBuilder::TranslateTypeFlags); + #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const AbstractMetaBuilder &ab); #endif diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h index 18c5afc17..30df236d6 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h @@ -43,6 +43,8 @@ class TypeDatabase; class AbstractMetaBuilderPrivate { public: + using TranslateTypeFlags = AbstractMetaBuilder::TranslateTypeFlags; + Q_DISABLE_COPY(AbstractMetaBuilderPrivate) AbstractMetaBuilderPrivate(); @@ -136,12 +138,12 @@ public: AbstractMetaType *translateType(const AddedFunction::TypeInfo &typeInfo); AbstractMetaType *translateType(const TypeInfo &type, AbstractMetaClass *currentClass, - bool resolveType = true, + TranslateTypeFlags flags = {}, QString *errorMessage = nullptr); static AbstractMetaType *translateTypeStatic(const TypeInfo &type, AbstractMetaClass *current, AbstractMetaBuilderPrivate *d = nullptr, - bool resolveType = true, + TranslateTypeFlags flags = {}, QString *errorMessageIn = nullptr); qint64 findOutValueFromString(const QString &stringValue, bool &ok); diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp index 455140e59..99e9d01a3 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt for Python. @@ -268,6 +268,15 @@ QString AbstractMetaType::cppSignature() const return m_cachedCppSignature; } +QString AbstractMetaType::pythonSignature() const +{ + // PYSIDE-921: Handle container returntypes correctly. + // This is now a clean reimplementation. + if (m_cachedPythonSignature.isEmpty()) + m_cachedPythonSignature = formatPythonSignature(false); + return m_cachedPythonSignature; +} + AbstractMetaType::TypeUsagePattern AbstractMetaType::determineUsagePattern() const { if (m_typeEntry->isTemplateArgument() || m_referenceType == RValueReference) @@ -722,37 +731,6 @@ ArgumentOwner AbstractMetaFunction::argumentOwner(const AbstractMetaClass *cls, return ArgumentOwner(); } - -QString AbstractMetaFunction::replacedDefaultExpression(const AbstractMetaClass *cls, int key) const -{ - const FunctionModificationList &modifications = this->modifications(cls); - for (const FunctionModification &modification : modifications) { - for (const ArgumentModification &argumentModification : modification.argument_mods) { - if (argumentModification.index == key - && !argumentModification.replacedDefaultExpression.isEmpty()) { - return argumentModification.replacedDefaultExpression; - } - } - } - - return QString(); -} - -bool AbstractMetaFunction::removedDefaultExpression(const AbstractMetaClass *cls, int key) const -{ - const FunctionModificationList &modifications = this->modifications(cls); - for (const FunctionModification &modification : modifications) { - for (const ArgumentModification &argumentModification : modification.argument_mods) { - if (argumentModification.index == key - && argumentModification.removedDefaultExpression) { - return true; - } - } - } - - return false; -} - QString AbstractMetaFunction::conversionRule(TypeSystem::Language language, int key) const { const FunctionModificationList &modifications = this->modifications(declaringClass()); @@ -771,19 +749,6 @@ QString AbstractMetaFunction::conversionRule(TypeSystem::Language language, int return QString(); } -QString AbstractMetaFunction::argumentReplaced(int key) const -{ - const FunctionModificationList &modifications = this->modifications(declaringClass()); - for (const FunctionModification &modification : modifications) { - for (const ArgumentModification &argumentModification : modification.argument_mods) { - if (argumentModification.index == key && !argumentModification.replace_value.isEmpty()) - return argumentModification.replace_value; - } - } - - return QString(); -} - // FIXME If we remove a arg. in the method at the base class, it will not reflect here. bool AbstractMetaFunction::argumentRemoved(int key) const { @@ -2555,6 +2520,58 @@ QString AbstractMetaType::formatSignature(bool minimal) const return result; } +QString AbstractMetaType::formatPythonSignature(bool minimal) const +{ + /* + * This is a version of the above, more suitable for Python. + * We avoid extra keywords that are not needed in Python. + * We prepend the package name, unless it is a primitive type. + * + * Primitive types like 'int', 'char' etc.: + * When we have a primitive with an indirection, we use that '*' + * character for later postprocessing, since those indirections + * need to be modified into a result tuple. + */ + QString result; + if (m_pattern == AbstractMetaType::NativePointerAsArrayPattern) + result += QLatin1String("array "); + // We no longer use the "const" qualifier for heuristics. Instead, + // NativePointerAsArrayPattern indicates when we have <array> in XML. + // if (m_typeEntry->isPrimitive() && isConstant()) + // result += QLatin1String("const "); + if (!m_typeEntry->isPrimitive() && !package().isEmpty()) + result += package() + QLatin1Char('.'); + if (isArray()) { + // Build nested array dimensions a[2][3] in correct order + result += m_arrayElementType->formatPythonSignature(true); + const int arrayPos = result.indexOf(QLatin1Char('[')); + if (arrayPos != -1) + result.insert(arrayPos, formatArraySize(m_arrayElementCount)); + else + result.append(formatArraySize(m_arrayElementCount)); + } else { + result += typeEntry()->qualifiedCppName(); + } + if (!m_instantiations.isEmpty()) { + result += QLatin1Char('['); + for (int i = 0, size = m_instantiations.size(); i < size; ++i) { + if (i > 0) + result += QLatin1String(", "); + result += m_instantiations.at(i)->formatPythonSignature(true); + } + result += QLatin1Char(']'); + } + if (m_typeEntry->isPrimitive()) + for (Indirection i : m_indirections) + result += TypeInfo::indirectionKeyword(i); + // If it is a flags type, we replace it with the full name: + // "PySide2.QtCore.Qt.ItemFlags" instead of "PySide2.QtCore.QFlags<Qt.ItemFlag>" + if (m_typeEntry->isFlags()) + result = fullName(); + result.replace(QLatin1String("::"), QLatin1String(".")); + return result; +} + bool AbstractMetaType::isCppPrimitive() const { return m_pattern == PrimitivePattern && m_typeEntry->isCppPrimitive(); diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h index 91ca4d7a9..077191471 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetalang.h +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt for Python. @@ -483,6 +483,8 @@ public: QString cppSignature() const; + QString pythonSignature() const; + AbstractMetaType *copy() const; bool applyArrayModification(QString *errorMessage); @@ -540,12 +542,14 @@ public: private: TypeUsagePattern determineUsagePattern() const; QString formatSignature(bool minimal) const; + QString formatPythonSignature(bool minimal) const; const TypeEntry *m_typeEntry = nullptr; AbstractMetaTypeList m_instantiations; QString m_package; mutable QString m_name; mutable QString m_cachedCppSignature; + mutable QString m_cachedPythonSignature; QString m_originalTypeDescription; int m_arrayElementCount = -1; @@ -667,7 +671,9 @@ public: } bool hasDefaultValueExpression() const - { return !m_originalExpression.isEmpty() || !m_expression.isEmpty(); } + { return !m_expression.isEmpty(); } + bool hasOriginalDefaultValueExpression() const + { return !m_originalExpression.isEmpty(); } bool hasUnmodifiedDefaultValueExpression() const { return !m_originalExpression.isEmpty() && m_originalExpression == m_expression; } bool hasModifiedDefaultValueExpression() const @@ -1016,8 +1022,6 @@ public: AbstractMetaFunction *copy() const; - QString replacedDefaultExpression(const AbstractMetaClass *cls, int idx) const; - bool removedDefaultExpression(const AbstractMetaClass *cls, int idx) const; QString conversionRule(TypeSystem::Language language, int idx) const; QVector<ReferenceCount> referenceCounts(const AbstractMetaClass *cls, int idx = -2) const; ArgumentOwner argumentOwner(const AbstractMetaClass *cls, int idx) const; @@ -1030,9 +1034,6 @@ public: bool isRemovedFromAllLanguages(const AbstractMetaClass *) const; bool isRemovedFrom(const AbstractMetaClass *, TypeSystem::Language language) const; bool argumentRemoved(int) const; - - QString argumentReplaced(int key) const; - /** * Verifies if any modification to the function is an inject code. * \return true if there is inject code modifications to the function. diff --git a/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.cpp b/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.cpp index 98b493c67..b85a022b3 100644 --- a/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.cpp +++ b/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.cpp @@ -47,11 +47,12 @@ void TestAbstractMetaClass::testClassName() void TestAbstractMetaClass::testClassNameUnderNamespace() { const char* cppCode ="namespace Namespace { class ClassName {}; }\n"; - const char* xmlCode = "\ - <typesystem package=\"Foo\">\n\ - <namespace-type name=\"Namespace\"/>\n\ - <value-type name=\"Namespace::ClassName\"/>\n\ - </typesystem>\n"; + const char* xmlCode = R"XML( + <typesystem package="Foo"> + <namespace-type name="Namespace"> + <value-type name="ClassName"/> + </namespace-type> + </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); QVERIFY(!builder.isNull()); AbstractMetaClassList classes = builder->classes(); @@ -201,11 +202,12 @@ void TestAbstractMetaClass::testDefaultValues() class B {};\n\ void method(B b = B());\n\ };\n"; - const char* xmlCode = "\ - <typesystem package=\"Foo\">\n\ - <value-type name='A'/>\n\ - <value-type name='A::B'/>\n\ - </typesystem>\n"; + const char* xmlCode = R"XML( + <typesystem package="Foo"> + <value-type name='A'> + <value-type name='B'/> + </value-type> + </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); QVERIFY(!builder.isNull()); AbstractMetaClassList classes = builder->classes(); @@ -224,17 +226,17 @@ void TestAbstractMetaClass::testModifiedDefaultValues() class B {};\n\ void method(B b = B());\n\ };\n"; - const char* xmlCode = "\ - <typesystem package=\"Foo\">\n\ - <value-type name='A'>\n\ - <modify-function signature='method(A::B)'>\n\ - <modify-argument index='1'>\n\ - <replace-default-expression with='Hello'/>\n\ - </modify-argument>\n\ - </modify-function>\n\ - </value-type>\n\ - <value-type name='A::B'/>\n\ - </typesystem>\n"; + const char* xmlCode = R"XML( + <typesystem package="Foo"> + <value-type name='A'> + <modify-function signature='method(A::B)'> + <modify-argument index='1'> + <replace-default-expression with='Hello'/> + </modify-argument> + </modify-function> + <value-type name='B'/> + </value-type> + </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); QVERIFY(!builder.isNull()); AbstractMetaClassList classes = builder->classes(); @@ -254,11 +256,12 @@ void TestAbstractMetaClass::testInnerClassOfAPolymorphicOne() class B {};\n\ virtual void method();\n\ };\n"; - const char* xmlCode = "\ - <typesystem package=\"Foo\">\n\ - <object-type name='A'/>\n\ - <value-type name='A::B'/>\n\ - </typesystem>\n"; + const char* xmlCode = R"XML( + <typesystem package="Foo"> + <object-type name='A'> + <value-type name='B'/> + </object-type> + </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); QVERIFY(!builder.isNull()); AbstractMetaClassList classes = builder->classes(); @@ -281,11 +284,12 @@ void TestAbstractMetaClass::testForwardDeclaredInnerClass() public:\n\ void foo();\n\ };\n"; - const char xmlCode[] = "\ - <typesystem package=\"Foo\">\n\ - <value-type name='A'/>\n\ - <value-type name='A::B'/>\n\ - </typesystem>\n"; + const char xmlCode[] = R"XML( + <typesystem package="Foo"> + <value-type name='A'> + <value-type name='B'/> + </value-type> + </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode)); QVERIFY(!builder.isNull()); AbstractMetaClassList classes = builder->classes(); diff --git a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp index c438e0c37..aeca2d3f4 100644 --- a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp +++ b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp @@ -71,8 +71,8 @@ void TestCodeInjections::testReadFile() <value-type name='A'>\n\ <conversion-rule ") + attribute + QLatin1String("/>\n\ <inject-code class='target' ") + attribute + QLatin1String("/>\n\ + <value-type name='B'/>\n\ </value-type>\n\ - <value-type name='A::B'/>\n\ </typesystem>\n"); QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode.toLocal8Bit().constData())); QVERIFY(!builder.isNull()); diff --git a/sources/shiboken2/ApiExtractor/tests/testresolvetype.cpp b/sources/shiboken2/ApiExtractor/tests/testresolvetype.cpp index 2e5a5759a..2203f3648 100644 --- a/sources/shiboken2/ApiExtractor/tests/testresolvetype.cpp +++ b/sources/shiboken2/ApiExtractor/tests/testresolvetype.cpp @@ -44,13 +44,15 @@ void TestResolveType::testResolveReturnTypeFromParentScope() C* method();\n\ };\n\ };"; - const char* xmlCode = "\n\ - <typesystem package='Foo'>\n\ - <namespace-type name='A'/>\n\ - <value-type name='A::B'/>\n\ - <value-type name='A::B::C'/>\n\ - <value-type name='A::D'/>\n\ - </typesystem>"; + const char* xmlCode = R"XML( + <typesystem package='Foo'> + <namespace-type name='A'> + <value-type name='B'> + <value-type name='C'/> + </value-type> + <value-type name='D'/> + </namespace-type> + </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); QVERIFY(!builder.isNull()); AbstractMetaClassList classes = builder->classes(); diff --git a/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp index 59b601f3b..5191cb38d 100644 --- a/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp +++ b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp @@ -63,9 +63,10 @@ namespace Internet { <typesystem package='Package.Internet'> <load-typesystem name='%1' generate='no'/> <container-type name='QList' type='list'/> - <namespace-type name='Internet' generate='no'/> - <value-type name='Internet::Url'/> - <value-type name='Internet::Bookmarks'/> + <namespace-type name='Internet' generate='no'> + <value-type name='Url'/> + <value-type name='Bookmarks'/> + </namespace-type> </typesystem>)XML").arg(file.fileName()); QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, qPrintable(xmlCode1), false)); @@ -97,11 +98,12 @@ namespace Namespace { const char xmlCode[] = R"XML( <typesystem package="Package"> <container-type name='QList' type='list'/> - <namespace-type name='Namespace'/> - <enum-type name='Namespace::SomeEnum'/> + <namespace-type name='Namespace'> + <enum-type name='SomeEnum'/> + <object-type name='A' generate='no'/> + <object-type name='B'/> + </namespace-type> <object-type name='Base'/> - <object-type name='Namespace::A' generate='no'/> - <object-type name='Namespace::B'/> </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); @@ -211,8 +213,9 @@ struct List { const char xmlCode[] = R"XML( <typesystem package='Package'> - <container-type name='List' type='list'/> - <value-type name='List::Iterator'/> + <container-type name='List' type='list'> + <value-type name='Iterator'/> + </container-type> </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); @@ -324,11 +327,12 @@ template<SomeEnum type> struct Future {}; const char xmlCode[] = R"XML( <typesystem package='Package'> - <namespace-type name='Namespace'/> - <enum-type name='Namespace::SomeEnum'/> - <value-type name='Namespace::A' generate='no'/> - <value-type name='Namespace::B'/> - <value-type name='Namespace::Future' generate='no'/> + <namespace-type name='Namespace'> + <enum-type name='SomeEnum'/> + <value-type name='A' generate='no'/> + <value-type name='B'/> + <value-type name='Future' generate='no'/> + </namespace-type> </typesystem>)XML"; QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); diff --git a/sources/shiboken2/ApiExtractor/typesystemparser.cpp b/sources/shiboken2/ApiExtractor/typesystemparser.cpp index 57ceb357f..5440de5c0 100644 --- a/sources/shiboken2/ApiExtractor/typesystemparser.cpp +++ b/sources/shiboken2/ApiExtractor/typesystemparser.cpp @@ -191,200 +191,200 @@ static EnumType functionName(QStringView needle, EnumType defaultValue = default ENUM_LOOKUP_BEGIN(TypeSystem::AllowThread, Qt::CaseInsensitive, allowThreadFromAttribute, TypeSystem::AllowThread::Unspecified) { - {QStringViewLiteral("yes"), TypeSystem::AllowThread::Allow}, - {QStringViewLiteral("true"), TypeSystem::AllowThread::Allow}, - {QStringViewLiteral("auto"), TypeSystem::AllowThread::Auto}, - {QStringViewLiteral("no"), TypeSystem::AllowThread::Disallow}, - {QStringViewLiteral("false"), TypeSystem::AllowThread::Disallow}, + {u"yes", TypeSystem::AllowThread::Allow}, + {u"true", TypeSystem::AllowThread::Allow}, + {u"auto", TypeSystem::AllowThread::Auto}, + {u"no", TypeSystem::AllowThread::Disallow}, + {u"false", TypeSystem::AllowThread::Disallow}, }; ENUM_LOOKUP_LINEAR_SEARCH() ENUM_LOOKUP_BEGIN(TypeSystem::Language, Qt::CaseInsensitive, languageFromAttribute, TypeSystem::NoLanguage) { - {QStringViewLiteral("all"), TypeSystem::All}, // sorted! - {QStringViewLiteral("constructors"), TypeSystem::Constructors}, - {QStringViewLiteral("destructor-function"), TypeSystem::DestructorFunction}, - {QStringViewLiteral("interface"), TypeSystem::Interface}, - {QStringViewLiteral("library-initializer"), TypeSystem::PackageInitializer}, - {QStringViewLiteral("native"), TypeSystem::NativeCode}, // em algum lugar do cpp - {QStringViewLiteral("shell"), TypeSystem::ShellCode}, // coloca no header, mas antes da declaracao da classe - {QStringViewLiteral("shell-declaration"), TypeSystem::ShellDeclaration}, - {QStringViewLiteral("target"), TypeSystem::TargetLangCode} // em algum lugar do cpp + {u"all", TypeSystem::All}, // sorted! + {u"constructors", TypeSystem::Constructors}, + {u"destructor-function", TypeSystem::DestructorFunction}, + {u"interface", TypeSystem::Interface}, + {u"library-initializer", TypeSystem::PackageInitializer}, + {u"native", TypeSystem::NativeCode}, // em algum lugar do cpp + {u"shell", TypeSystem::ShellCode}, // coloca no header, mas antes da declaracao da classe + {u"shell-declaration", TypeSystem::ShellDeclaration}, + {u"target", TypeSystem::TargetLangCode} // em algum lugar do cpp }; ENUM_LOOKUP_BINARY_SEARCH() ENUM_LOOKUP_BEGIN(TypeSystem::Ownership, Qt::CaseInsensitive, ownershipFromFromAttribute, TypeSystem::InvalidOwnership) { - {QStringViewLiteral("target"), TypeSystem::TargetLangOwnership}, - {QStringViewLiteral("c++"), TypeSystem::CppOwnership}, - {QStringViewLiteral("default"), TypeSystem::DefaultOwnership} + {u"target", TypeSystem::TargetLangOwnership}, + {u"c++", TypeSystem::CppOwnership}, + {u"default", TypeSystem::DefaultOwnership} }; ENUM_LOOKUP_LINEAR_SEARCH() ENUM_LOOKUP_BEGIN(AddedFunction::Access, Qt::CaseInsensitive, addedFunctionAccessFromAttribute, AddedFunction::InvalidAccess) { - {QStringViewLiteral("public"), AddedFunction::Public}, - {QStringViewLiteral("protected"), AddedFunction::Protected}, + {u"public", AddedFunction::Public}, + {u"protected", AddedFunction::Protected}, }; ENUM_LOOKUP_LINEAR_SEARCH() ENUM_LOOKUP_BEGIN(Modification::Modifiers, Qt::CaseSensitive, modifierFromAttribute, Modification::InvalidModifier) { - {QStringViewLiteral("private"), Modification::Private}, - {QStringViewLiteral("public"), Modification::Public}, - {QStringViewLiteral("protected"), Modification::Protected}, - {QStringViewLiteral("friendly"), Modification::Friendly}, - {QStringViewLiteral("rename"), Modification::Rename}, - {QStringViewLiteral("final"), Modification::Final}, - {QStringViewLiteral("non-final"), Modification::NonFinal} + {u"private", Modification::Private}, + {u"public", Modification::Public}, + {u"protected", Modification::Protected}, + {u"friendly", Modification::Friendly}, + {u"rename", Modification::Rename}, + {u"final", Modification::Final}, + {u"non-final", Modification::NonFinal} }; ENUM_LOOKUP_LINEAR_SEARCH() ENUM_LOOKUP_BEGIN(ReferenceCount::Action, Qt::CaseInsensitive, referenceCountFromAttribute, ReferenceCount::Invalid) { - {QStringViewLiteral("add"), ReferenceCount::Add}, - {QStringViewLiteral("add-all"), ReferenceCount::AddAll}, - {QStringViewLiteral("remove"), ReferenceCount::Remove}, - {QStringViewLiteral("set"), ReferenceCount::Set}, - {QStringViewLiteral("ignore"), ReferenceCount::Ignore} + {u"add", ReferenceCount::Add}, + {u"add-all", ReferenceCount::AddAll}, + {u"remove", ReferenceCount::Remove}, + {u"set", ReferenceCount::Set}, + {u"ignore", ReferenceCount::Ignore} }; ENUM_LOOKUP_LINEAR_SEARCH() ENUM_LOOKUP_BEGIN(ArgumentOwner::Action, Qt::CaseInsensitive, argumentOwnerActionFromAttribute, ArgumentOwner::Invalid) { - {QStringViewLiteral("add"), ArgumentOwner::Add}, - {QStringViewLiteral("remove"), ArgumentOwner::Remove} + {u"add", ArgumentOwner::Add}, + {u"remove", ArgumentOwner::Remove} }; ENUM_LOOKUP_LINEAR_SEARCH() ENUM_LOOKUP_BEGIN(TypeSystem::CodeSnipPosition, Qt::CaseInsensitive, codeSnipPositionFromAttribute, TypeSystem::CodeSnipPositionInvalid) { - {QStringViewLiteral("beginning"), TypeSystem::CodeSnipPositionBeginning}, - {QStringViewLiteral("end"), TypeSystem::CodeSnipPositionEnd}, - {QStringViewLiteral("declaration"), TypeSystem::CodeSnipPositionDeclaration}, - {QStringViewLiteral("prototype-initialization"), TypeSystem::CodeSnipPositionPrototypeInitialization}, - {QStringViewLiteral("constructor-initialization"), TypeSystem::CodeSnipPositionConstructorInitialization}, - {QStringViewLiteral("constructor"), TypeSystem::CodeSnipPositionConstructor} + {u"beginning", TypeSystem::CodeSnipPositionBeginning}, + {u"end", TypeSystem::CodeSnipPositionEnd}, + {u"declaration", TypeSystem::CodeSnipPositionDeclaration}, + {u"prototype-initialization", TypeSystem::CodeSnipPositionPrototypeInitialization}, + {u"constructor-initialization", TypeSystem::CodeSnipPositionConstructorInitialization}, + {u"constructor", TypeSystem::CodeSnipPositionConstructor} }; ENUM_LOOKUP_LINEAR_SEARCH() ENUM_LOOKUP_BEGIN(Include::IncludeType, Qt::CaseInsensitive, locationFromAttribute, Include::InvalidInclude) { - {QStringViewLiteral("global"), Include::IncludePath}, - {QStringViewLiteral("local"), Include::LocalPath}, - {QStringViewLiteral("target"), Include::TargetLangImport} + {u"global", Include::IncludePath}, + {u"local", Include::LocalPath}, + {u"target", Include::TargetLangImport} }; ENUM_LOOKUP_LINEAR_SEARCH() ENUM_LOOKUP_BEGIN(TypeSystem::DocModificationMode, Qt::CaseInsensitive, docModificationFromAttribute, TypeSystem::DocModificationInvalid) { - {QStringViewLiteral("append"), TypeSystem::DocModificationAppend}, - {QStringViewLiteral("prepend"), TypeSystem::DocModificationPrepend}, - {QStringViewLiteral("replace"), TypeSystem::DocModificationReplace} + {u"append", TypeSystem::DocModificationAppend}, + {u"prepend", TypeSystem::DocModificationPrepend}, + {u"replace", TypeSystem::DocModificationReplace} }; ENUM_LOOKUP_LINEAR_SEARCH() ENUM_LOOKUP_BEGIN(ContainerTypeEntry::Type, Qt::CaseSensitive, containerTypeFromAttribute, ContainerTypeEntry::NoContainer) { - {QStringViewLiteral("list"), ContainerTypeEntry::ListContainer}, - {QStringViewLiteral("string-list"), ContainerTypeEntry::StringListContainer}, - {QStringViewLiteral("linked-list"), ContainerTypeEntry::LinkedListContainer}, - {QStringViewLiteral("vector"), ContainerTypeEntry::VectorContainer}, - {QStringViewLiteral("stack"), ContainerTypeEntry::StackContainer}, - {QStringViewLiteral("queue"), ContainerTypeEntry::QueueContainer}, - {QStringViewLiteral("set"), ContainerTypeEntry::SetContainer}, - {QStringViewLiteral("map"), ContainerTypeEntry::MapContainer}, - {QStringViewLiteral("multi-map"), ContainerTypeEntry::MultiMapContainer}, - {QStringViewLiteral("hash"), ContainerTypeEntry::HashContainer}, - {QStringViewLiteral("multi-hash"), ContainerTypeEntry::MultiHashContainer}, - {QStringViewLiteral("pair"), ContainerTypeEntry::PairContainer} + {u"list", ContainerTypeEntry::ListContainer}, + {u"string-list", ContainerTypeEntry::StringListContainer}, + {u"linked-list", ContainerTypeEntry::LinkedListContainer}, + {u"vector", ContainerTypeEntry::VectorContainer}, + {u"stack", ContainerTypeEntry::StackContainer}, + {u"queue", ContainerTypeEntry::QueueContainer}, + {u"set", ContainerTypeEntry::SetContainer}, + {u"map", ContainerTypeEntry::MapContainer}, + {u"multi-map", ContainerTypeEntry::MultiMapContainer}, + {u"hash", ContainerTypeEntry::HashContainer}, + {u"multi-hash", ContainerTypeEntry::MultiHashContainer}, + {u"pair", ContainerTypeEntry::PairContainer} }; ENUM_LOOKUP_LINEAR_SEARCH() ENUM_LOOKUP_BEGIN(TypeRejection::MatchType, Qt::CaseSensitive, typeRejectionFromAttribute, TypeRejection::Invalid) { - {QStringViewLiteral("class"), TypeRejection::ExcludeClass}, - {QStringViewLiteral("function-name"), TypeRejection::Function}, - {QStringViewLiteral("field-name"), TypeRejection::Field}, - {QStringViewLiteral("enum-name"), TypeRejection::Enum }, - {QStringViewLiteral("argument-type"), TypeRejection::ArgumentType}, - {QStringViewLiteral("return-type"), TypeRejection::ReturnType} + {u"class", TypeRejection::ExcludeClass}, + {u"function-name", TypeRejection::Function}, + {u"field-name", TypeRejection::Field}, + {u"enum-name", TypeRejection::Enum }, + {u"argument-type", TypeRejection::ArgumentType}, + {u"return-type", TypeRejection::ReturnType} }; ENUM_LOOKUP_LINEAR_SEARCH() ENUM_LOOKUP_BEGIN(TypeSystem::ExceptionHandling, Qt::CaseSensitive, exceptionHandlingFromAttribute, TypeSystem::ExceptionHandling::Unspecified) { - {QStringViewLiteral("no"), TypeSystem::ExceptionHandling::Off}, - {QStringViewLiteral("false"), TypeSystem::ExceptionHandling::Off}, - {QStringViewLiteral("auto-off"), TypeSystem::ExceptionHandling::AutoDefaultToOff}, - {QStringViewLiteral("auto-on"), TypeSystem::ExceptionHandling::AutoDefaultToOn}, - {QStringViewLiteral("yes"), TypeSystem::ExceptionHandling::On}, - {QStringViewLiteral("true"), TypeSystem::ExceptionHandling::On}, + {u"no", TypeSystem::ExceptionHandling::Off}, + {u"false", TypeSystem::ExceptionHandling::Off}, + {u"auto-off", TypeSystem::ExceptionHandling::AutoDefaultToOff}, + {u"auto-on", TypeSystem::ExceptionHandling::AutoDefaultToOn}, + {u"yes", TypeSystem::ExceptionHandling::On}, + {u"true", TypeSystem::ExceptionHandling::On}, }; ENUM_LOOKUP_LINEAR_SEARCH() ENUM_LOOKUP_BEGIN(StackElement::ElementType, Qt::CaseInsensitive, elementFromTag, StackElement::None) { - {QStringViewLiteral("access"), StackElement::Access}, // sorted! - {QStringViewLiteral("add-conversion"), StackElement::AddConversion}, - {QStringViewLiteral("add-function"), StackElement::AddFunction}, - {QStringViewLiteral("argument-map"), StackElement::ArgumentMap}, - {QStringViewLiteral("array"), StackElement::Array}, - {QStringViewLiteral("container-type"), StackElement::ContainerTypeEntry}, - {QStringViewLiteral("conversion-rule"), StackElement::ConversionRule}, - {QStringViewLiteral("custom-constructor"), StackElement::CustomMetaConstructor}, - {QStringViewLiteral("custom-destructor"), StackElement::CustomMetaDestructor}, - {QStringViewLiteral("custom-type"), StackElement::CustomTypeEntry}, - {QStringViewLiteral("define-ownership"), StackElement::DefineOwnership}, - {QStringViewLiteral("enum-type"), StackElement::EnumTypeEntry}, - {QStringViewLiteral("extra-includes"), StackElement::ExtraIncludes}, - {QStringViewLiteral("function"), StackElement::FunctionTypeEntry}, - {QStringViewLiteral("include"), StackElement::Include}, - {QStringViewLiteral("inject-code"), StackElement::InjectCode}, - {QStringViewLiteral("inject-documentation"), StackElement::InjectDocumentation}, - {QStringViewLiteral("insert-template"), StackElement::TemplateInstanceEnum}, - {QStringViewLiteral("interface-type"), StackElement::InterfaceTypeEntry}, - {QStringViewLiteral("load-typesystem"), StackElement::LoadTypesystem}, - {QStringViewLiteral("modify-argument"), StackElement::ModifyArgument}, - {QStringViewLiteral("modify-documentation"), StackElement::ModifyDocumentation}, - {QStringViewLiteral("modify-field"), StackElement::ModifyField}, - {QStringViewLiteral("modify-function"), StackElement::ModifyFunction}, - {QStringViewLiteral("namespace-type"), StackElement::NamespaceTypeEntry}, - {QStringViewLiteral("native-to-target"), StackElement::NativeToTarget}, - {QStringViewLiteral("no-null-pointer"), StackElement::NoNullPointers}, - {QStringViewLiteral("object-type"), StackElement::ObjectTypeEntry}, - {QStringViewLiteral("parent"), StackElement::ParentOwner}, - {QStringViewLiteral("primitive-type"), StackElement::PrimitiveTypeEntry}, - {QStringViewLiteral("reference-count"), StackElement::ReferenceCount}, - {QStringViewLiteral("reject-enum-value"), StackElement::RejectEnumValue}, - {QStringViewLiteral("rejection"), StackElement::Rejection}, - {QStringViewLiteral("remove"), StackElement::Removal}, - {QStringViewLiteral("remove-argument"), StackElement::RemoveArgument}, - {QStringViewLiteral("remove-default-expression"), StackElement::RemoveDefaultExpression}, - {QStringViewLiteral("rename"), StackElement::Rename}, - {QStringViewLiteral("replace"), StackElement::Replace}, - {QStringViewLiteral("replace-default-expression"), StackElement::ReplaceDefaultExpression}, - {QStringViewLiteral("replace-type"), StackElement::ReplaceType}, - {QStringViewLiteral("smart-pointer-type"), StackElement::SmartPointerTypeEntry}, - {QStringViewLiteral("suppress-warning"), StackElement::SuppressedWarning}, - {QStringViewLiteral("target-to-native"), StackElement::TargetToNative}, - {QStringViewLiteral("template"), StackElement::Template}, - {QStringViewLiteral("typedef-type"), StackElement::TypedefTypeEntry}, - {QStringViewLiteral("typesystem"), StackElement::Root}, - {QStringViewLiteral("value-type"), StackElement::ValueTypeEntry}, + {u"access", StackElement::Access}, // sorted! + {u"add-conversion", StackElement::AddConversion}, + {u"add-function", StackElement::AddFunction}, + {u"argument-map", StackElement::ArgumentMap}, + {u"array", StackElement::Array}, + {u"container-type", StackElement::ContainerTypeEntry}, + {u"conversion-rule", StackElement::ConversionRule}, + {u"custom-constructor", StackElement::CustomMetaConstructor}, + {u"custom-destructor", StackElement::CustomMetaDestructor}, + {u"custom-type", StackElement::CustomTypeEntry}, + {u"define-ownership", StackElement::DefineOwnership}, + {u"enum-type", StackElement::EnumTypeEntry}, + {u"extra-includes", StackElement::ExtraIncludes}, + {u"function", StackElement::FunctionTypeEntry}, + {u"include", StackElement::Include}, + {u"inject-code", StackElement::InjectCode}, + {u"inject-documentation", StackElement::InjectDocumentation}, + {u"insert-template", StackElement::TemplateInstanceEnum}, + {u"interface-type", StackElement::InterfaceTypeEntry}, + {u"load-typesystem", StackElement::LoadTypesystem}, + {u"modify-argument", StackElement::ModifyArgument}, + {u"modify-documentation", StackElement::ModifyDocumentation}, + {u"modify-field", StackElement::ModifyField}, + {u"modify-function", StackElement::ModifyFunction}, + {u"namespace-type", StackElement::NamespaceTypeEntry}, + {u"native-to-target", StackElement::NativeToTarget}, + {u"no-null-pointer", StackElement::NoNullPointers}, + {u"object-type", StackElement::ObjectTypeEntry}, + {u"parent", StackElement::ParentOwner}, + {u"primitive-type", StackElement::PrimitiveTypeEntry}, + {u"reference-count", StackElement::ReferenceCount}, + {u"reject-enum-value", StackElement::RejectEnumValue}, + {u"rejection", StackElement::Rejection}, + {u"remove", StackElement::Removal}, + {u"remove-argument", StackElement::RemoveArgument}, + {u"remove-default-expression", StackElement::RemoveDefaultExpression}, + {u"rename", StackElement::Rename}, + {u"replace", StackElement::Replace}, + {u"replace-default-expression", StackElement::ReplaceDefaultExpression}, + {u"replace-type", StackElement::ReplaceType}, + {u"smart-pointer-type", StackElement::SmartPointerTypeEntry}, + {u"suppress-warning", StackElement::SuppressedWarning}, + {u"target-to-native", StackElement::TargetToNative}, + {u"template", StackElement::Template}, + {u"typedef-type", StackElement::TypedefTypeEntry}, + {u"typesystem", StackElement::Root}, + {u"value-type", StackElement::ValueTypeEntry}, }; ENUM_LOOKUP_BINARY_SEARCH() @@ -991,17 +991,17 @@ static bool convertRemovalAttribute(QStringView remove, Modification& mod, QStri if (remove.isEmpty()) return true; #ifdef QTBUG_69389_FIXED - if (remove.compare(QStringViewLiteral("all"), Qt::CaseInsensitive) == 0) { + if (remove.compare(u"all", Qt::CaseInsensitive) == 0) { #else - if (QtPrivate::compareStrings(remove, QStringViewLiteral("all"), Qt::CaseInsensitive) == 0) { + if (QtPrivate::compareStrings(remove, u"all", Qt::CaseInsensitive) == 0) { #endif mod.removal = TypeSystem::All; return true; } #ifdef QTBUG_69389_FIXED - if (remove.compare(QStringViewLiteral("target"), Qt::CaseInsensitive) == 0) { + if (remove.compare(u"target", Qt::CaseInsensitive) == 0) { #else - if (QtPrivate::compareStrings(remove, QStringViewLiteral("target"), Qt::CaseInsensitive) == 0) { + if (QtPrivate::compareStrings(remove, u"target", Qt::CaseInsensitive) == 0) { #endif mod.removal = TypeSystem::TargetLangAndNativeCode; return true; @@ -1044,7 +1044,7 @@ void TypeSystemParser::applyCommonAttributes(TypeEntry *type, QXmlStreamAttribut { type->setCodeGeneration(m_generate); const int revisionIndex = - indexOfAttribute(*attributes, QStringViewLiteral("revision")); + indexOfAttribute(*attributes, u"revision"); if (revisionIndex != -1) type->setRevision(attributes->takeAt(revisionIndex).value().toInt()); } @@ -1084,7 +1084,7 @@ FlagsTypeEntry * m_database->addType(ftype); const int revisionIndex = - indexOfAttribute(*attributes, QStringViewLiteral("flags-revision")); + indexOfAttribute(*attributes, u"flags-revision"); ftype->setRevision(revisionIndex != -1 ? attributes->takeAt(revisionIndex).value().toInt() : enumEntry->revision()); @@ -1181,7 +1181,7 @@ ContainerTypeEntry * const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { - const int typeIndex = indexOfAttribute(*attributes, QStringViewLiteral("type")); + const int typeIndex = indexOfAttribute(*attributes, u"type"); if (typeIndex == -1) { m_error = QLatin1String("no 'type' attribute specified"); return nullptr; @@ -1323,7 +1323,7 @@ ValueTypeEntry * auto *typeEntry = new ValueTypeEntry(name, since); applyCommonAttributes(typeEntry, attributes); const int defaultCtIndex = - indexOfAttribute(*attributes, QStringViewLiteral("default-constructor")); + indexOfAttribute(*attributes, u"default-constructor"); if (defaultCtIndex != -1) typeEntry->setDefaultConstructor(attributes->takeAt(defaultCtIndex).value().toString()); return typeEntry; @@ -1887,7 +1887,7 @@ bool TypeSystemParser::parseNoNullPointer(const QXmlStreamReader &reader, lastArgMod.noNullPointers = true; const int defaultValueIndex = - indexOfAttribute(*attributes, QStringViewLiteral("default-value")); + indexOfAttribute(*attributes, u"default-value"); if (defaultValueIndex != -1) { const QXmlStreamAttribute attribute = attributes->takeAt(defaultValueIndex); qCWarning(lcShiboken, "%s", @@ -2266,7 +2266,7 @@ bool TypeSystemParser::parseReplaceDefaultExpression(const QXmlStreamReader &, m_error = QLatin1String("Replace default expression only allowed as child of argument modification"); return false; } - const int withIndex = indexOfAttribute(*attributes, QStringViewLiteral("with")); + const int withIndex = indexOfAttribute(*attributes, u"with"); if (withIndex == -1 || attributes->at(withIndex).value().isEmpty()) { m_error = QLatin1String("Default expression replaced with empty string. Use remove-default-expression instead."); return false; diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp index 6da9fd933..7c6e921c7 100644 --- a/sources/shiboken2/generator/generator.cpp +++ b/sources/shiboken2/generator/generator.cpp @@ -760,7 +760,7 @@ DefaultValue Generator::minimalConstructor(const AbstractMetaClass *metaClass) c bool simple = true; bool suitable = true; for (int i = 0, size = arguments.size(); - suitable && i < size && !arguments.at(i)->hasDefaultValueExpression(); ++i) { + suitable && i < size && !arguments.at(i)->hasOriginalDefaultValueExpression(); ++i) { const AbstractMetaArgument *arg = arguments.at(i); const TypeEntry *aType = arg->type()->typeEntry(); suitable &= aType != cType; @@ -777,11 +777,12 @@ DefaultValue Generator::minimalConstructor(const AbstractMetaClass *metaClass) c bool ok = true; for (int i =0, size = arguments.size(); ok && i < size; ++i) { const AbstractMetaArgument *arg = arguments.at(i); - if (arg->hasDefaultValueExpression()) { - if (arg->hasModifiedDefaultValueExpression()) - args << arg->defaultValueExpression(); // Spell out modified values + if (arg->hasModifiedDefaultValueExpression()) { + args << arg->defaultValueExpression(); // Spell out modified values break; } + if (arg->hasOriginalDefaultValueExpression()) + break; auto argValue = minimalConstructor(arg->type()); ok &= argValue.isValid(); args << argValue.constructorParameter(); diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index 61429b383..5460fd7c7 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -317,7 +317,10 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext) s << "#include <pyside.h>" << endl; s << "#include <destroylistener.h>" << endl; s << "#include <qapp_macro.h>" << endl; - } + s << endl; + s << "QT_WARNING_DISABLE_DEPRECATED" << endl; + s << endl; + } s << "#include <typeinfo>" << endl; if (usePySideExtensions() && metaClass->isQObject()) { @@ -368,9 +371,6 @@ void CppGenerator::generateClass(QTextStream &s, GeneratorContext &classContext) if (metaClass->typeEntry()->typeFlags() & ComplexTypeEntry::Deprecated) s << "#Deprecated" << endl; - if (usePySideExtensions()) - s << "\nQT_WARNING_DISABLE_DEPRECATED\n"; - // Use class base namespace { const AbstractMetaClass *context = metaClass->enclosingClass(); @@ -1684,7 +1684,7 @@ void CppGenerator::writeConstructorWrapper(QTextStream &s, const AbstractMetaFun argNamesSet << arg->name(); } } - QStringList argNamesList = argNamesSet.toList(); + QStringList argNamesList = argNamesSet.values(); std::sort(argNamesList.begin(), argNamesList.end()); if (argNamesList.isEmpty()) { s << INDENT << "const char **argNames{};" << endl; @@ -1860,18 +1860,19 @@ void CppGenerator::writeMethodWrapper(QTextStream &s, const AbstractMetaFunction // For custom classes, operations like __radd__ and __rmul__ // will enter an infinite loop. if (rfunc->isBinaryOperator() && revOpName.contains(QLatin1String("shift"))) { + s << INDENT << "Shiboken::AutoDecRef attrName(Py_BuildValue(\"s\", \"" << revOpName << "\"));" << endl; s << INDENT << "if (!isReverse" << endl; { Indentation indent(INDENT); s << INDENT << "&& Shiboken::Object::checkType(" << PYTHON_ARG << ")" << endl; s << INDENT << "&& !PyObject_TypeCheck(" << PYTHON_ARG << ", self->ob_type)" << endl; - s << INDENT << "&& PyObject_HasAttrString(" << PYTHON_ARG << ", const_cast<char *>(\"" << revOpName << "\"))) {" << endl; + s << INDENT << "&& PyObject_HasAttr(" << PYTHON_ARG << ", attrName)) {" << endl; // This PyObject_CallMethod call will emit lots of warnings like // "deprecated conversion from string constant to char *" during compilation // due to the method name argument being declared as "char *" instead of "const char *" // issue 6952 http://bugs.python.org/issue6952 - s << INDENT << "PyObject *revOpMethod = PyObject_GetAttrString(" << PYTHON_ARG << ", const_cast<char *>(\"" << revOpName << "\"));" << endl; + s << INDENT << "PyObject *revOpMethod = PyObject_GetAttr(" << PYTHON_ARG << ", attrName);" << endl; s << INDENT << "if (revOpMethod && PyCallable_Check(revOpMethod)) {" << endl; { Indentation indent(INDENT); @@ -2154,6 +2155,8 @@ void CppGenerator::writeTypeCheck(QTextStream &s, const AbstractMetaType *argTyp QString customCheck; if (!customType.isEmpty()) { AbstractMetaType *metaType; + // PYSIDE-795: Note: XML-Overrides are handled in this shibokengenerator function! + // This enables iterables for QMatrix4x4 for instance. customCheck = guessCPythonCheckFunction(customType, &metaType); if (metaType) argType = metaType; @@ -2939,6 +2942,9 @@ void CppGenerator::writePythonToCppConversionFunctions(QTextStream &s, typeCheck = QLatin1String("PyType_Check(%in)"); else if (pyTypeName == QLatin1String("PyObject")) typeCheck = QLatin1String("PyObject_TypeCheck(%in, &PyBaseObject_Type)"); + // PYSIDE-795: We abuse PySequence for iterables + else if (pyTypeName == QLatin1String("PySequence")) + typeCheck = QLatin1String("Shiboken::String::checkIterable(%in)"); else if (pyTypeName.startsWith(QLatin1String("Py"))) typeCheck = pyTypeName + QLatin1String("_Check(%in)"); } @@ -3039,29 +3045,31 @@ void CppGenerator::writeNamedArgumentResolution(QTextStream &s, const AbstractMe QString pyArgName = usePyArgs ? pythonArgsAt(pyArgIndex) : QLatin1String(PYTHON_ARG); s << INDENT << "keyName = Py_BuildValue(\"s\",\"" << arg->name() << "\");" << endl; s << INDENT << "if (PyDict_Contains(kwds, keyName)) {" << endl; - s << INDENT << "value = PyDict_GetItemString(kwds, \"" << arg->name() << "\");" << endl; - s << INDENT << "if (value && " << pyArgName << ") {" << endl; { Indentation indent(INDENT); - s << INDENT << pyErrString.arg(arg->name()) << endl; - s << INDENT << returnStatement(m_currentErrorCode) << endl; - } - s << INDENT << INDENT << "} else if (value) {" << endl; - { - Indentation indent(INDENT); - s << INDENT << pyArgName << " = value;" << endl; - s << INDENT << "if (!"; - writeTypeCheck(s, arg->type(), pyArgName, isNumber(arg->type()->typeEntry()), func->typeReplaced(arg->argumentIndex() + 1)); - s << ')' << endl; + s << INDENT << "value = PyDict_GetItem(kwds, keyName);" << endl; + s << INDENT << "if (value && " << pyArgName << ") {" << endl; + { + Indentation indent(INDENT); + s << INDENT << pyErrString.arg(arg->name()) << endl; + s << INDENT << returnStatement(m_currentErrorCode) << endl; + } + s << INDENT << '}' << endl; + s << INDENT << "if (value) {" << endl; { Indentation indent(INDENT); - s << INDENT << "goto " << cpythonFunctionName(func) << "_TypeError;" << endl; + s << INDENT << pyArgName << " = value;" << endl; + s << INDENT << "if (!"; + writeTypeCheck(s, arg->type(), pyArgName, isNumber(arg->type()->typeEntry()), func->typeReplaced(arg->argumentIndex() + 1)); + s << ')' << endl; + { + Indentation indent(INDENT); + s << INDENT << "goto " << cpythonFunctionName(func) << "_TypeError;" << endl; + } } + s << INDENT << '}' << endl; } s << INDENT << '}' << endl; - if (arg != args.constLast()) - s << INDENT; - s << "}" << endl; } } s << INDENT << '}' << endl; @@ -4563,23 +4571,6 @@ void CppGenerator::writeMethodDefinition(QTextStream &s, const AbstractMetaFunct s << ',' << endl; } -static QString resolveRetOrArgType(const AbstractMetaType *someType) -{ - QString strRetArg; - if (CppGenerator::isCString(someType)) { - strRetArg = QLatin1String("str"); - } else if (someType->isPrimitive()) { - auto ptp = static_cast<const PrimitiveTypeEntry *>(someType->typeEntry()); - while (ptp->referencedTypeEntry()) - ptp = ptp->referencedTypeEntry(); - strRetArg = ptp->name(); - } else { - strRetArg = someType->fullName(); - } - strRetArg.replace(QLatin1String("::"), QLatin1String(".")); - return strRetArg; -} - void CppGenerator::writeSignatureInfo(QTextStream &s, const AbstractMetaFunctionList &overloads) { OverloadData overloadData(overloads, this); @@ -4593,11 +4584,7 @@ void CppGenerator::writeSignatureInfo(QTextStream &s, const AbstractMetaFunction QStringList args; const AbstractMetaArgumentList &arguments = f->arguments(); for (const AbstractMetaArgument *arg : arguments) { - AbstractMetaType *argType = getTypeWithoutContainer(arg->type()); - QString strArg = resolveRetOrArgType(arg->type()); - // PYSIDE-921: Handle container returntypes correctly. - if (argType != arg->type()) - strArg += QLatin1Char('[') + resolveRetOrArgType(argType) + QLatin1Char(']'); + QString strArg = arg->type()->pythonSignature(); if (!arg->defaultValueExpression().isEmpty()) { strArg += QLatin1Char('='); QString e = arg->defaultValueExpression(); @@ -4612,12 +4599,8 @@ void CppGenerator::writeSignatureInfo(QTextStream &s, const AbstractMetaFunction if (multiple) s << idx-- << ':'; s << funcName << '(' << args.join(QLatin1Char(',')) << ')'; - AbstractMetaType *returnType = getTypeWithoutContainer(f->type()); - // PYSIDE-921: Handle container returntypes correctly. - if (returnType != f->type()) - s << "->" << resolveRetOrArgType(f->type()) << '[' << resolveRetOrArgType(returnType) << ']'; - else if (returnType) - s << "->" << resolveRetOrArgType(returnType); + if (f->type()) + s << "->" << f->type()->pythonSignature(); s << endl; } } @@ -4634,6 +4617,15 @@ void CppGenerator::writeEnumsInitialization(QTextStream &s, AbstractMetaEnumList } } +static QString mangleName(QString name) +{ + if ( name == QLatin1String("None") + || name == QLatin1String("False") + || name == QLatin1String("True")) + name += QLatin1Char('_'); + return name; +} + void CppGenerator::writeEnumInitialization(QTextStream &s, const AbstractMetaEnum *cppEnum) { const AbstractMetaClass *enclosingClass = getProperEnclosingClassForEnum(cppEnum); @@ -4713,7 +4705,7 @@ void CppGenerator::writeEnumInitialization(QTextStream &s, const AbstractMetaEnu Indentation indent(INDENT); s << INDENT << "PyObject *anonEnumItem = PyInt_FromLong(" << enumValueText << ");" << endl; s << INDENT << "if (PyDict_SetItemString(reinterpret_cast<PyTypeObject *>(reinterpret_cast<SbkObjectType *>(" << enclosingObjectVariable - << "))->tp_dict, \"" << enumValue->name() << "\", anonEnumItem) < 0)" << endl; + << "))->tp_dict, \"" << mangleName(enumValue->name()) << "\", anonEnumItem) < 0)" << endl; { Indentation indent(INDENT); s << INDENT << returnStatement(m_currentErrorCode) << endl; @@ -4722,7 +4714,7 @@ void CppGenerator::writeEnumInitialization(QTextStream &s, const AbstractMetaEnu } s << INDENT << '}' << endl; } else { - s << INDENT << "if (PyModule_AddIntConstant(module, \"" << enumValue->name() << "\", "; + s << INDENT << "if (PyModule_AddIntConstant(module, \"" << mangleName(enumValue->name()) << "\", "; s << enumValueText << ") < 0)" << endl; { Indentation indent(INDENT); @@ -4735,7 +4727,7 @@ void CppGenerator::writeEnumInitialization(QTextStream &s, const AbstractMetaEnu s << ((enclosingClass || hasUpperEnclosingClass) ? "createScopedEnumItem" : "createGlobalEnumItem"); s << '(' << enumVarTypeObj << ',' << endl; Indentation indent(INDENT); - s << INDENT << enclosingObjectVariable << ", \"" << enumValue->name() << "\", "; + s << INDENT << enclosingObjectVariable << ", \"" << mangleName(enumValue->name()) << "\", "; s << enumValueText << "))" << endl; s << INDENT << returnStatement(m_currentErrorCode) << endl; } @@ -4744,7 +4736,7 @@ void CppGenerator::writeEnumInitialization(QTextStream &s, const AbstractMetaEnu s << INDENT << "if (!Shiboken::Enum::createScopedEnumItem(" << enumVarTypeObj << ',' << endl; Indentation indent(INDENT); - s << INDENT << enumVarTypeObj<< ", \"" << enumValue->name() << "\", " + s << INDENT << enumVarTypeObj<< ", \"" << mangleName(enumValue->name()) << "\", " << enumValueText << "))" << endl << INDENT << returnStatement(m_currentErrorCode) << endl; } @@ -5567,10 +5559,11 @@ bool CppGenerator::finishGeneration() { Indentation indentation(INDENT); s << INDENT << "PyObject *pyType = reinterpret_cast<PyObject *>(" << cppApiVariableName() << "[i]);" << endl; - s << INDENT << "if (pyType && PyObject_HasAttrString(pyType, \"staticMetaObject\"))"<< endl; + s << INDENT << "Shiboken::AutoDecRef attrName(Py_BuildValue(\"s\", \"staticMetaObject\"));" << endl; + s << INDENT << "if (pyType && PyObject_HasAttr(pyType, attrName))"<< endl; { Indentation indentation(INDENT); - s << INDENT << "PyObject_SetAttrString(pyType, \"staticMetaObject\", Py_None);" << endl; + s << INDENT << "PyObject_SetAttr(pyType, attrName, Py_None);" << endl; } } s << INDENT << "}" << endl; @@ -6034,7 +6027,7 @@ QString CppGenerator::writeReprFunction(QTextStream &s, s << INDENT << "str.replace(0, idx, Py_TYPE(self)->tp_name);" << endl; } s << INDENT << "str = str.trimmed();" << endl; - s << INDENT << "PyObject *mod = PyDict_GetItemString(Py_TYPE(self)->tp_dict, \"__module__\");" << endl; + s << INDENT << "PyObject *mod = PyDict_GetItem(Py_TYPE(self)->tp_dict, Shiboken::PyMagicName::module());" << endl; // PYSIDE-595: The introduction of heap types has the side effect that the module name // is always prepended to the type name. Therefore the strchr check: s << INDENT << "if (mod && !strchr(str, '.'))" << endl; diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.cpp b/sources/shiboken2/generator/shiboken2/headergenerator.cpp index 8a2c56232..e47c37523 100644 --- a/sources/shiboken2/generator/shiboken2/headergenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/headergenerator.cpp @@ -454,6 +454,11 @@ bool HeaderGenerator::finishGeneration() // TODO-CONVERTER ------------------------------------------------------------------------------ macrosStream << "// Macros for type check" << endl; + + if (usePySideExtensions()) { + typeFunctions << "QT_WARNING_PUSH" << endl; + typeFunctions << "QT_WARNING_DISABLE_DEPRECATED" << endl; + } for (const AbstractMetaEnum *cppEnum : qAsConst(globalEnums)) { if (cppEnum->isAnonymous() || cppEnum->isPrivate()) continue; @@ -489,6 +494,8 @@ bool HeaderGenerator::finishGeneration() includes << classType->include(); writeSbkTypeFunction(typeFunctions, metaType); } + if (usePySideExtensions()) + typeFunctions << "QT_WARNING_POP" << endl; QString moduleHeaderFileName(outputDirectory() + QDir::separator() + subDirectoryForPackage(packageName()) diff --git a/sources/shiboken2/generator/shiboken2/overloaddata.cpp b/sources/shiboken2/generator/shiboken2/overloaddata.cpp index 5c3d7d0b8..5f74ee64d 100644 --- a/sources/shiboken2/generator/shiboken2/overloaddata.cpp +++ b/sources/shiboken2/generator/shiboken2/overloaddata.cpp @@ -520,7 +520,7 @@ void OverloadData::addOverload(const AbstractMetaFunction *func) for (int i = 0; m_headOverloadData->m_minArgs > 0 && i < origNumArgs; i++) { if (func->argumentRemoved(i + 1)) continue; - if (!ShibokenGenerator::getDefaultValue(func, func->arguments().at(i)).isEmpty()) { + if (func->arguments().at(i)->hasDefaultValueExpression()) { int fixedArgIndex = i - removed; if (fixedArgIndex < m_headOverloadData->m_minArgs) m_headOverloadData->m_minArgs = fixedArgIndex; @@ -576,7 +576,7 @@ QStringList OverloadData::returnTypes() const else retTypes << QLatin1String("void"); } - return QStringList(retTypes.toList()); + return retTypes.values(); } bool OverloadData::hasNonVoidReturnType() const @@ -754,7 +754,7 @@ const AbstractMetaFunction *OverloadData::getFunctionWithDefaultValue() const if (func->argumentRemoved(i + 1)) removedArgs++; } - if (!ShibokenGenerator::getDefaultValue(func, func->arguments().at(m_argPos + removedArgs)).isEmpty()) + if (func->arguments().at(m_argPos + removedArgs)->hasDefaultValueExpression()) return func; } return nullptr; @@ -771,7 +771,7 @@ QVector<int> OverloadData::invalidArgumentLengths() const if (func->argumentRemoved(i+1)) { offset++; } else { - if (!ShibokenGenerator::getDefaultValue(func, args[i]).isEmpty()) + if (args.at(i)->hasDefaultValueExpression()) validArgLengths << i-offset; } } @@ -820,7 +820,7 @@ QPair<int, int> OverloadData::getMinMaxArguments(const AbstractMetaFunctionList if (func->argumentRemoved(j + 1)) continue; int fixedArgIndex = j - removed; - if (fixedArgIndex < minArgs && !ShibokenGenerator::getDefaultValue(func, func->arguments().at(j)).isEmpty()) + if (fixedArgIndex < minArgs && func->arguments().at(j)->hasDefaultValueExpression()) minArgs = fixedArgIndex; } } @@ -967,7 +967,7 @@ QString OverloadData::dumpGraph() const const AbstractMetaArgument *arg = argument(func); if (!arg) continue; - QString argDefault = ShibokenGenerator::getDefaultValue(func, arg); + QString argDefault = arg->defaultValueExpression(); if (!argDefault.isEmpty() || argDefault != arg->originalDefaultValueExpression()) { s << "<tr><td bgcolor=\"gray\" align=\"right\">f" << functionNumber(func); @@ -1038,7 +1038,7 @@ bool OverloadData::hasArgumentWithDefaultValue(const AbstractMetaFunction *func) for (const AbstractMetaArgument *arg : arguments) { if (func->argumentRemoved(arg->argumentIndex() + 1)) continue; - if (!ShibokenGenerator::getDefaultValue(func, arg).isEmpty()) + if (arg->hasDefaultValueExpression()) return true; } return false; @@ -1049,7 +1049,7 @@ AbstractMetaArgumentList OverloadData::getArgumentsWithDefaultValues(const Abstr AbstractMetaArgumentList args; const AbstractMetaArgumentList &arguments = func->arguments(); for (AbstractMetaArgument *arg : arguments) { - if (ShibokenGenerator::getDefaultValue(func, arg).isEmpty() + if (!arg->hasDefaultValueExpression() || func->argumentRemoved(arg->argumentIndex() + 1)) continue; args << arg; diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp index 2a8eefba6..67137369c 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -571,7 +571,7 @@ QString ShibokenGenerator::guessScopeForDefaultFlagsValue(const AbstractMetaFunc QString ShibokenGenerator::guessScopeForDefaultValue(const AbstractMetaFunction *func, const AbstractMetaArgument *arg) const { - QString value = getDefaultValue(func, arg); + QString value = arg->defaultValueExpression(); if (value.isEmpty() || arg->hasModifiedDefaultValueExpression() @@ -1255,6 +1255,11 @@ QString ShibokenGenerator::cpythonCheckFunction(const TypeEntry *type, bool gene QString ShibokenGenerator::guessCPythonCheckFunction(const QString &type, AbstractMetaType **metaType) { *metaType = nullptr; + // PYSIDE-795: We abuse PySequence for iterables. + // This part handles the overrides in the XML files. + if (type == QLatin1String("PySequence")) + return QLatin1String("Shiboken::String::checkIterable"); + if (type == QLatin1String("PyTypeObject")) return QLatin1String("PyType_Check"); @@ -2306,7 +2311,7 @@ AbstractMetaType *ShibokenGenerator::buildAbstractMetaTypeFromString(QString typ auto it = m_metaTypeFromStringCache.find(typeSignature); if (it == m_metaTypeFromStringCache.end()) { AbstractMetaType *metaType = - AbstractMetaBuilder::translateType(typeSignature, nullptr, true, errorMessage); + AbstractMetaBuilder::translateType(typeSignature, nullptr, {}, errorMessage); if (Q_UNLIKELY(!metaType)) { if (errorMessage) errorMessage->prepend(msgCannotBuildMetaType(typeSignature)); @@ -2708,22 +2713,6 @@ bool ShibokenGenerator::pythonFunctionWrapperUsesListOfArguments(const OverloadD || overloadData.hasArgumentWithDefaultValue(); } -QString ShibokenGenerator::getDefaultValue(const AbstractMetaFunction *func, const AbstractMetaArgument *arg) -{ - if (!arg->defaultValueExpression().isEmpty()) - return arg->defaultValueExpression(); - - //Check modifications - const FunctionModificationList &mods = func->modifications(); - for (const FunctionModification &m : mods) { - for (const ArgumentModification &am : m.argument_mods) { - if (am.index == (arg->argumentIndex() + 1)) - return am.replacedDefaultExpression; - } - } - return QString(); -} - void ShibokenGenerator::writeMinimalConstructorExpression(QTextStream &s, const AbstractMetaType *type, const QString &defaultCtor) { if (!defaultCtor.isEmpty()) { diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.h b/sources/shiboken2/generator/shiboken2/shibokengenerator.h index 84b3137b8..7970ceb94 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.h +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.h @@ -71,11 +71,6 @@ public: const char *name() const override { return "Shiboken"; } - /** - * Helper function to find for argument default value - */ - static QString getDefaultValue(const AbstractMetaFunction *func, const AbstractMetaArgument *arg); - /// Returns a list of all ancestor classes for the given class. AbstractMetaClassList getAllAncestors(const AbstractMetaClass *metaClass) const; diff --git a/sources/shiboken2/libshiboken/CMakeLists.txt b/sources/shiboken2/libshiboken/CMakeLists.txt index 7cbb22978..a38da8d89 100644 --- a/sources/shiboken2/libshiboken/CMakeLists.txt +++ b/sources/shiboken2/libshiboken/CMakeLists.txt @@ -30,8 +30,8 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/embed/signature_bootstrap.py" "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_bootstrap.py" @ONLY) add_custom_command( - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_bootstrap.inc" - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature.inc" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_bootstrap_inc.h" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/embed/signature_inc.h" COMMAND ${PYTHON_EXECUTABLE} -E "${CMAKE_CURRENT_SOURCE_DIR}/embed/embedding_generator.py" --cmake-dir "${CMAKE_CURRENT_BINARY_DIR}/embed" @@ -53,6 +53,7 @@ sbkconverter.cpp sbkenum.cpp sbkmodule.cpp sbkstring.cpp +sbkstaticstrings.cpp bindingmanager.cpp threadstatesaver.cpp shibokenbuffer.cpp @@ -62,8 +63,8 @@ pep384impl.cpp voidptr.cpp typespec.cpp bufferprocs_py37.cpp -embed/signature_bootstrap.inc -embed/signature.inc +embed/signature_bootstrap_inc.h +embed/signature_inc.h ) get_numpy_location() @@ -129,6 +130,7 @@ install(FILES python25compat.h sbkdbg.h sbkstring.h + sbkstaticstrings.h shiboken.h shibokenmacros.h threadstatesaver.h diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp index 9d233b847..000035627 100644 --- a/sources/shiboken2/libshiboken/basewrapper.cpp +++ b/sources/shiboken2/libshiboken/basewrapper.cpp @@ -44,6 +44,7 @@ #include "sbkconverter.h" #include "sbkenum.h" #include "sbkstring.h" +#include "sbkstaticstrings_p.h" #include "autodecref.h" #include "gilstate.h" #include <string> @@ -160,11 +161,10 @@ patch_tp_new_wrapper(PyTypeObject *type) * The old tp_new_wrapper is added to all types that have tp_new. * We patch that with a version that ignores the heaptype flag. */ - static PyObject *__new__ = nullptr; + auto newMethod = Shiboken::PyMagicName::new_(); if (old_tp_new_wrapper == nullptr) { - if ((__new__ = Py_BuildValue("s", "__new__")) == nullptr) - return -1; - PyObject *func = PyDict_GetItem(PyType_Type.tp_dict, __new__); + PyObject *func = PyDict_GetItem(PyType_Type.tp_dict, newMethod); + assert(func); PyCFunctionObject *pycf_ob = reinterpret_cast<PyCFunctionObject *>(func); old_tp_new_wrapper = reinterpret_cast<ternaryfunc>(pycf_ob->m_ml->ml_meth); } @@ -172,7 +172,7 @@ patch_tp_new_wrapper(PyTypeObject *type) Py_ssize_t i, n = PyTuple_GET_SIZE(mro); for (i = 0; i < n; i++) { type = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, i)); - PyObject *existing = PyDict_GetItem(type->tp_dict, __new__); + PyObject *existing = PyDict_GetItem(type->tp_dict, newMethod); if (existing && PyCFunction_Check(existing) && type->tp_flags & Py_TPFLAGS_HEAPTYPE) { auto *pycf_ob = reinterpret_cast<PyCFunctionObject *>(existing); @@ -182,7 +182,7 @@ patch_tp_new_wrapper(PyTypeObject *type) if (existing_wrapper == old_tp_new_wrapper) { PyObject *ob_type = reinterpret_cast<PyObject *>(type); Shiboken::AutoDecRef func(PyCFunction_New(tp_new_methoddef, ob_type)); - if (func.isNull() || PyDict_SetItem(type->tp_dict, __new__, func)) + if (func.isNull() || PyDict_SetItem(type->tp_dict, newMethod, func)) return -1; } } diff --git a/sources/shiboken2/libshiboken/embed/embedding_generator.py b/sources/shiboken2/libshiboken/embed/embedding_generator.py index 77aa5c329..15f63649b 100644 --- a/sources/shiboken2/libshiboken/embed/embedding_generator.py +++ b/sources/shiboken2/libshiboken/embed/embedding_generator.py @@ -88,7 +88,7 @@ def create_zipfile(limited_api): and make a chunked base64 encoded file from it. """ zip_name = "signature.zip" - inc_name = "signature.inc" + inc_name = "signature_inc.h" flag = '-b' if sys.version_info >= (3,) else '' os.chdir(work_dir) @@ -131,7 +131,7 @@ def create_zipfile(limited_api): tmp.close() # also generate a simple embeddable .pyc file for signature_bootstrap.pyc boot_name = "signature_bootstrap.py" if limited_api else "signature_bootstrap.pyc" - with open(boot_name, "rb") as ldr, open("signature_bootstrap.inc", "w") as inc: + with open(boot_name, "rb") as ldr, open("signature_bootstrap_inc.h", "w") as inc: _embed_bytefile(ldr, inc, limited_api) os.chdir(cur_dir) diff --git a/sources/shiboken2/libshiboken/helper.cpp b/sources/shiboken2/libshiboken/helper.cpp index fac72d56f..013080b6e 100644 --- a/sources/shiboken2/libshiboken/helper.cpp +++ b/sources/shiboken2/libshiboken/helper.cpp @@ -39,6 +39,7 @@ #include "helper.h" #include "sbkstring.h" +#include "sbkstaticstrings.h" #include <stdarg.h> #ifdef _WIN32 @@ -78,7 +79,7 @@ bool listToArgcArgv(PyObject *argList, int *argc, char ***argv, const char *defa if (hasEmptyArgList) { // Try to get the script name PyObject *globals = PyEval_GetGlobals(); - PyObject *appName = PyDict_GetItemString(globals, "__file__"); + PyObject *appName = PyDict_GetItem(globals, Shiboken::PyMagicName::file()); (*argv)[0] = strdup(appName ? Shiboken::String::toCString(appName) : defaultAppName); } else { for (int i = 0; i < numArgs; ++i) { diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp index fe7157d24..5729100bf 100644 --- a/sources/shiboken2/libshiboken/pep384impl.cpp +++ b/sources/shiboken2/libshiboken/pep384impl.cpp @@ -39,6 +39,8 @@ #include "pep384impl.h" #include "autodecref.h" +#include "sbkstaticstrings.h" +#include "sbkstaticstrings_p.h" extern "C" { @@ -85,14 +87,15 @@ static PyGetSetDef probe_getseters[] = { #define probe_tp_str make_dummy(2) #define probe_tp_traverse make_dummy(3) #define probe_tp_clear make_dummy(4) +#define probe_tp_iternext make_dummy(5) #define probe_tp_methods probe_methoddef #define probe_tp_getset probe_getseters -#define probe_tp_descr_get make_dummy(7) -#define probe_tp_init make_dummy(8) -#define probe_tp_alloc make_dummy(9) -#define probe_tp_new make_dummy(10) -#define probe_tp_free make_dummy(11) -#define probe_tp_is_gc make_dummy(12) +#define probe_tp_descr_get make_dummy(8) +#define probe_tp_init make_dummy(9) +#define probe_tp_alloc make_dummy(10) +#define probe_tp_new make_dummy(11) +#define probe_tp_free make_dummy(12) +#define probe_tp_is_gc make_dummy(13) #define probe_tp_name "type.probe" #define probe_tp_basicsize make_dummy_int(42) @@ -102,6 +105,7 @@ static PyType_Slot typeprobe_slots[] = { {Py_tp_str, probe_tp_str}, {Py_tp_traverse, probe_tp_traverse}, {Py_tp_clear, probe_tp_clear}, + {Py_tp_iternext, probe_tp_iternext}, {Py_tp_methods, probe_tp_methods}, {Py_tp_getset, probe_tp_getset}, {Py_tp_descr_get, probe_tp_descr_get}, @@ -125,16 +129,16 @@ check_PyTypeObject_valid() { auto *obtype = reinterpret_cast<PyObject *>(&PyType_Type); auto *probe_tp_base = reinterpret_cast<PyTypeObject *>( - PyObject_GetAttrString(obtype, "__base__")); - PyObject *probe_tp_bases = PyObject_GetAttrString(obtype, "__bases__"); + PyObject_GetAttr(obtype, Shiboken::PyMagicName::base())); + auto *probe_tp_bases = PyObject_GetAttr(obtype, Shiboken::PyMagicName::bases()); auto *check = reinterpret_cast<PyTypeObject *>( PyType_FromSpecWithBases(&typeprobe_spec, probe_tp_bases)); auto *typetype = reinterpret_cast<PyTypeObject *>(obtype); - PyObject *w = PyObject_GetAttrString(obtype, "__weakrefoffset__"); + PyObject *w = PyObject_GetAttr(obtype, Shiboken::PyMagicName::weakrefoffset()); long probe_tp_weakrefoffset = PyLong_AsLong(w); - PyObject *d = PyObject_GetAttrString(obtype, "__dictoffset__"); + PyObject *d = PyObject_GetAttr(obtype, Shiboken::PyMagicName::dictoffset()); long probe_tp_dictoffset = PyLong_AsLong(d); - PyObject *probe_tp_mro = PyObject_GetAttrString(obtype, "__mro__"); + PyObject *probe_tp_mro = PyObject_GetAttr(obtype, Shiboken::PyMagicName::mro()); if (false || strcmp(probe_tp_name, check->tp_name) != 0 || probe_tp_basicsize != check->tp_basicsize @@ -143,6 +147,7 @@ check_PyTypeObject_valid() || probe_tp_traverse != check->tp_traverse || probe_tp_clear != check->tp_clear || probe_tp_weakrefoffset != typetype->tp_weaklistoffset + || probe_tp_iternext != check->tp_iternext || probe_tp_methods != check->tp_methods || probe_tp_getset != check->tp_getset || probe_tp_base != typetype->tp_base @@ -416,9 +421,10 @@ PepRun_GetResult(const char *command, const char *resvar) PyObject *d, *v, *res; d = PyDict_New(); - if (d == NULL || PyDict_SetItemString(d, "__builtins__", - PyEval_GetBuiltins()) < 0) - return NULL; + if (d == nullptr + || PyDict_SetItem(d, Shiboken::PyMagicName::builtins(), PyEval_GetBuiltins()) < 0) { + return nullptr; + } v = PyRun_String(command, Py_file_input, d, d); res = v ? PyDict_GetItemString(d, resvar) : NULL; Py_XDECREF(v); @@ -457,7 +463,7 @@ PyMethod_New(PyObject *func, PyObject *self) PyObject * PyMethod_Function(PyObject *im) { - PyObject *ret = PyObject_GetAttrString(im, "__func__"); + PyObject *ret = PyObject_GetAttr(im, Shiboken::PyMagicName::func()); // We have to return a borrowed reference. Py_DECREF(ret); @@ -467,7 +473,7 @@ PyMethod_Function(PyObject *im) PyObject * PyMethod_Self(PyObject *im) { - PyObject *ret = PyObject_GetAttrString(im, "__self__"); + PyObject *ret = PyObject_GetAttr(im, Shiboken::PyMagicName::self()); // We have to return a borrowed reference. // If we don't obey that here, then we get a test error! @@ -620,8 +626,8 @@ _Pep_PrivateMangle(PyObject *self, PyObject *name) return name; } #endif - Shiboken::AutoDecRef privateobj(PyObject_GetAttrString( - reinterpret_cast<PyObject *>(Py_TYPE(self)), "__name__")); + Shiboken::AutoDecRef privateobj(PyObject_GetAttr( + reinterpret_cast<PyObject *>(Py_TYPE(self)), Shiboken::PyMagicName::name())); #ifndef Py_LIMITED_API return _Py_Mangle(privateobj, name); #else diff --git a/sources/shiboken2/libshiboken/pep384impl.h b/sources/shiboken2/libshiboken/pep384impl.h index 93f718988..1aa7e6fc0 100644 --- a/sources/shiboken2/libshiboken/pep384impl.h +++ b/sources/shiboken2/libshiboken/pep384impl.h @@ -110,7 +110,7 @@ typedef struct _typeobject { void *X23; // richcmpfunc tp_richcompare; Py_ssize_t tp_weaklistoffset; void *X25; // getiterfunc tp_iter; - void *X26; // iternextfunc tp_iternext; + iternextfunc tp_iternext; struct PyMethodDef *tp_methods; void *X28; // struct PyMemberDef *tp_members; struct PyGetSetDef *tp_getset; diff --git a/sources/shiboken2/libshiboken/sbkenum.cpp b/sources/shiboken2/libshiboken/sbkenum.cpp index 2dc785884..71fcf5f64 100644 --- a/sources/shiboken2/libshiboken/sbkenum.cpp +++ b/sources/shiboken2/libshiboken/sbkenum.cpp @@ -412,13 +412,6 @@ PyTypeObject *createScopedEnum(SbkObjectType *scope, const char *name, const cha static PyObject *createEnumItem(PyTypeObject *enumType, const char *itemName, long itemValue) { - char mangled[20]; - if (strcmp(itemName, "None") == 0 - || strcmp(itemName, "False") == 0 || strcmp(itemName, "True") == 0) { - strcpy(mangled, itemName); - strcat(mangled, "_"); - itemName = mangled; - } PyObject *enumItem = newItem(enumType, itemValue, itemName); if (PyDict_SetItemString(enumType->tp_dict, itemName, enumItem) < 0) return nullptr; diff --git a/sources/shiboken2/libshiboken/sbkstaticstrings.cpp b/sources/shiboken2/libshiboken/sbkstaticstrings.cpp new file mode 100644 index 000000000..3727eb494 --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkstaticstrings.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $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$ +** +****************************************************************************/ + +#include "sbkstaticstrings.h" +#include "sbkstaticstrings_p.h" +#include "sbkstring.h" + +#define STATIC_STRING_IMPL(funcName, value) \ +PyObject *funcName() \ +{ \ + static PyObject *const s = Shiboken::String::createStaticString(value); \ + return s; \ +} + +namespace Shiboken +{ +namespace PyName { +// exported: +STATIC_STRING_IMPL(dumps, "dumps") +STATIC_STRING_IMPL(loads, "loads") + +// Internal: +STATIC_STRING_IMPL(classmethod, "classmethod") +STATIC_STRING_IMPL(compile, "compile"); +STATIC_STRING_IMPL(function, "function") +STATIC_STRING_IMPL(marshal, "marshal") +STATIC_STRING_IMPL(method, "method") +STATIC_STRING_IMPL(overload, "overload") +STATIC_STRING_IMPL(staticmethod, "staticmethod") +} // namespace PyName + +namespace PyMagicName { +// exported: +STATIC_STRING_IMPL(class_, "__class__") +STATIC_STRING_IMPL(ecf, "__ecf__") +STATIC_STRING_IMPL(file, "__file__") +STATIC_STRING_IMPL(module, "__module__") +STATIC_STRING_IMPL(name, "__name__") + +// Internal: +STATIC_STRING_IMPL(base, "__base__") +STATIC_STRING_IMPL(bases, "__bases__") +STATIC_STRING_IMPL(builtins, "__builtins__") +STATIC_STRING_IMPL(code, "__code__") +STATIC_STRING_IMPL(dictoffset, "__dictoffset__") +STATIC_STRING_IMPL(func, "__func__") +STATIC_STRING_IMPL(func_kind, "__func_kind__") +STATIC_STRING_IMPL(iter, "__iter__") +STATIC_STRING_IMPL(mro, "__mro__") +STATIC_STRING_IMPL(new_, "__new__") +STATIC_STRING_IMPL(objclass, "__objclass__") +STATIC_STRING_IMPL(self, "__self__") +STATIC_STRING_IMPL(signature, "__signature__") +STATIC_STRING_IMPL(weakrefoffset, "__weakrefoffset__") +} // namespace PyMagicName +} // namespace Shiboken diff --git a/sources/shiboken2/libshiboken/sbkstaticstrings.h b/sources/shiboken2/libshiboken/sbkstaticstrings.h new file mode 100644 index 000000000..fa21a8e2c --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkstaticstrings.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $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$ +** +****************************************************************************/ + +#ifndef SBKSTATICSTRINGS_H +#define SBKSTATICSTRINGS_H + +#include "sbkpython.h" +#include "shibokenmacros.h" + +namespace Shiboken +{ +// Some often-used strings +namespace PyName +{ +LIBSHIBOKEN_API PyObject *dumps(); +LIBSHIBOKEN_API PyObject *loads(); +} // namespace PyName + +namespace PyMagicName +{ +LIBSHIBOKEN_API PyObject *class_(); +LIBSHIBOKEN_API PyObject *ecf(); +LIBSHIBOKEN_API PyObject *file(); +LIBSHIBOKEN_API PyObject *module(); +LIBSHIBOKEN_API PyObject *name(); +} // namespace PyMagicName +} // namespace Shiboken + +#endif // SBKSTATICSTRINGS_H diff --git a/sources/shiboken2/libshiboken/sbkstaticstrings_p.h b/sources/shiboken2/libshiboken/sbkstaticstrings_p.h new file mode 100644 index 000000000..42c5585fa --- /dev/null +++ b/sources/shiboken2/libshiboken/sbkstaticstrings_p.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $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$ +** +****************************************************************************/ + +#include "sbkpython.h" +#include "shibokenmacros.h" + +namespace Shiboken +{ +namespace PyName +{ +PyObject *classmethod(); +PyObject *compile(); +PyObject *function(); +PyObject *marshal(); +PyObject *method(); +PyObject *overload(); +PyObject *staticmethod(); +} // namespace PyName +namespace PyMagicName +{ +PyObject *base(); +PyObject *bases(); +PyObject *builtins(); +PyObject *code(); +PyObject *dictoffset(); +PyObject *func(); +PyObject *func_kind(); +PyObject *iter(); +PyObject *module(); +PyObject *mro(); +PyObject *new_(); +PyObject *objclass(); +PyObject *self(); +PyObject *signature(); +PyObject *weakrefoffset(); +} // namespace PyMagicName +} // namespace Shiboken diff --git a/sources/shiboken2/libshiboken/sbkstring.cpp b/sources/shiboken2/libshiboken/sbkstring.cpp index 9ba5be281..4a441222f 100644 --- a/sources/shiboken2/libshiboken/sbkstring.cpp +++ b/sources/shiboken2/libshiboken/sbkstring.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt for Python. @@ -38,14 +38,23 @@ ****************************************************************************/ #include "sbkstring.h" +#include "sbkstaticstrings_p.h" #include "autodecref.h" +#include <vector> + namespace Shiboken { namespace String { +// PYSIDE-795: Redirecting PySequence to Iterable +bool checkIterable(PyObject *obj) +{ + return PyObject_HasAttr(obj, Shiboken::PyMagicName::iter()); +} + bool checkType(PyTypeObject *type) { return type == &PyUnicode_Type @@ -200,6 +209,64 @@ Py_ssize_t len(PyObject *str) return 0; } -} // namespace String +/////////////////////////////////////////////////////////////////////// +// +// Implementation of efficient Python strings +// ------------------------------------------ +// +// Instead of repetitively executing +// +// PyObject *attr = PyObject_GetAttrString(obj, "__name__"); +// +// a helper of the form +// +// PyObject *name() +// { +// static PyObject *const s = Shiboken::String::createStaticString("__name__"); +// return result; +// } +// +// can now be implemented, which registers the string into a static set avoiding +// repetitive string creation. The resulting code looks like: +// +// PyObject *attr = PyObject_GetAttr(obj, name()); +// +// Missing: +// There is no finalization for the string structures, yet. +// But this is a global fault in shiboken. We are missing a true +// finalization like in all other modules. + +using StaticStrings = std::vector<PyObject *>; +static StaticStrings &staticStrings() +{ + static StaticStrings result; + return result; +} + +PyObject *createStaticString(const char *str) +{ +#if PY_VERSION_HEX >= 0x03000000 + PyObject *result = PyUnicode_InternFromString(str); +#else + PyObject *result = PyString_InternFromString(str); +#endif + if (result == nullptr) { + // This error is never checked, but also very unlikely. Report and exit. + PyErr_Print(); + Py_FatalError("unexpected error in createStaticString()"); + } + staticStrings().push_back(result); + return result; +} + +void finalizeStaticStrings() // Currently unused +{ + auto &list = staticStrings(); + for (auto s : list) + Py_DECREF(s); + list.clear(); +} + +} // namespace String } // namespace Shiboken diff --git a/sources/shiboken2/libshiboken/sbkstring.h b/sources/shiboken2/libshiboken/sbkstring.h index 7f434e1b9..84d7768c5 100644 --- a/sources/shiboken2/libshiboken/sbkstring.h +++ b/sources/shiboken2/libshiboken/sbkstring.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt for Python. @@ -43,17 +43,12 @@ #include "sbkpython.h" #include "shibokenmacros.h" -#if PY_MAJOR_VERSION >= 3 - #define SBK_BYTES_NAME "bytes" -#else - #define SBK_BYTES_NAME "str" -#endif - namespace Shiboken { namespace String { LIBSHIBOKEN_API bool check(PyObject *obj); + LIBSHIBOKEN_API bool checkIterable(PyObject *obj); LIBSHIBOKEN_API bool checkType(PyTypeObject *obj); LIBSHIBOKEN_API bool checkChar(PyObject *obj); LIBSHIBOKEN_API bool isConvertible(PyObject *obj); @@ -65,6 +60,7 @@ namespace String LIBSHIBOKEN_API PyObject *fromStringAndSize(const char *str, Py_ssize_t size); LIBSHIBOKEN_API int compare(PyObject *val1, const char *val2); LIBSHIBOKEN_API Py_ssize_t len(PyObject *str); + LIBSHIBOKEN_API PyObject *createStaticString(const char *str); } // namespace String } // namespace Shiboken diff --git a/sources/shiboken2/libshiboken/shiboken.h b/sources/shiboken2/libshiboken/shiboken.h index 1356670aa..0d2d6b0a6 100644 --- a/sources/shiboken2/libshiboken/shiboken.h +++ b/sources/shiboken2/libshiboken/shiboken.h @@ -52,6 +52,7 @@ #include "sbkenum.h" #include "sbkmodule.h" #include "sbkstring.h" +#include "sbkstaticstrings.h" #include "shibokenmacros.h" #include "shibokenbuffer.h" diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp index 0afdbcdc9..5430ab064 100644 --- a/sources/shiboken2/libshiboken/signature.cpp +++ b/sources/shiboken2/libshiboken/signature.cpp @@ -39,6 +39,8 @@ #include "basewrapper.h" #include "autodecref.h" +#include "sbkstaticstrings.h" +#include "sbkstaticstrings_p.h" extern "C" { @@ -51,11 +53,11 @@ extern "C" // These constants were needed in former versions of the module: #define PYTHON_HAS_QUALNAME (PY_VERSION_HEX >= 0x03030000) -#define PYTHON_HAS_UNICODE (PY_VERSION_HEX >= 0x03000000) #define PYTHON_HAS_WEAKREF_PYCFUNCTION (PY_VERSION_HEX >= 0x030500A0) #define PYTHON_IS_PYTHON3 (PY_VERSION_HEX >= 0x03000000) #define PYTHON_HAS_KEYWORDONLY (PYTHON_IS_PYTHON3) #define PYTHON_USES_PERCENT_V_FORMAT (PYTHON_IS_PYTHON3) +#define PYTHON_USES_D_COMMON (PY_VERSION_HEX >= 0x03020000) #define PYTHON_HAS_DESCR_REDUCE (PY_VERSION_HEX >= 0x03040000) #define PYTHON_HAS_METH_REDUCE (PYTHON_HAS_DESCR_REDUCE) #define PYTHON_NEEDS_ITERATOR_FLAG (!PYTHON_IS_PYTHON3) @@ -64,7 +66,7 @@ extern "C" #define PYTHON_HAS_INT_AND_LONG (!PYTHON_IS_PYTHON3) // These constants are still in use: -#define PYTHON_USES_D_COMMON (PY_VERSION_HEX >= 0x03020000) +#define PYTHON_USES_UNICODE (PY_VERSION_HEX >= 0x03000000) typedef struct safe_globals_struc { // init part 1: get arg_dict @@ -77,17 +79,18 @@ typedef struct safe_globals_struc { PyObject *create_signature_func; PyObject *seterror_argument_func; PyObject *make_helptext_func; + PyObject *finish_import_func; } safe_globals_struc, *safe_globals; static safe_globals pyside_globals = nullptr; static PyObject *GetTypeKey(PyObject *ob); -static PyObject *GetSignature_Function(PyObject *, const char *); -static PyObject *GetSignature_TypeMod(PyObject *, const char *); -static PyObject *GetSignature_Wrapper(PyObject *, const char *); +static PyObject *GetSignature_Function(PyObject *, PyObject *); +static PyObject *GetSignature_TypeMod(PyObject *, PyObject *); +static PyObject *GetSignature_Wrapper(PyObject *, PyObject *); static PyObject *get_signature(PyObject *self, PyObject *args); -static PyObject *get_signature_intern(PyObject *ob, const char *modifier); +static PyObject *get_signature_intern(PyObject *ob, PyObject *modifier); static PyObject *PySide_BuildSignatureProps(PyObject *class_mod); @@ -107,10 +110,10 @@ CreateSignature(PyObject *props, PyObject *key) const_cast<char *>("(OO)"), props, key); } -typedef PyObject *(*signaturefunc)(PyObject *, const char *); +typedef PyObject *(*signaturefunc)(PyObject *, PyObject *); static PyObject * -_get_written_signature(signaturefunc sf, PyObject *ob, const char *modifier) +_get_written_signature(signaturefunc sf, PyObject *ob, PyObject *modifier) { /* * Be a writable Attribute, but have a computed value. @@ -133,19 +136,19 @@ _get_written_signature(signaturefunc sf, PyObject *ob, const char *modifier) } static PyObject * -pyside_cf_get___signature__(PyObject *func, const char *modifier) +pyside_cf_get___signature__(PyObject *func, PyObject *modifier) { init_module_2(); return _get_written_signature(GetSignature_Function, func, modifier); } static PyObject * -pyside_sm_get___signature__(PyObject *sm, const char *modifier) +pyside_sm_get___signature__(PyObject *sm, PyObject *modifier) { init_module_2(); - Shiboken::AutoDecRef func(PyObject_GetAttrString(sm, "__func__")); + Shiboken::AutoDecRef func(PyObject_GetAttr(sm, Shiboken::PyMagicName::func())); if (Py_TYPE(func) == PepFunction_TypePtr) - return PyObject_GetAttrString(func, "__signature__"); + return PyObject_GetAttr(func, Shiboken::PyMagicName::signature()); return _get_written_signature(GetSignature_Function, func, modifier); } @@ -157,7 +160,7 @@ _get_class_of_cf(PyObject *ob_cf) selftype = PyDict_GetItem(pyside_globals->map_dict, ob_cf); if (selftype == nullptr) { // This must be an overloaded function that we handled special. - Shiboken::AutoDecRef special(Py_BuildValue("(Os)", ob_cf, "overload")); + Shiboken::AutoDecRef special(Py_BuildValue("(OO)", ob_cf, Shiboken::PyName::overload())); selftype = PyDict_GetItem(pyside_globals->map_dict, special); if (selftype == nullptr) { // This is probably a module function. We will return type(None). @@ -175,15 +178,15 @@ _get_class_of_cf(PyObject *ob_cf) static PyObject * _get_class_of_sm(PyObject *ob_sm) { - Shiboken::AutoDecRef func(PyObject_GetAttrString(ob_sm, "__func__")); + Shiboken::AutoDecRef func(PyObject_GetAttr(ob_sm, Shiboken::PyMagicName::func())); return _get_class_of_cf(func); } static PyObject * _get_class_of_descr(PyObject *ob) { - Shiboken::AutoDecRef func_name(PyObject_GetAttrString(ob, "__name__")); - return PyObject_GetAttrString(ob, "__objclass__"); + Shiboken::AutoDecRef func_name(PyObject_GetAttr(ob, Shiboken::PyMagicName::name())); + return PyObject_GetAttr(ob, Shiboken::PyMagicName::objclass()); } static PyObject * @@ -215,10 +218,10 @@ get_funcname(PyObject *ob) { PyObject *func = ob; if (Py_TYPE(ob) == PepStaticMethod_TypePtr) - func = PyObject_GetAttrString(ob, "__func__"); + func = PyObject_GetAttr(ob, Shiboken::PyMagicName::func()); else Py_INCREF(func); - PyObject *func_name = PyObject_GetAttrString(func, "__name__"); + PyObject *func_name = PyObject_GetAttr(func, Shiboken::PyMagicName::name()); Py_DECREF(func); if (func_name == nullptr) Py_FatalError("unexpected name problem in compute_name_key"); @@ -286,7 +289,7 @@ name_key_to_func(PyObject *ob) } static PyObject * -pyside_md_get___signature__(PyObject *ob_md, const char *modifier) +pyside_md_get___signature__(PyObject *ob_md, PyObject *modifier) { init_module_2(); Shiboken::AutoDecRef func(name_key_to_func(ob_md)); @@ -298,14 +301,14 @@ pyside_md_get___signature__(PyObject *ob_md, const char *modifier) } static PyObject * -pyside_wd_get___signature__(PyObject *ob, const char *modifier) +pyside_wd_get___signature__(PyObject *ob, PyObject *modifier) { init_module_2(); return _get_written_signature(GetSignature_Wrapper, ob, modifier); } static PyObject * -pyside_tp_get___signature__(PyObject *obtype_mod, const char *modifier) +pyside_tp_get___signature__(PyObject *obtype_mod, PyObject *modifier) { init_module_2(); return _get_written_signature(GetSignature_TypeMod, obtype_mod, modifier); @@ -313,7 +316,7 @@ pyside_tp_get___signature__(PyObject *obtype_mod, const char *modifier) // forward static PyObject * -GetSignature_Cached(PyObject *props, const char *func_kind, const char *modifier); +GetSignature_Cached(PyObject *props, PyObject *func_kind, PyObject *modifier); static PyObject * GetTypeKey(PyObject *ob) @@ -331,8 +334,8 @@ GetTypeKey(PyObject *ob) * * This is the PyCFunction behavior, as opposed to Python functions. */ - Shiboken::AutoDecRef class_name(PyObject_GetAttrString(ob, "__name__")); - Shiboken::AutoDecRef module_name(PyObject_GetAttrString(ob, "__module__")); + Shiboken::AutoDecRef class_name(PyObject_GetAttr(ob, Shiboken::PyMagicName::name())); + Shiboken::AutoDecRef module_name(PyObject_GetAttr(ob, Shiboken::PyMagicName::module())); if (module_name.isNull()) PyErr_Clear(); @@ -363,7 +366,7 @@ TypeKey_to_PropsDict(PyObject *type_key, PyObject *obtype) } static PyObject * -GetSignature_Function(PyObject *obfunc, const char *modifier) +GetSignature_Function(PyObject *obfunc, PyObject *modifier) { // make sure that we look into PyCFunction, only... if (Py_TYPE(obfunc) == PepFunction_TypePtr) @@ -375,29 +378,29 @@ GetSignature_Function(PyObject *obfunc, const char *modifier) PyObject *dict = TypeKey_to_PropsDict(type_key, obtype_mod); if (dict == nullptr) return nullptr; - Shiboken::AutoDecRef func_name(PyObject_GetAttrString(obfunc, "__name__")); + Shiboken::AutoDecRef func_name(PyObject_GetAttr(obfunc, Shiboken::PyMagicName::name())); PyObject *props = !func_name.isNull() ? PyDict_GetItem(dict, func_name) : nullptr; if (props == nullptr) Py_RETURN_NONE; int flags = PyCFunction_GET_FLAGS(obfunc); - const char *func_kind; + PyObject *func_kind; if (PyModule_Check(obtype_mod)) - func_kind = "function"; + func_kind = Shiboken::PyName::function(); else if (flags & METH_CLASS) - func_kind = "classmethod"; + func_kind = Shiboken::PyName::classmethod(); else if (flags & METH_STATIC) - func_kind = "staticmethod"; + func_kind = Shiboken::PyName::staticmethod(); else - func_kind = "method"; + func_kind = Shiboken::PyName::method(); return GetSignature_Cached(props, func_kind, modifier); } static PyObject * -GetSignature_Wrapper(PyObject *ob, const char *modifier) +GetSignature_Wrapper(PyObject *ob, PyObject *modifier) { - Shiboken::AutoDecRef func_name(PyObject_GetAttrString(ob, "__name__")); - Shiboken::AutoDecRef objclass(PyObject_GetAttrString(ob, "__objclass__")); + Shiboken::AutoDecRef func_name(PyObject_GetAttr(ob, Shiboken::PyMagicName::name())); + Shiboken::AutoDecRef objclass(PyObject_GetAttr(ob, Shiboken::PyMagicName::objclass())); Shiboken::AutoDecRef class_key(GetTypeKey(objclass)); if (func_name.isNull() || objclass.isNull() || class_key.isNull()) @@ -408,13 +411,13 @@ GetSignature_Wrapper(PyObject *ob, const char *modifier) PyObject *props = PyDict_GetItem(dict, func_name); if (props == nullptr) Py_RETURN_NONE; - return GetSignature_Cached(props, "method", modifier); + return GetSignature_Cached(props, Shiboken::PyName::method(), modifier); } static PyObject * -GetSignature_TypeMod(PyObject *ob, const char *modifier) +GetSignature_TypeMod(PyObject *ob, PyObject *modifier) { - Shiboken::AutoDecRef ob_name(PyObject_GetAttrString(ob, "__name__")); + Shiboken::AutoDecRef ob_name(PyObject_GetAttr(ob, Shiboken::PyMagicName::name())); Shiboken::AutoDecRef ob_key(GetTypeKey(ob)); PyObject *dict = TypeKey_to_PropsDict(ob_key, ob); @@ -423,19 +426,26 @@ GetSignature_TypeMod(PyObject *ob, const char *modifier) PyObject *props = PyDict_GetItem(dict, ob_name); if (props == nullptr) Py_RETURN_NONE; - return GetSignature_Cached(props, "method", modifier); + return GetSignature_Cached(props, Shiboken::PyName::method(), modifier); } static PyObject * -GetSignature_Cached(PyObject *props, const char *func_kind, const char *modifier) +GetSignature_Cached(PyObject *props, PyObject *func_kind, PyObject *modifier) { // Special case: We want to know the func_kind. - if (modifier && strcmp(modifier, "__func_kind__") == 0) - return Py_BuildValue("s", func_kind); + if (modifier) { +#if PYTHON_USES_UNICODE + PyUnicode_InternInPlace(&modifier); +#else + PyString_InternInPlace(&modifier); +#endif + if (modifier == Shiboken::PyMagicName::func_kind()) + return Py_BuildValue("O", func_kind); + } Shiboken::AutoDecRef key(modifier == nullptr - ? Py_BuildValue("s", func_kind) - : Py_BuildValue("(ss)", func_kind, modifier)); + ? Py_BuildValue("O", func_kind) + : Py_BuildValue("(OO)", func_kind, modifier)); PyObject *value = PyDict_GetItem(props, key); if (value == nullptr) { // we need to compute a signature object @@ -454,11 +464,11 @@ GetSignature_Cached(PyObject *props, const char *func_kind, const char *modifier } static const char *PySide_CompressedSignaturePackage[] = { -#include "embed/signature.inc" +#include "embed/signature_inc.h" }; static const unsigned char PySide_SignatureLoader[] = { -#include "embed/signature_bootstrap.inc" +#include "embed/signature_bootstrap_inc.h" }; static safe_globals_struc * @@ -477,13 +487,10 @@ init_phase_1(void) #ifdef Py_LIMITED_API // We must work for multiple versions, so use source code. #else - Shiboken::AutoDecRef marshal_str(Py_BuildValue("s", "marshal")); - if (marshal_str.isNull()) - goto error; - Shiboken::AutoDecRef marshal_module(PyImport_Import(marshal_str)); + Shiboken::AutoDecRef marshal_module(PyImport_Import(Shiboken::PyName::marshal())); if (marshal_module.isNull()) goto error; - Shiboken::AutoDecRef loads(PyObject_GetAttrString(marshal_module, "loads")); + Shiboken::AutoDecRef loads(PyObject_GetAttr(marshal_module, Shiboken::PyName::loads())); if (loads.isNull()) goto error; #endif @@ -495,7 +502,7 @@ init_phase_1(void) goto error; #ifdef Py_LIMITED_API PyObject *builtins = PyEval_GetBuiltins(); - PyObject *compile = PyDict_GetItemString(builtins, "compile"); + PyObject *compile = PyDict_GetItem(builtins, Shiboken::PyName::compile()); if (compile == nullptr) goto error; Shiboken::AutoDecRef code_obj(PyObject_CallFunction(compile, "Oss", @@ -512,7 +519,7 @@ init_phase_1(void) goto error; // Initialize the module PyObject *mdict = PyModule_GetDict(p->helper_module); - if (PyDict_SetItemString(mdict, "__builtins__", PyEval_GetBuiltins()) < 0) + if (PyDict_SetItem(mdict, Shiboken::PyMagicName::builtins(), PyEval_GetBuiltins()) < 0) goto error; /* * Unpack an embedded ZIP file with more signature modules. @@ -551,11 +558,14 @@ init_phase_1(void) if (p->value_dict == nullptr) goto error; + // This function will be disabled until phase 2 is done. + p->finish_import_func = nullptr; + return p; } error: PyErr_Print(); - PyErr_SetString(PyExc_SystemError, "could not initialize part 1"); + Py_FatalError("could not initialize part 1"); return nullptr; } @@ -593,11 +603,14 @@ init_phase_2(safe_globals_struc *p, PyMethodDef *methods) p->make_helptext_func = PyObject_GetAttrString(loader, "make_helptext"); if (p->make_helptext_func == nullptr) goto error; + p->finish_import_func = PyObject_GetAttrString(loader, "finish_import"); + if (p->finish_import_func == nullptr) + goto error; return 0; } error: PyErr_Print(); - PyErr_SetString(PyExc_SystemError, "could not initialize part 2"); + Py_FatalError("could not initialize part 2"); return -1; } @@ -795,7 +808,7 @@ static PyGetSetDef new_PyWrapperDescr_getsets[] = { // static PyObject * -get_signature_intern(PyObject *ob, const char *modifier) +get_signature_intern(PyObject *ob, PyObject *modifier) { if (PyType_IsSubtype(Py_TYPE(ob), &PyCFunction_Type)) return pyside_cf_get___signature__(ob, modifier); @@ -814,11 +827,11 @@ static PyObject * get_signature(PyObject * /* self */, PyObject *args) { PyObject *ob; - const char *modifier = nullptr; + PyObject *modifier = nullptr; init_module_1(); - if (!PyArg_ParseTuple(args, "O|s", &ob, &modifier)) + if (!PyArg_ParseTuple(args, "O|O", &ob, &modifier)) return nullptr; if (Py_TYPE(ob) == PepFunction_TypePtr) Py_RETURN_NONE; @@ -1030,7 +1043,16 @@ PySide_FinishSignatures(PyObject *module, const char *signatures[]) return -1; if (_finish_nested_classes(obdict) < 0) return -1; - return 0; + // The finish_import function will not work the first time since phase 2 + // was not yet run. But that is ok, because the first import is always for + // the shiboken module (or a test module). + if (pyside_globals->finish_import_func == nullptr) { + assert(strncmp(name, "PySide2.", 8) != 0); + return 0; + } + Shiboken::AutoDecRef ret(PyObject_CallFunction( + pyside_globals->finish_import_func, const_cast<char *>("(O)"), module)); + return ret.isNull() ? -1 : 0; } static int @@ -1093,13 +1115,14 @@ _build_func_to_type(PyObject *obtype) * "{name}.overload". */ PyObject *descr = PyDict_GetItemString(dict, meth->ml_name); - const char *look_attr = meth->ml_flags & METH_STATIC ? "__func__" : "__name__"; + PyObject *look_attr = meth->ml_flags & METH_STATIC + ? Shiboken::PyMagicName::func() : Shiboken::PyMagicName::name(); int check_name = meth->ml_flags & METH_STATIC ? 0 : 1; if (descr == nullptr) return -1; // We first check all methods if one is hidden by something else. - Shiboken::AutoDecRef look(PyObject_GetAttrString(descr, look_attr)); + Shiboken::AutoDecRef look(PyObject_GetAttr(descr, look_attr)); Shiboken::AutoDecRef given(Py_BuildValue("s", meth->ml_name)); if (look.isNull() || (check_name && PyObject_RichCompareBool(look, given, Py_EQ) != 1)) { @@ -1206,7 +1229,7 @@ SetError_Argument(PyObject *args, const char *func_name) */ PyObject * -Sbk_TypeGet___signature__(PyObject *ob, const char *modifier) +Sbk_TypeGet___signature__(PyObject *ob, PyObject *modifier) { return pyside_tp_get___signature__(ob, modifier); } diff --git a/sources/shiboken2/libshiboken/signature.h b/sources/shiboken2/libshiboken/signature.h index 57fd4047a..b22a78497 100644 --- a/sources/shiboken2/libshiboken/signature.h +++ b/sources/shiboken2/libshiboken/signature.h @@ -48,7 +48,7 @@ extern "C" LIBSHIBOKEN_API int SbkSpecial_Type_Ready(PyObject *, PyTypeObject *, const char *[]); LIBSHIBOKEN_API void FinishSignatureInitialization(PyObject *, const char *[]); LIBSHIBOKEN_API void SetError_Argument(PyObject *, const char *); -LIBSHIBOKEN_API PyObject *Sbk_TypeGet___signature__(PyObject *, const char *); +LIBSHIBOKEN_API PyObject *Sbk_TypeGet___signature__(PyObject *, PyObject *); LIBSHIBOKEN_API PyObject *Sbk_TypeGet___doc__(PyObject *); } // extern "C" diff --git a/sources/shiboken2/libshiboken/signature_doc.rst b/sources/shiboken2/libshiboken/signature_doc.rst index 9c42c5976..a984de4ce 100644 --- a/sources/shiboken2/libshiboken/signature_doc.rst +++ b/sources/shiboken2/libshiboken/signature_doc.rst @@ -73,8 +73,8 @@ It calls ``GetSignature_Function`` which returns the signature if it is found. Why this Code is Fast --------------------- -It costs a little time (maybe 4 seconds) to run througs every single signature -object, since these are more than 15000 Python objects. But all the signature +It costs a little time (maybe 6 seconds) to run througs every single signature +object, since these are more than 25000 Python objects. But all the signature objects will be rarely accessed but in special applications. The normal case are only a few accesses, and these are working pretty fast. @@ -111,10 +111,6 @@ the ``signature`` Python package. It has the following structure:: shiboken2/files.dir/shibokensupport/ backport_inspect.py - python_minilib_2_7.py - python_minilib_3_5.py - python_minilib_3_6.py - python_minilib_3_7.py signature/ loader.py @@ -125,6 +121,8 @@ the ``signature`` Python package. It has the following structure:: lib/ enum_sig.py + tool.py + Really important are the **parser**, **mapping**, **errorhandler**, **enum_sig**, diff --git a/sources/shiboken2/libshiboken/typespec.cpp b/sources/shiboken2/libshiboken/typespec.cpp index 6dc5b00bc..510ed51e6 100644 --- a/sources/shiboken2/libshiboken/typespec.cpp +++ b/sources/shiboken2/libshiboken/typespec.cpp @@ -39,6 +39,7 @@ #include "sbkpython.h" #include "typespec.h" +#include "sbkstaticstrings.h" #include <structmember.h> #if PY_MAJOR_VERSION < 3 @@ -730,7 +731,7 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) } // no PyId_ things in Python 2 // err = _PyDict_SetItemId(type->tp_dict, &PyId___module__, modname); - err = PyDict_SetItemString(type->tp_dict, "__module__", modname); + err = PyDict_SetItem(type->tp_dict, Shiboken::PyMagicName::module(), modname); Py_DECREF(modname); if (err != 0) goto fail; diff --git a/sources/shiboken2/shiboken_version.py b/sources/shiboken2/shiboken_version.py index 93c9fe6be..78ea0019d 100644 --- a/sources/shiboken2/shiboken_version.py +++ b/sources/shiboken2/shiboken_version.py @@ -1,6 +1,6 @@ ############################################################################# ## -## Copyright (C) 2018 The Qt Company Ltd. +## Copyright (C) 2019 The Qt Company Ltd. ## Contact: https://www.qt.io/licensing/ ## ## This file is part of Qt for Python. @@ -38,9 +38,8 @@ ############################################################################# major_version = "5" -minor_version = "13" -patch_version = "2" - +minor_version = "14" +patch_version = "0" # For example: "a", "b", "rc" # (which means "alpha", "beta", "release candidate"). diff --git a/sources/shiboken2/shibokenmodule/CMakeLists.txt b/sources/shiboken2/shibokenmodule/CMakeLists.txt index bbf2677e4..e1eafa12f 100644 --- a/sources/shiboken2/shibokenmodule/CMakeLists.txt +++ b/sources/shiboken2/shibokenmodule/CMakeLists.txt @@ -52,6 +52,8 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/ "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/layout.py" COPYONLY) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/loader.py" "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/loader.py" COPYONLY) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/importhandler.py" + "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/importhandler.py" COPYONLY) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/mapping.py" "${CMAKE_CURRENT_BINARY_DIR}/files.dir/shibokensupport/signature/mapping.py" COPYONLY) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/files.dir/shibokensupport/signature/parser.py" diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/backport_inspect.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/backport_inspect.py index c690493b6..1f6d70b31 100644 --- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/backport_inspect.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/backport_inspect.py @@ -113,7 +113,9 @@ CO_NOFREE = 0x0040 # We use '__builtin__' and '__name__' instead. def formatannotation(annotation, base_module=None): if getattr(annotation, '__module__', None) == 'typing': - return repr(annotation).replace('typing.', '') + # The replace must not be done on Python 2.7 because it + # already happens somewhere else. + return repr(annotation) ##.replace('typing.', '') if isinstance(annotation, type): if annotation.__module__ in ('__builtin__', base_module): return annotation.__name__ diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py new file mode 100644 index 000000000..0417f132a --- /dev/null +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/importhandler.py @@ -0,0 +1,103 @@ +############################################################################# +## +## Copyright (C) 2019 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of Qt for Python. +## +## $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$ +## +############################################################################# + +from __future__ import print_function, absolute_import + +""" +importhandler.py + +This module handles special actions after the import of PySide modules. +The reason for this was the wish to replace some deprecated functions +by a Python implementation that gives a warning. + +It provides a framework to safely call functions outside of files.dir, +because the implementation of deprecated functions should be visible +to the users (in the hope they don't use it any longer <wink>). + +As a first approach, the function finish_import redirects to +PySide2/support/deprecated.py . There can come other extensions as well. +""" + +try: + from PySide2.support import deprecated + have_deprecated = True +except ImportError: + have_deprecated = False + + +# called by loader.py from signature.cpp +def finish_import(module): + if have_deprecated and module.__name__.startswith("PySide2."): + try: + name = "fix_for_" + module.__name__.split(".")[1] + func = getattr(deprecated, name, None) + if func: + func(module) + except Exception as e: + name = e.__class__.__name__ + print(72 * "*") + print("Error in deprecated.py, ignored:") + print(" {name}: {e}".format(**locals())) + +""" +A note for people who might think this could be written in pure Python: + +Sure, by an explicit import of the modules to patch, this is no problem. +But in the general case, a module should only be imported on user +request and not because we want to patch it. So I started over. + +I then tried to do it on demand by redirection of the __import__ function. +Things worked quite nicely as it seemed, but at second view this solution +was much less appealing. + +Reason: +If someone executes as the first PySide statement + + from PySide2 import QtGui + +then this import is already running. We can see the other imports like the +diverse initializations and QtCore, because it is triggered by import of +QtGui. But the QtGui import can not be seen at all! + +With a lot of effort, sys.setprofile() and stack inspection with the inspect +module, it is *perhaps* possible to solve that. I tried for a day and then +gave up, since the solution is anyway not too nice when __import__ must +be overridden. +""" +#eof diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py index a5e3247b1..f11f3cf3d 100644 --- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py @@ -52,11 +52,6 @@ by producing a lot of clarity. import sys from shibokensupport.signature import inspect from shibokensupport.signature import get_signature -try: - from PySide2.QtCore import Qt - EnumType = type(Qt.Key) -except ImportError: - EnumType = None class ExactEnumerator(object): @@ -69,6 +64,14 @@ class ExactEnumerator(object): """ def __init__(self, formatter, result_type=dict): + global EnumType + try: + # Lazy import + from PySide2.QtCore import Qt + EnumType = type(Qt.Key) + except ImportError: + EnumType = None + self.fmt = formatter self.result_type = result_type self.fmt.level = 0 @@ -81,6 +84,7 @@ class ExactEnumerator(object): def module(self, mod_name): __import__(mod_name) + self.fmt.mod_name = mod_name with self.fmt.module(mod_name): module = sys.modules[mod_name] members = inspect.getmembers(module, inspect.isclass) @@ -90,7 +94,7 @@ class ExactEnumerator(object): for class_name, klass in members: ret.update(self.klass(class_name, klass)) if isinstance(klass, EnumType): - self.enum(klass) + raise SystemError("implement enum instances at module level") for func_name, func in functions: ret.update(self.function(func_name, func)) return ret @@ -106,26 +110,47 @@ class ExactEnumerator(object): name = modname + "." + base.__name__ bases_list.append(name) class_str = "{}({})".format(class_name, ", ".join(bases_list)) - with self.fmt.klass(class_name, class_str): - ret = self.result_type() - # class_members = inspect.getmembers(klass) - # gives us also the inherited things. - class_members = sorted(list(klass.__dict__.items())) - subclasses = [] - functions = [] - for thing_name, thing in class_members: - if inspect.isclass(thing): - subclass_name = ".".join((class_name, thing_name)) - subclasses.append((subclass_name, thing)) - elif inspect.isroutine(thing): - func_name = thing_name.split(".")[0] # remove ".overload" + ret = self.result_type() + # class_members = inspect.getmembers(klass) + # gives us also the inherited things. + class_members = sorted(list(klass.__dict__.items())) + subclasses = [] + functions = [] + enums = [] + + for thing_name, thing in class_members: + if inspect.isclass(thing): + subclass_name = ".".join((class_name, thing_name)) + subclasses.append((subclass_name, thing)) + elif inspect.isroutine(thing): + func_name = thing_name.split(".")[0] # remove ".overload" + signature = getattr(thing, "__signature__", None) + if signature is not None: functions.append((func_name, thing)) + elif type(type(thing)) is EnumType: + enums.append((thing_name, thing)) + init_signature = getattr(klass, "__signature__", None) + enums.sort(key=lambda tup: tup[1]) # sort by enum value + self.fmt.have_body = bool(subclasses or functions or enums or init_signature) + + with self.fmt.klass(class_name, class_str): self.fmt.level += 1 + self.fmt.class_name = class_name + if hasattr(self.fmt, "enum"): + # this is an optional feature + for enum_name, value in enums: + with self.fmt.enum(class_name, enum_name, int(value)): + pass for subclass_name, subclass in subclasses: + if klass == subclass: + # this is a side effect of the typing module for Python 2.7 + # via the "._gorg" property, which we can safely ignore. + print("Warning: {class_name} points to itself via {subclass_name}, skipped!" + .format(**locals())) + continue ret.update(self.klass(subclass_name, subclass)) - if isinstance(subclass, EnumType): - self.enum(subclass) - ret = self.function("__init__", klass) + self.fmt.class_name = class_name + ret.update(self.function("__init__", klass)) for func_name, func in functions: func_kind = get_signature(func, "__func_kind__") modifier = func_kind if func_kind in ( @@ -137,24 +162,13 @@ class ExactEnumerator(object): def function(self, func_name, func, modifier=None): self.fmt.level += 1 ret = self.result_type() - signature = getattr(func, '__signature__', None) + signature = func.__signature__ if signature is not None: with self.fmt.function(func_name, signature, modifier) as key: ret[key] = signature self.fmt.level -= 1 return ret - def enum(self, subclass): - if not hasattr(self.fmt, "enum"): - # this is an optional feature - return - class_name = subclass.__name__ - for enum_name, value in subclass.__dict__.items(): - if type(type(value)) is EnumType: - with self.fmt.enum(class_name, enum_name, int(value)): - pass - self._after_enum = True - def stringify(signature): if isinstance(signature, list): diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py index 8eff19d77..a0367883a 100644 --- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/loader.py @@ -89,6 +89,10 @@ def formatannotation(annotation, base_module=None): # break the Python license decorated files without an encoding line. # name used in signature.cpp +def pyside_type_init(type_key, sig_strings): + return parser.pyside_type_init(type_key, sig_strings) + +# name used in signature.cpp def create_signature(props, key): return layout.create_signature(props, key) @@ -100,6 +104,11 @@ def seterror_argument(args, func_name): def make_helptext(func): return errorhandler.make_helptext(func) +# name used in signature.cpp +def finish_import(module): + return importhandler.finish_import(module) + + import signature_bootstrap from shibokensupport import signature signature.get_signature = signature_bootstrap.get_signature @@ -185,6 +194,7 @@ def move_into_pyside_package(): put_into_package(PySide2.support.signature, layout) put_into_package(PySide2.support.signature, lib) put_into_package(PySide2.support.signature, parser) + put_into_package(PySide2.support.signature, importhandler) put_into_package(PySide2.support.signature.lib, enum_sig) put_into_package(None if orig_typing else PySide2.support.signature, typing) @@ -195,8 +205,8 @@ from shibokensupport.signature import errorhandler from shibokensupport.signature import layout from shibokensupport.signature import lib from shibokensupport.signature import parser +from shibokensupport.signature import importhandler from shibokensupport.signature.lib import enum_sig -from shibokensupport.signature.parser import pyside_type_init if "PySide2" in sys.modules: # We publish everything under "PySide2.support.signature", again. diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py index 163aac851..2110ebe7a 100644 --- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py @@ -66,7 +66,6 @@ Point = typing.Tuple[float, float] Variant = typing.Any ModelIndexList = typing.List[int] QImageCleanupFunction = typing.Callable -StringList = typing.List[str] # unfortunately, typing.Optional[t] expands to typing.Union[t, NoneType] # Until we can force it to create Optional[t] again, we use this. @@ -184,6 +183,27 @@ class Default(_NotCalled): class Instance(_NotCalled): pass +# Parameterized primitive variables +class _Parameterized(object): + def __init__(self, type): + self.type = type + self.__name__ = self.__class__.__name__ + + def __repr__(self): + return "{}({})".format( + type(self).__name__, self.type.__name__) + +# Mark the primitive variables to be moved into the result. +class ResultVariable(_Parameterized): + pass + +# Mark the primitive variables to become Sequence, Iterable or List +# (decided in the parser). +class ArrayLikeVariable(_Parameterized): + pass + +StringList = ArrayLikeVariable(str) + class Reloader(object): """ @@ -244,6 +264,7 @@ type_map = {} namespace = globals() # our module's __dict__ type_map.update({ + "...": ellipsis, "bool": bool, "char": Char, "char*": str, @@ -251,7 +272,7 @@ type_map.update({ "double": float, "float": float, "int": int, - "List": typing.List, + "List": ArrayLikeVariable, "long": int, "PyCallable": typing.Callable, "PyObject": object, @@ -264,7 +285,7 @@ type_map.update({ "qint64": int, "qint8": int, "qintptr": int, - "QList": typing.List, + "QList": ArrayLikeVariable, "qlonglong": int, "QMap": typing.Dict, "QPair": typing.Tuple, @@ -286,17 +307,28 @@ type_map.update({ "short": int, "signed char": Char, "signed long": int, + "std.list": typing.List, + "std.map": typing.Dict, + "std.pair": typing.Tuple, + "std.vector": typing.List, "str": str, "true": True, + "Tuple": typing.Tuple, + "uchar": Char, + "uchar*": str, + "uint": int, + "ulong": int, "ULONG_MAX": ulong_max, - "unsigned char": Char, - "unsigned int": int, # should we define an unsigned type? + "unsigned char": Char, # 5.9 + "unsigned char*": str, + "unsigned int": int, "unsigned long int": int, # 5.6, RHEL 6.6 "unsigned long long": int, "unsigned long": int, "unsigned short int": int, # 5.6, RHEL 6.6 "unsigned short": int, - "UnsignedShortType": int, # 5.9 + "Unspecified": None, + "ushort": int, "void": int, # be more specific? "WId": WId, "zero(bytes)": b"", @@ -305,7 +337,51 @@ type_map.update({ "zero(int)": 0, "zero(object)": None, "zero(str)": "", - "...": "...", + "zero(typing.Any)": None, + }) + +type_map.update({ + # Handling variables declared as array: + "array double*" : ArrayLikeVariable(float), + "array float*" : ArrayLikeVariable(float), + "array GLint*" : ArrayLikeVariable(int), + "array GLuint*" : ArrayLikeVariable(int), + "array int*" : ArrayLikeVariable(int), + "array long long*" : ArrayLikeVariable(int), + "array long*" : ArrayLikeVariable(int), + "array short*" : ArrayLikeVariable(int), + "array signed char*" : bytes, + "array unsigned char*" : bytes, + "array unsigned int*" : ArrayLikeVariable(int), + "array unsigned short*" : ArrayLikeVariable(int), + }) + +type_map.update({ + # Special cases: + "char*" : bytes, + "QChar*" : bytes, + "quint32*" : int, # only for QRandomGenerator + "quint8*" : bytearray, # only for QCborStreamReader and QCborValue + "uchar*" : bytes, + "unsigned char*": bytes, + }) + +type_map.update({ + # Handling variables that are returned, eventually as Tuples: + "bool*" : ResultVariable(bool), + "float*" : ResultVariable(float), + "int*" : ResultVariable(int), + "long long*" : ResultVariable(int), + "long*" : ResultVariable(int), + "PStr*" : ResultVariable(str), # module sample + "qint32*" : ResultVariable(int), + "qint64*" : ResultVariable(int), + "qreal*" : ResultVariable(float), + "QString*" : ResultVariable(str), + "quint16*" : ResultVariable(int), + "uint*" : ResultVariable(int), + "unsigned int*" : ResultVariable(int), + "QStringList*" : ResultVariable(StringList), }) @@ -330,6 +406,7 @@ def init_sample(): import datetime type_map.update({ "char": Char, + "char**": typing.List[str], "Complex": complex, "double": float, "Foo.HANDLE": int, @@ -346,7 +423,8 @@ def init_sample(): "sample.int": int, "sample.ObjectType": object, "sample.OddBool": bool, - "sample.Photon.TemplateBase": Missing("sample.Photon.TemplateBase"), + "sample.Photon.TemplateBase[Photon.DuplicatorType]": sample.Photon.ValueDuplicator, + "sample.Photon.TemplateBase[Photon.IdentityType]": sample.Photon.ValueIdentity, "sample.Point": Point, "sample.PStr": str, "sample.unsigned char": Char, @@ -381,6 +459,7 @@ def init_smart(): }) return locals() + # The PySide Part def init_PySide2_QtCore(): from PySide2.QtCore import Qt, QUrl, QDir @@ -402,50 +481,18 @@ def init_PySide2_QtCore(): "list of QAbstractAnimation": typing.List[PySide2.QtCore.QAbstractAnimation], "list of QAbstractState": typing.List[PySide2.QtCore.QAbstractState], "long long": int, - "long": int, "NULL": None, # 5.6, MSVC "nullptr": None, # 5.9 "PyByteArray": bytearray, "PyBytes": bytes, - "PyCallable": typing.Callable, - "PyObject": object, - "PySequence": typing.Iterable, # important for numpy - "PySide2.QtCore.bool": bool, - "PySide2.QtCore.char": StringList, # A 'char **' is a list of strings. - "PySide2.QtCore.double": float, - "PySide2.QtCore.float": float, - "PySide2.QtCore.int": int, - "PySide2.QtCore.int32_t": int, # 5.9 - "PySide2.QtCore.int64_t": int, # 5.9 - "PySide2.QtCore.long long": int, # 5.9, MSVC 15 - "PySide2.QtCore.long": int, - "PySide2.QtCore.QCborStreamReader.StringResult": typing.AnyStr, - "PySide2.QtCore.QChar": Char, - "PySide2.QtCore.qint16": int, - "PySide2.QtCore.qint32": int, - "PySide2.QtCore.qint64": int, - "PySide2.QtCore.qint8": int, - "PySide2.QtCore.qreal": float, - "PySide2.QtCore.QString": str, - "PySide2.QtCore.QStringList": StringList, - "PySide2.QtCore.quint16": int, - "PySide2.QtCore.quint32": int, - "PySide2.QtCore.quint64": int, - "PySide2.QtCore.quint8": int, + "PySide2.QtCore.QCborStreamReader.StringResult[PySide2.QtCore.QByteArray]": + PySide2.QtCore.QCborStringResultByteArray, + "PySide2.QtCore.QCborStreamReader.StringResult[QString]": + PySide2.QtCore.QCborStringResultString, "PySide2.QtCore.QUrl.ComponentFormattingOptions": PySide2.QtCore.QUrl.ComponentFormattingOption, # mismatch option/enum, why??? - "PySide2.QtCore.QVariant": Variant, - "PySide2.QtCore.short": int, - "PySide2.QtCore.signed char": Char, - "PySide2.QtCore.uchar": Char, - "PySide2.QtCore.uint32_t": int, # 5.9 - "PySide2.QtCore.unsigned char": Char, # 5.9 - "PySide2.QtCore.unsigned int": int, # 5.9 Ubuntu - "PySide2.QtCore.unsigned short": int, - "PyTypeObject": type, "PyUnicode": typing.Text, "Q_NULLPTR": None, - "QChar": Char, "QDir.Filters(AllEntries | NoDotAndDotDot)": Instance( "QDir.Filters(QDir.AllEntries | QDir.NoDotAndDotDot)"), "QDir.SortFlags(Name | IgnoreCase)": Instance( @@ -456,24 +503,21 @@ def init_PySide2_QtCore(): "QGenericArgument(NULL)": ellipsis, # 5.6, MSVC "QGenericArgument(nullptr)": ellipsis, # 5.10 "QGenericArgument(Q_NULLPTR)": ellipsis, - "QHash": typing.Dict, "QJsonObject": typing.Dict[str, PySide2.QtCore.QJsonValue], "QModelIndex()": Invalid("PySide2.QtCore.QModelIndex"), # repr is btw. very wrong, fix it?! "QModelIndexList": ModelIndexList, - "qptrdiff": int, - "QString": str, + "QModelIndexList": ModelIndexList, "QString()": "", - "QStringList": StringList, "QStringList()": [], "QStringRef": str, - "Qt.HANDLE": int, # be more explicit with some consts? - "quintptr": int, + "QStringRef": str, + "Qt.HANDLE": int, # be more explicit with some constants? "QUrl.FormattingOptions(PrettyDecoded)": Instance( "QUrl.FormattingOptions(QUrl.PrettyDecoded)"), - "QVariant": Variant, "QVariant()": Invalid(Variant), "QVariant.Type": type, # not so sure here... "QVariantMap": typing.Dict[str, Variant], + "QVariantMap": typing.Dict[str, Variant], }) try: type_map.update({ @@ -493,16 +537,12 @@ def init_PySide2_QtGui(): "GL_COLOR_BUFFER_BIT": GL_COLOR_BUFFER_BIT, "GL_NEAREST": GL_NEAREST, "int32_t": int, - "PySide2.QtCore.uint8_t": int, # macOS 5.9 - "PySide2.QtGui.QGenericMatrix": Missing("PySide2.QtGui.QGenericMatrix"), - "PySide2.QtGui.QPlatformSurface": int, # a handle - "QList< QTouchEvent.TouchPoint >()": [], # XXX improve? "QPixmap()": Default("PySide2.QtGui.QPixmap"), # can't create without qApp + "QPlatformSurface*": int, # a handle "QVector< QTextLayout.FormatRange >()": [], # do we need more structure? "uint32_t": int, "uint8_t": int, "USHRT_MAX": ushort_max, - "WId": WId, }) return locals() @@ -513,7 +553,6 @@ def init_PySide2_QtWidgets(): type_map.update({ "QMessageBox.StandardButtons(Yes | No)": Instance( "QMessageBox.StandardButtons(QMessageBox.Yes | QMessageBox.No)"), - "QVector< int >()": [], "QWidget.RenderFlags(DrawWindowBackground | DrawChildren)": Instance( "QWidget.RenderFlags(QWidget.DrawWindowBackground | QWidget.DrawChildren)"), "SH_Default": QStyleHintReturn.SH_Default, @@ -536,9 +575,12 @@ def init_PySide2_QtSql(): def init_PySide2_QtNetwork(): + best_structure = typing.OrderedDict if getattr(typing, "OrderedDict", None) else typing.Dict type_map.update({ - "QMultiMap": MultiMap, + "QMultiMap[PySide2.QtNetwork.QSsl.AlternativeNameEntryType, QString]": + best_structure[PySide2.QtNetwork.QSsl.AlternativeNameEntryType, typing.List[str]], }) + del best_structure return locals() @@ -557,6 +599,7 @@ def init_PySide2_QtMultimedia(): check_module(PySide2.QtMultimediaWidgets) type_map.update({ "QGraphicsVideoItem": PySide2.QtMultimediaWidgets.QGraphicsVideoItem, + "qint64": int, "QVideoWidget": PySide2.QtMultimediaWidgets.QVideoWidget, }) return locals() @@ -569,26 +612,23 @@ def init_PySide2_QtOpenGL(): "GLfloat": float, # 5.6, MSVC 15 "GLint": int, "GLuint": int, - "PySide2.QtOpenGL.GLint": int, - "PySide2.QtOpenGL.GLuint": int, }) return locals() def init_PySide2_QtQml(): type_map.update({ - "PySide2.QtQml.bool volatile": bool, "QJSValueList()": [], - "QVariantHash()": typing.Dict[str, Variant], # XXX sorted? + "QVariantHash()": typing.Dict[str, Variant], # from 5.9 }) return locals() def init_PySide2_QtQuick(): type_map.update({ - "PySide2.QtCore.uint": int, - "PySide2.QtQuick.QSharedPointer": int, - "T": int, + "PySide2.QtQuick.QSharedPointer[PySide2.QtQuick.QQuickItemGrabResult]": + PySide2.QtQuick.QQuickItemGrabResult, + "UnsignedShortType": int, }) return locals() @@ -602,6 +642,7 @@ def init_PySide2_QtScript(): def init_PySide2_QtTest(): type_map.update({ + "PySide2.QtTest.QTest.PySideQTouchEventSequence": PySide2.QtTest.QTest.QTouchEventSequence, "PySide2.QtTest.QTouchEventSequence": PySide2.QtTest.QTest.QTouchEventSequence, }) return locals() @@ -622,6 +663,10 @@ def init_PySide2_QtDataVisualization(): QtDataVisualization.QSurfaceDataArray = typing.List[QtDataVisualization.QSurfaceDataRow] type_map.update({ "100.0f": 100.0, + "QtDataVisualization.QBarDataArray": QtDataVisualization.QBarDataArray, + "QtDataVisualization.QBarDataArray*": QtDataVisualization.QBarDataArray, + "QtDataVisualization.QSurfaceDataArray": QtDataVisualization.QSurfaceDataArray, + "QtDataVisualization.QSurfaceDataArray*": QtDataVisualization.QSurfaceDataArray, }) return locals() diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py index 0081a07ba..8d970956b 100644 --- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py @@ -46,7 +46,7 @@ import types import keyword import functools from shibokensupport.signature.mapping import (type_map, update_mapping, - namespace, typing, _NotCalled) + namespace, typing, _NotCalled, ResultVariable, ArrayLikeVariable) from shibokensupport.signature.lib.tool import (SimpleNamespace, build_brace_pattern) @@ -170,9 +170,9 @@ def _resolve_value(thing, valtype, line): if thing in ("0", "None") and valtype: if valtype.startswith("PySide2.") or valtype.startswith("typing."): return None - mapped = type_map[valtype] + map = type_map[valtype] # typing.Any: '_SpecialForm' object has no attribute '__name__' - name = mapped.__name__ if hasattr(mapped, "__name__") else str(mapped) + name = map.__name__ if hasattr(map, "__name__") else str(map) thing = "zero({})".format(name) if thing in type_map: return type_map[thing] @@ -219,8 +219,6 @@ def to_string(thing): matrix_pattern = "PySide2.QtGui.QGenericMatrix" -# The matrix patch is borrowed from the future (extracted). -# It will work when the parser recognizes matrices. def handle_matrix(arg): n, m, typstr = tuple(map(lambda x:x.strip(), arg.split(","))) assert typstr == "float" @@ -238,7 +236,7 @@ def lno(level): """ -def _resolve_type(thing, line, level): +def _resolve_type(thing, line, level, var_handler): # Capture total replacements, first. Happens in # "PySide2.QtCore.QCborStreamReader.StringResult[PySide2.QtCore.QByteArray]" if thing in type_map: @@ -253,13 +251,13 @@ def _resolve_type(thing, line, level): # Special case: Handle the generic matrices. if contr == matrix_pattern: return handle_matrix(thing) - contr = _resolve_type(contr, line, level+1) + contr = var_handler(_resolve_type(contr, line, level+1, var_handler)) if isinstance(contr, _NotCalled): raise SystemError("Container types must exist:", repr(contr)) contr = to_string(contr) pieces = [] for part in _parse_arglist(thing): - part = _resolve_type(part, line, level+1) + part = var_handler(_resolve_type(part, line, level+1, var_handler)) if isinstance(part, _NotCalled): # fix the tag (i.e. "Missing") by repr part = repr(part) @@ -270,6 +268,46 @@ def _resolve_type(thing, line, level): return _resolve_value(thing, None, line) +def _handle_generic(obj, repl): + """ + Assign repl if obj is an ArrayLikeVariable + + This is a neat trick. Example: + + obj repl result + ---------------------- -------- --------- + ArrayLikeVariable List List + ArrayLikeVariable(str) List List[str] + ArrayLikeVariable Sequence Sequence + ArrayLikeVariable(str) Sequence Sequence[str] + """ + if isinstance(obj, ArrayLikeVariable): + return repl[obj.type] + if isinstance(obj, type) and issubclass(obj, ArrayLikeVariable): + # was "if obj is ArrayLikeVariable" + return repl + return obj + + +def handle_argvar(obj): + """ + Decide how array-like variables are resolved in arguments + + Currently, the best approximation is types.Sequence. + We want to change that to types.Iterable in the near future. + """ + return _handle_generic(obj, typing.Sequence) + + +def handle_retvar(obj): + """ + Decide how array-like variables are resolved in results + + This will probably stay typing.List forever. + """ + return _handle_generic(obj, typing.List) + + def calculate_props(line): parsed = SimpleNamespace(**_parse_line(line.strip())) arglist = parsed.arglist @@ -283,14 +321,14 @@ def calculate_props(line): ann = 'nullptr' # maps to None tup = name, ann arglist[idx] = tup - annotations[name] = _resolve_type(ann, line, 0) + annotations[name] = _resolve_type(ann, line, 0, handle_argvar) if len(tup) == 3: default = _resolve_value(tup[2], ann, line) _defaults.append(default) defaults = tuple(_defaults) returntype = parsed.returntype if returntype is not None: - annotations["return"] = _resolve_type(returntype, line, 0) + annotations["return"] = _resolve_type(returntype, line, 0, handle_retvar) props = SimpleNamespace() props.defaults = defaults props.kwdefaults = {} @@ -301,9 +339,61 @@ def calculate_props(line): shortname = funcname[funcname.rindex(".")+1:] props.name = shortname props.multi = parsed.multi + fix_variables(props, line) return vars(props) +def fix_variables(props, line): + annos = props.annotations + if not any(isinstance(ann, (ResultVariable, ArrayLikeVariable)) + for ann in annos.values()): + return + retvar = annos.get("return", None) + if retvar and isinstance(retvar, (ResultVariable, ArrayLikeVariable)): + # Special case: a ResultVariable which is the result will always be an array! + annos["return"] = retvar = typing.List[retvar.type] + fullname = props.fullname + varnames = list(props.varnames) + defaults = list(props.defaults) + diff = len(varnames) - len(defaults) + + safe_annos = annos.copy() + retvars = [retvar] if retvar else [] + deletions = [] + for idx, name in enumerate(varnames): + ann = safe_annos[name] + if isinstance(ann, ArrayLikeVariable): + ann = typing.Sequence[ann.type] + annos[name] = ann + if not isinstance(ann, ResultVariable): + continue + # We move the variable to the end and remove it. + retvars.append(ann.type) + deletions.append(idx) + del annos[name] + for idx in reversed(deletions): + # varnames: 0 1 2 3 4 5 6 7 + # defaults: 0 1 2 3 4 + # diff: 3 + del varnames[idx] + if idx >= diff: + del defaults[idx - diff] + else: + diff -= 1 + if retvars: + rvs = [] + retvars = list(handle_retvar(rv) if isinstance(rv, ArrayLikeVariable) else rv + for rv in retvars) + if len(retvars) == 1: + returntype = retvars[0] + else: + typestr = "typing.Tuple[{}]".format(", ".join(map(to_string, retvars))) + returntype = eval(typestr, namespace) + props.annotations["return"] = returntype + props.varnames = tuple(varnames) + props.defaults = tuple(defaults) + + def fixup_multilines(lines): """ Multilines can collapse when certain distinctions between C++ types diff --git a/sources/shiboken2/tests/samplebinding/pointerprimitivetype_test.py b/sources/shiboken2/tests/samplebinding/pointerprimitivetype_test.py new file mode 100644 index 000000000..c40770862 --- /dev/null +++ b/sources/shiboken2/tests/samplebinding/pointerprimitivetype_test.py @@ -0,0 +1,79 @@ +#!/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$ +## +############################################################################# + +""" +pointerprimitivetype_test.py + +check that the primitive types are correctly mapped by the signature module. + +Mapping +------- +IntArray2(const int*) -- <Signature (self, data: typing.Sequence)> +getMargins(int*,int*,int*,int*)const -- <Signature (self) -> typing.Tuple[int, int, int, int]> + +We explicitly check only against typing.Iterable in the first test, +because typing.Sequence is a subclass, but we will generalize this +to typing.Iterable in the future. +""" + +import unittest +from sample import IntArray2, VirtualMethods + +import shiboken2 +type.__signature__ # trigger init, which does not happen in tests +from shibokensupport.signature import typing + + +class PointerPrimitiveTypeTest(unittest.TestCase): + + def testArraySignature(self): + # signature="IntArray2(const int*)" + found = False + for sig in IntArray2.__signature__: + if "data" in sig.parameters: + found = True + break + self.assertTrue(found) + ann = sig.parameters["data"].annotation + self.assertEqual(ann.__args__, (int,)) + # un-specify this class (forget "int") by setting the _special + # flag, so we can check using issubclass (undocumented feature). + ann._special = True + self.assertTrue(issubclass(ann, typing.Iterable)) + + def testReturnVarSignature(self): + # signature="getMargins(int*,int*,int*,int*)const"> + ann = VirtualMethods.getMargins.__signature__.return_annotation + self.assertEqual(ann, typing.Tuple[int, int, int, int]) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml index 4d624f952..30ad5def7 100644 --- a/sources/shiboken2/tests/samplebinding/typesystem_sample.xml +++ b/sources/shiboken2/tests/samplebinding/typesystem_sample.xml @@ -227,7 +227,6 @@ </modify-argument> <modify-argument index="1"> <replace-type modified-type="PStr"/> - <remove-default-expression/> <replace-default-expression with="PStr()"/> </modify-argument> <inject-code class="target" position="end"> |