19e605113SDmitri Gribenko //===--- CommentToXML.cpp - Convert comments to XML representation --------===//
29e605113SDmitri Gribenko //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69e605113SDmitri Gribenko //
79e605113SDmitri Gribenko //===----------------------------------------------------------------------===//
89e605113SDmitri Gribenko 
99e605113SDmitri Gribenko #include "clang/Index/CommentToXML.h"
109e605113SDmitri Gribenko #include "clang/AST/ASTContext.h"
115553d0d4SChandler Carruth #include "clang/AST/Attr.h"
129e605113SDmitri Gribenko #include "clang/AST/Comment.h"
139e605113SDmitri Gribenko #include "clang/AST/CommentVisitor.h"
14*e08464fbSReid Kleckner #include "clang/Basic/FileManager.h"
1586565c13SReid Kleckner #include "clang/Basic/SourceManager.h"
169e605113SDmitri Gribenko #include "clang/Format/Format.h"
179e605113SDmitri Gribenko #include "clang/Index/USRGeneration.h"
189e605113SDmitri Gribenko #include "llvm/ADT/StringExtras.h"
199e605113SDmitri Gribenko #include "llvm/ADT/TinyPtrVector.h"
209e605113SDmitri Gribenko #include "llvm/Support/raw_ostream.h"
219e605113SDmitri Gribenko 
229e605113SDmitri Gribenko using namespace clang;
239e605113SDmitri Gribenko using namespace clang::comments;
249e605113SDmitri Gribenko using namespace clang::index;
259e605113SDmitri Gribenko 
269e605113SDmitri Gribenko namespace {
279e605113SDmitri Gribenko 
289e605113SDmitri Gribenko /// This comparison will sort parameters with valid index by index, then vararg
299e605113SDmitri Gribenko /// parameters, and invalid (unresolved) parameters last.
309e605113SDmitri Gribenko class ParamCommandCommentCompareIndex {
319e605113SDmitri Gribenko public:
operator ()(const ParamCommandComment * LHS,const ParamCommandComment * RHS) const329e605113SDmitri Gribenko   bool operator()(const ParamCommandComment *LHS,
339e605113SDmitri Gribenko                   const ParamCommandComment *RHS) const {
349e605113SDmitri Gribenko     unsigned LHSIndex = UINT_MAX;
359e605113SDmitri Gribenko     unsigned RHSIndex = UINT_MAX;
369e605113SDmitri Gribenko 
379e605113SDmitri Gribenko     if (LHS->isParamIndexValid()) {
389e605113SDmitri Gribenko       if (LHS->isVarArgParam())
399e605113SDmitri Gribenko         LHSIndex = UINT_MAX - 1;
409e605113SDmitri Gribenko       else
419e605113SDmitri Gribenko         LHSIndex = LHS->getParamIndex();
429e605113SDmitri Gribenko     }
439e605113SDmitri Gribenko     if (RHS->isParamIndexValid()) {
449e605113SDmitri Gribenko       if (RHS->isVarArgParam())
459e605113SDmitri Gribenko         RHSIndex = UINT_MAX - 1;
469e605113SDmitri Gribenko       else
479e605113SDmitri Gribenko         RHSIndex = RHS->getParamIndex();
489e605113SDmitri Gribenko     }
499e605113SDmitri Gribenko     return LHSIndex < RHSIndex;
509e605113SDmitri Gribenko   }
519e605113SDmitri Gribenko };
529e605113SDmitri Gribenko 
539e605113SDmitri Gribenko /// This comparison will sort template parameters in the following order:
549e605113SDmitri Gribenko /// \li real template parameters (depth = 1) in index order;
559e605113SDmitri Gribenko /// \li all other names (depth > 1);
569e605113SDmitri Gribenko /// \li unresolved names.
579e605113SDmitri Gribenko class TParamCommandCommentComparePosition {
589e605113SDmitri Gribenko public:
operator ()(const TParamCommandComment * LHS,const TParamCommandComment * RHS) const599e605113SDmitri Gribenko   bool operator()(const TParamCommandComment *LHS,
609e605113SDmitri Gribenko                   const TParamCommandComment *RHS) const {
619e605113SDmitri Gribenko     // Sort unresolved names last.
629e605113SDmitri Gribenko     if (!LHS->isPositionValid())
639e605113SDmitri Gribenko       return false;
649e605113SDmitri Gribenko     if (!RHS->isPositionValid())
659e605113SDmitri Gribenko       return true;
669e605113SDmitri Gribenko 
679e605113SDmitri Gribenko     if (LHS->getDepth() > 1)
689e605113SDmitri Gribenko       return false;
699e605113SDmitri Gribenko     if (RHS->getDepth() > 1)
709e605113SDmitri Gribenko       return true;
719e605113SDmitri Gribenko 
729e605113SDmitri Gribenko     // Sort template parameters in index order.
739e605113SDmitri Gribenko     if (LHS->getDepth() == 1 && RHS->getDepth() == 1)
749e605113SDmitri Gribenko       return LHS->getIndex(0) < RHS->getIndex(0);
759e605113SDmitri Gribenko 
769e605113SDmitri Gribenko     // Leave all other names in source order.
779e605113SDmitri Gribenko     return true;
789e605113SDmitri Gribenko   }
799e605113SDmitri Gribenko };
809e605113SDmitri Gribenko 
819e605113SDmitri Gribenko /// Separate parts of a FullComment.
829e605113SDmitri Gribenko struct FullCommentParts {
839e605113SDmitri Gribenko   /// Take a full comment apart and initialize members accordingly.
849e605113SDmitri Gribenko   FullCommentParts(const FullComment *C,
859e605113SDmitri Gribenko                    const CommandTraits &Traits);
869e605113SDmitri Gribenko 
879e605113SDmitri Gribenko   const BlockContentComment *Brief;
889e605113SDmitri Gribenko   const BlockContentComment *Headerfile;
899e605113SDmitri Gribenko   const ParagraphComment *FirstParagraph;
909e605113SDmitri Gribenko   SmallVector<const BlockCommandComment *, 4> Returns;
919e605113SDmitri Gribenko   SmallVector<const ParamCommandComment *, 8> Params;
929e605113SDmitri Gribenko   SmallVector<const TParamCommandComment *, 4> TParams;
939e605113SDmitri Gribenko   llvm::TinyPtrVector<const BlockCommandComment *> Exceptions;
949e605113SDmitri Gribenko   SmallVector<const BlockContentComment *, 8> MiscBlocks;
959e605113SDmitri Gribenko };
969e605113SDmitri Gribenko 
FullCommentParts(const FullComment * C,const CommandTraits & Traits)979e605113SDmitri Gribenko FullCommentParts::FullCommentParts(const FullComment *C,
989e605113SDmitri Gribenko                                    const CommandTraits &Traits) :
99236bde3dSCraig Topper     Brief(nullptr), Headerfile(nullptr), FirstParagraph(nullptr) {
1009e605113SDmitri Gribenko   for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
1019e605113SDmitri Gribenko        I != E; ++I) {
1029e605113SDmitri Gribenko     const Comment *Child = *I;
1039e605113SDmitri Gribenko     if (!Child)
1049e605113SDmitri Gribenko       continue;
1059e605113SDmitri Gribenko     switch (Child->getCommentKind()) {
1069e605113SDmitri Gribenko     case Comment::NoCommentKind:
1079e605113SDmitri Gribenko       continue;
1089e605113SDmitri Gribenko 
1099e605113SDmitri Gribenko     case Comment::ParagraphCommentKind: {
1109e605113SDmitri Gribenko       const ParagraphComment *PC = cast<ParagraphComment>(Child);
1119e605113SDmitri Gribenko       if (PC->isWhitespace())
1129e605113SDmitri Gribenko         break;
1139e605113SDmitri Gribenko       if (!FirstParagraph)
1149e605113SDmitri Gribenko         FirstParagraph = PC;
1159e605113SDmitri Gribenko 
1169e605113SDmitri Gribenko       MiscBlocks.push_back(PC);
1179e605113SDmitri Gribenko       break;
1189e605113SDmitri Gribenko     }
1199e605113SDmitri Gribenko 
1209e605113SDmitri Gribenko     case Comment::BlockCommandCommentKind: {
1219e605113SDmitri Gribenko       const BlockCommandComment *BCC = cast<BlockCommandComment>(Child);
1229e605113SDmitri Gribenko       const CommandInfo *Info = Traits.getCommandInfo(BCC->getCommandID());
1239e605113SDmitri Gribenko       if (!Brief && Info->IsBriefCommand) {
1249e605113SDmitri Gribenko         Brief = BCC;
1259e605113SDmitri Gribenko         break;
1269e605113SDmitri Gribenko       }
1279e605113SDmitri Gribenko       if (!Headerfile && Info->IsHeaderfileCommand) {
1289e605113SDmitri Gribenko         Headerfile = BCC;
1299e605113SDmitri Gribenko         break;
1309e605113SDmitri Gribenko       }
1319e605113SDmitri Gribenko       if (Info->IsReturnsCommand) {
1329e605113SDmitri Gribenko         Returns.push_back(BCC);
1339e605113SDmitri Gribenko         break;
1349e605113SDmitri Gribenko       }
1359e605113SDmitri Gribenko       if (Info->IsThrowsCommand) {
1369e605113SDmitri Gribenko         Exceptions.push_back(BCC);
1379e605113SDmitri Gribenko         break;
1389e605113SDmitri Gribenko       }
1399e605113SDmitri Gribenko       MiscBlocks.push_back(BCC);
1409e605113SDmitri Gribenko       break;
1419e605113SDmitri Gribenko     }
1429e605113SDmitri Gribenko 
1439e605113SDmitri Gribenko     case Comment::ParamCommandCommentKind: {
1449e605113SDmitri Gribenko       const ParamCommandComment *PCC = cast<ParamCommandComment>(Child);
1459e605113SDmitri Gribenko       if (!PCC->hasParamName())
1469e605113SDmitri Gribenko         break;
1479e605113SDmitri Gribenko 
1489e605113SDmitri Gribenko       if (!PCC->isDirectionExplicit() && !PCC->hasNonWhitespaceParagraph())
1499e605113SDmitri Gribenko         break;
1509e605113SDmitri Gribenko 
1519e605113SDmitri Gribenko       Params.push_back(PCC);
1529e605113SDmitri Gribenko       break;
1539e605113SDmitri Gribenko     }
1549e605113SDmitri Gribenko 
1559e605113SDmitri Gribenko     case Comment::TParamCommandCommentKind: {
1569e605113SDmitri Gribenko       const TParamCommandComment *TPCC = cast<TParamCommandComment>(Child);
1579e605113SDmitri Gribenko       if (!TPCC->hasParamName())
1589e605113SDmitri Gribenko         break;
1599e605113SDmitri Gribenko 
1609e605113SDmitri Gribenko       if (!TPCC->hasNonWhitespaceParagraph())
1619e605113SDmitri Gribenko         break;
1629e605113SDmitri Gribenko 
1639e605113SDmitri Gribenko       TParams.push_back(TPCC);
1649e605113SDmitri Gribenko       break;
1659e605113SDmitri Gribenko     }
1669e605113SDmitri Gribenko 
1679e605113SDmitri Gribenko     case Comment::VerbatimBlockCommentKind:
1689e605113SDmitri Gribenko       MiscBlocks.push_back(cast<BlockCommandComment>(Child));
1699e605113SDmitri Gribenko       break;
1709e605113SDmitri Gribenko 
1719e605113SDmitri Gribenko     case Comment::VerbatimLineCommentKind: {
1729e605113SDmitri Gribenko       const VerbatimLineComment *VLC = cast<VerbatimLineComment>(Child);
1739e605113SDmitri Gribenko       const CommandInfo *Info = Traits.getCommandInfo(VLC->getCommandID());
1749e605113SDmitri Gribenko       if (!Info->IsDeclarationCommand)
1759e605113SDmitri Gribenko         MiscBlocks.push_back(VLC);
1769e605113SDmitri Gribenko       break;
1779e605113SDmitri Gribenko     }
1789e605113SDmitri Gribenko 
1799e605113SDmitri Gribenko     case Comment::TextCommentKind:
1809e605113SDmitri Gribenko     case Comment::InlineCommandCommentKind:
1819e605113SDmitri Gribenko     case Comment::HTMLStartTagCommentKind:
1829e605113SDmitri Gribenko     case Comment::HTMLEndTagCommentKind:
1839e605113SDmitri Gribenko     case Comment::VerbatimBlockLineCommentKind:
1849e605113SDmitri Gribenko     case Comment::FullCommentKind:
1859e605113SDmitri Gribenko       llvm_unreachable("AST node of this kind can't be a child of "
1869e605113SDmitri Gribenko                        "a FullComment");
1879e605113SDmitri Gribenko     }
1889e605113SDmitri Gribenko   }
1899e605113SDmitri Gribenko 
1909e605113SDmitri Gribenko   // Sort params in order they are declared in the function prototype.
1919e605113SDmitri Gribenko   // Unresolved parameters are put at the end of the list in the same order
1929e605113SDmitri Gribenko   // they were seen in the comment.
193899d1392SFangrui Song   llvm::stable_sort(Params, ParamCommandCommentCompareIndex());
194899d1392SFangrui Song   llvm::stable_sort(TParams, TParamCommandCommentComparePosition());
1959e605113SDmitri Gribenko }
1969e605113SDmitri Gribenko 
printHTMLStartTagComment(const HTMLStartTagComment * C,llvm::raw_svector_ostream & Result)1979e605113SDmitri Gribenko void printHTMLStartTagComment(const HTMLStartTagComment *C,
1989e605113SDmitri Gribenko                               llvm::raw_svector_ostream &Result) {
1999e605113SDmitri Gribenko   Result << "<" << C->getTagName();
2009e605113SDmitri Gribenko 
2019e605113SDmitri Gribenko   if (C->getNumAttrs() != 0) {
2029e605113SDmitri Gribenko     for (unsigned i = 0, e = C->getNumAttrs(); i != e; i++) {
2039e605113SDmitri Gribenko       Result << " ";
2049e605113SDmitri Gribenko       const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
2059e605113SDmitri Gribenko       Result << Attr.Name;
2069e605113SDmitri Gribenko       if (!Attr.Value.empty())
2079e605113SDmitri Gribenko         Result << "=\"" << Attr.Value << "\"";
2089e605113SDmitri Gribenko     }
2099e605113SDmitri Gribenko   }
2109e605113SDmitri Gribenko 
2119e605113SDmitri Gribenko   if (!C->isSelfClosing())
2129e605113SDmitri Gribenko     Result << ">";
2139e605113SDmitri Gribenko   else
2149e605113SDmitri Gribenko     Result << "/>";
2159e605113SDmitri Gribenko }
2169e605113SDmitri Gribenko 
2179e605113SDmitri Gribenko class CommentASTToHTMLConverter :
2189e605113SDmitri Gribenko     public ConstCommentVisitor<CommentASTToHTMLConverter> {
2199e605113SDmitri Gribenko public:
2209e605113SDmitri Gribenko   /// \param Str accumulator for HTML.
CommentASTToHTMLConverter(const FullComment * FC,SmallVectorImpl<char> & Str,const CommandTraits & Traits)2219e605113SDmitri Gribenko   CommentASTToHTMLConverter(const FullComment *FC,
2229e605113SDmitri Gribenko                             SmallVectorImpl<char> &Str,
2239e605113SDmitri Gribenko                             const CommandTraits &Traits) :
2249e605113SDmitri Gribenko       FC(FC), Result(Str), Traits(Traits)
2259e605113SDmitri Gribenko   { }
2269e605113SDmitri Gribenko 
2279e605113SDmitri Gribenko   // Inline content.
2289e605113SDmitri Gribenko   void visitTextComment(const TextComment *C);
2299e605113SDmitri Gribenko   void visitInlineCommandComment(const InlineCommandComment *C);
2309e605113SDmitri Gribenko   void visitHTMLStartTagComment(const HTMLStartTagComment *C);
2319e605113SDmitri Gribenko   void visitHTMLEndTagComment(const HTMLEndTagComment *C);
2329e605113SDmitri Gribenko 
2339e605113SDmitri Gribenko   // Block content.
2349e605113SDmitri Gribenko   void visitParagraphComment(const ParagraphComment *C);
2359e605113SDmitri Gribenko   void visitBlockCommandComment(const BlockCommandComment *C);
2369e605113SDmitri Gribenko   void visitParamCommandComment(const ParamCommandComment *C);
2379e605113SDmitri Gribenko   void visitTParamCommandComment(const TParamCommandComment *C);
2389e605113SDmitri Gribenko   void visitVerbatimBlockComment(const VerbatimBlockComment *C);
2399e605113SDmitri Gribenko   void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
2409e605113SDmitri Gribenko   void visitVerbatimLineComment(const VerbatimLineComment *C);
2419e605113SDmitri Gribenko 
2429e605113SDmitri Gribenko   void visitFullComment(const FullComment *C);
2439e605113SDmitri Gribenko 
2449e605113SDmitri Gribenko   // Helpers.
2459e605113SDmitri Gribenko 
2469e605113SDmitri Gribenko   /// Convert a paragraph that is not a block by itself (an argument to some
2479e605113SDmitri Gribenko   /// command).
2489e605113SDmitri Gribenko   void visitNonStandaloneParagraphComment(const ParagraphComment *C);
2499e605113SDmitri Gribenko 
2509e605113SDmitri Gribenko   void appendToResultWithHTMLEscaping(StringRef S);
2519e605113SDmitri Gribenko 
2529e605113SDmitri Gribenko private:
2539e605113SDmitri Gribenko   const FullComment *FC;
2549e605113SDmitri Gribenko   /// Output stream for HTML.
2559e605113SDmitri Gribenko   llvm::raw_svector_ostream Result;
2569e605113SDmitri Gribenko 
2579e605113SDmitri Gribenko   const CommandTraits &Traits;
2589e605113SDmitri Gribenko };
2599e605113SDmitri Gribenko } // end unnamed namespace
2609e605113SDmitri Gribenko 
visitTextComment(const TextComment * C)2619e605113SDmitri Gribenko void CommentASTToHTMLConverter::visitTextComment(const TextComment *C) {
2629e605113SDmitri Gribenko   appendToResultWithHTMLEscaping(C->getText());
2639e605113SDmitri Gribenko }
2649e605113SDmitri Gribenko 
visitInlineCommandComment(const InlineCommandComment * C)2659e605113SDmitri Gribenko void CommentASTToHTMLConverter::visitInlineCommandComment(
2669e605113SDmitri Gribenko                                   const InlineCommandComment *C) {
2679e605113SDmitri Gribenko   // Nothing to render if no arguments supplied.
2689e605113SDmitri Gribenko   if (C->getNumArgs() == 0)
2699e605113SDmitri Gribenko     return;
2709e605113SDmitri Gribenko 
2719e605113SDmitri Gribenko   // Nothing to render if argument is empty.
2729e605113SDmitri Gribenko   StringRef Arg0 = C->getArgText(0);
2739e605113SDmitri Gribenko   if (Arg0.empty())
2749e605113SDmitri Gribenko     return;
2759e605113SDmitri Gribenko 
2769e605113SDmitri Gribenko   switch (C->getRenderKind()) {
2779e605113SDmitri Gribenko   case InlineCommandComment::RenderNormal:
2789e605113SDmitri Gribenko     for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
2799e605113SDmitri Gribenko       appendToResultWithHTMLEscaping(C->getArgText(i));
2809e605113SDmitri Gribenko       Result << " ";
2819e605113SDmitri Gribenko     }
2829e605113SDmitri Gribenko     return;
2839e605113SDmitri Gribenko 
2849e605113SDmitri Gribenko   case InlineCommandComment::RenderBold:
2859e605113SDmitri Gribenko     assert(C->getNumArgs() == 1);
2869e605113SDmitri Gribenko     Result << "<b>";
2879e605113SDmitri Gribenko     appendToResultWithHTMLEscaping(Arg0);
2889e605113SDmitri Gribenko     Result << "</b>";
2899e605113SDmitri Gribenko     return;
2909e605113SDmitri Gribenko   case InlineCommandComment::RenderMonospaced:
2919e605113SDmitri Gribenko     assert(C->getNumArgs() == 1);
2929e605113SDmitri Gribenko     Result << "<tt>";
2939e605113SDmitri Gribenko     appendToResultWithHTMLEscaping(Arg0);
2949e605113SDmitri Gribenko     Result<< "</tt>";
2959e605113SDmitri Gribenko     return;
2969e605113SDmitri Gribenko   case InlineCommandComment::RenderEmphasized:
2979e605113SDmitri Gribenko     assert(C->getNumArgs() == 1);
2989e605113SDmitri Gribenko     Result << "<em>";
2999e605113SDmitri Gribenko     appendToResultWithHTMLEscaping(Arg0);
3009e605113SDmitri Gribenko     Result << "</em>";
3019e605113SDmitri Gribenko     return;
302be1a9b38SMark de Wever   case InlineCommandComment::RenderAnchor:
303be1a9b38SMark de Wever     assert(C->getNumArgs() == 1);
304be1a9b38SMark de Wever     Result << "<span id=\"" << Arg0 << "\"></span>";
305be1a9b38SMark de Wever     return;
3069e605113SDmitri Gribenko   }
3079e605113SDmitri Gribenko }
3089e605113SDmitri Gribenko 
visitHTMLStartTagComment(const HTMLStartTagComment * C)3099e605113SDmitri Gribenko void CommentASTToHTMLConverter::visitHTMLStartTagComment(
3109e605113SDmitri Gribenko                                   const HTMLStartTagComment *C) {
3119e605113SDmitri Gribenko   printHTMLStartTagComment(C, Result);
3129e605113SDmitri Gribenko }
3139e605113SDmitri Gribenko 
visitHTMLEndTagComment(const HTMLEndTagComment * C)3149e605113SDmitri Gribenko void CommentASTToHTMLConverter::visitHTMLEndTagComment(
3159e605113SDmitri Gribenko                                   const HTMLEndTagComment *C) {
3169e605113SDmitri Gribenko   Result << "</" << C->getTagName() << ">";
3179e605113SDmitri Gribenko }
3189e605113SDmitri Gribenko 
visitParagraphComment(const ParagraphComment * C)3199e605113SDmitri Gribenko void CommentASTToHTMLConverter::visitParagraphComment(
3209e605113SDmitri Gribenko                                   const ParagraphComment *C) {
3219e605113SDmitri Gribenko   if (C->isWhitespace())
3229e605113SDmitri Gribenko     return;
3239e605113SDmitri Gribenko 
3249e605113SDmitri Gribenko   Result << "<p>";
3259e605113SDmitri Gribenko   for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
3269e605113SDmitri Gribenko        I != E; ++I) {
3279e605113SDmitri Gribenko     visit(*I);
3289e605113SDmitri Gribenko   }
3299e605113SDmitri Gribenko   Result << "</p>";
3309e605113SDmitri Gribenko }
3319e605113SDmitri Gribenko 
visitBlockCommandComment(const BlockCommandComment * C)3329e605113SDmitri Gribenko void CommentASTToHTMLConverter::visitBlockCommandComment(
3339e605113SDmitri Gribenko                                   const BlockCommandComment *C) {
3349e605113SDmitri Gribenko   const CommandInfo *Info = Traits.getCommandInfo(C->getCommandID());
3359e605113SDmitri Gribenko   if (Info->IsBriefCommand) {
3369e605113SDmitri Gribenko     Result << "<p class=\"para-brief\">";
3379e605113SDmitri Gribenko     visitNonStandaloneParagraphComment(C->getParagraph());
3389e605113SDmitri Gribenko     Result << "</p>";
3399e605113SDmitri Gribenko     return;
3409e605113SDmitri Gribenko   }
3419e605113SDmitri Gribenko   if (Info->IsReturnsCommand) {
3429e605113SDmitri Gribenko     Result << "<p class=\"para-returns\">"
3439e605113SDmitri Gribenko               "<span class=\"word-returns\">Returns</span> ";
3449e605113SDmitri Gribenko     visitNonStandaloneParagraphComment(C->getParagraph());
3459e605113SDmitri Gribenko     Result << "</p>";
3469e605113SDmitri Gribenko     return;
3479e605113SDmitri Gribenko   }
3489e605113SDmitri Gribenko   // We don't know anything about this command.  Just render the paragraph.
3499e605113SDmitri Gribenko   visit(C->getParagraph());
3509e605113SDmitri Gribenko }
3519e605113SDmitri Gribenko 
visitParamCommandComment(const ParamCommandComment * C)3529e605113SDmitri Gribenko void CommentASTToHTMLConverter::visitParamCommandComment(
3539e605113SDmitri Gribenko                                   const ParamCommandComment *C) {
3549e605113SDmitri Gribenko   if (C->isParamIndexValid()) {
3559e605113SDmitri Gribenko     if (C->isVarArgParam()) {
3569e605113SDmitri Gribenko       Result << "<dt class=\"param-name-index-vararg\">";
3579e605113SDmitri Gribenko       appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
3589e605113SDmitri Gribenko     } else {
3599e605113SDmitri Gribenko       Result << "<dt class=\"param-name-index-"
3609e605113SDmitri Gribenko              << C->getParamIndex()
3619e605113SDmitri Gribenko              << "\">";
3629e605113SDmitri Gribenko       appendToResultWithHTMLEscaping(C->getParamName(FC));
3639e605113SDmitri Gribenko     }
3649e605113SDmitri Gribenko   } else {
3659e605113SDmitri Gribenko     Result << "<dt class=\"param-name-index-invalid\">";
3669e605113SDmitri Gribenko     appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
3679e605113SDmitri Gribenko   }
3689e605113SDmitri Gribenko   Result << "</dt>";
3699e605113SDmitri Gribenko 
3709e605113SDmitri Gribenko   if (C->isParamIndexValid()) {
3719e605113SDmitri Gribenko     if (C->isVarArgParam())
3729e605113SDmitri Gribenko       Result << "<dd class=\"param-descr-index-vararg\">";
3739e605113SDmitri Gribenko     else
3749e605113SDmitri Gribenko       Result << "<dd class=\"param-descr-index-"
3759e605113SDmitri Gribenko              << C->getParamIndex()
3769e605113SDmitri Gribenko              << "\">";
3779e605113SDmitri Gribenko   } else
3789e605113SDmitri Gribenko     Result << "<dd class=\"param-descr-index-invalid\">";
3799e605113SDmitri Gribenko 
3809e605113SDmitri Gribenko   visitNonStandaloneParagraphComment(C->getParagraph());
3819e605113SDmitri Gribenko   Result << "</dd>";
3829e605113SDmitri Gribenko }
3839e605113SDmitri Gribenko 
visitTParamCommandComment(const TParamCommandComment * C)3849e605113SDmitri Gribenko void CommentASTToHTMLConverter::visitTParamCommandComment(
3859e605113SDmitri Gribenko                                   const TParamCommandComment *C) {
3869e605113SDmitri Gribenko   if (C->isPositionValid()) {
3879e605113SDmitri Gribenko     if (C->getDepth() == 1)
3889e605113SDmitri Gribenko       Result << "<dt class=\"tparam-name-index-"
3899e605113SDmitri Gribenko              << C->getIndex(0)
3909e605113SDmitri Gribenko              << "\">";
3919e605113SDmitri Gribenko     else
3929e605113SDmitri Gribenko       Result << "<dt class=\"tparam-name-index-other\">";
3939e605113SDmitri Gribenko     appendToResultWithHTMLEscaping(C->getParamName(FC));
3949e605113SDmitri Gribenko   } else {
3959e605113SDmitri Gribenko     Result << "<dt class=\"tparam-name-index-invalid\">";
3969e605113SDmitri Gribenko     appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
3979e605113SDmitri Gribenko   }
3989e605113SDmitri Gribenko 
3999e605113SDmitri Gribenko   Result << "</dt>";
4009e605113SDmitri Gribenko 
4019e605113SDmitri Gribenko   if (C->isPositionValid()) {
4029e605113SDmitri Gribenko     if (C->getDepth() == 1)
4039e605113SDmitri Gribenko       Result << "<dd class=\"tparam-descr-index-"
4049e605113SDmitri Gribenko              << C->getIndex(0)
4059e605113SDmitri Gribenko              << "\">";
4069e605113SDmitri Gribenko     else
4079e605113SDmitri Gribenko       Result << "<dd class=\"tparam-descr-index-other\">";
4089e605113SDmitri Gribenko   } else
4099e605113SDmitri Gribenko     Result << "<dd class=\"tparam-descr-index-invalid\">";
4109e605113SDmitri Gribenko 
4119e605113SDmitri Gribenko   visitNonStandaloneParagraphComment(C->getParagraph());
4129e605113SDmitri Gribenko   Result << "</dd>";
4139e605113SDmitri Gribenko }
4149e605113SDmitri Gribenko 
visitVerbatimBlockComment(const VerbatimBlockComment * C)4159e605113SDmitri Gribenko void CommentASTToHTMLConverter::visitVerbatimBlockComment(
4169e605113SDmitri Gribenko                                   const VerbatimBlockComment *C) {
4179e605113SDmitri Gribenko   unsigned NumLines = C->getNumLines();
4189e605113SDmitri Gribenko   if (NumLines == 0)
4199e605113SDmitri Gribenko     return;
4209e605113SDmitri Gribenko 
4219e605113SDmitri Gribenko   Result << "<pre>";
4229e605113SDmitri Gribenko   for (unsigned i = 0; i != NumLines; ++i) {
4239e605113SDmitri Gribenko     appendToResultWithHTMLEscaping(C->getText(i));
4249e605113SDmitri Gribenko     if (i + 1 != NumLines)
4259e605113SDmitri Gribenko       Result << '\n';
4269e605113SDmitri Gribenko   }
4279e605113SDmitri Gribenko   Result << "</pre>";
4289e605113SDmitri Gribenko }
4299e605113SDmitri Gribenko 
visitVerbatimBlockLineComment(const VerbatimBlockLineComment * C)4309e605113SDmitri Gribenko void CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
4319e605113SDmitri Gribenko                                   const VerbatimBlockLineComment *C) {
4329e605113SDmitri Gribenko   llvm_unreachable("should not see this AST node");
4339e605113SDmitri Gribenko }
4349e605113SDmitri Gribenko 
visitVerbatimLineComment(const VerbatimLineComment * C)4359e605113SDmitri Gribenko void CommentASTToHTMLConverter::visitVerbatimLineComment(
4369e605113SDmitri Gribenko                                   const VerbatimLineComment *C) {
4379e605113SDmitri Gribenko   Result << "<pre>";
4389e605113SDmitri Gribenko   appendToResultWithHTMLEscaping(C->getText());
4399e605113SDmitri Gribenko   Result << "</pre>";
4409e605113SDmitri Gribenko }
4419e605113SDmitri Gribenko 
visitFullComment(const FullComment * C)4429e605113SDmitri Gribenko void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
4439e605113SDmitri Gribenko   FullCommentParts Parts(C, Traits);
4449e605113SDmitri Gribenko 
4459e605113SDmitri Gribenko   bool FirstParagraphIsBrief = false;
4469e605113SDmitri Gribenko   if (Parts.Headerfile)
4479e605113SDmitri Gribenko     visit(Parts.Headerfile);
4489e605113SDmitri Gribenko   if (Parts.Brief)
4499e605113SDmitri Gribenko     visit(Parts.Brief);
4509e605113SDmitri Gribenko   else if (Parts.FirstParagraph) {
4519e605113SDmitri Gribenko     Result << "<p class=\"para-brief\">";
4529e605113SDmitri Gribenko     visitNonStandaloneParagraphComment(Parts.FirstParagraph);
4539e605113SDmitri Gribenko     Result << "</p>";
4549e605113SDmitri Gribenko     FirstParagraphIsBrief = true;
4559e605113SDmitri Gribenko   }
4569e605113SDmitri Gribenko 
4579e605113SDmitri Gribenko   for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
4589e605113SDmitri Gribenko     const Comment *C = Parts.MiscBlocks[i];
4599e605113SDmitri Gribenko     if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
4609e605113SDmitri Gribenko       continue;
4619e605113SDmitri Gribenko     visit(C);
4629e605113SDmitri Gribenko   }
4639e605113SDmitri Gribenko 
4649e605113SDmitri Gribenko   if (Parts.TParams.size() != 0) {
4659e605113SDmitri Gribenko     Result << "<dl>";
4669e605113SDmitri Gribenko     for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
4679e605113SDmitri Gribenko       visit(Parts.TParams[i]);
4689e605113SDmitri Gribenko     Result << "</dl>";
4699e605113SDmitri Gribenko   }
4709e605113SDmitri Gribenko 
4719e605113SDmitri Gribenko   if (Parts.Params.size() != 0) {
4729e605113SDmitri Gribenko     Result << "<dl>";
4739e605113SDmitri Gribenko     for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
4749e605113SDmitri Gribenko       visit(Parts.Params[i]);
4759e605113SDmitri Gribenko     Result << "</dl>";
4769e605113SDmitri Gribenko   }
4779e605113SDmitri Gribenko 
4789e605113SDmitri Gribenko   if (Parts.Returns.size() != 0) {
4799e605113SDmitri Gribenko     Result << "<div class=\"result-discussion\">";
4809e605113SDmitri Gribenko     for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
4819e605113SDmitri Gribenko       visit(Parts.Returns[i]);
4829e605113SDmitri Gribenko     Result << "</div>";
4839e605113SDmitri Gribenko   }
4849e605113SDmitri Gribenko 
4859e605113SDmitri Gribenko }
4869e605113SDmitri Gribenko 
visitNonStandaloneParagraphComment(const ParagraphComment * C)4879e605113SDmitri Gribenko void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
4889e605113SDmitri Gribenko                                   const ParagraphComment *C) {
4899e605113SDmitri Gribenko   if (!C)
4909e605113SDmitri Gribenko     return;
4919e605113SDmitri Gribenko 
4929e605113SDmitri Gribenko   for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
4939e605113SDmitri Gribenko        I != E; ++I) {
4949e605113SDmitri Gribenko     visit(*I);
4959e605113SDmitri Gribenko   }
4969e605113SDmitri Gribenko }
4979e605113SDmitri Gribenko 
appendToResultWithHTMLEscaping(StringRef S)4989e605113SDmitri Gribenko void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) {
4999e605113SDmitri Gribenko   for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
5009e605113SDmitri Gribenko     const char C = *I;
5019e605113SDmitri Gribenko     switch (C) {
5029e605113SDmitri Gribenko     case '&':
5039e605113SDmitri Gribenko       Result << "&amp;";
5049e605113SDmitri Gribenko       break;
5059e605113SDmitri Gribenko     case '<':
5069e605113SDmitri Gribenko       Result << "&lt;";
5079e605113SDmitri Gribenko       break;
5089e605113SDmitri Gribenko     case '>':
5099e605113SDmitri Gribenko       Result << "&gt;";
5109e605113SDmitri Gribenko       break;
5119e605113SDmitri Gribenko     case '"':
5129e605113SDmitri Gribenko       Result << "&quot;";
5139e605113SDmitri Gribenko       break;
5149e605113SDmitri Gribenko     case '\'':
5159e605113SDmitri Gribenko       Result << "&#39;";
5169e605113SDmitri Gribenko       break;
5179e605113SDmitri Gribenko     case '/':
5189e605113SDmitri Gribenko       Result << "&#47;";
5199e605113SDmitri Gribenko       break;
5209e605113SDmitri Gribenko     default:
5219e605113SDmitri Gribenko       Result << C;
5229e605113SDmitri Gribenko       break;
5239e605113SDmitri Gribenko     }
5249e605113SDmitri Gribenko   }
5259e605113SDmitri Gribenko }
5269e605113SDmitri Gribenko 
5279e605113SDmitri Gribenko namespace {
5289e605113SDmitri Gribenko class CommentASTToXMLConverter :
5299e605113SDmitri Gribenko     public ConstCommentVisitor<CommentASTToXMLConverter> {
5309e605113SDmitri Gribenko public:
5319e605113SDmitri Gribenko   /// \param Str accumulator for XML.
CommentASTToXMLConverter(const FullComment * FC,SmallVectorImpl<char> & Str,const CommandTraits & Traits,const SourceManager & SM)5329e605113SDmitri Gribenko   CommentASTToXMLConverter(const FullComment *FC,
5339e605113SDmitri Gribenko                            SmallVectorImpl<char> &Str,
5349e605113SDmitri Gribenko                            const CommandTraits &Traits,
535d21485d2SDaniel Jasper                            const SourceManager &SM) :
536d21485d2SDaniel Jasper       FC(FC), Result(Str), Traits(Traits), SM(SM) { }
5379e605113SDmitri Gribenko 
5389e605113SDmitri Gribenko   // Inline content.
5399e605113SDmitri Gribenko   void visitTextComment(const TextComment *C);
5409e605113SDmitri Gribenko   void visitInlineCommandComment(const InlineCommandComment *C);
5419e605113SDmitri Gribenko   void visitHTMLStartTagComment(const HTMLStartTagComment *C);
5429e605113SDmitri Gribenko   void visitHTMLEndTagComment(const HTMLEndTagComment *C);
5439e605113SDmitri Gribenko 
5449e605113SDmitri Gribenko   // Block content.
5459e605113SDmitri Gribenko   void visitParagraphComment(const ParagraphComment *C);
5469e605113SDmitri Gribenko 
5479e605113SDmitri Gribenko   void appendParagraphCommentWithKind(const ParagraphComment *C,
5489e605113SDmitri Gribenko                                       StringRef Kind);
5499e605113SDmitri Gribenko 
5509e605113SDmitri Gribenko   void visitBlockCommandComment(const BlockCommandComment *C);
5519e605113SDmitri Gribenko   void visitParamCommandComment(const ParamCommandComment *C);
5529e605113SDmitri Gribenko   void visitTParamCommandComment(const TParamCommandComment *C);
5539e605113SDmitri Gribenko   void visitVerbatimBlockComment(const VerbatimBlockComment *C);
5549e605113SDmitri Gribenko   void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
5559e605113SDmitri Gribenko   void visitVerbatimLineComment(const VerbatimLineComment *C);
5569e605113SDmitri Gribenko 
5579e605113SDmitri Gribenko   void visitFullComment(const FullComment *C);
5589e605113SDmitri Gribenko 
5599e605113SDmitri Gribenko   // Helpers.
5609e605113SDmitri Gribenko   void appendToResultWithXMLEscaping(StringRef S);
5616db07e2aSDmitri Gribenko   void appendToResultWithCDATAEscaping(StringRef S);
5629e605113SDmitri Gribenko 
5639e605113SDmitri Gribenko   void formatTextOfDeclaration(const DeclInfo *DI,
5649e605113SDmitri Gribenko                                SmallString<128> &Declaration);
5659e605113SDmitri Gribenko 
5669e605113SDmitri Gribenko private:
5679e605113SDmitri Gribenko   const FullComment *FC;
5689e605113SDmitri Gribenko 
5699e605113SDmitri Gribenko   /// Output stream for XML.
5709e605113SDmitri Gribenko   llvm::raw_svector_ostream Result;
5719e605113SDmitri Gribenko 
5729e605113SDmitri Gribenko   const CommandTraits &Traits;
5739e605113SDmitri Gribenko   const SourceManager &SM;
5749e605113SDmitri Gribenko };
5759e605113SDmitri Gribenko 
getSourceTextOfDeclaration(const DeclInfo * ThisDecl,SmallVectorImpl<char> & Str)5769e605113SDmitri Gribenko void getSourceTextOfDeclaration(const DeclInfo *ThisDecl,
5779e605113SDmitri Gribenko                                 SmallVectorImpl<char> &Str) {
5789e605113SDmitri Gribenko   ASTContext &Context = ThisDecl->CurrentDecl->getASTContext();
5799e605113SDmitri Gribenko   const LangOptions &LangOpts = Context.getLangOpts();
5809e605113SDmitri Gribenko   llvm::raw_svector_ostream OS(Str);
5819e605113SDmitri Gribenko   PrintingPolicy PPolicy(LangOpts);
5829e605113SDmitri Gribenko   PPolicy.PolishForDeclaration = true;
5839e605113SDmitri Gribenko   PPolicy.TerseOutput = true;
58436070ed8SAlex Lorenz   PPolicy.ConstantsAsWritten = true;
5859e605113SDmitri Gribenko   ThisDecl->CurrentDecl->print(OS, PPolicy,
5869e605113SDmitri Gribenko                                /*Indentation*/0, /*PrintInstantiation*/false);
5879e605113SDmitri Gribenko }
5889e605113SDmitri Gribenko 
formatTextOfDeclaration(const DeclInfo * DI,SmallString<128> & Declaration)5899e605113SDmitri Gribenko void CommentASTToXMLConverter::formatTextOfDeclaration(
5909e605113SDmitri Gribenko     const DeclInfo *DI, SmallString<128> &Declaration) {
5910772c423SBenjamin Kramer   // Formatting API expects null terminated input string.
5920772c423SBenjamin Kramer   StringRef StringDecl(Declaration.c_str(), Declaration.size());
5939e605113SDmitri Gribenko 
5949e605113SDmitri Gribenko   // Formatter specific code.
595528d682fSDaniel Jasper   unsigned Offset = 0;
5969e605113SDmitri Gribenko   unsigned Length = Declaration.size();
5979e605113SDmitri Gribenko 
59832eaa864SKrasimir Georgiev   format::FormatStyle Style = format::getLLVMStyle();
59932eaa864SKrasimir Georgiev   Style.FixNamespaceComments = false;
600528d682fSDaniel Jasper   tooling::Replacements Replaces =
601e48c1b56SKrasimir Georgiev       reformat(Style, StringDecl, tooling::Range(Offset, Length), "xmldecl.xd");
602528d682fSDaniel Jasper   auto FormattedStringDecl = applyAllReplacements(StringDecl, Replaces);
603528d682fSDaniel Jasper   if (static_cast<bool>(FormattedStringDecl)) {
604528d682fSDaniel Jasper     Declaration = *FormattedStringDecl;
605528d682fSDaniel Jasper   }
6069e605113SDmitri Gribenko }
6079e605113SDmitri Gribenko 
6089e605113SDmitri Gribenko } // end unnamed namespace
6099e605113SDmitri Gribenko 
visitTextComment(const TextComment * C)6109e605113SDmitri Gribenko void CommentASTToXMLConverter::visitTextComment(const TextComment *C) {
6119e605113SDmitri Gribenko   appendToResultWithXMLEscaping(C->getText());
6129e605113SDmitri Gribenko }
6139e605113SDmitri Gribenko 
visitInlineCommandComment(const InlineCommandComment * C)6149e605113SDmitri Gribenko void CommentASTToXMLConverter::visitInlineCommandComment(
6159e605113SDmitri Gribenko     const InlineCommandComment *C) {
6169e605113SDmitri Gribenko   // Nothing to render if no arguments supplied.
6179e605113SDmitri Gribenko   if (C->getNumArgs() == 0)
6189e605113SDmitri Gribenko     return;
6199e605113SDmitri Gribenko 
6209e605113SDmitri Gribenko   // Nothing to render if argument is empty.
6219e605113SDmitri Gribenko   StringRef Arg0 = C->getArgText(0);
6229e605113SDmitri Gribenko   if (Arg0.empty())
6239e605113SDmitri Gribenko     return;
6249e605113SDmitri Gribenko 
6259e605113SDmitri Gribenko   switch (C->getRenderKind()) {
6269e605113SDmitri Gribenko   case InlineCommandComment::RenderNormal:
6279e605113SDmitri Gribenko     for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
6289e605113SDmitri Gribenko       appendToResultWithXMLEscaping(C->getArgText(i));
6299e605113SDmitri Gribenko       Result << " ";
6309e605113SDmitri Gribenko     }
6319e605113SDmitri Gribenko     return;
6329e605113SDmitri Gribenko   case InlineCommandComment::RenderBold:
6339e605113SDmitri Gribenko     assert(C->getNumArgs() == 1);
6349e605113SDmitri Gribenko     Result << "<bold>";
6359e605113SDmitri Gribenko     appendToResultWithXMLEscaping(Arg0);
6369e605113SDmitri Gribenko     Result << "</bold>";
6379e605113SDmitri Gribenko     return;
6389e605113SDmitri Gribenko   case InlineCommandComment::RenderMonospaced:
6399e605113SDmitri Gribenko     assert(C->getNumArgs() == 1);
6409e605113SDmitri Gribenko     Result << "<monospaced>";
6419e605113SDmitri Gribenko     appendToResultWithXMLEscaping(Arg0);
6429e605113SDmitri Gribenko     Result << "</monospaced>";
6439e605113SDmitri Gribenko     return;
6449e605113SDmitri Gribenko   case InlineCommandComment::RenderEmphasized:
6459e605113SDmitri Gribenko     assert(C->getNumArgs() == 1);
6469e605113SDmitri Gribenko     Result << "<emphasized>";
6479e605113SDmitri Gribenko     appendToResultWithXMLEscaping(Arg0);
6489e605113SDmitri Gribenko     Result << "</emphasized>";
6499e605113SDmitri Gribenko     return;
650be1a9b38SMark de Wever   case InlineCommandComment::RenderAnchor:
651be1a9b38SMark de Wever     assert(C->getNumArgs() == 1);
652be1a9b38SMark de Wever     Result << "<anchor id=\"" << Arg0 << "\"></anchor>";
653be1a9b38SMark de Wever     return;
6549e605113SDmitri Gribenko   }
6559e605113SDmitri Gribenko }
6569e605113SDmitri Gribenko 
visitHTMLStartTagComment(const HTMLStartTagComment * C)6579e605113SDmitri Gribenko void CommentASTToXMLConverter::visitHTMLStartTagComment(
6589e605113SDmitri Gribenko     const HTMLStartTagComment *C) {
65993043620SDmitri Gribenko   Result << "<rawHTML";
6600b2026deSDmitri Gribenko   if (C->isMalformed())
6610b2026deSDmitri Gribenko     Result << " isMalformed=\"1\"";
6626db07e2aSDmitri Gribenko   Result << ">";
6636db07e2aSDmitri Gribenko   {
6646db07e2aSDmitri Gribenko     SmallString<32> Tag;
6656db07e2aSDmitri Gribenko     {
6666db07e2aSDmitri Gribenko       llvm::raw_svector_ostream TagOS(Tag);
6676db07e2aSDmitri Gribenko       printHTMLStartTagComment(C, TagOS);
6686db07e2aSDmitri Gribenko     }
6696db07e2aSDmitri Gribenko     appendToResultWithCDATAEscaping(Tag);
6706db07e2aSDmitri Gribenko   }
6716db07e2aSDmitri Gribenko   Result << "</rawHTML>";
6729e605113SDmitri Gribenko }
6739e605113SDmitri Gribenko 
6749e605113SDmitri Gribenko void
visitHTMLEndTagComment(const HTMLEndTagComment * C)6759e605113SDmitri Gribenko CommentASTToXMLConverter::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
67693043620SDmitri Gribenko   Result << "<rawHTML";
6770b2026deSDmitri Gribenko   if (C->isMalformed())
6780b2026deSDmitri Gribenko     Result << " isMalformed=\"1\"";
67993043620SDmitri Gribenko   Result << ">&lt;/" << C->getTagName() << "&gt;</rawHTML>";
6809e605113SDmitri Gribenko }
6819e605113SDmitri Gribenko 
6829e605113SDmitri Gribenko void
visitParagraphComment(const ParagraphComment * C)6839e605113SDmitri Gribenko CommentASTToXMLConverter::visitParagraphComment(const ParagraphComment *C) {
6849e605113SDmitri Gribenko   appendParagraphCommentWithKind(C, StringRef());
6859e605113SDmitri Gribenko }
6869e605113SDmitri Gribenko 
appendParagraphCommentWithKind(const ParagraphComment * C,StringRef ParagraphKind)6879e605113SDmitri Gribenko void CommentASTToXMLConverter::appendParagraphCommentWithKind(
6889e605113SDmitri Gribenko                                   const ParagraphComment *C,
6899e605113SDmitri Gribenko                                   StringRef ParagraphKind) {
6909e605113SDmitri Gribenko   if (C->isWhitespace())
6919e605113SDmitri Gribenko     return;
6929e605113SDmitri Gribenko 
6939e605113SDmitri Gribenko   if (ParagraphKind.empty())
6949e605113SDmitri Gribenko     Result << "<Para>";
6959e605113SDmitri Gribenko   else
6969e605113SDmitri Gribenko     Result << "<Para kind=\"" << ParagraphKind << "\">";
6979e605113SDmitri Gribenko 
6989e605113SDmitri Gribenko   for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
6999e605113SDmitri Gribenko        I != E; ++I) {
7009e605113SDmitri Gribenko     visit(*I);
7019e605113SDmitri Gribenko   }
7029e605113SDmitri Gribenko   Result << "</Para>";
7039e605113SDmitri Gribenko }
7049e605113SDmitri Gribenko 
visitBlockCommandComment(const BlockCommandComment * C)7059e605113SDmitri Gribenko void CommentASTToXMLConverter::visitBlockCommandComment(
7069e605113SDmitri Gribenko     const BlockCommandComment *C) {
7079e605113SDmitri Gribenko   StringRef ParagraphKind;
7089e605113SDmitri Gribenko 
7099e605113SDmitri Gribenko   switch (C->getCommandID()) {
7109e605113SDmitri Gribenko   case CommandTraits::KCI_attention:
7119e605113SDmitri Gribenko   case CommandTraits::KCI_author:
7129e605113SDmitri Gribenko   case CommandTraits::KCI_authors:
7139e605113SDmitri Gribenko   case CommandTraits::KCI_bug:
7149e605113SDmitri Gribenko   case CommandTraits::KCI_copyright:
7159e605113SDmitri Gribenko   case CommandTraits::KCI_date:
7169e605113SDmitri Gribenko   case CommandTraits::KCI_invariant:
7179e605113SDmitri Gribenko   case CommandTraits::KCI_note:
7189e605113SDmitri Gribenko   case CommandTraits::KCI_post:
7199e605113SDmitri Gribenko   case CommandTraits::KCI_pre:
7209e605113SDmitri Gribenko   case CommandTraits::KCI_remark:
7219e605113SDmitri Gribenko   case CommandTraits::KCI_remarks:
7229e605113SDmitri Gribenko   case CommandTraits::KCI_sa:
7239e605113SDmitri Gribenko   case CommandTraits::KCI_see:
7249e605113SDmitri Gribenko   case CommandTraits::KCI_since:
7259e605113SDmitri Gribenko   case CommandTraits::KCI_todo:
7269e605113SDmitri Gribenko   case CommandTraits::KCI_version:
7279e605113SDmitri Gribenko   case CommandTraits::KCI_warning:
7289e605113SDmitri Gribenko     ParagraphKind = C->getCommandName(Traits);
7294dc0b1acSReid Kleckner     break;
7309e605113SDmitri Gribenko   default:
7319e605113SDmitri Gribenko     break;
7329e605113SDmitri Gribenko   }
7339e605113SDmitri Gribenko 
7349e605113SDmitri Gribenko   appendParagraphCommentWithKind(C->getParagraph(), ParagraphKind);
7359e605113SDmitri Gribenko }
7369e605113SDmitri Gribenko 
visitParamCommandComment(const ParamCommandComment * C)7379e605113SDmitri Gribenko void CommentASTToXMLConverter::visitParamCommandComment(
7389e605113SDmitri Gribenko     const ParamCommandComment *C) {
7399e605113SDmitri Gribenko   Result << "<Parameter><Name>";
7409e605113SDmitri Gribenko   appendToResultWithXMLEscaping(C->isParamIndexValid()
7419e605113SDmitri Gribenko                                     ? C->getParamName(FC)
7429e605113SDmitri Gribenko                                     : C->getParamNameAsWritten());
7439e605113SDmitri Gribenko   Result << "</Name>";
7449e605113SDmitri Gribenko 
7459e605113SDmitri Gribenko   if (C->isParamIndexValid()) {
7469e605113SDmitri Gribenko     if (C->isVarArgParam())
7479e605113SDmitri Gribenko       Result << "<IsVarArg />";
7489e605113SDmitri Gribenko     else
7499e605113SDmitri Gribenko       Result << "<Index>" << C->getParamIndex() << "</Index>";
7509e605113SDmitri Gribenko   }
7519e605113SDmitri Gribenko 
7529e605113SDmitri Gribenko   Result << "<Direction isExplicit=\"" << C->isDirectionExplicit() << "\">";
7539e605113SDmitri Gribenko   switch (C->getDirection()) {
7549e605113SDmitri Gribenko   case ParamCommandComment::In:
7559e605113SDmitri Gribenko     Result << "in";
7569e605113SDmitri Gribenko     break;
7579e605113SDmitri Gribenko   case ParamCommandComment::Out:
7589e605113SDmitri Gribenko     Result << "out";
7599e605113SDmitri Gribenko     break;
7609e605113SDmitri Gribenko   case ParamCommandComment::InOut:
7619e605113SDmitri Gribenko     Result << "in,out";
7629e605113SDmitri Gribenko     break;
7639e605113SDmitri Gribenko   }
7649e605113SDmitri Gribenko   Result << "</Direction><Discussion>";
7659e605113SDmitri Gribenko   visit(C->getParagraph());
7669e605113SDmitri Gribenko   Result << "</Discussion></Parameter>";
7679e605113SDmitri Gribenko }
7689e605113SDmitri Gribenko 
visitTParamCommandComment(const TParamCommandComment * C)7699e605113SDmitri Gribenko void CommentASTToXMLConverter::visitTParamCommandComment(
7709e605113SDmitri Gribenko                                   const TParamCommandComment *C) {
7719e605113SDmitri Gribenko   Result << "<Parameter><Name>";
7729e605113SDmitri Gribenko   appendToResultWithXMLEscaping(C->isPositionValid() ? C->getParamName(FC)
7739e605113SDmitri Gribenko                                 : C->getParamNameAsWritten());
7749e605113SDmitri Gribenko   Result << "</Name>";
7759e605113SDmitri Gribenko 
7769e605113SDmitri Gribenko   if (C->isPositionValid() && C->getDepth() == 1) {
7779e605113SDmitri Gribenko     Result << "<Index>" << C->getIndex(0) << "</Index>";
7789e605113SDmitri Gribenko   }
7799e605113SDmitri Gribenko 
7809e605113SDmitri Gribenko   Result << "<Discussion>";
7819e605113SDmitri Gribenko   visit(C->getParagraph());
7829e605113SDmitri Gribenko   Result << "</Discussion></Parameter>";
7839e605113SDmitri Gribenko }
7849e605113SDmitri Gribenko 
visitVerbatimBlockComment(const VerbatimBlockComment * C)7859e605113SDmitri Gribenko void CommentASTToXMLConverter::visitVerbatimBlockComment(
7869e605113SDmitri Gribenko                                   const VerbatimBlockComment *C) {
7879e605113SDmitri Gribenko   unsigned NumLines = C->getNumLines();
7889e605113SDmitri Gribenko   if (NumLines == 0)
7899e605113SDmitri Gribenko     return;
7909e605113SDmitri Gribenko 
7919e605113SDmitri Gribenko   switch (C->getCommandID()) {
7929e605113SDmitri Gribenko   case CommandTraits::KCI_code:
7939e605113SDmitri Gribenko     Result << "<Verbatim xml:space=\"preserve\" kind=\"code\">";
7949e605113SDmitri Gribenko     break;
7959e605113SDmitri Gribenko   default:
7969e605113SDmitri Gribenko     Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
7979e605113SDmitri Gribenko     break;
7989e605113SDmitri Gribenko   }
7999e605113SDmitri Gribenko   for (unsigned i = 0; i != NumLines; ++i) {
8009e605113SDmitri Gribenko     appendToResultWithXMLEscaping(C->getText(i));
8019e605113SDmitri Gribenko     if (i + 1 != NumLines)
8029e605113SDmitri Gribenko       Result << '\n';
8039e605113SDmitri Gribenko   }
8049e605113SDmitri Gribenko   Result << "</Verbatim>";
8059e605113SDmitri Gribenko }
8069e605113SDmitri Gribenko 
visitVerbatimBlockLineComment(const VerbatimBlockLineComment * C)8079e605113SDmitri Gribenko void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
8089e605113SDmitri Gribenko                                   const VerbatimBlockLineComment *C) {
8099e605113SDmitri Gribenko   llvm_unreachable("should not see this AST node");
8109e605113SDmitri Gribenko }
8119e605113SDmitri Gribenko 
visitVerbatimLineComment(const VerbatimLineComment * C)8129e605113SDmitri Gribenko void CommentASTToXMLConverter::visitVerbatimLineComment(
8139e605113SDmitri Gribenko                                   const VerbatimLineComment *C) {
8149e605113SDmitri Gribenko   Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
8159e605113SDmitri Gribenko   appendToResultWithXMLEscaping(C->getText());
8169e605113SDmitri Gribenko   Result << "</Verbatim>";
8179e605113SDmitri Gribenko }
8189e605113SDmitri Gribenko 
visitFullComment(const FullComment * C)8199e605113SDmitri Gribenko void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
8209e605113SDmitri Gribenko   FullCommentParts Parts(C, Traits);
8219e605113SDmitri Gribenko 
8229e605113SDmitri Gribenko   const DeclInfo *DI = C->getDeclInfo();
8239e605113SDmitri Gribenko   StringRef RootEndTag;
8249e605113SDmitri Gribenko   if (DI) {
8259e605113SDmitri Gribenko     switch (DI->getKind()) {
8269e605113SDmitri Gribenko     case DeclInfo::OtherKind:
8279e605113SDmitri Gribenko       RootEndTag = "</Other>";
8289e605113SDmitri Gribenko       Result << "<Other";
8299e605113SDmitri Gribenko       break;
8309e605113SDmitri Gribenko     case DeclInfo::FunctionKind:
8319e605113SDmitri Gribenko       RootEndTag = "</Function>";
8329e605113SDmitri Gribenko       Result << "<Function";
8339e605113SDmitri Gribenko       switch (DI->TemplateKind) {
8349e605113SDmitri Gribenko       case DeclInfo::NotTemplate:
8359e605113SDmitri Gribenko         break;
8369e605113SDmitri Gribenko       case DeclInfo::Template:
8379e605113SDmitri Gribenko         Result << " templateKind=\"template\"";
8389e605113SDmitri Gribenko         break;
8399e605113SDmitri Gribenko       case DeclInfo::TemplateSpecialization:
8409e605113SDmitri Gribenko         Result << " templateKind=\"specialization\"";
8419e605113SDmitri Gribenko         break;
8429e605113SDmitri Gribenko       case DeclInfo::TemplatePartialSpecialization:
8439e605113SDmitri Gribenko         llvm_unreachable("partial specializations of functions "
8449e605113SDmitri Gribenko                          "are not allowed in C++");
8459e605113SDmitri Gribenko       }
8469e605113SDmitri Gribenko       if (DI->IsInstanceMethod)
8479e605113SDmitri Gribenko         Result << " isInstanceMethod=\"1\"";
8489e605113SDmitri Gribenko       if (DI->IsClassMethod)
8499e605113SDmitri Gribenko         Result << " isClassMethod=\"1\"";
8509e605113SDmitri Gribenko       break;
8519e605113SDmitri Gribenko     case DeclInfo::ClassKind:
8529e605113SDmitri Gribenko       RootEndTag = "</Class>";
8539e605113SDmitri Gribenko       Result << "<Class";
8549e605113SDmitri Gribenko       switch (DI->TemplateKind) {
8559e605113SDmitri Gribenko       case DeclInfo::NotTemplate:
8569e605113SDmitri Gribenko         break;
8579e605113SDmitri Gribenko       case DeclInfo::Template:
8589e605113SDmitri Gribenko         Result << " templateKind=\"template\"";
8599e605113SDmitri Gribenko         break;
8609e605113SDmitri Gribenko       case DeclInfo::TemplateSpecialization:
8619e605113SDmitri Gribenko         Result << " templateKind=\"specialization\"";
8629e605113SDmitri Gribenko         break;
8639e605113SDmitri Gribenko       case DeclInfo::TemplatePartialSpecialization:
8649e605113SDmitri Gribenko         Result << " templateKind=\"partialSpecialization\"";
8659e605113SDmitri Gribenko         break;
8669e605113SDmitri Gribenko       }
8679e605113SDmitri Gribenko       break;
8689e605113SDmitri Gribenko     case DeclInfo::VariableKind:
8699e605113SDmitri Gribenko       RootEndTag = "</Variable>";
8709e605113SDmitri Gribenko       Result << "<Variable";
8719e605113SDmitri Gribenko       break;
8729e605113SDmitri Gribenko     case DeclInfo::NamespaceKind:
8739e605113SDmitri Gribenko       RootEndTag = "</Namespace>";
8749e605113SDmitri Gribenko       Result << "<Namespace";
8759e605113SDmitri Gribenko       break;
8769e605113SDmitri Gribenko     case DeclInfo::TypedefKind:
8779e605113SDmitri Gribenko       RootEndTag = "</Typedef>";
8789e605113SDmitri Gribenko       Result << "<Typedef";
8799e605113SDmitri Gribenko       break;
8809e605113SDmitri Gribenko     case DeclInfo::EnumKind:
8819e605113SDmitri Gribenko       RootEndTag = "</Enum>";
8829e605113SDmitri Gribenko       Result << "<Enum";
8839e605113SDmitri Gribenko       break;
8849e605113SDmitri Gribenko     }
8859e605113SDmitri Gribenko 
8869e605113SDmitri Gribenko     {
8879e605113SDmitri Gribenko       // Print line and column number.
8889e605113SDmitri Gribenko       SourceLocation Loc = DI->CurrentDecl->getLocation();
8899e605113SDmitri Gribenko       std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
8909e605113SDmitri Gribenko       FileID FID = LocInfo.first;
8919e605113SDmitri Gribenko       unsigned FileOffset = LocInfo.second;
8929e605113SDmitri Gribenko 
8938b563665SYaron Keren       if (FID.isValid()) {
8949e605113SDmitri Gribenko         if (const FileEntry *FE = SM.getFileEntryForID(FID)) {
8959e605113SDmitri Gribenko           Result << " file=\"";
8969e605113SDmitri Gribenko           appendToResultWithXMLEscaping(FE->getName());
8979e605113SDmitri Gribenko           Result << "\"";
8989e605113SDmitri Gribenko         }
8999e605113SDmitri Gribenko         Result << " line=\"" << SM.getLineNumber(FID, FileOffset)
9009e605113SDmitri Gribenko                << "\" column=\"" << SM.getColumnNumber(FID, FileOffset)
9019e605113SDmitri Gribenko                << "\"";
9029e605113SDmitri Gribenko       }
9039e605113SDmitri Gribenko     }
9049e605113SDmitri Gribenko 
9059e605113SDmitri Gribenko     // Finish the root tag.
9069e605113SDmitri Gribenko     Result << ">";
9079e605113SDmitri Gribenko 
9089e605113SDmitri Gribenko     bool FoundName = false;
9099e605113SDmitri Gribenko     if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->CommentDecl)) {
9109e605113SDmitri Gribenko       if (DeclarationName DeclName = ND->getDeclName()) {
9119e605113SDmitri Gribenko         Result << "<Name>";
9129e605113SDmitri Gribenko         std::string Name = DeclName.getAsString();
9139e605113SDmitri Gribenko         appendToResultWithXMLEscaping(Name);
9149e605113SDmitri Gribenko         FoundName = true;
9159e605113SDmitri Gribenko         Result << "</Name>";
9169e605113SDmitri Gribenko       }
9179e605113SDmitri Gribenko     }
9189e605113SDmitri Gribenko     if (!FoundName)
9199e605113SDmitri Gribenko       Result << "<Name>&lt;anonymous&gt;</Name>";
9209e605113SDmitri Gribenko 
9219e605113SDmitri Gribenko     {
9229e605113SDmitri Gribenko       // Print USR.
9239e605113SDmitri Gribenko       SmallString<128> USR;
9249e605113SDmitri Gribenko       generateUSRForDecl(DI->CommentDecl, USR);
9259e605113SDmitri Gribenko       if (!USR.empty()) {
9269e605113SDmitri Gribenko         Result << "<USR>";
9279e605113SDmitri Gribenko         appendToResultWithXMLEscaping(USR);
9289e605113SDmitri Gribenko         Result << "</USR>";
9299e605113SDmitri Gribenko       }
9309e605113SDmitri Gribenko     }
9319e605113SDmitri Gribenko   } else {
9329e605113SDmitri Gribenko     // No DeclInfo -- just emit some root tag and name tag.
9339e605113SDmitri Gribenko     RootEndTag = "</Other>";
9349e605113SDmitri Gribenko     Result << "<Other><Name>unknown</Name>";
9359e605113SDmitri Gribenko   }
9369e605113SDmitri Gribenko 
9379e605113SDmitri Gribenko   if (Parts.Headerfile) {
9389e605113SDmitri Gribenko     Result << "<Headerfile>";
9399e605113SDmitri Gribenko     visit(Parts.Headerfile);
9409e605113SDmitri Gribenko     Result << "</Headerfile>";
9419e605113SDmitri Gribenko   }
9429e605113SDmitri Gribenko 
9439e605113SDmitri Gribenko   {
9449e605113SDmitri Gribenko     // Pretty-print the declaration.
9459e605113SDmitri Gribenko     Result << "<Declaration>";
9469e605113SDmitri Gribenko     SmallString<128> Declaration;
9479e605113SDmitri Gribenko     getSourceTextOfDeclaration(DI, Declaration);
9489e605113SDmitri Gribenko     formatTextOfDeclaration(DI, Declaration);
9499e605113SDmitri Gribenko     appendToResultWithXMLEscaping(Declaration);
9509e605113SDmitri Gribenko     Result << "</Declaration>";
9519e605113SDmitri Gribenko   }
9529e605113SDmitri Gribenko 
9539e605113SDmitri Gribenko   bool FirstParagraphIsBrief = false;
9549e605113SDmitri Gribenko   if (Parts.Brief) {
9559e605113SDmitri Gribenko     Result << "<Abstract>";
9569e605113SDmitri Gribenko     visit(Parts.Brief);
9579e605113SDmitri Gribenko     Result << "</Abstract>";
9589e605113SDmitri Gribenko   } else if (Parts.FirstParagraph) {
9599e605113SDmitri Gribenko     Result << "<Abstract>";
9609e605113SDmitri Gribenko     visit(Parts.FirstParagraph);
9619e605113SDmitri Gribenko     Result << "</Abstract>";
9629e605113SDmitri Gribenko     FirstParagraphIsBrief = true;
9639e605113SDmitri Gribenko   }
9649e605113SDmitri Gribenko 
9659e605113SDmitri Gribenko   if (Parts.TParams.size() != 0) {
9669e605113SDmitri Gribenko     Result << "<TemplateParameters>";
9679e605113SDmitri Gribenko     for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
9689e605113SDmitri Gribenko       visit(Parts.TParams[i]);
9699e605113SDmitri Gribenko     Result << "</TemplateParameters>";
9709e605113SDmitri Gribenko   }
9719e605113SDmitri Gribenko 
9729e605113SDmitri Gribenko   if (Parts.Params.size() != 0) {
9739e605113SDmitri Gribenko     Result << "<Parameters>";
9749e605113SDmitri Gribenko     for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
9759e605113SDmitri Gribenko       visit(Parts.Params[i]);
9769e605113SDmitri Gribenko     Result << "</Parameters>";
9779e605113SDmitri Gribenko   }
9789e605113SDmitri Gribenko 
9799e605113SDmitri Gribenko   if (Parts.Exceptions.size() != 0) {
9809e605113SDmitri Gribenko     Result << "<Exceptions>";
9819e605113SDmitri Gribenko     for (unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i)
9829e605113SDmitri Gribenko       visit(Parts.Exceptions[i]);
9839e605113SDmitri Gribenko     Result << "</Exceptions>";
9849e605113SDmitri Gribenko   }
9859e605113SDmitri Gribenko 
9869e605113SDmitri Gribenko   if (Parts.Returns.size() != 0) {
9879e605113SDmitri Gribenko     Result << "<ResultDiscussion>";
9889e605113SDmitri Gribenko     for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
9899e605113SDmitri Gribenko       visit(Parts.Returns[i]);
9909e605113SDmitri Gribenko     Result << "</ResultDiscussion>";
9919e605113SDmitri Gribenko   }
9929e605113SDmitri Gribenko 
9939e605113SDmitri Gribenko   if (DI->CommentDecl->hasAttrs()) {
9949e605113SDmitri Gribenko     const AttrVec &Attrs = DI->CommentDecl->getAttrs();
9959e605113SDmitri Gribenko     for (unsigned i = 0, e = Attrs.size(); i != e; i++) {
9969e605113SDmitri Gribenko       const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
9979e605113SDmitri Gribenko       if (!AA) {
9989e605113SDmitri Gribenko         if (const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
9999e605113SDmitri Gribenko           if (DA->getMessage().empty())
10009e605113SDmitri Gribenko             Result << "<Deprecated/>";
10019e605113SDmitri Gribenko           else {
10029e605113SDmitri Gribenko             Result << "<Deprecated>";
10039e605113SDmitri Gribenko             appendToResultWithXMLEscaping(DA->getMessage());
10049e605113SDmitri Gribenko             Result << "</Deprecated>";
10059e605113SDmitri Gribenko           }
10069e605113SDmitri Gribenko         }
10079e605113SDmitri Gribenko         else if (const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
10089e605113SDmitri Gribenko           if (UA->getMessage().empty())
10099e605113SDmitri Gribenko             Result << "<Unavailable/>";
10109e605113SDmitri Gribenko           else {
10119e605113SDmitri Gribenko             Result << "<Unavailable>";
10129e605113SDmitri Gribenko             appendToResultWithXMLEscaping(UA->getMessage());
10139e605113SDmitri Gribenko             Result << "</Unavailable>";
10149e605113SDmitri Gribenko           }
10159e605113SDmitri Gribenko         }
10169e605113SDmitri Gribenko         continue;
10179e605113SDmitri Gribenko       }
10189e605113SDmitri Gribenko 
10199e605113SDmitri Gribenko       // 'availability' attribute.
10209e605113SDmitri Gribenko       Result << "<Availability";
10219e605113SDmitri Gribenko       StringRef Distribution;
10229e605113SDmitri Gribenko       if (AA->getPlatform()) {
10239e605113SDmitri Gribenko         Distribution = AvailabilityAttr::getPrettyPlatformName(
10249e605113SDmitri Gribenko                                         AA->getPlatform()->getName());
10259e605113SDmitri Gribenko         if (Distribution.empty())
10269e605113SDmitri Gribenko           Distribution = AA->getPlatform()->getName();
10279e605113SDmitri Gribenko       }
10289e605113SDmitri Gribenko       Result << " distribution=\"" << Distribution << "\">";
10299e605113SDmitri Gribenko       VersionTuple IntroducedInVersion = AA->getIntroduced();
10309e605113SDmitri Gribenko       if (!IntroducedInVersion.empty()) {
10319e605113SDmitri Gribenko         Result << "<IntroducedInVersion>"
10329e605113SDmitri Gribenko                << IntroducedInVersion.getAsString()
10339e605113SDmitri Gribenko                << "</IntroducedInVersion>";
10349e605113SDmitri Gribenko       }
10359e605113SDmitri Gribenko       VersionTuple DeprecatedInVersion = AA->getDeprecated();
10369e605113SDmitri Gribenko       if (!DeprecatedInVersion.empty()) {
10379e605113SDmitri Gribenko         Result << "<DeprecatedInVersion>"
10389e605113SDmitri Gribenko                << DeprecatedInVersion.getAsString()
10399e605113SDmitri Gribenko                << "</DeprecatedInVersion>";
10409e605113SDmitri Gribenko       }
10419e605113SDmitri Gribenko       VersionTuple RemovedAfterVersion = AA->getObsoleted();
10429e605113SDmitri Gribenko       if (!RemovedAfterVersion.empty()) {
10439e605113SDmitri Gribenko         Result << "<RemovedAfterVersion>"
10449e605113SDmitri Gribenko                << RemovedAfterVersion.getAsString()
10459e605113SDmitri Gribenko                << "</RemovedAfterVersion>";
10469e605113SDmitri Gribenko       }
10479e605113SDmitri Gribenko       StringRef DeprecationSummary = AA->getMessage();
10489e605113SDmitri Gribenko       if (!DeprecationSummary.empty()) {
10499e605113SDmitri Gribenko         Result << "<DeprecationSummary>";
10509e605113SDmitri Gribenko         appendToResultWithXMLEscaping(DeprecationSummary);
10519e605113SDmitri Gribenko         Result << "</DeprecationSummary>";
10529e605113SDmitri Gribenko       }
10539e605113SDmitri Gribenko       if (AA->getUnavailable())
10549e605113SDmitri Gribenko         Result << "<Unavailable/>";
10559e605113SDmitri Gribenko       Result << "</Availability>";
10569e605113SDmitri Gribenko     }
10579e605113SDmitri Gribenko   }
10589e605113SDmitri Gribenko 
10599e605113SDmitri Gribenko   {
10609e605113SDmitri Gribenko     bool StartTagEmitted = false;
10619e605113SDmitri Gribenko     for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
10629e605113SDmitri Gribenko       const Comment *C = Parts.MiscBlocks[i];
10639e605113SDmitri Gribenko       if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
10649e605113SDmitri Gribenko         continue;
10659e605113SDmitri Gribenko       if (!StartTagEmitted) {
10669e605113SDmitri Gribenko         Result << "<Discussion>";
10679e605113SDmitri Gribenko         StartTagEmitted = true;
10689e605113SDmitri Gribenko       }
10699e605113SDmitri Gribenko       visit(C);
10709e605113SDmitri Gribenko     }
10719e605113SDmitri Gribenko     if (StartTagEmitted)
10729e605113SDmitri Gribenko       Result << "</Discussion>";
10739e605113SDmitri Gribenko   }
10749e605113SDmitri Gribenko 
10759e605113SDmitri Gribenko   Result << RootEndTag;
10769e605113SDmitri Gribenko }
10779e605113SDmitri Gribenko 
appendToResultWithXMLEscaping(StringRef S)10789e605113SDmitri Gribenko void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
10799e605113SDmitri Gribenko   for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
10809e605113SDmitri Gribenko     const char C = *I;
10819e605113SDmitri Gribenko     switch (C) {
10829e605113SDmitri Gribenko     case '&':
10839e605113SDmitri Gribenko       Result << "&amp;";
10849e605113SDmitri Gribenko       break;
10859e605113SDmitri Gribenko     case '<':
10869e605113SDmitri Gribenko       Result << "&lt;";
10879e605113SDmitri Gribenko       break;
10889e605113SDmitri Gribenko     case '>':
10899e605113SDmitri Gribenko       Result << "&gt;";
10909e605113SDmitri Gribenko       break;
10919e605113SDmitri Gribenko     case '"':
10929e605113SDmitri Gribenko       Result << "&quot;";
10939e605113SDmitri Gribenko       break;
10949e605113SDmitri Gribenko     case '\'':
10959e605113SDmitri Gribenko       Result << "&apos;";
10969e605113SDmitri Gribenko       break;
10979e605113SDmitri Gribenko     default:
10989e605113SDmitri Gribenko       Result << C;
10999e605113SDmitri Gribenko       break;
11009e605113SDmitri Gribenko     }
11019e605113SDmitri Gribenko   }
11029e605113SDmitri Gribenko }
11039e605113SDmitri Gribenko 
appendToResultWithCDATAEscaping(StringRef S)11046db07e2aSDmitri Gribenko void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) {
11056db07e2aSDmitri Gribenko   if (S.empty())
11066db07e2aSDmitri Gribenko     return;
11076db07e2aSDmitri Gribenko 
11086db07e2aSDmitri Gribenko   Result << "<![CDATA[";
11096db07e2aSDmitri Gribenko   while (!S.empty()) {
11106db07e2aSDmitri Gribenko     size_t Pos = S.find("]]>");
11116db07e2aSDmitri Gribenko     if (Pos == 0) {
11126db07e2aSDmitri Gribenko       Result << "]]]]><![CDATA[>";
11136db07e2aSDmitri Gribenko       S = S.drop_front(3);
11146db07e2aSDmitri Gribenko       continue;
11156db07e2aSDmitri Gribenko     }
11166db07e2aSDmitri Gribenko     if (Pos == StringRef::npos)
11176db07e2aSDmitri Gribenko       Pos = S.size();
11186db07e2aSDmitri Gribenko 
11196db07e2aSDmitri Gribenko     Result << S.substr(0, Pos);
11206db07e2aSDmitri Gribenko 
11216db07e2aSDmitri Gribenko     S = S.drop_front(Pos);
11226db07e2aSDmitri Gribenko   }
11236db07e2aSDmitri Gribenko   Result << "]]>";
11246db07e2aSDmitri Gribenko }
11256db07e2aSDmitri Gribenko 
CommentToXMLConverter()1126d21485d2SDaniel Jasper CommentToXMLConverter::CommentToXMLConverter() {}
~CommentToXMLConverter()1127637d1e66SAngel Garcia Gomez CommentToXMLConverter::~CommentToXMLConverter() {}
1128795f6a9dSNico Weber 
convertCommentToHTML(const FullComment * FC,SmallVectorImpl<char> & HTML,const ASTContext & Context)11299e605113SDmitri Gribenko void CommentToXMLConverter::convertCommentToHTML(const FullComment *FC,
11309e605113SDmitri Gribenko                                                  SmallVectorImpl<char> &HTML,
11319e605113SDmitri Gribenko                                                  const ASTContext &Context) {
11329e605113SDmitri Gribenko   CommentASTToHTMLConverter Converter(FC, HTML,
11339e605113SDmitri Gribenko                                       Context.getCommentCommandTraits());
11349e605113SDmitri Gribenko   Converter.visit(FC);
11359e605113SDmitri Gribenko }
11369e605113SDmitri Gribenko 
convertHTMLTagNodeToText(const comments::HTMLTagComment * HTC,SmallVectorImpl<char> & Text,const ASTContext & Context)11379e605113SDmitri Gribenko void CommentToXMLConverter::convertHTMLTagNodeToText(
11389e605113SDmitri Gribenko     const comments::HTMLTagComment *HTC, SmallVectorImpl<char> &Text,
11399e605113SDmitri Gribenko     const ASTContext &Context) {
1140236bde3dSCraig Topper   CommentASTToHTMLConverter Converter(nullptr, Text,
11419e605113SDmitri Gribenko                                       Context.getCommentCommandTraits());
11429e605113SDmitri Gribenko   Converter.visit(HTC);
11439e605113SDmitri Gribenko }
11449e605113SDmitri Gribenko 
convertCommentToXML(const FullComment * FC,SmallVectorImpl<char> & XML,const ASTContext & Context)11459e605113SDmitri Gribenko void CommentToXMLConverter::convertCommentToXML(const FullComment *FC,
11469e605113SDmitri Gribenko                                                 SmallVectorImpl<char> &XML,
11479e605113SDmitri Gribenko                                                 const ASTContext &Context) {
11489e605113SDmitri Gribenko   CommentASTToXMLConverter Converter(FC, XML, Context.getCommentCommandTraits(),
1149d21485d2SDaniel Jasper                                      Context.getSourceManager());
11509e605113SDmitri Gribenko   Converter.visit(FC);
11519e605113SDmitri Gribenko }
1152