[clangd] Have template template arguments target their referenced template decl

Fixes https://github.com/clangd/clangd/issues/473

Differential Revision: https://reviews.llvm.org/D85503
This commit is contained in:
Nathan Ridge 2020-08-09 20:37:43 -04:00
parent 582fd474dd
commit 70d583ad12
4 changed files with 38 additions and 2 deletions

View File

@ -596,6 +596,19 @@ public:
add(CCI->getAnyMember(), Flags); add(CCI->getAnyMember(), Flags);
// Constructor calls contain a TypeLoc node, so we don't handle them here. // Constructor calls contain a TypeLoc node, so we don't handle them here.
} }
void add(const TemplateArgument &Arg, RelSet Flags) {
// Only used for template template arguments.
// For type and non-type template arguments, SelectionTree
// will hit a more specific node (e.g. a TypeLoc or a
// DeclRefExpr).
if (Arg.getKind() == TemplateArgument::Template ||
Arg.getKind() == TemplateArgument::TemplateExpansion) {
if (TemplateDecl *TD = Arg.getAsTemplate().getAsTemplateDecl()) {
report(TD, Flags);
}
}
}
}; };
} // namespace } // namespace
@ -619,6 +632,8 @@ allTargetDecls(const ast_type_traits::DynTypedNode &N) {
Finder.add(*QT, Flags); Finder.add(*QT, Flags);
else if (const CXXCtorInitializer *CCI = N.get<CXXCtorInitializer>()) else if (const CXXCtorInitializer *CCI = N.get<CXXCtorInitializer>())
Finder.add(CCI, Flags); Finder.add(CCI, Flags);
else if (const TemplateArgumentLoc *TAL = N.get<TemplateArgumentLoc>())
Finder.add(TAL->getArgument(), Flags);
return Finder.takeDecls(); return Finder.takeDecls();
} }

View File

@ -479,6 +479,10 @@ public:
bool TraverseTypeLoc(TypeLoc X) { bool TraverseTypeLoc(TypeLoc X) {
return traverseNode(&X, [&] { return Base::TraverseTypeLoc(X); }); return traverseNode(&X, [&] { return Base::TraverseTypeLoc(X); });
} }
bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &X) {
return traverseNode(&X,
[&] { return Base::TraverseTemplateArgumentLoc(X); });
}
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc X) { bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc X) {
return traverseNode( return traverseNode(
&X, [&] { return Base::TraverseNestedNameSpecifierLoc(X); }); &X, [&] { return Base::TraverseNestedNameSpecifierLoc(X); });

View File

@ -376,6 +376,15 @@ TEST_F(TargetDeclTest, ClassTemplate) {
{"template<> class Foo<int *>", Rel::TemplateInstantiation}, {"template<> class Foo<int *>", Rel::TemplateInstantiation},
{"template <typename T> class Foo<T *>", Rel::TemplatePattern}); {"template <typename T> class Foo<T *>", Rel::TemplatePattern});
Code = R"cpp(
// Template template argument.
template<typename T> struct Vector {};
template <template <typename> class Container>
struct A {};
A<[[Vector]]> a;
)cpp";
EXPECT_DECLS("TemplateArgumentLoc", {"template <typename T> struct Vector"});
Flags.push_back("-std=c++17"); // for CTAD tests Flags.push_back("-std=c++17"); // for CTAD tests
Code = R"cpp( Code = R"cpp(

View File

@ -407,8 +407,16 @@ TEST(SelectionTest, CommonAncestor) {
s2[[-^>]]f(); s2[[-^>]]f();
} }
)cpp", )cpp",
"DeclRefExpr"} // DeclRefExpr to the "operator->" method. "DeclRefExpr"}, // DeclRefExpr to the "operator->" method.
};
// Template template argument.
{R"cpp(
template <typename> class Vector {};
template <template <typename> class Container> class A {};
A<[[V^ector]]> a;
)cpp",
"TemplateArgumentLoc"}};
for (const Case &C : Cases) { for (const Case &C : Cases) {
trace::TestTracer Tracer; trace::TestTracer Tracer;
Annotations Test(C.Code); Annotations Test(C.Code);