diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -384,11 +384,14 @@ } void VisitDeducedTemplateSpecializationType( const DeducedTemplateSpecializationType *DTST) { + if (const auto *UTN = DTST->getTemplateName().getAsUsingTemplateName()) + Outer.add(UTN->getFoundDecl(), Flags); + // FIXME: This is a workaround for https://llvm.org/PR42914, // which is causing DTST->getDeducedType() to be empty. We // fall back to the template pattern and miss the instantiation // even when it's known in principle. Once that bug is fixed, - // this method can be removed (the existing handling in + // the following code can be removed (the existing handling in // VisitDeducedType() is sufficient). if (auto *TD = DTST->getTemplateName().getAsTemplateDecl()) Outer.add(TD->getTemplatedDecl(), Flags | Rel::TemplatePattern); @@ -440,6 +443,9 @@ // class template specializations have a (specialized) CXXRecordDecl. else if (const CXXRecordDecl *RD = TST->getAsCXXRecordDecl()) Outer.add(RD, Flags); // add(Decl) will despecialize if needed. + else if (const auto *UTN = + TST->getTemplateName().getAsUsingTemplateName()) + Outer.add(UTN->getFoundDecl(), Flags); else { // fallback: the (un-specialized) declaration from primary template. if (auto *TD = TST->getTemplateName().getAsTemplateDecl()) @@ -508,6 +514,9 @@ Arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl()) { report(TD, Flags); } + if (const auto *UTN = + Arg.getAsTemplateOrTemplatePattern().getAsUsingTemplateName()) + add(UTN->getFoundDecl(), Flags); } } }; diff --git a/clang-tools-extra/clangd/IncludeCleaner.cpp b/clang-tools-extra/clangd/IncludeCleaner.cpp --- a/clang-tools-extra/clangd/IncludeCleaner.cpp +++ b/clang-tools-extra/clangd/IncludeCleaner.cpp @@ -73,11 +73,23 @@ } bool VisitTemplateSpecializationType(TemplateSpecializationType *TST) { + if (const auto *UTN = TST->getTemplateName().getAsUsingTemplateName()) { + add(UTN->getFoundDecl()); + return true; + } add(TST->getTemplateName().getAsTemplateDecl()); // Primary template. add(TST->getAsCXXRecordDecl()); // Specialization return true; } + // There is no VisitTemplateName in RAV, thus we override the Traverse version + // to handle the UsingTemplateName case. + bool TraverseTemplateName(TemplateName TN) { + if (const auto *UTN = TN.getAsUsingTemplateName()) + add(UTN->getFoundDecl()); + return Base::TraverseTemplateName(TN); + } + bool VisitUsingType(UsingType *UT) { add(UT->getFoundDecl()); return true; diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp --- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -229,6 +229,44 @@ )cpp"; EXPECT_DECLS("UnresolvedUsingValueDecl", {"using Base::waldo", Rel::Alias}, {"void waldo()"}); + + Code = R"cpp( + namespace ns { + template class S {}; + } + + using ns::S; + + template + using A = [[S]]; + )cpp"; + EXPECT_DECLS("TemplateSpecializationTypeLoc", {"using ns::S", Rel::Alias}, + {"template class S"}); + + Code = R"cpp( + namespace ns { + template class S {}; + } + + using ns::S; + template