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 "clang-c/Documentation.h"
16#include "CXComment.h"
17#include "CXCursor.h"
18#include "CXString.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
26using namespace clang;
27using namespace clang::comments;
28using namespace clang::cxcomment;
29
30extern "C" {
31
32CXComment 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
45enum 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
93unsigned 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
101CXComment 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
109unsigned 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
123unsigned 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
131CXString 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
139CXString 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
148enum CXCommentInlineCommandRenderKind
149clang_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
170unsigned 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
178CXString 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
187CXString 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
195unsigned 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
203unsigned 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
211CXString 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
219CXString 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
227CXString 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
236unsigned 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
244CXString 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
253CXComment 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
261CXString 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
269unsigned 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
277unsigned 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
285unsigned 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
293enum 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
312CXString 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
320unsigned 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
328unsigned 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
336unsigned 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
344CXString 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
353CXString 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
365CXString 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
380CXString 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
395CXString 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