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 <vector> + int fstBar = [[bar1]](); + int sndBar = [[bar2]](); + [[Bar]] bar; + int macroBar = [[BAR]]; + std::vector<int> vec; + )cpp", + + R"cpp([[#in^clude <vector>]] + std::[[vector]]<int> 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<typename> + class vector{}; + } + )cpp"); + TU.ExtraArgs.push_back("-isystem" + testPath("system")); + + auto AST = TU.build(); + std::vector<Matcher<ReferencesResult::Reference>> ExpectedLocations; + for (const auto &R : T.ranges()) + ExpectedLocations.push_back(AllOf(rangeIs(R), attrsAre(0u))); + for (const auto &P : 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 <optional> +#include <string> #include <vector> namespace clang { @@ -1312,6 +1317,63 @@ } } // namespace +ReferencesResult maybeFindIncludeReferences(ParsedAST &AST, Position Pos, + URIForFile URIMainFile) { + ReferencesResult Results; + const SourceManager &SM = AST.getSourceManager(); + auto Includes = AST.getIncludeStructure().MainFileIncludes; + auto ConvertedMainFileIncludes = convertIncludes(SM, Includes); + for (auto &Inc : 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 &Ref, + llvm::ArrayRef<include_cleaner::Header> 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)); + + ReferencesResult::Reference Result; + const auto *Token = AST.getTokens().spelledTokenAt(Loc); + Result.Loc.range = + Range{sourceLocToPosition(SM, Token->location()), + sourceLocToPosition(SM, Token->endLocation())}; + Result.Loc.uri = URIMainFile; + Results.References.push_back(std::move(Result)); + }); + if (Results.References.empty()) + return {}; + + // Add the #include line to the references list. + auto IncludeLen = + std::string{"#include"}.length() + Inc.Written.length() + 1; + ReferencesResult::Reference Result; + Result.Loc.range = clangd::Range{Position{Inc.HashLine, 0}, + Position{Inc.HashLine, (int)IncludeLen}}; + Result.Loc.uri = URIMainFile; + Results.References.push_back(std::move(Result)); + } + return Results; +} + ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, const SymbolIndex *Index, bool AddContext) { ReferencesResult Results; @@ -1324,6 +1386,10 @@ return {}; } + Results = maybeFindIncludeReferences(AST, Pos, URIMainFile); + if (!Results.References.empty()) + return Results; + llvm::DenseSet<SymbolID> IDsToQuery, OverriddenMethods; const auto *IdentifierAtCursor = @@ -1952,7 +2018,7 @@ return; // If there's a specific type alias, point at that rather than unwrapping. - if (const auto* TDT = T->getAs<TypedefType>()) + if (const auto *TDT = T->getAs<TypedefType>()) return Out.push_back(QualType(TDT, 0)); // Pointers etc => pointee type. @@ -1991,7 +2057,6 @@ return Result; } - std::vector<LocatedSymbol> findType(ParsedAST &AST, Position Pos) { const SourceManager &SM = AST.getSourceManager(); auto Offset = positionToOffset(SM.getBufferData(SM.getMainFileID()), Pos); Index: clang-tools-extra/clangd/IncludeCleaner.h =================================================================== --- clang-tools-extra/clangd/IncludeCleaner.h +++ clang-tools-extra/clangd/IncludeCleaner.h @@ -81,6 +81,11 @@ std::vector<include_cleaner::SymbolReference> collectMacroReferences(ParsedAST &AST); + +/// Find the first provider in the list that is matched by the includes. +std::optional<include_cleaner::Header> +firstSatisfiedProvider(const include_cleaner::Includes &Includes, + llvm::ArrayRef<include_cleaner::Header> Providers); } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/IncludeCleaner.cpp =================================================================== --- clang-tools-extra/clangd/IncludeCleaner.cpp +++ clang-tools-extra/clangd/IncludeCleaner.cpp @@ -432,5 +432,16 @@ return Result; } +std::optional<include_cleaner::Header> +firstSatisfiedProvider(const include_cleaner::Includes &Includes, + llvm::ArrayRef<include_cleaner::Header> Providers) { + for (const auto &H : Providers) { + auto MatchingIncludes = Includes.match(H); + if (!MatchingIncludes.empty()) + return H; + } + // No match for this provider in the includes list. + return {}; +} } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/Hover.cpp =================================================================== --- clang-tools-extra/clangd/Hover.cpp +++ clang-tools-extra/clangd/Hover.cpp @@ -1172,20 +1172,16 @@ UsedSymbols.find(Ref.Target) != UsedSymbols.end()) return; - for (const include_cleaner::Header &H : Providers) { - auto MatchingIncludes = ConvertedMainFileIncludes.match(H); - // No match for this provider in the main file. - if (MatchingIncludes.empty()) - continue; - - // Check if the hovered include matches this provider. - if (!HoveredInclude.match(H).empty()) - UsedSymbols.insert(Ref.Target); - - // Don't look for rest of the providers once we've found a match - // in the main file. - break; - } + auto Provider = + firstSatisfiedProvider(ConvertedMainFileIncludes, Providers); + if (!Provider) + return; + + // Check if the hovered include matches this provider. + if (HoveredInclude.match(*Provider).empty()) + return; + + UsedSymbols.insert(Ref.Target); }); for (const auto &UsedSymbolDecl : UsedSymbols)
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits