Index: clang-tools-extra/trunk/clangd/FindTarget.cpp =================================================================== --- clang-tools-extra/trunk/clangd/FindTarget.cpp +++ clang-tools-extra/trunk/clangd/FindTarget.cpp @@ -22,6 +22,7 @@ #include "clang/AST/PrettyPrinter.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/StmtVisitor.h" +#include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeLocVisitor.h" @@ -565,6 +566,34 @@ return true; } + // We re-define Traverse*, since there's no corresponding Visit*. + // TemplateArgumentLoc is the only way to get locations for references to + // template template parameters. + bool TraverseTemplateArgumentLoc(TemplateArgumentLoc A) { + switch (A.getArgument().getKind()) { + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + reportReference(ReferenceLoc{A.getTemplateQualifierLoc(), + A.getTemplateNameLoc(), + {A.getArgument() + .getAsTemplateOrTemplatePattern() + .getAsTemplateDecl()}}, + DynTypedNode::create(A.getArgument())); + break; + case TemplateArgument::Declaration: + break; // FIXME: can this actually happen in TemplateArgumentLoc? + case TemplateArgument::Integral: + case TemplateArgument::Null: + case TemplateArgument::NullPtr: + break; // no references. + case TemplateArgument::Pack: + case TemplateArgument::Type: + case TemplateArgument::Expression: + break; // Handled by VisitType and VisitExpression. + }; + return RecursiveASTVisitor::TraverseTemplateArgumentLoc(A); + } + bool VisitDecl(Decl *D) { visitNode(DynTypedNode::create(*D)); return true; @@ -623,15 +652,19 @@ auto Ref = explicitReference(N); if (!Ref) return; + reportReference(*Ref, N); + } + + void reportReference(const ReferenceLoc &Ref, DynTypedNode N) { // Our promise is to return only references from the source code. If we lack // location information, skip these nodes. // Normally this should not happen in practice, unless there are bugs in the // traversals or users started the traversal at an implicit node. - if (Ref->NameLoc.isInvalid()) { + if (Ref.NameLoc.isInvalid()) { dlog("invalid location at node {0}", nodeToString(N)); return; } - Out(*Ref); + Out(Ref); } llvm::function_ref Out; Index: clang-tools-extra/trunk/clangd/unittests/FindTargetTests.cpp =================================================================== --- clang-tools-extra/trunk/clangd/unittests/FindTargetTests.cpp +++ clang-tools-extra/trunk/clangd/unittests/FindTargetTests.cpp @@ -750,6 +750,39 @@ } )cpp", "0: targets = {I}\n"}, + // Template template parameters. + {R"cpp( + template struct vector {}; + + template class TT, template class ...TP> + void foo() { + $0^TT x; + $1^foo<$2^TT>(); + $3^foo<$4^vector>() + $5^foo<$6^TP...>(); + } + )cpp", + "0: targets = {TT}\n" + "1: targets = {foo}\n" + "2: targets = {TT}\n" + "3: targets = {foo}\n" + "4: targets = {vector}\n" + "5: targets = {foo}\n" + "6: targets = {TP}\n"}, + // Non-type template parameters with declarations. + {R"cpp( + int func(); + template struct wrapper {}; + + template + void foo() { + $0^wrapper<$1^func> w; + $2^FuncParam(); + } + )cpp", + "0: targets = {wrapper<&func>}\n" + "1: targets = {func}\n" + "2: targets = {FuncParam}\n"}, }; for (const auto &C : Cases) {