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