10b57cec5SDimitry Andric //===--- CommentToXML.cpp - Convert comments to XML representation --------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "clang/Index/CommentToXML.h" 100b57cec5SDimitry Andric #include "clang/AST/ASTContext.h" 110b57cec5SDimitry Andric #include "clang/AST/Attr.h" 120b57cec5SDimitry Andric #include "clang/AST/Comment.h" 130b57cec5SDimitry Andric #include "clang/AST/CommentVisitor.h" 145ffd83dbSDimitry Andric #include "clang/Basic/FileManager.h" 15*0fca6ea1SDimitry Andric #include "clang/Basic/IdentifierTable.h" 165ffd83dbSDimitry Andric #include "clang/Basic/SourceManager.h" 170b57cec5SDimitry Andric #include "clang/Format/Format.h" 180b57cec5SDimitry Andric #include "clang/Index/USRGeneration.h" 190b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 200b57cec5SDimitry Andric #include "llvm/ADT/TinyPtrVector.h" 210b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric using namespace clang; 240b57cec5SDimitry Andric using namespace clang::comments; 250b57cec5SDimitry Andric using namespace clang::index; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric namespace { 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric /// This comparison will sort parameters with valid index by index, then vararg 300b57cec5SDimitry Andric /// parameters, and invalid (unresolved) parameters last. 310b57cec5SDimitry Andric class ParamCommandCommentCompareIndex { 320b57cec5SDimitry Andric public: 330b57cec5SDimitry Andric bool operator()(const ParamCommandComment *LHS, 340b57cec5SDimitry Andric const ParamCommandComment *RHS) const { 350b57cec5SDimitry Andric unsigned LHSIndex = UINT_MAX; 360b57cec5SDimitry Andric unsigned RHSIndex = UINT_MAX; 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric if (LHS->isParamIndexValid()) { 390b57cec5SDimitry Andric if (LHS->isVarArgParam()) 400b57cec5SDimitry Andric LHSIndex = UINT_MAX - 1; 410b57cec5SDimitry Andric else 420b57cec5SDimitry Andric LHSIndex = LHS->getParamIndex(); 430b57cec5SDimitry Andric } 440b57cec5SDimitry Andric if (RHS->isParamIndexValid()) { 450b57cec5SDimitry Andric if (RHS->isVarArgParam()) 460b57cec5SDimitry Andric RHSIndex = UINT_MAX - 1; 470b57cec5SDimitry Andric else 480b57cec5SDimitry Andric RHSIndex = RHS->getParamIndex(); 490b57cec5SDimitry Andric } 500b57cec5SDimitry Andric return LHSIndex < RHSIndex; 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric }; 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric /// This comparison will sort template parameters in the following order: 550b57cec5SDimitry Andric /// \li real template parameters (depth = 1) in index order; 560b57cec5SDimitry Andric /// \li all other names (depth > 1); 570b57cec5SDimitry Andric /// \li unresolved names. 580b57cec5SDimitry Andric class TParamCommandCommentComparePosition { 590b57cec5SDimitry Andric public: 600b57cec5SDimitry Andric bool operator()(const TParamCommandComment *LHS, 610b57cec5SDimitry Andric const TParamCommandComment *RHS) const { 620b57cec5SDimitry Andric // Sort unresolved names last. 630b57cec5SDimitry Andric if (!LHS->isPositionValid()) 640b57cec5SDimitry Andric return false; 650b57cec5SDimitry Andric if (!RHS->isPositionValid()) 660b57cec5SDimitry Andric return true; 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric if (LHS->getDepth() > 1) 690b57cec5SDimitry Andric return false; 700b57cec5SDimitry Andric if (RHS->getDepth() > 1) 710b57cec5SDimitry Andric return true; 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric // Sort template parameters in index order. 740b57cec5SDimitry Andric if (LHS->getDepth() == 1 && RHS->getDepth() == 1) 750b57cec5SDimitry Andric return LHS->getIndex(0) < RHS->getIndex(0); 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric // Leave all other names in source order. 780b57cec5SDimitry Andric return true; 790b57cec5SDimitry Andric } 800b57cec5SDimitry Andric }; 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric /// Separate parts of a FullComment. 830b57cec5SDimitry Andric struct FullCommentParts { 840b57cec5SDimitry Andric /// Take a full comment apart and initialize members accordingly. 850b57cec5SDimitry Andric FullCommentParts(const FullComment *C, 860b57cec5SDimitry Andric const CommandTraits &Traits); 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric const BlockContentComment *Brief; 890b57cec5SDimitry Andric const BlockContentComment *Headerfile; 900b57cec5SDimitry Andric const ParagraphComment *FirstParagraph; 910b57cec5SDimitry Andric SmallVector<const BlockCommandComment *, 4> Returns; 920b57cec5SDimitry Andric SmallVector<const ParamCommandComment *, 8> Params; 930b57cec5SDimitry Andric SmallVector<const TParamCommandComment *, 4> TParams; 940b57cec5SDimitry Andric llvm::TinyPtrVector<const BlockCommandComment *> Exceptions; 950b57cec5SDimitry Andric SmallVector<const BlockContentComment *, 8> MiscBlocks; 960b57cec5SDimitry Andric }; 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric FullCommentParts::FullCommentParts(const FullComment *C, 990b57cec5SDimitry Andric const CommandTraits &Traits) : 1000b57cec5SDimitry Andric Brief(nullptr), Headerfile(nullptr), FirstParagraph(nullptr) { 1010b57cec5SDimitry Andric for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); 1020b57cec5SDimitry Andric I != E; ++I) { 1030b57cec5SDimitry Andric const Comment *Child = *I; 1040b57cec5SDimitry Andric if (!Child) 1050b57cec5SDimitry Andric continue; 1060b57cec5SDimitry Andric switch (Child->getCommentKind()) { 1075f757f3fSDimitry Andric case CommentKind::None: 1080b57cec5SDimitry Andric continue; 1090b57cec5SDimitry Andric 1105f757f3fSDimitry Andric case CommentKind::ParagraphComment: { 1110b57cec5SDimitry Andric const ParagraphComment *PC = cast<ParagraphComment>(Child); 1120b57cec5SDimitry Andric if (PC->isWhitespace()) 1130b57cec5SDimitry Andric break; 1140b57cec5SDimitry Andric if (!FirstParagraph) 1150b57cec5SDimitry Andric FirstParagraph = PC; 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric MiscBlocks.push_back(PC); 1180b57cec5SDimitry Andric break; 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric 1215f757f3fSDimitry Andric case CommentKind::BlockCommandComment: { 1220b57cec5SDimitry Andric const BlockCommandComment *BCC = cast<BlockCommandComment>(Child); 1230b57cec5SDimitry Andric const CommandInfo *Info = Traits.getCommandInfo(BCC->getCommandID()); 1240b57cec5SDimitry Andric if (!Brief && Info->IsBriefCommand) { 1250b57cec5SDimitry Andric Brief = BCC; 1260b57cec5SDimitry Andric break; 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric if (!Headerfile && Info->IsHeaderfileCommand) { 1290b57cec5SDimitry Andric Headerfile = BCC; 1300b57cec5SDimitry Andric break; 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric if (Info->IsReturnsCommand) { 1330b57cec5SDimitry Andric Returns.push_back(BCC); 1340b57cec5SDimitry Andric break; 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric if (Info->IsThrowsCommand) { 1370b57cec5SDimitry Andric Exceptions.push_back(BCC); 1380b57cec5SDimitry Andric break; 1390b57cec5SDimitry Andric } 1400b57cec5SDimitry Andric MiscBlocks.push_back(BCC); 1410b57cec5SDimitry Andric break; 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric 1445f757f3fSDimitry Andric case CommentKind::ParamCommandComment: { 1450b57cec5SDimitry Andric const ParamCommandComment *PCC = cast<ParamCommandComment>(Child); 1460b57cec5SDimitry Andric if (!PCC->hasParamName()) 1470b57cec5SDimitry Andric break; 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric if (!PCC->isDirectionExplicit() && !PCC->hasNonWhitespaceParagraph()) 1500b57cec5SDimitry Andric break; 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric Params.push_back(PCC); 1530b57cec5SDimitry Andric break; 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric 1565f757f3fSDimitry Andric case CommentKind::TParamCommandComment: { 1570b57cec5SDimitry Andric const TParamCommandComment *TPCC = cast<TParamCommandComment>(Child); 1580b57cec5SDimitry Andric if (!TPCC->hasParamName()) 1590b57cec5SDimitry Andric break; 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric if (!TPCC->hasNonWhitespaceParagraph()) 1620b57cec5SDimitry Andric break; 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric TParams.push_back(TPCC); 1650b57cec5SDimitry Andric break; 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric 1685f757f3fSDimitry Andric case CommentKind::VerbatimBlockComment: 1690b57cec5SDimitry Andric MiscBlocks.push_back(cast<BlockCommandComment>(Child)); 1700b57cec5SDimitry Andric break; 1710b57cec5SDimitry Andric 1725f757f3fSDimitry Andric case CommentKind::VerbatimLineComment: { 1730b57cec5SDimitry Andric const VerbatimLineComment *VLC = cast<VerbatimLineComment>(Child); 1740b57cec5SDimitry Andric const CommandInfo *Info = Traits.getCommandInfo(VLC->getCommandID()); 1750b57cec5SDimitry Andric if (!Info->IsDeclarationCommand) 1760b57cec5SDimitry Andric MiscBlocks.push_back(VLC); 1770b57cec5SDimitry Andric break; 1780b57cec5SDimitry Andric } 1790b57cec5SDimitry Andric 1805f757f3fSDimitry Andric case CommentKind::TextComment: 1815f757f3fSDimitry Andric case CommentKind::InlineCommandComment: 1825f757f3fSDimitry Andric case CommentKind::HTMLStartTagComment: 1835f757f3fSDimitry Andric case CommentKind::HTMLEndTagComment: 1845f757f3fSDimitry Andric case CommentKind::VerbatimBlockLineComment: 1855f757f3fSDimitry Andric case CommentKind::FullComment: 1860b57cec5SDimitry Andric llvm_unreachable("AST node of this kind can't be a child of " 1870b57cec5SDimitry Andric "a FullComment"); 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric } 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric // Sort params in order they are declared in the function prototype. 1920b57cec5SDimitry Andric // Unresolved parameters are put at the end of the list in the same order 1930b57cec5SDimitry Andric // they were seen in the comment. 1940b57cec5SDimitry Andric llvm::stable_sort(Params, ParamCommandCommentCompareIndex()); 1950b57cec5SDimitry Andric llvm::stable_sort(TParams, TParamCommandCommentComparePosition()); 1960b57cec5SDimitry Andric } 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric void printHTMLStartTagComment(const HTMLStartTagComment *C, 1990b57cec5SDimitry Andric llvm::raw_svector_ostream &Result) { 2000b57cec5SDimitry Andric Result << "<" << C->getTagName(); 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric if (C->getNumAttrs() != 0) { 2030b57cec5SDimitry Andric for (unsigned i = 0, e = C->getNumAttrs(); i != e; i++) { 2040b57cec5SDimitry Andric Result << " "; 2050b57cec5SDimitry Andric const HTMLStartTagComment::Attribute &Attr = C->getAttr(i); 2060b57cec5SDimitry Andric Result << Attr.Name; 2070b57cec5SDimitry Andric if (!Attr.Value.empty()) 2080b57cec5SDimitry Andric Result << "=\"" << Attr.Value << "\""; 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric } 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric if (!C->isSelfClosing()) 2130b57cec5SDimitry Andric Result << ">"; 2140b57cec5SDimitry Andric else 2150b57cec5SDimitry Andric Result << "/>"; 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric class CommentASTToHTMLConverter : 2190b57cec5SDimitry Andric public ConstCommentVisitor<CommentASTToHTMLConverter> { 2200b57cec5SDimitry Andric public: 2210b57cec5SDimitry Andric /// \param Str accumulator for HTML. 2220b57cec5SDimitry Andric CommentASTToHTMLConverter(const FullComment *FC, 2230b57cec5SDimitry Andric SmallVectorImpl<char> &Str, 2240b57cec5SDimitry Andric const CommandTraits &Traits) : 2250b57cec5SDimitry Andric FC(FC), Result(Str), Traits(Traits) 2260b57cec5SDimitry Andric { } 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric // Inline content. 2290b57cec5SDimitry Andric void visitTextComment(const TextComment *C); 2300b57cec5SDimitry Andric void visitInlineCommandComment(const InlineCommandComment *C); 2310b57cec5SDimitry Andric void visitHTMLStartTagComment(const HTMLStartTagComment *C); 2320b57cec5SDimitry Andric void visitHTMLEndTagComment(const HTMLEndTagComment *C); 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric // Block content. 2350b57cec5SDimitry Andric void visitParagraphComment(const ParagraphComment *C); 2360b57cec5SDimitry Andric void visitBlockCommandComment(const BlockCommandComment *C); 2370b57cec5SDimitry Andric void visitParamCommandComment(const ParamCommandComment *C); 2380b57cec5SDimitry Andric void visitTParamCommandComment(const TParamCommandComment *C); 2390b57cec5SDimitry Andric void visitVerbatimBlockComment(const VerbatimBlockComment *C); 2400b57cec5SDimitry Andric void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C); 2410b57cec5SDimitry Andric void visitVerbatimLineComment(const VerbatimLineComment *C); 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric void visitFullComment(const FullComment *C); 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric // Helpers. 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric /// Convert a paragraph that is not a block by itself (an argument to some 2480b57cec5SDimitry Andric /// command). 2490b57cec5SDimitry Andric void visitNonStandaloneParagraphComment(const ParagraphComment *C); 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric void appendToResultWithHTMLEscaping(StringRef S); 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric private: 2540b57cec5SDimitry Andric const FullComment *FC; 2550b57cec5SDimitry Andric /// Output stream for HTML. 2560b57cec5SDimitry Andric llvm::raw_svector_ostream Result; 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric const CommandTraits &Traits; 2590b57cec5SDimitry Andric }; 2600b57cec5SDimitry Andric } // end unnamed namespace 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric void CommentASTToHTMLConverter::visitTextComment(const TextComment *C) { 2630b57cec5SDimitry Andric appendToResultWithHTMLEscaping(C->getText()); 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric 2660b57cec5SDimitry Andric void CommentASTToHTMLConverter::visitInlineCommandComment( 2670b57cec5SDimitry Andric const InlineCommandComment *C) { 2680b57cec5SDimitry Andric // Nothing to render if no arguments supplied. 2690b57cec5SDimitry Andric if (C->getNumArgs() == 0) 2700b57cec5SDimitry Andric return; 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric // Nothing to render if argument is empty. 2730b57cec5SDimitry Andric StringRef Arg0 = C->getArgText(0); 2740b57cec5SDimitry Andric if (Arg0.empty()) 2750b57cec5SDimitry Andric return; 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric switch (C->getRenderKind()) { 2785f757f3fSDimitry Andric case InlineCommandRenderKind::Normal: 2790b57cec5SDimitry Andric for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) { 2800b57cec5SDimitry Andric appendToResultWithHTMLEscaping(C->getArgText(i)); 2810b57cec5SDimitry Andric Result << " "; 2820b57cec5SDimitry Andric } 2830b57cec5SDimitry Andric return; 2840b57cec5SDimitry Andric 2855f757f3fSDimitry Andric case InlineCommandRenderKind::Bold: 2860b57cec5SDimitry Andric assert(C->getNumArgs() == 1); 2870b57cec5SDimitry Andric Result << "<b>"; 2880b57cec5SDimitry Andric appendToResultWithHTMLEscaping(Arg0); 2890b57cec5SDimitry Andric Result << "</b>"; 2900b57cec5SDimitry Andric return; 2915f757f3fSDimitry Andric case InlineCommandRenderKind::Monospaced: 2920b57cec5SDimitry Andric assert(C->getNumArgs() == 1); 2930b57cec5SDimitry Andric Result << "<tt>"; 2940b57cec5SDimitry Andric appendToResultWithHTMLEscaping(Arg0); 2950b57cec5SDimitry Andric Result<< "</tt>"; 2960b57cec5SDimitry Andric return; 2975f757f3fSDimitry Andric case InlineCommandRenderKind::Emphasized: 2980b57cec5SDimitry Andric assert(C->getNumArgs() == 1); 2990b57cec5SDimitry Andric Result << "<em>"; 3000b57cec5SDimitry Andric appendToResultWithHTMLEscaping(Arg0); 3010b57cec5SDimitry Andric Result << "</em>"; 3020b57cec5SDimitry Andric return; 3035f757f3fSDimitry Andric case InlineCommandRenderKind::Anchor: 304480093f4SDimitry Andric assert(C->getNumArgs() == 1); 305480093f4SDimitry Andric Result << "<span id=\"" << Arg0 << "\"></span>"; 306480093f4SDimitry Andric return; 3070b57cec5SDimitry Andric } 3080b57cec5SDimitry Andric } 3090b57cec5SDimitry Andric 3100b57cec5SDimitry Andric void CommentASTToHTMLConverter::visitHTMLStartTagComment( 3110b57cec5SDimitry Andric const HTMLStartTagComment *C) { 3120b57cec5SDimitry Andric printHTMLStartTagComment(C, Result); 3130b57cec5SDimitry Andric } 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric void CommentASTToHTMLConverter::visitHTMLEndTagComment( 3160b57cec5SDimitry Andric const HTMLEndTagComment *C) { 3170b57cec5SDimitry Andric Result << "</" << C->getTagName() << ">"; 3180b57cec5SDimitry Andric } 3190b57cec5SDimitry Andric 3200b57cec5SDimitry Andric void CommentASTToHTMLConverter::visitParagraphComment( 3210b57cec5SDimitry Andric const ParagraphComment *C) { 3220b57cec5SDimitry Andric if (C->isWhitespace()) 3230b57cec5SDimitry Andric return; 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric Result << "<p>"; 3260b57cec5SDimitry Andric for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); 3270b57cec5SDimitry Andric I != E; ++I) { 3280b57cec5SDimitry Andric visit(*I); 3290b57cec5SDimitry Andric } 3300b57cec5SDimitry Andric Result << "</p>"; 3310b57cec5SDimitry Andric } 3320b57cec5SDimitry Andric 3330b57cec5SDimitry Andric void CommentASTToHTMLConverter::visitBlockCommandComment( 3340b57cec5SDimitry Andric const BlockCommandComment *C) { 3350b57cec5SDimitry Andric const CommandInfo *Info = Traits.getCommandInfo(C->getCommandID()); 3360b57cec5SDimitry Andric if (Info->IsBriefCommand) { 3370b57cec5SDimitry Andric Result << "<p class=\"para-brief\">"; 3380b57cec5SDimitry Andric visitNonStandaloneParagraphComment(C->getParagraph()); 3390b57cec5SDimitry Andric Result << "</p>"; 3400b57cec5SDimitry Andric return; 3410b57cec5SDimitry Andric } 3420b57cec5SDimitry Andric if (Info->IsReturnsCommand) { 3430b57cec5SDimitry Andric Result << "<p class=\"para-returns\">" 3440b57cec5SDimitry Andric "<span class=\"word-returns\">Returns</span> "; 3450b57cec5SDimitry Andric visitNonStandaloneParagraphComment(C->getParagraph()); 3460b57cec5SDimitry Andric Result << "</p>"; 3470b57cec5SDimitry Andric return; 3480b57cec5SDimitry Andric } 3490b57cec5SDimitry Andric // We don't know anything about this command. Just render the paragraph. 3500b57cec5SDimitry Andric visit(C->getParagraph()); 3510b57cec5SDimitry Andric } 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andric void CommentASTToHTMLConverter::visitParamCommandComment( 3540b57cec5SDimitry Andric const ParamCommandComment *C) { 3550b57cec5SDimitry Andric if (C->isParamIndexValid()) { 3560b57cec5SDimitry Andric if (C->isVarArgParam()) { 3570b57cec5SDimitry Andric Result << "<dt class=\"param-name-index-vararg\">"; 3580b57cec5SDimitry Andric appendToResultWithHTMLEscaping(C->getParamNameAsWritten()); 3590b57cec5SDimitry Andric } else { 3600b57cec5SDimitry Andric Result << "<dt class=\"param-name-index-" 3610b57cec5SDimitry Andric << C->getParamIndex() 3620b57cec5SDimitry Andric << "\">"; 3630b57cec5SDimitry Andric appendToResultWithHTMLEscaping(C->getParamName(FC)); 3640b57cec5SDimitry Andric } 3650b57cec5SDimitry Andric } else { 3660b57cec5SDimitry Andric Result << "<dt class=\"param-name-index-invalid\">"; 3670b57cec5SDimitry Andric appendToResultWithHTMLEscaping(C->getParamNameAsWritten()); 3680b57cec5SDimitry Andric } 3690b57cec5SDimitry Andric Result << "</dt>"; 3700b57cec5SDimitry Andric 3710b57cec5SDimitry Andric if (C->isParamIndexValid()) { 3720b57cec5SDimitry Andric if (C->isVarArgParam()) 3730b57cec5SDimitry Andric Result << "<dd class=\"param-descr-index-vararg\">"; 3740b57cec5SDimitry Andric else 3750b57cec5SDimitry Andric Result << "<dd class=\"param-descr-index-" 3760b57cec5SDimitry Andric << C->getParamIndex() 3770b57cec5SDimitry Andric << "\">"; 3780b57cec5SDimitry Andric } else 3790b57cec5SDimitry Andric Result << "<dd class=\"param-descr-index-invalid\">"; 3800b57cec5SDimitry Andric 3810b57cec5SDimitry Andric visitNonStandaloneParagraphComment(C->getParagraph()); 3820b57cec5SDimitry Andric Result << "</dd>"; 3830b57cec5SDimitry Andric } 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric void CommentASTToHTMLConverter::visitTParamCommandComment( 3860b57cec5SDimitry Andric const TParamCommandComment *C) { 3870b57cec5SDimitry Andric if (C->isPositionValid()) { 3880b57cec5SDimitry Andric if (C->getDepth() == 1) 3890b57cec5SDimitry Andric Result << "<dt class=\"tparam-name-index-" 3900b57cec5SDimitry Andric << C->getIndex(0) 3910b57cec5SDimitry Andric << "\">"; 3920b57cec5SDimitry Andric else 3930b57cec5SDimitry Andric Result << "<dt class=\"tparam-name-index-other\">"; 3940b57cec5SDimitry Andric appendToResultWithHTMLEscaping(C->getParamName(FC)); 3950b57cec5SDimitry Andric } else { 3960b57cec5SDimitry Andric Result << "<dt class=\"tparam-name-index-invalid\">"; 3970b57cec5SDimitry Andric appendToResultWithHTMLEscaping(C->getParamNameAsWritten()); 3980b57cec5SDimitry Andric } 3990b57cec5SDimitry Andric 4000b57cec5SDimitry Andric Result << "</dt>"; 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric if (C->isPositionValid()) { 4030b57cec5SDimitry Andric if (C->getDepth() == 1) 4040b57cec5SDimitry Andric Result << "<dd class=\"tparam-descr-index-" 4050b57cec5SDimitry Andric << C->getIndex(0) 4060b57cec5SDimitry Andric << "\">"; 4070b57cec5SDimitry Andric else 4080b57cec5SDimitry Andric Result << "<dd class=\"tparam-descr-index-other\">"; 4090b57cec5SDimitry Andric } else 4100b57cec5SDimitry Andric Result << "<dd class=\"tparam-descr-index-invalid\">"; 4110b57cec5SDimitry Andric 4120b57cec5SDimitry Andric visitNonStandaloneParagraphComment(C->getParagraph()); 4130b57cec5SDimitry Andric Result << "</dd>"; 4140b57cec5SDimitry Andric } 4150b57cec5SDimitry Andric 4160b57cec5SDimitry Andric void CommentASTToHTMLConverter::visitVerbatimBlockComment( 4170b57cec5SDimitry Andric const VerbatimBlockComment *C) { 4180b57cec5SDimitry Andric unsigned NumLines = C->getNumLines(); 4190b57cec5SDimitry Andric if (NumLines == 0) 4200b57cec5SDimitry Andric return; 4210b57cec5SDimitry Andric 4220b57cec5SDimitry Andric Result << "<pre>"; 4230b57cec5SDimitry Andric for (unsigned i = 0; i != NumLines; ++i) { 4240b57cec5SDimitry Andric appendToResultWithHTMLEscaping(C->getText(i)); 4250b57cec5SDimitry Andric if (i + 1 != NumLines) 4260b57cec5SDimitry Andric Result << '\n'; 4270b57cec5SDimitry Andric } 4280b57cec5SDimitry Andric Result << "</pre>"; 4290b57cec5SDimitry Andric } 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric void CommentASTToHTMLConverter::visitVerbatimBlockLineComment( 4320b57cec5SDimitry Andric const VerbatimBlockLineComment *C) { 4330b57cec5SDimitry Andric llvm_unreachable("should not see this AST node"); 4340b57cec5SDimitry Andric } 4350b57cec5SDimitry Andric 4360b57cec5SDimitry Andric void CommentASTToHTMLConverter::visitVerbatimLineComment( 4370b57cec5SDimitry Andric const VerbatimLineComment *C) { 4380b57cec5SDimitry Andric Result << "<pre>"; 4390b57cec5SDimitry Andric appendToResultWithHTMLEscaping(C->getText()); 4400b57cec5SDimitry Andric Result << "</pre>"; 4410b57cec5SDimitry Andric } 4420b57cec5SDimitry Andric 4430b57cec5SDimitry Andric void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) { 4440b57cec5SDimitry Andric FullCommentParts Parts(C, Traits); 4450b57cec5SDimitry Andric 4460b57cec5SDimitry Andric bool FirstParagraphIsBrief = false; 4470b57cec5SDimitry Andric if (Parts.Headerfile) 4480b57cec5SDimitry Andric visit(Parts.Headerfile); 4490b57cec5SDimitry Andric if (Parts.Brief) 4500b57cec5SDimitry Andric visit(Parts.Brief); 4510b57cec5SDimitry Andric else if (Parts.FirstParagraph) { 4520b57cec5SDimitry Andric Result << "<p class=\"para-brief\">"; 4530b57cec5SDimitry Andric visitNonStandaloneParagraphComment(Parts.FirstParagraph); 4540b57cec5SDimitry Andric Result << "</p>"; 4550b57cec5SDimitry Andric FirstParagraphIsBrief = true; 4560b57cec5SDimitry Andric } 4570b57cec5SDimitry Andric 4580b57cec5SDimitry Andric for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) { 4590b57cec5SDimitry Andric const Comment *C = Parts.MiscBlocks[i]; 4600b57cec5SDimitry Andric if (FirstParagraphIsBrief && C == Parts.FirstParagraph) 4610b57cec5SDimitry Andric continue; 4620b57cec5SDimitry Andric visit(C); 4630b57cec5SDimitry Andric } 4640b57cec5SDimitry Andric 4650b57cec5SDimitry Andric if (Parts.TParams.size() != 0) { 4660b57cec5SDimitry Andric Result << "<dl>"; 4670b57cec5SDimitry Andric for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i) 4680b57cec5SDimitry Andric visit(Parts.TParams[i]); 4690b57cec5SDimitry Andric Result << "</dl>"; 4700b57cec5SDimitry Andric } 4710b57cec5SDimitry Andric 4720b57cec5SDimitry Andric if (Parts.Params.size() != 0) { 4730b57cec5SDimitry Andric Result << "<dl>"; 4740b57cec5SDimitry Andric for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i) 4750b57cec5SDimitry Andric visit(Parts.Params[i]); 4760b57cec5SDimitry Andric Result << "</dl>"; 4770b57cec5SDimitry Andric } 4780b57cec5SDimitry Andric 4790b57cec5SDimitry Andric if (Parts.Returns.size() != 0) { 4800b57cec5SDimitry Andric Result << "<div class=\"result-discussion\">"; 4810b57cec5SDimitry Andric for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i) 4820b57cec5SDimitry Andric visit(Parts.Returns[i]); 4830b57cec5SDimitry Andric Result << "</div>"; 4840b57cec5SDimitry Andric } 4850b57cec5SDimitry Andric 4860b57cec5SDimitry Andric } 4870b57cec5SDimitry Andric 4880b57cec5SDimitry Andric void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment( 4890b57cec5SDimitry Andric const ParagraphComment *C) { 4900b57cec5SDimitry Andric if (!C) 4910b57cec5SDimitry Andric return; 4920b57cec5SDimitry Andric 4930b57cec5SDimitry Andric for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); 4940b57cec5SDimitry Andric I != E; ++I) { 4950b57cec5SDimitry Andric visit(*I); 4960b57cec5SDimitry Andric } 4970b57cec5SDimitry Andric } 4980b57cec5SDimitry Andric 4990b57cec5SDimitry Andric void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) { 5000b57cec5SDimitry Andric for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) { 5010b57cec5SDimitry Andric const char C = *I; 5020b57cec5SDimitry Andric switch (C) { 5030b57cec5SDimitry Andric case '&': 5040b57cec5SDimitry Andric Result << "&"; 5050b57cec5SDimitry Andric break; 5060b57cec5SDimitry Andric case '<': 5070b57cec5SDimitry Andric Result << "<"; 5080b57cec5SDimitry Andric break; 5090b57cec5SDimitry Andric case '>': 5100b57cec5SDimitry Andric Result << ">"; 5110b57cec5SDimitry Andric break; 5120b57cec5SDimitry Andric case '"': 5130b57cec5SDimitry Andric Result << """; 5140b57cec5SDimitry Andric break; 5150b57cec5SDimitry Andric case '\'': 5160b57cec5SDimitry Andric Result << "'"; 5170b57cec5SDimitry Andric break; 5180b57cec5SDimitry Andric case '/': 5190b57cec5SDimitry Andric Result << "/"; 5200b57cec5SDimitry Andric break; 5210b57cec5SDimitry Andric default: 5220b57cec5SDimitry Andric Result << C; 5230b57cec5SDimitry Andric break; 5240b57cec5SDimitry Andric } 5250b57cec5SDimitry Andric } 5260b57cec5SDimitry Andric } 5270b57cec5SDimitry Andric 5280b57cec5SDimitry Andric namespace { 5290b57cec5SDimitry Andric class CommentASTToXMLConverter : 5300b57cec5SDimitry Andric public ConstCommentVisitor<CommentASTToXMLConverter> { 5310b57cec5SDimitry Andric public: 5320b57cec5SDimitry Andric /// \param Str accumulator for XML. 5330b57cec5SDimitry Andric CommentASTToXMLConverter(const FullComment *FC, 5340b57cec5SDimitry Andric SmallVectorImpl<char> &Str, 5350b57cec5SDimitry Andric const CommandTraits &Traits, 5360b57cec5SDimitry Andric const SourceManager &SM) : 5370b57cec5SDimitry Andric FC(FC), Result(Str), Traits(Traits), SM(SM) { } 5380b57cec5SDimitry Andric 5390b57cec5SDimitry Andric // Inline content. 5400b57cec5SDimitry Andric void visitTextComment(const TextComment *C); 5410b57cec5SDimitry Andric void visitInlineCommandComment(const InlineCommandComment *C); 5420b57cec5SDimitry Andric void visitHTMLStartTagComment(const HTMLStartTagComment *C); 5430b57cec5SDimitry Andric void visitHTMLEndTagComment(const HTMLEndTagComment *C); 5440b57cec5SDimitry Andric 5450b57cec5SDimitry Andric // Block content. 5460b57cec5SDimitry Andric void visitParagraphComment(const ParagraphComment *C); 5470b57cec5SDimitry Andric 5480b57cec5SDimitry Andric void appendParagraphCommentWithKind(const ParagraphComment *C, 549*0fca6ea1SDimitry Andric StringRef ParagraphKind, 550*0fca6ea1SDimitry Andric StringRef PrependBodyText); 5510b57cec5SDimitry Andric 5520b57cec5SDimitry Andric void visitBlockCommandComment(const BlockCommandComment *C); 5530b57cec5SDimitry Andric void visitParamCommandComment(const ParamCommandComment *C); 5540b57cec5SDimitry Andric void visitTParamCommandComment(const TParamCommandComment *C); 5550b57cec5SDimitry Andric void visitVerbatimBlockComment(const VerbatimBlockComment *C); 5560b57cec5SDimitry Andric void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C); 5570b57cec5SDimitry Andric void visitVerbatimLineComment(const VerbatimLineComment *C); 5580b57cec5SDimitry Andric 5590b57cec5SDimitry Andric void visitFullComment(const FullComment *C); 5600b57cec5SDimitry Andric 5610b57cec5SDimitry Andric // Helpers. 5620b57cec5SDimitry Andric void appendToResultWithXMLEscaping(StringRef S); 5630b57cec5SDimitry Andric void appendToResultWithCDATAEscaping(StringRef S); 5640b57cec5SDimitry Andric 5650b57cec5SDimitry Andric void formatTextOfDeclaration(const DeclInfo *DI, 5660b57cec5SDimitry Andric SmallString<128> &Declaration); 5670b57cec5SDimitry Andric 5680b57cec5SDimitry Andric private: 5690b57cec5SDimitry Andric const FullComment *FC; 5700b57cec5SDimitry Andric 5710b57cec5SDimitry Andric /// Output stream for XML. 5720b57cec5SDimitry Andric llvm::raw_svector_ostream Result; 5730b57cec5SDimitry Andric 5740b57cec5SDimitry Andric const CommandTraits &Traits; 5750b57cec5SDimitry Andric const SourceManager &SM; 5760b57cec5SDimitry Andric }; 5770b57cec5SDimitry Andric 5780b57cec5SDimitry Andric void getSourceTextOfDeclaration(const DeclInfo *ThisDecl, 5790b57cec5SDimitry Andric SmallVectorImpl<char> &Str) { 5800b57cec5SDimitry Andric ASTContext &Context = ThisDecl->CurrentDecl->getASTContext(); 5810b57cec5SDimitry Andric const LangOptions &LangOpts = Context.getLangOpts(); 5820b57cec5SDimitry Andric llvm::raw_svector_ostream OS(Str); 5830b57cec5SDimitry Andric PrintingPolicy PPolicy(LangOpts); 5840b57cec5SDimitry Andric PPolicy.PolishForDeclaration = true; 5850b57cec5SDimitry Andric PPolicy.TerseOutput = true; 5860b57cec5SDimitry Andric PPolicy.ConstantsAsWritten = true; 5870b57cec5SDimitry Andric ThisDecl->CurrentDecl->print(OS, PPolicy, 5880b57cec5SDimitry Andric /*Indentation*/0, /*PrintInstantiation*/false); 5890b57cec5SDimitry Andric } 5900b57cec5SDimitry Andric 5910b57cec5SDimitry Andric void CommentASTToXMLConverter::formatTextOfDeclaration( 5920b57cec5SDimitry Andric const DeclInfo *DI, SmallString<128> &Declaration) { 5930b57cec5SDimitry Andric // Formatting API expects null terminated input string. 5940b57cec5SDimitry Andric StringRef StringDecl(Declaration.c_str(), Declaration.size()); 5950b57cec5SDimitry Andric 5960b57cec5SDimitry Andric // Formatter specific code. 5970b57cec5SDimitry Andric unsigned Offset = 0; 5980b57cec5SDimitry Andric unsigned Length = Declaration.size(); 5990b57cec5SDimitry Andric 6000b57cec5SDimitry Andric format::FormatStyle Style = format::getLLVMStyle(); 6010b57cec5SDimitry Andric Style.FixNamespaceComments = false; 6020b57cec5SDimitry Andric tooling::Replacements Replaces = 6030b57cec5SDimitry Andric reformat(Style, StringDecl, tooling::Range(Offset, Length), "xmldecl.xd"); 6040b57cec5SDimitry Andric auto FormattedStringDecl = applyAllReplacements(StringDecl, Replaces); 6050b57cec5SDimitry Andric if (static_cast<bool>(FormattedStringDecl)) { 6060b57cec5SDimitry Andric Declaration = *FormattedStringDecl; 6070b57cec5SDimitry Andric } 6080b57cec5SDimitry Andric } 6090b57cec5SDimitry Andric 6100b57cec5SDimitry Andric } // end unnamed namespace 6110b57cec5SDimitry Andric 6120b57cec5SDimitry Andric void CommentASTToXMLConverter::visitTextComment(const TextComment *C) { 6130b57cec5SDimitry Andric appendToResultWithXMLEscaping(C->getText()); 6140b57cec5SDimitry Andric } 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric void CommentASTToXMLConverter::visitInlineCommandComment( 6170b57cec5SDimitry Andric const InlineCommandComment *C) { 6180b57cec5SDimitry Andric // Nothing to render if no arguments supplied. 6190b57cec5SDimitry Andric if (C->getNumArgs() == 0) 6200b57cec5SDimitry Andric return; 6210b57cec5SDimitry Andric 6220b57cec5SDimitry Andric // Nothing to render if argument is empty. 6230b57cec5SDimitry Andric StringRef Arg0 = C->getArgText(0); 6240b57cec5SDimitry Andric if (Arg0.empty()) 6250b57cec5SDimitry Andric return; 6260b57cec5SDimitry Andric 6270b57cec5SDimitry Andric switch (C->getRenderKind()) { 6285f757f3fSDimitry Andric case InlineCommandRenderKind::Normal: 6290b57cec5SDimitry Andric for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) { 6300b57cec5SDimitry Andric appendToResultWithXMLEscaping(C->getArgText(i)); 6310b57cec5SDimitry Andric Result << " "; 6320b57cec5SDimitry Andric } 6330b57cec5SDimitry Andric return; 6345f757f3fSDimitry Andric case InlineCommandRenderKind::Bold: 6350b57cec5SDimitry Andric assert(C->getNumArgs() == 1); 6360b57cec5SDimitry Andric Result << "<bold>"; 6370b57cec5SDimitry Andric appendToResultWithXMLEscaping(Arg0); 6380b57cec5SDimitry Andric Result << "</bold>"; 6390b57cec5SDimitry Andric return; 6405f757f3fSDimitry Andric case InlineCommandRenderKind::Monospaced: 6410b57cec5SDimitry Andric assert(C->getNumArgs() == 1); 6420b57cec5SDimitry Andric Result << "<monospaced>"; 6430b57cec5SDimitry Andric appendToResultWithXMLEscaping(Arg0); 6440b57cec5SDimitry Andric Result << "</monospaced>"; 6450b57cec5SDimitry Andric return; 6465f757f3fSDimitry Andric case InlineCommandRenderKind::Emphasized: 6470b57cec5SDimitry Andric assert(C->getNumArgs() == 1); 6480b57cec5SDimitry Andric Result << "<emphasized>"; 6490b57cec5SDimitry Andric appendToResultWithXMLEscaping(Arg0); 6500b57cec5SDimitry Andric Result << "</emphasized>"; 6510b57cec5SDimitry Andric return; 6525f757f3fSDimitry Andric case InlineCommandRenderKind::Anchor: 653480093f4SDimitry Andric assert(C->getNumArgs() == 1); 654480093f4SDimitry Andric Result << "<anchor id=\"" << Arg0 << "\"></anchor>"; 655480093f4SDimitry Andric return; 6560b57cec5SDimitry Andric } 6570b57cec5SDimitry Andric } 6580b57cec5SDimitry Andric 6590b57cec5SDimitry Andric void CommentASTToXMLConverter::visitHTMLStartTagComment( 6600b57cec5SDimitry Andric const HTMLStartTagComment *C) { 6610b57cec5SDimitry Andric Result << "<rawHTML"; 6620b57cec5SDimitry Andric if (C->isMalformed()) 6630b57cec5SDimitry Andric Result << " isMalformed=\"1\""; 6640b57cec5SDimitry Andric Result << ">"; 6650b57cec5SDimitry Andric { 6660b57cec5SDimitry Andric SmallString<32> Tag; 6670b57cec5SDimitry Andric { 6680b57cec5SDimitry Andric llvm::raw_svector_ostream TagOS(Tag); 6690b57cec5SDimitry Andric printHTMLStartTagComment(C, TagOS); 6700b57cec5SDimitry Andric } 6710b57cec5SDimitry Andric appendToResultWithCDATAEscaping(Tag); 6720b57cec5SDimitry Andric } 6730b57cec5SDimitry Andric Result << "</rawHTML>"; 6740b57cec5SDimitry Andric } 6750b57cec5SDimitry Andric 6760b57cec5SDimitry Andric void 6770b57cec5SDimitry Andric CommentASTToXMLConverter::visitHTMLEndTagComment(const HTMLEndTagComment *C) { 6780b57cec5SDimitry Andric Result << "<rawHTML"; 6790b57cec5SDimitry Andric if (C->isMalformed()) 6800b57cec5SDimitry Andric Result << " isMalformed=\"1\""; 6810b57cec5SDimitry Andric Result << "></" << C->getTagName() << "></rawHTML>"; 6820b57cec5SDimitry Andric } 6830b57cec5SDimitry Andric 684*0fca6ea1SDimitry Andric void CommentASTToXMLConverter::visitParagraphComment( 685*0fca6ea1SDimitry Andric const ParagraphComment *C) { 686*0fca6ea1SDimitry Andric appendParagraphCommentWithKind(C, StringRef(), StringRef()); 6870b57cec5SDimitry Andric } 6880b57cec5SDimitry Andric 6890b57cec5SDimitry Andric void CommentASTToXMLConverter::appendParagraphCommentWithKind( 690*0fca6ea1SDimitry Andric const ParagraphComment *C, StringRef ParagraphKind, 691*0fca6ea1SDimitry Andric StringRef PrependBodyText) { 692*0fca6ea1SDimitry Andric if (C->isWhitespace() && PrependBodyText.empty()) 6930b57cec5SDimitry Andric return; 6940b57cec5SDimitry Andric 6950b57cec5SDimitry Andric if (ParagraphKind.empty()) 6960b57cec5SDimitry Andric Result << "<Para>"; 6970b57cec5SDimitry Andric else 6980b57cec5SDimitry Andric Result << "<Para kind=\"" << ParagraphKind << "\">"; 6990b57cec5SDimitry Andric 700*0fca6ea1SDimitry Andric if (!PrependBodyText.empty()) 701*0fca6ea1SDimitry Andric Result << PrependBodyText << " "; 702*0fca6ea1SDimitry Andric 703*0fca6ea1SDimitry Andric for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); I != E; 704*0fca6ea1SDimitry Andric ++I) { 7050b57cec5SDimitry Andric visit(*I); 7060b57cec5SDimitry Andric } 7070b57cec5SDimitry Andric Result << "</Para>"; 7080b57cec5SDimitry Andric } 7090b57cec5SDimitry Andric 7100b57cec5SDimitry Andric void CommentASTToXMLConverter::visitBlockCommandComment( 7110b57cec5SDimitry Andric const BlockCommandComment *C) { 7120b57cec5SDimitry Andric StringRef ParagraphKind; 713*0fca6ea1SDimitry Andric StringRef ExceptionType; 7140b57cec5SDimitry Andric 715*0fca6ea1SDimitry Andric const unsigned CommandID = C->getCommandID(); 716*0fca6ea1SDimitry Andric const CommandInfo *Info = Traits.getCommandInfo(CommandID); 717*0fca6ea1SDimitry Andric if (Info->IsThrowsCommand && C->getNumArgs() > 0) { 718*0fca6ea1SDimitry Andric ExceptionType = C->getArgText(0); 719*0fca6ea1SDimitry Andric } 720*0fca6ea1SDimitry Andric 721*0fca6ea1SDimitry Andric switch (CommandID) { 7220b57cec5SDimitry Andric case CommandTraits::KCI_attention: 7230b57cec5SDimitry Andric case CommandTraits::KCI_author: 7240b57cec5SDimitry Andric case CommandTraits::KCI_authors: 7250b57cec5SDimitry Andric case CommandTraits::KCI_bug: 7260b57cec5SDimitry Andric case CommandTraits::KCI_copyright: 7270b57cec5SDimitry Andric case CommandTraits::KCI_date: 7280b57cec5SDimitry Andric case CommandTraits::KCI_invariant: 7290b57cec5SDimitry Andric case CommandTraits::KCI_note: 7300b57cec5SDimitry Andric case CommandTraits::KCI_post: 7310b57cec5SDimitry Andric case CommandTraits::KCI_pre: 7320b57cec5SDimitry Andric case CommandTraits::KCI_remark: 7330b57cec5SDimitry Andric case CommandTraits::KCI_remarks: 7340b57cec5SDimitry Andric case CommandTraits::KCI_sa: 7350b57cec5SDimitry Andric case CommandTraits::KCI_see: 7360b57cec5SDimitry Andric case CommandTraits::KCI_since: 7370b57cec5SDimitry Andric case CommandTraits::KCI_todo: 7380b57cec5SDimitry Andric case CommandTraits::KCI_version: 7390b57cec5SDimitry Andric case CommandTraits::KCI_warning: 7400b57cec5SDimitry Andric ParagraphKind = C->getCommandName(Traits); 7410b57cec5SDimitry Andric break; 7420b57cec5SDimitry Andric default: 7430b57cec5SDimitry Andric break; 7440b57cec5SDimitry Andric } 7450b57cec5SDimitry Andric 746*0fca6ea1SDimitry Andric appendParagraphCommentWithKind(C->getParagraph(), ParagraphKind, 747*0fca6ea1SDimitry Andric ExceptionType); 7480b57cec5SDimitry Andric } 7490b57cec5SDimitry Andric 7500b57cec5SDimitry Andric void CommentASTToXMLConverter::visitParamCommandComment( 7510b57cec5SDimitry Andric const ParamCommandComment *C) { 7520b57cec5SDimitry Andric Result << "<Parameter><Name>"; 7530b57cec5SDimitry Andric appendToResultWithXMLEscaping(C->isParamIndexValid() 7540b57cec5SDimitry Andric ? C->getParamName(FC) 7550b57cec5SDimitry Andric : C->getParamNameAsWritten()); 7560b57cec5SDimitry Andric Result << "</Name>"; 7570b57cec5SDimitry Andric 7580b57cec5SDimitry Andric if (C->isParamIndexValid()) { 7590b57cec5SDimitry Andric if (C->isVarArgParam()) 7600b57cec5SDimitry Andric Result << "<IsVarArg />"; 7610b57cec5SDimitry Andric else 7620b57cec5SDimitry Andric Result << "<Index>" << C->getParamIndex() << "</Index>"; 7630b57cec5SDimitry Andric } 7640b57cec5SDimitry Andric 7650b57cec5SDimitry Andric Result << "<Direction isExplicit=\"" << C->isDirectionExplicit() << "\">"; 7660b57cec5SDimitry Andric switch (C->getDirection()) { 7675f757f3fSDimitry Andric case ParamCommandPassDirection::In: 7680b57cec5SDimitry Andric Result << "in"; 7690b57cec5SDimitry Andric break; 7705f757f3fSDimitry Andric case ParamCommandPassDirection::Out: 7710b57cec5SDimitry Andric Result << "out"; 7720b57cec5SDimitry Andric break; 7735f757f3fSDimitry Andric case ParamCommandPassDirection::InOut: 7740b57cec5SDimitry Andric Result << "in,out"; 7750b57cec5SDimitry Andric break; 7760b57cec5SDimitry Andric } 7770b57cec5SDimitry Andric Result << "</Direction><Discussion>"; 7780b57cec5SDimitry Andric visit(C->getParagraph()); 7790b57cec5SDimitry Andric Result << "</Discussion></Parameter>"; 7800b57cec5SDimitry Andric } 7810b57cec5SDimitry Andric 7820b57cec5SDimitry Andric void CommentASTToXMLConverter::visitTParamCommandComment( 7830b57cec5SDimitry Andric const TParamCommandComment *C) { 7840b57cec5SDimitry Andric Result << "<Parameter><Name>"; 7850b57cec5SDimitry Andric appendToResultWithXMLEscaping(C->isPositionValid() ? C->getParamName(FC) 7860b57cec5SDimitry Andric : C->getParamNameAsWritten()); 7870b57cec5SDimitry Andric Result << "</Name>"; 7880b57cec5SDimitry Andric 7890b57cec5SDimitry Andric if (C->isPositionValid() && C->getDepth() == 1) { 7900b57cec5SDimitry Andric Result << "<Index>" << C->getIndex(0) << "</Index>"; 7910b57cec5SDimitry Andric } 7920b57cec5SDimitry Andric 7930b57cec5SDimitry Andric Result << "<Discussion>"; 7940b57cec5SDimitry Andric visit(C->getParagraph()); 7950b57cec5SDimitry Andric Result << "</Discussion></Parameter>"; 7960b57cec5SDimitry Andric } 7970b57cec5SDimitry Andric 7980b57cec5SDimitry Andric void CommentASTToXMLConverter::visitVerbatimBlockComment( 7990b57cec5SDimitry Andric const VerbatimBlockComment *C) { 8000b57cec5SDimitry Andric unsigned NumLines = C->getNumLines(); 8010b57cec5SDimitry Andric if (NumLines == 0) 8020b57cec5SDimitry Andric return; 8030b57cec5SDimitry Andric 8040b57cec5SDimitry Andric switch (C->getCommandID()) { 8050b57cec5SDimitry Andric case CommandTraits::KCI_code: 8060b57cec5SDimitry Andric Result << "<Verbatim xml:space=\"preserve\" kind=\"code\">"; 8070b57cec5SDimitry Andric break; 8080b57cec5SDimitry Andric default: 8090b57cec5SDimitry Andric Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">"; 8100b57cec5SDimitry Andric break; 8110b57cec5SDimitry Andric } 8120b57cec5SDimitry Andric for (unsigned i = 0; i != NumLines; ++i) { 8130b57cec5SDimitry Andric appendToResultWithXMLEscaping(C->getText(i)); 8140b57cec5SDimitry Andric if (i + 1 != NumLines) 8150b57cec5SDimitry Andric Result << '\n'; 8160b57cec5SDimitry Andric } 8170b57cec5SDimitry Andric Result << "</Verbatim>"; 8180b57cec5SDimitry Andric } 8190b57cec5SDimitry Andric 8200b57cec5SDimitry Andric void CommentASTToXMLConverter::visitVerbatimBlockLineComment( 8210b57cec5SDimitry Andric const VerbatimBlockLineComment *C) { 8220b57cec5SDimitry Andric llvm_unreachable("should not see this AST node"); 8230b57cec5SDimitry Andric } 8240b57cec5SDimitry Andric 8250b57cec5SDimitry Andric void CommentASTToXMLConverter::visitVerbatimLineComment( 8260b57cec5SDimitry Andric const VerbatimLineComment *C) { 8270b57cec5SDimitry Andric Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">"; 8280b57cec5SDimitry Andric appendToResultWithXMLEscaping(C->getText()); 8290b57cec5SDimitry Andric Result << "</Verbatim>"; 8300b57cec5SDimitry Andric } 8310b57cec5SDimitry Andric 8320b57cec5SDimitry Andric void CommentASTToXMLConverter::visitFullComment(const FullComment *C) { 8330b57cec5SDimitry Andric FullCommentParts Parts(C, Traits); 8340b57cec5SDimitry Andric 8350b57cec5SDimitry Andric const DeclInfo *DI = C->getDeclInfo(); 8360b57cec5SDimitry Andric StringRef RootEndTag; 8370b57cec5SDimitry Andric if (DI) { 8380b57cec5SDimitry Andric switch (DI->getKind()) { 8390b57cec5SDimitry Andric case DeclInfo::OtherKind: 8400b57cec5SDimitry Andric RootEndTag = "</Other>"; 8410b57cec5SDimitry Andric Result << "<Other"; 8420b57cec5SDimitry Andric break; 8430b57cec5SDimitry Andric case DeclInfo::FunctionKind: 8440b57cec5SDimitry Andric RootEndTag = "</Function>"; 8450b57cec5SDimitry Andric Result << "<Function"; 8460b57cec5SDimitry Andric switch (DI->TemplateKind) { 8470b57cec5SDimitry Andric case DeclInfo::NotTemplate: 8480b57cec5SDimitry Andric break; 8490b57cec5SDimitry Andric case DeclInfo::Template: 8500b57cec5SDimitry Andric Result << " templateKind=\"template\""; 8510b57cec5SDimitry Andric break; 8520b57cec5SDimitry Andric case DeclInfo::TemplateSpecialization: 8530b57cec5SDimitry Andric Result << " templateKind=\"specialization\""; 8540b57cec5SDimitry Andric break; 8550b57cec5SDimitry Andric case DeclInfo::TemplatePartialSpecialization: 8560b57cec5SDimitry Andric llvm_unreachable("partial specializations of functions " 8570b57cec5SDimitry Andric "are not allowed in C++"); 8580b57cec5SDimitry Andric } 8590b57cec5SDimitry Andric if (DI->IsInstanceMethod) 8600b57cec5SDimitry Andric Result << " isInstanceMethod=\"1\""; 8610b57cec5SDimitry Andric if (DI->IsClassMethod) 8620b57cec5SDimitry Andric Result << " isClassMethod=\"1\""; 8630b57cec5SDimitry Andric break; 8640b57cec5SDimitry Andric case DeclInfo::ClassKind: 8650b57cec5SDimitry Andric RootEndTag = "</Class>"; 8660b57cec5SDimitry Andric Result << "<Class"; 8670b57cec5SDimitry Andric switch (DI->TemplateKind) { 8680b57cec5SDimitry Andric case DeclInfo::NotTemplate: 8690b57cec5SDimitry Andric break; 8700b57cec5SDimitry Andric case DeclInfo::Template: 8710b57cec5SDimitry Andric Result << " templateKind=\"template\""; 8720b57cec5SDimitry Andric break; 8730b57cec5SDimitry Andric case DeclInfo::TemplateSpecialization: 8740b57cec5SDimitry Andric Result << " templateKind=\"specialization\""; 8750b57cec5SDimitry Andric break; 8760b57cec5SDimitry Andric case DeclInfo::TemplatePartialSpecialization: 8770b57cec5SDimitry Andric Result << " templateKind=\"partialSpecialization\""; 8780b57cec5SDimitry Andric break; 8790b57cec5SDimitry Andric } 8800b57cec5SDimitry Andric break; 8810b57cec5SDimitry Andric case DeclInfo::VariableKind: 8820b57cec5SDimitry Andric RootEndTag = "</Variable>"; 8830b57cec5SDimitry Andric Result << "<Variable"; 8840b57cec5SDimitry Andric break; 8850b57cec5SDimitry Andric case DeclInfo::NamespaceKind: 8860b57cec5SDimitry Andric RootEndTag = "</Namespace>"; 8870b57cec5SDimitry Andric Result << "<Namespace"; 8880b57cec5SDimitry Andric break; 8890b57cec5SDimitry Andric case DeclInfo::TypedefKind: 8900b57cec5SDimitry Andric RootEndTag = "</Typedef>"; 8910b57cec5SDimitry Andric Result << "<Typedef"; 8920b57cec5SDimitry Andric break; 8930b57cec5SDimitry Andric case DeclInfo::EnumKind: 8940b57cec5SDimitry Andric RootEndTag = "</Enum>"; 8950b57cec5SDimitry Andric Result << "<Enum"; 8960b57cec5SDimitry Andric break; 8970b57cec5SDimitry Andric } 8980b57cec5SDimitry Andric 8990b57cec5SDimitry Andric { 9000b57cec5SDimitry Andric // Print line and column number. 9010b57cec5SDimitry Andric SourceLocation Loc = DI->CurrentDecl->getLocation(); 9020b57cec5SDimitry Andric std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); 9030b57cec5SDimitry Andric FileID FID = LocInfo.first; 9040b57cec5SDimitry Andric unsigned FileOffset = LocInfo.second; 9050b57cec5SDimitry Andric 9060b57cec5SDimitry Andric if (FID.isValid()) { 9075f757f3fSDimitry Andric if (OptionalFileEntryRef FE = SM.getFileEntryRefForID(FID)) { 9080b57cec5SDimitry Andric Result << " file=\""; 9090b57cec5SDimitry Andric appendToResultWithXMLEscaping(FE->getName()); 9100b57cec5SDimitry Andric Result << "\""; 9110b57cec5SDimitry Andric } 9120b57cec5SDimitry Andric Result << " line=\"" << SM.getLineNumber(FID, FileOffset) 9130b57cec5SDimitry Andric << "\" column=\"" << SM.getColumnNumber(FID, FileOffset) 9140b57cec5SDimitry Andric << "\""; 9150b57cec5SDimitry Andric } 9160b57cec5SDimitry Andric } 9170b57cec5SDimitry Andric 9180b57cec5SDimitry Andric // Finish the root tag. 9190b57cec5SDimitry Andric Result << ">"; 9200b57cec5SDimitry Andric 9210b57cec5SDimitry Andric bool FoundName = false; 9220b57cec5SDimitry Andric if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->CommentDecl)) { 9230b57cec5SDimitry Andric if (DeclarationName DeclName = ND->getDeclName()) { 9240b57cec5SDimitry Andric Result << "<Name>"; 9250b57cec5SDimitry Andric std::string Name = DeclName.getAsString(); 9260b57cec5SDimitry Andric appendToResultWithXMLEscaping(Name); 9270b57cec5SDimitry Andric FoundName = true; 9280b57cec5SDimitry Andric Result << "</Name>"; 9290b57cec5SDimitry Andric } 9300b57cec5SDimitry Andric } 9310b57cec5SDimitry Andric if (!FoundName) 9320b57cec5SDimitry Andric Result << "<Name><anonymous></Name>"; 9330b57cec5SDimitry Andric 9340b57cec5SDimitry Andric { 9350b57cec5SDimitry Andric // Print USR. 9360b57cec5SDimitry Andric SmallString<128> USR; 9370b57cec5SDimitry Andric generateUSRForDecl(DI->CommentDecl, USR); 9380b57cec5SDimitry Andric if (!USR.empty()) { 9390b57cec5SDimitry Andric Result << "<USR>"; 9400b57cec5SDimitry Andric appendToResultWithXMLEscaping(USR); 9410b57cec5SDimitry Andric Result << "</USR>"; 9420b57cec5SDimitry Andric } 9430b57cec5SDimitry Andric } 9440b57cec5SDimitry Andric } else { 9450b57cec5SDimitry Andric // No DeclInfo -- just emit some root tag and name tag. 9460b57cec5SDimitry Andric RootEndTag = "</Other>"; 9470b57cec5SDimitry Andric Result << "<Other><Name>unknown</Name>"; 9480b57cec5SDimitry Andric } 9490b57cec5SDimitry Andric 9500b57cec5SDimitry Andric if (Parts.Headerfile) { 9510b57cec5SDimitry Andric Result << "<Headerfile>"; 9520b57cec5SDimitry Andric visit(Parts.Headerfile); 9530b57cec5SDimitry Andric Result << "</Headerfile>"; 9540b57cec5SDimitry Andric } 9550b57cec5SDimitry Andric 9560b57cec5SDimitry Andric { 9570b57cec5SDimitry Andric // Pretty-print the declaration. 9580b57cec5SDimitry Andric Result << "<Declaration>"; 9590b57cec5SDimitry Andric SmallString<128> Declaration; 9600b57cec5SDimitry Andric getSourceTextOfDeclaration(DI, Declaration); 9610b57cec5SDimitry Andric formatTextOfDeclaration(DI, Declaration); 9620b57cec5SDimitry Andric appendToResultWithXMLEscaping(Declaration); 9630b57cec5SDimitry Andric Result << "</Declaration>"; 9640b57cec5SDimitry Andric } 9650b57cec5SDimitry Andric 9660b57cec5SDimitry Andric bool FirstParagraphIsBrief = false; 9670b57cec5SDimitry Andric if (Parts.Brief) { 9680b57cec5SDimitry Andric Result << "<Abstract>"; 9690b57cec5SDimitry Andric visit(Parts.Brief); 9700b57cec5SDimitry Andric Result << "</Abstract>"; 9710b57cec5SDimitry Andric } else if (Parts.FirstParagraph) { 9720b57cec5SDimitry Andric Result << "<Abstract>"; 9730b57cec5SDimitry Andric visit(Parts.FirstParagraph); 9740b57cec5SDimitry Andric Result << "</Abstract>"; 9750b57cec5SDimitry Andric FirstParagraphIsBrief = true; 9760b57cec5SDimitry Andric } 9770b57cec5SDimitry Andric 9780b57cec5SDimitry Andric if (Parts.TParams.size() != 0) { 9790b57cec5SDimitry Andric Result << "<TemplateParameters>"; 9800b57cec5SDimitry Andric for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i) 9810b57cec5SDimitry Andric visit(Parts.TParams[i]); 9820b57cec5SDimitry Andric Result << "</TemplateParameters>"; 9830b57cec5SDimitry Andric } 9840b57cec5SDimitry Andric 9850b57cec5SDimitry Andric if (Parts.Params.size() != 0) { 9860b57cec5SDimitry Andric Result << "<Parameters>"; 9870b57cec5SDimitry Andric for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i) 9880b57cec5SDimitry Andric visit(Parts.Params[i]); 9890b57cec5SDimitry Andric Result << "</Parameters>"; 9900b57cec5SDimitry Andric } 9910b57cec5SDimitry Andric 9920b57cec5SDimitry Andric if (Parts.Exceptions.size() != 0) { 9930b57cec5SDimitry Andric Result << "<Exceptions>"; 9940b57cec5SDimitry Andric for (unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i) 9950b57cec5SDimitry Andric visit(Parts.Exceptions[i]); 9960b57cec5SDimitry Andric Result << "</Exceptions>"; 9970b57cec5SDimitry Andric } 9980b57cec5SDimitry Andric 9990b57cec5SDimitry Andric if (Parts.Returns.size() != 0) { 10000b57cec5SDimitry Andric Result << "<ResultDiscussion>"; 10010b57cec5SDimitry Andric for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i) 10020b57cec5SDimitry Andric visit(Parts.Returns[i]); 10030b57cec5SDimitry Andric Result << "</ResultDiscussion>"; 10040b57cec5SDimitry Andric } 10050b57cec5SDimitry Andric 10060b57cec5SDimitry Andric if (DI->CommentDecl->hasAttrs()) { 10070b57cec5SDimitry Andric const AttrVec &Attrs = DI->CommentDecl->getAttrs(); 10080b57cec5SDimitry Andric for (unsigned i = 0, e = Attrs.size(); i != e; i++) { 10090b57cec5SDimitry Andric const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]); 10100b57cec5SDimitry Andric if (!AA) { 10110b57cec5SDimitry Andric if (const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) { 10120b57cec5SDimitry Andric if (DA->getMessage().empty()) 10130b57cec5SDimitry Andric Result << "<Deprecated/>"; 10140b57cec5SDimitry Andric else { 10150b57cec5SDimitry Andric Result << "<Deprecated>"; 10160b57cec5SDimitry Andric appendToResultWithXMLEscaping(DA->getMessage()); 10170b57cec5SDimitry Andric Result << "</Deprecated>"; 10180b57cec5SDimitry Andric } 10190b57cec5SDimitry Andric } 10200b57cec5SDimitry Andric else if (const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) { 10210b57cec5SDimitry Andric if (UA->getMessage().empty()) 10220b57cec5SDimitry Andric Result << "<Unavailable/>"; 10230b57cec5SDimitry Andric else { 10240b57cec5SDimitry Andric Result << "<Unavailable>"; 10250b57cec5SDimitry Andric appendToResultWithXMLEscaping(UA->getMessage()); 10260b57cec5SDimitry Andric Result << "</Unavailable>"; 10270b57cec5SDimitry Andric } 10280b57cec5SDimitry Andric } 10290b57cec5SDimitry Andric continue; 10300b57cec5SDimitry Andric } 10310b57cec5SDimitry Andric 10320b57cec5SDimitry Andric // 'availability' attribute. 10330b57cec5SDimitry Andric Result << "<Availability"; 10340b57cec5SDimitry Andric StringRef Distribution; 10350b57cec5SDimitry Andric if (AA->getPlatform()) { 10360b57cec5SDimitry Andric Distribution = AvailabilityAttr::getPrettyPlatformName( 10370b57cec5SDimitry Andric AA->getPlatform()->getName()); 10380b57cec5SDimitry Andric if (Distribution.empty()) 10390b57cec5SDimitry Andric Distribution = AA->getPlatform()->getName(); 10400b57cec5SDimitry Andric } 10410b57cec5SDimitry Andric Result << " distribution=\"" << Distribution << "\">"; 10420b57cec5SDimitry Andric VersionTuple IntroducedInVersion = AA->getIntroduced(); 10430b57cec5SDimitry Andric if (!IntroducedInVersion.empty()) { 10440b57cec5SDimitry Andric Result << "<IntroducedInVersion>" 10450b57cec5SDimitry Andric << IntroducedInVersion.getAsString() 10460b57cec5SDimitry Andric << "</IntroducedInVersion>"; 10470b57cec5SDimitry Andric } 10480b57cec5SDimitry Andric VersionTuple DeprecatedInVersion = AA->getDeprecated(); 10490b57cec5SDimitry Andric if (!DeprecatedInVersion.empty()) { 10500b57cec5SDimitry Andric Result << "<DeprecatedInVersion>" 10510b57cec5SDimitry Andric << DeprecatedInVersion.getAsString() 10520b57cec5SDimitry Andric << "</DeprecatedInVersion>"; 10530b57cec5SDimitry Andric } 10540b57cec5SDimitry Andric VersionTuple RemovedAfterVersion = AA->getObsoleted(); 10550b57cec5SDimitry Andric if (!RemovedAfterVersion.empty()) { 10560b57cec5SDimitry Andric Result << "<RemovedAfterVersion>" 10570b57cec5SDimitry Andric << RemovedAfterVersion.getAsString() 10580b57cec5SDimitry Andric << "</RemovedAfterVersion>"; 10590b57cec5SDimitry Andric } 10600b57cec5SDimitry Andric StringRef DeprecationSummary = AA->getMessage(); 10610b57cec5SDimitry Andric if (!DeprecationSummary.empty()) { 10620b57cec5SDimitry Andric Result << "<DeprecationSummary>"; 10630b57cec5SDimitry Andric appendToResultWithXMLEscaping(DeprecationSummary); 10640b57cec5SDimitry Andric Result << "</DeprecationSummary>"; 10650b57cec5SDimitry Andric } 10660b57cec5SDimitry Andric if (AA->getUnavailable()) 10670b57cec5SDimitry Andric Result << "<Unavailable/>"; 1068*0fca6ea1SDimitry Andric 1069*0fca6ea1SDimitry Andric IdentifierInfo *Environment = AA->getEnvironment(); 1070*0fca6ea1SDimitry Andric if (Environment) { 1071*0fca6ea1SDimitry Andric Result << "<Environment>" << Environment->getName() << "</Environment>"; 1072*0fca6ea1SDimitry Andric } 10730b57cec5SDimitry Andric Result << "</Availability>"; 10740b57cec5SDimitry Andric } 10750b57cec5SDimitry Andric } 10760b57cec5SDimitry Andric 10770b57cec5SDimitry Andric { 10780b57cec5SDimitry Andric bool StartTagEmitted = false; 10790b57cec5SDimitry Andric for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) { 10800b57cec5SDimitry Andric const Comment *C = Parts.MiscBlocks[i]; 10810b57cec5SDimitry Andric if (FirstParagraphIsBrief && C == Parts.FirstParagraph) 10820b57cec5SDimitry Andric continue; 10830b57cec5SDimitry Andric if (!StartTagEmitted) { 10840b57cec5SDimitry Andric Result << "<Discussion>"; 10850b57cec5SDimitry Andric StartTagEmitted = true; 10860b57cec5SDimitry Andric } 10870b57cec5SDimitry Andric visit(C); 10880b57cec5SDimitry Andric } 10890b57cec5SDimitry Andric if (StartTagEmitted) 10900b57cec5SDimitry Andric Result << "</Discussion>"; 10910b57cec5SDimitry Andric } 10920b57cec5SDimitry Andric 10930b57cec5SDimitry Andric Result << RootEndTag; 10940b57cec5SDimitry Andric } 10950b57cec5SDimitry Andric 10960b57cec5SDimitry Andric void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) { 10970b57cec5SDimitry Andric for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) { 10980b57cec5SDimitry Andric const char C = *I; 10990b57cec5SDimitry Andric switch (C) { 11000b57cec5SDimitry Andric case '&': 11010b57cec5SDimitry Andric Result << "&"; 11020b57cec5SDimitry Andric break; 11030b57cec5SDimitry Andric case '<': 11040b57cec5SDimitry Andric Result << "<"; 11050b57cec5SDimitry Andric break; 11060b57cec5SDimitry Andric case '>': 11070b57cec5SDimitry Andric Result << ">"; 11080b57cec5SDimitry Andric break; 11090b57cec5SDimitry Andric case '"': 11100b57cec5SDimitry Andric Result << """; 11110b57cec5SDimitry Andric break; 11120b57cec5SDimitry Andric case '\'': 11130b57cec5SDimitry Andric Result << "'"; 11140b57cec5SDimitry Andric break; 11150b57cec5SDimitry Andric default: 11160b57cec5SDimitry Andric Result << C; 11170b57cec5SDimitry Andric break; 11180b57cec5SDimitry Andric } 11190b57cec5SDimitry Andric } 11200b57cec5SDimitry Andric } 11210b57cec5SDimitry Andric 11220b57cec5SDimitry Andric void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) { 11230b57cec5SDimitry Andric if (S.empty()) 11240b57cec5SDimitry Andric return; 11250b57cec5SDimitry Andric 11260b57cec5SDimitry Andric Result << "<![CDATA["; 11270b57cec5SDimitry Andric while (!S.empty()) { 11280b57cec5SDimitry Andric size_t Pos = S.find("]]>"); 11290b57cec5SDimitry Andric if (Pos == 0) { 11300b57cec5SDimitry Andric Result << "]]]]><![CDATA[>"; 11310b57cec5SDimitry Andric S = S.drop_front(3); 11320b57cec5SDimitry Andric continue; 11330b57cec5SDimitry Andric } 11340b57cec5SDimitry Andric if (Pos == StringRef::npos) 11350b57cec5SDimitry Andric Pos = S.size(); 11360b57cec5SDimitry Andric 11370b57cec5SDimitry Andric Result << S.substr(0, Pos); 11380b57cec5SDimitry Andric 11390b57cec5SDimitry Andric S = S.drop_front(Pos); 11400b57cec5SDimitry Andric } 11410b57cec5SDimitry Andric Result << "]]>"; 11420b57cec5SDimitry Andric } 11430b57cec5SDimitry Andric 11440b57cec5SDimitry Andric CommentToXMLConverter::CommentToXMLConverter() {} 11450b57cec5SDimitry Andric CommentToXMLConverter::~CommentToXMLConverter() {} 11460b57cec5SDimitry Andric 11470b57cec5SDimitry Andric void CommentToXMLConverter::convertCommentToHTML(const FullComment *FC, 11480b57cec5SDimitry Andric SmallVectorImpl<char> &HTML, 11490b57cec5SDimitry Andric const ASTContext &Context) { 11500b57cec5SDimitry Andric CommentASTToHTMLConverter Converter(FC, HTML, 11510b57cec5SDimitry Andric Context.getCommentCommandTraits()); 11520b57cec5SDimitry Andric Converter.visit(FC); 11530b57cec5SDimitry Andric } 11540b57cec5SDimitry Andric 11550b57cec5SDimitry Andric void CommentToXMLConverter::convertHTMLTagNodeToText( 11560b57cec5SDimitry Andric const comments::HTMLTagComment *HTC, SmallVectorImpl<char> &Text, 11570b57cec5SDimitry Andric const ASTContext &Context) { 11580b57cec5SDimitry Andric CommentASTToHTMLConverter Converter(nullptr, Text, 11590b57cec5SDimitry Andric Context.getCommentCommandTraits()); 11600b57cec5SDimitry Andric Converter.visit(HTC); 11610b57cec5SDimitry Andric } 11620b57cec5SDimitry Andric 11630b57cec5SDimitry Andric void CommentToXMLConverter::convertCommentToXML(const FullComment *FC, 11640b57cec5SDimitry Andric SmallVectorImpl<char> &XML, 11650b57cec5SDimitry Andric const ASTContext &Context) { 11660b57cec5SDimitry Andric CommentASTToXMLConverter Converter(FC, XML, Context.getCommentCommandTraits(), 11670b57cec5SDimitry Andric Context.getSourceManager()); 11680b57cec5SDimitry Andric Converter.visit(FC); 11690b57cec5SDimitry Andric } 1170