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