[clangd] Capture the missing injected class names in findExplicitReferences.

Summary: Fixes https://github.com/clangd/clangd/issues/237.

Reviewers: kadircet, kbobyrev

Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D73088
This commit is contained in:
Haojian Wu 2020-01-21 11:50:57 +01:00
parent 651fa669a2
commit f651c402a2
4 changed files with 53 additions and 8 deletions

View File

@ -695,6 +695,13 @@ llvm::SmallVector<ReferenceLoc, 2> refInTypeLoc(TypeLoc L) {
DeclRelation::Alias)};
}
void VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
Ref = ReferenceLoc{NestedNameSpecifierLoc(),
TL.getNameLoc(),
/*IsDecl=*/false,
{TL.getDecl()}};
}
void VisitDependentTemplateSpecializationTypeLoc(
DependentTemplateSpecializationTypeLoc L) {
Ref = ReferenceLoc{

View File

@ -1,4 +1,4 @@
//===-- FindSymbolsTests.cpp -------------------------*- C++ -*------------===//
//===-- FindTargetTests.cpp --------------------------*- C++ -*------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@ -553,8 +553,8 @@ protected:
std::string DumpedReferences;
};
/// Parses \p Code, finds function '::foo' and annotates its body with results
/// of findExplicitReferecnces.
/// Parses \p Code, finds function or namespace '::foo' and annotates its body
/// with results of findExplicitReferecnces.
/// See actual tests for examples of annotation format.
AllRefs annotateReferencesInFoo(llvm::StringRef Code) {
TestTU TU;
@ -574,12 +574,21 @@ protected:
auto *TestDecl = &findDecl(AST, "foo");
if (auto *T = llvm::dyn_cast<FunctionTemplateDecl>(TestDecl))
TestDecl = T->getTemplatedDecl();
auto &Func = llvm::cast<FunctionDecl>(*TestDecl);
std::vector<ReferenceLoc> Refs;
findExplicitReferences(Func.getBody(), [&Refs](ReferenceLoc R) {
Refs.push_back(std::move(R));
});
if (const auto *Func = llvm::dyn_cast<FunctionDecl>(TestDecl))
findExplicitReferences(Func->getBody(), [&Refs](ReferenceLoc R) {
Refs.push_back(std::move(R));
});
else if (const auto *NS = llvm::dyn_cast<NamespaceDecl>(TestDecl))
findExplicitReferences(NS, [&Refs, &NS](ReferenceLoc R) {
// Avoid adding the namespace foo decl to the results.
if (R.Targets.size() == 1 && R.Targets.front() == NS)
return;
Refs.push_back(std::move(R));
});
else
ADD_FAILURE() << "Failed to find ::foo decl for test";
auto &SM = AST.getSourceManager();
llvm::sort(Refs, [&](const ReferenceLoc &L, const ReferenceLoc &R) {
@ -720,6 +729,25 @@ TEST_F(FindExplicitReferencesTest, All) {
"1: targets = {vi}, decl\n"
"2: targets = {valias}\n"
"3: targets = {vb}, decl\n"},
// Injected class name.
{R"cpp(
namespace foo {
template <typename $0^T>
class $1^$2^Bar {
~$3^Bar();
void $4^f($5^Bar);
};
}
)cpp",
"0: targets = {foo::Bar::T}, decl\n"
// FIXME: avoid the 2 duplicated foo::Bar references below, the first
// one comes from ClassTemplateDecl; the second comes from the
// underlying CXXRecordDecl.
"1: targets = {foo::Bar}, decl\n"
"2: targets = {foo::Bar}, decl\n"
"3: targets = {foo::Bar}\n"
"4: targets = {foo::Bar::f}, decl\n"
"5: targets = {foo::Bar}\n"},
// MemberExpr should know their using declaration.
{R"cpp(
struct X { void func(int); };

View File

@ -127,6 +127,16 @@ TEST(RenameTest, WithinFileRename) {
void [[Foo]]::foo(int x) {}
)cpp",
// Rename template class, including constructor/destructor.
R"cpp(
template <typename T>
class [[F^oo]] {
[[F^oo]]();
~[[F^oo]]();
void f([[Foo]] x);
};
)cpp",
// Class in template argument.
R"cpp(
class [[F^oo]] {};

View File

@ -525,7 +525,7 @@ $InactiveCode[[]] #endif
using $Typedef[[LVReference]] = $TemplateParameter[[T]] &;
using $Typedef[[RVReference]] = $TemplateParameter[[T]]&&;
using $Typedef[[Array]] = $TemplateParameter[[T]]*[3];
using $Typedef[[MemberPointer]] = int (A::*)(int);
using $Typedef[[MemberPointer]] = int ($Class[[A]]::*)(int);
// Use various previously defined typedefs in a function type.
void $Method[[func]](