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