clang-tools 22.0.0git
SymbolDocumentation.h
Go to the documentation of this file.
1//===--- SymbolDocumentation.h ==---------------------------------*- C++-*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Class to parse doxygen comments into a flat structure for consumption
10// in e.g. Hover and Code Completion
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SYMBOLDOCUMENTATION_H
15#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SYMBOLDOCUMENTATION_H
16
17#include "support/Markup.h"
18#include "clang/AST/Comment.h"
19#include "clang/AST/CommentLexer.h"
20#include "clang/AST/CommentParser.h"
21#include "clang/AST/CommentSema.h"
22#include "clang/AST/CommentVisitor.h"
23#include "clang/Basic/SourceManager.h"
24#include "llvm/Support/raw_ostream.h"
25#include <string>
26
27namespace clang {
28namespace clangd {
29
31 : public comments::ConstCommentVisitor<SymbolDocCommentVisitor> {
32public:
33 SymbolDocCommentVisitor(comments::FullComment *FC,
34 const CommentOptions &CommentOpts)
35 : Traits(Allocator, CommentOpts), Allocator() {
36 if (!FC)
37 return;
38
39 for (auto *Block : FC->getBlocks()) {
40 visit(Block);
41 }
42 }
43
44 SymbolDocCommentVisitor(llvm::StringRef Documentation,
45 const CommentOptions &CommentOpts)
46 : Traits(Allocator, CommentOpts), Allocator() {
47
48 if (Documentation.empty())
49 return;
50
51 CommentWithMarkers.reserve(Documentation.size() +
52 Documentation.count('\n') * 3);
53
54 // The comment lexer expects doxygen markers, so add them back.
55 // We need to use the /// style doxygen markers because the comment could
56 // contain the closing the closing tag "*/" of a C Style "/** */" comment
57 // which would break the parsing if we would just enclose the comment text
58 // with "/** */".
59 CommentWithMarkers = "///";
60 bool NewLine = true;
61 for (char C : Documentation) {
62 if (C == '\n') {
63 CommentWithMarkers += "\n///";
64 NewLine = true;
65 } else {
66 if (NewLine && (C == '<')) {
67 // A comment line starting with '///<' is treated as a doxygen
68 // comment. Therefore add a space to separate the '<' from the comment
69 // marker. This allows to parse html tags at the beginning of a line
70 // and the escape marker prevents adding the artificial space in the
71 // markup documentation. The extra space will not be rendered, since
72 // we render it as markdown.
73 CommentWithMarkers += ' ';
74 }
75 CommentWithMarkers += C;
76 NewLine = false;
77 }
78 }
79 SourceManagerForFile SourceMgrForFile("mock_file.cpp", CommentWithMarkers);
80
81 SourceManager &SourceMgr = SourceMgrForFile.get();
82 // The doxygen Sema requires a Diagostics consumer, since it reports
83 // warnings e.g. when parameters are not documented correctly. These
84 // warnings are not relevant for us, so we can ignore them.
85 SourceMgr.getDiagnostics().setClient(new IgnoringDiagConsumer);
86
87 comments::Sema S(Allocator, SourceMgr, SourceMgr.getDiagnostics(), Traits,
88 /*PP=*/nullptr);
89 comments::Lexer L(Allocator, SourceMgr.getDiagnostics(), Traits,
90 SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()),
91 CommentWithMarkers.data(),
92 CommentWithMarkers.data() + CommentWithMarkers.size());
93 comments::Parser P(L, S, Allocator, SourceMgr, SourceMgr.getDiagnostics(),
94 Traits);
95 comments::FullComment *FC = P.parseFullComment();
96
97 if (!FC)
98 return;
99
100 for (auto *Block : FC->getBlocks()) {
101 visit(Block);
102 }
103 }
104
105 bool isParameterDocumented(StringRef ParamName) const {
106 return Parameters.contains(ParamName);
107 }
108
109 bool isTemplateTypeParmDocumented(StringRef ParamName) const {
110 return TemplateParameters.contains(ParamName);
111 }
112
113 bool hasBriefCommand() const { return BriefParagraph; }
114
115 bool hasReturnCommand() const { return ReturnParagraph; }
116
117 bool hasRetvalCommands() const { return !RetvalParagraphs.empty(); }
118
119 bool hasNoteCommands() const { return !NoteParagraphs.empty(); }
120
121 bool hasWarningCommands() const { return !WarningParagraphs.empty(); }
122
123 /// Converts all unhandled comment commands to a markup document.
124 void docToMarkup(markup::Document &Out) const;
125 /// Converts the "brief" command(s) to a markup document.
126 void briefToMarkup(markup::Paragraph &Out) const;
127 /// Converts the "return" command(s) to a markup document.
128 void returnToMarkup(markup::Paragraph &Out) const;
129 /// Converts the "note" command(s) to a markup document.
130 void notesToMarkup(markup::Document &Out) const;
131 /// Converts the "warning" command(s) to a markup document.
132 void warningsToMarkup(markup::Document &Out) const;
133
134 void visitBlockCommandComment(const comments::BlockCommandComment *B);
135
136 void templateTypeParmDocToMarkup(StringRef TemplateParamName,
137 markup::Paragraph &Out) const;
138
139 void templateTypeParmDocToString(StringRef TemplateParamName,
140 llvm::raw_string_ostream &Out) const;
141
142 void parameterDocToMarkup(StringRef ParamName, markup::Paragraph &Out) const;
143
144 void parameterDocToString(StringRef ParamName,
145 llvm::raw_string_ostream &Out) const;
146
147 void visitParagraphComment(const comments::ParagraphComment *P) {
148 FreeParagraphs[CommentPartIndex] = P;
149 CommentPartIndex++;
150 }
151
152 void visitParamCommandComment(const comments::ParamCommandComment *P) {
153 Parameters[P->getParamNameAsWritten()] = P;
154 }
155
156 void visitTParamCommandComment(const comments::TParamCommandComment *TP) {
157 TemplateParameters[TP->getParamNameAsWritten()] = std::move(TP);
158 }
159
160private:
161 comments::CommandTraits Traits;
162 llvm::BumpPtrAllocator Allocator;
163 std::string CommentWithMarkers;
164
165 /// Index to keep track of the order of the comments.
166 /// We want to rearange some commands like \\param.
167 /// This index allows us to keep the order of the other comment parts.
168 unsigned CommentPartIndex = 0;
169
170 /// Paragraph of the "brief" command.
171 const comments::ParagraphComment *BriefParagraph = nullptr;
172
173 /// Paragraph of the "return" command.
174 const comments::ParagraphComment *ReturnParagraph = nullptr;
175
176 /// Paragraph(s) of the "note" command(s)
177 llvm::SmallVector<const comments::ParagraphComment *> RetvalParagraphs;
178
179 /// Paragraph(s) of the "note" command(s)
180 llvm::SmallVector<const comments::ParagraphComment *> NoteParagraphs;
181
182 /// Paragraph(s) of the "warning" command(s)
183 llvm::SmallVector<const comments::ParagraphComment *> WarningParagraphs;
184
185 /// All the paragraphs we don't have any special handling for,
186 /// e.g. "details".
187 llvm::SmallDenseMap<unsigned, const comments::BlockCommandComment *>
188 UnhandledCommands;
189
190 /// Parsed paragaph(s) of the "param" comamnd(s)
191 llvm::SmallDenseMap<StringRef, const comments::ParamCommandComment *>
192 Parameters;
193
194 /// Parsed paragaph(s) of the "tparam" comamnd(s)
195 llvm::SmallDenseMap<StringRef, const comments::TParamCommandComment *>
196 TemplateParameters;
197
198 /// All "free" text paragraphs.
199 llvm::SmallDenseMap<unsigned, const comments::ParagraphComment *>
200 FreeParagraphs;
201
202 void paragraphsToMarkup(
203 markup::Document &Out,
205 &Paragraphs) const;
206};
207
208} // namespace clangd
209} // namespace clang
210
211#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_SYMBOLDOCUMENTATION_H
void visitParagraphComment(const comments::ParagraphComment *P)
void notesToMarkup(markup::Document &Out) const
Converts the "note" command(s) to a markup document.
void visitParamCommandComment(const comments::ParamCommandComment *P)
void visitTParamCommandComment(const comments::TParamCommandComment *TP)
void docToMarkup(markup::Document &Out) const
Converts all unhandled comment commands to a markup document.
bool isTemplateTypeParmDocumented(StringRef ParamName) const
SymbolDocCommentVisitor(llvm::StringRef Documentation, const CommentOptions &CommentOpts)
void templateTypeParmDocToMarkup(StringRef TemplateParamName, markup::Paragraph &Out) const
void returnToMarkup(markup::Paragraph &Out) const
Converts the "return" command(s) to a markup document.
void parameterDocToMarkup(StringRef ParamName, markup::Paragraph &Out) const
void templateTypeParmDocToString(StringRef TemplateParamName, llvm::raw_string_ostream &Out) const
void parameterDocToString(StringRef ParamName, llvm::raw_string_ostream &Out) const
void visitBlockCommandComment(const comments::BlockCommandComment *B)
SymbolDocCommentVisitor(comments::FullComment *FC, const CommentOptions &CommentOpts)
void briefToMarkup(markup::Paragraph &Out) const
Converts the "brief" command(s) to a markup document.
void warningsToMarkup(markup::Document &Out) const
Converts the "warning" command(s) to a markup document.
bool isParameterDocumented(StringRef ParamName) const
Represents parts of the markup that can contain strings, like inline code, code block or plain text.
Definition Markup.h:45
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:44
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//