CXComment.cpp revision f0d151c485bec560e73c74e816cd969e0c485c71
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 "CXString.h" 16#include "CXComment.h" 17 18#include "clang/AST/CommentVisitor.h" 19 20#include "llvm/Support/ErrorHandling.h" 21#include "llvm/Support/raw_ostream.h" 22 23#include <climits> 24 25using namespace clang; 26using namespace clang::cxstring; 27using namespace clang::comments; 28using namespace clang::cxcomment; 29 30extern "C" { 31 32enum CXCommentKind clang_Comment_getKind(CXComment CXC) { 33 const Comment *C = getASTNode(CXC); 34 if (!C) 35 return CXComment_Null; 36 37 switch (C->getCommentKind()) { 38 case Comment::NoCommentKind: 39 return CXComment_Null; 40 41 case Comment::TextCommentKind: 42 return CXComment_Text; 43 44 case Comment::InlineCommandCommentKind: 45 return CXComment_InlineCommand; 46 47 case Comment::HTMLStartTagCommentKind: 48 return CXComment_HTMLStartTag; 49 50 case Comment::HTMLEndTagCommentKind: 51 return CXComment_HTMLEndTag; 52 53 case Comment::ParagraphCommentKind: 54 return CXComment_Paragraph; 55 56 case Comment::BlockCommandCommentKind: 57 return CXComment_BlockCommand; 58 59 case Comment::ParamCommandCommentKind: 60 return CXComment_ParamCommand; 61 62 case Comment::TParamCommandCommentKind: 63 return CXComment_TParamCommand; 64 65 case Comment::VerbatimBlockCommentKind: 66 return CXComment_VerbatimBlockCommand; 67 68 case Comment::VerbatimBlockLineCommentKind: 69 return CXComment_VerbatimBlockLine; 70 71 case Comment::VerbatimLineCommentKind: 72 return CXComment_VerbatimLine; 73 74 case Comment::FullCommentKind: 75 return CXComment_FullComment; 76 } 77 llvm_unreachable("unknown CommentKind"); 78} 79 80unsigned clang_Comment_getNumChildren(CXComment CXC) { 81 const Comment *C = getASTNode(CXC); 82 if (!C) 83 return 0; 84 85 return C->child_count(); 86} 87 88CXComment clang_Comment_getChild(CXComment CXC, unsigned ChildIdx) { 89 const Comment *C = getASTNode(CXC); 90 if (!C || ChildIdx >= C->child_count()) 91 return createCXComment(NULL); 92 93 return createCXComment(*(C->child_begin() + ChildIdx)); 94} 95 96unsigned clang_Comment_isWhitespace(CXComment CXC) { 97 const Comment *C = getASTNode(CXC); 98 if (!C) 99 return false; 100 101 if (const TextComment *TC = dyn_cast<TextComment>(C)) 102 return TC->isWhitespace(); 103 104 if (const ParagraphComment *PC = dyn_cast<ParagraphComment>(C)) 105 return PC->isWhitespace(); 106 107 return false; 108} 109 110unsigned clang_InlineContentComment_hasTrailingNewline(CXComment CXC) { 111 const InlineContentComment *ICC = getASTNodeAs<InlineContentComment>(CXC); 112 if (!ICC) 113 return false; 114 115 return ICC->hasTrailingNewline(); 116} 117 118CXString clang_TextComment_getText(CXComment CXC) { 119 const TextComment *TC = getASTNodeAs<TextComment>(CXC); 120 if (!TC) 121 return createCXString((const char *) 0); 122 123 return createCXString(TC->getText(), /*DupString=*/ false); 124} 125 126CXString clang_InlineCommandComment_getCommandName(CXComment CXC) { 127 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC); 128 if (!ICC) 129 return createCXString((const char *) 0); 130 131 return createCXString(ICC->getCommandName(), /*DupString=*/ false); 132} 133 134enum CXCommentInlineCommandRenderKind 135clang_InlineCommandComment_getRenderKind(CXComment CXC) { 136 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC); 137 if (!ICC) 138 return CXCommentInlineCommandRenderKind_Normal; 139 140 switch (ICC->getRenderKind()) { 141 case InlineCommandComment::RenderNormal: 142 return CXCommentInlineCommandRenderKind_Normal; 143 144 case InlineCommandComment::RenderBold: 145 return CXCommentInlineCommandRenderKind_Bold; 146 147 case InlineCommandComment::RenderMonospaced: 148 return CXCommentInlineCommandRenderKind_Monospaced; 149 150 case InlineCommandComment::RenderEmphasized: 151 return CXCommentInlineCommandRenderKind_Emphasized; 152 } 153 llvm_unreachable("unknown InlineCommandComment::RenderKind"); 154} 155 156unsigned clang_InlineCommandComment_getNumArgs(CXComment CXC) { 157 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC); 158 if (!ICC) 159 return 0; 160 161 return ICC->getNumArgs(); 162} 163 164CXString clang_InlineCommandComment_getArgText(CXComment CXC, 165 unsigned ArgIdx) { 166 const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC); 167 if (!ICC || ArgIdx >= ICC->getNumArgs()) 168 return createCXString((const char *) 0); 169 170 return createCXString(ICC->getArgText(ArgIdx), /*DupString=*/ false); 171} 172 173CXString clang_HTMLTagComment_getTagName(CXComment CXC) { 174 const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC); 175 if (!HTC) 176 return createCXString((const char *) 0); 177 178 return createCXString(HTC->getTagName(), /*DupString=*/ false); 179} 180 181unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment CXC) { 182 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC); 183 if (!HST) 184 return false; 185 186 return HST->isSelfClosing(); 187} 188 189unsigned clang_HTMLStartTag_getNumAttrs(CXComment CXC) { 190 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC); 191 if (!HST) 192 return 0; 193 194 return HST->getNumAttrs(); 195} 196 197CXString clang_HTMLStartTag_getAttrName(CXComment CXC, unsigned AttrIdx) { 198 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC); 199 if (!HST || AttrIdx >= HST->getNumAttrs()) 200 return createCXString((const char *) 0); 201 202 return createCXString(HST->getAttr(AttrIdx).Name, /*DupString=*/ false); 203} 204 205CXString clang_HTMLStartTag_getAttrValue(CXComment CXC, unsigned AttrIdx) { 206 const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC); 207 if (!HST || AttrIdx >= HST->getNumAttrs()) 208 return createCXString((const char *) 0); 209 210 return createCXString(HST->getAttr(AttrIdx).Value, /*DupString=*/ false); 211} 212 213CXString clang_BlockCommandComment_getCommandName(CXComment CXC) { 214 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC); 215 if (!BCC) 216 return createCXString((const char *) 0); 217 218 return createCXString(BCC->getCommandName(), /*DupString=*/ false); 219} 220 221unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC) { 222 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC); 223 if (!BCC) 224 return 0; 225 226 return BCC->getNumArgs(); 227} 228 229CXString clang_BlockCommandComment_getArgText(CXComment CXC, 230 unsigned ArgIdx) { 231 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC); 232 if (!BCC || ArgIdx >= BCC->getNumArgs()) 233 return createCXString((const char *) 0); 234 235 return createCXString(BCC->getArgText(ArgIdx), /*DupString=*/ false); 236} 237 238CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) { 239 const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC); 240 if (!BCC) 241 return createCXComment(NULL); 242 243 return createCXComment(BCC->getParagraph()); 244} 245 246CXString clang_ParamCommandComment_getParamName(CXComment CXC) { 247 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC); 248 if (!PCC || !PCC->hasParamName()) 249 return createCXString((const char *) 0); 250 251 return createCXString(PCC->getParamName(), /*DupString=*/ false); 252} 253 254unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) { 255 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC); 256 if (!PCC) 257 return false; 258 259 return PCC->isParamIndexValid(); 260} 261 262unsigned clang_ParamCommandComment_getParamIndex(CXComment CXC) { 263 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC); 264 if (!PCC || !PCC->isParamIndexValid()) 265 return ParamCommandComment::InvalidParamIndex; 266 267 return PCC->getParamIndex(); 268} 269 270unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment CXC) { 271 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC); 272 if (!PCC) 273 return false; 274 275 return PCC->isDirectionExplicit(); 276} 277 278enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection( 279 CXComment CXC) { 280 const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC); 281 if (!PCC) 282 return CXCommentParamPassDirection_In; 283 284 switch (PCC->getDirection()) { 285 case ParamCommandComment::In: 286 return CXCommentParamPassDirection_In; 287 288 case ParamCommandComment::Out: 289 return CXCommentParamPassDirection_Out; 290 291 case ParamCommandComment::InOut: 292 return CXCommentParamPassDirection_InOut; 293 } 294 llvm_unreachable("unknown ParamCommandComment::PassDirection"); 295} 296 297CXString clang_TParamCommandComment_getParamName(CXComment CXC) { 298 const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC); 299 if (!TPCC || !TPCC->hasParamName()) 300 return createCXString((const char *) 0); 301 302 return createCXString(TPCC->getParamName(), /*DupString=*/ false); 303} 304 305unsigned clang_TParamCommandComment_isParamPositionValid(CXComment CXC) { 306 const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC); 307 if (!TPCC) 308 return false; 309 310 return TPCC->isPositionValid(); 311} 312 313unsigned clang_TParamCommandComment_getDepth(CXComment CXC) { 314 const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC); 315 if (!TPCC || !TPCC->isPositionValid()) 316 return 0; 317 318 return TPCC->getDepth(); 319} 320 321unsigned clang_TParamCommandComment_getIndex(CXComment CXC, unsigned Depth) { 322 const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC); 323 if (!TPCC || !TPCC->isPositionValid() || Depth >= TPCC->getDepth()) 324 return 0; 325 326 return TPCC->getIndex(Depth); 327} 328 329CXString clang_VerbatimBlockLineComment_getText(CXComment CXC) { 330 const VerbatimBlockLineComment *VBL = 331 getASTNodeAs<VerbatimBlockLineComment>(CXC); 332 if (!VBL) 333 return createCXString((const char *) 0); 334 335 return createCXString(VBL->getText(), /*DupString=*/ false); 336} 337 338CXString clang_VerbatimLineComment_getText(CXComment CXC) { 339 const VerbatimLineComment *VLC = getASTNodeAs<VerbatimLineComment>(CXC); 340 if (!VLC) 341 return createCXString((const char *) 0); 342 343 return createCXString(VLC->getText(), /*DupString=*/ false); 344} 345 346} // end extern "C" 347 348//===----------------------------------------------------------------------===// 349// Helpers for converting comment AST to HTML. 350//===----------------------------------------------------------------------===// 351 352namespace { 353 354/// This comparison will sort parameters with valid index by index and 355/// invalid (unresolved) parameters last. 356class ParamCommandCommentCompareIndex { 357public: 358 bool operator()(const ParamCommandComment *LHS, 359 const ParamCommandComment *RHS) const { 360 unsigned LHSIndex = UINT_MAX; 361 unsigned RHSIndex = UINT_MAX; 362 if (LHS->isParamIndexValid()) 363 LHSIndex = LHS->getParamIndex(); 364 if (RHS->isParamIndexValid()) 365 RHSIndex = RHS->getParamIndex(); 366 367 return LHSIndex < RHSIndex; 368 } 369}; 370 371/// This comparison will sort template parameters in the following order: 372/// \li real template parameters (depth = 1) in index order; 373/// \li all other names (depth > 1); 374/// \li unresolved names. 375class TParamCommandCommentComparePosition { 376public: 377 bool operator()(const TParamCommandComment *LHS, 378 const TParamCommandComment *RHS) const { 379 // Sort unresolved names last. 380 if (!LHS->isPositionValid()) 381 return false; 382 if (!RHS->isPositionValid()) 383 return true; 384 385 if (LHS->getDepth() > 1) 386 return false; 387 if (RHS->getDepth() > 1) 388 return true; 389 390 // Sort template parameters in index order. 391 if (LHS->getDepth() == 1 && RHS->getDepth() == 1) 392 return LHS->getIndex(0) < RHS->getIndex(0); 393 394 // Leave all other names in source order. 395 return true; 396 } 397}; 398 399class CommentASTToHTMLConverter : 400 public ConstCommentVisitor<CommentASTToHTMLConverter> { 401public: 402 /// \param Str accumulator for HTML. 403 CommentASTToHTMLConverter(SmallVectorImpl<char> &Str) : Result(Str) { } 404 405 // Inline content. 406 void visitTextComment(const TextComment *C); 407 void visitInlineCommandComment(const InlineCommandComment *C); 408 void visitHTMLStartTagComment(const HTMLStartTagComment *C); 409 void visitHTMLEndTagComment(const HTMLEndTagComment *C); 410 411 // Block content. 412 void visitParagraphComment(const ParagraphComment *C); 413 void visitBlockCommandComment(const BlockCommandComment *C); 414 void visitParamCommandComment(const ParamCommandComment *C); 415 void visitTParamCommandComment(const TParamCommandComment *C); 416 void visitVerbatimBlockComment(const VerbatimBlockComment *C); 417 void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C); 418 void visitVerbatimLineComment(const VerbatimLineComment *C); 419 420 void visitFullComment(const FullComment *C); 421 422 // Helpers. 423 424 /// Convert a paragraph that is not a block by itself (an argument to some 425 /// command). 426 void visitNonStandaloneParagraphComment(const ParagraphComment *C); 427 428 void appendToResultWithHTMLEscaping(StringRef S); 429 430private: 431 /// Output stream for HTML. 432 llvm::raw_svector_ostream Result; 433}; 434} // end unnamed namespace 435 436void CommentASTToHTMLConverter::visitTextComment(const TextComment *C) { 437 appendToResultWithHTMLEscaping(C->getText()); 438} 439 440void CommentASTToHTMLConverter::visitInlineCommandComment( 441 const InlineCommandComment *C) { 442 // Nothing to render if no arguments supplied. 443 if (C->getNumArgs() == 0) 444 return; 445 446 // Nothing to render if argument is empty. 447 StringRef Arg0 = C->getArgText(0); 448 if (Arg0.empty()) 449 return; 450 451 switch (C->getRenderKind()) { 452 case InlineCommandComment::RenderNormal: 453 for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) { 454 appendToResultWithHTMLEscaping(C->getArgText(i)); 455 Result << " "; 456 } 457 return; 458 459 case InlineCommandComment::RenderBold: 460 assert(C->getNumArgs() == 1); 461 Result << "<b>"; 462 appendToResultWithHTMLEscaping(Arg0); 463 Result << "</b>"; 464 return; 465 case InlineCommandComment::RenderMonospaced: 466 assert(C->getNumArgs() == 1); 467 Result << "<tt>"; 468 appendToResultWithHTMLEscaping(Arg0); 469 Result<< "</tt>"; 470 return; 471 case InlineCommandComment::RenderEmphasized: 472 assert(C->getNumArgs() == 1); 473 Result << "<em>"; 474 appendToResultWithHTMLEscaping(Arg0); 475 Result << "</em>"; 476 return; 477 } 478} 479 480void CommentASTToHTMLConverter::visitHTMLStartTagComment( 481 const HTMLStartTagComment *C) { 482 Result << "<" << C->getTagName(); 483 484 if (C->getNumAttrs() != 0) { 485 for (unsigned i = 0, e = C->getNumAttrs(); i != e; i++) { 486 Result << " "; 487 const HTMLStartTagComment::Attribute &Attr = C->getAttr(i); 488 Result << Attr.Name; 489 if (!Attr.Value.empty()) 490 Result << "=\"" << Attr.Value << "\""; 491 } 492 } 493 494 if (!C->isSelfClosing()) 495 Result << ">"; 496 else 497 Result << "/>"; 498} 499 500void CommentASTToHTMLConverter::visitHTMLEndTagComment( 501 const HTMLEndTagComment *C) { 502 Result << "</" << C->getTagName() << ">"; 503} 504 505void CommentASTToHTMLConverter::visitParagraphComment( 506 const ParagraphComment *C) { 507 if (C->isWhitespace()) 508 return; 509 510 Result << "<p>"; 511 for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); 512 I != E; ++I) { 513 visit(*I); 514 } 515 Result << "</p>"; 516} 517 518void CommentASTToHTMLConverter::visitBlockCommandComment( 519 const BlockCommandComment *C) { 520 StringRef CommandName = C->getCommandName(); 521 if (CommandName == "brief" || CommandName == "short") { 522 Result << "<p class=\"para-brief\">"; 523 visitNonStandaloneParagraphComment(C->getParagraph()); 524 Result << "</p>"; 525 return; 526 } 527 if (CommandName == "returns" || CommandName == "return" || 528 CommandName == "result") { 529 Result << "<p class=\"para-returns\">" 530 "<span class=\"word-returns\">Returns</span> "; 531 visitNonStandaloneParagraphComment(C->getParagraph()); 532 Result << "</p>"; 533 return; 534 } 535 // We don't know anything about this command. Just render the paragraph. 536 visit(C->getParagraph()); 537} 538 539void CommentASTToHTMLConverter::visitParamCommandComment( 540 const ParamCommandComment *C) { 541 if (C->isParamIndexValid()) { 542 Result << "<dt class=\"param-name-index-" 543 << C->getParamIndex() 544 << "\">"; 545 } else 546 Result << "<dt class=\"param-name-index-invalid\">"; 547 548 appendToResultWithHTMLEscaping(C->getParamName()); 549 Result << "</dt>"; 550 551 if (C->isParamIndexValid()) { 552 Result << "<dd class=\"param-descr-index-" 553 << C->getParamIndex() 554 << "\">"; 555 } else 556 Result << "<dd class=\"param-descr-index-invalid\">"; 557 558 visitNonStandaloneParagraphComment(C->getParagraph()); 559 Result << "</dd>"; 560} 561 562void CommentASTToHTMLConverter::visitTParamCommandComment( 563 const TParamCommandComment *C) { 564 if (C->isPositionValid()) { 565 if (C->getDepth() == 1) 566 Result << "<dt class=\"taram-name-index-" 567 << C->getIndex(0) 568 << "\">"; 569 else 570 Result << "<dt class=\"taram-name-index-other\">"; 571 } else 572 Result << "<dt class=\"tparam-name-index-invalid\">"; 573 574 appendToResultWithHTMLEscaping(C->getParamName()); 575 Result << "</dt>"; 576 577 if (C->isPositionValid()) { 578 if (C->getDepth() == 1) 579 Result << "<dd class=\"tparam-descr-index-" 580 << C->getIndex(0) 581 << "\">"; 582 else 583 Result << "<dd class=\"tparam-descr-index-other\">"; 584 } else 585 Result << "<dd class=\"tparam-descr-index-invalid\">"; 586 587 visitNonStandaloneParagraphComment(C->getParagraph()); 588 Result << "</dd>"; 589} 590 591void CommentASTToHTMLConverter::visitVerbatimBlockComment( 592 const VerbatimBlockComment *C) { 593 unsigned NumLines = C->getNumLines(); 594 if (NumLines == 0) 595 return; 596 597 Result << "<pre>"; 598 for (unsigned i = 0; i != NumLines; ++i) { 599 appendToResultWithHTMLEscaping(C->getText(i)); 600 if (i + 1 != NumLines) 601 Result << '\n'; 602 } 603 Result << "</pre>"; 604} 605 606void CommentASTToHTMLConverter::visitVerbatimBlockLineComment( 607 const VerbatimBlockLineComment *C) { 608 llvm_unreachable("should not see this AST node"); 609} 610 611void CommentASTToHTMLConverter::visitVerbatimLineComment( 612 const VerbatimLineComment *C) { 613 Result << "<pre>"; 614 appendToResultWithHTMLEscaping(C->getText()); 615 Result << "</pre>"; 616} 617 618void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) { 619 const BlockContentComment *Brief = NULL; 620 const ParagraphComment *FirstParagraph = NULL; 621 const BlockCommandComment *Returns = NULL; 622 SmallVector<const ParamCommandComment *, 8> Params; 623 SmallVector<const TParamCommandComment *, 4> TParams; 624 SmallVector<const BlockContentComment *, 8> MiscBlocks; 625 626 // Extract various blocks into separate variables and vectors above. 627 for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); 628 I != E; ++I) { 629 const Comment *Child = *I; 630 if (!Child) 631 continue; 632 switch (Child->getCommentKind()) { 633 case Comment::NoCommentKind: 634 continue; 635 636 case Comment::ParagraphCommentKind: { 637 const ParagraphComment *PC = cast<ParagraphComment>(Child); 638 if (PC->isWhitespace()) 639 break; 640 if (!FirstParagraph) 641 FirstParagraph = PC; 642 643 MiscBlocks.push_back(PC); 644 break; 645 } 646 647 case Comment::BlockCommandCommentKind: { 648 const BlockCommandComment *BCC = cast<BlockCommandComment>(Child); 649 StringRef CommandName = BCC->getCommandName(); 650 if (!Brief && (CommandName == "brief" || CommandName == "short")) { 651 Brief = BCC; 652 break; 653 } 654 if (!Returns && (CommandName == "returns" || CommandName == "return")) { 655 Returns = BCC; 656 break; 657 } 658 MiscBlocks.push_back(BCC); 659 break; 660 } 661 662 case Comment::ParamCommandCommentKind: { 663 const ParamCommandComment *PCC = cast<ParamCommandComment>(Child); 664 if (!PCC->hasParamName()) 665 break; 666 667 if (!PCC->isDirectionExplicit() && !PCC->hasNonWhitespaceParagraph()) 668 break; 669 670 Params.push_back(PCC); 671 break; 672 } 673 674 case Comment::TParamCommandCommentKind: { 675 const TParamCommandComment *TPCC = cast<TParamCommandComment>(Child); 676 if (!TPCC->hasParamName()) 677 break; 678 679 if (!TPCC->hasNonWhitespaceParagraph()) 680 break; 681 682 TParams.push_back(TPCC); 683 break; 684 } 685 686 case Comment::VerbatimBlockCommentKind: 687 case Comment::VerbatimLineCommentKind: 688 MiscBlocks.push_back(cast<BlockCommandComment>(Child)); 689 break; 690 691 case Comment::TextCommentKind: 692 case Comment::InlineCommandCommentKind: 693 case Comment::HTMLStartTagCommentKind: 694 case Comment::HTMLEndTagCommentKind: 695 case Comment::VerbatimBlockLineCommentKind: 696 case Comment::FullCommentKind: 697 llvm_unreachable("AST node of this kind can't be a child of " 698 "a FullComment"); 699 } 700 } 701 702 // Sort params in order they are declared in the function prototype. 703 // Unresolved parameters are put at the end of the list in the same order 704 // they were seen in the comment. 705 std::stable_sort(Params.begin(), Params.end(), 706 ParamCommandCommentCompareIndex()); 707 708 std::stable_sort(TParams.begin(), TParams.end(), 709 TParamCommandCommentComparePosition()); 710 711 bool FirstParagraphIsBrief = false; 712 if (Brief) 713 visit(Brief); 714 else if (FirstParagraph) { 715 Result << "<p class=\"para-brief\">"; 716 visitNonStandaloneParagraphComment(FirstParagraph); 717 Result << "</p>"; 718 FirstParagraphIsBrief = true; 719 } 720 721 for (unsigned i = 0, e = MiscBlocks.size(); i != e; ++i) { 722 const Comment *C = MiscBlocks[i]; 723 if (FirstParagraphIsBrief && C == FirstParagraph) 724 continue; 725 visit(C); 726 } 727 728 if (TParams.size() != 0) { 729 Result << "<dl>"; 730 for (unsigned i = 0, e = TParams.size(); i != e; ++i) 731 visit(TParams[i]); 732 Result << "</dl>"; 733 } 734 735 if (Params.size() != 0) { 736 Result << "<dl>"; 737 for (unsigned i = 0, e = Params.size(); i != e; ++i) 738 visit(Params[i]); 739 Result << "</dl>"; 740 } 741 742 if (Returns) 743 visit(Returns); 744 745 Result.flush(); 746} 747 748void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment( 749 const ParagraphComment *C) { 750 if (!C) 751 return; 752 753 for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); 754 I != E; ++I) { 755 visit(*I); 756 } 757} 758 759void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) { 760 for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) { 761 const char C = *I; 762 switch (C) { 763 case '&': 764 Result << "&"; 765 break; 766 case '<': 767 Result << "<"; 768 break; 769 case '>': 770 Result << ">"; 771 break; 772 case '"': 773 Result << """; 774 break; 775 case '\'': 776 Result << "'"; 777 break; 778 case '/': 779 Result << "/"; 780 break; 781 default: 782 Result << C; 783 break; 784 } 785 } 786} 787 788extern "C" { 789 790CXString clang_HTMLTagComment_getAsString(CXComment CXC) { 791 const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC); 792 if (!HTC) 793 return createCXString((const char *) 0); 794 795 SmallString<128> HTML; 796 CommentASTToHTMLConverter Converter(HTML); 797 Converter.visit(HTC); 798 return createCXString(HTML.str(), /* DupString = */ true); 799} 800 801CXString clang_FullComment_getAsHTML(CXComment CXC) { 802 const FullComment *FC = getASTNodeAs<FullComment>(CXC); 803 if (!FC) 804 return createCXString((const char *) 0); 805 806 SmallString<1024> HTML; 807 CommentASTToHTMLConverter Converter(HTML); 808 Converter.visit(FC); 809 return createCXString(HTML.str(), /* DupString = */ true); 810} 811 812} // end extern "C" 813 814