aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2020-05-15 10:23:11 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2020-05-18 17:07:23 +0200
commit8d65e9c3e451d9ad3a715dacdb2b415bc2dca8a3 (patch)
treea3fa7246457fc7577ee47978e883aa5126ba6ba6
parentdc9c6f502e82105dd4c4cc5f3aca5915ed163910 (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>
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp67
-rw-r--r--sources/shiboken2/ApiExtractor/parser/codemodel.cpp77
-rw-r--r--sources/shiboken2/ApiExtractor/parser/codemodel.h31
-rw-r--r--sources/shiboken2/ApiExtractor/parser/codemodel_fwd.h3
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testtemplates.cpp49
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testtemplates.h1
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