diff options
Diffstat (limited to 'sources/shiboken2')
61 files changed, 2264 insertions, 1309 deletions
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index 84721968d..4566ed3bc 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -539,9 +539,6 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) cls->addDefaultCopyConstructor(ancestorHasPrivateCopyConstructor(cls)); } } - - if (cls->isAbstract() && !cls->isInterface()) - cls->typeEntry()->setLookupName(cls->typeEntry()->targetLangName() + QLatin1String("$ConcreteWrapper")); } const auto &allEntries = types->entries(); @@ -584,7 +581,7 @@ void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom) AbstractMetaClass *cls = AbstractMetaClass::findClass(m_metaClasses, name); const bool enumFound = cls - ? cls->findEnum(entry->targetLangName()) != nullptr + ? cls->findEnum(entry->targetLangEntryName()) != nullptr : m_enums.contains(entry); if (!enumFound) { @@ -836,13 +833,10 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem & QString qualifiedName = enumItem->qualifiedName().join(colonColon()); TypeEntry *typeEntry = nullptr; + const TypeEntry *enclosingTypeEntry = enclosing ? enclosing->typeEntry() : nullptr; if (enumItem->accessPolicy() == CodeModel::Private) { - QStringList names = enumItem->qualifiedName(); - const QString &enumName = names.constLast(); - QString nspace; - if (names.size() > 1) - nspace = QStringList(names.mid(0, names.size() - 1)).join(colonColon()); - typeEntry = new EnumTypeEntry(nspace, enumName, QVersionNumber(0, 0)); + typeEntry = new EnumTypeEntry(enumItem->qualifiedName().constLast(), + QVersionNumber(0, 0), enclosingTypeEntry); TypeDatabase::instance()->addType(typeEntry); } else if (enumItem->enumKind() != AnonymousEnum) { typeEntry = TypeDatabase::instance()->findType(qualifiedName); @@ -862,8 +856,8 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem & QString enumName = enumItem->name(); QString className; - if (enclosing) - className = enclosing->typeEntry()->qualifiedCppName(); + if (enclosingTypeEntry) + className = enclosingTypeEntry->qualifiedCppName(); QString rejectReason; if (TypeDatabase::instance()->isEnumRejected(className, enumName, &rejectReason)) { @@ -945,25 +939,13 @@ AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(const EnumModelItem & metaEnum->setOriginalAttributes(metaEnum->attributes()); // Register all enum values on Type database - QString prefix; - if (enclosing) { - prefix += enclosing->typeEntry()->qualifiedCppName(); - prefix += colonColon(); - } - if (enumItem->enumKind() == EnumClass) { - prefix += enumItem->name(); - prefix += colonColon(); - } + const bool isScopedEnum = enumItem->enumKind() == EnumClass; const EnumeratorList &enumerators = enumItem->enumerators(); for (const EnumeratorModelItem &e : enumerators) { - QString name; - if (enclosing) { - name += enclosing->name(); - name += colonColon(); - } - EnumValueTypeEntry *enumValue = - new EnumValueTypeEntry(prefix + e->name(), e->stringValue(), - enumTypeEntry, enumTypeEntry->version()); + auto enumValue = + new EnumValueTypeEntry(e->name(), e->stringValue(), + enumTypeEntry, isScopedEnum, + enumTypeEntry->version()); TypeDatabase::instance()->addType(enumValue); if (e->value().isNullValue()) enumTypeEntry->setNullValue(enumValue); @@ -1097,9 +1079,11 @@ AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem TemplateParameterList template_parameters = classItem->templateParameters(); QVector<TypeEntry *> template_args; template_args.clear(); + auto argumentParent = metaClass->typeEntry()->typeSystemTypeEntry(); for (int i = 0; i < template_parameters.size(); ++i) { const TemplateParameterModelItem ¶m = template_parameters.at(i); - TemplateArgumentEntry *param_type = new TemplateArgumentEntry(param->name(), type->version()); + auto param_type = new TemplateArgumentEntry(param->name(), type->version(), + argumentParent); param_type->setOrdinal(i); template_args.append(param_type); } @@ -1300,27 +1284,37 @@ void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaF metaFunction->replaceType(metaType); } -static bool _compareAbstractMetaTypes(const AbstractMetaType *type, const AbstractMetaType *other) +static bool _compareAbstractMetaTypes(const AbstractMetaType *type, + const AbstractMetaType *other, + AbstractMetaType::ComparisonFlags flags = {}) { return (type != nullptr) == (other != nullptr) - && (type == nullptr || *type == *other); + && (type == nullptr || type->compare(*other, flags)); } -static bool _compareAbstractMetaFunctions(const AbstractMetaFunction *func, const AbstractMetaFunction *other) +static bool _compareAbstractMetaFunctions(const AbstractMetaFunction *func, + const AbstractMetaFunction *other, + AbstractMetaType::ComparisonFlags argumentFlags = {}) { if (!func && !other) return true; if (!func || !other) return false; - if (func->arguments().count() != other->arguments().count() + if (func->name() != other->name()) + return false; + const int argumentsCount = func->arguments().count(); + if (argumentsCount != other->arguments().count() || func->isConstant() != other->isConstant() || func->isStatic() != other->isStatic() || !_compareAbstractMetaTypes(func->type(), other->type())) { return false; } - for (int i = 0; i < func->arguments().count(); ++i) { - if (!_compareAbstractMetaTypes(func->arguments().at(i)->type(), other->arguments().at(i)->type())) + for (int i = 0; i < argumentsCount; ++i) { + if (!_compareAbstractMetaTypes(func->arguments().at(i)->type(), + other->arguments().at(i)->type(), + argumentFlags)) { return false; + } } return true; } @@ -1346,29 +1340,6 @@ AbstractMetaFunctionList AbstractMetaBuilderPrivate::classFunctionList(const Sco return result; } -// For template classes, entries with more specific types may exist from out-of- -// line definitions. If there is a declaration which matches it after fixing -// the parameters, remove it as duplicate. For example: -// template class<T> Vector { public: -// Vector(const Vector &rhs); -// }; -// template class<T> -// Vector<T>::Vector(const Vector<T>&) {} // More specific, remove declaration. - -class DuplicatingFunctionPredicate : public std::unary_function<bool, const AbstractMetaFunction *> { -public: - explicit DuplicatingFunctionPredicate(const AbstractMetaFunction *f) : m_function(f) {} - - bool operator()(const AbstractMetaFunction *rhs) const - { - return rhs != m_function && rhs->name() == m_function->name() - && _compareAbstractMetaFunctions(m_function, rhs); - } - -private: - const AbstractMetaFunction *m_function; -}; - void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, AbstractMetaClass *metaClass) { @@ -1418,13 +1389,6 @@ void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem, metaClass->setHasNonPrivateConstructor(true); } - // Classes with virtual destructors should always have a shell class - // (since we aren't registering the destructors, we need this extra check) - if (metaFunction->isDestructor() && metaFunction->isVirtual() - && metaFunction->visibility() != AbstractMetaAttributes::Private) { - metaClass->setForceShellClass(true); - } - if (!metaFunction->isDestructor() && !(metaFunction->isPrivate() && metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction)) { @@ -1607,8 +1571,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 +1585,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 +1663,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 +1901,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 +1937,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 +1988,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 +2122,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 +2201,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: ")); @@ -2254,7 +2222,9 @@ AbstractMetaType *AbstractMetaBuilderPrivate::translateTypeStatic(const TypeInfo if (_ok) arrayType->setArrayElementCount(int(elems)); } - arrayType->setTypeEntry(new ArrayTypeEntry(elementType->typeEntry() , elementType->typeEntry()->version())); + auto elementTypeEntry = elementType->typeEntry(); + arrayType->setTypeEntry(new ArrayTypeEntry(elementTypeEntry, elementTypeEntry->version(), + elementTypeEntry->parent())); arrayType->decideUsagePattern(); elementType = arrayType; @@ -2344,7 +2314,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 +2336,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 +2359,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 +2405,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 +2482,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; @@ -2676,8 +2647,7 @@ bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass, if (isNumber) { t = typeDb->findType(typeName); if (!t) { - t = new EnumValueTypeEntry(typeName, typeName, nullptr, - QVersionNumber(0, 0)); + t = new ConstantValueTypeEntry(typeName, subclass->typeEntry()->typeSystemTypeEntry()); t->setCodeGeneration(0); typeDb->addType(t); } 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..b381a62cd 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h @@ -37,12 +37,15 @@ #include <QSet> #include <QFileInfo> +#include <QVector> class TypeDatabase; class AbstractMetaBuilderPrivate { public: + using TranslateTypeFlags = AbstractMetaBuilder::TranslateTypeFlags; + Q_DISABLE_COPY(AbstractMetaBuilderPrivate) AbstractMetaBuilderPrivate(); @@ -136,12 +139,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); @@ -185,7 +188,7 @@ public: QHash<const TypeEntry *, AbstractMetaEnum *> m_enums; - QList<NamespaceModelItem> m_scopes; + QVector<NamespaceModelItem> m_scopes; QSet<AbstractMetaClass *> m_setupInheritanceDone; diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp index 455140e59..5ae671d87 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. @@ -166,19 +166,9 @@ QString AbstractMetaType::package() const return m_typeEntry->targetLangPackage(); } -static QString lastNameSegment(QString name) -{ - const int index = name.lastIndexOf(QStringLiteral("::")); - if (index >= 0) - name.remove(0, index + 2); - return name; -} - QString AbstractMetaType::name() const { - if (m_name.isEmpty()) - m_name = lastNameSegment(m_typeEntry->targetLangName()); - return m_name; + return m_typeEntry->targetLangEntryName(); } QString AbstractMetaType::fullName() const @@ -256,11 +246,16 @@ AbstractMetaTypeCList AbstractMetaType::nestedArrayTypes() const return result; } -bool AbstractMetaType::isConstRef() const +bool AbstractMetaType::passByConstRef() const { return isConstant() && m_referenceType == LValueReference && indirections() == 0; } +bool AbstractMetaType::passByValue() const +{ + return m_referenceType == NoReference && indirections() == 0; +} + QString AbstractMetaType::cppSignature() const { if (m_cachedCppSignature.isEmpty()) @@ -268,12 +263,21 @@ 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) return InvalidPattern; - if (m_typeEntry->isPrimitive() && (actualIndirections() == 0 || isConstRef())) + if (m_typeEntry->isPrimitive() && (actualIndirections() == 0 || passByConstRef())) return PrimitivePattern; if (m_typeEntry->isVoid()) @@ -282,7 +286,7 @@ AbstractMetaType::TypeUsagePattern AbstractMetaType::determineUsagePattern() con if (m_typeEntry->isVarargs()) return VarargsPattern; - if (m_typeEntry->isEnum() && (actualIndirections() == 0 || isConstRef())) + if (m_typeEntry->isEnum() && (actualIndirections() == 0 || passByConstRef())) return EnumPattern; if (m_typeEntry->isObject()) { @@ -297,7 +301,7 @@ AbstractMetaType::TypeUsagePattern AbstractMetaType::determineUsagePattern() con if (m_typeEntry->isSmartPointer() && indirections() == 0) return SmartPointerPattern; - if (m_typeEntry->isFlags() && (actualIndirections() == 0 || isConstRef())) + if (m_typeEntry->isFlags() && (actualIndirections() == 0 || passByConstRef())) return FlagsPattern; if (m_typeEntry->isArray()) @@ -343,21 +347,29 @@ bool AbstractMetaType::hasTemplateChildren() const return false; } -bool AbstractMetaType::equals(const AbstractMetaType &rhs) const +bool AbstractMetaType::compare(const AbstractMetaType &rhs, ComparisonFlags flags) const { - if (m_typeEntry != rhs.m_typeEntry || m_constant != rhs.m_constant - || m_referenceType != rhs.m_referenceType + if (m_typeEntry != rhs.m_typeEntry || m_indirections != rhs.m_indirections || m_instantiations.size() != rhs.m_instantiations.size() || m_arrayElementCount != rhs.m_arrayElementCount) { return false; } + + if (m_constant != rhs.m_constant || m_referenceType != rhs.m_referenceType) { + if (!flags.testFlag(ConstRefMatchesValue) + || !(passByValue() || passByConstRef()) + || !(rhs.passByValue() || rhs.passByConstRef())) { + return false; + } + } + if ((m_arrayElementType != nullptr) != (rhs.m_arrayElementType != nullptr) - || (m_arrayElementType != nullptr && !m_arrayElementType->equals(*rhs.m_arrayElementType))) { + || (m_arrayElementType != nullptr && !m_arrayElementType->compare(*rhs.m_arrayElementType, flags))) { return false; } for (int i = 0, size = m_instantiations.size(); i < size; ++i) { - if (!m_instantiations.at(i)->equals(*rhs.m_instantiations.at(i))) + if (!m_instantiations.at(i)->compare(*rhs.m_instantiations.at(i), flags)) return false; } return true; @@ -722,37 +734,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 +752,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 { @@ -1361,7 +1329,6 @@ AbstractMetaClass::AbstractMetaClass() m_hasPrivateDestructor(false), m_hasProtectedDestructor(false), m_hasVirtualDestructor(false), - m_forceShellClass(false), m_hasHashFunction(false), m_hasEqualsOperator(false), m_hasCloneOperator(false), @@ -1634,7 +1601,7 @@ bool AbstractMetaClass::hasSignal(const AbstractMetaFunction *other) const QString AbstractMetaClass::name() const { - return lastNameSegment(m_typeEntry->targetLangName()); + return m_typeEntry->targetLangEntryName(); } void AbstractMetaClass::setBaseClass(AbstractMetaClass *baseClass) @@ -2555,6 +2522,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()->targetLangName(); + } + 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(); @@ -2762,7 +2781,7 @@ AbstractMetaEnumValue *AbstractMetaEnum::findEnumValue(const QString &value) con QString AbstractMetaEnum::name() const { - return m_typeEntry->targetLangName(); + return m_typeEntry->targetLangEntryName(); } QString AbstractMetaEnum::qualifier() const diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h index 91ca4d7a9..2ae1b6d21 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. @@ -249,21 +249,11 @@ public: return m_originalAttributes & Private; } - bool wasProtected() const - { - return m_originalAttributes & Protected; - } - bool wasPublic() const { return m_originalAttributes & Public; } - bool wasFriendly() const - { - return m_originalAttributes & Friendly; - } - void setDocumentation(const Documentation& doc) { m_doc = doc; @@ -312,6 +302,11 @@ public: }; Q_ENUM(TypeUsagePattern) + enum ComparisonFlag { + ConstRefMatchesValue = 0x1 + }; + Q_DECLARE_FLAGS(ComparisonFlags, ComparisonFlag); + AbstractMetaType(); ~AbstractMetaType(); @@ -438,7 +433,8 @@ public: bool isVolatile() const { return m_volatile; } void setVolatile(bool v) { m_volatile = v; } - bool isConstRef() const; + bool passByConstRef() const; + bool passByValue() const; ReferenceType referenceType() const { return m_referenceType; } void setReferenceType(ReferenceType ref) { m_referenceType = ref; } @@ -483,6 +479,8 @@ public: QString cppSignature() const; + QString pythonSignature() const; + AbstractMetaType *copy() const; bool applyArrayModification(QString *errorMessage); @@ -535,17 +533,18 @@ public: bool hasTemplateChildren() const; - bool equals(const AbstractMetaType &rhs) const; + bool compare(const AbstractMetaType &rhs, ComparisonFlags = {}) const; 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; @@ -565,10 +564,12 @@ private: Q_DISABLE_COPY(AbstractMetaType) }; +Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaType::ComparisonFlags); + inline bool operator==(const AbstractMetaType &t1, const AbstractMetaType &t2) -{ return t1.equals(t2); } +{ return t1.compare(t2); } inline bool operator!=(const AbstractMetaType &t1, const AbstractMetaType &t2) -{ return !t1.equals(t2); } +{ return !t1.compare(t2); } #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const AbstractMetaType *at); @@ -667,7 +668,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 @@ -886,7 +889,6 @@ public: QString minimalSignature() const; QString debugSignature() const; // including virtual/override/final, etc., for debugging only. - QStringList possibleIntrospectionCompatibleSignatures() const; bool isModifiedRemoved(int types = TypeSystem::All) const; @@ -1016,8 +1018,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 +1030,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. @@ -1529,11 +1526,6 @@ public: bool hasSignals() const; bool inheritsFrom(const AbstractMetaClass *other) const; - void setForceShellClass(bool on) - { - m_forceShellClass = on; - } - /** * Says if the class that declares or inherits a virtual function. * \return true if the class implements or inherits any virtual methods @@ -1731,7 +1723,6 @@ private: uint m_hasPrivateDestructor : 1; uint m_hasProtectedDestructor : 1; uint m_hasVirtualDestructor : 1; - uint m_forceShellClass : 1; uint m_hasHashFunction : 1; uint m_hasEqualsOperator : 1; uint m_hasCloneOperator : 1; diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp index 8d1b4debf..a5b153499 100644 --- a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp +++ b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp @@ -40,7 +40,7 @@ #include <QtCore/QStack> #include <QtCore/QVector> -#include <string.h> +#include <cstring> #include <ctype.h> #if QT_VERSION < 0x050800 @@ -202,6 +202,8 @@ public: template <class Item> void qualifyTypeDef(const CXCursor &typeRefCursor, const QSharedPointer<Item> &item) const; + bool visitHeader(const char *cFileName) const; + BaseVisitor *m_baseVisitor; CodeModel *m_model; @@ -665,31 +667,62 @@ Builder::~Builder() delete d; } -static inline bool compareHeaderName(const char *haystack, const char *needle) +static const char *cBaseName(const char *fileName) { - const char *lastSlash = strrchr(haystack, '/'); + const char *lastSlash = std::strrchr(fileName, '/'); #ifdef Q_OS_WIN if (lastSlash == nullptr) - lastSlash = strrchr(haystack, '\\'); + lastSlash = std::strrchr(fileName, '\\'); #endif - if (lastSlash == nullptr) - lastSlash = haystack; - else - ++lastSlash; + return lastSlash != nullptr ? (lastSlash + 1) : fileName; +} + +static inline bool cCompareFileName(const char *f1, const char *f2) +{ #ifdef Q_OS_WIN - return _stricmp(lastSlash, needle) == 0; + return _stricmp(f1, f2) == 0; #else - return strcmp(lastSlash, needle) == 0; + return std::strcmp(f1, f2) == 0; #endif } #ifdef Q_OS_UNIX -static bool cStringStartsWith(const char *prefix, const char *str) +template<size_t N> +static bool cStringStartsWith(const char *str, const char (&prefix)[N]) { - return strncmp(prefix, str, strlen(prefix)) == 0; + return std::strncmp(prefix, str, N - 1) == 0; } #endif +bool BuilderPrivate::visitHeader(const char *cFileName) const +{ + // Resolve OpenGL typedefs although the header is considered a system header. + const char *baseName = cBaseName(cFileName); + if (cCompareFileName(baseName, "gl.h")) + return true; +#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) + if (cStringStartsWith(cFileName, "/usr/include/stdint.h")) + return true; +#endif +#ifdef Q_OS_LINUX + if (cStringStartsWith(cFileName, "/usr/include/stdlib.h") + || cStringStartsWith(cFileName, "/usr/include/sys/types.h")) { + return true; + } +#endif // Q_OS_LINUX +#ifdef Q_OS_MACOS + // Parse the following system headers to get the correct typdefs for types like + // int32_t, which are used in the macOS implementation of OpenGL framework. + if (cCompareFileName(baseName, "gltypes.h") + || cStringStartsWith(cFileName, "/usr/include/_types") + || cStringStartsWith(cFileName, "/usr/include/_types") + || cStringStartsWith(cFileName, "/usr/include/sys/_types")) { + return true; + } +#endif // Q_OS_MACOS + return false; +} + bool Builder::visitLocation(const CXSourceLocation &location) const { if (clang_Location_isInSystemHeader(location) == 0) @@ -701,28 +734,12 @@ bool Builder::visitLocation(const CXSourceLocation &location) const clang_getExpansionLocation(location, &file, &line, &column, &offset); const CXString cxFileName = clang_getFileName(file); // Has been observed to be 0 for invalid locations + bool result = false; if (const char *cFileName = clang_getCString(cxFileName)) { - // Resolve OpenGL typedefs although the header is considered a system header. - const bool visitHeader = compareHeaderName(cFileName, "gl.h") -#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) - || cStringStartsWith("/usr/include/stdint.h", cFileName) -#endif -#if defined(Q_OS_LINUX) - || cStringStartsWith("/usr/include/stdlib.h", cFileName) - || cStringStartsWith("/usr/include/sys/types.h", cFileName) -#elif defined(Q_OS_MACOS) - // Parse the following system headers to get the correct typdefs for types like - // int32_t, which are used in the macOS implementation of OpenGL framework. - || compareHeaderName(cFileName, "gltypes.h") - || cStringStartsWith("/usr/include/_types", cFileName) - || cStringStartsWith("/usr/include/sys/_types", cFileName) -#endif - ; + result = d->visitHeader(cFileName); clang_disposeString(cxFileName); - if (visitHeader) - return true; } - return false; + return result; } FileModelItem Builder::dom() const diff --git a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp index f301733fe..d3e5e212f 100644 --- a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp +++ b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp @@ -309,6 +309,8 @@ QByteArrayList emulatedCompilerOptions() HeaderPaths headerPaths; result.append(QByteArrayLiteral("-fms-compatibility-version=19")); result.append(QByteArrayLiteral("-Wno-microsoft-enum-value")); + // Fix yvals_core.h: STL1000: Unexpected compiler version, expected Clang 7 or newer (MSVC2017 update) + result.append(QByteArrayLiteral("-D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH")); #elif defined(Q_CC_CLANG) HeaderPaths headerPaths = gppInternalIncludePaths(compilerFromCMake(QStringLiteral("clang++"))); result.append(noStandardIncludeOption()); diff --git a/sources/shiboken2/ApiExtractor/header_paths.h b/sources/shiboken2/ApiExtractor/header_paths.h index 0c25702ef..c9b5144c8 100644 --- a/sources/shiboken2/ApiExtractor/header_paths.h +++ b/sources/shiboken2/ApiExtractor/header_paths.h @@ -30,7 +30,7 @@ #define HEADER_PATHS_H #include <QByteArray> -#include <QList> +#include <QVector> #include <QString> enum class HeaderType @@ -67,6 +67,6 @@ public: } }; -using HeaderPaths = QList<HeaderPath>; +using HeaderPaths = QVector<HeaderPath>; #endif // HEADER_PATHS_H diff --git a/sources/shiboken2/ApiExtractor/messages.cpp b/sources/shiboken2/ApiExtractor/messages.cpp index 5b3a57fcc..546e9c4ed 100644 --- a/sources/shiboken2/ApiExtractor/messages.cpp +++ b/sources/shiboken2/ApiExtractor/messages.cpp @@ -328,6 +328,18 @@ QString msgConversionTypesDiffer(const QString &varType, const QString &conversi return result; } +QString msgCannotFindSmartPointer(const QString &instantiationType, + const AbstractMetaClassList &pointers) +{ + QString result; + QTextStream str(&result); + str << "Unable to find smart pointer type for " << instantiationType << " (known types:"; + for (auto t : pointers) + str << ' ' << t->fullName(); + str << ")."; + return result; +} + // main.cpp QString msgLeftOverArguments(const QMap<QString, QString> &remainingArgs) @@ -463,6 +475,17 @@ QString msgInvalidRegularExpression(const QString &pattern, const QString &why) return QLatin1String("Invalid pattern \"") + pattern + QLatin1String("\": ") + why; } +QString msgNoRootTypeSystemEntry() +{ + return QLatin1String("Type system entry appears out of order, there does not seem to be a root type system element."); +} + +QString msgIncorrectlyNestedName(const QString &name) +{ + return QLatin1String("Nesting types by specifying '::' is no longer supported (") + + name + QLatin1String(")."); +} + // qtdocgenerator.cpp QString msgTagWarning(const QXmlStreamReader &reader, const QString &context, diff --git a/sources/shiboken2/ApiExtractor/messages.h b/sources/shiboken2/ApiExtractor/messages.h index 2fee0de8f..2b7b75ba0 100644 --- a/sources/shiboken2/ApiExtractor/messages.h +++ b/sources/shiboken2/ApiExtractor/messages.h @@ -117,6 +117,9 @@ QString msgCannotUseEnumAsInt(const QString &name); QString msgConversionTypesDiffer(const QString &varType, const QString &conversionType); +QString msgCannotFindSmartPointer(const QString &instantiationType, + const AbstractMetaClassList &pointers); + QString msgLeftOverArguments(const QMap<QString, QString> &remainingArgs); QString msgInvalidVersion(const QString &package, const QString &version); @@ -128,6 +131,10 @@ QString msgExtendingNamespaceRequiresPattern(const QString &name); QString msgInvalidRegularExpression(const QString &pattern, const QString &why); +QString msgNoRootTypeSystemEntry(); + +QString msgIncorrectlyNestedName(const QString &name); + QString msgCyclicDependency(const QString &funcName, const QString &graphName, const QVector<const AbstractMetaFunction *> &involvedConversions); 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/typedatabase.cpp b/sources/shiboken2/ApiExtractor/typedatabase.cpp index 4f8887bd2..014f4dadc 100644 --- a/sources/shiboken2/ApiExtractor/typedatabase.cpp +++ b/sources/shiboken2/ApiExtractor/typedatabase.cpp @@ -793,7 +793,8 @@ void TypeEntry::formatDebug(QDebug &d) const if (m_name != cppName) d << "\", cppName=\"" << cppName << '"'; d << ", type=" << m_type << ", codeGeneration=0x" - << hex << m_codeGeneration << dec; + << hex << m_codeGeneration << dec + << ", target=\"" << targetLangName() << '"'; FORMAT_NONEMPTY_STRING("package", m_targetLangPackage) FORMAT_BOOL("stream", m_stream) FORMAT_LIST_SIZE("codeSnips", m_codeSnips) @@ -812,7 +813,6 @@ void TypeEntry::formatDebug(QDebug &d) const void ComplexTypeEntry::formatDebug(QDebug &d) const { TypeEntry::formatDebug(d); - FORMAT_NONEMPTY_STRING("targetLangName", m_targetLangName) FORMAT_BOOL("polymorphicBase", m_polymorphicBase) FORMAT_BOOL("genericClass", m_genericClass) FORMAT_BOOL("deleteInMainThread", m_deleteInMainThread) @@ -822,7 +822,6 @@ void ComplexTypeEntry::formatDebug(QDebug &d) const << ", except=" << int(m_exceptionHandling); FORMAT_NONEMPTY_STRING("defaultSuperclass", m_defaultSuperclass) FORMAT_NONEMPTY_STRING("polymorphicIdValue", m_polymorphicIdValue) - FORMAT_NONEMPTY_STRING("lookupName", m_lookupName) FORMAT_NONEMPTY_STRING("targetType", m_targetType) FORMAT_NONEMPTY_STRING("hash", m_hashFunction) FORMAT_LIST_SIZE("addedFunctions", m_addedFunctions) @@ -840,9 +839,6 @@ void TypedefEntry::formatDebug(QDebug &d) const void EnumTypeEntry::formatDebug(QDebug &d) const { TypeEntry::formatDebug(d); - FORMAT_NONEMPTY_STRING("package", m_packageName) - FORMAT_NONEMPTY_STRING("qualifier", m_qualifier) - FORMAT_NONEMPTY_STRING("targetLangName", m_targetLangName) if (m_flags) d << ", flags=(" << m_flags << ')'; } diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp index fa141670c..abd2bfb07 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.cpp +++ b/sources/shiboken2/ApiExtractor/typesystem.cpp @@ -43,17 +43,13 @@ static QString strings_jobject = QLatin1String("jobject"); static inline QString callOperator() { return QStringLiteral("operator()"); } -PrimitiveTypeEntry::PrimitiveTypeEntry(const QString &name, const QVersionNumber &vr) : - TypeEntry(name, PrimitiveType, vr), +PrimitiveTypeEntry::PrimitiveTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntry *parent) : + TypeEntry(entryName, PrimitiveType, vr, parent), m_preferredTargetLangType(true) { } -QString PrimitiveTypeEntry::targetLangName() const -{ - return m_targetLangName; -} - QString PrimitiveTypeEntry::targetLangApiName() const { return m_targetLangApiName; @@ -80,6 +76,12 @@ CodeSnipList TypeEntry::codeSnips() const return m_codeSnips; } +void TypeEntry::addExtraInclude(const Include &newInclude) +{ + if (!m_extraIncludes.contains(newInclude)) + m_extraIncludes.append(newInclude); +} + QString Modification::accessModifierString() const { if (isPrivate()) return QLatin1String("private"); @@ -112,12 +114,6 @@ FieldModification ComplexTypeEntry::fieldModification(const QString &name) const return mod; } -QString ComplexTypeEntry::targetLangName() const -{ - return m_targetLangName.isEmpty() ? - TypeEntry::targetLangName() : m_targetLangName; -} - void ComplexTypeEntry::setDefaultConstructor(const QString& defaultConstructor) { m_defaultConstructor = defaultConstructor; @@ -141,36 +137,11 @@ void ComplexTypeEntry::useAsTypedef(const ComplexTypeEntry *source) { TypeEntry::useAsTypedef(source); m_qualifiedCppName = source->m_qualifiedCppName; - m_targetLangName = source->m_targetLangName; - m_lookupName = source->m_lookupName; m_targetType = source->m_targetType; } ComplexTypeEntry::ComplexTypeEntry(const ComplexTypeEntry &) = default; -QString ContainerTypeEntry::targetLangName() const -{ - - switch (m_type) { - case StringListContainer: return QLatin1String("QStringList"); - case ListContainer: return QLatin1String("QList"); - case LinkedListContainer: return QLatin1String("QLinkedList"); - case VectorContainer: return QLatin1String("QVector"); - case StackContainer: return QLatin1String("QStack"); - case QueueContainer: return QLatin1String("QQueue"); - case SetContainer: return QLatin1String("QSet"); - case MapContainer: return QLatin1String("QMap"); - case MultiMapContainer: return QLatin1String("QMultiMap"); - case HashContainer: return QLatin1String("QHash"); - case MultiHashContainer: return QLatin1String("QMultiHash"); - case PairContainer: return QLatin1String("QPair"); - default: - qWarning("bad type... %d", m_type); - break; - } - return QString(); -} - QString ContainerTypeEntry::qualifiedCppName() const { if (m_type == StringListContainer) @@ -187,23 +158,19 @@ ContainerTypeEntry::ContainerTypeEntry(const ContainerTypeEntry &) = default; QString EnumTypeEntry::targetLangQualifier() const { - TypeEntry *te = TypeDatabase::instance()->findType(m_qualifier); - return te ? te->targetLangName() : m_qualifier; + const QString q = qualifier(); + if (!q.isEmpty()) { + if (auto te = TypeDatabase::instance()->findType(q)) + return te->targetLangName(); + } + return q; } -QString EnumTypeEntry::qualifiedTargetLangName() const +QString EnumTypeEntry::qualifier() const { - QString qualifiedName; - QString pkg = targetLangPackage(); - QString qualifier = targetLangQualifier(); - - if (!pkg.isEmpty()) - qualifiedName += pkg + QLatin1Char('.'); - if (!qualifier.isEmpty()) - qualifiedName += qualifier + QLatin1Char('.'); - qualifiedName += targetLangName(); - - return qualifiedName; + auto parentEntry = parent(); + return parentEntry && parentEntry->type() != TypeEntry::TypeSystemType ? + parentEntry->name() : QString(); } QString EnumTypeEntry::targetLangApiName() const @@ -230,30 +197,6 @@ TypeEntry *FlagsTypeEntry::clone() const FlagsTypeEntry::FlagsTypeEntry(const FlagsTypeEntry &) = default; -QString FlagsTypeEntry::qualifiedTargetLangName() const -{ - return targetLangPackage() + QLatin1Char('.') + m_enum->targetLangQualifier() - + QLatin1Char('.') + targetLangName(); -} - -QString FlagsTypeEntry::targetLangName() const -{ - return m_targetLangName; -} - -/*! - * The Visual Studio 2002 compiler doesn't support these symbols, - * which our typedefs unforntuatly expand to. - */ -QString fixCppTypeName(const QString &name) -{ - if (name == QLatin1String("long long")) - return QLatin1String("qint64"); - if (name == QLatin1String("unsigned long long")) - return QLatin1String("quint64"); - return name; -} - QString TemplateInstance::expandCode() const { TemplateEntry *templateEntry = TypeDatabase::instance()->findTemplate(m_name); @@ -623,10 +566,17 @@ AddedFunction::TypeInfo AddedFunction::TypeInfo::fromSignature(const QString& si return parseType(signature); } -ComplexTypeEntry::ComplexTypeEntry(const QString &name, TypeEntry::Type t, - const QVersionNumber &vr) : - TypeEntry(name, t, vr), - m_qualifiedCppName(name), +static QString buildName(const QString &entryName, const TypeEntry *parent) +{ + return parent == nullptr || parent->type() == TypeEntry::TypeSystemType + ? entryName : parent->name() + QLatin1String("::") + entryName; +} + +ComplexTypeEntry::ComplexTypeEntry(const QString &entryName, TypeEntry::Type t, + const QVersionNumber &vr, + const TypeEntry *parent) : + TypeEntry(entryName, t, vr, parent), + m_qualifiedCppName(buildName(entryName, parent)), m_polymorphicBase(false), m_genericClass(false), m_deleteInMainThread(false) @@ -638,11 +588,6 @@ bool ComplexTypeEntry::isComplex() const return true; } -QString ComplexTypeEntry::lookupName() const -{ - return m_lookupName.isEmpty() ? targetLangName() : m_lookupName; -} - QString ComplexTypeEntry::targetLangApiName() const { return strings_jobject; @@ -724,10 +669,13 @@ bool TypeEntry::isCppPrimitive() const return typeName.contains(QLatin1Char(' ')) || primitiveCppTypes().contains(typeName); } -TypeEntry::TypeEntry(const QString &name, TypeEntry::Type t, const QVersionNumber &vr) : - m_name(name), - m_type(t), - m_version(vr) +TypeEntry::TypeEntry(const QString &entryName, TypeEntry::Type t, const QVersionNumber &vr, + const TypeEntry *parent) : + m_parent(parent), + m_name(buildName(entryName, parent)), + m_entryName(entryName), + m_version(vr), + m_type(t) { } @@ -736,6 +684,51 @@ TypeEntry::~TypeEntry() delete m_customConversion; } +const TypeSystemTypeEntry *TypeEntry::typeSystemTypeEntry() const +{ + for (auto e = this; e; e = e->parent()) { + if (e->type() == TypeEntry::TypeSystemType) + return static_cast<const TypeSystemTypeEntry *>(e); + } + return nullptr; +} + +QString TypeEntry::targetLangName() const +{ + if (m_cachedTargetLangName.isEmpty()) + m_cachedTargetLangName = buildTargetLangName(); + return m_cachedTargetLangName; +} + +QString TypeEntry::buildTargetLangName() const +{ + QString result = m_entryName; + for (auto p = parent(); p && p->type() != TypeEntry::TypeSystemType; p = p->parent()) { + if (!result.isEmpty()) + result.prepend(QLatin1Char('.')); + QString n = p->m_entryName; + n.replace(QLatin1String("::"), QLatin1String(".")); // Primitive types may have "std::" + result.prepend(n); + } + return result; +} + +QString TypeEntry::targetLangEntryName() const +{ + if (m_cachedTargetLangEntryName.isEmpty()) { + m_cachedTargetLangEntryName = targetLangName(); + const int lastDot = m_cachedTargetLangEntryName.lastIndexOf(QLatin1Char('.')); + if (lastDot != -1) + m_cachedTargetLangEntryName.remove(0, lastDot + 1); + } + return m_cachedTargetLangEntryName; +} + +QString TypeEntry::qualifiedTargetLangName() const +{ + return targetLangPackage() + QLatin1Char('.') + targetLangName(); +} + bool TypeEntry::hasCustomConversion() const { return m_customConversion != nullptr; @@ -759,6 +752,7 @@ TypeEntry *TypeEntry::clone() const // Take over parameters relevant for typedefs void TypeEntry::useAsTypedef(const TypeEntry *source) { + m_entryName = source->m_entryName; m_name = source->m_name; m_targetLangPackage = source->m_targetLangPackage; m_codeGeneration = source->m_codeGeneration; @@ -767,8 +761,9 @@ void TypeEntry::useAsTypedef(const TypeEntry *source) TypeEntry::TypeEntry(const TypeEntry &) = default; -TypeSystemTypeEntry::TypeSystemTypeEntry(const QString &name, const QVersionNumber &vr) : - TypeEntry(name, TypeSystemType, vr) +TypeSystemTypeEntry::TypeSystemTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntry *parent) : + TypeEntry(entryName, TypeSystemType, vr, parent) { } @@ -780,7 +775,7 @@ TypeEntry *TypeSystemTypeEntry::clone() const TypeSystemTypeEntry::TypeSystemTypeEntry(const TypeSystemTypeEntry &) = default; VoidTypeEntry::VoidTypeEntry() : - TypeEntry(QLatin1String("void"), VoidType, QVersionNumber(0, 0)) + TypeEntry(QLatin1String("void"), VoidType, QVersionNumber(0, 0), nullptr) { } @@ -792,7 +787,7 @@ TypeEntry *VoidTypeEntry::clone() const VoidTypeEntry::VoidTypeEntry(const VoidTypeEntry &) = default; VarargsTypeEntry::VarargsTypeEntry() : - TypeEntry(QLatin1String("..."), VarargsType, QVersionNumber(0, 0)) + TypeEntry(QLatin1String("..."), VarargsType, QVersionNumber(0, 0), nullptr) { } @@ -803,8 +798,9 @@ TypeEntry *VarargsTypeEntry::clone() const VarargsTypeEntry::VarargsTypeEntry(const VarargsTypeEntry &) = default; -TemplateArgumentEntry::TemplateArgumentEntry(const QString &name, const QVersionNumber &vr) : - TypeEntry(name, TemplateArgumentType, vr) +TemplateArgumentEntry::TemplateArgumentEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntry *parent) : + TypeEntry(entryName, TemplateArgumentType, vr, parent) { } @@ -815,14 +811,15 @@ TypeEntry *TemplateArgumentEntry::clone() const TemplateArgumentEntry::TemplateArgumentEntry(const TemplateArgumentEntry &) = default; -ArrayTypeEntry::ArrayTypeEntry(const TypeEntry *nested_type, const QVersionNumber &vr) : - TypeEntry(QLatin1String("Array"), ArrayType, vr), +ArrayTypeEntry::ArrayTypeEntry(const TypeEntry *nested_type, const QVersionNumber &vr, + const TypeEntry *parent) : + TypeEntry(QLatin1String("Array"), ArrayType, vr, parent), m_nestedType(nested_type) { Q_ASSERT(m_nestedType); } -QString ArrayTypeEntry::targetLangName() const +QString ArrayTypeEntry::buildTargetLangName() const { return m_nestedType->targetLangName() + QLatin1String("[]"); } @@ -841,24 +838,19 @@ TypeEntry *ArrayTypeEntry::clone() const ArrayTypeEntry::ArrayTypeEntry(const ArrayTypeEntry &) = default; -EnumTypeEntry::EnumTypeEntry(const QString &nspace, const QString &enumName, - const QVersionNumber &vr) : - TypeEntry(nspace.isEmpty() ? enumName : nspace + QLatin1String("::") + enumName, - EnumType, vr), - m_qualifier(nspace), - m_targetLangName(enumName) -{ -} - -QString EnumTypeEntry::targetLangName() const +EnumTypeEntry::EnumTypeEntry(const QString &entryName, + const QVersionNumber &vr, + const TypeEntry *parent) : + TypeEntry(entryName, EnumType, vr, parent) { - return m_targetLangName; } EnumValueTypeEntry::EnumValueTypeEntry(const QString &name, const QString &value, const EnumTypeEntry *enclosingEnum, + bool isScopedEnum, const QVersionNumber &vr) : - TypeEntry(name, TypeEntry::EnumValue, vr), + TypeEntry(name, TypeEntry::EnumValue, vr, + isScopedEnum ? enclosingEnum : enclosingEnum->parent()), m_value(value), m_enclosingEnum(enclosingEnum) { @@ -871,16 +863,37 @@ TypeEntry *EnumValueTypeEntry::clone() const EnumValueTypeEntry::EnumValueTypeEntry(const EnumValueTypeEntry &) = default; -FlagsTypeEntry::FlagsTypeEntry(const QString &name, const QVersionNumber &vr) : - TypeEntry(name, FlagsType, vr) +FlagsTypeEntry::FlagsTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntry *parent) : + TypeEntry(entryName, FlagsType, vr, parent) +{ +} + +QString FlagsTypeEntry::buildTargetLangName() const { + QString on = m_originalName; + on.replace(QLatin1String("::"), QLatin1String(".")); + return on; } +ConstantValueTypeEntry::ConstantValueTypeEntry(const QString& name, + const TypeEntry *parent) : + TypeEntry(name, ConstantValueType, QVersionNumber(0, 0), parent) +{ +} + +TypeEntry *ConstantValueTypeEntry::clone() const +{ + return new ConstantValueTypeEntry(*this); +} + +ConstantValueTypeEntry::ConstantValueTypeEntry(const ConstantValueTypeEntry &) = default; + /* A typedef entry allows for specifying template specializations in the * typesystem XML file. */ -TypedefEntry::TypedefEntry(const QString &name, const QString &sourceType, - const QVersionNumber &vr) : - ComplexTypeEntry(name, TypedefType, vr), +TypedefEntry::TypedefEntry(const QString &entryName, const QString &sourceType, + const QVersionNumber &vr, const TypeEntry *parent) : + ComplexTypeEntry(entryName, TypedefType, vr, parent), m_sourceType(sourceType) { } @@ -892,20 +905,21 @@ TypeEntry *TypedefEntry::clone() const TypedefEntry::TypedefEntry(const TypedefEntry &) = default; -ContainerTypeEntry::ContainerTypeEntry(const QString &name, Type type, - const QVersionNumber &vr) : - ComplexTypeEntry(name, ContainerType, vr), +ContainerTypeEntry::ContainerTypeEntry(const QString &entryName, Type type, + const QVersionNumber &vr, + const TypeEntry *parent) : + ComplexTypeEntry(entryName, ContainerType, vr, parent), m_type(type) { setCodeGeneration(GenerateForSubclass); } -SmartPointerTypeEntry::SmartPointerTypeEntry(const QString &name, +SmartPointerTypeEntry::SmartPointerTypeEntry(const QString &entryName, const QString &getterName, const QString &smartPointerType, const QString &refCountMethodName, - const QVersionNumber &vr) : - ComplexTypeEntry(name, SmartPointerType, vr), + const QVersionNumber &vr, const TypeEntry *parent) : + ComplexTypeEntry(entryName, SmartPointerType, vr, parent), m_getterName(getterName), m_smartPointerType(smartPointerType), m_refCountMethodName(refCountMethodName) @@ -919,8 +933,9 @@ TypeEntry *SmartPointerTypeEntry::clone() const SmartPointerTypeEntry::SmartPointerTypeEntry(const SmartPointerTypeEntry &) = default; -NamespaceTypeEntry::NamespaceTypeEntry(const QString &name, const QVersionNumber &vr) : - ComplexTypeEntry(name, NamespaceType, vr) +NamespaceTypeEntry::NamespaceTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntry *parent) : + ComplexTypeEntry(entryName, NamespaceType, vr, parent) { } @@ -944,8 +959,9 @@ bool NamespaceTypeEntry::matchesFile(const QString &needle) const return m_filePattern.match(needle).hasMatch(); } -ValueTypeEntry::ValueTypeEntry(const QString &name, const QVersionNumber &vr) : - ComplexTypeEntry(name, BasicValueType, vr) +ValueTypeEntry::ValueTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntry *parent) : + ComplexTypeEntry(entryName, BasicValueType, vr, parent) { } @@ -966,8 +982,9 @@ TypeEntry *ValueTypeEntry::clone() const ValueTypeEntry::ValueTypeEntry(const ValueTypeEntry &) = default; -ValueTypeEntry::ValueTypeEntry(const QString &name, Type t, const QVersionNumber &vr) : - ComplexTypeEntry(name, t, vr) +ValueTypeEntry::ValueTypeEntry(const QString &entryName, Type t, const QVersionNumber &vr, + const TypeEntry *parent) : + ComplexTypeEntry(entryName, t, vr, parent) { } @@ -1105,8 +1122,9 @@ void CustomConversion::TargetToNativeConversion::setConversion(const QString& co m_d->conversion = conversion; } -InterfaceTypeEntry::InterfaceTypeEntry(const QString &name, const QVersionNumber &vr) : - ComplexTypeEntry(name, InterfaceType, vr) +InterfaceTypeEntry::InterfaceTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntry *parent) : + ComplexTypeEntry(entryName, InterfaceType, vr, parent) { } @@ -1128,9 +1146,10 @@ TypeEntry *InterfaceTypeEntry::clone() const InterfaceTypeEntry::InterfaceTypeEntry(const InterfaceTypeEntry &) = default; -FunctionTypeEntry::FunctionTypeEntry(const QString &name, const QString &signature, - const QVersionNumber &vr) : - TypeEntry(name, FunctionType, vr) +FunctionTypeEntry::FunctionTypeEntry(const QString &entryName, const QString &signature, + const QVersionNumber &vr, + const TypeEntry *parent) : + TypeEntry(entryName, FunctionType, vr, parent) { addSignature(signature); } @@ -1142,8 +1161,9 @@ TypeEntry *FunctionTypeEntry::clone() const FunctionTypeEntry::FunctionTypeEntry(const FunctionTypeEntry &) = default; -ObjectTypeEntry::ObjectTypeEntry(const QString &name, const QVersionNumber &vr) - : ComplexTypeEntry(name, ObjectType, vr) +ObjectTypeEntry::ObjectTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntry *parent) + : ComplexTypeEntry(entryName, ObjectType, vr, parent) { } diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h index 6a88ecd4d..4d0a23ca1 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.h +++ b/sources/shiboken2/ApiExtractor/typesystem.h @@ -543,6 +543,7 @@ private: }; class CustomConversion; +class TypeSystemTypeEntry; class TypeEntry { @@ -559,6 +560,7 @@ public: FlagsType, EnumType, EnumValue, + ConstantValueType, TemplateArgumentType, ThreadType, BasicValueType, @@ -591,7 +593,8 @@ public: }; Q_ENUM(CodeGeneration) - explicit TypeEntry(const QString &name, Type t, const QVersionNumber &vr); + explicit TypeEntry(const QString &entryName, Type t, const QVersionNumber &vr, + const TypeEntry *parent); virtual ~TypeEntry(); @@ -599,6 +602,11 @@ public: { return m_type; } + + const TypeEntry *parent() const { return m_parent; } + void setParent(const TypeEntry *p) { m_parent = p; } + const TypeSystemTypeEntry *typeSystemTypeEntry() const; + bool isPrimitive() const { return m_type == PrimitiveType; @@ -699,10 +707,9 @@ public: } // The type's name in C++, fully qualified - QString name() const - { - return m_name; - } + QString name() const { return m_name; } + // Name as specified in XML + QString entryName() const { return m_entryName; } uint codeGeneration() const { @@ -749,28 +756,15 @@ public: } // The type's name in TargetLang - virtual QString targetLangName() const - { - return m_name; - } - - // The type to lookup when converting to TargetLang - virtual QString lookupName() const - { - return targetLangName(); - } + QString targetLangName() const; // "Foo.Bar" + void setTargetLangName(const QString &n) { m_cachedTargetLangName = n; } + QString targetLangEntryName() const; // "Bar" // The package QString targetLangPackage() const { return m_targetLangPackage; } void setTargetLangPackage(const QString &p) { m_targetLangPackage = p; } - virtual QString qualifiedTargetLangName() const - { - QString pkg = targetLangPackage(); - if (pkg.isEmpty()) - return targetLangName(); - return pkg + QLatin1Char('.') + targetLangName(); - } + QString qualifiedTargetLangName() const; virtual InterfaceTypeEntry *designatedInterface() const { @@ -836,13 +830,7 @@ public: { m_extraIncludes = includes; } - void addExtraInclude(const Include &include) - { - if (!m_includesUsed.value(include.name(), false)) { - m_extraIncludes << include; - m_includesUsed[include.name()] = true; - } - } + void addExtraInclude(const Include &newInclude); Include include() const { @@ -904,30 +892,36 @@ public: protected: TypeEntry(const TypeEntry &); + virtual QString buildTargetLangName() const; + private: - QString m_name; + const TypeEntry *m_parent; + QString m_name; // fully qualified + QString m_entryName; QString m_targetLangPackage; - Type m_type; - uint m_codeGeneration = GenerateAll; + mutable QString m_cachedTargetLangName; // "Foo.Bar" + mutable QString m_cachedTargetLangEntryName; // "Bar" CustomFunction m_customConstructor; CustomFunction m_customDestructor; CodeSnipList m_codeSnips; DocModificationList m_docModifications; IncludeList m_extraIncludes; Include m_include; - QHash<QString, bool> m_includesUsed; QString m_conversionRule; - bool m_stream = false; QVersionNumber m_version; CustomConversion *m_customConversion = nullptr; + uint m_codeGeneration = GenerateAll; int m_revision = 0; int m_sbkIndex = 0; + Type m_type; + bool m_stream = false; }; class TypeSystemTypeEntry : public TypeEntry { public: - explicit TypeSystemTypeEntry(const QString &name, const QVersionNumber &vr); + explicit TypeSystemTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntry *parent); TypeEntry *clone() const override; @@ -960,7 +954,8 @@ protected: class TemplateArgumentEntry : public TypeEntry { public: - explicit TemplateArgumentEntry(const QString &name, const QVersionNumber &vr); + explicit TemplateArgumentEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntry *parent); int ordinal() const { @@ -983,7 +978,8 @@ private: class ArrayTypeEntry : public TypeEntry { public: - explicit ArrayTypeEntry(const TypeEntry *nested_type, const QVersionNumber &vr); + explicit ArrayTypeEntry(const TypeEntry *nested_type, const QVersionNumber &vr, + const TypeEntry *parent); void setNestedTypeEntry(TypeEntry *nested) { @@ -994,7 +990,6 @@ public: return m_nestedType; } - QString targetLangName() const override; QString targetLangApiName() const override; TypeEntry *clone() const override; @@ -1002,6 +997,8 @@ public: protected: ArrayTypeEntry(const ArrayTypeEntry &); + QString buildTargetLangName() const override; + private: const TypeEntry *m_nestedType; }; @@ -1010,13 +1007,8 @@ private: class PrimitiveTypeEntry : public TypeEntry { public: - explicit PrimitiveTypeEntry(const QString &name, const QVersionNumber &vr); - - QString targetLangName() const override; - void setTargetLangName(const QString &targetLangName) - { - m_targetLangName = targetLangName; - } + explicit PrimitiveTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntry *parent); QString targetLangApiName() const override; void setTargetLangApiName(const QString &targetLangApiName) @@ -1077,7 +1069,6 @@ protected: PrimitiveTypeEntry(const PrimitiveTypeEntry &); private: - QString m_targetLangName; QString m_targetLangApiName; QString m_defaultConstructor; uint m_preferredTargetLangType : 1; @@ -1089,23 +1080,15 @@ class EnumValueTypeEntry; class EnumTypeEntry : public TypeEntry { public: - explicit EnumTypeEntry(const QString &nspace, const QString &enumName, - const QVersionNumber &vr); + explicit EnumTypeEntry(const QString &entryName, + const QVersionNumber &vr, + const TypeEntry *parent); - QString targetLangName() const override; QString targetLangQualifier() const; - QString qualifiedTargetLangName() const override; QString targetLangApiName() const override; - QString qualifier() const - { - return m_qualifier; - } - void setQualifier(const QString &q) - { - m_qualifier = q; - } + QString qualifier() const; const EnumValueTypeEntry *nullValue() const { return m_nullValue; } void setNullValue(const EnumValueTypeEntry *n) { m_nullValue = n; } @@ -1140,9 +1123,6 @@ protected: EnumTypeEntry(const EnumTypeEntry &); private: - QString m_packageName; - QString m_qualifier; - QString m_targetLangName; const EnumValueTypeEntry *m_nullValue = nullptr; QStringList m_rejectedEnums; @@ -1156,7 +1136,9 @@ private: class EnumValueTypeEntry : public TypeEntry { public: - explicit EnumValueTypeEntry(const QString& name, const QString& value, const EnumTypeEntry* enclosingEnum, const QVersionNumber &vr); + explicit EnumValueTypeEntry(const QString& name, const QString& value, + const EnumTypeEntry* enclosingEnum, + bool isScopedEnum, const QVersionNumber &vr); QString value() const { return m_value; } const EnumTypeEntry* enclosingEnum() const { return m_enclosingEnum; } @@ -1174,10 +1156,9 @@ private: class FlagsTypeEntry : public TypeEntry { public: - explicit FlagsTypeEntry(const QString &name, const QVersionNumber &vr); + explicit FlagsTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntry *parent); - QString qualifiedTargetLangName() const override; - QString targetLangName() const override; QString targetLangApiName() const override; QString originalName() const @@ -1191,11 +1172,11 @@ public: QString flagsName() const { - return m_targetLangName; + return m_flagsName; } void setFlagsName(const QString &name) { - m_targetLangName = name; + m_flagsName = name; } EnumTypeEntry *originator() const @@ -1212,12 +1193,27 @@ public: protected: FlagsTypeEntry(const FlagsTypeEntry &); + QString buildTargetLangName() const override; + private: QString m_originalName; - QString m_targetLangName; + QString m_flagsName; EnumTypeEntry *m_enum = nullptr; }; +// For primitive values, typically to provide a dummy type for +// example the '2' in non-type template 'Array<2>'. +class ConstantValueTypeEntry : public TypeEntry +{ +public: + explicit ConstantValueTypeEntry(const QString& name, + const TypeEntry *parent); + + TypeEntry *clone() const override; + +protected: + ConstantValueTypeEntry(const ConstantValueTypeEntry &); +}; class ComplexTypeEntry : public TypeEntry { @@ -1233,17 +1229,11 @@ public: Unknown }; - explicit ComplexTypeEntry(const QString &name, Type t, const QVersionNumber &vr); + explicit ComplexTypeEntry(const QString &entryName, Type t, const QVersionNumber &vr, + const TypeEntry *parent); bool isComplex() const override; - void setLookupName(const QString &name) - { - m_lookupName = name; - } - - QString lookupName() const override; - QString targetLangApiName() const override; void setTypeFlags(TypeFlags flags) @@ -1335,12 +1325,6 @@ public: m_targetType = code; } - QString targetLangName() const override; - void setTargetLangName(const QString &name) - { - m_targetLangName = name; - } - bool isGenericClass() const { return m_genericClass; @@ -1408,14 +1392,12 @@ private: QString m_defaultConstructor; QString m_defaultSuperclass; QString m_qualifiedCppName; - QString m_targetLangName; uint m_polymorphicBase : 1; uint m_genericClass : 1; uint m_deleteInMainThread : 1; QString m_polymorphicIdValue; - QString m_lookupName; QString m_targetType; TypeFlags m_typeFlags; CopyableFlag m_copyableFlag = Unknown; @@ -1432,9 +1414,10 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(ComplexTypeEntry::TypeFlags) class TypedefEntry : public ComplexTypeEntry { public: - explicit TypedefEntry(const QString &name, + explicit TypedefEntry(const QString &entryName, const QString &sourceType, - const QVersionNumber &vr); + const QVersionNumber &vr, + const TypeEntry *parent); QString sourceType() const { return m_sourceType; } void setSourceType(const QString &s) { m_sourceType =s; } @@ -1480,7 +1463,8 @@ public: }; Q_ENUM(Type) - explicit ContainerTypeEntry(const QString &name, Type type, const QVersionNumber &vr); + explicit ContainerTypeEntry(const QString &entryName, Type type, const QVersionNumber &vr, + const TypeEntry *parent); Type type() const { @@ -1488,7 +1472,6 @@ public: } QString typeName() const; - QString targetLangName() const override; QString qualifiedCppName() const override; TypeEntry *clone() const override; @@ -1506,11 +1489,12 @@ private: class SmartPointerTypeEntry : public ComplexTypeEntry { public: - explicit SmartPointerTypeEntry(const QString &name, + explicit SmartPointerTypeEntry(const QString &entryName, const QString &getterName, const QString &smartPointerType, const QString &refCountMethodName, - const QVersionNumber &vr); + const QVersionNumber &vr, + const TypeEntry *parent); QString getter() const { @@ -1536,7 +1520,8 @@ private: class NamespaceTypeEntry : public ComplexTypeEntry { public: - explicit NamespaceTypeEntry(const QString &name, const QVersionNumber &vr); + explicit NamespaceTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntry *parent); TypeEntry *clone() const override; @@ -1566,7 +1551,8 @@ private: class ValueTypeEntry : public ComplexTypeEntry { public: - explicit ValueTypeEntry(const QString &name, const QVersionNumber &vr); + explicit ValueTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntry *parent); bool isValue() const override; @@ -1575,14 +1561,16 @@ public: TypeEntry *clone() const override; protected: - explicit ValueTypeEntry(const QString &name, Type t, const QVersionNumber &vr); + explicit ValueTypeEntry(const QString &entryName, Type t, const QVersionNumber &vr, + const TypeEntry *parent); ValueTypeEntry(const ValueTypeEntry &); }; class InterfaceTypeEntry : public ComplexTypeEntry { public: - explicit InterfaceTypeEntry(const QString &name, const QVersionNumber &vr); + explicit InterfaceTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntry *parent); static QString interfaceName(const QString &name) { @@ -1615,7 +1603,8 @@ class FunctionTypeEntry : public TypeEntry { public: explicit FunctionTypeEntry(const QString& name, const QString& signature, - const QVersionNumber &vr); + const QVersionNumber &vr, + const TypeEntry *parent); void addSignature(const QString& signature) { m_signatures << signature; @@ -1643,7 +1632,8 @@ private: class ObjectTypeEntry : public ComplexTypeEntry { public: - explicit ObjectTypeEntry(const QString &name, const QVersionNumber &vr); + explicit ObjectTypeEntry(const QString &entryName, const QVersionNumber &vr, + const TypeEntry *parent); InterfaceTypeEntry *designatedInterface() const override; void setDesignatedInterface(InterfaceTypeEntry *entry) @@ -1684,8 +1674,6 @@ struct TypeRejection QDebug operator<<(QDebug d, const TypeRejection &r); #endif -QString fixCppTypeName(const QString &name); - class CustomConversion { public: diff --git a/sources/shiboken2/ApiExtractor/typesystemparser.cpp b/sources/shiboken2/ApiExtractor/typesystemparser.cpp index 57ceb357f..7388b07fc 100644 --- a/sources/shiboken2/ApiExtractor/typesystemparser.cpp +++ b/sources/shiboken2/ApiExtractor/typesystemparser.cpp @@ -81,6 +81,7 @@ static inline QString preferredTargetLangTypeAttribute() { return QStringLiteral static inline QString removeAttribute() { return QStringLiteral("remove"); } static inline QString renameAttribute() { return QStringLiteral("rename"); } static inline QString readAttribute() { return QStringLiteral("read"); } +static inline QString targetLangNameAttribute() { return QStringLiteral("target-lang-name"); } static inline QString writeAttribute() { return QStringLiteral("write"); } static inline QString replaceAttribute() { return QStringLiteral("replace"); } static inline QString toAttribute() { return QStringLiteral("to"); } @@ -191,200 +192,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 +992,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; @@ -1040,41 +1041,59 @@ static QString checkSignatureError(const QString& signature, const QString& tag) return QString(); } +inline const TypeEntry *TypeSystemParser::currentParentTypeEntry() const +{ + return m_current ? m_current->entry : nullptr; +} + +bool TypeSystemParser::checkRootElement() +{ + const bool ok = currentParentTypeEntry() != nullptr; + if (!ok) + m_error = msgNoRootTypeSystemEntry(); + return ok; +} + void TypeSystemParser::applyCommonAttributes(TypeEntry *type, QXmlStreamAttributes *attributes) const { 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()); } FlagsTypeEntry * TypeSystemParser::parseFlagsEntry(const QXmlStreamReader &, - EnumTypeEntry *enumEntry, - const QString &name, QString flagName, + EnumTypeEntry *enumEntry, QString flagName, const QVersionNumber &since, QXmlStreamAttributes *attributes) { - FlagsTypeEntry *ftype = new FlagsTypeEntry(QLatin1String("QFlags<") + name + QLatin1Char('>'), since); + if (!checkRootElement()) + return nullptr; + auto ftype = new FlagsTypeEntry(QLatin1String("QFlags<") + enumEntry->name() + QLatin1Char('>'), + since, + currentParentTypeEntry()->typeSystemTypeEntry()); ftype->setOriginator(enumEntry); ftype->setTargetLangPackage(enumEntry->targetLangPackage()); - // Try to get the guess the qualified flag name - const int lastSepPos = name.lastIndexOf(colonColon()); - if (lastSepPos >= 0 && !flagName.contains(colonColon())) - flagName.prepend(name.left(lastSepPos + 2)); + // Try toenumEntry get the guess the qualified flag name + if (!flagName.contains(colonColon())) { + auto eq = enumEntry->qualifier(); + if (!eq.isEmpty()) + flagName.prepend(eq + colonColon()); + } ftype->setOriginalName(flagName); applyCommonAttributes(ftype, attributes); - QString n = ftype->originalName(); - QStringList lst = n.split(colonColon()); + QStringList lst = flagName.split(colonColon()); + const QString targetLangFlagName = QStringList(lst.mid(0, lst.size() - 1)).join(QLatin1Char('.')); const QString &targetLangQualifier = enumEntry->targetLangQualifier(); - if (QStringList(lst.mid(0, lst.size() - 1)).join(colonColon()) != targetLangQualifier) { + if (targetLangFlagName != targetLangQualifier) { qCWarning(lcShiboken).noquote().nospace() - << QStringLiteral("enum %1 and flags %2 differ in qualifiers") - .arg(targetLangQualifier, lst.constFirst()); + << QStringLiteral("enum %1 and flags %2 (%3) differ in qualifiers") + .arg(targetLangQualifier, lst.constFirst(), targetLangFlagName); } ftype->setFlagsName(lst.constLast()); @@ -1084,7 +1103,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()); @@ -1096,6 +1115,8 @@ SmartPointerTypeEntry * const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { + if (!checkRootElement()) + return nullptr; QString smartPointerType; QString getter; QString refCountMethodName; @@ -1138,7 +1159,8 @@ SmartPointerTypeEntry * return nullptr; } - auto *type = new SmartPointerTypeEntry(name, getter, smartPointerType, refCountMethodName, since); + auto *type = new SmartPointerTypeEntry(name, getter, smartPointerType, + refCountMethodName, since, currentParentTypeEntry()); applyCommonAttributes(type, attributes); return type; } @@ -1148,12 +1170,14 @@ PrimitiveTypeEntry * const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { - auto *type = new PrimitiveTypeEntry(name, since); + if (!checkRootElement()) + return nullptr; + auto *type = new PrimitiveTypeEntry(name, since, currentParentTypeEntry()); applyCommonAttributes(type, attributes); for (int i = attributes->size() - 1; i >= 0; --i) { const QStringRef name = attributes->at(i).qualifiedName(); - if (name == QLatin1String("target-lang-name")) { - type->setTargetLangName(attributes->takeAt(i).value().toString()); + if (name == targetLangNameAttribute()) { + type->setTargetLangName(attributes->takeAt(i).value().toString()); } else if (name == QLatin1String("target-lang-api-name")) { type->setTargetLangApiName(attributes->takeAt(i).value().toString()); } else if (name == preferredConversionAttribute()) { @@ -1168,8 +1192,6 @@ PrimitiveTypeEntry * } } - if (type->targetLangName().isEmpty()) - type->setTargetLangName(type->name()); if (type->targetLangApiName().isEmpty()) type->setTargetLangApiName(type->name()); type->setTargetLangPackage(m_defaultPackage); @@ -1181,7 +1203,9 @@ ContainerTypeEntry * const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { - const int typeIndex = indexOfAttribute(*attributes, QStringViewLiteral("type")); + if (!checkRootElement()) + return nullptr; + const int typeIndex = indexOfAttribute(*attributes, u"type"); if (typeIndex == -1) { m_error = QLatin1String("no 'type' attribute specified"); return nullptr; @@ -1192,24 +1216,19 @@ ContainerTypeEntry * m_error = QLatin1String("there is no container of type ") + typeName.toString(); return nullptr; } - auto *type = new ContainerTypeEntry(name, containerType, since); + auto *type = new ContainerTypeEntry(name, containerType, since, currentParentTypeEntry()); applyCommonAttributes(type, attributes); return type; } EnumTypeEntry * TypeSystemParser::parseEnumTypeEntry(const QXmlStreamReader &reader, - const QString &fullName, const QVersionNumber &since, + const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { - QString scope; - QString name = fullName; - const int sep = fullName.lastIndexOf(colonColon()); - if (sep != -1) { - scope = fullName.left(sep); - name = fullName.right(fullName.size() - sep - 2); - } - auto *entry = new EnumTypeEntry(scope, name, since); + if (!checkRootElement()) + return nullptr; + auto *entry = new EnumTypeEntry(name, since, currentParentTypeEntry()); applyCommonAttributes(entry, attributes); entry->setTargetLangPackage(m_defaultPackage); @@ -1237,7 +1256,7 @@ EnumTypeEntry * if (!flagNames.isEmpty()) { const QStringList &flagNameList = flagNames.split(QLatin1Char(',')); for (const QString &flagName : flagNameList) - parseFlagsEntry(reader, entry, fullName, flagName.trimmed(), since, attributes); + parseFlagsEntry(reader, entry, flagName.trimmed(), since, attributes); } return entry; } @@ -1247,13 +1266,15 @@ ObjectTypeEntry * const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { - auto *otype = new ObjectTypeEntry(name, since); + if (!checkRootElement()) + return nullptr; + auto *otype = new ObjectTypeEntry(name, since, currentParentTypeEntry()); applyCommonAttributes(otype, attributes); QString targetLangName = name; bool generate = true; for (int i = attributes->size() - 1; i >= 0; --i) { const QStringRef name = attributes->at(i).qualifiedName(); - if (name == QLatin1String("target-lang-name")) { + if (name == targetLangNameAttribute()) { targetLangName = attributes->takeAt(i).value().toString(); } else if (name == generateAttribute()) { generate = convertBoolean(attributes->takeAt(i).value(), @@ -1261,8 +1282,9 @@ ObjectTypeEntry * } } - InterfaceTypeEntry *itype = - new InterfaceTypeEntry(InterfaceTypeEntry::interfaceName(targetLangName), since); + auto itype = new InterfaceTypeEntry(InterfaceTypeEntry::interfaceName(targetLangName), + since, currentParentTypeEntry()); + itype->setTargetLangName(targetLangName); if (generate) itype->setCodeGeneration(m_generate); @@ -1279,7 +1301,9 @@ NamespaceTypeEntry * const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { - QScopedPointer<NamespaceTypeEntry> result(new NamespaceTypeEntry(name, since)); + if (!checkRootElement()) + return nullptr; + QScopedPointer<NamespaceTypeEntry> result(new NamespaceTypeEntry(name, since, currentParentTypeEntry())); applyCommonAttributes(result.data(), attributes); applyComplexTypeAttributes(reader, result.data(), attributes); for (int i = attributes->size() - 1; i >= 0; --i) { @@ -1320,10 +1344,12 @@ ValueTypeEntry * const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { - auto *typeEntry = new ValueTypeEntry(name, since); + if (!checkRootElement()) + return nullptr; + auto *typeEntry = new ValueTypeEntry(name, since, currentParentTypeEntry()); 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; @@ -1334,6 +1360,8 @@ FunctionTypeEntry * const QString &name, const QVersionNumber &since, QXmlStreamAttributes *attributes) { + if (!checkRootElement()) + return nullptr; const int signatureIndex = indexOfAttribute(*attributes, signatureAttribute()); if (signatureIndex == -1) { m_error = msgMissingAttribute(signatureAttribute()); @@ -1345,7 +1373,7 @@ FunctionTypeEntry * TypeEntry *existingType = m_database->findType(name); if (!existingType) { - auto *result = new FunctionTypeEntry(name, signature, since); + auto *result = new FunctionTypeEntry(name, signature, since, currentParentTypeEntry()); applyCommonAttributes(result, attributes); return result; } @@ -1366,6 +1394,8 @@ TypedefEntry * const QVersionNumber &since, QXmlStreamAttributes *attributes) { + if (!checkRootElement()) + return nullptr; if (m_current && m_current->type != StackElement::Root && m_current->type != StackElement::NamespaceTypeEntry) { m_error = QLatin1String("typedef entries must be nested in namespaces or type system."); @@ -1377,7 +1407,7 @@ TypedefEntry * return nullptr; } const QString sourceType = attributes->takeAt(sourceIndex).value().toString(); - auto result = new TypedefEntry(name, sourceType, since); + auto result = new TypedefEntry(name, sourceType, since, currentParentTypeEntry()); applyCommonAttributes(result, attributes); return result; } @@ -1407,7 +1437,7 @@ void TypeSystemParser::applyComplexTypeAttributes(const QXmlStreamReader &reader qPrintable(msgUnimplementedAttributeWarning(reader, name))); const bool v = convertBoolean(attributes->takeAt(i).value(), genericClassAttribute(), false); ctype->setGenericClass(v); - } else if (name == QLatin1String("target-lang-name")) { + } else if (name == targetLangNameAttribute()) { ctype->setTargetLangName(attributes->takeAt(i).value().toString()); } else if (name == QLatin1String("polymorphic-base")) { ctype->setPolymorphicIdValue(attributes->takeAt(i).value().toString()); @@ -1618,8 +1648,10 @@ TypeSystemTypeEntry *TypeSystemParser::parseRootElement(const QXmlStreamReader & auto *moduleEntry = const_cast<TypeSystemTypeEntry *>(m_database->findTypeSystemType(m_defaultPackage)); const bool add = moduleEntry == nullptr; - if (add) - moduleEntry = new TypeSystemTypeEntry(m_defaultPackage, since); + if (add) { + moduleEntry = new TypeSystemTypeEntry(m_defaultPackage, since, + currentParentTypeEntry()); + } moduleEntry->setCodeGeneration(m_generate); if ((m_generate == TypeEntry::GenerateForSubclass || @@ -1887,7 +1919,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 +2298,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; @@ -2630,6 +2662,12 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) return false; } } + // Allow for primitive and/or std:: types only, else require proper nesting. + if (element->type != StackElement::PrimitiveTypeEntry && name.contains(QLatin1Char(':')) + && !name.contains(QLatin1String("std::"))) { + m_error = msgIncorrectlyNestedName(name); + return false; + } if (m_database->hasDroppedTypeEntries()) { QString identifier = getNamePrefix(element) + QLatin1Char('.'); @@ -2677,13 +2715,6 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) } } - // Fix type entry name using nesting information. - if (element->type & StackElement::TypeEntryMask - && element->parent && element->parent->type != StackElement::Root) { - name = element->parent->entry->name() + colonColon() + name; - } - - if (name.isEmpty()) { m_error = QLatin1String("no 'name' attribute specified"); return false; @@ -2691,7 +2722,9 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) switch (element->type) { case StackElement::CustomTypeEntry: - element->entry = new TypeEntry(name, TypeEntry::CustomType, since); + if (!checkRootElement()) + return false; + element->entry = new TypeEntry(name, TypeEntry::CustomType, since, m_current->entry); break; case StackElement::PrimitiveTypeEntry: element->entry = parsePrimitiveTypeEntry(reader, name, since, &attributes); @@ -2745,7 +2778,9 @@ bool TypeSystemParser::startElement(const QXmlStreamReader &reader) return false; break; case StackElement::ObjectTypeEntry: - element->entry = new ObjectTypeEntry(name, since); + if (!checkRootElement()) + return false; + element->entry = new ObjectTypeEntry(name, since, currentParentTypeEntry()); applyCommonAttributes(element->entry, &attributes); applyComplexTypeAttributes(reader, static_cast<ComplexTypeEntry *>(element->entry), &attributes); break; diff --git a/sources/shiboken2/ApiExtractor/typesystemparser.h b/sources/shiboken2/ApiExtractor/typesystemparser.h index aaf22353e..d3ea54fc6 100644 --- a/sources/shiboken2/ApiExtractor/typesystemparser.h +++ b/sources/shiboken2/ApiExtractor/typesystemparser.h @@ -162,6 +162,8 @@ private: bool importFileElement(const QXmlStreamAttributes &atts); + const TypeEntry *currentParentTypeEntry() const; + bool checkRootElement(); void applyCommonAttributes(TypeEntry *type, QXmlStreamAttributes *attributes) const; PrimitiveTypeEntry * parsePrimitiveTypeEntry(const QXmlStreamReader &, const QString &name, @@ -174,8 +176,8 @@ private: const QVersionNumber &since, QXmlStreamAttributes *); FlagsTypeEntry * parseFlagsEntry(const QXmlStreamReader &, EnumTypeEntry *enumEntry, - const QString &name, QString flagName, - const QVersionNumber &since, QXmlStreamAttributes *); + QString flagName, const QVersionNumber &since, + QXmlStreamAttributes *); NamespaceTypeEntry * parseNamespaceTypeEntry(const QXmlStreamReader &, diff --git a/sources/shiboken2/data/shiboken_helpers.cmake b/sources/shiboken2/data/shiboken_helpers.cmake index 8111fa61f..5d7ff56bb 100644 --- a/sources/shiboken2/data/shiboken_helpers.cmake +++ b/sources/shiboken2/data/shiboken_helpers.cmake @@ -221,15 +221,20 @@ macro(set_quiet_build) endmacro() macro(get_python_extension_suffix) - # Result of imp.get_suffixes() depends on the platform, but generally looks something like: - # [('.cpython-34m-x86_64-linux-gnu.so', 'rb', 3), ('.cpython-34m.so', 'rb', 3), - # ('.abi3.so', 'rb', 3), ('.so', 'rb', 3), ('.py', 'r', 1), ('.pyc', 'rb', 2)] - # We pick the first most detailed one, strip of the file extension part. + # Result of importlib.machinery.EXTENSION_SUFFIXES depends on the platform, + # but generally looks something like: + # ['.cpython-38-x86_64-linux-gnu.so', '.abi3.so', '.so'] + # We pick the first most detailed one. execute_process( COMMAND ${PYTHON_EXECUTABLE} -c "if True: - import imp, re - first_suffix = imp.get_suffixes()[0][0] + import re + try: + from importlib import machinery + first_suffix = machinery.EXTENSION_SUFFIXES[0] + except AttributeError: + import imp + first_suffix = imp.get_suffixes()[0][0] res = re.search(r'^(.+)\\.', first_suffix) if res: first_suffix = res.group(1) diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp index 6da9fd933..484b1f641 100644 --- a/sources/shiboken2/generator/generator.cpp +++ b/sources/shiboken2/generator/generator.cpp @@ -430,9 +430,16 @@ bool Generator::generate() return false; } + const auto smartPointers = m_d->apiextractor->smartPointers(); for (const AbstractMetaType *type : qAsConst(m_d->instantiatedSmartPointers)) { AbstractMetaClass *smartPointerClass = - AbstractMetaClass::findClass(m_d->apiextractor->smartPointers(), type->typeEntry()); + AbstractMetaClass::findClass(smartPointers, type->typeEntry()); + if (!smartPointerClass) { + qCWarning(lcShiboken, "%s", + qPrintable(msgCannotFindSmartPointer(type->cppSignature(), + smartPointers))); + return false; + } GeneratorContext context(smartPointerClass, type, true); if (!generateFileForContext(context)) return false; @@ -760,7 +767,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 +784,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/qtdoc/qtdocgenerator.cpp b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp index 86abf21b0..ca9f9b3ae 100644 --- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp +++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.cpp @@ -438,15 +438,15 @@ QString QtXmlToSphinx::resolveContextForMethod(const QString& methodName) const } if (metaClass) { - QList<const AbstractMetaFunction*> funcList; + AbstractMetaFunctionList funcList; const AbstractMetaFunctionList &methods = metaClass->queryFunctionsByName(methodName); - for (const AbstractMetaFunction *func : methods) { + for (AbstractMetaFunction *func : methods) { if (methodName == func->name()) funcList.append(func); } const AbstractMetaClass *implementingClass = nullptr; - for (const AbstractMetaFunction *func : qAsConst(funcList)) { + for (AbstractMetaFunction *func : qAsConst(funcList)) { implementingClass = func->implementingClass(); if (implementingClass->name() == currentClass) break; @@ -847,7 +847,7 @@ void QtXmlToSphinx::handleTableTag(QXmlStreamReader& reader) m_tableHasHeader = false; } else if (token == QXmlStreamReader::EndElement) { // write the table on m_output - m_currentTable.enableHeader(m_tableHasHeader); + m_currentTable.setHeaderEnabled(m_tableHasHeader); m_currentTable.normalize(); m_output << ensureEndl << m_currentTable; m_currentTable.clear(); @@ -864,7 +864,7 @@ void QtXmlToSphinx::handleTermTag(QXmlStreamReader& reader) } else if (token == QXmlStreamReader::EndElement) { TableCell cell; cell.data = popOutputBuffer().trimmed(); - m_currentTable << (TableRow() << cell); + m_currentTable.appendRow(TableRow(1, cell)); } } @@ -874,7 +874,7 @@ void QtXmlToSphinx::handleItemTag(QXmlStreamReader& reader) QXmlStreamReader::TokenType token = reader.tokenType(); if (token == QXmlStreamReader::StartElement) { if (m_currentTable.isEmpty()) - m_currentTable << TableRow(); + m_currentTable.appendRow({}); TableRow& row = m_currentTable.last(); TableCell cell; cell.colSpan = reader.attributes().value(QLatin1String("colspan")).toShort(); @@ -896,7 +896,7 @@ void QtXmlToSphinx::handleRowTag(QXmlStreamReader& reader) QXmlStreamReader::TokenType token = reader.tokenType(); if (token == QXmlStreamReader::StartElement) { m_tableHasHeader = reader.name() == QLatin1String("header"); - m_currentTable << TableRow(); + m_currentTable.appendRow({}); } } @@ -919,8 +919,8 @@ void QtXmlToSphinx::handleListTag(QXmlStreamReader& reader) if (token == QXmlStreamReader::StartElement) { listType = webXmlListType(reader.attributes().value(QLatin1String("type"))); if (listType == EnumeratedList) { - m_currentTable << TableRow{TableCell(QLatin1String("Constant")), - TableCell(QLatin1String("Description"))}; + m_currentTable.appendRow(TableRow{TableCell(QLatin1String("Constant")), + TableCell(QLatin1String("Description"))}); m_tableHasHeader = true; } INDENT.indent--; @@ -943,7 +943,7 @@ void QtXmlToSphinx::handleListTag(QXmlStreamReader& reader) } break; case EnumeratedList: - m_currentTable.enableHeader(m_tableHasHeader); + m_currentTable.setHeaderEnabled(m_tableHasHeader); m_currentTable.normalize(); m_output << ensureEndl << m_currentTable; break; @@ -1328,53 +1328,49 @@ void QtXmlToSphinx::Table::normalize() if (m_normalized || isEmpty()) return; - int row; - int col; - QtXmlToSphinx::Table& self = *this; - //QDoc3 generates tables with wrong number of columns. We have to //check and if necessary, merge the last columns. int maxCols = -1; - for (const auto &row : qAsConst(self)) { + for (const auto &row : qAsConst(m_rows)) { if (row.count() > maxCols) maxCols = row.count(); } if (maxCols <= 0) return; // add col spans - for (row = 0; row < count(); ++row) { - for (col = 0; col < at(row).count(); ++col) { - QtXmlToSphinx::TableCell& cell = self[row][col]; + for (int row = 0; row < m_rows.count(); ++row) { + for (int col = 0; col < m_rows.at(row).count(); ++col) { + QtXmlToSphinx::TableCell& cell = m_rows[row][col]; bool mergeCols = (col >= maxCols); if (cell.colSpan > 0) { QtXmlToSphinx::TableCell newCell; newCell.colSpan = -1; for (int i = 0, max = cell.colSpan-1; i < max; ++i) { - self[row].insert(col+1, newCell); + m_rows[row].insert(col + 1, newCell); } cell.colSpan = 0; col++; } else if (mergeCols) { - self[row][maxCols - 1].data += QLatin1Char(' ') + cell.data; + m_rows[row][maxCols - 1].data += QLatin1Char(' ') + cell.data; } } } // row spans - const int numCols = first().count(); - for (col = 0; col < numCols; ++col) { - for (row = 0; row < count(); ++row) { - if (col < self[row].count()) { - QtXmlToSphinx::TableCell& cell = self[row][col]; + const int numCols = m_rows.constFirst().count(); + for (int col = 0; col < numCols; ++col) { + for (int row = 0; row < m_rows.count(); ++row) { + if (col < m_rows[row].count()) { + QtXmlToSphinx::TableCell& cell = m_rows[row][col]; if (cell.rowSpan > 0) { QtXmlToSphinx::TableCell newCell; newCell.rowSpan = -1; int targetRow = row + 1; const int targetEndRow = - std::min(targetRow + cell.rowSpan - 1, count()); + std::min(targetRow + cell.rowSpan - 1, m_rows.count()); cell.rowSpan = 0; for ( ; targetRow < targetEndRow; ++targetRow) - self[targetRow].insert(col, newCell); + m_rows[targetRow].insert(col, newCell); row++; } } @@ -1385,20 +1381,26 @@ void QtXmlToSphinx::Table::normalize() QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table) { - if (table.isEmpty()) - return s; + table.format(s); + return s; +} - if (!table.isNormalized()) { +void QtXmlToSphinx::Table::format (QTextStream& s) const +{ + if (isEmpty()) + return; + + if (!isNormalized()) { qCDebug(lcShiboken) << "Attempt to print an unnormalized table!"; - return s; + return; } // calc width and height of each column and row - const int headerColumnCount = table.constFirst().count(); + const int headerColumnCount = m_rows.constFirst().count(); QVector<int> colWidths(headerColumnCount); - QVector<int> rowHeights(table.count()); - for (int i = 0, maxI = table.count(); i < maxI; ++i) { - const QtXmlToSphinx::TableRow& row = table[i]; + QVector<int> rowHeights(m_rows.count()); + for (int i = 0, maxI = m_rows.count(); i < maxI; ++i) { + const QtXmlToSphinx::TableRow& row = m_rows.at(i); for (int j = 0, maxJ = std::min(row.count(), colWidths.size()); j < maxJ; ++j) { const QVector<QStringRef> rowLines = row[j].data.splitRef(QLatin1Char('\n')); // cache this would be a good idea for (const QStringRef &str : rowLines) @@ -1408,7 +1410,7 @@ QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table) } if (!*std::max_element(colWidths.begin(), colWidths.end())) - return s; // empty table (table with empty cells) + return; // empty table (table with empty cells) // create a horizontal line to be used later. QString horizontalLine = QLatin1String("+"); @@ -1418,8 +1420,8 @@ QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table) } // write table rows - for (int i = 0, maxI = table.count(); i < maxI; ++i) { // for each row - const QtXmlToSphinx::TableRow& row = table[i]; + for (int i = 0, maxI = m_rows.count(); i < maxI; ++i) { // for each row + const QtXmlToSphinx::TableRow& row = m_rows.at(i); // print line s << INDENT << '+'; @@ -1427,7 +1429,7 @@ QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table) char c; if (col >= row.length() || row[col].rowSpan == -1) c = ' '; - else if (i == 1 && table.hasHeader()) + else if (i == 1 && hasHeader()) c = '='; else c = '-'; @@ -1461,7 +1463,6 @@ QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table) } s << INDENT << horizontalLine << endl; s << endl; - return s; } static QString getFuncName(const AbstractMetaFunction* cppFunc) { @@ -2159,7 +2160,7 @@ static void writeFancyToc(QTextStream& s, const QStringList& items, int cols = 4 currentColData.clear(); i = 0; } - table << row; + table.appendRow(row); table.normalize(); s << ".. container:: pysidetoc" << endl << endl; s << table; @@ -2192,15 +2193,23 @@ void QtDocGenerator::writeModuleDocumentation() /* Avoid showing "Detailed Description for *every* class in toc tree */ Indentation indentation(INDENT); + // Store the it.key() in a QString so that it can be stripped off unwanted + // information when neeeded. For example, the RST files in the extras directory + // doesn't include the PySide# prefix in their names. + const QString moduleName = it.key(); + const int lastIndex = moduleName.lastIndexOf(QLatin1Char('.')); // Search for extra-sections if (!m_extraSectionDir.isEmpty()) { QDir extraSectionDir(m_extraSectionDir); - QStringList fileList = extraSectionDir.entryList(QStringList() << (it.key() + QLatin1String("?*.rst")), QDir::Files); + if (!extraSectionDir.exists()) + qCWarning(lcShiboken) << m_extraSectionDir << "doesn't exist"; + + QStringList fileList = extraSectionDir.entryList(QStringList() << (moduleName.mid(lastIndex + 1) + QLatin1String("?*.rst")), QDir::Files); QStringList::iterator it2 = fileList.begin(); for (; it2 != fileList.end(); ++it2) { QString origFileName(*it2); - it2->remove(0, it.key().count() + 1); + it2->remove(0, moduleName.indexOf(QLatin1Char('.'))); QString newFilePath = outputDir + QLatin1Char('/') + *it2; if (QFile::exists(newFilePath)) QFile::remove(newFilePath); @@ -2230,7 +2239,7 @@ void QtDocGenerator::writeModuleDocumentation() s << "--------------------" << endl << endl; // module doc is always wrong and C++istic, so go straight to the extra directory! - QFile moduleDoc(m_extraSectionDir + QLatin1Char('/') + it.key() + QLatin1String(".rst")); + QFile moduleDoc(m_extraSectionDir + QLatin1Char('/') + moduleName.mid(lastIndex + 1) + QLatin1String(".rst")); if (moduleDoc.open(QIODevice::ReadOnly | QIODevice::Text)) { s << moduleDoc.readAll(); moduleDoc.close(); diff --git a/sources/shiboken2/generator/qtdoc/qtdocgenerator.h b/sources/shiboken2/generator/qtdoc/qtdocgenerator.h index 53e292d22..56cb9c4bb 100644 --- a/sources/shiboken2/generator/qtdoc/qtdocgenerator.h +++ b/sources/shiboken2/generator/qtdoc/qtdocgenerator.h @@ -67,13 +67,16 @@ public: TableCell(const char* text) : data(QLatin1String(text)) {} }; - using TableRow = QList<TableCell>; - class Table : public QList<TableRow> + using TableRow = QVector<TableCell>; + + class Table { public: Table() = default; - void enableHeader(bool enable) + bool isEmpty() const { return m_rows.isEmpty(); } + + void setHeaderEnabled(bool enable) { m_hasHeader = enable; } @@ -92,10 +95,19 @@ public: void clear() { m_normalized = false; - QList<TableRow>::clear(); + m_rows.clear(); } + void appendRow(const TableRow &row) { m_rows.append(row); } + + const TableRow &constFirst() { return m_rows.constFirst(); } + TableRow &first() { return m_rows.first(); } + TableRow &last() { return m_rows.last(); } + + void format (QTextStream& s) const; + private: + QVector<TableRow> m_rows; bool m_hasHeader = false; bool m_normalized = false; }; 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..fd75c620e 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -324,18 +324,16 @@ bool ShibokenGenerator::shouldGenerateCppWrapper(const AbstractMetaClass *metaCl void ShibokenGenerator::lookForEnumsInClassesNotToBeGenerated(AbstractMetaEnumList &enumList, const AbstractMetaClass *metaClass) { - if (!metaClass) - return; - + Q_ASSERT(metaClass); + // if a scope is not to be generated, collect its enums into the parent scope if (metaClass->typeEntry()->codeGeneration() == TypeEntry::GenerateForSubclass) { const AbstractMetaEnumList &enums = metaClass->enums(); - for (const AbstractMetaEnum *metaEnum : enums) { - if (metaEnum->isPrivate() || metaEnum->typeEntry()->codeGeneration() == TypeEntry::GenerateForSubclass) - continue; - if (!enumList.contains(const_cast<AbstractMetaEnum *>(metaEnum))) - enumList.append(const_cast<AbstractMetaEnum *>(metaEnum)); + for (AbstractMetaEnum *metaEnum : enums) { + if (!metaEnum->isPrivate() && metaEnum->typeEntry()->generateCode() + && !enumList.contains(metaEnum)) { + enumList.append(metaEnum); + } } - lookForEnumsInClassesNotToBeGenerated(enumList, metaClass->enclosingClass()); } } @@ -571,7 +569,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 +1253,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 +2309,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 +2711,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..cb9041d0c 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**, @@ -267,6 +265,17 @@ we can now capture the error output of COIN and check the generated module in. +Explicitly Enforcing Recreation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The former way to regenerate the registry files was to remove the files +and check that in. This has the desired effect, but creates huge deltas. +As a more efficient way, we have prepared a comment in the first line +that contains the word "recreate". +By uncommenting this line, a NameError is triggered, which has the same +effect. + + init_platform.py ~~~~~~~~~~~~~~~~ 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 0d5681cc5..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 = "3" - +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/libsmart/smart.cpp b/sources/shiboken2/tests/libsmart/smart.cpp index 8d85d67a1..6a4deb50a 100644 --- a/sources/shiboken2/tests/libsmart/smart.cpp +++ b/sources/shiboken2/tests/libsmart/smart.cpp @@ -28,10 +28,52 @@ #include "smart.h" -bool shouldPrint() { +#include <algorithm> +#include <iostream> + +static inline bool shouldPrint() +{ return Registry::getInstance()->shouldPrint(); } +void SharedPtrBase::logDefaultConstructor(const void *t) +{ + if (shouldPrint()) + std::cout << "shared_ptr default constructor " << t << '\n'; +} + +void SharedPtrBase::logConstructor(const void *t, const void *pointee) +{ + if (shouldPrint()) { + std::cout << "shared_ptr constructor " << t << " with pointer " + << pointee << '\n'; + } +} + +void SharedPtrBase::logCopyConstructor(const void *t, const void *refData) +{ + if (shouldPrint()) { + std::cout << "shared_ptr copy constructor " << t << " with pointer " + << refData << '\n'; + } +} + +void SharedPtrBase::logAssignment(const void *t, const void *refData) +{ + if (shouldPrint()) { + std::cout << "shared_ptr assignment operator " << t << " with pointer " + << refData << "\n"; + } +} + +void SharedPtrBase::logDestructor(const void *t, int remainingRefCount) +{ + if (shouldPrint()) { + std::cout << "shared_ptr destructor " << t << " remaining refcount " + << remainingRefCount << '\n'; + } +} + Obj::Obj() : m_integer(123), m_internalInteger(new Integer) { Registry::getInstance()->add(this); @@ -143,10 +185,9 @@ Registry *Registry::getInstance() return ®istry; } -Registry::Registry() : m_printStuff(false) -{ +Registry::Registry() = default; -} +Registry::~Registry() = default; void Registry::add(Obj *p) { diff --git a/sources/shiboken2/tests/libsmart/smart.h b/sources/shiboken2/tests/libsmart/smart.h index 3347b22c1..6238f27d5 100644 --- a/sources/shiboken2/tests/libsmart/smart.h +++ b/sources/shiboken2/tests/libsmart/smart.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** 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. @@ -29,193 +29,9 @@ #ifndef SMART_H #define SMART_H -#include <algorithm> -#include <iostream> -#include <vector> - -#include "libsmartmacros.h" - -// Forward declarations. -template <class T> -class SharedPtr; -class Integer; -class Obj; - -LIB_SMART_API bool shouldPrint(); - -// Used to track which C++ objects are alive. -class LIB_SMART_API Registry { -public: - static Registry *getInstance(); - - void add(Obj *p); - void add(Integer *p); - void remove(Obj *p); - void remove(Integer *p); - int countObjects() const; - int countIntegers() const; - bool shouldPrint() const; - void setShouldPrint(bool flag); - -protected: - Registry(); - -private: - bool m_printStuff; - std::vector<Obj *> m_objects; - std::vector<Integer *> m_integers; -}; - -template <class T> -class RefData { -public: - RefData(T *ptr) : m_refCount(1), m_heldPtr(ptr) {} - ~RefData() { delete m_heldPtr; } - int inc() { return ++m_refCount; } - int dec() { return --m_refCount; } - int useCount() { return m_refCount; } - int m_refCount; - T *m_heldPtr; -}; - -template <class T> -class SharedPtr { -public: - SharedPtr() : m_refData(nullptr) { - if (shouldPrint()) - std::cout << "shared_ptr default constructor " << this << "\n"; - } - - SharedPtr(T *v) - { - if (shouldPrint()) - std::cout << "shared_ptr constructor " << this << " with pointer " << v << "\n"; - if (v) - m_refData = new RefData<T>(v); - } - - SharedPtr(const SharedPtr<T> &other) : m_refData(other.m_refData) - { - if (shouldPrint()) - std::cout << "shared_ptr copy constructor " << this << " with pointer " - << other.m_refData << "\n"; - if (m_refData) - m_refData->inc(); - } - - SharedPtr<T> &operator=(const SharedPtr<T>& other) - { - if (this != &other) { - if (shouldPrint()) - std::cout << "shared_ptr assignment operator " << this << " with pointer " - << other.m_refData << "\n"; - if (m_refData && m_refData->dec() == 0) - delete m_refData; - m_refData = other.m_refData; - if (m_refData) - m_refData->inc(); - } - return *this; - } - - T *data() const - { - if (m_refData) - return m_refData->m_heldPtr; - return nullptr; - } - - int useCount() const - { - if (m_refData) - return m_refData->useCount(); - return 0; - } - - void dummyMethod1() - { - - } - - T& operator*() const - { - // Crashes if smart pointer is empty (just like std::shared_ptr). - return *(m_refData->m_heldPtr); - } - - T *operator->() const - { - if (m_refData) - return m_refData->m_heldPtr; - return nullptr; - } - - bool operator!() const - { - return !m_refData || !m_refData->m_heldPtr; - } - - bool isNull() const - { - return !m_refData || !m_refData->m_heldPtr; - } - - operator bool() const - { - return m_refData && m_refData->m_heldPtr; - } - - ~SharedPtr() - { - if (m_refData) { - if (shouldPrint()) - std::cout << "shared_ptr destructor " << this << " remaining refcount " - << m_refData->useCount() - 1 << "\n"; - } - if (m_refData && m_refData->dec() == 0) - delete m_refData; - } - - RefData<T> *m_refData; -}; - -class LIB_SMART_API Integer { -public: - Integer(); - Integer(const Integer &other); - Integer &operator=(const Integer &other); - ~Integer(); - void printInteger(); - int m_int; -}; - -namespace Smart { -class LIB_SMART_API Integer2 : public Integer { -public: - Integer2(); - Integer2(const Integer2 &other); -}; -} - - -// Couldn't name it Object because it caused some namespace clashes. -class LIB_SMART_API Obj { -public: - Obj(); - virtual ~Obj(); - - void printObj(); - Integer takeInteger(Integer val); - SharedPtr<Obj> giveSharedPtrToObj(); - std::vector<SharedPtr<Obj> > giveSharedPtrToObjList(int size); - SharedPtr<Integer> giveSharedPtrToInteger(); - SharedPtr<Smart::Integer2> giveSharedPtrToInteger2(); - int takeSharedPtrToObj(SharedPtr<Obj> pObj); - int takeSharedPtrToInteger(SharedPtr<Integer> pInt); - - int m_integer; - Integer *m_internalInteger; -}; +#include "smart_sharedptr.h" +#include "smart_integer.h" +#include "smart_obj.h" +#include "smart_registry.h" #endif // SMART_H - diff --git a/sources/shiboken2/tests/libsmart/smart_integer.h b/sources/shiboken2/tests/libsmart/smart_integer.h new file mode 100644 index 000000000..3756f68b0 --- /dev/null +++ b/sources/shiboken2/tests/libsmart/smart_integer.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef SMART_INTEGER_H +#define SMART_INTEGER_H + +#include "libsmartmacros.h" + +class LIB_SMART_API Integer { +public: + Integer(); + Integer(const Integer &other); + Integer &operator=(const Integer &other); + ~Integer(); + void printInteger(); + int m_int; +}; + +namespace Smart { +class LIB_SMART_API Integer2 : public Integer { +public: + Integer2(); + Integer2(const Integer2 &other); +}; +} // namespace Smart + +#endif // SMART_INTEGER_H diff --git a/sources/shiboken2/tests/libsmart/smart_obj.h b/sources/shiboken2/tests/libsmart/smart_obj.h new file mode 100644 index 000000000..12425366e --- /dev/null +++ b/sources/shiboken2/tests/libsmart/smart_obj.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef SMART_OBJ_H +#define SMART_OBJ_H + +#include "libsmartmacros.h" +#include "smart_sharedptr.h" + +#include <vector> + +class Integer; +class Obj; +namespace Smart { class Integer2; } + +// Couldn't name it Object because it caused some namespace clashes. +class LIB_SMART_API Obj { +public: + Obj(); + virtual ~Obj(); + + void printObj(); + Integer takeInteger(Integer val); + SharedPtr<Obj> giveSharedPtrToObj(); + std::vector<SharedPtr<Obj> > giveSharedPtrToObjList(int size); + SharedPtr<Integer> giveSharedPtrToInteger(); + SharedPtr<Smart::Integer2> giveSharedPtrToInteger2(); + int takeSharedPtrToObj(SharedPtr<Obj> pObj); + int takeSharedPtrToInteger(SharedPtr<Integer> pInt); + + int m_integer; + Integer *m_internalInteger; +}; + +#endif // SMART_OBJ_H diff --git a/sources/shiboken2/tests/libsmart/smart_registry.h b/sources/shiboken2/tests/libsmart/smart_registry.h new file mode 100644 index 000000000..6171ddb59 --- /dev/null +++ b/sources/shiboken2/tests/libsmart/smart_registry.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef SMART_REGISTRY_H +#define SMART_REGISTRY_H + +#include <vector> + +#include "libsmartmacros.h" + +class Obj; +class Integer; + +// Used to track which C++ objects are alive. +class LIB_SMART_API Registry { +public: + static Registry *getInstance(); + ~Registry(); + + Registry(const Registry &) = delete; + Registry &operator=(const Registry &) = delete; + Registry(Registry &&) = delete; + Registry &operator=(Registry &&) = delete; + + void add(Obj *p); + void add(Integer *p); + void remove(Obj *p); + void remove(Integer *p); + int countObjects() const; + int countIntegers() const; + bool shouldPrint() const; + void setShouldPrint(bool flag); + +protected: + Registry(); + +private: + std::vector<Obj *> m_objects; + std::vector<Integer *> m_integers; + bool m_printStuff = false; +}; + +#endif // SMART_REGISTRY_H diff --git a/sources/shiboken2/tests/libsmart/smart_sharedptr.h b/sources/shiboken2/tests/libsmart/smart_sharedptr.h new file mode 100644 index 000000000..84184e1f8 --- /dev/null +++ b/sources/shiboken2/tests/libsmart/smart_sharedptr.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef SMART_SHARED_PTR_H +#define SMART_SHARED_PTR_H + +#include "libsmartmacros.h" + +template <class T> +class RefData { +public: + RefData(T *ptr) : m_refCount(1), m_heldPtr(ptr) {} + ~RefData() { delete m_heldPtr; } + int inc() { return ++m_refCount; } + int dec() { return --m_refCount; } + int useCount() { return m_refCount; } + int m_refCount; + T *m_heldPtr; +}; + +struct SharedPtrBase +{ + LIB_SMART_API static void logDefaultConstructor(const void *t); + LIB_SMART_API static void logConstructor(const void *t, const void *pointee); + LIB_SMART_API static void logCopyConstructor(const void *t, const void *refData); + LIB_SMART_API static void logAssignment(const void *t, const void *refData); + LIB_SMART_API static void logDestructor(const void *t, int remainingRefCount); +}; + +template <class T> +class SharedPtr : public SharedPtrBase { +public: + SharedPtr() { logDefaultConstructor(this); } + + SharedPtr(T *v) + { + logConstructor(this, v); + if (v) + m_refData = new RefData<T>(v); + } + + SharedPtr(const SharedPtr<T> &other) : m_refData(other.m_refData) + { + logCopyConstructor(this, other.m_refData); + if (m_refData) + m_refData->inc(); + } + + SharedPtr<T> &operator=(const SharedPtr<T>& other) + { + if (this != &other) { + logAssignment(this, other.m_refData); + if (m_refData && m_refData->dec() == 0) + delete m_refData; + m_refData = other.m_refData; + if (m_refData) + m_refData->inc(); + } + return *this; + } + + T *data() const + { + return m_refData ? m_refData->m_heldPtr : nullptr; + } + + int useCount() const + { + return m_refData ? m_refData->useCount() : 0; + } + + void dummyMethod1() + { + + } + + T& operator*() const + { + // Crashes if smart pointer is empty (just like std::shared_ptr). + return *(m_refData->m_heldPtr); + } + + T *operator->() const + { + return m_refData ? m_refData->m_heldPtr : nullptr; + } + + bool operator!() const + { + return !m_refData || !m_refData->m_heldPtr; + } + + bool isNull() const + { + return !m_refData || !m_refData->m_heldPtr; + } + + operator bool() const + { + return m_refData && m_refData->m_heldPtr; + } + + ~SharedPtr() + { + if (m_refData) + logDestructor(this, m_refData->useCount() - 1); + if (m_refData && m_refData->dec() == 0) + delete m_refData; + } + +private: + RefData<T> *m_refData = nullptr; +}; + +#endif // SMART_SHARED_PTR_H 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"> |