1259701Sdim//===--- CommentToXML.cpp - Convert comments to XML representation --------===// 2259701Sdim// 3259701Sdim// The LLVM Compiler Infrastructure 4259701Sdim// 5259701Sdim// This file is distributed under the University of Illinois Open Source 6259701Sdim// License. See LICENSE.TXT for details. 7259701Sdim// 8259701Sdim//===----------------------------------------------------------------------===// 9259701Sdim 10259701Sdim#include "clang/Index/CommentToXML.h" 11259701Sdim#include "SimpleFormatContext.h" 12259701Sdim#include "clang/AST/Attr.h" 13259701Sdim#include "clang/AST/ASTContext.h" 14259701Sdim#include "clang/AST/Comment.h" 15259701Sdim#include "clang/AST/CommentVisitor.h" 16259701Sdim#include "clang/Format/Format.h" 17259701Sdim#include "clang/Index/USRGeneration.h" 18259701Sdim#include "clang/Lex/Lexer.h" 19259701Sdim#include "llvm/ADT/StringExtras.h" 20259701Sdim#include "llvm/ADT/TinyPtrVector.h" 21259701Sdim#include "llvm/Support/raw_ostream.h" 22259701Sdim 23259701Sdimusing namespace clang; 24259701Sdimusing namespace clang::comments; 25259701Sdimusing namespace clang::index; 26259701Sdim 27259701Sdimnamespace { 28259701Sdim 29259701Sdim/// This comparison will sort parameters with valid index by index, then vararg 30259701Sdim/// parameters, and invalid (unresolved) parameters last. 31259701Sdimclass ParamCommandCommentCompareIndex { 32259701Sdimpublic: 33259701Sdim bool operator()(const ParamCommandComment *LHS, 34259701Sdim const ParamCommandComment *RHS) const { 35259701Sdim unsigned LHSIndex = UINT_MAX; 36259701Sdim unsigned RHSIndex = UINT_MAX; 37259701Sdim 38259701Sdim if (LHS->isParamIndexValid()) { 39259701Sdim if (LHS->isVarArgParam()) 40259701Sdim LHSIndex = UINT_MAX - 1; 41259701Sdim else 42259701Sdim LHSIndex = LHS->getParamIndex(); 43259701Sdim } 44259701Sdim if (RHS->isParamIndexValid()) { 45259701Sdim if (RHS->isVarArgParam()) 46259701Sdim RHSIndex = UINT_MAX - 1; 47259701Sdim else 48259701Sdim RHSIndex = RHS->getParamIndex(); 49259701Sdim } 50259701Sdim return LHSIndex < RHSIndex; 51259701Sdim } 52259701Sdim}; 53259701Sdim 54259701Sdim/// This comparison will sort template parameters in the following order: 55259701Sdim/// \li real template parameters (depth = 1) in index order; 56259701Sdim/// \li all other names (depth > 1); 57259701Sdim/// \li unresolved names. 58259701Sdimclass TParamCommandCommentComparePosition { 59259701Sdimpublic: 60259701Sdim bool operator()(const TParamCommandComment *LHS, 61259701Sdim const TParamCommandComment *RHS) const { 62259701Sdim // Sort unresolved names last. 63259701Sdim if (!LHS->isPositionValid()) 64259701Sdim return false; 65259701Sdim if (!RHS->isPositionValid()) 66259701Sdim return true; 67259701Sdim 68259701Sdim if (LHS->getDepth() > 1) 69259701Sdim return false; 70259701Sdim if (RHS->getDepth() > 1) 71259701Sdim return true; 72259701Sdim 73259701Sdim // Sort template parameters in index order. 74259701Sdim if (LHS->getDepth() == 1 && RHS->getDepth() == 1) 75259701Sdim return LHS->getIndex(0) < RHS->getIndex(0); 76259701Sdim 77259701Sdim // Leave all other names in source order. 78259701Sdim return true; 79259701Sdim } 80259701Sdim}; 81259701Sdim 82259701Sdim/// Separate parts of a FullComment. 83259701Sdimstruct FullCommentParts { 84259701Sdim /// Take a full comment apart and initialize members accordingly. 85259701Sdim FullCommentParts(const FullComment *C, 86259701Sdim const CommandTraits &Traits); 87259701Sdim 88259701Sdim const BlockContentComment *Brief; 89259701Sdim const BlockContentComment *Headerfile; 90259701Sdim const ParagraphComment *FirstParagraph; 91259701Sdim SmallVector<const BlockCommandComment *, 4> Returns; 92259701Sdim SmallVector<const ParamCommandComment *, 8> Params; 93259701Sdim SmallVector<const TParamCommandComment *, 4> TParams; 94259701Sdim llvm::TinyPtrVector<const BlockCommandComment *> Exceptions; 95259701Sdim SmallVector<const BlockContentComment *, 8> MiscBlocks; 96259701Sdim}; 97259701Sdim 98259701SdimFullCommentParts::FullCommentParts(const FullComment *C, 99259701Sdim const CommandTraits &Traits) : 100259701Sdim Brief(NULL), Headerfile(NULL), FirstParagraph(NULL) { 101259701Sdim for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); 102259701Sdim I != E; ++I) { 103259701Sdim const Comment *Child = *I; 104259701Sdim if (!Child) 105259701Sdim continue; 106259701Sdim switch (Child->getCommentKind()) { 107259701Sdim case Comment::NoCommentKind: 108259701Sdim continue; 109259701Sdim 110259701Sdim case Comment::ParagraphCommentKind: { 111259701Sdim const ParagraphComment *PC = cast<ParagraphComment>(Child); 112259701Sdim if (PC->isWhitespace()) 113259701Sdim break; 114259701Sdim if (!FirstParagraph) 115259701Sdim FirstParagraph = PC; 116259701Sdim 117259701Sdim MiscBlocks.push_back(PC); 118259701Sdim break; 119259701Sdim } 120259701Sdim 121259701Sdim case Comment::BlockCommandCommentKind: { 122259701Sdim const BlockCommandComment *BCC = cast<BlockCommandComment>(Child); 123259701Sdim const CommandInfo *Info = Traits.getCommandInfo(BCC->getCommandID()); 124259701Sdim if (!Brief && Info->IsBriefCommand) { 125259701Sdim Brief = BCC; 126259701Sdim break; 127259701Sdim } 128259701Sdim if (!Headerfile && Info->IsHeaderfileCommand) { 129259701Sdim Headerfile = BCC; 130259701Sdim break; 131259701Sdim } 132259701Sdim if (Info->IsReturnsCommand) { 133259701Sdim Returns.push_back(BCC); 134259701Sdim break; 135259701Sdim } 136259701Sdim if (Info->IsThrowsCommand) { 137259701Sdim Exceptions.push_back(BCC); 138259701Sdim break; 139259701Sdim } 140259701Sdim MiscBlocks.push_back(BCC); 141259701Sdim break; 142259701Sdim } 143259701Sdim 144259701Sdim case Comment::ParamCommandCommentKind: { 145259701Sdim const ParamCommandComment *PCC = cast<ParamCommandComment>(Child); 146259701Sdim if (!PCC->hasParamName()) 147259701Sdim break; 148259701Sdim 149259701Sdim if (!PCC->isDirectionExplicit() && !PCC->hasNonWhitespaceParagraph()) 150259701Sdim break; 151259701Sdim 152259701Sdim Params.push_back(PCC); 153259701Sdim break; 154259701Sdim } 155259701Sdim 156259701Sdim case Comment::TParamCommandCommentKind: { 157259701Sdim const TParamCommandComment *TPCC = cast<TParamCommandComment>(Child); 158259701Sdim if (!TPCC->hasParamName()) 159259701Sdim break; 160259701Sdim 161259701Sdim if (!TPCC->hasNonWhitespaceParagraph()) 162259701Sdim break; 163259701Sdim 164259701Sdim TParams.push_back(TPCC); 165259701Sdim break; 166259701Sdim } 167259701Sdim 168259701Sdim case Comment::VerbatimBlockCommentKind: 169259701Sdim MiscBlocks.push_back(cast<BlockCommandComment>(Child)); 170259701Sdim break; 171259701Sdim 172259701Sdim case Comment::VerbatimLineCommentKind: { 173259701Sdim const VerbatimLineComment *VLC = cast<VerbatimLineComment>(Child); 174259701Sdim const CommandInfo *Info = Traits.getCommandInfo(VLC->getCommandID()); 175259701Sdim if (!Info->IsDeclarationCommand) 176259701Sdim MiscBlocks.push_back(VLC); 177259701Sdim break; 178259701Sdim } 179259701Sdim 180259701Sdim case Comment::TextCommentKind: 181259701Sdim case Comment::InlineCommandCommentKind: 182259701Sdim case Comment::HTMLStartTagCommentKind: 183259701Sdim case Comment::HTMLEndTagCommentKind: 184259701Sdim case Comment::VerbatimBlockLineCommentKind: 185259701Sdim case Comment::FullCommentKind: 186259701Sdim llvm_unreachable("AST node of this kind can't be a child of " 187259701Sdim "a FullComment"); 188259701Sdim } 189259701Sdim } 190259701Sdim 191259701Sdim // Sort params in order they are declared in the function prototype. 192259701Sdim // Unresolved parameters are put at the end of the list in the same order 193259701Sdim // they were seen in the comment. 194259701Sdim std::stable_sort(Params.begin(), Params.end(), 195259701Sdim ParamCommandCommentCompareIndex()); 196259701Sdim 197259701Sdim std::stable_sort(TParams.begin(), TParams.end(), 198259701Sdim TParamCommandCommentComparePosition()); 199259701Sdim} 200259701Sdim 201259701Sdimvoid printHTMLStartTagComment(const HTMLStartTagComment *C, 202259701Sdim llvm::raw_svector_ostream &Result) { 203259701Sdim Result << "<" << C->getTagName(); 204259701Sdim 205259701Sdim if (C->getNumAttrs() != 0) { 206259701Sdim for (unsigned i = 0, e = C->getNumAttrs(); i != e; i++) { 207259701Sdim Result << " "; 208259701Sdim const HTMLStartTagComment::Attribute &Attr = C->getAttr(i); 209259701Sdim Result << Attr.Name; 210259701Sdim if (!Attr.Value.empty()) 211259701Sdim Result << "=\"" << Attr.Value << "\""; 212259701Sdim } 213259701Sdim } 214259701Sdim 215259701Sdim if (!C->isSelfClosing()) 216259701Sdim Result << ">"; 217259701Sdim else 218259701Sdim Result << "/>"; 219259701Sdim} 220259701Sdim 221259701Sdimclass CommentASTToHTMLConverter : 222259701Sdim public ConstCommentVisitor<CommentASTToHTMLConverter> { 223259701Sdimpublic: 224259701Sdim /// \param Str accumulator for HTML. 225259701Sdim CommentASTToHTMLConverter(const FullComment *FC, 226259701Sdim SmallVectorImpl<char> &Str, 227259701Sdim const CommandTraits &Traits) : 228259701Sdim FC(FC), Result(Str), Traits(Traits) 229259701Sdim { } 230259701Sdim 231259701Sdim // Inline content. 232259701Sdim void visitTextComment(const TextComment *C); 233259701Sdim void visitInlineCommandComment(const InlineCommandComment *C); 234259701Sdim void visitHTMLStartTagComment(const HTMLStartTagComment *C); 235259701Sdim void visitHTMLEndTagComment(const HTMLEndTagComment *C); 236259701Sdim 237259701Sdim // Block content. 238259701Sdim void visitParagraphComment(const ParagraphComment *C); 239259701Sdim void visitBlockCommandComment(const BlockCommandComment *C); 240259701Sdim void visitParamCommandComment(const ParamCommandComment *C); 241259701Sdim void visitTParamCommandComment(const TParamCommandComment *C); 242259701Sdim void visitVerbatimBlockComment(const VerbatimBlockComment *C); 243259701Sdim void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C); 244259701Sdim void visitVerbatimLineComment(const VerbatimLineComment *C); 245259701Sdim 246259701Sdim void visitFullComment(const FullComment *C); 247259701Sdim 248259701Sdim // Helpers. 249259701Sdim 250259701Sdim /// Convert a paragraph that is not a block by itself (an argument to some 251259701Sdim /// command). 252259701Sdim void visitNonStandaloneParagraphComment(const ParagraphComment *C); 253259701Sdim 254259701Sdim void appendToResultWithHTMLEscaping(StringRef S); 255259701Sdim 256259701Sdimprivate: 257259701Sdim const FullComment *FC; 258259701Sdim /// Output stream for HTML. 259259701Sdim llvm::raw_svector_ostream Result; 260259701Sdim 261259701Sdim const CommandTraits &Traits; 262259701Sdim}; 263259701Sdim} // end unnamed namespace 264259701Sdim 265259701Sdimvoid CommentASTToHTMLConverter::visitTextComment(const TextComment *C) { 266259701Sdim appendToResultWithHTMLEscaping(C->getText()); 267259701Sdim} 268259701Sdim 269259701Sdimvoid CommentASTToHTMLConverter::visitInlineCommandComment( 270259701Sdim const InlineCommandComment *C) { 271259701Sdim // Nothing to render if no arguments supplied. 272259701Sdim if (C->getNumArgs() == 0) 273259701Sdim return; 274259701Sdim 275259701Sdim // Nothing to render if argument is empty. 276259701Sdim StringRef Arg0 = C->getArgText(0); 277259701Sdim if (Arg0.empty()) 278259701Sdim return; 279259701Sdim 280259701Sdim switch (C->getRenderKind()) { 281259701Sdim case InlineCommandComment::RenderNormal: 282259701Sdim for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) { 283259701Sdim appendToResultWithHTMLEscaping(C->getArgText(i)); 284259701Sdim Result << " "; 285259701Sdim } 286259701Sdim return; 287259701Sdim 288259701Sdim case InlineCommandComment::RenderBold: 289259701Sdim assert(C->getNumArgs() == 1); 290259701Sdim Result << "<b>"; 291259701Sdim appendToResultWithHTMLEscaping(Arg0); 292259701Sdim Result << "</b>"; 293259701Sdim return; 294259701Sdim case InlineCommandComment::RenderMonospaced: 295259701Sdim assert(C->getNumArgs() == 1); 296259701Sdim Result << "<tt>"; 297259701Sdim appendToResultWithHTMLEscaping(Arg0); 298259701Sdim Result<< "</tt>"; 299259701Sdim return; 300259701Sdim case InlineCommandComment::RenderEmphasized: 301259701Sdim assert(C->getNumArgs() == 1); 302259701Sdim Result << "<em>"; 303259701Sdim appendToResultWithHTMLEscaping(Arg0); 304259701Sdim Result << "</em>"; 305259701Sdim return; 306259701Sdim } 307259701Sdim} 308259701Sdim 309259701Sdimvoid CommentASTToHTMLConverter::visitHTMLStartTagComment( 310259701Sdim const HTMLStartTagComment *C) { 311259701Sdim printHTMLStartTagComment(C, Result); 312259701Sdim} 313259701Sdim 314259701Sdimvoid CommentASTToHTMLConverter::visitHTMLEndTagComment( 315259701Sdim const HTMLEndTagComment *C) { 316259701Sdim Result << "</" << C->getTagName() << ">"; 317259701Sdim} 318259701Sdim 319259701Sdimvoid CommentASTToHTMLConverter::visitParagraphComment( 320259701Sdim const ParagraphComment *C) { 321259701Sdim if (C->isWhitespace()) 322259701Sdim return; 323259701Sdim 324259701Sdim Result << "<p>"; 325259701Sdim for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); 326259701Sdim I != E; ++I) { 327259701Sdim visit(*I); 328259701Sdim } 329259701Sdim Result << "</p>"; 330259701Sdim} 331259701Sdim 332259701Sdimvoid CommentASTToHTMLConverter::visitBlockCommandComment( 333259701Sdim const BlockCommandComment *C) { 334259701Sdim const CommandInfo *Info = Traits.getCommandInfo(C->getCommandID()); 335259701Sdim if (Info->IsBriefCommand) { 336259701Sdim Result << "<p class=\"para-brief\">"; 337259701Sdim visitNonStandaloneParagraphComment(C->getParagraph()); 338259701Sdim Result << "</p>"; 339259701Sdim return; 340259701Sdim } 341259701Sdim if (Info->IsReturnsCommand) { 342259701Sdim Result << "<p class=\"para-returns\">" 343259701Sdim "<span class=\"word-returns\">Returns</span> "; 344259701Sdim visitNonStandaloneParagraphComment(C->getParagraph()); 345259701Sdim Result << "</p>"; 346259701Sdim return; 347259701Sdim } 348259701Sdim // We don't know anything about this command. Just render the paragraph. 349259701Sdim visit(C->getParagraph()); 350259701Sdim} 351259701Sdim 352259701Sdimvoid CommentASTToHTMLConverter::visitParamCommandComment( 353259701Sdim const ParamCommandComment *C) { 354259701Sdim if (C->isParamIndexValid()) { 355259701Sdim if (C->isVarArgParam()) { 356259701Sdim Result << "<dt class=\"param-name-index-vararg\">"; 357259701Sdim appendToResultWithHTMLEscaping(C->getParamNameAsWritten()); 358259701Sdim } else { 359259701Sdim Result << "<dt class=\"param-name-index-" 360259701Sdim << C->getParamIndex() 361259701Sdim << "\">"; 362259701Sdim appendToResultWithHTMLEscaping(C->getParamName(FC)); 363259701Sdim } 364259701Sdim } else { 365259701Sdim Result << "<dt class=\"param-name-index-invalid\">"; 366259701Sdim appendToResultWithHTMLEscaping(C->getParamNameAsWritten()); 367259701Sdim } 368259701Sdim Result << "</dt>"; 369259701Sdim 370259701Sdim if (C->isParamIndexValid()) { 371259701Sdim if (C->isVarArgParam()) 372259701Sdim Result << "<dd class=\"param-descr-index-vararg\">"; 373259701Sdim else 374259701Sdim Result << "<dd class=\"param-descr-index-" 375259701Sdim << C->getParamIndex() 376259701Sdim << "\">"; 377259701Sdim } else 378259701Sdim Result << "<dd class=\"param-descr-index-invalid\">"; 379259701Sdim 380259701Sdim visitNonStandaloneParagraphComment(C->getParagraph()); 381259701Sdim Result << "</dd>"; 382259701Sdim} 383259701Sdim 384259701Sdimvoid CommentASTToHTMLConverter::visitTParamCommandComment( 385259701Sdim const TParamCommandComment *C) { 386259701Sdim if (C->isPositionValid()) { 387259701Sdim if (C->getDepth() == 1) 388259701Sdim Result << "<dt class=\"tparam-name-index-" 389259701Sdim << C->getIndex(0) 390259701Sdim << "\">"; 391259701Sdim else 392259701Sdim Result << "<dt class=\"tparam-name-index-other\">"; 393259701Sdim appendToResultWithHTMLEscaping(C->getParamName(FC)); 394259701Sdim } else { 395259701Sdim Result << "<dt class=\"tparam-name-index-invalid\">"; 396259701Sdim appendToResultWithHTMLEscaping(C->getParamNameAsWritten()); 397259701Sdim } 398259701Sdim 399259701Sdim Result << "</dt>"; 400259701Sdim 401259701Sdim if (C->isPositionValid()) { 402259701Sdim if (C->getDepth() == 1) 403259701Sdim Result << "<dd class=\"tparam-descr-index-" 404259701Sdim << C->getIndex(0) 405259701Sdim << "\">"; 406259701Sdim else 407259701Sdim Result << "<dd class=\"tparam-descr-index-other\">"; 408259701Sdim } else 409259701Sdim Result << "<dd class=\"tparam-descr-index-invalid\">"; 410259701Sdim 411259701Sdim visitNonStandaloneParagraphComment(C->getParagraph()); 412259701Sdim Result << "</dd>"; 413259701Sdim} 414259701Sdim 415259701Sdimvoid CommentASTToHTMLConverter::visitVerbatimBlockComment( 416259701Sdim const VerbatimBlockComment *C) { 417259701Sdim unsigned NumLines = C->getNumLines(); 418259701Sdim if (NumLines == 0) 419259701Sdim return; 420259701Sdim 421259701Sdim Result << "<pre>"; 422259701Sdim for (unsigned i = 0; i != NumLines; ++i) { 423259701Sdim appendToResultWithHTMLEscaping(C->getText(i)); 424259701Sdim if (i + 1 != NumLines) 425259701Sdim Result << '\n'; 426259701Sdim } 427259701Sdim Result << "</pre>"; 428259701Sdim} 429259701Sdim 430259701Sdimvoid CommentASTToHTMLConverter::visitVerbatimBlockLineComment( 431259701Sdim const VerbatimBlockLineComment *C) { 432259701Sdim llvm_unreachable("should not see this AST node"); 433259701Sdim} 434259701Sdim 435259701Sdimvoid CommentASTToHTMLConverter::visitVerbatimLineComment( 436259701Sdim const VerbatimLineComment *C) { 437259701Sdim Result << "<pre>"; 438259701Sdim appendToResultWithHTMLEscaping(C->getText()); 439259701Sdim Result << "</pre>"; 440259701Sdim} 441259701Sdim 442259701Sdimvoid CommentASTToHTMLConverter::visitFullComment(const FullComment *C) { 443259701Sdim FullCommentParts Parts(C, Traits); 444259701Sdim 445259701Sdim bool FirstParagraphIsBrief = false; 446259701Sdim if (Parts.Headerfile) 447259701Sdim visit(Parts.Headerfile); 448259701Sdim if (Parts.Brief) 449259701Sdim visit(Parts.Brief); 450259701Sdim else if (Parts.FirstParagraph) { 451259701Sdim Result << "<p class=\"para-brief\">"; 452259701Sdim visitNonStandaloneParagraphComment(Parts.FirstParagraph); 453259701Sdim Result << "</p>"; 454259701Sdim FirstParagraphIsBrief = true; 455259701Sdim } 456259701Sdim 457259701Sdim for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) { 458259701Sdim const Comment *C = Parts.MiscBlocks[i]; 459259701Sdim if (FirstParagraphIsBrief && C == Parts.FirstParagraph) 460259701Sdim continue; 461259701Sdim visit(C); 462259701Sdim } 463259701Sdim 464259701Sdim if (Parts.TParams.size() != 0) { 465259701Sdim Result << "<dl>"; 466259701Sdim for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i) 467259701Sdim visit(Parts.TParams[i]); 468259701Sdim Result << "</dl>"; 469259701Sdim } 470259701Sdim 471259701Sdim if (Parts.Params.size() != 0) { 472259701Sdim Result << "<dl>"; 473259701Sdim for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i) 474259701Sdim visit(Parts.Params[i]); 475259701Sdim Result << "</dl>"; 476259701Sdim } 477259701Sdim 478259701Sdim if (Parts.Returns.size() != 0) { 479259701Sdim Result << "<div class=\"result-discussion\">"; 480259701Sdim for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i) 481259701Sdim visit(Parts.Returns[i]); 482259701Sdim Result << "</div>"; 483259701Sdim } 484259701Sdim 485259701Sdim Result.flush(); 486259701Sdim} 487259701Sdim 488259701Sdimvoid CommentASTToHTMLConverter::visitNonStandaloneParagraphComment( 489259701Sdim const ParagraphComment *C) { 490259701Sdim if (!C) 491259701Sdim return; 492259701Sdim 493259701Sdim for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); 494259701Sdim I != E; ++I) { 495259701Sdim visit(*I); 496259701Sdim } 497259701Sdim} 498259701Sdim 499259701Sdimvoid CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) { 500259701Sdim for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) { 501259701Sdim const char C = *I; 502259701Sdim switch (C) { 503259701Sdim case '&': 504259701Sdim Result << "&"; 505259701Sdim break; 506259701Sdim case '<': 507259701Sdim Result << "<"; 508259701Sdim break; 509259701Sdim case '>': 510259701Sdim Result << ">"; 511259701Sdim break; 512259701Sdim case '"': 513259701Sdim Result << """; 514259701Sdim break; 515259701Sdim case '\'': 516259701Sdim Result << "'"; 517259701Sdim break; 518259701Sdim case '/': 519259701Sdim Result << "/"; 520259701Sdim break; 521259701Sdim default: 522259701Sdim Result << C; 523259701Sdim break; 524259701Sdim } 525259701Sdim } 526259701Sdim} 527259701Sdim 528259701Sdimnamespace { 529259701Sdimclass CommentASTToXMLConverter : 530259701Sdim public ConstCommentVisitor<CommentASTToXMLConverter> { 531259701Sdimpublic: 532259701Sdim /// \param Str accumulator for XML. 533259701Sdim CommentASTToXMLConverter(const FullComment *FC, 534259701Sdim SmallVectorImpl<char> &Str, 535259701Sdim const CommandTraits &Traits, 536259701Sdim const SourceManager &SM, 537259701Sdim SimpleFormatContext &SFC, 538259701Sdim unsigned FUID) : 539259701Sdim FC(FC), Result(Str), Traits(Traits), SM(SM), 540259701Sdim FormatRewriterContext(SFC), 541259701Sdim FormatInMemoryUniqueId(FUID) { } 542259701Sdim 543259701Sdim // Inline content. 544259701Sdim void visitTextComment(const TextComment *C); 545259701Sdim void visitInlineCommandComment(const InlineCommandComment *C); 546259701Sdim void visitHTMLStartTagComment(const HTMLStartTagComment *C); 547259701Sdim void visitHTMLEndTagComment(const HTMLEndTagComment *C); 548259701Sdim 549259701Sdim // Block content. 550259701Sdim void visitParagraphComment(const ParagraphComment *C); 551259701Sdim 552259701Sdim void appendParagraphCommentWithKind(const ParagraphComment *C, 553259701Sdim StringRef Kind); 554259701Sdim 555259701Sdim void visitBlockCommandComment(const BlockCommandComment *C); 556259701Sdim void visitParamCommandComment(const ParamCommandComment *C); 557259701Sdim void visitTParamCommandComment(const TParamCommandComment *C); 558259701Sdim void visitVerbatimBlockComment(const VerbatimBlockComment *C); 559259701Sdim void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C); 560259701Sdim void visitVerbatimLineComment(const VerbatimLineComment *C); 561259701Sdim 562259701Sdim void visitFullComment(const FullComment *C); 563259701Sdim 564259701Sdim // Helpers. 565259701Sdim void appendToResultWithXMLEscaping(StringRef S); 566259701Sdim 567259701Sdim void formatTextOfDeclaration(const DeclInfo *DI, 568259701Sdim SmallString<128> &Declaration); 569259701Sdim 570259701Sdimprivate: 571259701Sdim const FullComment *FC; 572259701Sdim 573259701Sdim /// Output stream for XML. 574259701Sdim llvm::raw_svector_ostream Result; 575259701Sdim 576259701Sdim const CommandTraits &Traits; 577259701Sdim const SourceManager &SM; 578259701Sdim SimpleFormatContext &FormatRewriterContext; 579259701Sdim unsigned FormatInMemoryUniqueId; 580259701Sdim}; 581259701Sdim 582259701Sdimvoid getSourceTextOfDeclaration(const DeclInfo *ThisDecl, 583259701Sdim SmallVectorImpl<char> &Str) { 584259701Sdim ASTContext &Context = ThisDecl->CurrentDecl->getASTContext(); 585259701Sdim const LangOptions &LangOpts = Context.getLangOpts(); 586259701Sdim llvm::raw_svector_ostream OS(Str); 587259701Sdim PrintingPolicy PPolicy(LangOpts); 588259701Sdim PPolicy.PolishForDeclaration = true; 589259701Sdim PPolicy.TerseOutput = true; 590259701Sdim ThisDecl->CurrentDecl->print(OS, PPolicy, 591259701Sdim /*Indentation*/0, /*PrintInstantiation*/false); 592259701Sdim} 593259701Sdim 594259701Sdimvoid CommentASTToXMLConverter::formatTextOfDeclaration( 595259701Sdim const DeclInfo *DI, SmallString<128> &Declaration) { 596259701Sdim // FIXME. formatting API expects null terminated input string. 597259701Sdim // There might be more efficient way of doing this. 598259701Sdim std::string StringDecl = Declaration.str(); 599259701Sdim 600259701Sdim // Formatter specific code. 601259701Sdim // Form a unique in memory buffer name. 602259701Sdim SmallString<128> filename; 603259701Sdim filename += "xmldecl"; 604259701Sdim filename += llvm::utostr(FormatInMemoryUniqueId); 605259701Sdim filename += ".xd"; 606259701Sdim FileID ID = FormatRewriterContext.createInMemoryFile(filename, StringDecl); 607259701Sdim SourceLocation Start = FormatRewriterContext.Sources.getLocForStartOfFile(ID) 608259701Sdim .getLocWithOffset(0); 609259701Sdim unsigned Length = Declaration.size(); 610259701Sdim 611259701Sdim std::vector<CharSourceRange> Ranges( 612259701Sdim 1, CharSourceRange::getCharRange(Start, Start.getLocWithOffset(Length))); 613259701Sdim ASTContext &Context = DI->CurrentDecl->getASTContext(); 614259701Sdim const LangOptions &LangOpts = Context.getLangOpts(); 615259701Sdim Lexer Lex(ID, FormatRewriterContext.Sources.getBuffer(ID), 616259701Sdim FormatRewriterContext.Sources, LangOpts); 617259701Sdim tooling::Replacements Replace = reformat( 618259701Sdim format::getLLVMStyle(), Lex, FormatRewriterContext.Sources, Ranges); 619259701Sdim applyAllReplacements(Replace, FormatRewriterContext.Rewrite); 620259701Sdim Declaration = FormatRewriterContext.getRewrittenText(ID); 621259701Sdim} 622259701Sdim 623259701Sdim} // end unnamed namespace 624259701Sdim 625259701Sdimvoid CommentASTToXMLConverter::visitTextComment(const TextComment *C) { 626259701Sdim appendToResultWithXMLEscaping(C->getText()); 627259701Sdim} 628259701Sdim 629259701Sdimvoid CommentASTToXMLConverter::visitInlineCommandComment( 630259701Sdim const InlineCommandComment *C) { 631259701Sdim // Nothing to render if no arguments supplied. 632259701Sdim if (C->getNumArgs() == 0) 633259701Sdim return; 634259701Sdim 635259701Sdim // Nothing to render if argument is empty. 636259701Sdim StringRef Arg0 = C->getArgText(0); 637259701Sdim if (Arg0.empty()) 638259701Sdim return; 639259701Sdim 640259701Sdim switch (C->getRenderKind()) { 641259701Sdim case InlineCommandComment::RenderNormal: 642259701Sdim for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) { 643259701Sdim appendToResultWithXMLEscaping(C->getArgText(i)); 644259701Sdim Result << " "; 645259701Sdim } 646259701Sdim return; 647259701Sdim case InlineCommandComment::RenderBold: 648259701Sdim assert(C->getNumArgs() == 1); 649259701Sdim Result << "<bold>"; 650259701Sdim appendToResultWithXMLEscaping(Arg0); 651259701Sdim Result << "</bold>"; 652259701Sdim return; 653259701Sdim case InlineCommandComment::RenderMonospaced: 654259701Sdim assert(C->getNumArgs() == 1); 655259701Sdim Result << "<monospaced>"; 656259701Sdim appendToResultWithXMLEscaping(Arg0); 657259701Sdim Result << "</monospaced>"; 658259701Sdim return; 659259701Sdim case InlineCommandComment::RenderEmphasized: 660259701Sdim assert(C->getNumArgs() == 1); 661259701Sdim Result << "<emphasized>"; 662259701Sdim appendToResultWithXMLEscaping(Arg0); 663259701Sdim Result << "</emphasized>"; 664259701Sdim return; 665259701Sdim } 666259701Sdim} 667259701Sdim 668259701Sdimvoid CommentASTToXMLConverter::visitHTMLStartTagComment( 669259701Sdim const HTMLStartTagComment *C) { 670259701Sdim Result << "<rawHTML><![CDATA["; 671259701Sdim printHTMLStartTagComment(C, Result); 672259701Sdim Result << "]]></rawHTML>"; 673259701Sdim} 674259701Sdim 675259701Sdimvoid 676259701SdimCommentASTToXMLConverter::visitHTMLEndTagComment(const HTMLEndTagComment *C) { 677259701Sdim Result << "<rawHTML></" << C->getTagName() << "></rawHTML>"; 678259701Sdim} 679259701Sdim 680259701Sdimvoid 681259701SdimCommentASTToXMLConverter::visitParagraphComment(const ParagraphComment *C) { 682259701Sdim appendParagraphCommentWithKind(C, StringRef()); 683259701Sdim} 684259701Sdim 685259701Sdimvoid CommentASTToXMLConverter::appendParagraphCommentWithKind( 686259701Sdim const ParagraphComment *C, 687259701Sdim StringRef ParagraphKind) { 688259701Sdim if (C->isWhitespace()) 689259701Sdim return; 690259701Sdim 691259701Sdim if (ParagraphKind.empty()) 692259701Sdim Result << "<Para>"; 693259701Sdim else 694259701Sdim Result << "<Para kind=\"" << ParagraphKind << "\">"; 695259701Sdim 696259701Sdim for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); 697259701Sdim I != E; ++I) { 698259701Sdim visit(*I); 699259701Sdim } 700259701Sdim Result << "</Para>"; 701259701Sdim} 702259701Sdim 703259701Sdimvoid CommentASTToXMLConverter::visitBlockCommandComment( 704259701Sdim const BlockCommandComment *C) { 705259701Sdim StringRef ParagraphKind; 706259701Sdim 707259701Sdim switch (C->getCommandID()) { 708259701Sdim case CommandTraits::KCI_attention: 709259701Sdim case CommandTraits::KCI_author: 710259701Sdim case CommandTraits::KCI_authors: 711259701Sdim case CommandTraits::KCI_bug: 712259701Sdim case CommandTraits::KCI_copyright: 713259701Sdim case CommandTraits::KCI_date: 714259701Sdim case CommandTraits::KCI_invariant: 715259701Sdim case CommandTraits::KCI_note: 716259701Sdim case CommandTraits::KCI_post: 717259701Sdim case CommandTraits::KCI_pre: 718259701Sdim case CommandTraits::KCI_remark: 719259701Sdim case CommandTraits::KCI_remarks: 720259701Sdim case CommandTraits::KCI_sa: 721259701Sdim case CommandTraits::KCI_see: 722259701Sdim case CommandTraits::KCI_since: 723259701Sdim case CommandTraits::KCI_todo: 724259701Sdim case CommandTraits::KCI_version: 725259701Sdim case CommandTraits::KCI_warning: 726259701Sdim ParagraphKind = C->getCommandName(Traits); 727259701Sdim default: 728259701Sdim break; 729259701Sdim } 730259701Sdim 731259701Sdim appendParagraphCommentWithKind(C->getParagraph(), ParagraphKind); 732259701Sdim} 733259701Sdim 734259701Sdimvoid CommentASTToXMLConverter::visitParamCommandComment( 735259701Sdim const ParamCommandComment *C) { 736259701Sdim Result << "<Parameter><Name>"; 737259701Sdim appendToResultWithXMLEscaping(C->isParamIndexValid() 738259701Sdim ? C->getParamName(FC) 739259701Sdim : C->getParamNameAsWritten()); 740259701Sdim Result << "</Name>"; 741259701Sdim 742259701Sdim if (C->isParamIndexValid()) { 743259701Sdim if (C->isVarArgParam()) 744259701Sdim Result << "<IsVarArg />"; 745259701Sdim else 746259701Sdim Result << "<Index>" << C->getParamIndex() << "</Index>"; 747259701Sdim } 748259701Sdim 749259701Sdim Result << "<Direction isExplicit=\"" << C->isDirectionExplicit() << "\">"; 750259701Sdim switch (C->getDirection()) { 751259701Sdim case ParamCommandComment::In: 752259701Sdim Result << "in"; 753259701Sdim break; 754259701Sdim case ParamCommandComment::Out: 755259701Sdim Result << "out"; 756259701Sdim break; 757259701Sdim case ParamCommandComment::InOut: 758259701Sdim Result << "in,out"; 759259701Sdim break; 760259701Sdim } 761259701Sdim Result << "</Direction><Discussion>"; 762259701Sdim visit(C->getParagraph()); 763259701Sdim Result << "</Discussion></Parameter>"; 764259701Sdim} 765259701Sdim 766259701Sdimvoid CommentASTToXMLConverter::visitTParamCommandComment( 767259701Sdim const TParamCommandComment *C) { 768259701Sdim Result << "<Parameter><Name>"; 769259701Sdim appendToResultWithXMLEscaping(C->isPositionValid() ? C->getParamName(FC) 770259701Sdim : C->getParamNameAsWritten()); 771259701Sdim Result << "</Name>"; 772259701Sdim 773259701Sdim if (C->isPositionValid() && C->getDepth() == 1) { 774259701Sdim Result << "<Index>" << C->getIndex(0) << "</Index>"; 775259701Sdim } 776259701Sdim 777259701Sdim Result << "<Discussion>"; 778259701Sdim visit(C->getParagraph()); 779259701Sdim Result << "</Discussion></Parameter>"; 780259701Sdim} 781259701Sdim 782259701Sdimvoid CommentASTToXMLConverter::visitVerbatimBlockComment( 783259701Sdim const VerbatimBlockComment *C) { 784259701Sdim unsigned NumLines = C->getNumLines(); 785259701Sdim if (NumLines == 0) 786259701Sdim return; 787259701Sdim 788259701Sdim switch (C->getCommandID()) { 789259701Sdim case CommandTraits::KCI_code: 790259701Sdim Result << "<Verbatim xml:space=\"preserve\" kind=\"code\">"; 791259701Sdim break; 792259701Sdim default: 793259701Sdim Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">"; 794259701Sdim break; 795259701Sdim } 796259701Sdim for (unsigned i = 0; i != NumLines; ++i) { 797259701Sdim appendToResultWithXMLEscaping(C->getText(i)); 798259701Sdim if (i + 1 != NumLines) 799259701Sdim Result << '\n'; 800259701Sdim } 801259701Sdim Result << "</Verbatim>"; 802259701Sdim} 803259701Sdim 804259701Sdimvoid CommentASTToXMLConverter::visitVerbatimBlockLineComment( 805259701Sdim const VerbatimBlockLineComment *C) { 806259701Sdim llvm_unreachable("should not see this AST node"); 807259701Sdim} 808259701Sdim 809259701Sdimvoid CommentASTToXMLConverter::visitVerbatimLineComment( 810259701Sdim const VerbatimLineComment *C) { 811259701Sdim Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">"; 812259701Sdim appendToResultWithXMLEscaping(C->getText()); 813259701Sdim Result << "</Verbatim>"; 814259701Sdim} 815259701Sdim 816259701Sdimvoid CommentASTToXMLConverter::visitFullComment(const FullComment *C) { 817259701Sdim FullCommentParts Parts(C, Traits); 818259701Sdim 819259701Sdim const DeclInfo *DI = C->getDeclInfo(); 820259701Sdim StringRef RootEndTag; 821259701Sdim if (DI) { 822259701Sdim switch (DI->getKind()) { 823259701Sdim case DeclInfo::OtherKind: 824259701Sdim RootEndTag = "</Other>"; 825259701Sdim Result << "<Other"; 826259701Sdim break; 827259701Sdim case DeclInfo::FunctionKind: 828259701Sdim RootEndTag = "</Function>"; 829259701Sdim Result << "<Function"; 830259701Sdim switch (DI->TemplateKind) { 831259701Sdim case DeclInfo::NotTemplate: 832259701Sdim break; 833259701Sdim case DeclInfo::Template: 834259701Sdim Result << " templateKind=\"template\""; 835259701Sdim break; 836259701Sdim case DeclInfo::TemplateSpecialization: 837259701Sdim Result << " templateKind=\"specialization\""; 838259701Sdim break; 839259701Sdim case DeclInfo::TemplatePartialSpecialization: 840259701Sdim llvm_unreachable("partial specializations of functions " 841259701Sdim "are not allowed in C++"); 842259701Sdim } 843259701Sdim if (DI->IsInstanceMethod) 844259701Sdim Result << " isInstanceMethod=\"1\""; 845259701Sdim if (DI->IsClassMethod) 846259701Sdim Result << " isClassMethod=\"1\""; 847259701Sdim break; 848259701Sdim case DeclInfo::ClassKind: 849259701Sdim RootEndTag = "</Class>"; 850259701Sdim Result << "<Class"; 851259701Sdim switch (DI->TemplateKind) { 852259701Sdim case DeclInfo::NotTemplate: 853259701Sdim break; 854259701Sdim case DeclInfo::Template: 855259701Sdim Result << " templateKind=\"template\""; 856259701Sdim break; 857259701Sdim case DeclInfo::TemplateSpecialization: 858259701Sdim Result << " templateKind=\"specialization\""; 859259701Sdim break; 860259701Sdim case DeclInfo::TemplatePartialSpecialization: 861259701Sdim Result << " templateKind=\"partialSpecialization\""; 862259701Sdim break; 863259701Sdim } 864259701Sdim break; 865259701Sdim case DeclInfo::VariableKind: 866259701Sdim RootEndTag = "</Variable>"; 867259701Sdim Result << "<Variable"; 868259701Sdim break; 869259701Sdim case DeclInfo::NamespaceKind: 870259701Sdim RootEndTag = "</Namespace>"; 871259701Sdim Result << "<Namespace"; 872259701Sdim break; 873259701Sdim case DeclInfo::TypedefKind: 874259701Sdim RootEndTag = "</Typedef>"; 875259701Sdim Result << "<Typedef"; 876259701Sdim break; 877259701Sdim case DeclInfo::EnumKind: 878259701Sdim RootEndTag = "</Enum>"; 879259701Sdim Result << "<Enum"; 880259701Sdim break; 881259701Sdim } 882259701Sdim 883259701Sdim { 884259701Sdim // Print line and column number. 885259701Sdim SourceLocation Loc = DI->CurrentDecl->getLocation(); 886259701Sdim std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); 887259701Sdim FileID FID = LocInfo.first; 888259701Sdim unsigned FileOffset = LocInfo.second; 889259701Sdim 890259701Sdim if (!FID.isInvalid()) { 891259701Sdim if (const FileEntry *FE = SM.getFileEntryForID(FID)) { 892259701Sdim Result << " file=\""; 893259701Sdim appendToResultWithXMLEscaping(FE->getName()); 894259701Sdim Result << "\""; 895259701Sdim } 896259701Sdim Result << " line=\"" << SM.getLineNumber(FID, FileOffset) 897259701Sdim << "\" column=\"" << SM.getColumnNumber(FID, FileOffset) 898259701Sdim << "\""; 899259701Sdim } 900259701Sdim } 901259701Sdim 902259701Sdim // Finish the root tag. 903259701Sdim Result << ">"; 904259701Sdim 905259701Sdim bool FoundName = false; 906259701Sdim if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->CommentDecl)) { 907259701Sdim if (DeclarationName DeclName = ND->getDeclName()) { 908259701Sdim Result << "<Name>"; 909259701Sdim std::string Name = DeclName.getAsString(); 910259701Sdim appendToResultWithXMLEscaping(Name); 911259701Sdim FoundName = true; 912259701Sdim Result << "</Name>"; 913259701Sdim } 914259701Sdim } 915259701Sdim if (!FoundName) 916259701Sdim Result << "<Name><anonymous></Name>"; 917259701Sdim 918259701Sdim { 919259701Sdim // Print USR. 920259701Sdim SmallString<128> USR; 921259701Sdim generateUSRForDecl(DI->CommentDecl, USR); 922259701Sdim if (!USR.empty()) { 923259701Sdim Result << "<USR>"; 924259701Sdim appendToResultWithXMLEscaping(USR); 925259701Sdim Result << "</USR>"; 926259701Sdim } 927259701Sdim } 928259701Sdim } else { 929259701Sdim // No DeclInfo -- just emit some root tag and name tag. 930259701Sdim RootEndTag = "</Other>"; 931259701Sdim Result << "<Other><Name>unknown</Name>"; 932259701Sdim } 933259701Sdim 934259701Sdim if (Parts.Headerfile) { 935259701Sdim Result << "<Headerfile>"; 936259701Sdim visit(Parts.Headerfile); 937259701Sdim Result << "</Headerfile>"; 938259701Sdim } 939259701Sdim 940259701Sdim { 941259701Sdim // Pretty-print the declaration. 942259701Sdim Result << "<Declaration>"; 943259701Sdim SmallString<128> Declaration; 944259701Sdim getSourceTextOfDeclaration(DI, Declaration); 945259701Sdim formatTextOfDeclaration(DI, Declaration); 946259701Sdim appendToResultWithXMLEscaping(Declaration); 947259701Sdim Result << "</Declaration>"; 948259701Sdim } 949259701Sdim 950259701Sdim bool FirstParagraphIsBrief = false; 951259701Sdim if (Parts.Brief) { 952259701Sdim Result << "<Abstract>"; 953259701Sdim visit(Parts.Brief); 954259701Sdim Result << "</Abstract>"; 955259701Sdim } else if (Parts.FirstParagraph) { 956259701Sdim Result << "<Abstract>"; 957259701Sdim visit(Parts.FirstParagraph); 958259701Sdim Result << "</Abstract>"; 959259701Sdim FirstParagraphIsBrief = true; 960259701Sdim } 961259701Sdim 962259701Sdim if (Parts.TParams.size() != 0) { 963259701Sdim Result << "<TemplateParameters>"; 964259701Sdim for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i) 965259701Sdim visit(Parts.TParams[i]); 966259701Sdim Result << "</TemplateParameters>"; 967259701Sdim } 968259701Sdim 969259701Sdim if (Parts.Params.size() != 0) { 970259701Sdim Result << "<Parameters>"; 971259701Sdim for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i) 972259701Sdim visit(Parts.Params[i]); 973259701Sdim Result << "</Parameters>"; 974259701Sdim } 975259701Sdim 976259701Sdim if (Parts.Exceptions.size() != 0) { 977259701Sdim Result << "<Exceptions>"; 978259701Sdim for (unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i) 979259701Sdim visit(Parts.Exceptions[i]); 980259701Sdim Result << "</Exceptions>"; 981259701Sdim } 982259701Sdim 983259701Sdim if (Parts.Returns.size() != 0) { 984259701Sdim Result << "<ResultDiscussion>"; 985259701Sdim for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i) 986259701Sdim visit(Parts.Returns[i]); 987259701Sdim Result << "</ResultDiscussion>"; 988259701Sdim } 989259701Sdim 990259701Sdim if (DI->CommentDecl->hasAttrs()) { 991259701Sdim const AttrVec &Attrs = DI->CommentDecl->getAttrs(); 992259701Sdim for (unsigned i = 0, e = Attrs.size(); i != e; i++) { 993259701Sdim const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]); 994259701Sdim if (!AA) { 995259701Sdim if (const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) { 996259701Sdim if (DA->getMessage().empty()) 997259701Sdim Result << "<Deprecated/>"; 998259701Sdim else { 999259701Sdim Result << "<Deprecated>"; 1000259701Sdim appendToResultWithXMLEscaping(DA->getMessage()); 1001259701Sdim Result << "</Deprecated>"; 1002259701Sdim } 1003259701Sdim } 1004259701Sdim else if (const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) { 1005259701Sdim if (UA->getMessage().empty()) 1006259701Sdim Result << "<Unavailable/>"; 1007259701Sdim else { 1008259701Sdim Result << "<Unavailable>"; 1009259701Sdim appendToResultWithXMLEscaping(UA->getMessage()); 1010259701Sdim Result << "</Unavailable>"; 1011259701Sdim } 1012259701Sdim } 1013259701Sdim continue; 1014259701Sdim } 1015259701Sdim 1016259701Sdim // 'availability' attribute. 1017259701Sdim Result << "<Availability"; 1018259701Sdim StringRef Distribution; 1019259701Sdim if (AA->getPlatform()) { 1020259701Sdim Distribution = AvailabilityAttr::getPrettyPlatformName( 1021259701Sdim AA->getPlatform()->getName()); 1022259701Sdim if (Distribution.empty()) 1023259701Sdim Distribution = AA->getPlatform()->getName(); 1024259701Sdim } 1025259701Sdim Result << " distribution=\"" << Distribution << "\">"; 1026259701Sdim VersionTuple IntroducedInVersion = AA->getIntroduced(); 1027259701Sdim if (!IntroducedInVersion.empty()) { 1028259701Sdim Result << "<IntroducedInVersion>" 1029259701Sdim << IntroducedInVersion.getAsString() 1030259701Sdim << "</IntroducedInVersion>"; 1031259701Sdim } 1032259701Sdim VersionTuple DeprecatedInVersion = AA->getDeprecated(); 1033259701Sdim if (!DeprecatedInVersion.empty()) { 1034259701Sdim Result << "<DeprecatedInVersion>" 1035259701Sdim << DeprecatedInVersion.getAsString() 1036259701Sdim << "</DeprecatedInVersion>"; 1037259701Sdim } 1038259701Sdim VersionTuple RemovedAfterVersion = AA->getObsoleted(); 1039259701Sdim if (!RemovedAfterVersion.empty()) { 1040259701Sdim Result << "<RemovedAfterVersion>" 1041259701Sdim << RemovedAfterVersion.getAsString() 1042259701Sdim << "</RemovedAfterVersion>"; 1043259701Sdim } 1044259701Sdim StringRef DeprecationSummary = AA->getMessage(); 1045259701Sdim if (!DeprecationSummary.empty()) { 1046259701Sdim Result << "<DeprecationSummary>"; 1047259701Sdim appendToResultWithXMLEscaping(DeprecationSummary); 1048259701Sdim Result << "</DeprecationSummary>"; 1049259701Sdim } 1050259701Sdim if (AA->getUnavailable()) 1051259701Sdim Result << "<Unavailable/>"; 1052259701Sdim Result << "</Availability>"; 1053259701Sdim } 1054259701Sdim } 1055259701Sdim 1056259701Sdim { 1057259701Sdim bool StartTagEmitted = false; 1058259701Sdim for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) { 1059259701Sdim const Comment *C = Parts.MiscBlocks[i]; 1060259701Sdim if (FirstParagraphIsBrief && C == Parts.FirstParagraph) 1061259701Sdim continue; 1062259701Sdim if (!StartTagEmitted) { 1063259701Sdim Result << "<Discussion>"; 1064259701Sdim StartTagEmitted = true; 1065259701Sdim } 1066259701Sdim visit(C); 1067259701Sdim } 1068259701Sdim if (StartTagEmitted) 1069259701Sdim Result << "</Discussion>"; 1070259701Sdim } 1071259701Sdim 1072259701Sdim Result << RootEndTag; 1073259701Sdim 1074259701Sdim Result.flush(); 1075259701Sdim} 1076259701Sdim 1077259701Sdimvoid CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) { 1078259701Sdim for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) { 1079259701Sdim const char C = *I; 1080259701Sdim switch (C) { 1081259701Sdim case '&': 1082259701Sdim Result << "&"; 1083259701Sdim break; 1084259701Sdim case '<': 1085259701Sdim Result << "<"; 1086259701Sdim break; 1087259701Sdim case '>': 1088259701Sdim Result << ">"; 1089259701Sdim break; 1090259701Sdim case '"': 1091259701Sdim Result << """; 1092259701Sdim break; 1093259701Sdim case '\'': 1094259701Sdim Result << "'"; 1095259701Sdim break; 1096259701Sdim default: 1097259701Sdim Result << C; 1098259701Sdim break; 1099259701Sdim } 1100259701Sdim } 1101259701Sdim} 1102259701Sdim 1103259701Sdimvoid CommentToXMLConverter::convertCommentToHTML(const FullComment *FC, 1104259701Sdim SmallVectorImpl<char> &HTML, 1105259701Sdim const ASTContext &Context) { 1106259701Sdim CommentASTToHTMLConverter Converter(FC, HTML, 1107259701Sdim Context.getCommentCommandTraits()); 1108259701Sdim Converter.visit(FC); 1109259701Sdim} 1110259701Sdim 1111259701Sdimvoid CommentToXMLConverter::convertHTMLTagNodeToText( 1112259701Sdim const comments::HTMLTagComment *HTC, SmallVectorImpl<char> &Text, 1113259701Sdim const ASTContext &Context) { 1114259701Sdim CommentASTToHTMLConverter Converter(0, Text, 1115259701Sdim Context.getCommentCommandTraits()); 1116259701Sdim Converter.visit(HTC); 1117259701Sdim} 1118259701Sdim 1119259701Sdimvoid CommentToXMLConverter::convertCommentToXML(const FullComment *FC, 1120259701Sdim SmallVectorImpl<char> &XML, 1121259701Sdim const ASTContext &Context) { 1122259701Sdim if (!FormatContext) { 1123259701Sdim FormatContext = new SimpleFormatContext(Context.getLangOpts()); 1124259701Sdim } else if ((FormatInMemoryUniqueId % 1000) == 0) { 1125259701Sdim // Delete after some number of iterations, so the buffers don't grow 1126259701Sdim // too large. 1127259701Sdim delete FormatContext; 1128259701Sdim FormatContext = new SimpleFormatContext(Context.getLangOpts()); 1129259701Sdim } 1130259701Sdim 1131259701Sdim CommentASTToXMLConverter Converter(FC, XML, Context.getCommentCommandTraits(), 1132259701Sdim Context.getSourceManager(), *FormatContext, 1133259701Sdim FormatInMemoryUniqueId++); 1134259701Sdim Converter.visit(FC); 1135259701Sdim} 1136259701Sdim 1137