ilya-biryukov created this revision.
ilya-biryukov added a reviewer: sammccall.
Herald added subscribers: kadircet, arphaman, jkorous, MaskRay.
Herald added a project: clang.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D61601

Files:
  clang-tools-extra/clangd/ClangdLSPServer.cpp
  clang-tools-extra/clangd/ClangdLSPServer.h
  clang-tools-extra/clangd/ClangdServer.cpp
  clang-tools-extra/clangd/ClangdServer.h
  clang-tools-extra/clangd/FormattedString.cpp
  clang-tools-extra/clangd/FormattedString.h
  clang-tools-extra/clangd/Protocol.cpp
  clang-tools-extra/clangd/Protocol.h
  clang-tools-extra/clangd/XRefs.cpp
  clang-tools-extra/clangd/XRefs.h
  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
@@ -580,7 +580,10 @@
               int test1 = bonjour;
             }
           )cpp",
-          "Declared in function main\n\nint bonjour",
+          "text[Declared in]code[function main]\n"
+          "codeblock(cpp) [\n"
+          "int bonjour\n"
+          "]",
       },
       {
           R"cpp(// Local variable in method
@@ -591,7 +594,10 @@
               }
             };
           )cpp",
-          "Declared in function s::method\n\nint bonjour",
+          "text[Declared in]code[function s::method]\n"
+          "codeblock(cpp) [\n"
+          "int bonjour\n"
+          "]",
       },
       {
           R"cpp(// Struct
@@ -602,7 +608,10 @@
               ns1::My^Class* Params;
             }
           )cpp",
-          "Declared in namespace ns1\n\nstruct MyClass {}",
+          "text[Declared in]code[namespace ns1]\n"
+          "codeblock(cpp) [\n"
+          "struct MyClass {}\n"
+          "]",
       },
       {
           R"cpp(// Class
@@ -613,7 +622,10 @@
               ns1::My^Class* Params;
             }
           )cpp",
-          "Declared in namespace ns1\n\nclass MyClass {}",
+          "text[Declared in]code[namespace ns1]\n"
+          "codeblock(cpp) [\n"
+          "class MyClass {}\n"
+          "]",
       },
       {
           R"cpp(// Union
@@ -624,7 +636,10 @@
               ns1::My^Union Params;
             }
           )cpp",
-          "Declared in namespace ns1\n\nunion MyUnion {}",
+          "text[Declared in]code[namespace ns1]\n"
+          "codeblock(cpp) [\n"
+          "union MyUnion {}\n"
+          "]",
       },
       {
           R"cpp(// Function definition via pointer
@@ -633,7 +648,10 @@
               auto *X = &^foo;
             }
           )cpp",
-          "Declared in global namespace\n\nint foo(int)",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "int foo(int)\n"
+          "]",
       },
       {
           R"cpp(// Function declaration via call
@@ -642,7 +660,10 @@
               return ^foo(42);
             }
           )cpp",
-          "Declared in global namespace\n\nint foo(int)",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "int foo(int)\n"
+          "]",
       },
       {
           R"cpp(// Field
@@ -652,7 +673,10 @@
               bar.^x;
             }
           )cpp",
-          "Declared in struct Foo\n\nint x",
+          "text[Declared in]code[struct Foo]\n"
+          "codeblock(cpp) [\n"
+          "int x\n"
+          "]",
       },
       {
           R"cpp(// Field with initialization
@@ -662,7 +686,10 @@
               bar.^x;
             }
           )cpp",
-          "Declared in struct Foo\n\nint x = 5",
+          "text[Declared in]code[struct Foo]\n"
+          "codeblock(cpp) [\n"
+          "int x = 5\n"
+          "]",
       },
       {
           R"cpp(// Static field
@@ -671,7 +698,10 @@
               Foo::^x;
             }
           )cpp",
-          "Declared in struct Foo\n\nstatic int x",
+          "text[Declared in]code[struct Foo]\n"
+          "codeblock(cpp) [\n"
+          "static int x\n"
+          "]",
       },
       {
           R"cpp(// Field, member initializer
@@ -680,7 +710,10 @@
               Foo() : ^x(0) {}
             };
           )cpp",
-          "Declared in struct Foo\n\nint x",
+          "text[Declared in]code[struct Foo]\n"
+          "codeblock(cpp) [\n"
+          "int x\n"
+          "]",
       },
       {
           R"cpp(// Field, GNU old-style field designator
@@ -689,7 +722,10 @@
               Foo bar = { ^x : 1 };
             }
           )cpp",
-          "Declared in struct Foo\n\nint x",
+          "text[Declared in]code[struct Foo]\n"
+          "codeblock(cpp) [\n"
+          "int x\n"
+          "]",
       },
       {
           R"cpp(// Field, field designator
@@ -698,7 +734,10 @@
               Foo bar = { .^x = 2 };
             }
           )cpp",
-          "Declared in struct Foo\n\nint x",
+          "text[Declared in]code[struct Foo]\n"
+          "codeblock(cpp) [\n"
+          "int x\n"
+          "]",
       },
       {
           R"cpp(// Method call
@@ -708,7 +747,10 @@
               bar.^x();
             }
           )cpp",
-          "Declared in struct Foo\n\nint x()",
+          "text[Declared in]code[struct Foo]\n"
+          "codeblock(cpp) [\n"
+          "int x()\n"
+          "]",
       },
       {
           R"cpp(// Static method call
@@ -717,7 +759,10 @@
               Foo::^x();
             }
           )cpp",
-          "Declared in struct Foo\n\nstatic int x()",
+          "text[Declared in]code[struct Foo]\n"
+          "codeblock(cpp) [\n"
+          "static int x()\n"
+          "]",
       },
       {
           R"cpp(// Typedef
@@ -726,7 +771,10 @@
               ^Foo bar;
             }
           )cpp",
-          "Declared in global namespace\n\ntypedef int Foo",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "typedef int Foo\n"
+          "]",
       },
       {
           R"cpp(// Namespace
@@ -735,7 +783,10 @@
             } // namespace ns
             int main() { ^ns::Foo::bar(); }
           )cpp",
-          "Declared in global namespace\n\nnamespace ns {\n}",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "namespace ns {\n}\n"
+          "]",
       },
       {
           R"cpp(// Anonymous namespace
@@ -746,7 +797,10 @@
             } // namespace ns
             int main() { ns::f^oo++; }
           )cpp",
-          "Declared in namespace ns::(anonymous)\n\nint foo",
+          "text[Declared in]code[namespace ns::(anonymous)]\n"
+          "codeblock(cpp) [\n"
+          "int foo\n"
+          "]",
       },
       {
           R"cpp(// Macro
@@ -756,14 +810,18 @@
             #define MACRO 2
             #undef macro
           )cpp",
-          "#define MACRO 1",
+          "codeblock(cpp) [\n"
+          "#define MACRO 1\n"
+          "]",
       },
       {
           R"cpp(// Macro
             #define MACRO 0
             #define MACRO2 ^MACRO
           )cpp",
-          "#define MACRO 0",
+          "codeblock(cpp) [\n"
+          "#define MACRO 0\n"
+          "]",
       },
       {
           R"cpp(// Macro
@@ -772,9 +830,11 @@
             }
             int main() ^MACRO
           )cpp",
-          R"cpp(#define MACRO {\
+          R"cpp(codeblock(cpp) [
+#define MACRO {\
               return 0;\
-            })cpp",
+            }
+])cpp",
       },
       {
           R"cpp(// Forward class declaration
@@ -782,7 +842,10 @@
             class Foo {};
             F^oo* foo();
           )cpp",
-          "Declared in global namespace\n\nclass Foo {}",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "class Foo {}\n"
+          "]",
       },
       {
           R"cpp(// Function declaration
@@ -790,7 +853,10 @@
             void g() { f^oo(); }
             void foo() {}
           )cpp",
-          "Declared in global namespace\n\nvoid foo()",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "void foo()\n"
+          "]",
       },
       {
           R"cpp(// Enum declaration
@@ -801,7 +867,10 @@
               Hel^lo hello = ONE;
             }
           )cpp",
-          "Declared in global namespace\n\nenum Hello {\n}",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "enum Hello {\n}\n"
+          "]",
       },
       {
           R"cpp(// Enumerator
@@ -812,7 +881,10 @@
               Hello hello = O^NE;
             }
           )cpp",
-          "Declared in enum Hello\n\nONE",
+          "text[Declared in]code[enum Hello]\n"
+          "codeblock(cpp) [\n"
+          "ONE\n"
+          "]",
       },
       {
           R"cpp(// Enumerator in anonymous enum
@@ -823,7 +895,10 @@
               int hello = O^NE;
             }
           )cpp",
-          "Declared in enum (anonymous)\n\nONE",
+          "text[Declared in]code[enum (anonymous)]\n"
+          "codeblock(cpp) [\n"
+          "ONE\n"
+          "]",
       },
       {
           R"cpp(// Global variable
@@ -832,7 +907,10 @@
               he^y++;
             }
           )cpp",
-          "Declared in global namespace\n\nstatic int hey = 10",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "static int hey = 10\n"
+          "]",
       },
       {
           R"cpp(// Global variable in namespace
@@ -843,7 +921,10 @@
               ns1::he^y++;
             }
           )cpp",
-          "Declared in namespace ns1\n\nstatic int hey = 10",
+          "text[Declared in]code[namespace ns1]\n"
+          "codeblock(cpp) [\n"
+          "static int hey = 10\n"
+          "]",
       },
       {
           R"cpp(// Field in anonymous struct
@@ -854,7 +935,10 @@
               s.he^llo++;
             }
           )cpp",
-          "Declared in struct (anonymous)\n\nint hello",
+          "text[Declared in]code[struct (anonymous)]\n"
+          "codeblock(cpp) [\n"
+          "int hello\n"
+          "]",
       },
       {
           R"cpp(// Templated function
@@ -864,7 +948,10 @@
             }
             void g() { auto x = f^oo<int>(); }
           )cpp",
-          "Declared in global namespace\n\ntemplate <typename T> T foo()",
+          "text[Declared in]code[global namespace]\n"
+          "codeblock(cpp) [\n"
+          "template <typename T> T foo()\n"
+          "]",
       },
       {
           R"cpp(// Anonymous union
@@ -875,7 +962,10 @@
             };
             void g() { struct outer o; o.v.d^ef++; }
           )cpp",
-          "Declared in union outer::(anonymous)\n\nint def",
+          "text[Declared in]code[union outer::(anonymous)]\n"
+          "codeblock(cpp) [\n"
+          "int def\n"
+          "]",
       },
       {
           R"cpp(// Nothing
@@ -891,7 +981,9 @@
               ^auto i = 1;
             }
           )cpp",
-          "int",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
       },
       {
           R"cpp(// Simple initialization with const auto
@@ -899,7 +991,9 @@
               const ^auto i = 1;
             }
           )cpp",
-          "int",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
       },
       {
           R"cpp(// Simple initialization with const auto&
@@ -907,7 +1001,9 @@
               const ^auto& i = 1;
             }
           )cpp",
-          "int",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
       },
       {
           R"cpp(// Simple initialization with auto&
@@ -915,7 +1011,9 @@
               ^auto& i = 1;
             }
           )cpp",
-          "int",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
       },
       {
           R"cpp(// Simple initialization with auto*
@@ -924,7 +1022,9 @@
               ^auto* i = &a;
             }
           )cpp",
-          "int",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
       },
       {
           R"cpp(// Auto with initializer list.
@@ -937,7 +1037,9 @@
               ^auto i = {1,2};
             }
           )cpp",
-          "class std::initializer_list<int>",
+          "codeblock(cpp) [\n"
+          "class std::initializer_list<int>\n"
+          "]",
       },
       {
           R"cpp(// User defined conversion to auto
@@ -945,7 +1047,9 @@
               operator ^auto() const { return 10; }
             };
           )cpp",
-          "int",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
       },
       {
           R"cpp(// Simple initialization with decltype(auto)
@@ -953,7 +1057,9 @@
               ^decltype(auto) i = 1;
             }
           )cpp",
-          "int",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
       },
       {
           R"cpp(// Simple initialization with const decltype(auto)
@@ -962,7 +1068,9 @@
               ^decltype(auto) i = j;
             }
           )cpp",
-          "const int",
+          "codeblock(cpp) [\n"
+          "const int\n"
+          "]",
       },
       {
           R"cpp(// Simple initialization with const& decltype(auto)
@@ -972,7 +1080,9 @@
               ^decltype(auto) i = j;
             }
           )cpp",
-          "const int &",
+          "codeblock(cpp) [\n"
+          "const int &\n"
+          "]",
       },
       {
           R"cpp(// Simple initialization with & decltype(auto)
@@ -982,7 +1092,9 @@
               ^decltype(auto) i = j;
             }
           )cpp",
-          "int &",
+          "codeblock(cpp) [\n"
+          "int &\n"
+          "]",
       },
       {
           R"cpp(// decltype with initializer list: nothing
@@ -1003,7 +1115,9 @@
               return 0;
             }
           )cpp",
-          "int",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
       },
       {
           R"cpp(// auto function return with trailing type
@@ -1012,7 +1126,9 @@
               return Bar();
             }
           )cpp",
-          "struct Bar",
+          "codeblock(cpp) [\n"
+          "struct Bar\n"
+          "]",
       },
       {
           R"cpp(// trailing return type
@@ -1021,7 +1137,9 @@
               return Bar();
             }
           )cpp",
-          "struct Bar",
+          "codeblock(cpp) [\n"
+          "struct Bar\n"
+          "]",
       },
       {
           R"cpp(// auto in function return
@@ -1030,7 +1148,9 @@
               return Bar();
             }
           )cpp",
-          "struct Bar",
+          "codeblock(cpp) [\n"
+          "struct Bar\n"
+          "]",
       },
       {
           R"cpp(// auto& in function return
@@ -1039,7 +1159,9 @@
               return Bar();
             }
           )cpp",
-          "struct Bar",
+          "codeblock(cpp) [\n"
+          "struct Bar\n"
+          "]",
       },
       {
           R"cpp(// auto* in function return
@@ -1049,7 +1171,9 @@
               return bar;
             }
           )cpp",
-          "struct Bar",
+          "codeblock(cpp) [\n"
+          "struct Bar\n"
+          "]",
       },
       {
           R"cpp(// const auto& in function return
@@ -1058,7 +1182,9 @@
               return Bar();
             }
           )cpp",
-          "struct Bar",
+          "codeblock(cpp) [\n"
+          "struct Bar\n"
+          "]",
       },
       {
           R"cpp(// decltype(auto) in function return
@@ -1067,7 +1193,9 @@
               return Bar();
             }
           )cpp",
-          "struct Bar",
+          "codeblock(cpp) [\n"
+          "struct Bar\n"
+          "]",
       },
       {
           R"cpp(// decltype(auto) reference in function return
@@ -1077,7 +1205,9 @@
               return (a);
             }
           )cpp",
-          "int &",
+          "codeblock(cpp) [\n"
+          "int &\n"
+          "]",
       },
       {
           R"cpp(// decltype lvalue reference
@@ -1086,7 +1216,9 @@
               ^decltype(I) J = I;
             }
           )cpp",
-          "int",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
       },
       {
           R"cpp(// decltype lvalue reference
@@ -1096,7 +1228,9 @@
               ^decltype(K) J = I;
             }
           )cpp",
-          "int &",
+          "codeblock(cpp) [\n"
+          "int &\n"
+          "]",
       },
       {
           R"cpp(// decltype lvalue reference parenthesis
@@ -1105,7 +1239,9 @@
               ^decltype((I)) J = I;
             }
           )cpp",
-          "int &",
+          "codeblock(cpp) [\n"
+          "int &\n"
+          "]",
       },
       {
           R"cpp(// decltype rvalue reference
@@ -1114,7 +1250,9 @@
               ^decltype(static_cast<int&&>(I)) J = static_cast<int&&>(I);
             }
           )cpp",
-          "int &&",
+          "codeblock(cpp) [\n"
+          "int &&\n"
+          "]",
       },
       {
           R"cpp(// decltype rvalue reference function call
@@ -1124,7 +1262,9 @@
               ^decltype(bar()) J = bar();
             }
           )cpp",
-          "int &&",
+          "codeblock(cpp) [\n"
+          "int &&\n"
+          "]",
       },
       {
           R"cpp(// decltype of function with trailing return type.
@@ -1136,7 +1276,9 @@
               ^decltype(test()) i = test();
             }
           )cpp",
-          "struct Bar",
+          "codeblock(cpp) [\n"
+          "struct Bar\n"
+          "]",
       },
       {
           R"cpp(// decltype of var with decltype.
@@ -1146,7 +1288,9 @@
               ^decltype(J) K = J;
             }
           )cpp",
-          "int",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
       },
       {
           R"cpp(// structured binding. Not supported yet
@@ -1174,7 +1318,9 @@
             int bar();
             ^auto (*foo)() = bar;
           )cpp",
-          "int",
+          "codeblock(cpp) [\n"
+          "int\n"
+          "]",
       },
   };
 
@@ -1185,7 +1331,8 @@
     auto AST = TU.build();
     if (auto H = getHover(AST, T.point())) {
       EXPECT_NE("", Test.ExpectedHover) << Test.Input;
-      EXPECT_EQ(H->contents.value, Test.ExpectedHover.str()) << Test.Input;
+      EXPECT_EQ(H->Content.renderForTests(), Test.ExpectedHover.str())
+          << Test.Input;
     } else
       EXPECT_EQ("", Test.ExpectedHover.str()) << Test.Input;
   }
Index: clang-tools-extra/clangd/XRefs.h
===================================================================
--- clang-tools-extra/clangd/XRefs.h
+++ clang-tools-extra/clangd/XRefs.h
@@ -14,6 +14,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_XREFS_H
 
 #include "ClangdUnit.h"
+#include "FormattedString.h"
 #include "Protocol.h"
 #include "index/Index.h"
 #include "llvm/ADT/Optional.h"
@@ -46,8 +47,12 @@
 std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
                                                       Position Pos);
 
+struct HoverInfo {
+  FormattedString Content;
+  llvm::Optional<Range> Range;
+};
 /// Get the hover information when hovering at \p Pos.
-llvm::Optional<Hover> getHover(ParsedAST &AST, Position Pos);
+llvm::Optional<HoverInfo> getHover(ParsedAST &AST, Position Pos);
 
 /// Returns reference locations of the symbol at a specified \p Pos.
 /// \p Limit limits the number of results returned (0 means no limit).
Index: clang-tools-extra/clangd/XRefs.cpp
===================================================================
--- clang-tools-extra/clangd/XRefs.cpp
+++ clang-tools-extra/clangd/XRefs.cpp
@@ -8,6 +8,7 @@
 #include "XRefs.h"
 #include "AST.h"
 #include "FindSymbols.h"
+#include "FormattedString.h"
 #include "Logger.h"
 #include "SourceCode.h"
 #include "URI.h"
@@ -526,17 +527,16 @@
 }
 
 /// Generate a \p Hover object given the declaration \p D.
-static Hover getHoverContents(const Decl *D) {
-  Hover H;
+static FormattedString getHoverContents(const Decl *D) {
+  FormattedString R;
   llvm::Optional<std::string> NamedScope = getScopeName(D);
 
   // Generate the "Declared in" section.
   if (NamedScope) {
     assert(!NamedScope->empty());
 
-    H.contents.value += "Declared in ";
-    H.contents.value += *NamedScope;
-    H.contents.value += "\n\n";
+    R.appendText("Declared in");
+    R.appendInlineCode(*NamedScope);
   }
 
   // We want to include the template in the Hover.
@@ -548,29 +548,26 @@
 
   PrintingPolicy Policy =
       printingPolicyForDecls(D->getASTContext().getPrintingPolicy());
-
   D->print(OS, Policy);
 
-  OS.flush();
-
-  H.contents.value += DeclText;
-  return H;
+  R.appendCodeBlock(OS.str());
+  return R;
 }
 
 /// Generate a \p Hover object given the type \p T.
-static Hover getHoverContents(QualType T, ASTContext &ASTCtx) {
-  Hover H;
-  std::string TypeText;
-  llvm::raw_string_ostream OS(TypeText);
+static FormattedString getHoverContents(QualType T, ASTContext &ASTCtx) {
+  std::string Code;
+  llvm::raw_string_ostream OS(Code);
   PrintingPolicy Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy());
   T.print(OS, Policy);
-  OS.flush();
-  H.contents.value += TypeText;
-  return H;
+
+  FormattedString R;
+  R.appendCodeBlock(OS.str());
+  return R;
 }
 
 /// Generate a \p Hover object given the macro \p MacroDecl.
-static Hover getHoverContents(MacroDecl Decl, ParsedAST &AST) {
+static FormattedString getHoverContents(MacroDecl Decl, ParsedAST &AST) {
   SourceManager &SM = AST.getASTContext().getSourceManager();
   std::string Definition = Decl.Name;
 
@@ -590,10 +587,9 @@
     }
   }
 
-  Hover H;
-  H.contents.kind = MarkupKind::PlainText;
-  H.contents.value = "#define " + Definition;
-  return H;
+  FormattedString S;
+  S.appendCodeBlock("#define " + std::move(Definition));
+  return S;
 }
 
 namespace {
@@ -708,22 +704,31 @@
   return V.getDeducedType();
 }
 
-llvm::Optional<Hover> getHover(ParsedAST &AST, Position Pos) {
+llvm::Optional<HoverInfo> getHover(ParsedAST &AST, Position Pos) {
   const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
   SourceLocation SourceLocationBeg =
       getBeginningOfIdentifier(AST, Pos, SourceMgr.getMainFileID());
   // Identified symbols at a specific position.
   auto Symbols = getSymbolAtPosition(AST, SourceLocationBeg);
 
-  if (!Symbols.Macros.empty())
-    return getHoverContents(Symbols.Macros[0], AST);
+  if (!Symbols.Macros.empty()) {
+    HoverInfo H;
+    H.Content = getHoverContents(Symbols.Macros[0], AST);
+    return H;
+  }
 
-  if (!Symbols.Decls.empty())
-    return getHoverContents(Symbols.Decls[0]);
+  if (!Symbols.Decls.empty()) {
+    HoverInfo H;
+    H.Content = getHoverContents(Symbols.Decls[0]);
+    return H;
+  }
 
   auto DeducedType = getDeducedType(AST, SourceLocationBeg);
-  if (DeducedType && !DeducedType->isNull())
-    return getHoverContents(*DeducedType, AST.getASTContext());
+  if (DeducedType && !DeducedType->isNull()) {
+    HoverInfo H;
+    H.Content = getHoverContents(*DeducedType, AST.getASTContext());
+    return H;
+  }
 
   return None;
 }
Index: clang-tools-extra/clangd/Protocol.h
===================================================================
--- clang-tools-extra/clangd/Protocol.h
+++ clang-tools-extra/clangd/Protocol.h
@@ -353,6 +353,15 @@
 bool fromJSON(const llvm::json::Value &, OffsetEncoding &);
 llvm::raw_ostream &operator<<(llvm::raw_ostream &, OffsetEncoding);
 
+// Describes the content type that a client supports in various result literals
+// like `Hover`, `ParameterInfo` or `CompletionItem`.
+enum class MarkupKind {
+  Plaintext,
+  Markdown,
+};
+bool fromJSON(const llvm::json::Value &, MarkupKind &);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, MarkupKind);
+
 // This struct doesn't mirror LSP!
 // The protocol defines deeply nested structures for client capabilities.
 // Instead of mapping them all, this just parses out the bits we care about.
@@ -391,6 +400,9 @@
 
   /// Supported encodings for LSP character offsets. (clangd extension).
   llvm::Optional<std::vector<OffsetEncoding>> offsetEncoding;
+
+  /// The content format that should be used for Hover requests.
+  MarkupKind HoverContentFormat = MarkupKind::Plaintext;
 };
 bool fromJSON(const llvm::json::Value &, ClientCapabilities &);
 
@@ -861,13 +873,8 @@
 };
 bool fromJSON(const llvm::json::Value &, CompletionParams &);
 
-enum class MarkupKind {
-  PlainText,
-  Markdown,
-};
-
 struct MarkupContent {
-  MarkupKind kind = MarkupKind::PlainText;
+  MarkupKind kind = MarkupKind::Plaintext;
   std::string value;
 };
 llvm::json::Value toJSON(const MarkupContent &MC);
Index: clang-tools-extra/clangd/Protocol.cpp
===================================================================
--- clang-tools-extra/clangd/Protocol.cpp
+++ clang-tools-extra/clangd/Protocol.cpp
@@ -17,6 +17,7 @@
 #include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/JSON.h"
@@ -302,6 +303,17 @@
               DocumentSymbol->getBoolean("hierarchicalDocumentSymbolSupport"))
         R.HierarchicalDocumentSymbol = *HierarchicalSupport;
     }
+    if (auto *Hover = TextDocument->getObject("hover")) {
+      if (auto *ContentFormat = Hover->getArray("contentFormat")) {
+        for (const auto &Format : *ContentFormat) {
+          MarkupKind K = MarkupKind::Plaintext;
+          if (fromJSON(Format, K)) {
+            R.HoverContentFormat = K;
+            break;
+          }
+        }
+      }
+    }
   }
   if (auto *Workspace = O->getObject("workspace")) {
     if (auto *Symbol = Workspace->getObject("symbol")) {
@@ -675,7 +687,7 @@
 
 static llvm::StringRef toTextKind(MarkupKind Kind) {
   switch (Kind) {
-  case MarkupKind::PlainText:
+  case MarkupKind::Plaintext:
     return "plaintext";
   case MarkupKind::Markdown:
     return "markdown";
@@ -683,6 +695,23 @@
   llvm_unreachable("Invalid MarkupKind");
 }
 
+bool fromJSON(const llvm::json::Value &V, MarkupKind &K) {
+  auto Str = V.getAsString();
+  if (!Str)
+    return false;
+  if (*Str == "plaintext")
+    K = MarkupKind::Plaintext;
+  else if (*Str == "markdown")
+    K = MarkupKind::Markdown;
+  else
+    return false;
+  return true;
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, MarkupKind K) {
+  return OS << toTextKind(K);
+}
+
 llvm::json::Value toJSON(const MarkupContent &MC) {
   if (MC.value.empty())
     return nullptr;
Index: clang-tools-extra/clangd/FormattedString.h
===================================================================
--- clang-tools-extra/clangd/FormattedString.h
+++ clang-tools-extra/clangd/FormattedString.h
@@ -36,6 +36,7 @@
 
   std::string renderAsMarkdown() const;
   std::string renderAsPlainText() const;
+  std::string renderForTests() const;
 
 private:
   enum class ChunkKind {
Index: clang-tools-extra/clangd/FormattedString.cpp
===================================================================
--- clang-tools-extra/clangd/FormattedString.cpp
+++ clang-tools-extra/clangd/FormattedString.cpp
@@ -9,6 +9,7 @@
 #include "clang/Basic/CharInfo.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormatVariadic.h"
 #include <cstddef>
 #include <string>
 
@@ -169,5 +170,27 @@
     R.pop_back();
   return R;
 }
+
+std::string FormattedString::renderForTests() const {
+  std::string R;
+  for (const auto &C : Chunks) {
+    switch (C.Kind) {
+    case ChunkKind::PlainText:
+      R += "text[" + C.Contents + "]";
+      break;
+    case ChunkKind::InlineCodeBlock:
+      R += "code[" + C.Contents + "]";
+      break;
+    case ChunkKind::CodeBlock:
+      if (!R.empty())
+        R += "\n";
+      R += llvm::formatv("codeblock({0}) [\n{1}\n]\n", C.Language, C.Contents);
+      break;
+    }
+  }
+  while (!R.empty() && isWhitespace(R.back()))
+    R.pop_back();
+  return R;
+}
 } // namespace clangd
 } // namespace clang
Index: clang-tools-extra/clangd/ClangdServer.h
===================================================================
--- clang-tools-extra/clangd/ClangdServer.h
+++ clang-tools-extra/clangd/ClangdServer.h
@@ -14,6 +14,7 @@
 #include "ClangdUnit.h"
 #include "CodeComplete.h"
 #include "FSProvider.h"
+#include "FormattedString.h"
 #include "Function.h"
 #include "GlobalCompilationDatabase.h"
 #include "Protocol.h"
@@ -180,7 +181,7 @@
 
   /// Get code hover for a given position.
   void findHover(PathRef File, Position Pos,
-                 Callback<llvm::Optional<Hover>> CB);
+                 Callback<llvm::Optional<HoverInfo>> CB);
 
   /// Get information about type hierarchy for a given position.
   void typeHierarchy(PathRef File, Position Pos, int Resolve,
Index: clang-tools-extra/clangd/ClangdServer.cpp
===================================================================
--- clang-tools-extra/clangd/ClangdServer.cpp
+++ clang-tools-extra/clangd/ClangdServer.cpp
@@ -10,11 +10,13 @@
 #include "ClangdUnit.h"
 #include "CodeComplete.h"
 #include "FindSymbols.h"
+#include "FormattedString.h"
 #include "Headers.h"
 #include "Protocol.h"
 #include "SourceCode.h"
 #include "TUScheduler.h"
 #include "Trace.h"
+#include "XRefs.h"
 #include "index/CanonicalIncludes.h"
 #include "index/FileIndex.h"
 #include "index/Merge.h"
@@ -523,14 +525,12 @@
 }
 
 void ClangdServer::findHover(PathRef File, Position Pos,
-                             Callback<llvm::Optional<Hover>> CB) {
-  auto Action = [Pos](Callback<llvm::Optional<Hover>> CB,
-                      llvm::Expected<InputsAndAST> InpAST) {
+                             Callback<llvm::Optional<HoverInfo>> CB) {
+  auto Action = [Pos](decltype(CB) CB, llvm::Expected<InputsAndAST> InpAST) {
     if (!InpAST)
       return CB(InpAST.takeError());
     CB(clangd::getHover(InpAST->AST, Pos));
   };
-
   WorkScheduler.runWithAST("Hover", File, Bind(Action, std::move(CB)));
 }
 
Index: clang-tools-extra/clangd/ClangdLSPServer.h
===================================================================
--- clang-tools-extra/clangd/ClangdLSPServer.h
+++ clang-tools-extra/clangd/ClangdLSPServer.h
@@ -154,7 +154,10 @@
   bool SupportsHierarchicalDocumentSymbol = false;
   /// Whether the client supports showing file status.
   bool SupportFileStatus = false;
-  // Store of the current versions of the open documents.
+  /// Which kind of markup should we use in textDocument/hover responses.
+  MarkupKind HoverContentFormat = MarkupKind::Plaintext;
+
+  /// Store of the current versions of the open documents.
   DraftStore DraftMgr;
 
   // The CDB is created by the "initialize" LSP method.
Index: clang-tools-extra/clangd/ClangdLSPServer.cpp
===================================================================
--- clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -8,6 +8,7 @@
 
 #include "ClangdLSPServer.h"
 #include "Diagnostics.h"
+#include "FormattedString.h"
 #include "Protocol.h"
 #include "SourceCode.h"
 #include "Trace.h"
@@ -358,6 +359,7 @@
   SupportsHierarchicalDocumentSymbol =
       Params.capabilities.HierarchicalDocumentSymbol;
   SupportFileStatus = Params.initializationOptions.FileStatus;
+  HoverContentFormat = Params.capabilities.HoverContentFormat;
   llvm::json::Object Result{
       {{"capabilities",
         llvm::json::Object{
@@ -839,7 +841,31 @@
 void ClangdLSPServer::onHover(const TextDocumentPositionParams &Params,
                               Callback<llvm::Optional<Hover>> Reply) {
   Server->findHover(Params.textDocument.uri.file(), Params.position,
-                    std::move(Reply));
+                    Bind(
+                        [this](decltype(Reply) Reply,
+                               llvm::Expected<llvm::Optional<HoverInfo>> H) {
+                          if (!H)
+                            return Reply(H.takeError());
+                          if (!*H)
+                            return Reply(llvm::None);
+
+                          Hover R;
+                          switch (HoverContentFormat) {
+                          case MarkupKind::Plaintext:
+                            R.contents.kind = MarkupKind::Plaintext;
+                            R.contents.value =
+                                (*H)->Content.renderAsPlainText();
+                            R.range = (*H)->Range;
+                            return Reply(std::move(R));
+                          case MarkupKind::Markdown:
+                            R.contents.kind = MarkupKind::Markdown;
+                            R.contents.value = (*H)->Content.renderAsMarkdown();
+                            R.range = (*H)->Range;
+                            return Reply(std::move(R));
+                          };
+                          llvm_unreachable("unhandled MarkupKind");
+                        },
+                        std::move(Reply)));
 }
 
 void ClangdLSPServer::onTypeHierarchy(
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to