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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits