summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clangd
diff options
context:
space:
mode:
authorUtkarsh Saxena <usx@google.com>2020-01-08 13:57:00 +0100
committerUtkarsh Saxena <usx@google.com>2020-01-13 11:11:18 +0100
commit734aa1d133f264746f721a244d2c66bc99648ee5 (patch)
tree4ac7af834f12389285a5de66ed0ecb46697299c3 /clang-tools-extra/clangd
parentc9babcbda77e69698825cfb9ce771352be93acee (diff)
downloadbcm5719-llvm-734aa1d133f264746f721a244d2c66bc99648ee5.tar.gz
bcm5719-llvm-734aa1d133f264746f721a244d2c66bc99648ee5.zip
[clangd] Publish xref for macros from Index and AST.
Summary: With this patch the `findReferences` API will return Xref for macros. If the symbol under the cursor is a macro then we collect the references to it from: 1. Main file by looking at the ParsedAST. (These were added to the ParsedAST in https://reviews.llvm.org/D70008) 2. Files other than the mainfile by looking at the: * static index (Added in https://reviews.llvm.org/D70489) * file index (Added in https://reviews.llvm.org/D71406) This patch collects all the xref from the above places and outputs it in `findReferences` API. Reviewers: kadircet Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D72395
Diffstat (limited to 'clang-tools-extra/clangd')
-rw-r--r--clang-tools-extra/clangd/XRefs.cpp99
-rw-r--r--clang-tools-extra/clangd/unittests/XRefsTests.cpp49
2 files changed, 106 insertions, 42 deletions
diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp
index fa33c796ce2..ac62393541a 100644
--- a/clang-tools-extra/clangd/XRefs.cpp
+++ b/clang-tools-extra/clangd/XRefs.cpp
@@ -432,52 +432,73 @@ ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit,
elog("Failed to get a path for the main file, so no references");
return Results;
}
+ auto URIMainFile = URIForFile::canonicalize(*MainFilePath, *MainFilePath);
auto Loc = SM.getMacroArgExpandedLocation(
getBeginningOfIdentifier(Pos, SM, AST.getLangOpts()));
- // TODO: should we handle macros, too?
- // We also show references to the targets of using-decls, so we include
- // DeclRelation::Underlying.
- DeclRelationSet Relations = DeclRelation::TemplatePattern |
- DeclRelation::Alias | DeclRelation::Underlying;
- auto Decls = getDeclAtPosition(AST, Loc, Relations);
-
- // We traverse the AST to find references in the main file.
- auto MainFileRefs = findRefs(Decls, AST);
- // We may get multiple refs with the same location and different Roles, as
- // cross-reference is only interested in locations, we deduplicate them
- // by the location to avoid emitting duplicated locations.
- MainFileRefs.erase(std::unique(MainFileRefs.begin(), MainFileRefs.end(),
- [](const ReferenceFinder::Reference &L,
- const ReferenceFinder::Reference &R) {
- return L.Loc == R.Loc;
- }),
- MainFileRefs.end());
- for (const auto &Ref : MainFileRefs) {
- if (auto Range = getTokenRange(SM, AST.getLangOpts(), Ref.Loc)) {
- Location Result;
- Result.range = *Range;
- Result.uri = URIForFile::canonicalize(*MainFilePath, *MainFilePath);
- Results.References.push_back(std::move(Result));
+ RefsRequest Req;
+
+ if (auto Macro = locateMacroAt(Loc, AST.getPreprocessor())) {
+ // Handle references to macro.
+ if (auto MacroSID = getSymbolID(Macro->Name, Macro->Info, SM)) {
+ // Collect macro references from main file.
+ const auto &IDToRefs = AST.getMacros().MacroRefs;
+ auto Refs = IDToRefs.find(*MacroSID);
+ if (Refs != IDToRefs.end()) {
+ for (const auto Ref : Refs->second) {
+ Location Result;
+ Result.range = Ref;
+ Result.uri = URIMainFile;
+ Results.References.push_back(std::move(Result));
+ }
+ }
+ Req.IDs.insert(*MacroSID);
+ }
+ } else {
+ // Handle references to Decls.
+
+ // We also show references to the targets of using-decls, so we include
+ // DeclRelation::Underlying.
+ DeclRelationSet Relations = DeclRelation::TemplatePattern |
+ DeclRelation::Alias | DeclRelation::Underlying;
+ auto Decls = getDeclAtPosition(AST, Loc, Relations);
+
+ // We traverse the AST to find references in the main file.
+ auto MainFileRefs = findRefs(Decls, AST);
+ // We may get multiple refs with the same location and different Roles, as
+ // cross-reference is only interested in locations, we deduplicate them
+ // by the location to avoid emitting duplicated locations.
+ MainFileRefs.erase(std::unique(MainFileRefs.begin(), MainFileRefs.end(),
+ [](const ReferenceFinder::Reference &L,
+ const ReferenceFinder::Reference &R) {
+ return L.Loc == R.Loc;
+ }),
+ MainFileRefs.end());
+ for (const auto &Ref : MainFileRefs) {
+ if (auto Range = getTokenRange(SM, AST.getLangOpts(), Ref.Loc)) {
+ Location Result;
+ Result.range = *Range;
+ Result.uri = URIMainFile;
+ Results.References.push_back(std::move(Result));
+ }
+ }
+ if (Index && Results.References.size() <= Limit) {
+ for (const Decl *D : Decls) {
+ // Not all symbols can be referenced from outside (e.g.
+ // function-locals).
+ // TODO: we could skip TU-scoped symbols here (e.g. static functions) if
+ // we know this file isn't a header. The details might be tricky.
+ if (D->getParentFunctionOrMethod())
+ continue;
+ if (auto ID = getSymbolID(D))
+ Req.IDs.insert(*ID);
+ }
}
}
// Now query the index for references from other files.
- if (Index && Results.References.size() <= Limit) {
- RefsRequest Req;
+ if (!Req.IDs.empty() && Index && Results.References.size() <= Limit) {
Req.Limit = Limit;
-
- for (const Decl *D : Decls) {
- // Not all symbols can be referenced from outside (e.g. function-locals).
- // TODO: we could skip TU-scoped symbols here (e.g. static functions) if
- // we know this file isn't a header. The details might be tricky.
- if (D->getParentFunctionOrMethod())
- continue;
- if (auto ID = getSymbolID(D))
- Req.IDs.insert(*ID);
- }
- if (Req.IDs.empty())
- return Results;
Results.HasMore |= Index->refs(Req, [&](const Ref &R) {
- // no need to continue process if we reach the limit.
+ // No need to continue process if we reach the limit.
if (Results.References.size() > Limit)
return;
auto LSPLoc = toLSPLocation(R.Location, *MainFilePath);
diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
index 6d16fa51373..79d7090a28e 100644
--- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -937,6 +937,13 @@ TEST(FindReferences, WithinAST) {
[[CAT]](Fo, o) foo4;
}
)cpp",
+
+ R"cpp(// Macros
+ #define [[MA^CRO]](X) (X+1)
+ void test() {
+ int x = [[MACRO]]([[MACRO]](1));
+ }
+ )cpp",
};
for (const char *Test : Tests) {
Annotations T(Test);
@@ -1011,7 +1018,7 @@ TEST(FindReferences, ExplicitSymbols) {
}
}
-TEST(FindReferences, NeedsIndex) {
+TEST(FindReferences, NeedsIndexForSymbols) {
const char *Header = "int foo();";
Annotations Main("int main() { [[f^oo]](); }");
TestTU TU;
@@ -1040,13 +1047,49 @@ TEST(FindReferences, NeedsIndex) {
EXPECT_EQ(1u, LimitRefs.References.size());
EXPECT_TRUE(LimitRefs.HasMore);
- // If the main file is in the index, we don't return duplicates.
- // (even if the references are in a different location)
+ // Avoid indexed results for the main file. Use AST for the mainfile.
TU.Code = ("\n\n" + Main.code()).str();
EXPECT_THAT(findReferences(AST, Main.point(), 0, TU.index().get()).References,
ElementsAre(RangeIs(Main.range())));
}
+TEST(FindReferences, NeedsIndexForMacro) {
+ const char *Header = "#define MACRO(X) (X+1)";
+ Annotations Main(R"cpp(
+ int main() {
+ int a = [[MA^CRO]](1);
+ }
+ )cpp");
+ TestTU TU;
+ TU.Code = Main.code();
+ TU.HeaderCode = Header;
+ auto AST = TU.build();
+
+ // References in main file are returned without index.
+ EXPECT_THAT(
+ findReferences(AST, Main.point(), 0, /*Index=*/nullptr).References,
+ ElementsAre(RangeIs(Main.range())));
+
+ Annotations IndexedMain(R"cpp(
+ int indexed_main() {
+ int a = [[MACRO]](1);
+ }
+ )cpp");
+
+ // References from indexed files are included.
+ TestTU IndexedTU;
+ IndexedTU.Code = IndexedMain.code();
+ IndexedTU.Filename = "Indexed.cpp";
+ IndexedTU.HeaderCode = Header;
+ EXPECT_THAT(
+ findReferences(AST, Main.point(), 0, IndexedTU.index().get()).References,
+ ElementsAre(RangeIs(Main.range()), RangeIs(IndexedMain.range())));
+ auto LimitRefs =
+ findReferences(AST, Main.point(), /*Limit*/ 1, IndexedTU.index().get());
+ EXPECT_EQ(1u, LimitRefs.References.size());
+ EXPECT_TRUE(LimitRefs.HasMore);
+}
+
TEST(FindReferences, NoQueryForLocalSymbols) {
struct RecordingIndex : public MemIndex {
mutable Optional<llvm::DenseSet<SymbolID>> RefIDs;
OpenPOWER on IntegriCloud