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 "clang-c/Documentation.h" 16#include "CXComment.h" 17#include "CXCursor.h" 18#include "CXString.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 26using namespace clang; 27using namespace clang::comments; 28using namespace clang::cxcomment; 29 30extern "C" { 31 32CXComment 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 45enum 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 93unsigned 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 101CXComment 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 109unsigned 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 123unsigned 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 131CXString 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 139CXString 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 148enum CXCommentInlineCommandRenderKind 149clang_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 170unsigned 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 178CXString 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 187CXString 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 195unsigned 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 203unsigned 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 211CXString 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 219CXString 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 227CXString 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 236unsigned 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 244CXString 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 253CXComment 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 261CXString 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 269unsigned 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 277unsigned 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 285unsigned 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 293enum 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 312CXString 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 320unsigned 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 328unsigned 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 336unsigned 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 344CXString 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 353CXString 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 365CXString 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 380CXString 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 395CXString 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