xref: /netbsd-src/external/apache2/llvm/dist/clang/tools/libclang/CXComment.cpp (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
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 
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 
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 
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 
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 
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 
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 
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 
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
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   llvm_unreachable("unknown InlineCommandComment::RenderKind");
164 }
165 
166 unsigned clang_InlineCommandComment_getNumArgs(CXComment CXC) {
167   const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
168   if (!ICC)
169     return 0;
170 
171   return ICC->getNumArgs();
172 }
173 
174 CXString clang_InlineCommandComment_getArgText(CXComment CXC,
175                                                unsigned ArgIdx) {
176   const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
177   if (!ICC || ArgIdx >= ICC->getNumArgs())
178     return cxstring::createNull();
179 
180   return cxstring::createRef(ICC->getArgText(ArgIdx));
181 }
182 
183 CXString clang_HTMLTagComment_getTagName(CXComment CXC) {
184   const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
185   if (!HTC)
186     return cxstring::createNull();
187 
188   return cxstring::createRef(HTC->getTagName());
189 }
190 
191 unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment CXC) {
192   const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
193   if (!HST)
194     return false;
195 
196   return HST->isSelfClosing();
197 }
198 
199 unsigned clang_HTMLStartTag_getNumAttrs(CXComment CXC) {
200   const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
201   if (!HST)
202     return 0;
203 
204   return HST->getNumAttrs();
205 }
206 
207 CXString clang_HTMLStartTag_getAttrName(CXComment CXC, unsigned AttrIdx) {
208   const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
209   if (!HST || AttrIdx >= HST->getNumAttrs())
210     return cxstring::createNull();
211 
212   return cxstring::createRef(HST->getAttr(AttrIdx).Name);
213 }
214 
215 CXString clang_HTMLStartTag_getAttrValue(CXComment CXC, unsigned AttrIdx) {
216   const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
217   if (!HST || AttrIdx >= HST->getNumAttrs())
218     return cxstring::createNull();
219 
220   return cxstring::createRef(HST->getAttr(AttrIdx).Value);
221 }
222 
223 CXString clang_BlockCommandComment_getCommandName(CXComment CXC) {
224   const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
225   if (!BCC)
226     return cxstring::createNull();
227 
228   const CommandTraits &Traits = getCommandTraits(CXC);
229   return cxstring::createRef(BCC->getCommandName(Traits));
230 }
231 
232 unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC) {
233   const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
234   if (!BCC)
235     return 0;
236 
237   return BCC->getNumArgs();
238 }
239 
240 CXString clang_BlockCommandComment_getArgText(CXComment CXC,
241                                               unsigned ArgIdx) {
242   const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
243   if (!BCC || ArgIdx >= BCC->getNumArgs())
244     return cxstring::createNull();
245 
246   return cxstring::createRef(BCC->getArgText(ArgIdx));
247 }
248 
249 CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) {
250   const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
251   if (!BCC)
252     return createCXComment(nullptr, nullptr);
253 
254   return createCXComment(BCC->getParagraph(), CXC.TranslationUnit);
255 }
256 
257 CXString clang_ParamCommandComment_getParamName(CXComment CXC) {
258   const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
259   if (!PCC || !PCC->hasParamName())
260     return cxstring::createNull();
261 
262   return cxstring::createRef(PCC->getParamNameAsWritten());
263 }
264 
265 unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) {
266   const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
267   if (!PCC)
268     return false;
269 
270   return PCC->isParamIndexValid();
271 }
272 
273 unsigned clang_ParamCommandComment_getParamIndex(CXComment CXC) {
274   const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
275   if (!PCC || !PCC->isParamIndexValid() || PCC->isVarArgParam())
276     return ParamCommandComment::InvalidParamIndex;
277 
278   return PCC->getParamIndex();
279 }
280 
281 unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment CXC) {
282   const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
283   if (!PCC)
284     return false;
285 
286   return PCC->isDirectionExplicit();
287 }
288 
289 enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection(
290                                                             CXComment CXC) {
291   const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
292   if (!PCC)
293     return CXCommentParamPassDirection_In;
294 
295   switch (PCC->getDirection()) {
296   case ParamCommandComment::In:
297     return CXCommentParamPassDirection_In;
298 
299   case ParamCommandComment::Out:
300     return CXCommentParamPassDirection_Out;
301 
302   case ParamCommandComment::InOut:
303     return CXCommentParamPassDirection_InOut;
304   }
305   llvm_unreachable("unknown ParamCommandComment::PassDirection");
306 }
307 
308 CXString clang_TParamCommandComment_getParamName(CXComment CXC) {
309   const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
310   if (!TPCC || !TPCC->hasParamName())
311     return cxstring::createNull();
312 
313   return cxstring::createRef(TPCC->getParamNameAsWritten());
314 }
315 
316 unsigned clang_TParamCommandComment_isParamPositionValid(CXComment CXC) {
317   const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
318   if (!TPCC)
319     return false;
320 
321   return TPCC->isPositionValid();
322 }
323 
324 unsigned clang_TParamCommandComment_getDepth(CXComment CXC) {
325   const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
326   if (!TPCC || !TPCC->isPositionValid())
327     return 0;
328 
329   return TPCC->getDepth();
330 }
331 
332 unsigned clang_TParamCommandComment_getIndex(CXComment CXC, unsigned Depth) {
333   const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
334   if (!TPCC || !TPCC->isPositionValid() || Depth >= TPCC->getDepth())
335     return 0;
336 
337   return TPCC->getIndex(Depth);
338 }
339 
340 CXString clang_VerbatimBlockLineComment_getText(CXComment CXC) {
341   const VerbatimBlockLineComment *VBL =
342       getASTNodeAs<VerbatimBlockLineComment>(CXC);
343   if (!VBL)
344     return cxstring::createNull();
345 
346   return cxstring::createRef(VBL->getText());
347 }
348 
349 CXString clang_VerbatimLineComment_getText(CXComment CXC) {
350   const VerbatimLineComment *VLC = getASTNodeAs<VerbatimLineComment>(CXC);
351   if (!VLC)
352     return cxstring::createNull();
353 
354   return cxstring::createRef(VLC->getText());
355 }
356 
357 //===----------------------------------------------------------------------===//
358 // Converting comments to XML.
359 //===----------------------------------------------------------------------===//
360 
361 CXString clang_HTMLTagComment_getAsString(CXComment CXC) {
362   const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
363   if (!HTC)
364     return cxstring::createNull();
365 
366   CXTranslationUnit TU = CXC.TranslationUnit;
367   if (!TU->CommentToXML)
368     TU->CommentToXML = new clang::index::CommentToXMLConverter();
369 
370   SmallString<128> Text;
371   TU->CommentToXML->convertHTMLTagNodeToText(
372       HTC, Text, cxtu::getASTUnit(TU)->getASTContext());
373   return cxstring::createDup(Text.str());
374 }
375 
376 CXString clang_FullComment_getAsHTML(CXComment CXC) {
377   const FullComment *FC = getASTNodeAs<FullComment>(CXC);
378   if (!FC)
379     return cxstring::createNull();
380 
381   CXTranslationUnit TU = CXC.TranslationUnit;
382   if (!TU->CommentToXML)
383     TU->CommentToXML = new clang::index::CommentToXMLConverter();
384 
385   SmallString<1024> HTML;
386   TU->CommentToXML
387       ->convertCommentToHTML(FC, HTML, cxtu::getASTUnit(TU)->getASTContext());
388   return cxstring::createDup(HTML.str());
389 }
390 
391 CXString clang_FullComment_getAsXML(CXComment CXC) {
392   const FullComment *FC = getASTNodeAs<FullComment>(CXC);
393   if (!FC)
394     return cxstring::createNull();
395 
396   CXTranslationUnit TU = CXC.TranslationUnit;
397   if (!TU->CommentToXML)
398     TU->CommentToXML = new clang::index::CommentToXMLConverter();
399 
400   SmallString<1024> XML;
401   TU->CommentToXML
402       ->convertCommentToXML(FC, XML, cxtu::getASTUnit(TU)->getASTContext());
403   return cxstring::createDup(XML.str());
404 }
405 
406