1 //===- CXComment.cpp - libclang APIs for manipulating CXComments ----------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines all libclang APIs related to walking comment AST.
11 //===----------------------------------------------------------------------===//
13 #include "CXComment.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"
24 using namespace clang
;
25 using namespace clang::comments
;
26 using namespace clang::cxcomment
;
28 CXComment
clang_Cursor_getParsedComment(CXCursor C
) {
29 using namespace clang::cxcursor
;
31 if (!clang_isDeclaration(C
.kind
))
32 return createCXComment(nullptr, nullptr);
34 const Decl
*D
= getCursorDecl(C
);
35 const ASTContext
&Context
= getCursorContext(C
);
36 const FullComment
*FC
= Context
.getCommentForDecl(D
, /*PP=*/nullptr);
38 return createCXComment(FC
, getCursorTU(C
));
41 enum CXCommentKind
clang_Comment_getKind(CXComment CXC
) {
42 const Comment
*C
= getASTNode(CXC
);
44 return CXComment_Null
;
46 switch (C
->getCommentKind()) {
47 case Comment::NoCommentKind
:
48 return CXComment_Null
;
50 case Comment::TextCommentKind
:
51 return CXComment_Text
;
53 case Comment::InlineCommandCommentKind
:
54 return CXComment_InlineCommand
;
56 case Comment::HTMLStartTagCommentKind
:
57 return CXComment_HTMLStartTag
;
59 case Comment::HTMLEndTagCommentKind
:
60 return CXComment_HTMLEndTag
;
62 case Comment::ParagraphCommentKind
:
63 return CXComment_Paragraph
;
65 case Comment::BlockCommandCommentKind
:
66 return CXComment_BlockCommand
;
68 case Comment::ParamCommandCommentKind
:
69 return CXComment_ParamCommand
;
71 case Comment::TParamCommandCommentKind
:
72 return CXComment_TParamCommand
;
74 case Comment::VerbatimBlockCommentKind
:
75 return CXComment_VerbatimBlockCommand
;
77 case Comment::VerbatimBlockLineCommentKind
:
78 return CXComment_VerbatimBlockLine
;
80 case Comment::VerbatimLineCommentKind
:
81 return CXComment_VerbatimLine
;
83 case Comment::FullCommentKind
:
84 return CXComment_FullComment
;
86 llvm_unreachable("unknown CommentKind");
89 unsigned clang_Comment_getNumChildren(CXComment CXC
) {
90 const Comment
*C
= getASTNode(CXC
);
94 return C
->child_count();
97 CXComment
clang_Comment_getChild(CXComment CXC
, unsigned ChildIdx
) {
98 const Comment
*C
= getASTNode(CXC
);
99 if (!C
|| ChildIdx
>= C
->child_count())
100 return createCXComment(nullptr, nullptr);
102 return createCXComment(*(C
->child_begin() + ChildIdx
), CXC
.TranslationUnit
);
105 unsigned clang_Comment_isWhitespace(CXComment CXC
) {
106 const Comment
*C
= getASTNode(CXC
);
110 if (const TextComment
*TC
= dyn_cast
<TextComment
>(C
))
111 return TC
->isWhitespace();
113 if (const ParagraphComment
*PC
= dyn_cast
<ParagraphComment
>(C
))
114 return PC
->isWhitespace();
119 unsigned clang_InlineContentComment_hasTrailingNewline(CXComment CXC
) {
120 const InlineContentComment
*ICC
= getASTNodeAs
<InlineContentComment
>(CXC
);
124 return ICC
->hasTrailingNewline();
127 CXString
clang_TextComment_getText(CXComment CXC
) {
128 const TextComment
*TC
= getASTNodeAs
<TextComment
>(CXC
);
130 return cxstring::createNull();
132 return cxstring::createRef(TC
->getText());
135 CXString
clang_InlineCommandComment_getCommandName(CXComment CXC
) {
136 const InlineCommandComment
*ICC
= getASTNodeAs
<InlineCommandComment
>(CXC
);
138 return cxstring::createNull();
140 const CommandTraits
&Traits
= getCommandTraits(CXC
);
141 return cxstring::createRef(ICC
->getCommandName(Traits
));
144 enum CXCommentInlineCommandRenderKind
145 clang_InlineCommandComment_getRenderKind(CXComment CXC
) {
146 const InlineCommandComment
*ICC
= getASTNodeAs
<InlineCommandComment
>(CXC
);
148 return CXCommentInlineCommandRenderKind_Normal
;
150 switch (ICC
->getRenderKind()) {
151 case InlineCommandComment::RenderNormal
:
152 return CXCommentInlineCommandRenderKind_Normal
;
154 case InlineCommandComment::RenderBold
:
155 return CXCommentInlineCommandRenderKind_Bold
;
157 case InlineCommandComment::RenderMonospaced
:
158 return CXCommentInlineCommandRenderKind_Monospaced
;
160 case InlineCommandComment::RenderEmphasized
:
161 return CXCommentInlineCommandRenderKind_Emphasized
;
163 case InlineCommandComment::RenderAnchor
:
164 return CXCommentInlineCommandRenderKind_Anchor
;
166 llvm_unreachable("unknown InlineCommandComment::RenderKind");
169 unsigned clang_InlineCommandComment_getNumArgs(CXComment CXC
) {
170 const InlineCommandComment
*ICC
= getASTNodeAs
<InlineCommandComment
>(CXC
);
174 return ICC
->getNumArgs();
177 CXString
clang_InlineCommandComment_getArgText(CXComment CXC
,
179 const InlineCommandComment
*ICC
= getASTNodeAs
<InlineCommandComment
>(CXC
);
180 if (!ICC
|| ArgIdx
>= ICC
->getNumArgs())
181 return cxstring::createNull();
183 return cxstring::createRef(ICC
->getArgText(ArgIdx
));
186 CXString
clang_HTMLTagComment_getTagName(CXComment CXC
) {
187 const HTMLTagComment
*HTC
= getASTNodeAs
<HTMLTagComment
>(CXC
);
189 return cxstring::createNull();
191 return cxstring::createRef(HTC
->getTagName());
194 unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment CXC
) {
195 const HTMLStartTagComment
*HST
= getASTNodeAs
<HTMLStartTagComment
>(CXC
);
199 return HST
->isSelfClosing();
202 unsigned clang_HTMLStartTag_getNumAttrs(CXComment CXC
) {
203 const HTMLStartTagComment
*HST
= getASTNodeAs
<HTMLStartTagComment
>(CXC
);
207 return HST
->getNumAttrs();
210 CXString
clang_HTMLStartTag_getAttrName(CXComment CXC
, unsigned AttrIdx
) {
211 const HTMLStartTagComment
*HST
= getASTNodeAs
<HTMLStartTagComment
>(CXC
);
212 if (!HST
|| AttrIdx
>= HST
->getNumAttrs())
213 return cxstring::createNull();
215 return cxstring::createRef(HST
->getAttr(AttrIdx
).Name
);
218 CXString
clang_HTMLStartTag_getAttrValue(CXComment CXC
, unsigned AttrIdx
) {
219 const HTMLStartTagComment
*HST
= getASTNodeAs
<HTMLStartTagComment
>(CXC
);
220 if (!HST
|| AttrIdx
>= HST
->getNumAttrs())
221 return cxstring::createNull();
223 return cxstring::createRef(HST
->getAttr(AttrIdx
).Value
);
226 CXString
clang_BlockCommandComment_getCommandName(CXComment CXC
) {
227 const BlockCommandComment
*BCC
= getASTNodeAs
<BlockCommandComment
>(CXC
);
229 return cxstring::createNull();
231 const CommandTraits
&Traits
= getCommandTraits(CXC
);
232 return cxstring::createRef(BCC
->getCommandName(Traits
));
235 unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC
) {
236 const BlockCommandComment
*BCC
= getASTNodeAs
<BlockCommandComment
>(CXC
);
240 return BCC
->getNumArgs();
243 CXString
clang_BlockCommandComment_getArgText(CXComment CXC
,
245 const BlockCommandComment
*BCC
= getASTNodeAs
<BlockCommandComment
>(CXC
);
246 if (!BCC
|| ArgIdx
>= BCC
->getNumArgs())
247 return cxstring::createNull();
249 return cxstring::createRef(BCC
->getArgText(ArgIdx
));
252 CXComment
clang_BlockCommandComment_getParagraph(CXComment CXC
) {
253 const BlockCommandComment
*BCC
= getASTNodeAs
<BlockCommandComment
>(CXC
);
255 return createCXComment(nullptr, nullptr);
257 return createCXComment(BCC
->getParagraph(), CXC
.TranslationUnit
);
260 CXString
clang_ParamCommandComment_getParamName(CXComment CXC
) {
261 const ParamCommandComment
*PCC
= getASTNodeAs
<ParamCommandComment
>(CXC
);
262 if (!PCC
|| !PCC
->hasParamName())
263 return cxstring::createNull();
265 return cxstring::createRef(PCC
->getParamNameAsWritten());
268 unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC
) {
269 const ParamCommandComment
*PCC
= getASTNodeAs
<ParamCommandComment
>(CXC
);
273 return PCC
->isParamIndexValid();
276 unsigned clang_ParamCommandComment_getParamIndex(CXComment CXC
) {
277 const ParamCommandComment
*PCC
= getASTNodeAs
<ParamCommandComment
>(CXC
);
278 if (!PCC
|| !PCC
->isParamIndexValid() || PCC
->isVarArgParam())
279 return ParamCommandComment::InvalidParamIndex
;
281 return PCC
->getParamIndex();
284 unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment CXC
) {
285 const ParamCommandComment
*PCC
= getASTNodeAs
<ParamCommandComment
>(CXC
);
289 return PCC
->isDirectionExplicit();
292 enum CXCommentParamPassDirection
clang_ParamCommandComment_getDirection(
294 const ParamCommandComment
*PCC
= getASTNodeAs
<ParamCommandComment
>(CXC
);
296 return CXCommentParamPassDirection_In
;
298 switch (PCC
->getDirection()) {
299 case ParamCommandComment::In
:
300 return CXCommentParamPassDirection_In
;
302 case ParamCommandComment::Out
:
303 return CXCommentParamPassDirection_Out
;
305 case ParamCommandComment::InOut
:
306 return CXCommentParamPassDirection_InOut
;
308 llvm_unreachable("unknown ParamCommandComment::PassDirection");
311 CXString
clang_TParamCommandComment_getParamName(CXComment CXC
) {
312 const TParamCommandComment
*TPCC
= getASTNodeAs
<TParamCommandComment
>(CXC
);
313 if (!TPCC
|| !TPCC
->hasParamName())
314 return cxstring::createNull();
316 return cxstring::createRef(TPCC
->getParamNameAsWritten());
319 unsigned clang_TParamCommandComment_isParamPositionValid(CXComment CXC
) {
320 const TParamCommandComment
*TPCC
= getASTNodeAs
<TParamCommandComment
>(CXC
);
324 return TPCC
->isPositionValid();
327 unsigned clang_TParamCommandComment_getDepth(CXComment CXC
) {
328 const TParamCommandComment
*TPCC
= getASTNodeAs
<TParamCommandComment
>(CXC
);
329 if (!TPCC
|| !TPCC
->isPositionValid())
332 return TPCC
->getDepth();
335 unsigned clang_TParamCommandComment_getIndex(CXComment CXC
, unsigned Depth
) {
336 const TParamCommandComment
*TPCC
= getASTNodeAs
<TParamCommandComment
>(CXC
);
337 if (!TPCC
|| !TPCC
->isPositionValid() || Depth
>= TPCC
->getDepth())
340 return TPCC
->getIndex(Depth
);
343 CXString
clang_VerbatimBlockLineComment_getText(CXComment CXC
) {
344 const VerbatimBlockLineComment
*VBL
=
345 getASTNodeAs
<VerbatimBlockLineComment
>(CXC
);
347 return cxstring::createNull();
349 return cxstring::createRef(VBL
->getText());
352 CXString
clang_VerbatimLineComment_getText(CXComment CXC
) {
353 const VerbatimLineComment
*VLC
= getASTNodeAs
<VerbatimLineComment
>(CXC
);
355 return cxstring::createNull();
357 return cxstring::createRef(VLC
->getText());
360 //===----------------------------------------------------------------------===//
361 // Converting comments to XML.
362 //===----------------------------------------------------------------------===//
364 CXString
clang_HTMLTagComment_getAsString(CXComment CXC
) {
365 const HTMLTagComment
*HTC
= getASTNodeAs
<HTMLTagComment
>(CXC
);
367 return cxstring::createNull();
369 CXTranslationUnit TU
= CXC
.TranslationUnit
;
370 if (!TU
->CommentToXML
)
371 TU
->CommentToXML
= new clang::index::CommentToXMLConverter();
373 SmallString
<128> Text
;
374 TU
->CommentToXML
->convertHTMLTagNodeToText(
375 HTC
, Text
, cxtu::getASTUnit(TU
)->getASTContext());
376 return cxstring::createDup(Text
.str());
379 CXString
clang_FullComment_getAsHTML(CXComment CXC
) {
380 const FullComment
*FC
= getASTNodeAs
<FullComment
>(CXC
);
382 return cxstring::createNull();
384 CXTranslationUnit TU
= CXC
.TranslationUnit
;
385 if (!TU
->CommentToXML
)
386 TU
->CommentToXML
= new clang::index::CommentToXMLConverter();
388 SmallString
<1024> HTML
;
390 ->convertCommentToHTML(FC
, HTML
, cxtu::getASTUnit(TU
)->getASTContext());
391 return cxstring::createDup(HTML
.str());
394 CXString
clang_FullComment_getAsXML(CXComment CXC
) {
395 const FullComment
*FC
= getASTNodeAs
<FullComment
>(CXC
);
397 return cxstring::createNull();
399 CXTranslationUnit TU
= CXC
.TranslationUnit
;
400 if (!TU
->CommentToXML
)
401 TU
->CommentToXML
= new clang::index::CommentToXMLConverter();
403 SmallString
<1024> XML
;
405 ->convertCommentToXML(FC
, XML
, cxtu::getASTUnit(TU
)->getASTContext());
406 return cxstring::createDup(XML
.str());