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/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>
 
@@ -2941,7 +2943,7 @@
                 )cpp"),
        "int foo();", "#include \"foo.h\"", "#include \"foo.h\"",
        [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
-       {Annotations(
+      {Annotations(
            R"cpp(
                  #include "foo.h"
 
@@ -2954,8 +2956,9 @@
           private:
             int val;
         };
-       )cpp", "", "", [](HoverInfo &HI) { HI.Provider = ""; }},
-       {Annotations(
+       )cpp",
+       "", "", [](HoverInfo &HI) { HI.Provider = ""; }},
+      {Annotations(
            R"cpp(
                 #include "bar.h"
                 
@@ -2963,20 +2966,23 @@
             )cpp"),
        R"cpp(
           int foo();
-       )cpp", "#include \"foo.h\"", "", [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
-       {Annotations(
+       )cpp",
+       "#include \"foo.h\"", "",
+       [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
+      {Annotations(
            R"cpp(
                 #include "bar.h"
             
                 int F = [[f^oo]](); 
             )cpp"),
        "int foo();",
-        R"cpp(
+       R"cpp(
           #include "foo.h"
           #include "foobar.h"
 
-        )cpp", "int foo();", [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
-        {Annotations(
+        )cpp",
+       "int foo();", [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
+      {Annotations(
            R"cpp(
                 #include "bar.h"
             
@@ -2984,18 +2990,19 @@
             )cpp"),
        R"cpp(
           #include "foobar.h"
-       )cpp", R"cpp(
+       )cpp",
+       R"cpp(
           #include "foo.h"
           #include "foobar.h"
 
-        )cpp", "int foo();", [](HoverInfo &HI) { HI.Provider = "\"foobar.h\""; }},
+        )cpp",
+       "int foo();", [](HoverInfo &HI) { HI.Provider = "\"foobar.h\""; }},
       {Annotations(
            R"cpp(
                   #include "foo.h"
                   int F = [[^MACRO]];
                 )cpp"),
-       "#define MACRO 5",
-       "", "",
+       "#define MACRO 5", "", "",
        [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
       {Annotations(
            R"cpp(
@@ -3004,8 +3011,7 @@
 
                   int F = [[M^ACRO]];
                 )cpp"),
-       "#define MACRO 5",
-       "#define MACRO 10", "",
+       "#define MACRO 5", "#define MACRO 10", "",
        [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
       {Annotations(
            R"cpp(
@@ -3014,16 +3020,14 @@
 
                   int F = [[MA^CRO]](5);
                 )cpp"),
-       "#define MACRO(X) X+1",
-       "#include \"foobar.h\"", "#define MACRO(X) X+3",
+       "#define MACRO(X) X+1", "#include \"foobar.h\"", "#define MACRO(X) X+3",
        [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
       {Annotations(
            R"cpp(
                   #include "foo.h"
                   int [[^F]] = MACRO(5);
                 )cpp"),
-       "#define MACRO(X) (X+1)",
-       "", "",
+       "#define MACRO(X) (X+1)", "", "",
        [](HoverInfo &HI) { HI.Provider = ""; }},
       {Annotations(
            R"cpp(
@@ -3032,7 +3036,7 @@
                 )cpp"),
        "#define MACRO 5", "#include \"foo.h\"", "",
        [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }},
-       {Annotations(
+      {Annotations(
            R"cpp(
                   #include "bar.h"    
                   int F = [[MACR^O]];
@@ -3040,9 +3044,9 @@
        "#define MACRO 5", R"cpp(
         #include "foo.h"
         #include "foobar.h"
-      )cpp", "#define MACRO 10",
-       [](HoverInfo &HI) { HI.Provider = "\"foobar.h\""; }},
-       {Annotations(
+      )cpp",
+       "#define MACRO 10", [](HoverInfo &HI) { HI.Provider = "\"foobar.h\""; }},
+      {Annotations(
            R"cpp(
             #include "bar.h"    
             
@@ -3051,21 +3055,21 @@
        "", R"cpp(
         // IWYU pragma: private, include "foo.h"
         int foo();
-      )cpp", "",
-       [](HoverInfo &HI) { HI.Provider = "\"bar.h\""; }},
-       {Annotations(
+      )cpp",
+       "", [](HoverInfo &HI) { HI.Provider = "\"bar.h\""; }},
+      {Annotations(
            R"cpp(
             #include "bar.h"    
             
             int F = [[fo^o]]();
           )cpp"),
        "", "#include \"foobar.h\"",
-      R"cpp(
+       R"cpp(
         // IWYU pragma: private, include "public.h"
         int foo();
       )cpp",
        [](HoverInfo &HI) { HI.Provider = "\"public.h\""; }},
-       {Annotations(
+      {Annotations(
            R"cpp(
             #include "bar.h"    
             
@@ -3075,10 +3079,10 @@
         namespace std {
           class vector {};
         }
-       )cpp", "#include \"foo.h\"",
-      "",
+       )cpp",
+       "#include \"foo.h\"", "",
        [](HoverInfo &HI) { HI.Provider = "<vector>"; }},
-       {Annotations(
+      {Annotations(
            R"cpp(
             #include "foo.h"    
             
@@ -3090,10 +3094,9 @@
        R"cpp(
         class Foo {};
         Foo& operator+(const Foo &lhs, const Foo &rhs);
-       )cpp", "#include \"foo.h\"",
-      "",
-       [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }}
-       };
+       )cpp",
+       "#include \"foo.h\"", "",
+       [](HoverInfo &HI) { HI.Provider = "\"foo.h\""; }}};
 
   for (const auto &Case : Cases) {
     SCOPED_TRACE(Case.Code.code());
@@ -3143,7 +3146,7 @@
     namespace absl {
       using std::string_view;
   })cpp";
-   llvm::StringLiteral StdHeader = R"cpp(
+  llvm::StringLiteral StdHeader = R"cpp(
     namespace std {
       class string_view {};
   })cpp";
@@ -3160,6 +3163,104 @@
   EXPECT_EQ(H->Provider, "<string_view>");
 }
 
+TEST(Hover, UsedSymbols) {
+  struct {
+    Annotations Code;
+    llvm::StringLiteral FooHeader;
+    llvm::StringLiteral BarHeader;
+    llvm::StringLiteral SystemHeader;
+    const std::function<void(HoverInfo &)> ExpectedBuilder;
+  } Cases[] = {{Annotations(R"cpp(
+      [[#inclu^de "foo.h"]]            
+      
+      int var = foo();
+    )cpp"),
+                "int foo();", "", "",
+                [](HoverInfo &HI) { HI.UsedSymbolNames = {"foo"}; }},
+               {Annotations(R"cpp(
+      [[^#include "foo.h"]]            
+      
+      int var = foo();
+    )cpp"),
+                "int foo();", "", "",
+                [](HoverInfo &HI) { HI.UsedSymbolNames = {"foo"}; }},
+               {Annotations(R"cpp(
+      [[#include "fo^o.h"]]            
+      
+      int var = foo();
+    )cpp"),
+                "int foo();", "", "",
+                [](HoverInfo &HI) { HI.UsedSymbolNames = {"foo"}; }},
+               {Annotations(R"cpp(
+      [[#include "foo.h"^]]            
+      
+      int var = foo();
+    )cpp"),
+                "int foo();", "", "",
+                [](HoverInfo &HI) { HI.UsedSymbolNames = {"foo"}; }},
+               {Annotations(R"cpp(
+      #include "foo.h"  
+      [[#incl^ude "bar.h"]]
+      
+      int var = foo();
+    )cpp"),
+                "int foo();", "int bar();", "",
+                [](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"),
+                "int foo();", "int bar(); int foobar(); class X {};", "",
+                [](HoverInfo &HI) {
+                  HI.UsedSymbolNames = {"X", "bar", "foobar"};
+                }},
+               {Annotations(R"cpp(
+            [[#in^clude <foo>]]
+
+            int fooVar = foo();
+          )cpp"),
+                "", "",
+                R"cpp(
+          int foo();
+        )cpp",
+                [](HoverInfo &HI) { HI.UsedSymbolNames = {"foo"}; }},
+               {Annotations(R"cpp(
+            [[#in^clude "bar.h"]]
+            #include "foo.h"
+
+            int fooVar = foo();
+          )cpp"),
+                R"cpp(
+          // IWYU pragma: private, include "bar.h"
+          int 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(Case.FooHeader);
+    TU.AdditionalFiles["bar.h"] = guard(Case.BarHeader);
+    TU.AdditionalFiles["system/foo"] = guard(Case.SystemHeader);
+    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(
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
@@ -253,6 +253,7 @@
   }
   return Result;
 }
+} // namespace
 
 std::vector<include_cleaner::SymbolReference>
 collectMacroReferences(ParsedAST &AST) {
@@ -274,7 +275,6 @@
   }
   return Macros;
 }
-} // namespace
 
 include_cleaner::Includes
 convertIncludes(const SourceManager &SM,
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>
 
@@ -1126,6 +1130,58 @@
   }
 }
 
+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,
@@ -1155,6 +1211,7 @@
     HI.Definition =
         URIForFile::canonicalize(Inc.Resolved, AST.tuPath()).file().str();
     HI.DefinitionLanguage = "";
+    maybeAddUsedSymbols(AST, HI, Inc);
     return HI;
   }
 
@@ -1370,6 +1427,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