diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -432,9 +432,48 @@ 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? + auto AddRefFromIndex = [&](const Ref &R) { + // No need to continue process if we reach the limit. + if (Results.References.size() > Limit) + return; + auto LSPLoc = toLSPLocation(R.Location, *MainFilePath); + // Avoid indexed results for the main file - the AST is authoritative. + if (!LSPLoc || LSPLoc->uri.file() == *MainFilePath) + return; + + Results.References.push_back(std::move(*LSPLoc)); + }; + // Handle references to macro. + if (auto Macro = locateMacroAt(Loc, AST.getPreprocessor())) { + 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 Loc; + Loc.uri = URIMainFile; + Loc.range = Ref; + Results.References.push_back(Loc); + } + } + // Query the index for references from other files. + if (Index && Results.References.size() < Limit) { + RefsRequest Req; + Req.Limit = Limit; + Req.IDs.insert(*MacroSID); + Results.HasMore |= Index->refs(Req, AddRefFromIndex); + } + } + if (Results.References.size() > Limit) { + Results.HasMore = true; + Results.References.resize(Limit); + } + return Results; + } // We also show references to the targets of using-decls, so we include // DeclRelation::Underlying. DeclRelationSet Relations = DeclRelation::TemplatePattern | @@ -456,7 +495,7 @@ if (auto Range = getTokenRange(SM, AST.getLangOpts(), Ref.Loc)) { Location Result; Result.range = *Range; - Result.uri = URIForFile::canonicalize(*MainFilePath, *MainFilePath); + Result.uri = URIMainFile; Results.References.push_back(std::move(Result)); } } @@ -476,17 +515,7 @@ } if (Req.IDs.empty()) return Results; - Results.HasMore |= Index->refs(Req, [&](const Ref &R) { - // no need to continue process if we reach the limit. - if (Results.References.size() > Limit) - return; - auto LSPLoc = toLSPLocation(R.Location, *MainFilePath); - // Avoid indexed results for the main file - the AST is authoritative. - if (!LSPLoc || LSPLoc->uri.file() == *MainFilePath) - return; - - Results.References.push_back(std::move(*LSPLoc)); - }); + Results.HasMore |= Index->refs(Req, AddRefFromIndex); } if (Results.References.size() > Limit) { Results.HasMore = true; diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -937,6 +937,13 @@ [[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); @@ -1012,8 +1019,16 @@ } TEST(FindReferences, NeedsIndex) { - const char *Header = "int foo();"; - Annotations Main("int main() { [[f^oo]](); }"); + const char *Header = (R"cpp( + int foo(); + #define MACRO(X) (X+1) + )cpp"); + Annotations Main(R"cpp( + int main() { + $foo[[f$foo^oo]](); + int a = $macro[[MA$macro^CRO]](1); + } + )cpp"); TestTU TU; TU.Code = Main.code(); TU.HeaderCode = Header; @@ -1021,10 +1036,17 @@ // References in main file are returned without index. EXPECT_THAT( - findReferences(AST, Main.point(), 0, /*Index=*/nullptr).References, - ElementsAre(RangeIs(Main.range()))); + findReferences(AST, Main.point("foo"), 0, /*Index=*/nullptr).References, + ElementsAre(RangeIs(Main.range("foo")))); + EXPECT_THAT( + findReferences(AST, Main.point("macro"), 0, /*Index=*/nullptr).References, + ElementsAre(RangeIs(Main.range("macro")))); + Annotations IndexedMain(R"cpp( - int main() { [[f^oo]](); } + int indexed_main() { + $foo[[foo]](); + int a = $macro[[MACRO]](1); + } )cpp"); // References from indexed files are included. @@ -1033,18 +1055,21 @@ 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()))); + findReferences(AST, Main.point("foo"), 0, IndexedTU.index().get()).References, + ElementsAre(RangeIs(Main.range("foo")), RangeIs(IndexedMain.range("foo")))); + EXPECT_THAT( + findReferences(AST, Main.point("macro"), 0, IndexedTU.index().get()).References, + ElementsAre(RangeIs(Main.range("macro")), RangeIs(IndexedMain.range("macro")))); auto LimitRefs = - findReferences(AST, Main.point(), /*Limit*/ 1, IndexedTU.index().get()); + findReferences(AST, Main.point("foo"), /*Limit*/ 1, IndexedTU.index().get()); 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) TU.Code = ("\n\n" + Main.code()).str(); - EXPECT_THAT(findReferences(AST, Main.point(), 0, TU.index().get()).References, - ElementsAre(RangeIs(Main.range()))); + EXPECT_THAT(findReferences(AST, Main.point("foo"), 0, TU.index().get()).References, + ElementsAre(RangeIs(Main.range("foo")))); } TEST(FindReferences, NoQueryForLocalSymbols) {