[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
This revision was landed with ongoing or failed builds. This revision was automatically updated to reflect the committed changes. Closed by commit rG9e9b1effac34: [clangd] Implement cross reference request for #include lines. (authored by VitaNuo). Changed prior to commit: https://reviews.llvm.org/D147044?vs=515227=515228#toc Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 Files: clang-tools-extra/clangd/Hover.cpp clang-tools-extra/clangd/IncludeCleaner.cpp clang-tools-extra/clangd/IncludeCleaner.h clang-tools-extra/clangd/XRefs.cpp clang-tools-extra/clangd/unittests/HoverTests.cpp clang-tools-extra/clangd/unittests/IncludeCleanerTests.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 @@ -43,6 +43,10 @@ using ::testing::UnorderedElementsAreArray; using ::testing::UnorderedPointwise; +std::string guard(llvm::StringRef Code) { + return "#pragma once\n" + Code.str(); +} + MATCHER_P2(FileRange, File, Range, "") { return Location{URIForFile::canonicalize(File, testRoot()), Range} == arg; } @@ -2293,6 +2297,50 @@ checkFindRefs(Test); } +TEST(FindReferences, UsedSymbolsFromInclude) { + const char *Tests[] = { + R"cpp([[#include ^"bar.h"]] +#include +int fstBar = [[bar1]](); +int sndBar = [[bar2]](); +[[Bar]] bar; +int macroBar = [[BAR]]; +std::vector vec; + )cpp", + + R"cpp([[#in^clude ]] +std::[[vector]] vec; + )cpp"}; + for (const char *Test : Tests) { +Annotations T(Test); +auto TU = TestTU::withCode(T.code()); +TU.ExtraArgs.push_back("-std=c++20"); +TU.AdditionalFiles["bar.h"] = guard(R"cpp( + #define BAR 5 + int bar1(); + int bar2(); + class Bar {}; +)cpp"); +TU.AdditionalFiles["system/vector"] = guard(R"cpp( + namespace std { +template +class vector{}; + } +)cpp"); +TU.ExtraArgs.push_back("-isystem" + testPath("system")); + +auto AST = TU.build(); +std::vector> ExpectedLocations; +for (const auto : T.ranges()) + ExpectedLocations.push_back(AllOf(rangeIs(R), attrsAre(0u))); +for (const auto : T.points()) + EXPECT_THAT(findReferences(AST, P, 0).References, + UnorderedElementsAreArray(ExpectedLocations)) + << "Failed for Refs at " << P << "\n" + << Test; + } +} + TEST(FindReferences, NeedsIndexForSymbols) { const char *Header = "int foo();"; Annotations Main("int main() { [[f^oo]](); }"); Index: clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp === --- clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp +++ clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp @@ -29,6 +29,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" #include +#include #include #include #include @@ -435,6 +436,48 @@ MainCode.range()); } +TEST(IncludeCleaner, FirstMatchedProvider) { + struct { +const char *Code; +const std::vector Providers; +const std::optional ExpectedProvider; + } Cases[] = { + {R"cpp( +#include "bar.h" +#include "foo.h" + )cpp", + {include_cleaner::Header{"bar.h"}, include_cleaner::Header{"foo.h"}}, + include_cleaner::Header{"bar.h"}}, + {R"cpp( +#include "bar.h" +#include "foo.h" + )cpp", + {include_cleaner::Header{"foo.h"}, include_cleaner::Header{"bar.h"}}, + include_cleaner::Header{"foo.h"}}, + {"#include \"bar.h\"", + {include_cleaner::Header{"bar.h"}}, + include_cleaner::Header{"bar.h"}}, + {"#include \"bar.h\"", {include_cleaner::Header{"foo.h"}}, std::nullopt}, + {"#include \"bar.h\"", {}, std::nullopt}}; + for (const auto : Cases) { +Annotations Code{Case.Code}; +SCOPED_TRACE(Code.code()); + +TestTU TU; +TU.Code = Code.code(); +TU.AdditionalFiles["bar.h"] = ""; +TU.AdditionalFiles["foo.h"] = ""; + +auto AST = TU.build(); +std::optional MatchedProvider = +firstMatchedProvider( +convertIncludes(AST.getSourceManager(), +AST.getIncludeStructure().MainFileIncludes), +Case.Providers); +EXPECT_EQ(MatchedProvider, Case.ExpectedProvider); + } +} + } // namespace } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/unittests/HoverTests.cpp === --- clang-tools-extra/clangd/unittests/HoverTests.cpp +++ clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -2999,36 +2999,7 @@ #in^clude
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
VitaNuo updated this revision to Diff 515227. VitaNuo marked 3 inline comments as done. VitaNuo added a comment. Add a test case. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 Files: clang-tools-extra/clangd/Hover.cpp clang-tools-extra/clangd/IncludeCleaner.cpp clang-tools-extra/clangd/IncludeCleaner.h clang-tools-extra/clangd/XRefs.cpp clang-tools-extra/clangd/unittests/HoverTests.cpp clang-tools-extra/clangd/unittests/IncludeCleanerTests.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 @@ -43,6 +43,10 @@ using ::testing::UnorderedElementsAreArray; using ::testing::UnorderedPointwise; +std::string guard(llvm::StringRef Code) { + return "#pragma once\n" + Code.str(); +} + MATCHER_P2(FileRange, File, Range, "") { return Location{URIForFile::canonicalize(File, testRoot()), Range} == arg; } @@ -2293,6 +2297,50 @@ checkFindRefs(Test); } +TEST(FindReferences, UsedSymbolsFromInclude) { + const char *Tests[] = { + R"cpp([[#include ^"bar.h"]] +#include +int fstBar = [[bar1]](); +int sndBar = [[bar2]](); +[[Bar]] bar; +int macroBar = [[BAR]]; +std::vector vec; + )cpp", + + R"cpp([[#in^clude ]] +std::[[vector]] vec; + )cpp"}; + for (const char *Test : Tests) { +Annotations T(Test); +auto TU = TestTU::withCode(T.code()); +TU.ExtraArgs.push_back("-std=c++20"); +TU.AdditionalFiles["bar.h"] = guard(R"cpp( + #define BAR 5 + int bar1(); + int bar2(); + class Bar {}; +)cpp"); +TU.AdditionalFiles["system/vector"] = guard(R"cpp( + namespace std { +template +class vector{}; + } +)cpp"); +TU.ExtraArgs.push_back("-isystem" + testPath("system")); + +auto AST = TU.build(); +std::vector> ExpectedLocations; +for (const auto : T.ranges()) + ExpectedLocations.push_back(AllOf(rangeIs(R), attrsAre(0u))); +for (const auto : T.points()) + EXPECT_THAT(findReferences(AST, P, 0).References, + UnorderedElementsAreArray(ExpectedLocations)) + << "Failed for Refs at " << P << "\n" + << Test; + } +} + TEST(FindReferences, NeedsIndexForSymbols) { const char *Header = "int foo();"; Annotations Main("int main() { [[f^oo]](); }"); Index: clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp === --- clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp +++ clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp @@ -29,6 +29,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" #include +#include #include #include #include @@ -384,6 +385,48 @@ EXPECT_THAT(Findings.UnusedIncludes, IsEmpty()); } +TEST(IncludeCleaner, FirstMatchedProvider) { + struct { +const char *Code; +const std::vector Providers; +const std::optional ExpectedProvider; + } Cases[] = { + {R"cpp( +#include "bar.h" +#include "foo.h" + )cpp", + {include_cleaner::Header{"bar.h"}, include_cleaner::Header{"foo.h"}}, + include_cleaner::Header{"bar.h"}}, + {R"cpp( +#include "bar.h" +#include "foo.h" + )cpp", + {include_cleaner::Header{"foo.h"}, include_cleaner::Header{"bar.h"}}, + include_cleaner::Header{"foo.h"}}, + {"#include \"bar.h\"", + {include_cleaner::Header{"bar.h"}}, + include_cleaner::Header{"bar.h"}}, + {"#include \"bar.h\"", {include_cleaner::Header{"foo.h"}}, std::nullopt}, + {"#include \"bar.h\"", {}, std::nullopt}}; + for (const auto : Cases) { +Annotations Code{Case.Code}; +SCOPED_TRACE(Code.code()); + +TestTU TU; +TU.Code = Code.code(); +TU.AdditionalFiles["bar.h"] = ""; +TU.AdditionalFiles["foo.h"] = ""; + +auto AST = TU.build(); +std::optional MatchedProvider = +firstMatchedProvider( +convertIncludes(AST.getSourceManager(), +AST.getIncludeStructure().MainFileIncludes), +Case.Providers); +EXPECT_EQ(MatchedProvider, Case.ExpectedProvider); + } +} + } // namespace } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/unittests/HoverTests.cpp === --- clang-tools-extra/clangd/unittests/HoverTests.cpp +++ clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -2999,36 +2999,7 @@ #in^clude std::vector vec; )cpp", -[](HoverInfo ) { HI.UsedSymbolNames = {"vector"}; }}, - {R"cpp( - #in^clude
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
kadircet accepted this revision. kadircet added a comment. This revision is now accepted and ready to land. thanks! Comment at: clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp:398 + )cpp", + {include_cleaner::Header{"bar.h"}, include_cleaner::Header{"foo.h"}}, + include_cleaner::Header{"bar.h"}}, can you add a similar test case in which `foo.h` comes before `bar.h` ? Comment at: clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp:410 +TestTU TU; +TU.Filename = "foo.cpp"; +TU.Code = Code.code(); nit: no need for the filename Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
VitaNuo marked an inline comment as done. VitaNuo added inline comments. Comment at: clang-tools-extra/clangd/IncludeCleaner.h:87 +std::optional +firstMatchedProvider(const include_cleaner::Includes , + llvm::ArrayRef Providers); kadircet wrote: > VitaNuo wrote: > > kadircet wrote: > > > can you also move tests related to this functionality from HoverTests > > > into IncludeCleanerTests ? > > Not really, not sure what you mean. > > > > This function receives a ranked list of providers that should be a result > > of include_cleaner analysis. > > > > If I just test the function based on a fake list of providers, the test > > will be trivial. The current hover test seems to provide more value than > > that. > > If I just test the function based on a fake list of providers, the test > > will be trivial. > > but that's the "unit" of logic we're trying to test, no? Ok, I've extracted a test. Hopefully that's what you've meant. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
VitaNuo updated this revision to Diff 514901. VitaNuo added a comment. Extract a test for th firstMatchedProvider method. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 Files: clang-tools-extra/clangd/Hover.cpp clang-tools-extra/clangd/IncludeCleaner.cpp clang-tools-extra/clangd/IncludeCleaner.h clang-tools-extra/clangd/XRefs.cpp clang-tools-extra/clangd/unittests/HoverTests.cpp clang-tools-extra/clangd/unittests/IncludeCleanerTests.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 @@ -43,6 +43,10 @@ using ::testing::UnorderedElementsAreArray; using ::testing::UnorderedPointwise; +std::string guard(llvm::StringRef Code) { + return "#pragma once\n" + Code.str(); +} + MATCHER_P2(FileRange, File, Range, "") { return Location{URIForFile::canonicalize(File, testRoot()), Range} == arg; } @@ -2293,6 +2297,50 @@ checkFindRefs(Test); } +TEST(FindReferences, UsedSymbolsFromInclude) { + const char *Tests[] = { + R"cpp([[#include ^"bar.h"]] +#include +int fstBar = [[bar1]](); +int sndBar = [[bar2]](); +[[Bar]] bar; +int macroBar = [[BAR]]; +std::vector vec; + )cpp", + + R"cpp([[#in^clude ]] +std::[[vector]] vec; + )cpp"}; + for (const char *Test : Tests) { +Annotations T(Test); +auto TU = TestTU::withCode(T.code()); +TU.ExtraArgs.push_back("-std=c++20"); +TU.AdditionalFiles["bar.h"] = guard(R"cpp( + #define BAR 5 + int bar1(); + int bar2(); + class Bar {}; +)cpp"); +TU.AdditionalFiles["system/vector"] = guard(R"cpp( + namespace std { +template +class vector{}; + } +)cpp"); +TU.ExtraArgs.push_back("-isystem" + testPath("system")); + +auto AST = TU.build(); +std::vector> ExpectedLocations; +for (const auto : T.ranges()) + ExpectedLocations.push_back(AllOf(rangeIs(R), attrsAre(0u))); +for (const auto : T.points()) + EXPECT_THAT(findReferences(AST, P, 0).References, + UnorderedElementsAreArray(ExpectedLocations)) + << "Failed for Refs at " << P << "\n" + << Test; + } +} + TEST(FindReferences, NeedsIndexForSymbols) { const char *Header = "int foo();"; Annotations Main("int main() { [[f^oo]](); }"); Index: clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp === --- clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp +++ clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp @@ -29,6 +29,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" #include +#include #include #include #include @@ -384,6 +385,43 @@ EXPECT_THAT(Findings.UnusedIncludes, IsEmpty()); } +TEST(IncludeCleaner, FirstMatchedProvider) { + struct { +const char *Code; +const std::vector Providers; +const std::optional ExpectedProvider; + } Cases[] = { + {R"cpp( +#include "bar.h" +#include "foo.h" + )cpp", + {include_cleaner::Header{"bar.h"}, include_cleaner::Header{"foo.h"}}, + include_cleaner::Header{"bar.h"}}, + {"#include \"bar.h\"", + {include_cleaner::Header{"bar.h"}}, + include_cleaner::Header{"bar.h"}}, + {"#include \"bar.h\"", {include_cleaner::Header{"foo.h"}}, std::nullopt}, + {"#include \"bar.h\"", {}, std::nullopt}}; + for (const auto : Cases) { +Annotations Code{Case.Code}; +SCOPED_TRACE(Code.code()); + +TestTU TU; +TU.Filename = "foo.cpp"; +TU.Code = Code.code(); +TU.AdditionalFiles["bar.h"] = ""; +TU.AdditionalFiles["foo.h"] = ""; + +auto AST = TU.build(); +std::optional MatchedProvider = +firstMatchedProvider( +convertIncludes(AST.getSourceManager(), +AST.getIncludeStructure().MainFileIncludes), +Case.Providers); +EXPECT_EQ(MatchedProvider, Case.ExpectedProvider); + } +} + } // namespace } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/unittests/HoverTests.cpp === --- clang-tools-extra/clangd/unittests/HoverTests.cpp +++ clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -2999,36 +2999,7 @@ #in^clude std::vector vec; )cpp", -[](HoverInfo ) { HI.UsedSymbolNames = {"vector"}; }}, - {R"cpp( - #in^clude "public.h" - #include "private.h" - int fooVar = foo(); -)cpp", -[](HoverInfo ) { HI.UsedSymbolNames = {"foo"}; }}, -
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
kadircet added inline comments. Comment at: clang-tools-extra/clangd/IncludeCleaner.h:87 +std::optional +firstMatchedProvider(const include_cleaner::Includes , + llvm::ArrayRef Providers); VitaNuo wrote: > kadircet wrote: > > can you also move tests related to this functionality from HoverTests into > > IncludeCleanerTests ? > Not really, not sure what you mean. > > This function receives a ranked list of providers that should be a result of > include_cleaner analysis. > > If I just test the function based on a fake list of providers, the test will > be trivial. The current hover test seems to provide more value than that. > If I just test the function based on a fake list of providers, the test will > be trivial. but that's the "unit" of logic we're trying to test, no? Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
VitaNuo added a comment. Thanks for the comments! Comment at: clang-tools-extra/clangd/IncludeCleaner.h:87 +std::optional +firstMatchedProvider(const include_cleaner::Includes , + llvm::ArrayRef Providers); kadircet wrote: > can you also move tests related to this functionality from HoverTests into > IncludeCleanerTests ? Not really, not sure what you mean. This function receives a ranked list of providers that should be a result of include_cleaner analysis. If I just test the function based on a fake list of providers, the test will be trivial. The current hover test seems to provide more value than that. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
VitaNuo updated this revision to Diff 510484. VitaNuo marked 5 inline comments as done. VitaNuo added a comment. Address review comments. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 Files: clang-tools-extra/clangd/Hover.cpp clang-tools-extra/clangd/IncludeCleaner.cpp clang-tools-extra/clangd/IncludeCleaner.h clang-tools-extra/clangd/XRefs.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 @@ -43,6 +43,10 @@ using ::testing::UnorderedElementsAreArray; using ::testing::UnorderedPointwise; +std::string guard(llvm::StringRef Code) { + return "#pragma once\n" + Code.str(); +} + MATCHER_P2(FileRange, File, Range, "") { return Location{URIForFile::canonicalize(File, testRoot()), Range} == arg; } @@ -2293,6 +2297,50 @@ checkFindRefs(Test); } +TEST(FindReferences, UsedSymbolsFromInclude) { + const char *Tests[] = { + R"cpp([[#include ^"bar.h"]] +#include +int fstBar = [[bar1]](); +int sndBar = [[bar2]](); +[[Bar]] bar; +int macroBar = [[BAR]]; +std::vector vec; + )cpp", + + R"cpp([[#in^clude ]] +std::[[vector]] vec; + )cpp"}; + for (const char *Test : Tests) { +Annotations T(Test); +auto TU = TestTU::withCode(T.code()); +TU.ExtraArgs.push_back("-std=c++20"); +TU.AdditionalFiles["bar.h"] = guard(R"cpp( + #define BAR 5 + int bar1(); + int bar2(); + class Bar {}; +)cpp"); +TU.AdditionalFiles["system/vector"] = guard(R"cpp( + namespace std { +template +class vector{}; + } +)cpp"); +TU.ExtraArgs.push_back("-isystem" + testPath("system")); + +auto AST = TU.build(); +std::vector> ExpectedLocations; +for (const auto : T.ranges()) + ExpectedLocations.push_back(AllOf(rangeIs(R), attrsAre(0u))); +for (const auto : T.points()) + EXPECT_THAT(findReferences(AST, P, 0).References, + UnorderedElementsAreArray(ExpectedLocations)) + << "Failed for Refs at " << P << "\n" + << Test; + } +} + TEST(FindReferences, NeedsIndexForSymbols) { const char *Header = "int foo();"; Annotations Main("int main() { [[f^oo]](); }"); Index: clang-tools-extra/clangd/XRefs.cpp === --- clang-tools-extra/clangd/XRefs.cpp +++ clang-tools-extra/clangd/XRefs.cpp @@ -9,13 +9,17 @@ #include "AST.h" #include "FindSymbols.h" #include "FindTarget.h" +#include "Headers.h" #include "HeuristicResolver.h" +#include "IncludeCleaner.h" #include "ParsedAST.h" #include "Protocol.h" #include "Quality.h" #include "Selection.h" #include "SourceCode.h" #include "URI.h" +#include "clang-include-cleaner/Analysis.h" +#include "clang-include-cleaner/Types.h" #include "index/Index.h" #include "index/Merge.h" #include "index/Relation.h" @@ -48,6 +52,7 @@ #include "clang/Index/IndexingAction.h" #include "clang/Index/IndexingOptions.h" #include "clang/Index/USRGeneration.h" +#include "clang/Lex/Lexer.h" #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -61,6 +66,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include +#include #include namespace clang { @@ -1310,6 +1316,63 @@ return printQualifiedName(*ND); return {}; } + +std::optional +maybeFindIncludeReferences(ParsedAST , Position Pos, + URIForFile URIMainFile) { + const auto = AST.getIncludeStructure().MainFileIncludes; + auto IncludeOnLine = llvm::find_if(Includes, [](const Inclusion ) { +return Inc.HashLine == Pos.line; + }); + if (IncludeOnLine == Includes.end()) +return std::nullopt; + + const auto = *IncludeOnLine; + const SourceManager = AST.getSourceManager(); + ReferencesResult Results; + auto ConvertedMainFileIncludes = convertIncludes(SM, Includes); + auto ReferencedInclude = convertIncludes(SM, Inc); + include_cleaner::walkUsed( + AST.getLocalTopLevelDecls(), collectMacroReferences(AST), + AST.getPragmaIncludes(), SM, + [&](const include_cleaner::SymbolReference , + llvm::ArrayRef Providers) { +if (Ref.RT != include_cleaner::RefType::Explicit) + return; + +auto Provider = +firstMatchedProvider(ConvertedMainFileIncludes, Providers); +if (!Provider || ReferencedInclude.match(*Provider).empty()) + return; + +auto Loc = SM.getFileLoc(Ref.RefLocation); +// File locations can be outside of the main file if macro is +// expanded through an #include. +while (SM.getFileID(Loc) !=
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
kadircet added inline comments. Comment at: clang-tools-extra/clangd/IncludeCleaner.cpp:443 + // No match for this provider in the includes list. + return {}; +} `return std::nullopt` Comment at: clang-tools-extra/clangd/IncludeCleaner.h:87 +std::optional +firstMatchedProvider(const include_cleaner::Includes , + llvm::ArrayRef Providers); can you also move tests related to this functionality from HoverTests into IncludeCleanerTests ? Comment at: clang-tools-extra/clangd/XRefs.cpp:1320 +ReferencesResult maybeFindIncludeReferences(ParsedAST , Position Pos, +URIForFile URIMainFile) { can you put this into anon namespace? we should also change the return type to `std::optional`, as we can "legitimately" have empty result for an include, e.g. it's unused or all of the refs are implicit etc. Comment at: clang-tools-extra/clangd/XRefs.cpp:1324 + const SourceManager = AST.getSourceManager(); + auto Includes = AST.getIncludeStructure().MainFileIncludes; + auto ConvertedMainFileIncludes = convertIncludes(SM, Includes); `const auto = AST.getIncludeStructure().MainFileIncludes;` (`&` is the important bit, as we're copying all of them otherwise) Comment at: clang-tools-extra/clangd/XRefs.cpp:1325 + auto Includes = AST.getIncludeStructure().MainFileIncludes; + auto ConvertedMainFileIncludes = convertIncludes(SM, Includes); + for (auto : Includes) { let's move this into the for loop, after we've found a matching include to not necessarily create a copy of all the includes again. nit: you can also write the loop below as following and reduce some nesting. ``` auto IncludeOnLine = llvm::find_if(Includes, [](const Inclusion& Inc) { return Inc.HashLine == Pos.Line; }); if (IncludeOnLine == Includes.end()) return Results; const auto = *IncludeOnLine; ... ``` Comment at: clang-tools-extra/clangd/XRefs.cpp:1348 + auto Loc = SM.getFileLoc(Ref.RefLocation); + for (const auto : Providers) { +auto MatchingIncludes = ConvertedMainFileIncludes.match(H); VitaNuo wrote: > kadircet wrote: > > we're implementing and testing this logic twice now, once in here and once > > in hover. can we instead have a helper in `IncludeCleaner.h` that looks > > like: > > ``` > > std::optional firstSatisfiedProvider(const > > include_cleaner::Includes& Includes, > > llvm::ArrayRef Providers); > > // I'd actually return the matching `std::vector` (the > > highest ranked provider that matched some includes in main file), and check > > if the include of interest is part of that set for rest of the operations. > > // Since it represents both the provider and the include in the main file. > > whereas the provider on it's own doesn't say anything about which include > > in main file triggered satisfaction. > > ``` > > and turn these call sites into > > ``` > > auto Provider = firstSatisfiedProvider(ConvertedMainFileIncludes, > > Providers); > > if(!Provider || ReferencedInclude.match(Provider).empty()) > > return; > > // Include in question provides the symbol, do magic. > > ``` > Is the comment under the code in the first snippet a mistake/outdated > content? It confused me. that wasn't supposed to be a comment **in** the code but rather a comment **for** the code :D i was suggesting to return the set of `Include`s matched by the first provider, rather than returning the provider. but feel free to keep it as-is. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
VitaNuo updated this revision to Diff 510042. VitaNuo added a comment. Simplify. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 Files: clang-tools-extra/clangd/Hover.cpp clang-tools-extra/clangd/IncludeCleaner.cpp clang-tools-extra/clangd/IncludeCleaner.h clang-tools-extra/clangd/XRefs.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 @@ -43,6 +43,10 @@ using ::testing::UnorderedElementsAreArray; using ::testing::UnorderedPointwise; +std::string guard(llvm::StringRef Code) { + return "#pragma once\n" + Code.str(); +} + MATCHER_P2(FileRange, File, Range, "") { return Location{URIForFile::canonicalize(File, testRoot()), Range} == arg; } @@ -2293,6 +2297,50 @@ checkFindRefs(Test); } +TEST(FindReferences, UsedSymbolsFromInclude) { + const char *Tests[] = { + R"cpp([[#include ^"bar.h"]] +#include +int fstBar = [[bar1]](); +int sndBar = [[bar2]](); +[[Bar]] bar; +int macroBar = [[BAR]]; +std::vector vec; + )cpp", + + R"cpp([[#in^clude ]] +std::[[vector]] vec; + )cpp"}; + for (const char *Test : Tests) { +Annotations T(Test); +auto TU = TestTU::withCode(T.code()); +TU.ExtraArgs.push_back("-std=c++20"); +TU.AdditionalFiles["bar.h"] = guard(R"cpp( + #define BAR 5 + int bar1(); + int bar2(); + class Bar {}; +)cpp"); +TU.AdditionalFiles["system/vector"] = guard(R"cpp( + namespace std { +template +class vector{}; + } +)cpp"); +TU.ExtraArgs.push_back("-isystem" + testPath("system")); + +auto AST = TU.build(); +std::vector> ExpectedLocations; +for (const auto : T.ranges()) + ExpectedLocations.push_back(AllOf(rangeIs(R), attrsAre(0u))); +for (const auto : T.points()) + EXPECT_THAT(findReferences(AST, P, 0).References, + UnorderedElementsAreArray(ExpectedLocations)) + << "Failed for Refs at " << P << "\n" + << Test; + } +} + TEST(FindReferences, NeedsIndexForSymbols) { const char *Header = "int foo();"; Annotations Main("int main() { [[f^oo]](); }"); Index: clang-tools-extra/clangd/XRefs.cpp === --- clang-tools-extra/clangd/XRefs.cpp +++ clang-tools-extra/clangd/XRefs.cpp @@ -10,12 +10,15 @@ #include "FindSymbols.h" #include "FindTarget.h" #include "HeuristicResolver.h" +#include "IncludeCleaner.h" #include "ParsedAST.h" #include "Protocol.h" #include "Quality.h" #include "Selection.h" #include "SourceCode.h" #include "URI.h" +#include "clang-include-cleaner/Analysis.h" +#include "clang-include-cleaner/Types.h" #include "index/Index.h" #include "index/Merge.h" #include "index/Relation.h" @@ -48,6 +51,7 @@ #include "clang/Index/IndexingAction.h" #include "clang/Index/IndexingOptions.h" #include "clang/Index/USRGeneration.h" +#include "clang/Lex/Lexer.h" #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -61,6 +65,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include +#include #include namespace clang { @@ -1312,6 +1317,59 @@ } } // namespace +ReferencesResult maybeFindIncludeReferences(ParsedAST , Position Pos, +URIForFile URIMainFile) { + ReferencesResult Results; + const SourceManager = AST.getSourceManager(); + auto Includes = AST.getIncludeStructure().MainFileIncludes; + auto ConvertedMainFileIncludes = convertIncludes(SM, Includes); + for (auto : Includes) { +if (Inc.HashLine != Pos.line) + continue; + +auto ReferencedInclude = convertIncludes(SM, Inc); +include_cleaner::walkUsed( +AST.getLocalTopLevelDecls(), collectMacroReferences(AST), +AST.getPragmaIncludes(), SM, +[&](const include_cleaner::SymbolReference , +llvm::ArrayRef Providers) { + if (Ref.RT != include_cleaner::RefType::Explicit) +return; + + auto Provider = + firstMatchedProvider(ConvertedMainFileIncludes, Providers); + if (!Provider || ReferencedInclude.match(*Provider).empty()) +return; + + auto Loc = SM.getFileLoc(Ref.RefLocation); + // File locations can be outside of the main file if macro is + // expanded through an #include. + while (SM.getFileID(Loc) != SM.getMainFileID()) +Loc = SM.getIncludeLoc(SM.getFileID(Loc)); + + ReferencesResult::Reference Result; + const auto *Token = AST.getTokens().spelledTokenAt(Loc); + Result.Loc.range = +
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
VitaNuo added a comment. Thanks for the comments! Comment at: clang-tools-extra/clangd/XRefs.cpp:1348 + auto Loc = SM.getFileLoc(Ref.RefLocation); + for (const auto : Providers) { +auto MatchingIncludes = ConvertedMainFileIncludes.match(H); kadircet wrote: > we're implementing and testing this logic twice now, once in here and once in > hover. can we instead have a helper in `IncludeCleaner.h` that looks like: > ``` > std::optional firstSatisfiedProvider(const > include_cleaner::Includes& Includes, llvm::ArrayRef > Providers); > // I'd actually return the matching `std::vector` (the > highest ranked provider that matched some includes in main file), and check > if the include of interest is part of that set for rest of the operations. > // Since it represents both the provider and the include in the main file. > whereas the provider on it's own doesn't say anything about which include in > main file triggered satisfaction. > ``` > and turn these call sites into > ``` > auto Provider = firstSatisfiedProvider(ConvertedMainFileIncludes, Providers); > if(!Provider || ReferencedInclude.match(Provider).empty()) > return; > // Include in question provides the symbol, do magic. > ``` Is the comment under the code in the first snippet a mistake/outdated content? It confused me. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
VitaNuo updated this revision to Diff 510039. VitaNuo added a comment. Rename function. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 Files: clang-tools-extra/clangd/Hover.cpp clang-tools-extra/clangd/IncludeCleaner.cpp clang-tools-extra/clangd/IncludeCleaner.h clang-tools-extra/clangd/XRefs.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 @@ -43,6 +43,10 @@ using ::testing::UnorderedElementsAreArray; using ::testing::UnorderedPointwise; +std::string guard(llvm::StringRef Code) { + return "#pragma once\n" + Code.str(); +} + MATCHER_P2(FileRange, File, Range, "") { return Location{URIForFile::canonicalize(File, testRoot()), Range} == arg; } @@ -2293,6 +2297,50 @@ checkFindRefs(Test); } +TEST(FindReferences, UsedSymbolsFromInclude) { + const char *Tests[] = { + R"cpp([[#include ^"bar.h"]] +#include +int fstBar = [[bar1]](); +int sndBar = [[bar2]](); +[[Bar]] bar; +int macroBar = [[BAR]]; +std::vector vec; + )cpp", + + R"cpp([[#in^clude ]] +std::[[vector]] vec; + )cpp"}; + for (const char *Test : Tests) { +Annotations T(Test); +auto TU = TestTU::withCode(T.code()); +TU.ExtraArgs.push_back("-std=c++20"); +TU.AdditionalFiles["bar.h"] = guard(R"cpp( + #define BAR 5 + int bar1(); + int bar2(); + class Bar {}; +)cpp"); +TU.AdditionalFiles["system/vector"] = guard(R"cpp( + namespace std { +template +class vector{}; + } +)cpp"); +TU.ExtraArgs.push_back("-isystem" + testPath("system")); + +auto AST = TU.build(); +std::vector> ExpectedLocations; +for (const auto : T.ranges()) + ExpectedLocations.push_back(AllOf(rangeIs(R), attrsAre(0u))); +for (const auto : T.points()) + EXPECT_THAT(findReferences(AST, P, 0).References, + UnorderedElementsAreArray(ExpectedLocations)) + << "Failed for Refs at " << P << "\n" + << Test; + } +} + TEST(FindReferences, NeedsIndexForSymbols) { const char *Header = "int foo();"; Annotations Main("int main() { [[f^oo]](); }"); Index: clang-tools-extra/clangd/XRefs.cpp === --- clang-tools-extra/clangd/XRefs.cpp +++ clang-tools-extra/clangd/XRefs.cpp @@ -10,12 +10,15 @@ #include "FindSymbols.h" #include "FindTarget.h" #include "HeuristicResolver.h" +#include "IncludeCleaner.h" #include "ParsedAST.h" #include "Protocol.h" #include "Quality.h" #include "Selection.h" #include "SourceCode.h" #include "URI.h" +#include "clang-include-cleaner/Analysis.h" +#include "clang-include-cleaner/Types.h" #include "index/Index.h" #include "index/Merge.h" #include "index/Relation.h" @@ -48,6 +51,7 @@ #include "clang/Index/IndexingAction.h" #include "clang/Index/IndexingOptions.h" #include "clang/Index/USRGeneration.h" +#include "clang/Lex/Lexer.h" #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -61,6 +65,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include +#include #include namespace clang { @@ -1312,6 +1317,63 @@ } } // namespace +ReferencesResult maybeFindIncludeReferences(ParsedAST , Position Pos, +URIForFile URIMainFile) { + ReferencesResult Results; + const SourceManager = AST.getSourceManager(); + auto Includes = AST.getIncludeStructure().MainFileIncludes; + auto ConvertedMainFileIncludes = convertIncludes(SM, Includes); + for (auto : Includes) { +if (Inc.HashLine != Pos.line) + continue; + +auto ReferencedInclude = convertIncludes(SM, Inc); +include_cleaner::walkUsed( +AST.getLocalTopLevelDecls(), collectMacroReferences(AST), +AST.getPragmaIncludes(), SM, +[&](const include_cleaner::SymbolReference , +llvm::ArrayRef Providers) { + if (Ref.RT != include_cleaner::RefType::Explicit) +return; + + auto Provider = + firstMatchedProvider(ConvertedMainFileIncludes, Providers); + if (!Provider) +return; + + // Check if the referenced include matches this provider. + if (ReferencedInclude.match(*Provider).empty()) +return; + + auto Loc = SM.getFileLoc(Ref.RefLocation); + // File locations can be outside of the main file if macro is + // expanded through an #include. + while (SM.getFileID(Loc) != SM.getMainFileID()) +Loc = SM.getIncludeLoc(SM.getFileID(Loc)); + + ReferencesResult::Reference
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
VitaNuo updated this revision to Diff 510036. VitaNuo added a comment. Remove extra formatting changes. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 Files: clang-tools-extra/clangd/Hover.cpp clang-tools-extra/clangd/IncludeCleaner.cpp clang-tools-extra/clangd/IncludeCleaner.h clang-tools-extra/clangd/XRefs.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 @@ -43,6 +43,10 @@ using ::testing::UnorderedElementsAreArray; using ::testing::UnorderedPointwise; +std::string guard(llvm::StringRef Code) { + return "#pragma once\n" + Code.str(); +} + MATCHER_P2(FileRange, File, Range, "") { return Location{URIForFile::canonicalize(File, testRoot()), Range} == arg; } @@ -2293,6 +2297,51 @@ checkFindRefs(Test); } +TEST(FindReferences, UsedSymbolsFromInclude) { + const char *Tests[] = { + R"cpp([[#include ^"bar.h"]] +#include +int fstBar = [[bar1]](); +int sndBar = [[bar2]](); +[[Bar]] bar; +int macroBar = [[BAR]]; +std::vector vec; + )cpp", + + R"cpp([[#in^clude ]] +std::[[vector]] vec; + )cpp"}; + for (const char *Test : Tests) { +Annotations T(Test); +auto TU = TestTU::withCode(T.code()); +TU.ExtraArgs.push_back("-std=c++20"); +TU.AdditionalFiles["bar.h"] = guard(R"cpp( + #define BAR 5 + int bar1(); + int bar2(); + class Bar {}; +)cpp"); +TU.AdditionalFiles["system/vector"] = guard(R"cpp( + namespace std { +template +class vector{}; + } +)cpp"); +TU.ExtraArgs.push_back("-isystem" + testPath("system")); + +auto AST = TU.build(); +std::vector> ExpectedLocations; +for (const auto : T.ranges()) + ExpectedLocations.push_back(AllOf(rangeIs(R), attrsAre(0u))); +for (const auto : T.points()) { + EXPECT_THAT(findReferences(AST, P, 0).References, + UnorderedElementsAreArray(ExpectedLocations)) + << "Failed for Refs at " << P << "\n" + << Test; +} + } +} + TEST(FindReferences, NeedsIndexForSymbols) { const char *Header = "int foo();"; Annotations Main("int main() { [[f^oo]](); }"); Index: clang-tools-extra/clangd/XRefs.cpp === --- clang-tools-extra/clangd/XRefs.cpp +++ clang-tools-extra/clangd/XRefs.cpp @@ -10,12 +10,15 @@ #include "FindSymbols.h" #include "FindTarget.h" #include "HeuristicResolver.h" +#include "IncludeCleaner.h" #include "ParsedAST.h" #include "Protocol.h" #include "Quality.h" #include "Selection.h" #include "SourceCode.h" #include "URI.h" +#include "clang-include-cleaner/Analysis.h" +#include "clang-include-cleaner/Types.h" #include "index/Index.h" #include "index/Merge.h" #include "index/Relation.h" @@ -48,6 +51,7 @@ #include "clang/Index/IndexingAction.h" #include "clang/Index/IndexingOptions.h" #include "clang/Index/USRGeneration.h" +#include "clang/Lex/Lexer.h" #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -61,6 +65,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include +#include #include namespace clang { @@ -1312,6 +1317,63 @@ } } // namespace +ReferencesResult maybeFindIncludeReferences(ParsedAST , Position Pos, +URIForFile URIMainFile) { + ReferencesResult Results; + const SourceManager = AST.getSourceManager(); + auto Includes = AST.getIncludeStructure().MainFileIncludes; + auto ConvertedMainFileIncludes = convertIncludes(SM, Includes); + for (auto : Includes) { +if (Inc.HashLine != Pos.line) + continue; + +auto ReferencedInclude = convertIncludes(SM, Inc); +include_cleaner::walkUsed( +AST.getLocalTopLevelDecls(), collectMacroReferences(AST), +AST.getPragmaIncludes(), SM, +[&](const include_cleaner::SymbolReference , +llvm::ArrayRef Providers) { + if (Ref.RT != include_cleaner::RefType::Explicit) +return; + + auto Provider = + firstSatisfiedProvider(ConvertedMainFileIncludes, Providers); + if (!Provider) +return; + + // Check if the referenced include matches this provider. + if (ReferencedInclude.match(*Provider).empty()) +return; + + auto Loc = SM.getFileLoc(Ref.RefLocation); + // File locations can be outside of the main file if macro is + // expanded through an #include. + while (SM.getFileID(Loc) != SM.getMainFileID()) +Loc = SM.getIncludeLoc(SM.getFileID(Loc)); + +
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
VitaNuo updated this revision to Diff 510032. VitaNuo added a comment. Simplify. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 Files: clang-tools-extra/clangd/Hover.cpp clang-tools-extra/clangd/IncludeCleaner.cpp clang-tools-extra/clangd/IncludeCleaner.h clang-tools-extra/clangd/XRefs.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 @@ -43,6 +43,10 @@ using ::testing::UnorderedElementsAreArray; using ::testing::UnorderedPointwise; +std::string guard(llvm::StringRef Code) { + return "#pragma once\n" + Code.str(); +} + MATCHER_P2(FileRange, File, Range, "") { return Location{URIForFile::canonicalize(File, testRoot()), Range} == arg; } @@ -2293,6 +2297,51 @@ checkFindRefs(Test); } +TEST(FindReferences, UsedSymbolsFromInclude) { + const char *Tests[] = { + R"cpp([[#include ^"bar.h"]] +#include +int fstBar = [[bar1]](); +int sndBar = [[bar2]](); +[[Bar]] bar; +int macroBar = [[BAR]]; +std::vector vec; + )cpp", + + R"cpp([[#in^clude ]] +std::[[vector]] vec; + )cpp"}; + for (const char *Test : Tests) { +Annotations T(Test); +auto TU = TestTU::withCode(T.code()); +TU.ExtraArgs.push_back("-std=c++20"); +TU.AdditionalFiles["bar.h"] = guard(R"cpp( + #define BAR 5 + int bar1(); + int bar2(); + class Bar {}; +)cpp"); +TU.AdditionalFiles["system/vector"] = guard(R"cpp( + namespace std { +template +class vector{}; + } +)cpp"); +TU.ExtraArgs.push_back("-isystem" + testPath("system")); + +auto AST = TU.build(); +std::vector> ExpectedLocations; +for (const auto : T.ranges()) + ExpectedLocations.push_back(AllOf(rangeIs(R), attrsAre(0u))); +for (const auto : T.points()) { + EXPECT_THAT(findReferences(AST, P, 0).References, + UnorderedElementsAreArray(ExpectedLocations)) + << "Failed for Refs at " << P << "\n" + << Test; +} + } +} + TEST(FindReferences, NeedsIndexForSymbols) { const char *Header = "int foo();"; Annotations Main("int main() { [[f^oo]](); }"); Index: clang-tools-extra/clangd/XRefs.cpp === --- clang-tools-extra/clangd/XRefs.cpp +++ clang-tools-extra/clangd/XRefs.cpp @@ -10,12 +10,15 @@ #include "FindSymbols.h" #include "FindTarget.h" #include "HeuristicResolver.h" +#include "IncludeCleaner.h" #include "ParsedAST.h" #include "Protocol.h" #include "Quality.h" #include "Selection.h" #include "SourceCode.h" #include "URI.h" +#include "clang-include-cleaner/Analysis.h" +#include "clang-include-cleaner/Types.h" #include "index/Index.h" #include "index/Merge.h" #include "index/Relation.h" @@ -48,6 +51,7 @@ #include "clang/Index/IndexingAction.h" #include "clang/Index/IndexingOptions.h" #include "clang/Index/USRGeneration.h" +#include "clang/Lex/Lexer.h" #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -61,6 +65,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include +#include #include namespace clang { @@ -1312,6 +1317,63 @@ } } // namespace +ReferencesResult maybeFindIncludeReferences(ParsedAST , Position Pos, +URIForFile URIMainFile) { + ReferencesResult Results; + const SourceManager = AST.getSourceManager(); + auto Includes = AST.getIncludeStructure().MainFileIncludes; + auto ConvertedMainFileIncludes = convertIncludes(SM, Includes); + for (auto : Includes) { +if (Inc.HashLine != Pos.line) + continue; + +auto ReferencedInclude = convertIncludes(SM, Inc); +include_cleaner::walkUsed( +AST.getLocalTopLevelDecls(), collectMacroReferences(AST), +AST.getPragmaIncludes(), SM, +[&](const include_cleaner::SymbolReference , +llvm::ArrayRef Providers) { + if (Ref.RT != include_cleaner::RefType::Explicit) +return; + + auto Provider = + firstSatisfiedProvider(ConvertedMainFileIncludes, Providers); + if (!Provider) +return; + + // Check if the referenced include matches this provider. + if (ReferencedInclude.match(*Provider).empty()) +return; + + auto Loc = SM.getFileLoc(Ref.RefLocation); + // File locations can be outside of the main file if macro is + // expanded through an #include. + while (SM.getFileID(Loc) != SM.getMainFileID()) +Loc = SM.getIncludeLoc(SM.getFileID(Loc)); + +
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
VitaNuo updated this revision to Diff 510027. VitaNuo marked 10 inline comments as done. VitaNuo added a comment. Address review comments. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 Files: clang-tools-extra/clangd/Hover.cpp clang-tools-extra/clangd/IncludeCleaner.cpp clang-tools-extra/clangd/IncludeCleaner.h clang-tools-extra/clangd/XRefs.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 @@ -43,6 +43,10 @@ using ::testing::UnorderedElementsAreArray; using ::testing::UnorderedPointwise; +std::string guard(llvm::StringRef Code) { + return "#pragma once\n" + Code.str(); +} + MATCHER_P2(FileRange, File, Range, "") { return Location{URIForFile::canonicalize(File, testRoot()), Range} == arg; } @@ -2293,6 +2297,51 @@ checkFindRefs(Test); } +TEST(FindReferences, UsedSymbolsFromInclude) { + const char *Tests[] = { + R"cpp([[#include ^"bar.h"]] +#include +int fstBar = [[bar1]](); +int sndBar = [[bar2]](); +[[Bar]] bar; +int macroBar = [[BAR]]; +std::vector vec; + )cpp", + + R"cpp([[#in^clude ]] +std::[[vector]] vec; + )cpp"}; + for (const char *Test : Tests) { +Annotations T(Test); +auto TU = TestTU::withCode(T.code()); +TU.ExtraArgs.push_back("-std=c++20"); +TU.AdditionalFiles["bar.h"] = guard(R"cpp( + #define BAR 5 + int bar1(); + int bar2(); + class Bar {}; +)cpp"); +TU.AdditionalFiles["system/vector"] = guard(R"cpp( + namespace std { +template +class vector{}; + } +)cpp"); +TU.ExtraArgs.push_back("-isystem" + testPath("system")); + +auto AST = TU.build(); +std::vector> ExpectedLocations; +for (const auto : T.ranges()) + ExpectedLocations.push_back(AllOf(rangeIs(R), attrsAre(0u))); +for (const auto : T.points()) { + EXPECT_THAT(findReferences(AST, P, 0).References, + UnorderedElementsAreArray(ExpectedLocations)) + << "Failed for Refs at " << P << "\n" + << Test; +} + } +} + TEST(FindReferences, NeedsIndexForSymbols) { const char *Header = "int foo();"; Annotations Main("int main() { [[f^oo]](); }"); Index: clang-tools-extra/clangd/XRefs.cpp === --- clang-tools-extra/clangd/XRefs.cpp +++ clang-tools-extra/clangd/XRefs.cpp @@ -10,12 +10,15 @@ #include "FindSymbols.h" #include "FindTarget.h" #include "HeuristicResolver.h" +#include "IncludeCleaner.h" #include "ParsedAST.h" #include "Protocol.h" #include "Quality.h" #include "Selection.h" #include "SourceCode.h" #include "URI.h" +#include "clang-include-cleaner/Analysis.h" +#include "clang-include-cleaner/Types.h" #include "index/Index.h" #include "index/Merge.h" #include "index/Relation.h" @@ -48,6 +51,7 @@ #include "clang/Index/IndexingAction.h" #include "clang/Index/IndexingOptions.h" #include "clang/Index/USRGeneration.h" +#include "clang/Lex/Lexer.h" #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -61,6 +65,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include +#include #include namespace clang { @@ -1312,6 +1317,63 @@ } } // namespace +ReferencesResult maybeFindIncludeReferences(ParsedAST , Position Pos, +URIForFile URIMainFile) { + ReferencesResult Results; + const SourceManager = AST.getSourceManager(); + auto Includes = AST.getIncludeStructure().MainFileIncludes; + auto ConvertedMainFileIncludes = convertIncludes(SM, Includes); + for (auto : Includes) { +if (Inc.HashLine != Pos.line) + continue; + +auto ReferencedInclude = convertIncludes(SM, Inc); +include_cleaner::walkUsed( +AST.getLocalTopLevelDecls(), collectMacroReferences(AST), +AST.getPragmaIncludes(), SM, +[&](const include_cleaner::SymbolReference , +llvm::ArrayRef Providers) { + if (Ref.RT != include_cleaner::RefType::Explicit) +return; + + auto Provider = + firstSatisfiedProvider(ConvertedMainFileIncludes, Providers); + if (!Provider) +return; + + // Check if the referenced include matches this provider. + if (ReferencedInclude.match(*Provider).empty()) +return; + + auto Loc = SM.getFileLoc(Ref.RefLocation); + // File locations can be outside of the main file if macro is + // expanded through an #include. + while (SM.getFileID(Loc) != SM.getMainFileID()) +Loc =
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
kadircet added inline comments. Comment at: clang-tools-extra/clangd/XRefs.cpp:1338 + +auto ReferencedInclude = convertIncludes(SM, Inc); +include_cleaner::walkUsed( can we put the rest into a separate function (I know this function is already quite long, but I think we shouldn't make it worse, and probably refactor soon). I believe something like below should work? ``` std::vector getIncludeUsages(const ParsedAST , const Inclusion ); ``` Comment at: clang-tools-extra/clangd/XRefs.cpp:1347 + + auto Loc = SM.getFileLoc(Ref.RefLocation); + for (const auto : Providers) { nit: no need to calculate the file location, if we're not going to emit a reference. so maybe move this into the place where we're going to use the `Loc`. Comment at: clang-tools-extra/clangd/XRefs.cpp:1347 + + auto Loc = SM.getFileLoc(Ref.RefLocation); + for (const auto : Providers) { kadircet wrote: > nit: no need to calculate the file location, if we're not going to emit a > reference. so maybe move this into the place where we're going to use the > `Loc`. this file location might fall outside of the main file when they get expanded through `#include` directives, so we need something like https://reviews.llvm.org/D147139 Comment at: clang-tools-extra/clangd/XRefs.cpp:1348 + auto Loc = SM.getFileLoc(Ref.RefLocation); + for (const auto : Providers) { +auto MatchingIncludes = ConvertedMainFileIncludes.match(H); we're implementing and testing this logic twice now, once in here and once in hover. can we instead have a helper in `IncludeCleaner.h` that looks like: ``` std::optional firstSatisfiedProvider(const include_cleaner::Includes& Includes, llvm::ArrayRef Providers); // I'd actually return the matching `std::vector` (the highest ranked provider that matched some includes in main file), and check if the include of interest is part of that set for rest of the operations. // Since it represents both the provider and the include in the main file. whereas the provider on it's own doesn't say anything about which include in main file triggered satisfaction. ``` and turn these call sites into ``` auto Provider = firstSatisfiedProvider(ConvertedMainFileIncludes, Providers); if(!Provider || ReferencedInclude.match(Provider).empty()) return; // Include in question provides the symbol, do magic. ``` Comment at: clang-tools-extra/clangd/XRefs.cpp:1358 + auto TokLen = + Lexer::MeasureTokenLength(Loc, SM, AST.getLangOpts()); + Result.Loc.range = no need to re-run the lexer, these references are inside the main file for sure, so you can use token buffer instead. Comment at: clang-tools-extra/clangd/XRefs.cpp:1381 +Result.Loc.uri = URIMainFile; +Results.References.push_back(std::move(Result)); + } we can return Results directly here, no need to run rest of the logic Comment at: clang-tools-extra/clangd/XRefs.cpp:2004 -// Given a type targeted by the cursor, return one or more types that are more interesting -// to target. -static void unwrapFindType( -QualType T, const HeuristicResolver* H, llvm::SmallVector& Out) { +// Given a type targeted by the cursor, return one or more types that are more +// interesting to target. can you revert changes below? I feel like they're unrelated formatting changes Comment at: clang-tools-extra/clangd/unittests/XRefsTests.cpp:1909 TU.ExtraArgs.push_back("-std=c++20"); + TU.AdditionalFiles["bar.h"] = guard(R"cpp( +#define BAR 5 rather than introducing these into all tests, can we have our own TestTU and whatnot in the relevant test? something like MainFileReferencesOnly test Comment at: clang-tools-extra/clangd/unittests/XRefsTests.cpp:2322 + const char *Tests[] = { + R"cpp([[#include ^"bar.h"]] +int fstBar = [[bar1]](); can you also have a second include header that provides some other symbols and make sure references of those don't get highlighted? Comment at: clang-tools-extra/clangd/unittests/XRefsTests.cpp:2329 + + R"cpp([[#in^clude ]] +std::[[vector]] vec; we don't really need rest of these tests, they're testing the "symbol is provided by first provider included in the main file" logic Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
VitaNuo updated this revision to Diff 509017. VitaNuo added a comment. Formatting. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 Files: clang-tools-extra/clangd/XRefs.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 @@ -5,8 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===--===// -#include "Annotations.h" #include "AST.h" +#include "Annotations.h" #include "ParsedAST.h" #include "Protocol.h" #include "SourceCode.h" @@ -43,6 +43,10 @@ using ::testing::UnorderedElementsAreArray; using ::testing::UnorderedPointwise; +std::string guard(llvm::StringRef Code) { + return "#pragma once\n" + Code.str(); +} + MATCHER_P2(FileRange, File, Range, "") { return Location{URIForFile::canonicalize(File, testRoot()), Range} == arg; } @@ -1876,8 +1880,8 @@ ASSERT_GT(A.points().size(), 0u) << Case; for (auto Pos : A.points()) EXPECT_THAT(findType(AST, Pos), - ElementsAre( -sym("Target", HeaderA.range("Target"), HeaderA.range("Target" + ElementsAre(sym("Target", HeaderA.range("Target"), + HeaderA.range("Target" << Case; } @@ -1888,11 +1892,12 @@ TU.Code = A.code().str(); ParsedAST AST = TU.build(); -EXPECT_THAT(findType(AST, A.point()), -UnorderedElementsAre( - sym("Target", HeaderA.range("Target"), HeaderA.range("Target")), - sym("smart_ptr", HeaderA.range("smart_ptr"), HeaderA.range("smart_ptr")) -)) +EXPECT_THAT( +findType(AST, A.point()), +UnorderedElementsAre( +sym("Target", HeaderA.range("Target"), HeaderA.range("Target")), +sym("smart_ptr", HeaderA.range("smart_ptr"), +HeaderA.range("smart_ptr" << Case; } } @@ -1901,6 +1906,25 @@ Annotations T(Test); auto TU = TestTU::withCode(T.code()); TU.ExtraArgs.push_back("-std=c++20"); + TU.AdditionalFiles["bar.h"] = guard(R"cpp( +#define BAR 5 +int bar1(); +int bar2(); +class Bar {}; + )cpp"); + TU.AdditionalFiles["private.h"] = guard(R"cpp( +// IWYU pragma: private, include "public.h" +int foo(); + )cpp"); + TU.AdditionalFiles["public.h"] = guard(""); + TU.AdditionalFiles["system/vector"] = guard(R"cpp( +namespace std { + template + class vector{}; +} + )cpp"); + TU.AdditionalFiles["forward.h"] = guard("class Bar;"); + TU.ExtraArgs.push_back("-isystem" + testPath("system")); auto AST = TU.build(); std::vector> ExpectedLocations; @@ -2293,6 +2317,42 @@ checkFindRefs(Test); } +TEST(FindReferences, UsedSymbolsFromInclude) { + const char *Tests[] = { + R"cpp([[#include ^"bar.h"]] +int fstBar = [[bar1]](); +int sndBar = [[bar2]](); +[[Bar]] bar; +int macroBar = [[BAR]]; + )cpp", + + R"cpp([[#in^clude ]] +std::[[vector]] vec; + )cpp", + + R"cpp([[#in^clude "public.h"]] +#include "private.h" +int fooVar = [[foo]](); + )cpp", + + R"cpp(#include "bar.h" +#include "for^ward.h" +Bar *x; + )cpp", + + R"cpp([[#include "b^ar.h"]] +#define DEF(X) const Bar *X +[[DEF]](a); + )cpp", + + R"cpp([[#in^clude "bar.h"]] +#define BAZ(X) const X x +BAZ([[Bar]]); + )cpp"}; + for (const char *Test : Tests) +checkFindRefs(Test); +} + TEST(FindReferences, NeedsIndexForSymbols) { const char *Header = "int foo();"; Annotations Main("int main() { [[f^oo]](); }"); Index: clang-tools-extra/clangd/XRefs.cpp === --- clang-tools-extra/clangd/XRefs.cpp +++ clang-tools-extra/clangd/XRefs.cpp @@ -10,12 +10,15 @@ #include "FindSymbols.h" #include "FindTarget.h" #include "HeuristicResolver.h" +#include "IncludeCleaner.h" #include "ParsedAST.h" #include "Protocol.h" #include "Quality.h" #include "Selection.h" #include "SourceCode.h" #include "URI.h" +#include "clang-include-cleaner/Analysis.h" +#include "clang-include-cleaner/Types.h" #include "index/Index.h" #include "index/Merge.h" #include "index/Relation.h" @@ -48,6 +51,7 @@ #include "clang/Index/IndexingAction.h" #include "clang/Index/IndexingOptions.h" #include "clang/Index/USRGeneration.h" +#include "clang/Lex/Lexer.h" #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -61,6 +65,7 @@ #include "llvm/Support/Path.h" #include
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
VitaNuo updated this revision to Diff 509015. VitaNuo added a comment. Remove redundant code. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 Files: clang-tools-extra/clangd/XRefs.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 @@ -5,8 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===--===// -#include "Annotations.h" #include "AST.h" +#include "Annotations.h" #include "ParsedAST.h" #include "Protocol.h" #include "SourceCode.h" @@ -43,6 +43,10 @@ using ::testing::UnorderedElementsAreArray; using ::testing::UnorderedPointwise; +std::string guard(llvm::StringRef Code) { + return "#pragma once\n" + Code.str(); +} + MATCHER_P2(FileRange, File, Range, "") { return Location{URIForFile::canonicalize(File, testRoot()), Range} == arg; } @@ -1876,8 +1880,8 @@ ASSERT_GT(A.points().size(), 0u) << Case; for (auto Pos : A.points()) EXPECT_THAT(findType(AST, Pos), - ElementsAre( -sym("Target", HeaderA.range("Target"), HeaderA.range("Target" + ElementsAre(sym("Target", HeaderA.range("Target"), + HeaderA.range("Target" << Case; } @@ -1888,11 +1892,12 @@ TU.Code = A.code().str(); ParsedAST AST = TU.build(); -EXPECT_THAT(findType(AST, A.point()), -UnorderedElementsAre( - sym("Target", HeaderA.range("Target"), HeaderA.range("Target")), - sym("smart_ptr", HeaderA.range("smart_ptr"), HeaderA.range("smart_ptr")) -)) +EXPECT_THAT( +findType(AST, A.point()), +UnorderedElementsAre( +sym("Target", HeaderA.range("Target"), HeaderA.range("Target")), +sym("smart_ptr", HeaderA.range("smart_ptr"), +HeaderA.range("smart_ptr" << Case; } } @@ -1901,6 +1906,25 @@ Annotations T(Test); auto TU = TestTU::withCode(T.code()); TU.ExtraArgs.push_back("-std=c++20"); + TU.AdditionalFiles["bar.h"] = guard(R"cpp( +#define BAR 5 +int bar1(); +int bar2(); +class Bar {}; + )cpp"); + TU.AdditionalFiles["private.h"] = guard(R"cpp( +// IWYU pragma: private, include "public.h" +int foo(); + )cpp"); + TU.AdditionalFiles["public.h"] = guard(""); + TU.AdditionalFiles["system/vector"] = guard(R"cpp( +namespace std { + template + class vector{}; +} + )cpp"); + TU.AdditionalFiles["forward.h"] = guard("class Bar;"); + TU.ExtraArgs.push_back("-isystem" + testPath("system")); auto AST = TU.build(); std::vector> ExpectedLocations; @@ -2293,6 +2317,42 @@ checkFindRefs(Test); } +TEST(FindReferences, UsedSymbolsFromInclude) { + const char *Tests[] = { + R"cpp([[#include ^"bar.h"]] +int fstBar = [[bar1]](); +int sndBar = [[bar2]](); +[[Bar]] bar; +int macroBar = [[BAR]]; + )cpp", + + R"cpp([[#in^clude ]] +std::[[vector]] vec; + )cpp", + + R"cpp([[#in^clude "public.h"]] +#include "private.h" +int fooVar = [[foo]](); + )cpp", + + R"cpp(#include "bar.h" +#include "for^ward.h" +Bar *x; + )cpp", + + R"cpp([[#include "b^ar.h"]] +#define DEF(X) const Bar *X +[[DEF]](a); + )cpp", + + R"cpp([[#in^clude "bar.h"]] +#define BAZ(X) const X x +BAZ([[Bar]]); + )cpp"}; + for (const char *Test : Tests) +checkFindRefs(Test); +} + TEST(FindReferences, NeedsIndexForSymbols) { const char *Header = "int foo();"; Annotations Main("int main() { [[f^oo]](); }"); Index: clang-tools-extra/clangd/XRefs.cpp === --- clang-tools-extra/clangd/XRefs.cpp +++ clang-tools-extra/clangd/XRefs.cpp @@ -10,12 +10,15 @@ #include "FindSymbols.h" #include "FindTarget.h" #include "HeuristicResolver.h" +#include "IncludeCleaner.h" #include "ParsedAST.h" #include "Protocol.h" #include "Quality.h" #include "Selection.h" #include "SourceCode.h" #include "URI.h" +#include "clang-include-cleaner/Analysis.h" +#include "clang-include-cleaner/Types.h" #include "index/Index.h" #include "index/Merge.h" #include "index/Relation.h" @@ -48,6 +51,7 @@ #include "clang/Index/IndexingAction.h" #include "clang/Index/IndexingOptions.h" #include "clang/Index/USRGeneration.h" +#include "clang/Lex/Lexer.h" #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -61,6 +65,7 @@ #include "llvm/Support/Path.h" #include
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
VitaNuo updated this revision to Diff 508986. VitaNuo added a comment. Formatting. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 Files: clang-tools-extra/clangd/XRefs.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 @@ -5,8 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===--===// -#include "Annotations.h" #include "AST.h" +#include "Annotations.h" #include "ParsedAST.h" #include "Protocol.h" #include "SourceCode.h" @@ -43,6 +43,10 @@ using ::testing::UnorderedElementsAreArray; using ::testing::UnorderedPointwise; +std::string guard(llvm::StringRef Code) { + return "#pragma once\n" + Code.str(); +} + MATCHER_P2(FileRange, File, Range, "") { return Location{URIForFile::canonicalize(File, testRoot()), Range} == arg; } @@ -1876,8 +1880,8 @@ ASSERT_GT(A.points().size(), 0u) << Case; for (auto Pos : A.points()) EXPECT_THAT(findType(AST, Pos), - ElementsAre( -sym("Target", HeaderA.range("Target"), HeaderA.range("Target" + ElementsAre(sym("Target", HeaderA.range("Target"), + HeaderA.range("Target" << Case; } @@ -1888,11 +1892,12 @@ TU.Code = A.code().str(); ParsedAST AST = TU.build(); -EXPECT_THAT(findType(AST, A.point()), -UnorderedElementsAre( - sym("Target", HeaderA.range("Target"), HeaderA.range("Target")), - sym("smart_ptr", HeaderA.range("smart_ptr"), HeaderA.range("smart_ptr")) -)) +EXPECT_THAT( +findType(AST, A.point()), +UnorderedElementsAre( +sym("Target", HeaderA.range("Target"), HeaderA.range("Target")), +sym("smart_ptr", HeaderA.range("smart_ptr"), +HeaderA.range("smart_ptr" << Case; } } @@ -1901,6 +1906,25 @@ Annotations T(Test); auto TU = TestTU::withCode(T.code()); TU.ExtraArgs.push_back("-std=c++20"); + TU.AdditionalFiles["bar.h"] = guard(R"cpp( +#define BAR 5 +int bar1(); +int bar2(); +class Bar {}; + )cpp"); + TU.AdditionalFiles["private.h"] = guard(R"cpp( +// IWYU pragma: private, include "public.h" +int foo(); + )cpp"); + TU.AdditionalFiles["public.h"] = guard(""); + TU.AdditionalFiles["system/vector"] = guard(R"cpp( +namespace std { + template + class vector{}; +} + )cpp"); + TU.AdditionalFiles["forward.h"] = guard("class Bar;"); + TU.ExtraArgs.push_back("-isystem" + testPath("system")); auto AST = TU.build(); std::vector> ExpectedLocations; @@ -2293,6 +2317,42 @@ checkFindRefs(Test); } +TEST(FindReferences, UsedSymbolsFromInclude) { + const char *Tests[] = { + R"cpp([[#include ^"bar.h"]] +int fstBar = [[bar1]](); +int sndBar = [[bar2]](); +[[Bar]] bar; +int macroBar = [[BAR]]; + )cpp", + + R"cpp([[#in^clude ]] +std::[[vector]] vec; + )cpp", + + R"cpp([[#in^clude "public.h"]] +#include "private.h" +int fooVar = [[foo]](); + )cpp", + + R"cpp(#include "bar.h" +#include "for^ward.h" +Bar *x; + )cpp", + + R"cpp([[#include "b^ar.h"]] +#define DEF(X) const Bar *X +[[DEF]](a); + )cpp", + + R"cpp([[#in^clude "bar.h"]] +#define BAZ(X) const X x +BAZ([[Bar]]); + )cpp"}; + for (const char *Test : Tests) +checkFindRefs(Test); +} + TEST(FindReferences, NeedsIndexForSymbols) { const char *Header = "int foo();"; Annotations Main("int main() { [[f^oo]](); }"); Index: clang-tools-extra/clangd/XRefs.cpp === --- clang-tools-extra/clangd/XRefs.cpp +++ clang-tools-extra/clangd/XRefs.cpp @@ -10,12 +10,15 @@ #include "FindSymbols.h" #include "FindTarget.h" #include "HeuristicResolver.h" +#include "IncludeCleaner.h" #include "ParsedAST.h" #include "Protocol.h" #include "Quality.h" #include "Selection.h" #include "SourceCode.h" #include "URI.h" +#include "clang-include-cleaner/Analysis.h" +#include "clang-include-cleaner/Types.h" #include "index/Index.h" #include "index/Merge.h" #include "index/Relation.h" @@ -48,6 +51,7 @@ #include "clang/Index/IndexingAction.h" #include "clang/Index/IndexingOptions.h" #include "clang/Index/USRGeneration.h" +#include "clang/Lex/Lexer.h" #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -61,6 +65,7 @@ #include "llvm/Support/Path.h" #include
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
VitaNuo updated this revision to Diff 508975. VitaNuo added a comment. Smaller improvements. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D147044/new/ https://reviews.llvm.org/D147044 Files: clang-tools-extra/clangd/XRefs.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 @@ -5,8 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===--===// -#include "Annotations.h" #include "AST.h" +#include "Annotations.h" #include "ParsedAST.h" #include "Protocol.h" #include "SourceCode.h" @@ -43,6 +43,10 @@ using ::testing::UnorderedElementsAreArray; using ::testing::UnorderedPointwise; +std::string guard(llvm::StringRef Code) { + return "#pragma once\n" + Code.str(); +} + MATCHER_P2(FileRange, File, Range, "") { return Location{URIForFile::canonicalize(File, testRoot()), Range} == arg; } @@ -1876,8 +1880,8 @@ ASSERT_GT(A.points().size(), 0u) << Case; for (auto Pos : A.points()) EXPECT_THAT(findType(AST, Pos), - ElementsAre( -sym("Target", HeaderA.range("Target"), HeaderA.range("Target" + ElementsAre(sym("Target", HeaderA.range("Target"), + HeaderA.range("Target" << Case; } @@ -1888,11 +1892,12 @@ TU.Code = A.code().str(); ParsedAST AST = TU.build(); -EXPECT_THAT(findType(AST, A.point()), -UnorderedElementsAre( - sym("Target", HeaderA.range("Target"), HeaderA.range("Target")), - sym("smart_ptr", HeaderA.range("smart_ptr"), HeaderA.range("smart_ptr")) -)) +EXPECT_THAT( +findType(AST, A.point()), +UnorderedElementsAre( +sym("Target", HeaderA.range("Target"), HeaderA.range("Target")), +sym("smart_ptr", HeaderA.range("smart_ptr"), +HeaderA.range("smart_ptr" << Case; } } @@ -1901,6 +1906,25 @@ Annotations T(Test); auto TU = TestTU::withCode(T.code()); TU.ExtraArgs.push_back("-std=c++20"); + TU.AdditionalFiles["bar.h"] = guard(R"cpp( +#define BAR 5 +int bar1(); +int bar2(); +class Bar {}; + )cpp"); + TU.AdditionalFiles["private.h"] = guard(R"cpp( +// IWYU pragma: private, include "public.h" +int foo(); + )cpp"); + TU.AdditionalFiles["public.h"] = guard(""); + TU.AdditionalFiles["system/vector"] = guard(R"cpp( +namespace std { + template + class vector{}; +} + )cpp"); + TU.AdditionalFiles["forward.h"] = guard("class Bar;"); + TU.ExtraArgs.push_back("-isystem" + testPath("system")); auto AST = TU.build(); std::vector> ExpectedLocations; @@ -2293,6 +2317,42 @@ checkFindRefs(Test); } +TEST(FindReferences, UsedSymbolsFromInclude) { + const char *Tests[] = { + R"cpp([[#include ^"bar.h"]] +int fstBar = [[bar1]](); +int sndBar = [[bar2]](); +[[Bar]] bar; +int macroBar = [[BAR]]; + )cpp", + + R"cpp([[#in^clude ]] +std::[[vector]] vec; + )cpp", + + R"cpp([[#in^clude "public.h"]] +#include "private.h" +int fooVar = [[foo]](); + )cpp", + + R"cpp(#include "bar.h" +#include "for^ward.h" +Bar *x; + )cpp", + + R"cpp([[#include "b^ar.h"]] +#define DEF(X) const Bar *X +[[DEF]](a); + )cpp", + + R"cpp([[#in^clude "bar.h"]] +#define BAZ(X) const X x +BAZ([[Bar]]); + )cpp"}; + for (const char *Test : Tests) +checkFindRefs(Test); +} + TEST(FindReferences, NeedsIndexForSymbols) { const char *Header = "int foo();"; Annotations Main("int main() { [[f^oo]](); }"); Index: clang-tools-extra/clangd/XRefs.cpp === --- clang-tools-extra/clangd/XRefs.cpp +++ clang-tools-extra/clangd/XRefs.cpp @@ -10,12 +10,15 @@ #include "FindSymbols.h" #include "FindTarget.h" #include "HeuristicResolver.h" +#include "IncludeCleaner.h" #include "ParsedAST.h" #include "Protocol.h" #include "Quality.h" #include "Selection.h" #include "SourceCode.h" #include "URI.h" +#include "clang-include-cleaner/Analysis.h" +#include "clang-include-cleaner/Types.h" #include "index/Index.h" #include "index/Merge.h" #include "index/Relation.h" @@ -48,6 +51,7 @@ #include "clang/Index/IndexingAction.h" #include "clang/Index/IndexingOptions.h" #include "clang/Index/USRGeneration.h" +#include "clang/Lex/Lexer.h" #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -61,6 +65,7 @@ #include "llvm/Support/Path.h" #include
[PATCH] D147044: [clangd] Implement cross reference request for #include lines.
VitaNuo created this revision. Herald added subscribers: kadircet, arphaman. Herald added a project: All. VitaNuo requested review of this revision. Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov. Herald added a project: clang-tools-extra. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D147044 Files: clang-tools-extra/clangd/XRefs.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 @@ -5,8 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===--===// -#include "Annotations.h" #include "AST.h" +#include "Annotations.h" #include "ParsedAST.h" #include "Protocol.h" #include "SourceCode.h" @@ -43,6 +43,10 @@ using ::testing::UnorderedElementsAreArray; using ::testing::UnorderedPointwise; +std::string guard(llvm::StringRef Code) { + return "#pragma once\n" + Code.str(); +} + MATCHER_P2(FileRange, File, Range, "") { return Location{URIForFile::canonicalize(File, testRoot()), Range} == arg; } @@ -1876,8 +1880,8 @@ ASSERT_GT(A.points().size(), 0u) << Case; for (auto Pos : A.points()) EXPECT_THAT(findType(AST, Pos), - ElementsAre( -sym("Target", HeaderA.range("Target"), HeaderA.range("Target" + ElementsAre(sym("Target", HeaderA.range("Target"), + HeaderA.range("Target" << Case; } @@ -1888,11 +1892,12 @@ TU.Code = A.code().str(); ParsedAST AST = TU.build(); -EXPECT_THAT(findType(AST, A.point()), -UnorderedElementsAre( - sym("Target", HeaderA.range("Target"), HeaderA.range("Target")), - sym("smart_ptr", HeaderA.range("smart_ptr"), HeaderA.range("smart_ptr")) -)) +EXPECT_THAT( +findType(AST, A.point()), +UnorderedElementsAre( +sym("Target", HeaderA.range("Target"), HeaderA.range("Target")), +sym("smart_ptr", HeaderA.range("smart_ptr"), +HeaderA.range("smart_ptr" << Case; } } @@ -1901,6 +1906,25 @@ Annotations T(Test); auto TU = TestTU::withCode(T.code()); TU.ExtraArgs.push_back("-std=c++20"); + TU.AdditionalFiles["bar.h"] = guard(R"cpp( +#define BAR 5 +int bar1(); +int bar2(); +class Bar {}; + )cpp"); + TU.AdditionalFiles["private.h"] = guard(R"cpp( +// IWYU pragma: private, include "public.h" +int foo(); + )cpp"); + TU.AdditionalFiles["public.h"] = guard(""); + TU.AdditionalFiles["system/vector"] = guard(R"cpp( +namespace std { + template + class vector{}; +} + )cpp"); + TU.AdditionalFiles["forward.h"] = guard("class Bar;"); + TU.ExtraArgs.push_back("-isystem" + testPath("system")); auto AST = TU.build(); std::vector> ExpectedLocations; @@ -2293,6 +2317,42 @@ checkFindRefs(Test); } +TEST(FindReferences, UsedSymbolsFromInclude) { + const char *Tests[] = { + R"cpp([[#include ^"bar.h"]] +int fstBar = [[bar1]](); +int sndBar = [[bar2]](); +[[Bar]] bar; +int macroBar = [[BAR]]; + )cpp", + + R"cpp([[#in^clude ]] +std::[[vector]] vec; + )cpp", + + R"cpp([[#in^clude "public.h"]] +#include "private.h" +int fooVar = [[foo]](); + )cpp", + + R"cpp(#include "bar.h" +#include "for^ward.h" +Bar *x; + )cpp", + + R"cpp([[#include "b^ar.h"]] +#define DEF(X) const Bar *X +[[DEF]](a); + )cpp", + + R"cpp([[#in^clude "bar.h"]] +#define BAZ(X) const X x +BAZ([[Bar]]); + )cpp"}; + for (const char *Test : Tests) +checkFindRefs(Test); +} + TEST(FindReferences, NeedsIndexForSymbols) { const char *Header = "int foo();"; Annotations Main("int main() { [[f^oo]](); }"); Index: clang-tools-extra/clangd/XRefs.cpp === --- clang-tools-extra/clangd/XRefs.cpp +++ clang-tools-extra/clangd/XRefs.cpp @@ -10,12 +10,15 @@ #include "FindSymbols.h" #include "FindTarget.h" #include "HeuristicResolver.h" +#include "IncludeCleaner.h" #include "ParsedAST.h" #include "Protocol.h" #include "Quality.h" #include "Selection.h" #include "SourceCode.h" #include "URI.h" +#include "clang-include-cleaner/Analysis.h" +#include "clang-include-cleaner/Types.h" #include "index/Index.h" #include "index/Merge.h" #include "index/Relation.h" @@ -48,6 +51,7 @@ #include "clang/Index/IndexingAction.h" #include "clang/Index/IndexingOptions.h" #include "clang/Index/USRGeneration.h" +#include "clang/Lex/Lexer.h" #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/ArrayRef.h" #include