Clang Project

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