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