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 24 using namespace clang; 25 using namespace clang::comments; 26 using namespace clang::cxcomment; 27 28 CXComment clang_Cursor_getParsedComment(CXCursor C) { 29 using namespace clang::cxcursor; 30 31 if (!clang_isDeclaration(C.kind)) 32 return createCXComment(nullptr, nullptr); 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(FC, getCursorTU(C)); 39 } 40 41 enum 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 89 unsigned 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 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); 101 102 return createCXComment(*(C->child_begin() + ChildIdx), CXC.TranslationUnit); 103 } 104 105 unsigned 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 119 unsigned 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 127 CXString 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 135 CXString 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 144 enum CXCommentInlineCommandRenderKind 145 clang_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 case InlineCommandComment::RenderAnchor: 164 return CXCommentInlineCommandRenderKind_Anchor; 165 } 166 llvm_unreachable("unknown InlineCommandComment::RenderKind"); 167 } 168 169 unsigned clang_InlineCommandComment_getNumArgs(CXComment CXC) { 170 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC); 171 if (!ICC) 172 return 0; 173 174 return ICC->getNumArgs(); 175 } 176 177 CXString clang_InlineCommandComment_getArgText(CXComment CXC, 178 unsigned ArgIdx) { 179 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC); 180 if (!ICC || ArgIdx >= ICC->getNumArgs()) 181 return cxstring::createNull(); 182 183 return cxstring::createRef(ICC->getArgText(ArgIdx)); 184 } 185 186 CXString clang_HTMLTagComment_getTagName(CXComment CXC) { 187 const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC); 188 if (!HTC) 189 return cxstring::createNull(); 190 191 return cxstring::createRef(HTC->getTagName()); 192 } 193 194 unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment CXC) { 195 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC); 196 if (!HST) 197 return false; 198 199 return HST->isSelfClosing(); 200 } 201 202 unsigned clang_HTMLStartTag_getNumAttrs(CXComment CXC) { 203 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC); 204 if (!HST) 205 return 0; 206 207 return HST->getNumAttrs(); 208 } 209 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(); 214 215 return cxstring::createRef(HST->getAttr(AttrIdx).Name); 216 } 217 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(); 222 223 return cxstring::createRef(HST->getAttr(AttrIdx).Value); 224 } 225 226 CXString clang_BlockCommandComment_getCommandName(CXComment CXC) { 227 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC); 228 if (!BCC) 229 return cxstring::createNull(); 230 231 const CommandTraits &Traits = getCommandTraits(CXC); 232 return cxstring::createRef(BCC->getCommandName(Traits)); 233 } 234 235 unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC) { 236 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC); 237 if (!BCC) 238 return 0; 239 240 return BCC->getNumArgs(); 241 } 242 243 CXString clang_BlockCommandComment_getArgText(CXComment CXC, 244 unsigned ArgIdx) { 245 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC); 246 if (!BCC || ArgIdx >= BCC->getNumArgs()) 247 return cxstring::createNull(); 248 249 return cxstring::createRef(BCC->getArgText(ArgIdx)); 250 } 251 252 CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) { 253 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC); 254 if (!BCC) 255 return createCXComment(nullptr, nullptr); 256 257 return createCXComment(BCC->getParagraph(), CXC.TranslationUnit); 258 } 259 260 CXString clang_ParamCommandComment_getParamName(CXComment CXC) { 261 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC); 262 if (!PCC || !PCC->hasParamName()) 263 return cxstring::createNull(); 264 265 return cxstring::createRef(PCC->getParamNameAsWritten()); 266 } 267 268 unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) { 269 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC); 270 if (!PCC) 271 return false; 272 273 return PCC->isParamIndexValid(); 274 } 275 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; 280 281 return PCC->getParamIndex(); 282 } 283 284 unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment CXC) { 285 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC); 286 if (!PCC) 287 return false; 288 289 return PCC->isDirectionExplicit(); 290 } 291 292 enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection( 293 CXComment CXC) { 294 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC); 295 if (!PCC) 296 return CXCommentParamPassDirection_In; 297 298 switch (PCC->getDirection()) { 299 case ParamCommandComment::In: 300 return CXCommentParamPassDirection_In; 301 302 case ParamCommandComment::Out: 303 return CXCommentParamPassDirection_Out; 304 305 case ParamCommandComment::InOut: 306 return CXCommentParamPassDirection_InOut; 307 } 308 llvm_unreachable("unknown ParamCommandComment::PassDirection"); 309 } 310 311 CXString clang_TParamCommandComment_getParamName(CXComment CXC) { 312 const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC); 313 if (!TPCC || !TPCC->hasParamName()) 314 return cxstring::createNull(); 315 316 return cxstring::createRef(TPCC->getParamNameAsWritten()); 317 } 318 319 unsigned clang_TParamCommandComment_isParamPositionValid(CXComment CXC) { 320 const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC); 321 if (!TPCC) 322 return false; 323 324 return TPCC->isPositionValid(); 325 } 326 327 unsigned clang_TParamCommandComment_getDepth(CXComment CXC) { 328 const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC); 329 if (!TPCC || !TPCC->isPositionValid()) 330 return 0; 331 332 return TPCC->getDepth(); 333 } 334 335 unsigned clang_TParamCommandComment_getIndex(CXComment CXC, unsigned Depth) { 336 const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC); 337 if (!TPCC || !TPCC->isPositionValid() || Depth >= TPCC->getDepth()) 338 return 0; 339 340 return TPCC->getIndex(Depth); 341 } 342 343 CXString clang_VerbatimBlockLineComment_getText(CXComment CXC) { 344 const VerbatimBlockLineComment *VBL = 345 getASTNodeAs<VerbatimBlockLineComment>(CXC); 346 if (!VBL) 347 return cxstring::createNull(); 348 349 return cxstring::createRef(VBL->getText()); 350 } 351 352 CXString clang_VerbatimLineComment_getText(CXComment CXC) { 353 const VerbatimLineComment *VLC = getASTNodeAs<VerbatimLineComment>(CXC); 354 if (!VLC) 355 return cxstring::createNull(); 356 357 return cxstring::createRef(VLC->getText()); 358 } 359 360 //===----------------------------------------------------------------------===// 361 // Converting comments to XML. 362 //===----------------------------------------------------------------------===// 363 364 CXString clang_HTMLTagComment_getAsString(CXComment CXC) { 365 const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC); 366 if (!HTC) 367 return cxstring::createNull(); 368 369 CXTranslationUnit TU = CXC.TranslationUnit; 370 if (!TU->CommentToXML) 371 TU->CommentToXML = new clang::index::CommentToXMLConverter(); 372 373 SmallString<128> Text; 374 TU->CommentToXML->convertHTMLTagNodeToText( 375 HTC, Text, cxtu::getASTUnit(TU)->getASTContext()); 376 return cxstring::createDup(Text.str()); 377 } 378 379 CXString clang_FullComment_getAsHTML(CXComment CXC) { 380 const FullComment *FC = getASTNodeAs<FullComment>(CXC); 381 if (!FC) 382 return cxstring::createNull(); 383 384 CXTranslationUnit TU = CXC.TranslationUnit; 385 if (!TU->CommentToXML) 386 TU->CommentToXML = new clang::index::CommentToXMLConverter(); 387 388 SmallString<1024> HTML; 389 TU->CommentToXML 390 ->convertCommentToHTML(FC, HTML, cxtu::getASTUnit(TU)->getASTContext()); 391 return cxstring::createDup(HTML.str()); 392 } 393 394 CXString clang_FullComment_getAsXML(CXComment CXC) { 395 const FullComment *FC = getASTNodeAs<FullComment>(CXC); 396 if (!FC) 397 return cxstring::createNull(); 398 399 CXTranslationUnit TU = CXC.TranslationUnit; 400 if (!TU->CommentToXML) 401 TU->CommentToXML = new clang::index::CommentToXMLConverter(); 402 403 SmallString<1024> XML; 404 TU->CommentToXML 405 ->convertCommentToXML(FC, XML, cxtu::getASTUnit(TU)->getASTContext()); 406 return cxstring::createDup(XML.str()); 407 } 408 409