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 llvm_unreachable("unknown InlineCommandComment::RenderKind"); 164 } 165 166 unsigned 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 174 CXString 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 183 CXString 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 191 unsigned 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 199 unsigned 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 207 CXString clang_HTMLStartTag_getAttrName(CXComment CXC, unsigned 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 215 CXString clang_HTMLStartTag_getAttrValue(CXComment CXC, unsigned 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 223 CXString 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 232 unsigned 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 240 CXString 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 249 CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) { 250 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC); 251 if (!BCC) 252 return createCXComment(nullptr, nullptr); 253 254 return createCXComment(BCC->getParagraph(), CXC.TranslationUnit); 255 } 256 257 CXString 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 265 unsigned 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 273 unsigned 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 281 unsigned 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 289 enum 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 308 CXString 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 316 unsigned 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 324 unsigned 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 332 unsigned clang_TParamCommandComment_getIndex(CXComment CXC, unsigned 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 340 CXString 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 349 CXString 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 361 CXString 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<128> Text; 371 TU->CommentToXML->convertHTMLTagNodeToText( 372 HTC, Text, cxtu::getASTUnit(TU)->getASTContext()); 373 return cxstring::createDup(Text.str()); 374 } 375 376 CXString 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<1024> HTML; 386 TU->CommentToXML 387 ->convertCommentToHTML(FC, HTML, cxtu::getASTUnit(TU)->getASTContext()); 388 return cxstring::createDup(HTML.str()); 389 } 390 391 CXString 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<1024> XML; 401 TU->CommentToXML 402 ->convertCommentToXML(FC, XML, cxtu::getASTUnit(TU)->getASTContext()); 403 return cxstring::createDup(XML.str()); 404 } 405 406