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