diff --git a/plugins/clang/duchain/builder.cpp b/plugins/clang/duchain/builder.cpp --- a/plugins/clang/duchain/builder.cpp +++ b/plugins/clang/duchain/builder.cpp @@ -69,6 +69,24 @@ } //BEGIN helpers +// HACK: current alias type template machinery is badly broken wrt spelling +// location, work around this by adjusting all references to point to child +// type alias node with proper location +// TODO: investigate upstream implementation of CXCursor_TypeAliasTemplateDecl +CXCursor findEmbeddedTypeAlias(CXCursor aliasTemplate) +{ + auto result = clang_getNullCursor(); + clang_visitChildren(aliasTemplate, [] (CXCursor cursor, CXCursor, CXClientData data) { + if (clang_getCursorKind(cursor) == CXCursor_TypeAliasDecl) { + auto res = reinterpret_cast(data); + *res = cursor; + return CXChildVisit_Break; + } + return CXChildVisit_Continue; + }, &result); + return result; +} + /** * Find the cursor that cursor @p cursor references * @@ -81,6 +99,11 @@ CXCursor referencedCursor(CXCursor cursor) { auto referenced = clang_getCursorReferenced(cursor); + // HACK: see notes at getEmbeddedTypeAlias() + if (clang_getCursorKind(referenced) == CXCursor_TypeAliasTemplateDecl) { + return findEmbeddedTypeAlias(referenced); + } + if (!clang_equalCursors(cursor, referenced)) { return referenced; } @@ -321,6 +344,12 @@ EnableIf = dummy> CXChildVisitResult dispatchCursor(CXCursor cursor, CXCursor parent); + CXChildVisitResult dispatchTypeAliasTemplate(CXCursor cursor, CXCursor parent) + { + return CursorKindTraits::isClass(clang_getCursorKind(parent)) ? buildTypeAliasTemplateDecl(cursor) + : buildTypeAliasTemplateDecl(cursor); + } + template AbstractType *dispatchType(CXType type, CXCursor cursor) { @@ -338,6 +367,9 @@ template CXChildVisitResult buildDeclaration(CXCursor cursor); + template + CXChildVisitResult buildTypeAliasTemplateDecl(CXCursor cursor); + CXChildVisitResult buildUse(CXCursor cursor); CXChildVisitResult buildMacroExpansion(CXCursor cursor); CXChildVisitResult buildCompoundStatement(CXCursor cursor); @@ -1213,6 +1245,26 @@ classDecl->addBaseClass({decl->indexedType(), access, virtualInherited}); return CXChildVisit_Recurse; } + +template +CXChildVisitResult Visitor::buildTypeAliasTemplateDecl(CXCursor cursor) +{ + auto aliasDecl = findEmbeddedTypeAlias(cursor); + // NOTE: using aliasDecl here averts having to add a workaround to makeId() + auto id = makeId(aliasDecl); + // create template context to prevent leaking child template params + auto context = createContext(cursor, QualifiedIdentifier(id)); + using DeclType = typename DeclType::Type; + createDeclaration(aliasDecl, id, context); + CurrentContext newParent(context, m_parentContext->keepAliveContexts); + PushValue pushCurrent(m_parentContext, &newParent); + clang_visitChildren(cursor, [] (CXCursor cursor, CXCursor parent, CXClientData data) { + // NOTE: immediately recurse into embedded alias decl + return clang_getCursorKind(cursor) == CXCursor_TypeAliasDecl ? + CXChildVisit_Recurse : visitCursor(cursor, parent, data); + }, this); + return CXChildVisit_Continue; +} //END build* DeclarationPointer Visitor::findDeclaration(CXCursor cursor) const @@ -1503,6 +1555,9 @@ return visitor->buildCXXBaseSpecifier(cursor); case CXCursor_ParmDecl: return visitor->buildParmDecl(cursor); + // TODO: fix upstream and then just adapt this to UseCursorKind() + case CXCursor_TypeAliasTemplateDecl: + return visitor->dispatchTypeAliasTemplate(cursor, parent); default: return CXChildVisit_Recurse; } diff --git a/plugins/clang/tests/test_duchain.cpp b/plugins/clang/tests/test_duchain.cpp --- a/plugins/clang/tests/test_duchain.cpp +++ b/plugins/clang/tests/test_duchain.cpp @@ -1729,19 +1729,24 @@ void TestDUChain::testTypeAliasTemplate() { - TestFile file(QStringLiteral("template using TypeAliasTemplate = T;"), QStringLiteral("cpp")); + TestFile file(QStringLiteral("template using Alias = T; using Foo = Alias;"), QStringLiteral("cpp")); QVERIFY(file.parseAndWait()); DUChainReadLocker lock; QVERIFY(file.topContext()); - auto templateAlias = file.topContext()->localDeclarations().last(); + QCOMPARE(file.topContext()->localDeclarations().size(), 2); + auto templateAlias = file.topContext()->localDeclarations().first(); QVERIFY(templateAlias); #if CINDEX_VERSION_MINOR < 31 QEXPECT_FAIL("", "TypeAliasTemplate is not exposed via LibClang", Abort); #endif + QVERIFY(templateAlias->isTypeAlias()); QVERIFY(templateAlias->abstractType()); - QCOMPARE(templateAlias->abstractType()->toString(), QStringLiteral("TypeAliasTemplate")); + QCOMPARE(templateAlias->abstractType()->toString(), QStringLiteral("Alias")); + QCOMPARE(templateAlias->uses().size(), 1); + QCOMPARE(templateAlias->uses().first().size(), 1); + QCOMPARE(templateAlias->uses().first().first(), RangeInRevision(0, 51, 0, 56)); } void TestDUChain::testDeclarationsInsideMacroExpansion()