xref: /freebsd-src/contrib/llvm-project/clang/lib/Index/CommentToXML.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 << "&amp;";
5050b57cec5SDimitry Andric       break;
5060b57cec5SDimitry Andric     case '<':
5070b57cec5SDimitry Andric       Result << "&lt;";
5080b57cec5SDimitry Andric       break;
5090b57cec5SDimitry Andric     case '>':
5100b57cec5SDimitry Andric       Result << "&gt;";
5110b57cec5SDimitry Andric       break;
5120b57cec5SDimitry Andric     case '"':
5130b57cec5SDimitry Andric       Result << "&quot;";
5140b57cec5SDimitry Andric       break;
5150b57cec5SDimitry Andric     case '\'':
5160b57cec5SDimitry Andric       Result << "&#39;";
5170b57cec5SDimitry Andric       break;
5180b57cec5SDimitry Andric     case '/':
5190b57cec5SDimitry Andric       Result << "&#47;";
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 << ">&lt;/" << C->getTagName() << "&gt;</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>&lt;anonymous&gt;</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 << "&amp;";
11020b57cec5SDimitry Andric       break;
11030b57cec5SDimitry Andric     case '<':
11040b57cec5SDimitry Andric       Result << "&lt;";
11050b57cec5SDimitry Andric       break;
11060b57cec5SDimitry Andric     case '>':
11070b57cec5SDimitry Andric       Result << "&gt;";
11080b57cec5SDimitry Andric       break;
11090b57cec5SDimitry Andric     case '"':
11100b57cec5SDimitry Andric       Result << "&quot;";
11110b57cec5SDimitry Andric       break;
11120b57cec5SDimitry Andric     case '\'':
11130b57cec5SDimitry Andric       Result << "&apos;";
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