Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang-tools-extra/clangd/CodeComplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ toCompletionItemKind(index::SymbolKind Kind,
const llvm::StringRef *Signature = nullptr) {
using SK = index::SymbolKind;
switch (Kind) {
// FIXME: for backwards compatibility, the include directive kind is treated
// the same as Unknown
case SK::IncludeDirective:
case SK::Unknown:
return CompletionItemKind::Missing;
case SK::Module:
Expand Down
8 changes: 6 additions & 2 deletions clang-tools-extra/clangd/CodeCompletionStrings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ std::string getDeclComment(const ASTContext &Ctx, const NamedDecl &Decl) {
std::string Doc;

if (Cfg.Documentation.CommentFormat == Config::CommentFormatPolicy::Doxygen &&
isa<ParmVarDecl>(Decl)) {
isa<ParmVarDecl, TemplateTypeParmDecl>(Decl)) {
// Parameters are documented in their declaration context (function or
// template function).
const NamedDecl *ND = dyn_cast<NamedDecl>(Decl.getDeclContext());
Expand All @@ -135,7 +135,11 @@ std::string getDeclComment(const ASTContext &Ctx, const NamedDecl &Decl) {
std::string RawDoc;
llvm::raw_string_ostream OS(RawDoc);

V.parameterDocToString(dyn_cast<ParmVarDecl>(&Decl)->getName(), OS);
if (auto *PVD = dyn_cast<ParmVarDecl>(&Decl))
V.parameterDocToString(PVD->getName(), OS);
else
V.templateTypeParmDocToString(
cast<TemplateTypeParmDecl>(&Decl)->getName(), OS);

Doc = StringRef(RawDoc).trim().str();
} else {
Expand Down
111 changes: 82 additions & 29 deletions clang-tools-extra/clangd/Hover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1274,10 +1274,10 @@ std::optional<HoverInfo> getHover(ParsedAST &AST, Position Pos,
HoverCountMetric.record(1, "include");
HoverInfo HI;
HI.Name = std::string(llvm::sys::path::filename(Inc.Resolved));
// FIXME: We don't have a fitting value for Kind.
HI.Definition =
URIForFile::canonicalize(Inc.Resolved, AST.tuPath()).file().str();
HI.DefinitionLanguage = "";
HI.Kind = index::SymbolKind::IncludeDirective;
maybeAddUsedSymbols(AST, HI, Inc);
return HI;
}
Expand Down Expand Up @@ -1483,10 +1483,6 @@ void HoverInfo::sizeToMarkupParagraph(markup::Paragraph &P) const {
}

markup::Document HoverInfo::presentDoxygen() const {
// NOTE: this function is currently almost identical to presentDefault().
// This is to have a minimal change when introducing the doxygen parser.
// This function will be changed when rearranging the output for doxygen
// parsed documentation.

markup::Document Output;
// Header contains a text of the form:
Expand All @@ -1502,45 +1498,108 @@ markup::Document HoverInfo::presentDoxygen() const {
// level 1 and 2 headers in a huge font, see
// https://github.com/microsoft/vscode/issues/88417 for details.
markup::Paragraph &Header = Output.addHeading(3);
if (Kind != index::SymbolKind::Unknown)
if (Kind != index::SymbolKind::Unknown &&
Kind != index::SymbolKind::IncludeDirective)
Header.appendText(index::getSymbolKindString(Kind)).appendSpace();
assert(!Name.empty() && "hover triggered on a nameless symbol");

Header.appendCode(Name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW the NOTE: comment above should be removed now I think?

if (Kind == index::SymbolKind::IncludeDirective) {
Header.appendCode(Name);

if (!Definition.empty())
Output.addParagraph().appendCode(Definition);

if (!UsedSymbolNames.empty()) {
Output.addRuler();
usedSymbolNamesToMarkup(Output);
}

return Output;
}

if (!Definition.empty()) {
Output.addRuler();
definitionScopeToMarkup(Output);
} else {
Header.appendCode(Name);
}

if (!Provider.empty()) {
providerToMarkupParagraph(Output);
}

// Put a linebreak after header to increase readability.
Output.addRuler();
// Print Types on their own lines to reduce chances of getting line-wrapped by
// editor, as they might be long.
if (ReturnType) {
// For functions we display signature in a list form, e.g.:
// → `x`
// Parameters:
// - `bool param1`
// - `int param2 = 5`
Output.addParagraph().appendText("→ ").appendCode(
llvm::to_string(*ReturnType));
}

SymbolDocCommentVisitor SymbolDoc(Documentation, CommentOpts);

if (SymbolDoc.hasBriefCommand()) {
SymbolDoc.briefToMarkup(Output.addParagraph());
Output.addRuler();
}

// For functions we display signature in a list form, e.g.:
// Template Parameters:
// - `typename T` - description
// Parameters:
// - `bool param1` - description
// - `int param2 = 5` - description
// Returns
// `type` - description
if (TemplateParameters && !TemplateParameters->empty()) {
Output.addParagraph().appendBoldText("Template Parameters:");
markup::BulletList &L = Output.addBulletList();
for (const auto &Param : *TemplateParameters) {
markup::Paragraph &P = L.addItem().addParagraph();
P.appendCode(llvm::to_string(Param));
if (SymbolDoc.isTemplateTypeParmDocumented(llvm::to_string(Param.Name))) {
P.appendText(" - ");
SymbolDoc.templateTypeParmDocToMarkup(llvm::to_string(Param.Name), P);
}
}
Output.addRuler();
}

if (Parameters && !Parameters->empty()) {
Output.addParagraph().appendText("Parameters:");
Output.addParagraph().appendBoldText("Parameters:");
markup::BulletList &L = Output.addBulletList();
for (const auto &Param : *Parameters) {
markup::Paragraph &P = L.addItem().addParagraph();
P.appendCode(llvm::to_string(Param));

if (SymbolDoc.isParameterDocumented(llvm::to_string(Param.Name))) {
P.appendText(" -");
P.appendText(" - ");
SymbolDoc.parameterDocToMarkup(llvm::to_string(Param.Name), P);
}
}
Output.addRuler();
}

// Print Types on their own lines to reduce chances of getting line-wrapped by
// editor, as they might be long.
if (ReturnType &&
((ReturnType->Type != "void" && !ReturnType->AKA.has_value()) ||
(ReturnType->AKA.has_value() && ReturnType->AKA != "void"))) {
Output.addParagraph().appendBoldText("Returns:");
markup::Paragraph &P = Output.addParagraph();
P.appendCode(llvm::to_string(*ReturnType));

if (SymbolDoc.hasReturnCommand()) {
P.appendText(" - ");
SymbolDoc.returnToMarkup(P);
}
Output.addRuler();
}

// add specially handled doxygen commands.
SymbolDoc.warningsToMarkup(Output);
SymbolDoc.notesToMarkup(Output);

// add any other documentation.
SymbolDoc.docToMarkup(Output);

Output.addRuler();

// Don't print Type after Parameters or ReturnType as this will just duplicate
// the information
if (Type && !ReturnType && !Parameters)
Expand All @@ -1561,13 +1620,6 @@ markup::Document HoverInfo::presentDoxygen() const {
calleeArgInfoToMarkupParagraph(Output.addParagraph());
}

SymbolDoc.docToMarkup(Output);

if (!Definition.empty()) {
Output.addRuler();
definitionScopeToMarkup(Output);
}

if (!UsedSymbolNames.empty()) {
Output.addRuler();
usedSymbolNamesToMarkup(Output);
Expand All @@ -1591,7 +1643,8 @@ markup::Document HoverInfo::presentDefault() const {
// level 1 and 2 headers in a huge font, see
// https://github.com/microsoft/vscode/issues/88417 for details.
markup::Paragraph &Header = Output.addHeading(3);
if (Kind != index::SymbolKind::Unknown)
if (Kind != index::SymbolKind::Unknown &&
Kind != index::SymbolKind::IncludeDirective)
Header.appendText(index::getSymbolKindString(Kind)).appendSpace();
assert(!Name.empty() && "hover triggered on a nameless symbol");
Header.appendCode(Name);
Expand All @@ -1615,7 +1668,7 @@ markup::Document HoverInfo::presentDefault() const {
}

if (Parameters && !Parameters->empty()) {
Output.addParagraph().appendText("Parameters: ");
Output.addParagraph().appendText("Parameters:");
markup::BulletList &L = Output.addBulletList();
for (const auto &Param : *Parameters)
L.addItem().addParagraph().appendCode(llvm::to_string(Param));
Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/clangd/Quality.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ categorize(const index::SymbolInfo &D) {
case index::SymbolKind::Parameter:
case index::SymbolKind::NonTypeTemplateParm:
return SymbolQualitySignals::Variable;
// FIXME: for backwards compatibility, the include directive kind is treated
// the same as Unknown
case index::SymbolKind::IncludeDirective:
case index::SymbolKind::Using:
case index::SymbolKind::Module:
case index::SymbolKind::Unknown:
Expand Down
103 changes: 96 additions & 7 deletions clang-tools-extra/clangd/SymbolDocumentation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ void commandToMarkup(markup::Paragraph &Out, StringRef Command,
comments::CommandMarkerKind CommandMarker,
StringRef Args) {
Out.appendBoldText(commandMarkerAsString(CommandMarker) + Command.str());
Out.appendSpace();
if (!Args.empty()) {
Out.appendSpace();
Out.appendEmphasizedText(Args.str());
}
}
Expand Down Expand Up @@ -132,7 +132,8 @@ class ParagraphToMarkupDocument
const comments::CommandTraits &Traits;

/// If true, the next leading space after a new line is trimmed.
bool LastChunkEndsWithNewline = false;
/// Initially set it to true, to always trim the first text line.
bool LastChunkEndsWithNewline = true;
};

class ParagraphToString
Expand Down Expand Up @@ -263,8 +264,76 @@ class BlockCommentToMarkupDocument
StringRef CommentEscapeMarker;
};

void SymbolDocCommentVisitor::parameterDocToMarkup(StringRef ParamName,
markup::Paragraph &Out) {
void SymbolDocCommentVisitor::visitBlockCommandComment(
const comments::BlockCommandComment *B) {
switch (B->getCommandID()) {
case comments::CommandTraits::KCI_brief: {
if (!BriefParagraph) {
BriefParagraph = B->getParagraph();
return;
}
break;
}
case comments::CommandTraits::KCI_return:
case comments::CommandTraits::KCI_returns:
if (!ReturnParagraph) {
ReturnParagraph = B->getParagraph();
return;
}
break;
case comments::CommandTraits::KCI_retval:
RetvalParagraphs.push_back(B->getParagraph());
return;
case comments::CommandTraits::KCI_warning:
WarningParagraphs.push_back(B->getParagraph());
return;
case comments::CommandTraits::KCI_note:
NoteParagraphs.push_back(B->getParagraph());
return;
default:
break;
}

// For all other commands, we store them in the UnhandledCommands map.
// This allows us to keep the order of the comments.
UnhandledCommands[CommentPartIndex] = B;
CommentPartIndex++;
}

void SymbolDocCommentVisitor::paragraphsToMarkup(
markup::Document &Out,
const llvm::SmallVectorImpl<const comments::ParagraphComment *> &Paragraphs)
const {
if (Paragraphs.empty())
return;

for (const auto *P : Paragraphs) {
ParagraphToMarkupDocument(Out.addParagraph(), Traits).visit(P);
}
}

void SymbolDocCommentVisitor::briefToMarkup(markup::Paragraph &Out) const {
if (!BriefParagraph)
return;
ParagraphToMarkupDocument(Out, Traits).visit(BriefParagraph);
}

void SymbolDocCommentVisitor::returnToMarkup(markup::Paragraph &Out) const {
if (!ReturnParagraph)
return;
ParagraphToMarkupDocument(Out, Traits).visit(ReturnParagraph);
}

void SymbolDocCommentVisitor::notesToMarkup(markup::Document &Out) const {
paragraphsToMarkup(Out, NoteParagraphs);
}

void SymbolDocCommentVisitor::warningsToMarkup(markup::Document &Out) const {
paragraphsToMarkup(Out, WarningParagraphs);
}

void SymbolDocCommentVisitor::parameterDocToMarkup(
StringRef ParamName, markup::Paragraph &Out) const {
if (ParamName.empty())
return;

Expand All @@ -274,7 +343,7 @@ void SymbolDocCommentVisitor::parameterDocToMarkup(StringRef ParamName,
}

void SymbolDocCommentVisitor::parameterDocToString(
StringRef ParamName, llvm::raw_string_ostream &Out) {
StringRef ParamName, llvm::raw_string_ostream &Out) const {
if (ParamName.empty())
return;

Expand All @@ -283,15 +352,35 @@ void SymbolDocCommentVisitor::parameterDocToString(
}
}

void SymbolDocCommentVisitor::docToMarkup(markup::Document &Out) {
void SymbolDocCommentVisitor::docToMarkup(markup::Document &Out) const {
for (unsigned I = 0; I < CommentPartIndex; ++I) {
if (const auto *BC = BlockCommands.lookup(I)) {
if (const auto *BC = UnhandledCommands.lookup(I)) {
BlockCommentToMarkupDocument(Out, Traits).visit(BC);
} else if (const auto *P = FreeParagraphs.lookup(I)) {
ParagraphToMarkupDocument(Out.addParagraph(), Traits).visit(P);
}
}
}

void SymbolDocCommentVisitor::templateTypeParmDocToMarkup(
StringRef TemplateParamName, markup::Paragraph &Out) const {
if (TemplateParamName.empty())
return;

if (const auto *TP = TemplateParameters.lookup(TemplateParamName)) {
ParagraphToMarkupDocument(Out, Traits).visit(TP->getParagraph());
}
}

void SymbolDocCommentVisitor::templateTypeParmDocToString(
StringRef TemplateParamName, llvm::raw_string_ostream &Out) const {
if (TemplateParamName.empty())
return;

if (const auto *P = TemplateParameters.lookup(TemplateParamName)) {
ParagraphToString(Out, Traits).visit(P->getParagraph());
}
}

} // namespace clangd
} // namespace clang
Loading
Loading