diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-05-15 10:23:11 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-05-18 17:07:23 +0200 |
commit | 8d65e9c3e451d9ad3a715dacdb2b415bc2dca8a3 (patch) | |
tree | a3fa7246457fc7577ee47978e883aa5126ba6ba6 | |
parent | dc9c6f502e82105dd4c4cc5f3aca5915ed163910 (diff) |
Add support for template type aliases
In Qt 6 as of May 2020, this is used to alias QList to QVector:
template<typename T> using QList = QVector<T>
which shiboken needs to handle. Introduce a new code model
item for this and add it to the resolver.
Task-number: PYSIDE-904
Change-Id: I9e558635e843b60d44c0ceaaaa68b09b50c25c9f
Reviewed-by: Christian Tismer <tismer@stackless.com>
6 files changed, 217 insertions, 11 deletions
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp index ebec8770e..63de317c3 100644 --- a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp +++ b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp @@ -191,6 +191,8 @@ public: bool addTemplateInstantiationsRecursion(const CXType &type, TypeInfo *t) const; void addTypeDef(const CXCursor &cursor, const CXType &cxType); + void startTemplateTypeAlias(const CXCursor &cursor); + void endTemplateTypeAlias(const CXCursor &typeAliasCursor); TemplateParameterModelItem createTemplateParameter(const CXCursor &cursor) const; TemplateParameterModelItem createNonTypeTemplateParameter(const CXCursor &cursor) const; @@ -216,12 +218,14 @@ public: CursorTypedefHash m_cursorTypedefHash; mutable TypeInfoHash m_typeInfoHash; // Cache type information + mutable QHash<QString, TemplateTypeAliasModelItem> m_templateTypeAliases; ClassModelItem m_currentClass; EnumModelItem m_currentEnum; FunctionModelItem m_currentFunction; ArgumentModelItem m_currentArgument; VariableModelItem m_currentField; + TemplateTypeAliasModelItem m_currentTemplateTypeAlias; QByteArrayList m_systemIncludes; // files, like "memory" QByteArrayList m_systemIncludePaths; // paths, like "/usr/include/Qt/" @@ -552,6 +556,26 @@ void BuilderPrivate::addTypeDef(const CXCursor &cursor, const CXType &cxType) m_cursorTypedefHash.insert(cursor, item); } +void BuilderPrivate::startTemplateTypeAlias(const CXCursor &cursor) +{ + const QString target = getCursorSpelling(cursor); + m_currentTemplateTypeAlias.reset(new _TemplateTypeAliasModelItem(m_model, target)); + setFileName(cursor, m_currentTemplateTypeAlias.data()); + m_currentTemplateTypeAlias->setScope(m_scope); +} + +void BuilderPrivate::endTemplateTypeAlias(const CXCursor &typeAliasCursor) +{ + CXType type = clang_getTypedefDeclUnderlyingType(typeAliasCursor); + // Usually "<elaborated>std::list<T>" or "<unexposed>Container1<T>", + // as obtained with parser of PYSIDE-323 + if (type.kind == CXType_Unexposed || type.kind == CXType_Elaborated) { + m_currentTemplateTypeAlias->setType(createTypeInfo(type)); + m_scopeStack.back()->addTemplateTypeAlias(m_currentTemplateTypeAlias); + } + m_currentTemplateTypeAlias.reset(); +} + // extract an expression from the cursor via source // CXCursor_EnumConstantDecl, ParmDecl (a = Flag1 | Flag2) QString BuilderPrivate::cursorValueExpression(BaseVisitor *bv, const CXCursor &cursor) const @@ -597,8 +621,22 @@ long clang_EnumDecl_isScoped4(BaseVisitor *bv, const CXCursor &cursor) // Add a base class to the current class from CXCursor_CXXBaseSpecifier void BuilderPrivate::addBaseClass(const CXCursor &cursor) { - const CXType inheritedType = clang_getCursorType(cursor); // Note spelling has "struct baseClass", - QString baseClassName = getTypeName(inheritedType); // use type. + // Note: spelling has "struct baseClass", use type + QString baseClassName; + const CXType inheritedType = clang_getCursorType(cursor); + if (inheritedType.kind == CXType_Unexposed) { + // The type is unexposed when the base class is a template type alias: + // "class QItemSelection : public QList<X>" where QList is aliased to QVector. + // Try to resolve via code model. + TypeInfo info = createTypeInfo(inheritedType); + auto parentScope = m_scopeStack.at(m_scopeStack.size() - 2); // Current is class. + auto resolved = TypeInfo::resolveType(info, parentScope); + if (resolved != info) + baseClassName = resolved.toString(); + } + if (baseClassName.isEmpty()) + baseClassName = getTypeName(inheritedType); + const CXCursor declCursor = clang_getTypeDeclaration(inheritedType); const CursorClassHash::const_iterator it = m_cursorClassHash.constFind(declCursor); const CodeModel::AccessPolicy access = accessPolicy(clang_getCXXAccessSpecifier(cursor)); @@ -990,6 +1028,8 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) // Apply to function/member template? if (!d->m_currentFunction.isNull()) { d->m_currentFunction->setTemplateParameters(d->m_currentFunction->templateParameters() << tItem); + } else if (!d->m_currentTemplateTypeAlias.isNull()) { + d->m_currentTemplateTypeAlias->addTemplateParameter(tItem); } else if (!d->m_currentClass.isNull()) { // Apply to class const QString &tplParmName = tItem->name(); if (Q_UNLIKELY(!insertTemplateParameterIntoClassName(tplParmName, d->m_currentClass) @@ -1005,13 +1045,19 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor) } } break; - case CXCursor_TypeAliasDecl: - case CXCursor_TypeAliasTemplateDecl: { // May contain nested CXCursor_TemplateTypeParameter - const CXType type = clang_getCanonicalType(clang_getCursorType(cursor)); - if (type.kind > CXType_Unexposed) - d->addTypeDef(cursor, type); - } - return Skip; + case CXCursor_TypeAliasTemplateDecl: + d->startTemplateTypeAlias(cursor); + break; + case CXCursor_TypeAliasDecl: // May contain nested CXCursor_TemplateTypeParameter + if (d->m_currentTemplateTypeAlias.isNull()) { + const CXType type = clang_getCanonicalType(clang_getCursorType(cursor)); + if (type.kind > CXType_Unexposed) + d->addTypeDef(cursor, type); + return Skip; + } else { + d->endTemplateTypeAlias(cursor); + } + break; case CXCursor_TypedefDecl: { auto underlyingType = clang_getTypedefDeclUnderlyingType(cursor); d->addTypeDef(cursor, underlyingType); @@ -1090,6 +1136,9 @@ bool Builder::endToken(const CXCursor &cursor) case CXCursor_ParmDecl: d->m_currentArgument.clear(); break; + case CXCursor_TypeAliasTemplateDecl: + d->m_currentTemplateTypeAlias.reset(); + break; default: break; } diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.cpp b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp index a33887836..e381ba083 100644 --- a/sources/shiboken2/ApiExtractor/parser/codemodel.cpp +++ b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp @@ -91,6 +91,8 @@ static CodeModelItem findRecursion(const ScopeModelItem &scope, return es; if (TypeDefModelItem tp = scope->findTypeDef(nameSegment)) return tp; + if (TemplateTypeAliasModelItem tta = scope->findTemplateTypeAlias(nameSegment)) + return tta; return CodeModelItem(); } if (auto nestedClass = scope->findClass(nameSegment)) @@ -191,6 +193,23 @@ TypeInfo TypeInfo::resolveType(CodeModelItem __item, TypeInfo const &__type, con return resolveType(nextItem, combined, __scope); } + if (TemplateTypeAliasModelItem templateTypeAlias = qSharedPointerDynamicCast<_TemplateTypeAliasModelItem>(__item)) { + + TypeInfo combined = TypeInfo::combine(templateTypeAlias->type(), otherType); + // For the alias "template<typename T> using QList = QVector<T>" with + // other="QList<int>", replace the instantiations to obtain "QVector<int>". + auto aliasInstantiations = templateTypeAlias->type().instantiations(); + auto concreteInstantiations = otherType.instantiations(); + const int count = qMin(aliasInstantiations.size(), concreteInstantiations.size()); + for (int i = 0; i < count; ++i) + aliasInstantiations[i] = concreteInstantiations[i]; + combined.setInstantiations(aliasInstantiations); + const CodeModelItem nextItem = __scope->model()->findItem(combined.qualifiedName(), __scope); + if (!nextItem) + return combined; + return resolveType(nextItem, combined, __scope); + } + return otherType; } @@ -639,6 +658,9 @@ void _CodeModelItem::formatKind(QDebug &d, int k) case Kind_TypeDef: d << "TypeDefModelItem"; break; + case Kind_TemplateTypeAlias: + d << "TemplateTypeAliasModelItem"; + break; default: d << "CodeModelItem"; break; @@ -802,6 +824,11 @@ void _ScopeModelItem::addTypeDef(const TypeDefModelItem &item) m_typeDefs.append(item); } +void _ScopeModelItem::addTemplateTypeAlias(const TemplateTypeAliasModelItem &item) +{ + m_templateTypeAliases.append(item); +} + void _ScopeModelItem::addEnum(const EnumModelItem &item) { m_enums.append(item); @@ -812,6 +839,7 @@ void _ScopeModelItem::appendScope(const _ScopeModelItem &other) m_classes += other.m_classes; m_enums += other.m_enums; m_typeDefs += other.m_typeDefs; + m_templateTypeAliases += other.m_templateTypeAliases; m_variables += other.m_variables; m_functions += other.m_functions; m_enumsDeclarations += other.m_enumsDeclarations; @@ -856,6 +884,7 @@ void _ScopeModelItem::formatScopeItemsDebug(QDebug &d) const formatScopeList(d, ", classes=", m_classes, "\n", true); formatScopeList(d, ", enums=", m_enums, "\n", true); formatScopeList(d, ", aliases=", m_typeDefs, "\n", true); + formatScopeList(d, ", template type aliases=", m_templateTypeAliases, "\n", true); formatScopeList(d, ", functions=", m_functions, "\n", true); formatScopeList(d, ", variables=", m_variables); } @@ -907,6 +936,11 @@ TypeDefModelItem _ScopeModelItem::findTypeDef(const QString &name) const return findModelItem(m_typeDefs, name); } +TemplateTypeAliasModelItem _ScopeModelItem::findTemplateTypeAlias(const QString &name) const +{ + return findModelItem(m_templateTypeAliases, name); +} + EnumModelItem _ScopeModelItem::findEnum(const QString &name) const { return findModelItem(m_enums, name); @@ -1226,6 +1260,48 @@ void _TypeDefModelItem::formatDebug(QDebug &d) const #endif // !QT_NO_DEBUG_STREAM // --------------------------------------------------------------------------- + +_TemplateTypeAliasModelItem::_TemplateTypeAliasModelItem(CodeModel *model, int kind) + : _CodeModelItem(model, kind) {} + +_TemplateTypeAliasModelItem::_TemplateTypeAliasModelItem(CodeModel *model, const QString &name, int kind) + : _CodeModelItem(model, name, kind) {} + +TemplateParameterList _TemplateTypeAliasModelItem::templateParameters() const +{ + return m_templateParameters; +} + +void _TemplateTypeAliasModelItem::addTemplateParameter(const TemplateParameterModelItem &templateParameter) +{ + m_templateParameters.append(templateParameter); +} + +TypeInfo _TemplateTypeAliasModelItem::type() const +{ + return m_type; +} + +void _TemplateTypeAliasModelItem::setType(const TypeInfo &type) +{ + m_type = type; +} + +#ifndef QT_NO_DEBUG_STREAM +void _TemplateTypeAliasModelItem::formatDebug(QDebug &d) const +{ + _CodeModelItem::formatDebug(d); + d << ", <"; + for (int i = 0, count = m_templateParameters.size(); i < count; ++i) { + if (i) + d << ", "; + d << m_templateParameters.at(i)->name(); + } + d << ">, type=" << m_type; +} +#endif // !QT_NO_DEBUG_STREAM + +// --------------------------------------------------------------------------- CodeModel::AccessPolicy _EnumModelItem::accessPolicy() const { return m_accessPolicy; @@ -1473,4 +1549,3 @@ void _MemberModelItem::formatDebug(QDebug &d) const #endif // !QT_NO_DEBUG_STREAM // kate: space-indent on; indent-width 2; replace-tabs on; - diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.h b/sources/shiboken2/ApiExtractor/parser/codemodel.h index cfe2e055c..5bbd9ed3e 100644 --- a/sources/shiboken2/ApiExtractor/parser/codemodel.h +++ b/sources/shiboken2/ApiExtractor/parser/codemodel.h @@ -267,7 +267,8 @@ public: Kind_File = 5 << FirstKind | Kind_Namespace, Kind_TemplateParameter = 7 << FirstKind, Kind_TypeDef = 8 << FirstKind, - Kind_Variable = 9 << FirstKind | Kind_Member + Kind_TemplateTypeAlias = 9 << FirstKind, + Kind_Variable = 10 << FirstKind | Kind_Member }; public: @@ -333,18 +334,21 @@ public: EnumList enums() const { return m_enums; } inline FunctionList functions() const { return m_functions; } TypeDefList typeDefs() const { return m_typeDefs; } + TemplateTypeAliasList templateTypeAliases() const { return m_templateTypeAliases; } VariableList variables() const { return m_variables; } void addClass(const ClassModelItem &item); void addEnum(const EnumModelItem &item); void addFunction(const FunctionModelItem &item); void addTypeDef(const TypeDefModelItem &item); + void addTemplateTypeAlias(const TemplateTypeAliasModelItem &item); void addVariable(const VariableModelItem &item); ClassModelItem findClass(const QString &name) const; EnumModelItem findEnum(const QString &name) const; FunctionList findFunctions(const QString &name) const; TypeDefModelItem findTypeDef(const QString &name) const; + TemplateTypeAliasModelItem findTemplateTypeAlias(const QString &name) const; VariableModelItem findVariable(const QString &name) const; void addEnumsDeclaration(const QString &enumsDeclaration); @@ -372,6 +376,7 @@ private: ClassList m_classes; EnumList m_enums; TypeDefList m_typeDefs; + TemplateTypeAliasList m_templateTypeAliases; VariableList m_variables; FunctionList m_functions; @@ -683,6 +688,30 @@ private: TypeInfo m_type; }; +class _TemplateTypeAliasModelItem : public _CodeModelItem +{ +public: + DECLARE_MODEL_NODE(TemplateTypeAlias) + + explicit _TemplateTypeAliasModelItem(CodeModel *model, int kind = __node_kind); + explicit _TemplateTypeAliasModelItem(CodeModel *model, const QString &name, + int kind = __node_kind); + + TemplateParameterList templateParameters() const; + void addTemplateParameter(const TemplateParameterModelItem &templateParameter); + + TypeInfo type() const; + void setType(const TypeInfo &type); + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const override; +#endif + +private: + TemplateParameterList m_templateParameters; + TypeInfo m_type; +}; + class _EnumModelItem: public _CodeModelItem { public: diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel_fwd.h b/sources/shiboken2/ApiExtractor/parser/codemodel_fwd.h index 54dbe78dc..87fea5cde 100644 --- a/sources/shiboken2/ApiExtractor/parser/codemodel_fwd.h +++ b/sources/shiboken2/ApiExtractor/parser/codemodel_fwd.h @@ -47,6 +47,7 @@ class _NamespaceModelItem; class _ScopeModelItem; class _TemplateParameterModelItem; class _TypeDefModelItem; +class _TemplateTypeAliasModelItem; class _VariableModelItem; class _MemberModelItem; class TypeInfo; @@ -62,6 +63,7 @@ using NamespaceModelItem = QSharedPointer<_NamespaceModelItem>; using ScopeModelItem = QSharedPointer<_ScopeModelItem>; using TemplateParameterModelItem = QSharedPointer<_TemplateParameterModelItem>; using TypeDefModelItem = QSharedPointer<_TypeDefModelItem>; +using TemplateTypeAliasModelItem = QSharedPointer<_TemplateTypeAliasModelItem>; using VariableModelItem = QSharedPointer<_VariableModelItem>; using MemberModelItem = QSharedPointer<_MemberModelItem>; @@ -76,6 +78,7 @@ using NamespaceList = QVector<NamespaceModelItem>; using ScopeList = QVector<ScopeModelItem>; using TemplateParameterList = QVector<TemplateParameterModelItem>; using TypeDefList = QVector<TypeDefModelItem>; +using TemplateTypeAliasList = QVector<TemplateTypeAliasModelItem>; using VariableList = QVector<VariableModelItem>; using MemberList = QVector<MemberModelItem>; diff --git a/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp index 5191cb38d..926b0bc59 100644 --- a/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp +++ b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp @@ -561,4 +561,53 @@ void TestTemplates::testTemplateTypeDefs() QCOMPARE(xmlValueField->type()->cppSignature(), QLatin1String("int")); } +void TestTemplates::testTemplateTypeAliases() +{ + // Model Qt 6's "template<typename T> using QList = QVector<T>" + const char cppCode[] = R"CPP( +template<typename T> +class Container1 { }; + +template<typename T> +using Container2 = Container1<T>; + +class Test +{ +public: + Container2<int> m_intContainer; +}; + +class Derived : public Container2<int> +{ +public: +}; +)CPP"; + + const char xmlCode[] = R"XML( +<typesystem package='Foo'> + <primitive-type name='int'/> + <value-type name='Container1'/> + <value-type name='Derived'/> + <object-type name='Test'/> +</typesystem>)XML"; + + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true)); + QVERIFY(!builder.isNull()); + + AbstractMetaClassList classes = builder->classes(); + auto testClass = AbstractMetaClass::findClass(classes, QLatin1String("Test")); + QVERIFY(testClass); + + auto fields = testClass->fields(); + QCOMPARE(fields.count(), 1); + auto fieldType = testClass->fields().at(0)->type(); + QCOMPARE(fieldType->name(), QLatin1String("Container1")); + QCOMPARE(fieldType->instantiations().size(), 1); + + auto derived = AbstractMetaClass::findClass(classes, QLatin1String("Derived")); + QVERIFY(derived); + auto base = derived->templateBaseClass(); + QCOMPARE(base->name(), QLatin1String("Container1")); +} + QTEST_APPLESS_MAIN(TestTemplates) diff --git a/sources/shiboken2/ApiExtractor/tests/testtemplates.h b/sources/shiboken2/ApiExtractor/tests/testtemplates.h index df3de18b9..80d97512e 100644 --- a/sources/shiboken2/ApiExtractor/tests/testtemplates.h +++ b/sources/shiboken2/ApiExtractor/tests/testtemplates.h @@ -48,6 +48,7 @@ private slots: void testContainerTypeIncompleteArgument(); void testTemplateTypeDefs_data(); void testTemplateTypeDefs(); + void testTemplateTypeAliases(); }; #endif |