[clangd] Handle the new Using TemplateName.

Add supports in FindTarget and IncludeCleaner. This would
improve AST-based features on a tempalte which is found via a using
declaration. For example, go-to-def on `vect^or<int> v;` gives us the
location of `using std::vector`, which was not previously.

Base on https://reviews.llvm.org/D123127

Differential Revision: https://reviews.llvm.org/D123212
This commit is contained in:
Haojian Wu 2022-04-06 13:03:21 +02:00
parent 37b1515b0a
commit 95f0f69441
4 changed files with 82 additions and 2 deletions

View File

@ -384,11 +384,14 @@ public:
}
void VisitDeducedTemplateSpecializationType(
const DeducedTemplateSpecializationType *DTST) {
if (const auto *USD = DTST->getTemplateName().getAsUsingShadowDecl())
Outer.add(USD, 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);
@ -419,6 +422,9 @@ public:
VisitTemplateSpecializationType(const TemplateSpecializationType *TST) {
// Have to handle these case-by-case.
if (const auto *UTN = TST->getTemplateName().getAsUsingShadowDecl())
Outer.add(UTN, Flags);
// templated type aliases: there's no specialized/instantiated using
// decl to point to. So try to find a decl for the underlying type
// (after substitution), and failing that point to the (templated) using
@ -508,6 +514,9 @@ public:
Arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl()) {
report(TD, Flags);
}
if (const auto *USD =
Arg.getAsTemplateOrTemplatePattern().getAsUsingShadowDecl())
add(USD, Flags);
}
}
};

View File

@ -79,11 +79,29 @@ public:
}
bool VisitTemplateSpecializationType(TemplateSpecializationType *TST) {
add(TST->getTemplateName().getAsTemplateDecl()); // Primary template.
// Using templateName case is handled by the override TraverseTemplateName.
if (TST->getTemplateName().getKind() == TemplateName::UsingTemplate)
return true;
add(TST->getAsCXXRecordDecl()); // Specialization
return true;
}
// There is no VisitTemplateName in RAV, thus we override the Traverse version
// to handle the Using TemplateName case.
bool TraverseTemplateName(TemplateName TN) {
VisitTemplateName(TN);
return Base::TraverseTemplateName(TN);
}
// A pseudo VisitTemplateName, dispatched by the above TraverseTemplateName!
bool VisitTemplateName(TemplateName TN) {
if (const auto *USD = TN.getAsUsingShadowDecl()) {
add(USD);
return true;
}
add(TN.getAsTemplateDecl()); // Primary template.
return true;
}
bool VisitUsingType(UsingType *UT) {
add(UT->getFoundDecl());
return true;

View File

@ -229,6 +229,45 @@ TEST_F(TargetDeclTest, UsingDecl) {
)cpp";
EXPECT_DECLS("UnresolvedUsingValueDecl", {"using Base<T>::waldo", Rel::Alias},
{"void waldo()"});
Code = R"cpp(
namespace ns {
template<typename T> class S {};
}
using ns::S;
template<typename T>
using A = [[S]]<T>;
)cpp";
EXPECT_DECLS("TemplateSpecializationTypeLoc", {"using ns::S", Rel::Alias},
{"template <typename T> class S"},
{"class S", Rel::TemplatePattern});
Code = R"cpp(
namespace ns {
template<typename T> class S {};
}
using ns::S;
template <template <typename> class T> class X {};
using B = X<[[S]]>;
)cpp";
EXPECT_DECLS("TemplateArgumentLoc", {"using ns::S", Rel::Alias},
{"template <typename T> class S"});
Code = R"cpp(
namespace ns {
template<typename T> class S { public: S(T); };
}
using ns::S;
[[S]] s(123);
)cpp";
Flags.push_back("-std=c++17"); // For CTAD feature.
EXPECT_DECLS("DeducedTemplateSpecializationTypeLoc",
{"using ns::S", Rel::Alias}, {"template <typename T> class S"},
{"class S", Rel::TemplatePattern});
}
TEST_F(TargetDeclTest, BaseSpecifier) {

View File

@ -79,9 +79,22 @@ TEST(IncludeCleaner, ReferencedLocations) {
"using namespace ns;",
},
{
// Refs from UsingTypeLoc and implicit constructor!
"struct ^A {}; using B = A; using ^C = B;",
"C a;",
},
{"namespace ns { template<typename T> class A {}; } using ns::^A;",
"A<int>* a;"},
{"namespace ns { template<typename T> class A {}; } using ns::^A;",
R"cpp(
template <template <typename> class T> class X {};
X<A> x;
)cpp"},
{R"cpp(
namespace ns { template<typename T> struct ^A { ^A(T); }; }
using ns::^A;
)cpp",
"A CATD(123);"},
{
"typedef bool ^Y; template <typename T> struct ^X {};",
"X<Y> x;",
@ -227,6 +240,7 @@ TEST(IncludeCleaner, ReferencedLocations) {
TU.Code = T.MainCode;
Annotations Header(T.HeaderCode);
TU.HeaderCode = Header.code().str();
TU.ExtraArgs.push_back("-std=c++17");
auto AST = TU.build();
std::vector<Position> Points;