1 //===- CXComment.cpp - libclang APIs for manipulating CXComments ----------===//
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 // This file defines all libclang APIs related to walking comment AST.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "CXComment.h"
14 #include "CXCursor.h"
15 #include "CXString.h"
16 #include "clang-c/Documentation.h"
17 #include "clang-c/Index.h"
18 #include "clang/AST/Decl.h"
19 #include "clang/Index/CommentToXML.h"
20 #include "llvm/ADT/StringExtras.h"
21 #include "llvm/Support/ErrorHandling.h"
22 #include <climits>
23
24 using namespace clang;
25 using namespace clang::comments;
26 using namespace clang::cxcomment;
27
clang_Cursor_getParsedComment(CXCursor C)28 CXComment clang_Cursor_getParsedComment(CXCursor C) {
29 using namespace clang::cxcursor;
30
31 if (!clang_isDeclaration(C.kind))
32 return createCXComment(nullptr, nullptr);
33
34 const Decl *D = getCursorDecl(C);
35 const ASTContext &Context = getCursorContext(C);
36 const FullComment *FC = Context.getCommentForDecl(D, /*PP=*/nullptr);
37
38 return createCXComment(FC, getCursorTU(C));
39 }
40
clang_Comment_getKind(CXComment CXC)41 enum CXCommentKind clang_Comment_getKind(CXComment CXC) {
42 const Comment *C = getASTNode(CXC);
43 if (!C)
44 return CXComment_Null;
45
46 switch (C->getCommentKind()) {
47 case Comment::NoCommentKind:
48 return CXComment_Null;
49
50 case Comment::TextCommentKind:
51 return CXComment_Text;
52
53 case Comment::InlineCommandCommentKind:
54 return CXComment_InlineCommand;
55
56 case Comment::HTMLStartTagCommentKind:
57 return CXComment_HTMLStartTag;
58
59 case Comment::HTMLEndTagCommentKind:
60 return CXComment_HTMLEndTag;
61
62 case Comment::ParagraphCommentKind:
63 return CXComment_Paragraph;
64
65 case Comment::BlockCommandCommentKind:
66 return CXComment_BlockCommand;
67
68 case Comment::ParamCommandCommentKind:
69 return CXComment_ParamCommand;
70
71 case Comment::TParamCommandCommentKind:
72 return CXComment_TParamCommand;
73
74 case Comment::VerbatimBlockCommentKind:
75 return CXComment_VerbatimBlockCommand;
76
77 case Comment::VerbatimBlockLineCommentKind:
78 return CXComment_VerbatimBlockLine;
79
80 case Comment::VerbatimLineCommentKind:
81 return CXComment_VerbatimLine;
82
83 case Comment::FullCommentKind:
84 return CXComment_FullComment;
85 }
86 llvm_unreachable("unknown CommentKind");
87 }
88
clang_Comment_getNumChildren(CXComment CXC)89 unsigned clang_Comment_getNumChildren(CXComment CXC) {
90 const Comment *C = getASTNode(CXC);
91 if (!C)
92 return 0;
93
94 return C->child_count();
95 }
96
clang_Comment_getChild(CXComment CXC,unsigned ChildIdx)97 CXComment clang_Comment_getChild(CXComment CXC, unsigned ChildIdx) {
98 const Comment *C = getASTNode(CXC);
99 if (!C || ChildIdx >= C->child_count())
100 return createCXComment(nullptr, nullptr);
101
102 return createCXComment(*(C->child_begin() + ChildIdx), CXC.TranslationUnit);
103 }
104
clang_Comment_isWhitespace(CXComment CXC)105 unsigned clang_Comment_isWhitespace(CXComment CXC) {
106 const Comment *C = getASTNode(CXC);
107 if (!C)
108 return false;
109
110 if (const TextComment *TC = dyn_cast<TextComment>(C))
111 return TC->isWhitespace();
112
113 if (const ParagraphComment *PC = dyn_cast<ParagraphComment>(C))
114 return PC->isWhitespace();
115
116 return false;
117 }
118
clang_InlineContentComment_hasTrailingNewline(CXComment CXC)119 unsigned clang_InlineContentComment_hasTrailingNewline(CXComment CXC) {
120 const InlineContentComment *ICC = getASTNodeAs<InlineContentComment>(CXC);
121 if (!ICC)
122 return false;
123
124 return ICC->hasTrailingNewline();
125 }
126
clang_TextComment_getText(CXComment CXC)127 CXString clang_TextComment_getText(CXComment CXC) {
128 const TextComment *TC = getASTNodeAs<TextComment>(CXC);
129 if (!TC)
130 return cxstring::createNull();
131
132 return cxstring::createRef(TC->getText());
133 }
134
clang_InlineCommandComment_getCommandName(CXComment CXC)135 CXString clang_InlineCommandComment_getCommandName(CXComment CXC) {
136 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
137 if (!ICC)
138 return cxstring::createNull();
139
140 const CommandTraits &Traits = getCommandTraits(CXC);
141 return cxstring::createRef(ICC->getCommandName(Traits));
142 }
143
144 enum CXCommentInlineCommandRenderKind
clang_InlineCommandComment_getRenderKind(CXComment CXC)145 clang_InlineCommandComment_getRenderKind(CXComment CXC) {
146 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
147 if (!ICC)
148 return CXCommentInlineCommandRenderKind_Normal;
149
150 switch (ICC->getRenderKind()) {
151 case InlineCommandComment::RenderNormal:
152 return CXCommentInlineCommandRenderKind_Normal;
153
154 case InlineCommandComment::RenderBold:
155 return CXCommentInlineCommandRenderKind_Bold;
156
157 case InlineCommandComment::RenderMonospaced:
158 return CXCommentInlineCommandRenderKind_Monospaced;
159
160 case InlineCommandComment::RenderEmphasized:
161 return CXCommentInlineCommandRenderKind_Emphasized;
162
163 case InlineCommandComment::RenderAnchor:
164 return CXCommentInlineCommandRenderKind_Anchor;
165 }
166 llvm_unreachable("unknown InlineCommandComment::RenderKind");
167 }
168
clang_InlineCommandComment_getNumArgs(CXComment CXC)169 unsigned clang_InlineCommandComment_getNumArgs(CXComment CXC) {
170 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
171 if (!ICC)
172 return 0;
173
174 return ICC->getNumArgs();
175 }
176
clang_InlineCommandComment_getArgText(CXComment CXC,unsigned ArgIdx)177 CXString clang_InlineCommandComment_getArgText(CXComment CXC,
178 unsigned ArgIdx) {
179 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
180 if (!ICC || ArgIdx >= ICC->getNumArgs())
181 return cxstring::createNull();
182
183 return cxstring::createRef(ICC->getArgText(ArgIdx));
184 }
185
clang_HTMLTagComment_getTagName(CXComment CXC)186 CXString clang_HTMLTagComment_getTagName(CXComment CXC) {
187 const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
188 if (!HTC)
189 return cxstring::createNull();
190
191 return cxstring::createRef(HTC->getTagName());
192 }
193
clang_HTMLStartTagComment_isSelfClosing(CXComment CXC)194 unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment CXC) {
195 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
196 if (!HST)
197 return false;
198
199 return HST->isSelfClosing();
200 }
201
clang_HTMLStartTag_getNumAttrs(CXComment CXC)202 unsigned clang_HTMLStartTag_getNumAttrs(CXComment CXC) {
203 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
204 if (!HST)
205 return 0;
206
207 return HST->getNumAttrs();
208 }
209
clang_HTMLStartTag_getAttrName(CXComment CXC,unsigned AttrIdx)210 CXString clang_HTMLStartTag_getAttrName(CXComment CXC, unsigned AttrIdx) {
211 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
212 if (!HST || AttrIdx >= HST->getNumAttrs())
213 return cxstring::createNull();
214
215 return cxstring::createRef(HST->getAttr(AttrIdx).Name);
216 }
217
clang_HTMLStartTag_getAttrValue(CXComment CXC,unsigned AttrIdx)218 CXString clang_HTMLStartTag_getAttrValue(CXComment CXC, unsigned AttrIdx) {
219 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
220 if (!HST || AttrIdx >= HST->getNumAttrs())
221 return cxstring::createNull();
222
223 return cxstring::createRef(HST->getAttr(AttrIdx).Value);
224 }
225
clang_BlockCommandComment_getCommandName(CXComment CXC)226 CXString clang_BlockCommandComment_getCommandName(CXComment CXC) {
227 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
228 if (!BCC)
229 return cxstring::createNull();
230
231 const CommandTraits &Traits = getCommandTraits(CXC);
232 return cxstring::createRef(BCC->getCommandName(Traits));
233 }
234
clang_BlockCommandComment_getNumArgs(CXComment CXC)235 unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC) {
236 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
237 if (!BCC)
238 return 0;
239
240 return BCC->getNumArgs();
241 }
242
clang_BlockCommandComment_getArgText(CXComment CXC,unsigned ArgIdx)243 CXString clang_BlockCommandComment_getArgText(CXComment CXC,
244 unsigned ArgIdx) {
245 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
246 if (!BCC || ArgIdx >= BCC->getNumArgs())
247 return cxstring::createNull();
248
249 return cxstring::createRef(BCC->getArgText(ArgIdx));
250 }
251
clang_BlockCommandComment_getParagraph(CXComment CXC)252 CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) {
253 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
254 if (!BCC)
255 return createCXComment(nullptr, nullptr);
256
257 return createCXComment(BCC->getParagraph(), CXC.TranslationUnit);
258 }
259
clang_ParamCommandComment_getParamName(CXComment CXC)260 CXString clang_ParamCommandComment_getParamName(CXComment CXC) {
261 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
262 if (!PCC || !PCC->hasParamName())
263 return cxstring::createNull();
264
265 return cxstring::createRef(PCC->getParamNameAsWritten());
266 }
267
clang_ParamCommandComment_isParamIndexValid(CXComment CXC)268 unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) {
269 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
270 if (!PCC)
271 return false;
272
273 return PCC->isParamIndexValid();
274 }
275
clang_ParamCommandComment_getParamIndex(CXComment CXC)276 unsigned clang_ParamCommandComment_getParamIndex(CXComment CXC) {
277 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
278 if (!PCC || !PCC->isParamIndexValid() || PCC->isVarArgParam())
279 return ParamCommandComment::InvalidParamIndex;
280
281 return PCC->getParamIndex();
282 }
283
clang_ParamCommandComment_isDirectionExplicit(CXComment CXC)284 unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment CXC) {
285 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
286 if (!PCC)
287 return false;
288
289 return PCC->isDirectionExplicit();
290 }
291
clang_ParamCommandComment_getDirection(CXComment CXC)292 enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection(
293 CXComment CXC) {
294 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
295 if (!PCC)
296 return CXCommentParamPassDirection_In;
297
298 switch (PCC->getDirection()) {
299 case ParamCommandComment::In:
300 return CXCommentParamPassDirection_In;
301
302 case ParamCommandComment::Out:
303 return CXCommentParamPassDirection_Out;
304
305 case ParamCommandComment::InOut:
306 return CXCommentParamPassDirection_InOut;
307 }
308 llvm_unreachable("unknown ParamCommandComment::PassDirection");
309 }
310
clang_TParamCommandComment_getParamName(CXComment CXC)311 CXString clang_TParamCommandComment_getParamName(CXComment CXC) {
312 const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
313 if (!TPCC || !TPCC->hasParamName())
314 return cxstring::createNull();
315
316 return cxstring::createRef(TPCC->getParamNameAsWritten());
317 }
318
clang_TParamCommandComment_isParamPositionValid(CXComment CXC)319 unsigned clang_TParamCommandComment_isParamPositionValid(CXComment CXC) {
320 const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
321 if (!TPCC)
322 return false;
323
324 return TPCC->isPositionValid();
325 }
326
clang_TParamCommandComment_getDepth(CXComment CXC)327 unsigned clang_TParamCommandComment_getDepth(CXComment CXC) {
328 const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
329 if (!TPCC || !TPCC->isPositionValid())
330 return 0;
331
332 return TPCC->getDepth();
333 }
334
clang_TParamCommandComment_getIndex(CXComment CXC,unsigned Depth)335 unsigned clang_TParamCommandComment_getIndex(CXComment CXC, unsigned Depth) {
336 const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
337 if (!TPCC || !TPCC->isPositionValid() || Depth >= TPCC->getDepth())
338 return 0;
339
340 return TPCC->getIndex(Depth);
341 }
342
clang_VerbatimBlockLineComment_getText(CXComment CXC)343 CXString clang_VerbatimBlockLineComment_getText(CXComment CXC) {
344 const VerbatimBlockLineComment *VBL =
345 getASTNodeAs<VerbatimBlockLineComment>(CXC);
346 if (!VBL)
347 return cxstring::createNull();
348
349 return cxstring::createRef(VBL->getText());
350 }
351
clang_VerbatimLineComment_getText(CXComment CXC)352 CXString clang_VerbatimLineComment_getText(CXComment CXC) {
353 const VerbatimLineComment *VLC = getASTNodeAs<VerbatimLineComment>(CXC);
354 if (!VLC)
355 return cxstring::createNull();
356
357 return cxstring::createRef(VLC->getText());
358 }
359
360 //===----------------------------------------------------------------------===//
361 // Converting comments to XML.
362 //===----------------------------------------------------------------------===//
363
clang_HTMLTagComment_getAsString(CXComment CXC)364 CXString clang_HTMLTagComment_getAsString(CXComment CXC) {
365 const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
366 if (!HTC)
367 return cxstring::createNull();
368
369 CXTranslationUnit TU = CXC.TranslationUnit;
370 if (!TU->CommentToXML)
371 TU->CommentToXML = new clang::index::CommentToXMLConverter();
372
373 SmallString<128> Text;
374 TU->CommentToXML->convertHTMLTagNodeToText(
375 HTC, Text, cxtu::getASTUnit(TU)->getASTContext());
376 return cxstring::createDup(Text.str());
377 }
378
clang_FullComment_getAsHTML(CXComment CXC)379 CXString clang_FullComment_getAsHTML(CXComment CXC) {
380 const FullComment *FC = getASTNodeAs<FullComment>(CXC);
381 if (!FC)
382 return cxstring::createNull();
383
384 CXTranslationUnit TU = CXC.TranslationUnit;
385 if (!TU->CommentToXML)
386 TU->CommentToXML = new clang::index::CommentToXMLConverter();
387
388 SmallString<1024> HTML;
389 TU->CommentToXML
390 ->convertCommentToHTML(FC, HTML, cxtu::getASTUnit(TU)->getASTContext());
391 return cxstring::createDup(HTML.str());
392 }
393
clang_FullComment_getAsXML(CXComment CXC)394 CXString clang_FullComment_getAsXML(CXComment CXC) {
395 const FullComment *FC = getASTNodeAs<FullComment>(CXC);
396 if (!FC)
397 return cxstring::createNull();
398
399 CXTranslationUnit TU = CXC.TranslationUnit;
400 if (!TU->CommentToXML)
401 TU->CommentToXML = new clang::index::CommentToXMLConverter();
402
403 SmallString<1024> XML;
404 TU->CommentToXML
405 ->convertCommentToXML(FC, XML, cxtu::getASTUnit(TU)->getASTContext());
406 return cxstring::createDup(XML.str());
407 }
408
409