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 extern "C" { 30 31 CXComment clang_Cursor_getParsedComment(CXCursor C) { 32 using namespace clang::cxcursor; 33 34 if (!clang_isDeclaration(C.kind)) 35 return createCXComment(nullptr, nullptr); 36 37 const Decl *D = getCursorDecl(C); 38 const ASTContext &Context = getCursorContext(C); 39 const FullComment *FC = Context.getCommentForDecl(D, /*PP=*/nullptr); 40 41 return createCXComment(FC, getCursorTU(C)); 42 } 43 44 enum CXCommentKind clang_Comment_getKind(CXComment CXC) { 45 const Comment *C = getASTNode(CXC); 46 if (!C) 47 return CXComment_Null; 48 49 switch (C->getCommentKind()) { 50 case Comment::NoCommentKind: 51 return CXComment_Null; 52 53 case Comment::TextCommentKind: 54 return CXComment_Text; 55 56 case Comment::InlineCommandCommentKind: 57 return CXComment_InlineCommand; 58 59 case Comment::HTMLStartTagCommentKind: 60 return CXComment_HTMLStartTag; 61 62 case Comment::HTMLEndTagCommentKind: 63 return CXComment_HTMLEndTag; 64 65 case Comment::ParagraphCommentKind: 66 return CXComment_Paragraph; 67 68 case Comment::BlockCommandCommentKind: 69 return CXComment_BlockCommand; 70 71 case Comment::ParamCommandCommentKind: 72 return CXComment_ParamCommand; 73 74 case Comment::TParamCommandCommentKind: 75 return CXComment_TParamCommand; 76 77 case Comment::VerbatimBlockCommentKind: 78 return CXComment_VerbatimBlockCommand; 79 80 case Comment::VerbatimBlockLineCommentKind: 81 return CXComment_VerbatimBlockLine; 82 83 case Comment::VerbatimLineCommentKind: 84 return CXComment_VerbatimLine; 85 86 case Comment::FullCommentKind: 87 return CXComment_FullComment; 88 } 89 llvm_unreachable("unknown CommentKind"); 90 } 91 92 unsigned clang_Comment_getNumChildren(CXComment CXC) { 93 const Comment *C = getASTNode(CXC); 94 if (!C) 95 return 0; 96 97 return C->child_count(); 98 } 99 100 CXComment clang_Comment_getChild(CXComment CXC, unsigned ChildIdx) { 101 const Comment *C = getASTNode(CXC); 102 if (!C || ChildIdx >= C->child_count()) 103 return createCXComment(nullptr, nullptr); 104 105 return createCXComment(*(C->child_begin() + ChildIdx), CXC.TranslationUnit); 106 } 107 108 unsigned clang_Comment_isWhitespace(CXComment CXC) { 109 const Comment *C = getASTNode(CXC); 110 if (!C) 111 return false; 112 113 if (const TextComment *TC = dyn_cast<TextComment>(C)) 114 return TC->isWhitespace(); 115 116 if (const ParagraphComment *PC = dyn_cast<ParagraphComment>(C)) 117 return PC->isWhitespace(); 118 119 return false; 120 } 121 122 unsigned clang_InlineContentComment_hasTrailingNewline(CXComment CXC) { 123 const InlineContentComment *ICC = getASTNodeAs<InlineContentComment>(CXC); 124 if (!ICC) 125 return false; 126 127 return ICC->hasTrailingNewline(); 128 } 129 130 CXString clang_TextComment_getText(CXComment CXC) { 131 const TextComment *TC = getASTNodeAs<TextComment>(CXC); 132 if (!TC) 133 return cxstring::createNull(); 134 135 return cxstring::createRef(TC->getText()); 136 } 137 138 CXString clang_InlineCommandComment_getCommandName(CXComment CXC) { 139 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC); 140 if (!ICC) 141 return cxstring::createNull(); 142 143 const CommandTraits &Traits = getCommandTraits(CXC); 144 return cxstring::createRef(ICC->getCommandName(Traits)); 145 } 146 147 enum CXCommentInlineCommandRenderKind 148 clang_InlineCommandComment_getRenderKind(CXComment CXC) { 149 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC); 150 if (!ICC) 151 return CXCommentInlineCommandRenderKind_Normal; 152 153 switch (ICC->getRenderKind()) { 154 case InlineCommandComment::RenderNormal: 155 return CXCommentInlineCommandRenderKind_Normal; 156 157 case InlineCommandComment::RenderBold: 158 return CXCommentInlineCommandRenderKind_Bold; 159 160 case InlineCommandComment::RenderMonospaced: 161 return CXCommentInlineCommandRenderKind_Monospaced; 162 163 case InlineCommandComment::RenderEmphasized: 164 return CXCommentInlineCommandRenderKind_Emphasized; 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 } // end extern "C" 410 411