hokein created this revision.
hokein added a reviewer: ilya-biryukov.
Herald added subscribers: usaxena95, kadircet, arphaman, jkorous, MaskRay.
Herald added a project: clang.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D68977
Files:
clang-tools-extra/clangd/FindTarget.cpp
clang-tools-extra/clangd/FindTarget.h
clang-tools-extra/clangd/XRefs.cpp
clang-tools-extra/clangd/unittests/FindTargetTests.cpp
clang-tools-extra/clangd/unittests/XRefsTests.cpp
Index: clang-tools-extra/clangd/unittests/XRefsTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -2277,7 +2277,8 @@
if (const auto *ND = llvm::dyn_cast<NamedDecl>(D))
Names.push_back(ND->getQualifiedNameAsString());
}
- EXPECT_THAT(Names, UnorderedElementsAreArray(C.ExpectedDecls));
+ EXPECT_THAT(Names, UnorderedElementsAreArray(C.ExpectedDecls))
+ << File.code();
}
}
Index: clang-tools-extra/clangd/unittests/FindTargetTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -520,8 +520,28 @@
findExplicitReferences(Func.getBody(), [&Refs](ReferenceLoc R) {
Refs.push_back(std::move(R));
});
+ return dumpReferences(std::move(Refs), Code, AST.getSourceManager());
+ }
+
+ /// Similar to annotateReferencesInFoo, but finds all references in the main
+ /// AST.
+ AllRefs annotateReferencesInMainAST(llvm::StringRef Code) {
+ TestTU TU;
+ TU.Code = Code;
- auto &SM = AST.getSourceManager();
+ auto AST = TU.build();
+ std::vector<ReferenceLoc> Refs;
+ for (const auto *ToplLevelDecl : AST.getLocalTopLevelDecls()) {
+ findExplicitReferences(ToplLevelDecl, [&Refs](ReferenceLoc R) {
+ Refs.push_back(std::move(R));
+ });
+ }
+ return dumpReferences(std::move(Refs), Code, AST.getSourceManager());
+ }
+
+private:
+ AllRefs dumpReferences(std::vector<ReferenceLoc> Refs, llvm::StringRef Code,
+ const SourceManager &SM) {
llvm::sort(Refs, [&](const ReferenceLoc &L, const ReferenceLoc &R) {
return SM.isBeforeInTranslationUnit(L.NameLoc, R.NameLoc);
});
@@ -590,8 +610,8 @@
using namespace $1^alias;
}
)cpp",
- "0: targets = {ns}\n"
- "1: targets = {alias}\n"},
+ "0: targets = {ns}, decl ref\n"
+ "1: targets = {alias}, decl ref\n"},
// Using declarations.
{R"cpp(
namespace ns { int global; }
@@ -600,59 +620,67 @@
}
)cpp",
"0: targets = {ns}\n"
- "1: targets = {ns::global}, qualifier = 'ns::'\n"},
+ "1: targets = {ns::global}, qualifier = 'ns::', decl ref\n"},
// Simple types.
{R"cpp(
struct Struct { int a; };
using Typedef = int;
void foo() {
- $0^Struct x;
- $1^Typedef y;
- static_cast<$2^Struct*>(0);
+ $0^Struct $1^x;
+ $2^Typedef $3^y;
+ static_cast<$4^Struct*>(0);
}
)cpp",
"0: targets = {Struct}\n"
- "1: targets = {Typedef}\n"
- "2: targets = {Struct}\n"},
+ "1: targets = {x}, decl ref\n"
+ "2: targets = {Typedef}\n"
+ "3: targets = {y}, decl ref\n"
+ "4: targets = {Struct}\n"},
// Name qualifiers.
{R"cpp(
namespace a { namespace b { struct S { typedef int type; }; } }
void foo() {
- $0^a::$1^b::$2^S x;
- using namespace $3^a::$4^b;
- $5^S::$6^type y;
+ $0^a::$1^b::$2^S $3^x;
+ using namespace $4^a::$5^b;
+ $6^S::$7^type $8^y;
}
)cpp",
"0: targets = {a}\n"
"1: targets = {a::b}, qualifier = 'a::'\n"
"2: targets = {a::b::S}, qualifier = 'a::b::'\n"
- "3: targets = {a}\n"
- "4: targets = {a::b}, qualifier = 'a::'\n"
- "5: targets = {a::b::S}\n"
- "6: targets = {a::b::S::type}, qualifier = 'struct S::'\n"},
+ "3: targets = {x}, decl ref\n"
+ "4: targets = {a}\n"
+ "5: targets = {a::b}, qualifier = 'a::', decl ref\n"
+ "6: targets = {a::b::S}\n"
+ "7: targets = {a::b::S::type}, qualifier = 'struct S::'\n"
+ "8: targets = {y}, decl ref\n"},
// Simple templates.
{R"cpp(
template <class T> struct vector { using value_type = T; };
template <> struct vector<bool> { using value_type = bool; };
void foo() {
- $0^vector<int> vi;
- $1^vector<bool> vb;
+ $0^vector<int> $1^vi;
+ $2^vector<bool> $3^vb;
}
)cpp",
"0: targets = {vector<int>}\n"
- "1: targets = {vector<bool>}\n"},
+ "1: targets = {vi}, decl ref\n"
+ "2: targets = {vector<bool>}\n"
+ "3: targets = {vb}, decl ref\n"},
// Template type aliases.
{R"cpp(
template <class T> struct vector { using value_type = T; };
template <> struct vector<bool> { using value_type = bool; };
template <class T> using valias = vector<T>;
void foo() {
- $0^valias<int> vi;
- $1^valias<bool> vb;
+ $0^valias<int> $1^vi;
+ $2^valias<bool> $3^vb;
}
)cpp",
"0: targets = {valias}\n"
- "1: targets = {valias}\n"},
+ "1: targets = {vi}, decl ref\n"
+ "2: targets = {valias}\n"
+ "3: targets = {vb}, decl ref\n"},
// MemberExpr should know their using declaration.
{R"cpp(
struct X { void func(int); }
@@ -694,13 +722,14 @@
};
void foo() {
- for (int x : $0^vector()) {
- $1^x = 10;
+ for (int $0^x : $1^vector()) {
+ $2^x = 10;
}
}
)cpp",
- "0: targets = {vector}\n"
- "1: targets = {x}\n"},
+ "0: targets = {x}, decl ref\n"
+ "1: targets = {vector}\n"
+ "2: targets = {x}\n"},
// Handle UnresolvedLookupExpr.
{R"cpp(
namespace ns1 { void func(char*); }
@@ -736,39 +765,42 @@
void foo() {
static_cast<$0^T>(0);
$1^T();
- $2^T t;
+ $2^T $3^t;
}
)cpp",
"0: targets = {T}\n"
"1: targets = {T}\n"
- "2: targets = {T}\n"},
+ "2: targets = {T}\n"
+ "3: targets = {t}, decl ref\n"},
// Non-type template parameters.
{R"cpp(
template <int I>
void foo() {
- int x = $0^I;
+ int $0^x = $1^I;
}
)cpp",
- "0: targets = {I}\n"},
+ "0: targets = {x}, decl ref\n"
+ "1: targets = {I}\n"},
// Template template parameters.
{R"cpp(
template <class T> struct vector {};
template <template<class> class TT, template<class> class ...TP>
void foo() {
- $0^TT<int> x;
- $1^foo<$2^TT>();
- $3^foo<$4^vector>()
- $5^foo<$6^TP...>();
+ $0^TT<int> $1^x;
+ $2^foo<$3^TT>();
+ $4^foo<$5^vector>()
+ $6^foo<$7^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"},
+ "1: targets = {x}, decl ref\n"
+ "2: targets = {foo}\n"
+ "3: targets = {TT}\n"
+ "4: targets = {foo}\n"
+ "5: targets = {vector}\n"
+ "6: targets = {foo}\n"
+ "7: targets = {TP}\n"},
// Non-type template parameters with declarations.
{R"cpp(
int func();
@@ -776,13 +808,14 @@
template <int(*FuncParam)()>
void foo() {
- $0^wrapper<$1^func> w;
- $2^FuncParam();
+ $0^wrapper<$1^func> $2^w;
+ $3^FuncParam();
}
)cpp",
"0: targets = {wrapper<&func>}\n"
"1: targets = {func}\n"
- "2: targets = {FuncParam}\n"},
+ "2: targets = {w}, decl ref\n"
+ "3: targets = {FuncParam}\n"},
};
for (const auto &C : Cases) {
@@ -796,6 +829,70 @@
}
}
+TEST_F(FindExplicitReferencesTest, DeclReference) {
+ std::pair</*Code*/ llvm::StringRef, /*References*/ llvm::StringRef> Cases[] =
+ {
+ // simple declarations.
+ {R"cpp(
+ class $0^Foo { $1^Foo(); $2^~$3^Foo(); int $4^field; };
+ int $5^Var;
+ void $6^Fun() {}
+ enum $7^E { $8^ABC };
+ typedef int $9^INT;
+ using $10^INT2 = int;
+ template<typename $11^T>
+ // FIXME: the duplicated locations are from FunctionTemplateDecl and
+ // the underlying FunctionDecl. we should report just one.
+ void $12^$13^F() {}
+ )cpp",
+ "0: targets = {Foo}, decl ref\n"
+ "1: targets = {Foo::Foo}, decl ref\n"
+ "2: targets = {Foo::~Foo}, decl ref\n"
+ "3: targets = {Foo}\n"
+ "4: targets = {Foo::field}, decl ref\n"
+ "5: targets = {Var}, decl ref\n"
+ "6: targets = {Fun}, decl ref\n"
+ "7: targets = {E}, decl ref\n"
+ "8: targets = {ABC}, decl ref\n"
+ "9: targets = {INT}, decl ref\n"
+ "10: targets = {INT2}, decl ref\n"
+ "11: targets = {T}, decl ref\n"
+ "12: targets = {F}, decl ref\n"
+ "13: targets = {F}, decl ref\n"},
+ // declarations with qualifiers.
+ {R"cpp(
+ namespace $0^ns {
+ class $1^Foo {
+ void $2^method();
+ };
+ void $3^func();
+ }
+ void $4^ns::$5^Foo::$6^method() {}
+ void $7^ns::$8^func() {}
+ )cpp",
+ "0: targets = {ns}, decl ref\n"
+ "1: targets = {ns::Foo}, decl ref\n"
+ "2: targets = {ns::Foo::method}, decl ref\n"
+ "3: targets = {ns::func}, decl ref\n"
+ "4: targets = {ns}\n"
+ "5: targets = {ns::Foo}, qualifier = 'ns::'\n"
+ "6: targets = {ns::Foo::method}, qualifier = 'ns::class Foo::', "
+ "decl ref\n"
+ "7: targets = {ns}\n"
+ "8: targets = {ns::func}, qualifier = 'ns::', decl ref\n"},
+ };
+
+ for (const auto &C : Cases) {
+ llvm::StringRef ExpectedCode = C.first;
+ llvm::StringRef ExpectedRefs = C.second;
+
+ auto Actual =
+ annotateReferencesInMainAST(llvm::Annotations(ExpectedCode).code());
+ EXPECT_EQ(ExpectedCode, Actual.AnnotatedCode);
+ EXPECT_EQ(ExpectedRefs, Actual.DumpedReferences) << ExpectedCode;
+ }
+}
+
} // namespace
} // namespace clangd
} // namespace clang
Index: clang-tools-extra/clangd/XRefs.cpp
===================================================================
--- clang-tools-extra/clangd/XRefs.cpp
+++ clang-tools-extra/clangd/XRefs.cpp
@@ -1307,7 +1307,8 @@
llvm::DenseSet<const Decl *> DeclRefs;
findExplicitReferences(FD, [&](ReferenceLoc Ref) {
for (const Decl *D : Ref.Targets) {
- if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter())
+ if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&
+ !Ref.IsDecl)
DeclRefs.insert(D);
}
});
Index: clang-tools-extra/clangd/FindTarget.h
===================================================================
--- clang-tools-extra/clangd/FindTarget.h
+++ clang-tools-extra/clangd/FindTarget.h
@@ -86,6 +86,8 @@
NestedNameSpecifierLoc Qualifier;
/// Start location of the last name part, i.e. 'foo' in 'ns::foo<int>'.
SourceLocation NameLoc;
+ /// True if the reference is a declaration or definition;
+ bool IsDecl;
// FIXME: add info about template arguments.
/// A list of targets referenced by this name. Normally this has a single
/// element, but multiple is also possible, e.g. in case of using declarations
Index: clang-tools-extra/clangd/FindTarget.cpp
===================================================================
--- clang-tools-extra/clangd/FindTarget.cpp
+++ clang-tools-extra/clangd/FindTarget.cpp
@@ -415,15 +415,16 @@
Optional<ReferenceLoc> refInDecl(const Decl *D) {
struct Visitor : ConstDeclVisitor<Visitor> {
llvm::Optional<ReferenceLoc> Ref;
-
+ bool DeclRef = true;
void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
Ref = ReferenceLoc{D->getQualifierLoc(),
D->getIdentLocation(),
+ DeclRef,
{D->getNominatedNamespaceAsWritten()}};
}
void VisitUsingDecl(const UsingDecl *D) {
- Ref = ReferenceLoc{D->getQualifierLoc(), D->getLocation(),
+ Ref = ReferenceLoc{D->getQualifierLoc(), D->getLocation(), DeclRef,
explicitReferenceTargets(DynTypedNode::create(*D),
DeclRelation::Underlying)};
}
@@ -431,8 +432,24 @@
void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
Ref = ReferenceLoc{D->getQualifierLoc(),
D->getTargetNameLoc(),
+ DeclRef,
{D->getAliasedNamespace()}};
}
+
+ void VisitTagDecl(const TagDecl *ND) {
+ Ref =
+ ReferenceLoc{ND->getQualifierLoc(), ND->getLocation(), DeclRef, {ND}};
+ }
+
+ void VisitDeclaratorDecl(const DeclaratorDecl *ND) {
+ Ref =
+ ReferenceLoc{ND->getQualifierLoc(), ND->getLocation(), DeclRef, {ND}};
+ }
+
+ void VisitNamedDecl(const NamedDecl *ND) {
+ Ref = ReferenceLoc{
+ NestedNameSpecifierLoc(), ND->getLocation(), DeclRef, {ND}};
+ }
};
Visitor V;
@@ -444,20 +461,24 @@
struct Visitor : ConstStmtVisitor<Visitor> {
// FIXME: handle more complicated cases, e.g. ObjC, designated initializers.
llvm::Optional<ReferenceLoc> Ref;
-
+ bool NotDeclRef = false;
void VisitDeclRefExpr(const DeclRefExpr *E) {
- Ref = ReferenceLoc{
- E->getQualifierLoc(), E->getNameInfo().getLoc(), {E->getFoundDecl()}};
+ Ref = ReferenceLoc{E->getQualifierLoc(),
+ E->getNameInfo().getLoc(),
+ NotDeclRef,
+ {E->getFoundDecl()}};
}
void VisitMemberExpr(const MemberExpr *E) {
Ref = ReferenceLoc{E->getQualifierLoc(),
E->getMemberNameInfo().getLoc(),
+ NotDeclRef,
{E->getFoundDecl()}};
}
void VisitOverloadExpr(const OverloadExpr *E) {
Ref = ReferenceLoc{E->getQualifierLoc(), E->getNameInfo().getLoc(),
+ NotDeclRef,
llvm::SmallVector<const NamedDecl *, 1>(
E->decls().begin(), E->decls().end())};
}
@@ -471,7 +492,7 @@
Optional<ReferenceLoc> refInTypeLoc(TypeLoc L) {
struct Visitor : TypeLocVisitor<Visitor> {
llvm::Optional<ReferenceLoc> Ref;
-
+ bool NotDeclRef = false;
void VisitElaboratedTypeLoc(ElaboratedTypeLoc L) {
// We only know about qualifier, rest if filled by inner locations.
Visit(L.getNamedTypeLoc().getUnqualifiedLoc());
@@ -483,13 +504,13 @@
}
void VisitTagTypeLoc(TagTypeLoc L) {
- Ref =
- ReferenceLoc{NestedNameSpecifierLoc(), L.getNameLoc(), {L.getDecl()}};
+ Ref = ReferenceLoc{
+ NestedNameSpecifierLoc(), L.getNameLoc(), NotDeclRef, {L.getDecl()}};
}
void VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc L) {
- Ref =
- ReferenceLoc{NestedNameSpecifierLoc(), L.getNameLoc(), {L.getDecl()}};
+ Ref = ReferenceLoc{
+ NestedNameSpecifierLoc(), L.getNameLoc(), NotDeclRef, {L.getDecl()}};
}
void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc L) {
@@ -502,14 +523,14 @@
// 2. 'vector<int>' with mask 'Underlying'.
// we want to return only #1 in this case.
Ref = ReferenceLoc{
- NestedNameSpecifierLoc(), L.getTemplateNameLoc(),
+ NestedNameSpecifierLoc(), L.getTemplateNameLoc(), NotDeclRef,
explicitReferenceTargets(DynTypedNode::create(L.getType()),
DeclRelation::Alias)};
}
void VisitDeducedTemplateSpecializationTypeLoc(
DeducedTemplateSpecializationTypeLoc L) {
Ref = ReferenceLoc{
- NestedNameSpecifierLoc(), L.getNameLoc(),
+ NestedNameSpecifierLoc(), L.getNameLoc(), NotDeclRef,
explicitReferenceTargets(DynTypedNode::create(L.getType()),
DeclRelation::Alias)};
}
@@ -517,19 +538,21 @@
void VisitDependentTemplateSpecializationTypeLoc(
DependentTemplateSpecializationTypeLoc L) {
Ref = ReferenceLoc{
- L.getQualifierLoc(), L.getTemplateNameLoc(),
+ L.getQualifierLoc(), L.getTemplateNameLoc(), NotDeclRef,
explicitReferenceTargets(DynTypedNode::create(L.getType()))};
}
void VisitDependentNameTypeLoc(DependentNameTypeLoc L) {
Ref = ReferenceLoc{
- L.getQualifierLoc(), L.getNameLoc(),
+ L.getQualifierLoc(), L.getNameLoc(), NotDeclRef,
explicitReferenceTargets(DynTypedNode::create(L.getType()))};
}
void VisitTypedefTypeLoc(TypedefTypeLoc L) {
- Ref = ReferenceLoc{
- NestedNameSpecifierLoc(), L.getNameLoc(), {L.getTypedefNameDecl()}};
+ Ref = ReferenceLoc{NestedNameSpecifierLoc(),
+ L.getNameLoc(),
+ NotDeclRef,
+ {L.getTypedefNameDecl()}};
}
};
@@ -575,6 +598,7 @@
case TemplateArgument::TemplateExpansion:
reportReference(ReferenceLoc{A.getTemplateQualifierLoc(),
A.getTemplateNameLoc(),
+ false,
{A.getArgument()
.getAsTemplateOrTemplatePattern()
.getAsTemplateDecl()}},
@@ -631,7 +655,7 @@
if (auto *E = N.get<Expr>())
return refInExpr(E);
if (auto *NNSL = N.get<NestedNameSpecifierLoc>())
- return ReferenceLoc{NNSL->getPrefix(), NNSL->getLocalBeginLoc(),
+ return ReferenceLoc{NNSL->getPrefix(), NNSL->getLocalBeginLoc(), false,
explicitReferenceTargets(DynTypedNode::create(
*NNSL->getNestedNameSpecifier()))};
if (const TypeLoc *TL = N.get<TypeLoc>())
@@ -642,6 +666,7 @@
assert(CCI->isAnyMemberInitializer());
return ReferenceLoc{NestedNameSpecifierLoc(),
CCI->getMemberLocation(),
+ false,
{CCI->getAnyMember()}};
}
// We do not have location information for other nodes (QualType, etc)
@@ -727,6 +752,8 @@
PrintingPolicy(LangOptions()));
OS << "'";
}
+ if (R.IsDecl)
+ OS << ", decl ref";
return OS;
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits