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/ADT/StringRef.h"
25#include "llvm/Support/raw_ostream.h"
26#include <string>
27
28namespace clang {
29namespace clangd {
30
32 : public comments::ConstCommentVisitor<SymbolDocCommentVisitor> {
33public:
34 SymbolDocCommentVisitor(comments::FullComment *FC,
35 const CommentOptions &CommentOpts)
36 : Traits(Allocator, CommentOpts), Allocator() {
37 if (!FC)
38 return;
39
40 for (auto *Block : FC->getBlocks()) {
41 visit(Block);
42 }
43 }
44
45 SymbolDocCommentVisitor(llvm::StringRef Documentation,
46 const CommentOptions &CommentOpts)
47 : Traits(Allocator, CommentOpts), Allocator() {
48
49 if (Documentation.empty())
50 return;
51
52 CommentWithMarkers.reserve(Documentation.size() +
53 Documentation.count('\n') * 3);
54
55 preprocessDocumentation(Documentation);
56
57 SourceManagerForFile SourceMgrForFile("mock_file.cpp", CommentWithMarkers);
58
59 SourceManager &SourceMgr = SourceMgrForFile.get();
60 // The doxygen Sema requires a Diagostics consumer, since it reports
61 // warnings e.g. when parameters are not documented correctly. These
62 // warnings are not relevant for us, so we can ignore them.
63 SourceMgr.getDiagnostics().setClient(new IgnoringDiagConsumer);
64
65 comments::Sema S(Allocator, SourceMgr, SourceMgr.getDiagnostics(), Traits,
66 /*PP=*/nullptr);
67 comments::Lexer L(Allocator, SourceMgr.getDiagnostics(), Traits,
68 SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()),
69 CommentWithMarkers.data(),
70 CommentWithMarkers.data() + CommentWithMarkers.size());
71 comments::Parser P(L, S, Allocator, SourceMgr, SourceMgr.getDiagnostics(),
72 Traits);
73 comments::FullComment *FC = P.parseFullComment();
74
75 if (!FC)
76 return;
77
78 for (auto *Block : FC->getBlocks()) {
79 visit(Block);
80 }
81
82 // If we have not seen a brief command, use the very first free paragraph as
83 // the brief.
84 if (!BriefParagraph && !FreeParagraphs.empty() &&
85 FreeParagraphs.contains(0)) {
86 BriefParagraph = FreeParagraphs.lookup(0);
87 FreeParagraphs.erase(0);
88 }
89 }
90
91 bool isParameterDocumented(StringRef ParamName) const {
92 return Parameters.contains(ParamName);
93 }
94
95 bool isTemplateTypeParmDocumented(StringRef ParamName) const {
96 return TemplateParameters.contains(ParamName);
97 }
98
99 bool hasBriefCommand() const { return BriefParagraph; }
100
101 bool hasReturnCommand() const { return ReturnParagraph; }
102
103 bool hasDetailedDoc() const {
104 return !FreeParagraphs.empty() || !BlockCommands.empty();
105 }
106
107 /// Converts all unhandled comment commands to a markup document.
108 void detailedDocToMarkup(markup::Document &Out) const;
109 /// Converts the "brief" command(s) to a markup document.
110 void briefToMarkup(markup::Paragraph &Out) const;
111 /// Converts the "return" command(s) to a markup document.
112 void returnToMarkup(markup::Paragraph &Out) const;
113 /// Converts the "retval" command(s) to a markup document.
114 void retvalsToMarkup(markup::Document &Out) const;
115
116 void visitBlockCommandComment(const comments::BlockCommandComment *B);
117
118 void templateTypeParmDocToMarkup(StringRef TemplateParamName,
119 markup::Paragraph &Out) const;
120
121 void templateTypeParmDocToString(StringRef TemplateParamName,
122 llvm::raw_string_ostream &Out) const;
123
124 void parameterDocToMarkup(StringRef ParamName, markup::Paragraph &Out) const;
125
126 void parameterDocToString(StringRef ParamName,
127 llvm::raw_string_ostream &Out) const;
128
129 void visitParagraphComment(const comments::ParagraphComment *P) {
130 if (!P->isWhitespace()) {
131 FreeParagraphs[CommentPartIndex] = P;
132 CommentPartIndex++;
133 }
134 }
135
136 void visitParamCommandComment(const comments::ParamCommandComment *P) {
137 Parameters[P->getParamNameAsWritten()] = P;
138 }
139
140 void visitTParamCommandComment(const comments::TParamCommandComment *TP) {
141 TemplateParameters[TP->getParamNameAsWritten()] = std::move(TP);
142 }
143
144 /// \brief Preprocesses the raw documentation string to prepare it for doxygen
145 /// parsing.
146 ///
147 /// This is a workaround to provide better support for markdown in
148 /// doxygen. Clang's doxygen parser e.g. does not handle markdown code blocks.
149 ///
150 /// The documentation string is preprocessed to replace some markdown
151 /// constructs with parsable doxygen commands. E.g. markdown code blocks are
152 /// replaced with doxygen \\code{.lang} ...
153 /// \\endcode blocks.
154 ///
155 /// Additionally, potential doxygen commands inside markdown
156 /// inline code spans are escaped to avoid that doxygen tries to interpret
157 /// them as commands.
158 ///
159 /// \note Although this is a workaround, it is very similar to what
160 /// doxygen itself does for markdown. In doxygen, the first parsing step is
161 /// also a markdown preprocessing step.
162 /// See https://www.doxygen.nl/manual/markdown.html
163 void preprocessDocumentation(StringRef Doc);
164
165private:
166 comments::CommandTraits Traits;
167 llvm::BumpPtrAllocator Allocator;
168 std::string CommentWithMarkers;
169
170 /// Index to keep track of the order of the comments.
171 /// We want to rearange some commands like \\param.
172 /// This index allows us to keep the order of the other comment parts.
173 unsigned CommentPartIndex = 0;
174
175 /// Paragraph of the "brief" command.
176 const comments::ParagraphComment *BriefParagraph = nullptr;
177
178 /// Paragraph of the "return" command.
179 const comments::ParagraphComment *ReturnParagraph = nullptr;
180
181 /// All the "retval" command(s)
182 llvm::SmallVector<const comments::BlockCommandComment *> RetvalCommands;
183
184 /// All the parsed doxygen block commands.
185 /// They might have special handling internally like \\note or \\warning
186 llvm::SmallDenseMap<unsigned, const comments::BlockCommandComment *>
187 BlockCommands;
188
189 /// Parsed paragaph(s) of the "param" comamnd(s)
190 llvm::SmallDenseMap<StringRef, const comments::ParamCommandComment *>
191 Parameters;
192
193 /// Parsed paragaph(s) of the "tparam" comamnd(s)
194 llvm::SmallDenseMap<StringRef, const comments::TParamCommandComment *>
195 TemplateParameters;
196
197 /// All "free" text paragraphs.
198 llvm::SmallDenseMap<unsigned, const comments::ParagraphComment *>
199 FreeParagraphs;
200};
201
202} // namespace clangd
203} // namespace clang
204
205#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_SYMBOLDOCUMENTATION_H
void visitParagraphComment(const comments::ParagraphComment *P)
void visitParamCommandComment(const comments::ParamCommandComment *P)
void visitTParamCommandComment(const comments::TParamCommandComment *TP)
void detailedDocToMarkup(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 preprocessDocumentation(StringRef Doc)
Preprocesses the raw documentation string to prepare it for doxygen parsing.
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.
bool isParameterDocumented(StringRef ParamName) const
void retvalsToMarkup(markup::Document &Out) const
Converts the "retval" command(s) to a markup document.
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:45
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//