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