daiyousei-qz created this revision.
daiyousei-qz added reviewers: nridge, sammccall.
Herald added subscribers: usaxena95, kadircet, arphaman.
Herald added a project: All.
daiyousei-qz requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

This patch adds macro expansion preview to hover info. Basically, the refactor 
infrastructure for expanding macro is used for this purpose. The following 
steps are added to getHoverContents for macros:

1. calling AST.getTokens().expansionStartingAt(...) to get expanded tokens
2. calling reformat(...) to format expanded tokens

Some opinions are wanted:

1. Should we present macro expansion before definition in the hover card?
2. Should we truncate/ignore macro expansion if it's too long?

Also, some limitation applies:

1. Expansion isn't available in macro definition/arguments as the refactor code 
action isn't either.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D127082

Files:
  clang-tools-extra/clangd/Hover.cpp
  clang-tools-extra/clangd/Hover.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
@@ -478,15 +478,46 @@
          HI.Definition = "Foo<int>";
        }},
 
-      // macro
+      // variable-like macro
+      {R"cpp(
+        #define MACRO 41
+        int x = [[MAC^RO]];
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "MACRO";
+         HI.Kind = index::SymbolKind::Macro;
+         HI.Definition = "#define MACRO 41";
+         HI.MacroExpansion = "41";
+       }},
+
+      // function-like macro
       {R"cpp(
         // Best MACRO ever.
-        #define MACRO(x,y,z) void foo(x, y, z);
+        #define MACRO(x,y,z) void foo(x, y, z)
         [[MAC^RO]](int, double d, bool z = false);
         )cpp",
        [](HoverInfo &HI) {
-         HI.Name = "MACRO", HI.Kind = index::SymbolKind::Macro,
-         HI.Definition = "#define MACRO(x, y, z) void foo(x, y, z);";
+         HI.Name = "MACRO";
+         HI.Kind = index::SymbolKind::Macro;
+         HI.Definition = "#define MACRO(x, y, z) void foo(x, y, z)";
+         HI.MacroExpansion = "void foo(int, double d, bool z = false)";
+       }},
+
+      // nested macro
+      {R"cpp(
+        #define STRINGIFY_AUX(s) #s
+        #define STRINGIFY(s) STRINGIFY_AUX(s)
+        #define DECL_STR(NAME, VALUE) const char *v_##NAME = STRINGIFY(VALUE)
+        #define FOO 41
+
+        [[DECL^_STR]](foo, FOO);
+        )cpp",
+       [](HoverInfo &HI) {
+         HI.Name = "DECL_STR";
+         HI.Kind = index::SymbolKind::Macro;
+         HI.Definition = "#define DECL_STR(NAME, VALUE) const char *v_##NAME = "
+                         "STRINGIFY(VALUE)";
+         HI.MacroExpansion = "const char *v_foo = \"41\"";
        }},
 
       // constexprs
@@ -1070,6 +1101,7 @@
     EXPECT_EQ(H->Kind, Expected.Kind);
     EXPECT_EQ(H->Documentation, Expected.Documentation);
     EXPECT_EQ(H->Definition, Expected.Definition);
+    EXPECT_EQ(H->MacroExpansion, Expected.MacroExpansion);
     EXPECT_EQ(H->Type, Expected.Type);
     EXPECT_EQ(H->ReturnType, Expected.ReturnType);
     EXPECT_EQ(H->Parameters, Expected.Parameters);
@@ -1567,6 +1599,7 @@
             HI.Name = "MACRO";
             HI.Kind = index::SymbolKind::Macro;
             HI.Definition = "#define MACRO 0";
+            HI.MacroExpansion = "0";
           }},
       {
           R"cpp(// Macro
@@ -1577,6 +1610,8 @@
             HI.Name = "MACRO";
             HI.Kind = index::SymbolKind::Macro;
             HI.Definition = "#define MACRO 0";
+            // FIXME: expansion of MACRO isn't available in macro
+            // definition/arguments
           }},
       {
           R"cpp(// Macro
@@ -1591,6 +1626,7 @@
             HI.Definition =
                 R"cpp(#define MACRO                                                                  \
   { return 0; })cpp";
+            HI.MacroExpansion = "{ return 0; }";
           }},
       {
           R"cpp(// Forward class declaration
@@ -2625,6 +2661,7 @@
     EXPECT_EQ(H->Kind, Expected.Kind);
     EXPECT_EQ(H->Documentation, Expected.Documentation);
     EXPECT_EQ(H->Definition, Expected.Definition);
+    EXPECT_EQ(H->MacroExpansion, Expected.MacroExpansion);
     EXPECT_EQ(H->Type, Expected.Type);
     EXPECT_EQ(H->ReturnType, Expected.ReturnType);
     EXPECT_EQ(H->Parameters, Expected.Parameters);
Index: clang-tools-extra/clangd/Hover.h
===================================================================
--- clang-tools-extra/clangd/Hover.h
+++ clang-tools-extra/clangd/Hover.h
@@ -71,6 +71,7 @@
   std::string Documentation;
   /// Source code containing the definition of the symbol.
   std::string Definition;
+  std::string MacroExpansion;
   const char *DefinitionLanguage = "cpp";
   /// Access specifier for declarations inside class/struct/unions, empty for
   /// others.
Index: clang-tools-extra/clangd/Hover.cpp
===================================================================
--- clang-tools-extra/clangd/Hover.cpp
+++ clang-tools-extra/clangd/Hover.cpp
@@ -643,7 +643,8 @@
 }
 
 /// Generate a \p Hover object given the macro \p MacroDecl.
-HoverInfo getHoverContents(const DefinedMacro &Macro, ParsedAST &AST) {
+HoverInfo getHoverContents(const clang::syntax::Token &Tok,
+                           const DefinedMacro &Macro, ParsedAST &AST) {
   HoverInfo HI;
   SourceManager &SM = AST.getSourceManager();
   HI.Name = std::string(Macro.Name);
@@ -672,6 +673,18 @@
         HI.Definition =
             ("#define " + Buffer.substr(StartOffset, EndOffset - StartOffset))
                 .str();
+
+      auto Expansion = AST.getTokens().expansionStartingAt(&Tok);
+      if (Expansion) {
+        // TODO: Limit size of expansion
+        std::string ExpansionTextBuffer;
+        for (const auto &ExpandedTok : Expansion->Expanded) {
+          ExpansionTextBuffer += ExpandedTok.text(SM);
+          ExpansionTextBuffer += " ";
+        }
+
+        HI.MacroExpansion = std::move(ExpansionTextBuffer);
+      }
     }
   }
   return HI;
@@ -1006,7 +1019,7 @@
       // Prefer the identifier token as a fallback highlighting range.
       HighlightRange = Tok.range(SM).toCharRange(SM);
       if (auto M = locateMacroAt(Tok, AST.getPreprocessor())) {
-        HI = getHoverContents(*M, AST);
+        HI = getHoverContents(Tok, *M, AST);
         break;
       }
     } else if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
@@ -1057,11 +1070,25 @@
   if (!HI)
     return llvm::None;
 
-  auto Replacements = format::reformat(
-      Style, HI->Definition, tooling::Range(0, HI->Definition.size()));
-  if (auto Formatted =
-          tooling::applyAllReplacements(HI->Definition, Replacements))
-    HI->Definition = *Formatted;
+  // Reformat Definition
+  if (!HI->Definition.empty()) {
+    auto Replacements = format::reformat(
+        Style, HI->Definition, tooling::Range(0, HI->Definition.size()));
+    if (auto Formatted =
+            tooling::applyAllReplacements(HI->Definition, Replacements))
+      HI->Definition = *Formatted;
+  }
+
+  // Reformat Macro Expansion
+  if (!HI->MacroExpansion.empty()) {
+    auto Replacements =
+        format::reformat(Style, HI->MacroExpansion,
+                         tooling::Range(0, HI->MacroExpansion.size()));
+    if (auto Formatted =
+            tooling::applyAllReplacements(HI->MacroExpansion, Replacements))
+      HI->MacroExpansion = *Formatted;
+  }
+
   HI->DefinitionLanguage = getMarkdownLanguage(AST.getASTContext());
   HI->SymRange = halfOpenToRange(SM, HighlightRange);
 
@@ -1177,6 +1204,12 @@
                         DefinitionLanguage);
   }
 
+  if (!MacroExpansion.empty()) {
+    Output.addRuler();
+    Output.addParagraph().appendText("Macro Expansion:");
+    Output.addCodeBlock(MacroExpansion, DefinitionLanguage);
+  }
+
   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