VitaNuo updated this revision to Diff 506141.
VitaNuo added a comment.

Finish the test.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D146244/new/

https://reviews.llvm.org/D146244

Files:
  clang-tools-extra/clangd/Hover.cpp
  clang-tools-extra/clangd/Hover.h
  clang-tools-extra/clangd/IncludeCleaner.cpp
  clang-tools-extra/clangd/IncludeCleaner.h
  clang-tools-extra/clangd/unittests/HoverTests.cpp

Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -10,6 +10,7 @@
 #include "Annotations.h"
 #include "Config.h"
 #include "Hover.h"
+#include "TestFS.h"
 #include "TestIndex.h"
 #include "TestTU.h"
 #include "index/MemIndex.h"
@@ -20,6 +21,7 @@
 
 #include "gtest/gtest.h"
 #include <functional>
+#include <optional>
 #include <string>
 #include <vector>
 
@@ -2951,7 +2953,7 @@
     TU.AdditionalFiles["all.h"] = guard(R"cpp(
       #include "foo.h"
     )cpp");
-  
+
     auto AST = TU.build();
     auto H = getHover(AST, Case.Code.point(), format::getLLVMStyle(), nullptr);
     ASSERT_TRUE(H);
@@ -2980,6 +2982,74 @@
     EXPECT_EQ(Case.HI.present().asMarkdown(), Case.ExpectedMarkdown);
 }
 
+TEST(Hover, UsedSymbols) {
+  struct {
+    Annotations Code;
+    const std::function<void(HoverInfo &)> ExpectedBuilder;
+  } Cases[] = {{Annotations(R"cpp(
+      [[#inclu^de "foo.h"]]            
+      
+      int var = foo();
+    )cpp"),
+                [](HoverInfo &HI) { HI.UsedSymbolNames = {"foo"}; }},
+               {Annotations(R"cpp(
+      [[#incl^ude "foo.h"]]
+    )cpp"),
+                [](HoverInfo &HI) { HI.UsedSymbolNames = {}; }},
+               {Annotations(R"cpp(
+      #include "foo.h"  
+      [[#include ^"bar.h"]]
+      
+        int fooVar = foo();
+        int barVar = bar();
+        int foobarVar = foobar();
+
+        X x;
+    )cpp"),
+                [](HoverInfo &HI) {
+                  HI.UsedSymbolNames = {"X", "bar", "foobar"};
+                }},
+               {Annotations(R"cpp(
+      [[#in^clude <foo>]]
+
+        int fooVar = foo();
+      )cpp"),
+                [](HoverInfo &HI) { HI.UsedSymbolNames = {"foo"}; }},
+               {Annotations(R"cpp(
+      [[#in^clude "public.h"]]
+      #include "private.h"
+
+      int fooVar = foo();
+    )cpp"),
+                [](HoverInfo &HI) { HI.UsedSymbolNames = {"foo"}; }}
+
+  };
+  for (const auto &Case : Cases) {
+    SCOPED_TRACE(Case.Code.code());
+
+    TestTU TU;
+    TU.Filename = "foo.cpp";
+    TU.Code = Case.Code.code();
+    TU.AdditionalFiles["foo.h"] = guard("int foo();");
+    TU.AdditionalFiles["bar.h"] = guard("int bar(); int foobar(); class X {};");
+    TU.AdditionalFiles["private.h"] = guard(R"cpp(
+          // IWYU pragma: private, include "public.h"
+          int foo(); 
+       )cpp");
+     TU.AdditionalFiles["public.h"] = guard("");
+    TU.AdditionalFiles["system/foo"] = guard("int foo();");
+    TU.ExtraArgs.push_back("-isystem" + testPath("system"));
+
+    auto AST = TU.build();
+    auto H = getHover(AST, Case.Code.point(), format::getLLVMStyle(), nullptr);
+    ASSERT_TRUE(H);
+    HoverInfo Expected;
+    Case.ExpectedBuilder(Expected);
+    SCOPED_TRACE(H->present().asMarkdown());
+    EXPECT_EQ(H->UsedSymbolNames, Expected.UsedSymbolNames);
+  }
+}
+
 TEST(Hover, DocsFromIndex) {
   Annotations T(R"cpp(
   template <typename T> class X {};
Index: clang-tools-extra/clangd/IncludeCleaner.h
===================================================================
--- clang-tools-extra/clangd/IncludeCleaner.h
+++ clang-tools-extra/clangd/IncludeCleaner.h
@@ -74,6 +74,9 @@
 
 std::string spellHeader(ParsedAST &AST, const FileEntry *MainFile,
                         include_cleaner::Header Provider);
+
+std::vector<include_cleaner::SymbolReference>
+collectMacroReferences(ParsedAST &AST);
 } // namespace clangd
 } // namespace clang
 
Index: clang-tools-extra/clangd/IncludeCleaner.cpp
===================================================================
--- clang-tools-extra/clangd/IncludeCleaner.cpp
+++ clang-tools-extra/clangd/IncludeCleaner.cpp
@@ -124,27 +124,6 @@
   return true;
 }
 
-std::vector<include_cleaner::SymbolReference>
-collectMacroReferences(ParsedAST &AST) {
-  const auto &SM = AST.getSourceManager();
-  //  FIXME: !!this is a hacky way to collect macro references.
-  std::vector<include_cleaner::SymbolReference> Macros;
-  auto &PP = AST.getPreprocessor();
-  for (const syntax::Token &Tok :
-       AST.getTokens().spelledTokens(SM.getMainFileID())) {
-    auto Macro = locateMacroAt(Tok, PP);
-    if (!Macro)
-      continue;
-    if (auto DefLoc = Macro->Info->getDefinitionLoc(); DefLoc.isValid())
-      Macros.push_back(
-          {Tok.location(),
-           include_cleaner::Macro{/*Name=*/PP.getIdentifierInfo(Tok.text(SM)),
-                                  DefLoc},
-           include_cleaner::RefType::Explicit});
-  }
-  return Macros;
-}
-
 llvm::StringRef getResolvedPath(const include_cleaner::Header &SymProvider) {
   switch (SymProvider.kind()) {
   case include_cleaner::Header::Physical:
@@ -276,6 +255,28 @@
 }
 } // namespace
 
+
+std::vector<include_cleaner::SymbolReference>
+collectMacroReferences(ParsedAST &AST) {
+  const auto &SM = AST.getSourceManager();
+  //  FIXME: !!this is a hacky way to collect macro references.
+  std::vector<include_cleaner::SymbolReference> Macros;
+  auto &PP = AST.getPreprocessor();
+  for (const syntax::Token &Tok :
+       AST.getTokens().spelledTokens(SM.getMainFileID())) {
+    auto Macro = locateMacroAt(Tok, PP);
+    if (!Macro)
+      continue;
+    if (auto DefLoc = Macro->Info->getDefinitionLoc(); DefLoc.isValid())
+      Macros.push_back(
+          {Tok.location(),
+           include_cleaner::Macro{/*Name=*/PP.getIdentifierInfo(Tok.text(SM)),
+                                  DefLoc},
+           include_cleaner::RefType::Explicit});
+  }
+  return Macros;
+}
+
 include_cleaner::Includes
 convertIncludes(const SourceManager &SM,
                 const llvm::ArrayRef<Inclusion> MainFileIncludes) {
Index: clang-tools-extra/clangd/Hover.h
===================================================================
--- clang-tools-extra/clangd/Hover.h
+++ clang-tools-extra/clangd/Hover.h
@@ -15,6 +15,7 @@
 #include "clang/Index/IndexSymbol.h"
 #include <optional>
 #include <string>
+#include <vector>
 
 namespace clang {
 namespace clangd {
@@ -110,6 +111,9 @@
   };
   // Set only if CalleeArgInfo is set.
   std::optional<PassType> CallPassType;
+  // Set when hovering over the #include line. Contains the names of symbols
+  // from a #include'd file that are used in the main file.
+  std::optional<std::vector<std::string>> UsedSymbolNames;
 
   /// Produce a user-readable information.
   markup::Document present() const;
Index: clang-tools-extra/clangd/Hover.cpp
===================================================================
--- clang-tools-extra/clangd/Hover.cpp
+++ clang-tools-extra/clangd/Hover.cpp
@@ -12,6 +12,7 @@
 #include "CodeCompletionStrings.h"
 #include "Config.h"
 #include "FindTarget.h"
+#include "Headers.h"
 #include "IncludeCleaner.h"
 #include "ParsedAST.h"
 #include "Selection.h"
@@ -38,7 +39,9 @@
 #include "clang/AST/RecordLayout.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/CharInfo.h"
+#include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
 #include "clang/Basic/Specifiers.h"
 #include "clang/Basic/TokenKinds.h"
 #include "clang/Index/IndexSymbol.h"
@@ -53,6 +56,7 @@
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/Support/raw_ostream.h"
 #include <optional>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -1134,6 +1138,58 @@
   HI.Provider = spellHeader(AST, SM.getFileEntryForID(SM.getMainFileID()), H);
 }
 
+std::string getRefName(include_cleaner::SymbolReference Ref) {
+  std::string Name;
+  switch (Ref.Target.kind()) {
+  case include_cleaner::Symbol::Declaration:
+    Name = llvm::dyn_cast<NamedDecl>(&Ref.Target.declaration())
+               ->getDeclName()
+               .getAsString();
+    break;
+  case include_cleaner::Symbol::Macro:
+    Name = Ref.Target.macro().Name->getName();
+    break;
+  }
+  return Name;
+}
+
+void maybeAddUsedSymbols(ParsedAST &AST, HoverInfo &HI, const Inclusion &Inc) {
+  const SourceManager &SM = AST.getSourceManager();
+  std::set<std::string> UsedSymbolNames;
+  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 ||
+        !SM.isWrittenInMainFile(SM.getSpellingLoc(Ref.RefLocation))) {
+          return;
+        }
+
+        for (const include_cleaner::Header &H : Providers) {
+          switch (H.kind()) {
+          case include_cleaner::Header::Physical:
+            if (Inc.Resolved == H.physical()->tryGetRealPathName()) 
+              UsedSymbolNames.insert(getRefName(Ref));
+            break;
+          case include_cleaner::Header::Standard:
+            if (Inc.Written == H.standard().name())
+              UsedSymbolNames.insert(getRefName(Ref));
+            break;
+          case include_cleaner::Header::Verbatim:
+            if (Inc.Written == H.verbatim())
+              UsedSymbolNames.insert(getRefName(Ref));
+            break;
+          }
+        }
+      });
+
+  if (!UsedSymbolNames.empty())
+    HI.UsedSymbolNames = std::optional<std::vector<std::string>>{
+        {UsedSymbolNames.begin(), UsedSymbolNames.end()}};
+}
+
 } // namespace
 
 std::optional<HoverInfo> getHover(ParsedAST &AST, Position Pos,
@@ -1163,6 +1219,7 @@
     HI.Definition =
         URIForFile::canonicalize(Inc.Resolved, AST.tuPath()).file().str();
     HI.DefinitionLanguage = "";
+    maybeAddUsedSymbols(AST, HI, Inc);
     return HI;
   }
 
@@ -1378,6 +1435,24 @@
     Output.addCodeBlock(Buffer, DefinitionLanguage);
   }
 
+  if (UsedSymbolNames) {
+    Output.addRuler();
+    markup::Paragraph &P = Output.addParagraph();
+    P.appendText("provides ");
+
+    for (unsigned I = 0; I < UsedSymbolNames->size() - 1 && I < 4; I++) {
+      P.appendCode((*UsedSymbolNames)[I]);
+      P.appendText(", ");
+    }
+
+    P.appendCode((*UsedSymbolNames)[UsedSymbolNames->size() - 1]);
+    if (UsedSymbolNames->size() > 5) {
+      P.appendText(" and ");
+      P.appendText(std::to_string(UsedSymbolNames->size() - 5));
+      P.appendText(" more");
+    }
+  }
+
   return Output;
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to