tom-anders created this revision.
Herald added subscribers: kadircet, arphaman.
Herald added a project: All.
tom-anders added reviewers: nridge, sammccall, kadircet.
tom-anders published this revision for review.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.
Only for AST-based results, storage in the index is implemented in [3/3]


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D134131

Files:
  clang-tools-extra/clangd/CodeComplete.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.cpp
  clang-tools-extra/clangd/CodeCompletionStrings.h
  clang-tools-extra/clangd/Hover.cpp
  clang-tools-extra/clangd/Hover.h
  clang-tools-extra/clangd/index/SymbolCollector.cpp
  clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
  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 "SymbolDocumentationMatchers.h"
 #include "TestIndex.h"
 #include "TestTU.h"
 #include "index/MemIndex.h"
@@ -43,7 +44,8 @@
          HI.NamespaceScope = "";
          HI.Name = "foo";
          HI.Kind = index::SymbolKind::Function;
-         HI.Documentation = "Best foo ever.";
+         HI.Documentation =
+             SymbolDocumentationOwned::descriptionOnly("Best foo ever.");
          HI.Definition = "void foo()";
          HI.ReturnType = "void";
          HI.Type = "void ()";
@@ -60,7 +62,8 @@
          HI.NamespaceScope = "ns1::ns2::";
          HI.Name = "foo";
          HI.Kind = index::SymbolKind::Function;
-         HI.Documentation = "Best foo ever.";
+         HI.Documentation =
+             SymbolDocumentationOwned::descriptionOnly("Best foo ever.");
          HI.Definition = "void foo()";
          HI.ReturnType = "void";
          HI.Type = "void ()";
@@ -148,8 +151,8 @@
        [](HoverInfo &HI) {
          HI.Name = "__func__";
          HI.Kind = index::SymbolKind::Variable;
-         HI.Documentation =
-             "Name of the current function (predefined variable)";
+         HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+             "Name of the current function (predefined variable)");
          HI.Value = "\"foo\"";
          HI.Type = "const char[4]";
        }},
@@ -162,8 +165,8 @@
        [](HoverInfo &HI) {
          HI.Name = "__func__";
          HI.Kind = index::SymbolKind::Variable;
-         HI.Documentation =
-             "Name of the current function (predefined variable)";
+         HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+             "Name of the current function (predefined variable)");
          HI.Type = "const char[]";
        }},
       // Anon namespace and local scope.
@@ -741,7 +744,8 @@
          HI.Definition = "template <> class Foo<int *>";
          // FIXME: Maybe force instantiation to make use of real template
          // pattern.
-         HI.Documentation = "comment from primary";
+         HI.Documentation =
+             SymbolDocumentationOwned::descriptionOnly("comment from primary");
        }},
       {// Template Type Parameter
        R"cpp(
@@ -793,7 +797,8 @@
          HI.NamespaceScope = "";
          HI.Definition = "float y()";
          HI.LocalScope = "X::";
-         HI.Documentation = "Trivial accessor for `Y`.";
+         HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+             "Trivial accessor for `Y`.");
          HI.Type = "float ()";
          HI.ReturnType = "float";
          HI.Parameters.emplace();
@@ -809,7 +814,8 @@
          HI.NamespaceScope = "";
          HI.Definition = "void setY(float v)";
          HI.LocalScope = "X::";
-         HI.Documentation = "Trivial setter for `Y`.";
+         HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+             "Trivial setter for `Y`.");
          HI.Type = "void (float)";
          HI.ReturnType = "void";
          HI.Parameters.emplace();
@@ -828,7 +834,8 @@
          HI.NamespaceScope = "";
          HI.Definition = "X &setY(float v)";
          HI.LocalScope = "X::";
-         HI.Documentation = "Trivial setter for `Y`.";
+         HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+             "Trivial setter for `Y`.");
          HI.Type = "X &(float)";
          HI.ReturnType = "X &";
          HI.Parameters.emplace();
@@ -848,7 +855,8 @@
          HI.NamespaceScope = "";
          HI.Definition = "void setY(float v)";
          HI.LocalScope = "X::";
-         HI.Documentation = "Trivial setter for `Y`.";
+         HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+             "Trivial setter for `Y`.");
          HI.Type = "void (float)";
          HI.ReturnType = "void";
          HI.Parameters.emplace();
@@ -1140,7 +1148,7 @@
     EXPECT_EQ(H->LocalScope, Expected.LocalScope);
     EXPECT_EQ(H->Name, Expected.Name);
     EXPECT_EQ(H->Kind, Expected.Kind);
-    EXPECT_EQ(H->Documentation, Expected.Documentation);
+    ASSERT_THAT(H->Documentation, matchesDoc(Expected.Documentation));
     EXPECT_EQ(H->Definition, Expected.Definition);
     EXPECT_EQ(H->Type, Expected.Type);
     EXPECT_EQ(H->ReturnType, Expected.ReturnType);
@@ -1417,7 +1425,8 @@
             HI.NamespaceScope = "";
             HI.Type = "void (int)";
             HI.Definition = "void foo(int)";
-            HI.Documentation = "Function definition via pointer";
+            HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+                "Function definition via pointer");
             HI.ReturnType = "void";
             HI.Parameters = {
                 {{"int"}, llvm::None, llvm::None},
@@ -1436,7 +1445,8 @@
             HI.NamespaceScope = "";
             HI.Type = "int (int)";
             HI.Definition = "int foo(int)";
-            HI.Documentation = "Function declaration via call";
+            HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+                "Function declaration via call");
             HI.ReturnType = "int";
             HI.Parameters = {
                 {{"int"}, llvm::None, llvm::None},
@@ -1584,7 +1594,8 @@
             HI.NamespaceScope = "";
             HI.Definition = "typedef int Foo";
             HI.Type = "int";
-            HI.Documentation = "Typedef";
+            HI.Documentation =
+                SymbolDocumentationOwned::descriptionOnly("Typedef");
           }},
       {
           R"cpp(// Typedef with embedded definition
@@ -1599,7 +1610,8 @@
             HI.NamespaceScope = "";
             HI.Definition = "typedef struct Bar Foo";
             HI.Type = "struct Bar";
-            HI.Documentation = "Typedef with embedded definition";
+            HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+                "Typedef with embedded definition");
           }},
       {
           R"cpp(// Namespace
@@ -1646,7 +1658,7 @@
             HI.NamespaceScope = "ns::";
             HI.Type = "void ()";
             HI.Definition = "void foo()";
-            HI.Documentation = "";
+            HI.Documentation = SymbolDocumentationOwned::descriptionOnly("");
             HI.ReturnType = "void";
             HI.Parameters = std::vector<HoverInfo::Param>{};
           }},
@@ -1714,10 +1726,18 @@
             HI.Kind = index::SymbolKind::Class;
             HI.NamespaceScope = "";
             HI.Definition = "class Foo {}";
-            HI.Documentation = "Forward class declaration";
+            HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+                "Forward class declaration");
           }},
       {
-          R"cpp(// Function declaration
+          R"cpp(
+            /// \brief Function declaration
+            /// \details Some details
+            /// \throws std::runtime_error sometimes
+            /// \param x doc for x
+            /// \warning Watch out!
+            /// \note note1 \note note2
+            /// \return Nothing
             void foo();
             void g() { [[f^oo]](); }
             void foo() {}
@@ -1728,7 +1748,22 @@
             HI.NamespaceScope = "";
             HI.Type = "void ()";
             HI.Definition = "void foo()";
-            HI.Documentation = "Function declaration";
+            HI.Documentation.Brief = "Function declaration";
+            HI.Documentation.Description = "\\details Some details\n\n\\throws "
+                                           "std::runtime_error sometimes";
+            HI.Documentation.Parameters = {
+                {"x", "doc for x"},
+            };
+            HI.Documentation.Returns = "Nothing";
+            HI.Documentation.Notes = {"note1", "note2"};
+            HI.Documentation.Warnings = {"Watch out!"};
+            HI.Documentation.CommentText = R"(\brief Function declaration
+\details Some details
+\throws std::runtime_error sometimes
+\param x doc for x
+\warning Watch out!
+\note note1 \note note2
+\return Nothing)";
             HI.ReturnType = "void";
             HI.Parameters = std::vector<HoverInfo::Param>{};
           }},
@@ -1746,7 +1781,8 @@
             HI.Kind = index::SymbolKind::Enum;
             HI.NamespaceScope = "";
             HI.Definition = "enum Hello {}";
-            HI.Documentation = "Enum declaration";
+            HI.Documentation =
+                SymbolDocumentationOwned::descriptionOnly("Enum declaration");
           }},
       {
           R"cpp(// Enumerator
@@ -1817,7 +1853,8 @@
             HI.NamespaceScope = "";
             HI.Type = "int";
             HI.Definition = "static int hey = 10";
-            HI.Documentation = "Global variable";
+            HI.Documentation =
+                SymbolDocumentationOwned::descriptionOnly("Global variable");
             // FIXME: Value shouldn't be set in this case
             HI.Value = "10 (0xa)";
           }},
@@ -1869,7 +1906,8 @@
             HI.NamespaceScope = "";
             HI.Type = "int ()";
             HI.Definition = "template <> int foo<int>()";
-            HI.Documentation = "Templated function";
+            HI.Documentation =
+                SymbolDocumentationOwned::descriptionOnly("Templated function");
             HI.ReturnType = "int";
             HI.Parameters = std::vector<HoverInfo::Param>{};
             // FIXME: We should populate template parameters with arguments in
@@ -1906,7 +1944,8 @@
             HI.Definition = "void indexSymbol()";
             HI.ReturnType = "void";
             HI.Parameters = std::vector<HoverInfo::Param>{};
-            HI.Documentation = "comment from index";
+            HI.Documentation =
+                SymbolDocumentationOwned::descriptionOnly("comment from index");
           }},
       {
           R"cpp(// Simple initialization with auto
@@ -2075,7 +2114,8 @@
             HI.Name = "auto";
             HI.Kind = index::SymbolKind::TypeAlias;
             HI.Definition = "Bar";
-            HI.Documentation = "auto function return with trailing type";
+            HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+                "auto function return with trailing type");
           }},
       {
           R"cpp(// trailing return type
@@ -2088,7 +2128,8 @@
             HI.Name = "decltype";
             HI.Kind = index::SymbolKind::TypeAlias;
             HI.Definition = "Bar";
-            HI.Documentation = "trailing return type";
+            HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+                "trailing return type");
           }},
       {
           R"cpp(// auto in function return
@@ -2101,7 +2142,8 @@
             HI.Name = "auto";
             HI.Kind = index::SymbolKind::TypeAlias;
             HI.Definition = "Bar";
-            HI.Documentation = "auto in function return";
+            HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+                "auto in function return");
           }},
       {
           R"cpp(// auto& in function return
@@ -2115,7 +2157,8 @@
             HI.Name = "auto";
             HI.Kind = index::SymbolKind::TypeAlias;
             HI.Definition = "Bar";
-            HI.Documentation = "auto& in function return";
+            HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+                "auto& in function return");
           }},
       {
           R"cpp(// auto* in function return
@@ -2129,7 +2172,8 @@
             HI.Name = "auto";
             HI.Kind = index::SymbolKind::TypeAlias;
             HI.Definition = "Bar";
-            HI.Documentation = "auto* in function return";
+            HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+                "auto* in function return");
           }},
       {
           R"cpp(// const auto& in function return
@@ -2143,7 +2187,8 @@
             HI.Name = "auto";
             HI.Kind = index::SymbolKind::TypeAlias;
             HI.Definition = "Bar";
-            HI.Documentation = "const auto& in function return";
+            HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+                "const auto& in function return");
           }},
       {
           R"cpp(// decltype(auto) in function return
@@ -2156,7 +2201,8 @@
             HI.Name = "decltype";
             HI.Kind = index::SymbolKind::TypeAlias;
             HI.Definition = "Bar";
-            HI.Documentation = "decltype(auto) in function return";
+            HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+                "decltype(auto) in function return");
           }},
       {
           R"cpp(// decltype(auto) reference in function return
@@ -2246,8 +2292,8 @@
             HI.Name = "decltype";
             HI.Kind = index::SymbolKind::TypeAlias;
             HI.Definition = "Bar";
-            HI.Documentation =
-                "decltype of function with trailing return type.";
+            HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+                "decltype of function with trailing return type.");
           }},
       {
           R"cpp(// decltype of var with decltype.
@@ -2317,7 +2363,8 @@
             HI.Name = "auto";
             HI.Kind = index::SymbolKind::TypeAlias;
             HI.Definition = "cls_type // aka: cls";
-            HI.Documentation = "auto on alias";
+            HI.Documentation =
+                SymbolDocumentationOwned::descriptionOnly("auto on alias");
           }},
       {
           R"cpp(// auto on alias
@@ -2329,7 +2376,8 @@
             HI.Name = "auto";
             HI.Kind = index::SymbolKind::TypeAlias;
             HI.Definition = "templ<int>";
-            HI.Documentation = "auto on alias";
+            HI.Documentation =
+                SymbolDocumentationOwned::descriptionOnly("auto on alias");
           }},
       {
           R"cpp(// Undeduced auto declaration
@@ -2420,7 +2468,8 @@
             HI.Kind = index::SymbolKind::Struct;
             HI.NamespaceScope = "";
             HI.Name = "cls<cls<cls<int>>>";
-            HI.Documentation = "type of nested templates.";
+            HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+                "type of nested templates.");
           }},
       {
           R"cpp(// type with decltype
@@ -2714,7 +2763,8 @@
          HI.Name = "nonnull";
          HI.Kind = index::SymbolKind::Unknown; // FIXME: no suitable value
          HI.Definition = "__attribute__((nonnull))";
-         HI.Documentation = Attr::getDocumentation(attr::NonNull).str();
+         HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+             Attr::getDocumentation(attr::NonNull).str());
        }},
   };
 
@@ -2753,7 +2803,7 @@
     EXPECT_EQ(H->LocalScope, Expected.LocalScope);
     EXPECT_EQ(H->Name, Expected.Name);
     EXPECT_EQ(H->Kind, Expected.Kind);
-    EXPECT_EQ(H->Documentation, Expected.Documentation);
+    ASSERT_THAT(H->Documentation, matchesDoc(Expected.Documentation));
     EXPECT_EQ(H->Definition, Expected.Definition);
     EXPECT_EQ(H->Type, Expected.Type);
     EXPECT_EQ(H->ReturnType, Expected.ReturnType);
@@ -2786,7 +2836,9 @@
   for (const auto &P : T.points()) {
     auto H = getHover(AST, P, format::getLLVMStyle(), Index.get());
     ASSERT_TRUE(H);
-    EXPECT_EQ(H->Documentation, IndexSym.Documentation);
+    ASSERT_THAT(H->Documentation,
+                matchesDoc(SymbolDocumentationOwned::descriptionOnly(
+                    std::string(IndexSym.Documentation))));
   }
 }
 
@@ -2811,7 +2863,8 @@
   for (const auto &P : T.points()) {
     auto H = getHover(AST, P, format::getLLVMStyle(), nullptr);
     ASSERT_TRUE(H);
-    EXPECT_EQ(H->Documentation, "doc");
+    ASSERT_THAT(H->Documentation,
+                matchesDoc(SymbolDocumentationOwned::descriptionOnly("doc")));
   }
 }
 
@@ -2849,7 +2902,9 @@
     for (const auto &P : T.points(Comment)) {
       auto H = getHover(AST, P, format::getLLVMStyle(), nullptr);
       ASSERT_TRUE(H);
-      EXPECT_EQ(H->Documentation, Comment);
+      ASSERT_THAT(
+          H->Documentation,
+          matchesDoc(SymbolDocumentationOwned::descriptionOnly(Comment)));
     }
   }
 }
@@ -2881,7 +2936,14 @@
                 {{"typename"}, std::string("T"), llvm::None},
                 {{"typename"}, std::string("C"), std::string("bool")},
             };
-            HI.Documentation = "documentation";
+            HI.Documentation.Brief = "brief";
+            HI.Documentation.Description = "details";
+            HI.Documentation.Parameters = {
+                {"Parameters", "should be ignored for classes"}};
+            HI.Documentation.Returns = "Returns should be ignored for classes";
+            HI.Documentation.Notes = {"note1", "note2"};
+            HI.Documentation.Warnings = {"warning1", "warning2"};
+            HI.Documentation.CommentText = "Not used for Hover presentation";
             HI.Definition =
                 "template <typename T, typename C = bool> class Foo {}";
             HI.Name = "foo";
@@ -2889,8 +2951,17 @@
           },
           R"(class foo
 
+brief
 Size: 10 bytes
-documentation
+details
+
+Warnings:
+- warning1
+- warning2
+
+Notes:
+- note1
+- note2
 
 template <typename T, typename C = bool> class Foo {})",
       },
@@ -2909,17 +2980,37 @@
             HI.Parameters->push_back(P);
             P.Default = "default";
             HI.Parameters->push_back(P);
+            HI.Documentation.Brief = "brief";
+            HI.Documentation.Description = "details";
+            HI.Documentation.Parameters = {
+                {"foo", "param doc"},
+                {"bar", "doc for parameter not in the signature"}};
+            HI.Documentation.Returns = "doc for return";
+            HI.Documentation.Notes = {"note1", "note2"};
+            HI.Documentation.Warnings = {"warning1", "warning2"};
+            HI.Documentation.CommentText = "Not used for Hover presentation";
             HI.NamespaceScope = "ns::";
             HI.Definition = "ret_type foo(params) {}";
           },
           "function foo\n"
           "\n"
-          "→ ret_type (aka can_ret_type)\n"
+          "brief\n"
+          "→ ret_type (aka can_ret_type): doc for return\n"
           "Parameters:\n"
           "- \n"
           "- type (aka can_type)\n"
-          "- type foo (aka can_type)\n"
+          "- type foo (aka can_type): param doc\n"
           "- type foo = default (aka can_type)\n"
+          "- bar: doc for parameter not in the signature\n"
+          "details\n"
+          "\n"
+          "Warnings:\n"
+          "- warning1\n"
+          "- warning2\n"
+          "\n"
+          "Notes:\n"
+          "- note1\n"
+          "- note2\n"
           "\n"
           "// In namespace ns\n"
           "ret_type foo(params) {}",
@@ -3291,7 +3382,7 @@
 
   template <typename T>
   struct S {
-    // Foo bar baz
+    /// Foo bar baz
     friend auto operator<=>(S, S) = default;
   };
   static_assert(S<void>() =^= S<void>());
@@ -3301,7 +3392,10 @@
   TU.ExtraArgs.push_back("-std=c++20");
   auto AST = TU.build();
   auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
-  EXPECT_EQ(HI->Documentation, "Foo bar baz");
+
+  ASSERT_THAT(
+      HI->Documentation,
+      matchesDoc(SymbolDocumentationOwned::descriptionOnly("Foo bar baz")));
 }
 
 TEST(Hover, ForwardStructNoCrash) {
Index: clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
+++ clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp
@@ -58,12 +58,39 @@
             "Annotation: Ano\n\nIs this brief?");
 }
 
-TEST_F(CompletionStringTest, GetDeclCommentBadUTF8) {
+TEST_F(CompletionStringTest, GetDeclDocumentationBadUTF8) {
   // <ff> is not a valid byte here, should be replaced by encoded <U+FFFD>.
-  auto TU = TestTU::withCode("/*x\xffy*/ struct X;");
+  const std::string Code = llvm::formatv(R"cpp(
+  /// \brief {0}
+  /// \details {0}
+  /// \param {0} {0}
+  /// \warning {0}
+  /// \note {0}
+  /// \return {0}
+  struct X;
+  )cpp",
+                                         "x\xffy");
+
+  auto TU = TestTU::withCode(Code);
   auto AST = TU.build();
-  EXPECT_EQ("x\xef\xbf\xbdy",
-            getDeclComment(AST.getASTContext(), findDecl(AST, "X")));
+
+  const std::string Utf8Replacement = "x\xef\xbf\xbdy";
+  SymbolDocumentationOwned ExpectedDoc;
+  ExpectedDoc.Brief = Utf8Replacement;
+  ExpectedDoc.Returns = Utf8Replacement;
+  ExpectedDoc.Parameters = {{Utf8Replacement, Utf8Replacement}};
+  ExpectedDoc.Notes = {Utf8Replacement};
+  ExpectedDoc.Warnings = {Utf8Replacement};
+  ExpectedDoc.Description = {"\\details " + Utf8Replacement};
+  ExpectedDoc.CommentText = llvm::formatv(R"(\brief {0}
+\details {0}
+\param {0} {0}
+\warning {0}
+\note {0}
+\return {0})", Utf8Replacement);
+
+  EXPECT_THAT(getDeclDocumentation(AST.getASTContext(), findDecl(AST, "X")),
+              matchesDoc(ExpectedDoc));
 }
 
 TEST_F(CompletionStringTest, DoxygenParsing) {
@@ -144,9 +171,7 @@
             ->getFormattedText(Ctx.getSourceManager(), Ctx.getDiagnostics());
     Case.ExpectedBuilder(ExpectedDoc);
 
-    const RawComment *RC = getCompletionComment(Ctx, &Decl);
-    EXPECT_THAT(RC, testing::NotNull());
-    EXPECT_THAT(parseDoxygenComment(*RC, Ctx, &Decl), matchesDoc(ExpectedDoc));
+    EXPECT_THAT(getDeclDocumentation(Ctx, Decl), matchesDoc(ExpectedDoc));
   }
 }
 
Index: clang-tools-extra/clangd/index/SymbolCollector.cpp
===================================================================
--- clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -913,8 +913,9 @@
       *CompletionTUInfo,
       /*IncludeBriefComments*/ false);
   std::string Documentation =
-      formatDocumentation(*CCS, getDocComment(Ctx, SymbolCompletion,
-                                              /*CommentsFromHeaders=*/true));
+      formatDocumentation(*CCS, getDocumentation(Ctx, SymbolCompletion,
+                                                 /*CommentsFromHeaders=*/true)
+                                    .CommentText);
   if (!(S.Flags & Symbol::IndexedForCodeCompletion)) {
     if (Opts.StoreAllDocumentation)
       S.Documentation = Documentation;
Index: clang-tools-extra/clangd/Hover.h
===================================================================
--- clang-tools-extra/clangd/Hover.h
+++ clang-tools-extra/clangd/Hover.h
@@ -11,6 +11,7 @@
 
 #include "ParsedAST.h"
 #include "Protocol.h"
+#include "SymbolDocumentation.h"
 #include "support/Markup.h"
 #include "clang/Index/IndexSymbol.h"
 
@@ -68,7 +69,7 @@
   std::string Name;
   llvm::Optional<Range> SymRange;
   index::SymbolKind Kind = index::SymbolKind::Unknown;
-  std::string Documentation;
+  SymbolDocumentationOwned Documentation;
   /// Source code containing the definition of the symbol.
   std::string Definition;
   const char *DefinitionLanguage = "cpp";
Index: clang-tools-extra/clangd/Hover.cpp
===================================================================
--- clang-tools-extra/clangd/Hover.cpp
+++ clang-tools-extra/clangd/Hover.cpp
@@ -333,7 +333,8 @@
   LookupRequest Req;
   Req.IDs.insert(ID);
   Index->lookup(Req, [&](const Symbol &S) {
-    Hover.Documentation = std::string(S.Documentation);
+    Hover.Documentation =
+        SymbolDocumentationOwned::descriptionOnly(std::string(S.Documentation));
   });
 }
 
@@ -592,10 +593,11 @@
 
   HI.Name = printName(Ctx, *D);
   const auto *CommentD = getDeclForComment(D);
-  HI.Documentation = getDeclComment(Ctx, *CommentD);
+  HI.Documentation = getDeclDocumentation(Ctx, *CommentD);
   enhanceFromIndex(HI, *CommentD, Index);
   if (HI.Documentation.empty())
-    HI.Documentation = synthesizeDocumentation(D);
+    HI.Documentation =
+        SymbolDocumentationOwned::descriptionOnly(synthesizeDocumentation(D));
 
   HI.Kind = index::getSymbolInfo(D).Kind;
 
@@ -649,7 +651,8 @@
   HoverInfo HI;
   HI.Name = PE.getIdentKindName();
   HI.Kind = index::SymbolKind::Variable;
-  HI.Documentation = "Name of the current function (predefined variable)";
+  HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+      "Name of the current function (predefined variable)");
   if (const StringLiteral *Name = PE.getFunctionName()) {
     HI.Value.emplace();
     llvm::raw_string_ostream OS(*HI.Value);
@@ -769,7 +772,7 @@
 
     if (const auto *D = QT->getAsTagDecl()) {
       const auto *CommentD = getDeclForComment(D);
-      HI.Documentation = getDeclComment(ASTCtx, *CommentD);
+      HI.Documentation = getDeclDocumentation(ASTCtx, *CommentD);
       enhanceFromIndex(HI, *CommentD, Index);
     }
   }
@@ -836,7 +839,8 @@
     llvm::raw_string_ostream OS(HI.Definition);
     A->printPretty(OS, AST.getASTContext().getPrintingPolicy());
   }
-  HI.Documentation = Attr::getDocumentation(A->getKind()).str();
+  HI.Documentation = SymbolDocumentationOwned::descriptionOnly(
+      Attr::getDocumentation(A->getKind()).str());
   return HI;
 }
 
@@ -1172,6 +1176,10 @@
 
   // Put a linebreak after header to increase readability.
   Output.addRuler();
+
+  if (!Documentation.Brief.empty())
+    parseDocumentation(Documentation.Brief, Output);
+
   // Print Types on their own lines to reduce chances of getting line-wrapped by
   // editor, as they might be long.
   if (ReturnType) {
@@ -1180,15 +1188,44 @@
     // Parameters:
     // - `bool param1`
     // - `int param2 = 5`
-    Output.addParagraph().appendText("→ ").appendCode(
+    auto &P = Output.addParagraph().appendText("→ ").appendCode(
         llvm::to_string(*ReturnType));
-  }
 
+    if (!Documentation.Returns.empty())
+      P.appendText(": ").appendText(Documentation.Returns);
+  }
   if (Parameters && !Parameters->empty()) {
     Output.addParagraph().appendText("Parameters: ");
     markup::BulletList &L = Output.addBulletList();
-    for (const auto &Param : *Parameters)
-      L.addItem().addParagraph().appendCode(llvm::to_string(Param));
+
+    llvm::SmallVector<ParameterDocumentationOwned> ParamDocs =
+        Documentation.Parameters;
+
+    for (const auto &Param : *Parameters) {
+      auto &Paragraph = L.addItem().addParagraph();
+      Paragraph.appendCode(llvm::to_string(Param));
+
+      if (Param.Name.has_value()) {
+        auto ParamDoc = std::find_if(ParamDocs.begin(), ParamDocs.end(),
+                                     [Param](const auto &ParamDoc) {
+                                       return Param.Name == ParamDoc.Name;
+                                     });
+        if (ParamDoc != ParamDocs.end()) {
+          Paragraph.appendText(": ").appendText(ParamDoc->Description);
+          ParamDocs.erase(ParamDoc);
+        }
+      }
+    }
+
+    // We erased all parameters that matched, but some may still be left,
+    // usually typos. Let's also print them here.
+    for (const auto &ParamDoc : ParamDocs) {
+      L.addItem()
+          .addParagraph()
+          .appendCode(ParamDoc.Name)
+          .appendText(": ")
+          .appendText(ParamDoc.Description);
+    }
   }
 
   // Don't print Type after Parameters or ReturnType as this will just duplicate
@@ -1232,8 +1269,30 @@
     Output.addParagraph().appendText(OS.str());
   }
 
-  if (!Documentation.empty())
-    parseDocumentation(Documentation, Output);
+  if (!Documentation.Description.empty())
+    parseDocumentation(Documentation.Description, Output);
+
+  if (!Documentation.Warnings.empty()) {
+    Output.addRuler();
+    Output.addParagraph()
+        .appendText("Warning")
+        .appendText(Documentation.Warnings.size() > 1 ? "s" : "")
+        .appendText(": ");
+    markup::BulletList &L = Output.addBulletList();
+    for (const auto &Warning : Documentation.Warnings)
+      parseDocumentation(Warning, L.addItem());
+  }
+
+  if (!Documentation.Notes.empty()) {
+    Output.addRuler();
+    Output.addParagraph()
+        .appendText("Note")
+        .appendText(Documentation.Notes.size() > 1 ? "s" : "")
+        .appendText(": ");
+    markup::BulletList &L = Output.addBulletList();
+    for (const auto &Note : Documentation.Notes)
+      parseDocumentation(Note, L.addItem());
+  }
 
   if (!Definition.empty()) {
     Output.addRuler();
Index: clang-tools-extra/clangd/CodeCompletionStrings.h
===================================================================
--- clang-tools-extra/clangd/CodeCompletionStrings.h
+++ clang-tools-extra/clangd/CodeCompletionStrings.h
@@ -16,24 +16,25 @@
 
 #include "clang/Sema/CodeCompleteConsumer.h"
 
+#include "SymbolDocumentation.h"
+
 namespace clang {
 class ASTContext;
 
 namespace clangd {
 
-/// Gets a minimally formatted documentation comment of \p Result, with comment
-/// markers stripped. See clang::RawComment::getFormattedText() for the detailed
-/// explanation of how the comment text is transformed.
-/// Returns empty string when no comment is available.
+/// Gets the parsed doxygen documentation of \p Result.
+/// Returns an empty SymbolDocumentationOwned when no comment is available.
 /// If \p CommentsFromHeaders parameter is set, only comments from the main
 /// file will be returned. It is used to workaround crashes when parsing
 /// comments in the stale headers, coming from completion preamble.
-std::string getDocComment(const ASTContext &Ctx,
-                          const CodeCompletionResult &Result,
-                          bool CommentsFromHeaders);
+SymbolDocumentationOwned getDocumentation(const ASTContext &Ctx,
+                                          const CodeCompletionResult &Result,
+                                          bool CommentsFromHeaders);
 
-/// Similar to getDocComment, but returns the comment for a NamedDecl.
-std::string getDeclComment(const ASTContext &Ctx, const NamedDecl &D);
+/// Similar to getDocumentation, but returns the comment for a NamedDecl.
+SymbolDocumentationOwned getDeclDocumentation(const ASTContext &Ctx,
+                                              const NamedDecl &D);
 
 /// Formats the signature for an item, as a display string and snippet.
 /// e.g. for const_reference std::vector<T>::at(size_type) const, this returns:
Index: clang-tools-extra/clangd/CodeCompletionStrings.cpp
===================================================================
--- clang-tools-extra/clangd/CodeCompletionStrings.cpp
+++ clang-tools-extra/clangd/CodeCompletionStrings.cpp
@@ -58,39 +58,42 @@
 
 } // namespace
 
-std::string getDocComment(const ASTContext &Ctx,
-                          const CodeCompletionResult &Result,
-                          bool CommentsFromHeaders) {
+SymbolDocumentationOwned getDocumentation(const ASTContext &Ctx,
+                                          const CodeCompletionResult &Result,
+                                          bool CommentsFromHeaders) {
+  // FIXME: CommentsFromHeaders seems to be unused? Is this a bug?
+
   // FIXME: clang's completion also returns documentation for RK_Pattern if they
   // contain a pattern for ObjC properties. Unfortunately, there is no API to
   // get this declaration, so we don't show documentation in that case.
   if (Result.Kind != CodeCompletionResult::RK_Declaration)
-    return "";
-  return Result.getDeclaration() ? getDeclComment(Ctx, *Result.getDeclaration())
-                                 : "";
+    return {};
+  return Result.getDeclaration()
+             ? getDeclDocumentation(Ctx, *Result.getDeclaration())
+             : SymbolDocumentationOwned{};
 }
 
-std::string getDeclComment(const ASTContext &Ctx, const NamedDecl &Decl) {
+SymbolDocumentationOwned getDeclDocumentation(const ASTContext &Ctx,
+                                              const NamedDecl &Decl) {
   if (isa<NamespaceDecl>(Decl)) {
     // Namespaces often have too many redecls for any particular redecl comment
     // to be useful. Moreover, we often confuse file headers or generated
     // comments with namespace comments. Therefore we choose to just ignore
     // the comments for namespaces.
-    return "";
+    return {};
   }
   const RawComment *RC = getCompletionComment(Ctx, &Decl);
   if (!RC)
-    return "";
+    return {};
   // Sanity check that the comment does not come from the PCH. We choose to not
   // write them into PCH, because they are racy and slow to load.
   assert(!Ctx.getSourceManager().isLoadedSourceLocation(RC->getBeginLoc()));
-  std::string Doc =
-      RC->getFormattedText(Ctx.getSourceManager(), Ctx.getDiagnostics());
-  if (!looksLikeDocComment(Doc))
-    return "";
-  // Clang requires source to be UTF-8, but doesn't enforce this in comments.
-  if (!llvm::json::isUTF8(Doc))
-    Doc = llvm::json::fixUTF8(Doc);
+
+  SymbolDocumentationOwned Doc = parseDoxygenComment(*RC, Ctx, &Decl);
+
+  if (!looksLikeDocComment(Doc.CommentText))
+    return {};
+
   return Doc;
 }
 
Index: clang-tools-extra/clangd/CodeComplete.cpp
===================================================================
--- clang-tools-extra/clangd/CodeComplete.cpp
+++ clang-tools-extra/clangd/CodeComplete.cpp
@@ -427,8 +427,9 @@
       if (C.IndexResult) {
         SetDoc(C.IndexResult->Documentation);
       } else if (C.SemaResult) {
-        const auto DocComment = getDocComment(*ASTCtx, *C.SemaResult,
-                                              /*CommentsFromHeaders=*/false);
+        const auto DocComment = getDocumentation(*ASTCtx, *C.SemaResult,
+                                                 /*CommentsFromHeaders=*/false)
+                                    .CommentText;
         SetDoc(formatDocumentation(*SemaCCS, DocComment));
       }
     }
@@ -982,7 +983,9 @@
       ScoredSignatures.push_back(processOverloadCandidate(
           Candidate, *CCS,
           Candidate.getFunction()
-              ? getDeclComment(S.getASTContext(), *Candidate.getFunction())
+              ? getDeclDocumentation(S.getASTContext(),
+                                     *Candidate.getFunction())
+                    .CommentText
               : ""));
     }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to