186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko//===--- CommentToXML.cpp - Convert comments to XML representation --------===//
286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko//
386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko//                     The LLVM Compiler Infrastructure
486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko//
586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko// This file is distributed under the University of Illinois Open Source
686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko// License. See LICENSE.TXT for details.
786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko//
886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko//===----------------------------------------------------------------------===//
986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
1086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko#include "clang/Index/CommentToXML.h"
1186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko#include "SimpleFormatContext.h"
1286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko#include "clang/AST/ASTContext.h"
13651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "clang/AST/Attr.h"
1486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko#include "clang/AST/Comment.h"
1586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko#include "clang/AST/CommentVisitor.h"
1686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko#include "clang/Format/Format.h"
1786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko#include "clang/Index/USRGeneration.h"
1886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko#include "clang/Lex/Lexer.h"
1986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko#include "llvm/ADT/StringExtras.h"
2086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko#include "llvm/ADT/TinyPtrVector.h"
2186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko#include "llvm/Support/raw_ostream.h"
2286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
2386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkousing namespace clang;
2486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkousing namespace clang::comments;
2586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkousing namespace clang::index;
2686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
2786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkonamespace {
2886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
2986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko/// This comparison will sort parameters with valid index by index, then vararg
3086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko/// parameters, and invalid (unresolved) parameters last.
3186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkoclass ParamCommandCommentCompareIndex {
3286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkopublic:
3386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  bool operator()(const ParamCommandComment *LHS,
3486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                  const ParamCommandComment *RHS) const {
3586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    unsigned LHSIndex = UINT_MAX;
3686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    unsigned RHSIndex = UINT_MAX;
3786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
3886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (LHS->isParamIndexValid()) {
3986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (LHS->isVarArgParam())
4086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        LHSIndex = UINT_MAX - 1;
4186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      else
4286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        LHSIndex = LHS->getParamIndex();
4386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    }
4486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (RHS->isParamIndexValid()) {
4586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (RHS->isVarArgParam())
4686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        RHSIndex = UINT_MAX - 1;
4786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      else
4886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        RHSIndex = RHS->getParamIndex();
4986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    }
5086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return LHSIndex < RHSIndex;
5186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
5286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko};
5386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
5486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko/// This comparison will sort template parameters in the following order:
5586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko/// \li real template parameters (depth = 1) in index order;
5686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko/// \li all other names (depth > 1);
5786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko/// \li unresolved names.
5886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkoclass TParamCommandCommentComparePosition {
5986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkopublic:
6086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  bool operator()(const TParamCommandComment *LHS,
6186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                  const TParamCommandComment *RHS) const {
6286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    // Sort unresolved names last.
6386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (!LHS->isPositionValid())
6486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      return false;
6586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (!RHS->isPositionValid())
6686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      return true;
6786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
6886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (LHS->getDepth() > 1)
6986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      return false;
7086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (RHS->getDepth() > 1)
7186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      return true;
7286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
7386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    // Sort template parameters in index order.
7486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (LHS->getDepth() == 1 && RHS->getDepth() == 1)
7586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      return LHS->getIndex(0) < RHS->getIndex(0);
7686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
7786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    // Leave all other names in source order.
7886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return true;
7986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
8086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko};
8186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
8286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko/// Separate parts of a FullComment.
8386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkostruct FullCommentParts {
8486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  /// Take a full comment apart and initialize members accordingly.
8586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  FullCommentParts(const FullComment *C,
8686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                   const CommandTraits &Traits);
8786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
8886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  const BlockContentComment *Brief;
8986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  const BlockContentComment *Headerfile;
9086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  const ParagraphComment *FirstParagraph;
9186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  SmallVector<const BlockCommandComment *, 4> Returns;
9286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  SmallVector<const ParamCommandComment *, 8> Params;
9386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  SmallVector<const TParamCommandComment *, 4> TParams;
9486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  llvm::TinyPtrVector<const BlockCommandComment *> Exceptions;
9586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  SmallVector<const BlockContentComment *, 8> MiscBlocks;
9686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko};
9786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
9886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri GribenkoFullCommentParts::FullCommentParts(const FullComment *C,
9986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                   const CommandTraits &Traits) :
1006bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    Brief(nullptr), Headerfile(nullptr), FirstParagraph(nullptr) {
10186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
10286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko       I != E; ++I) {
10386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    const Comment *Child = *I;
10486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (!Child)
10586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      continue;
10686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    switch (Child->getCommentKind()) {
10786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case Comment::NoCommentKind:
10886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      continue;
10986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
11086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case Comment::ParagraphCommentKind: {
11186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      const ParagraphComment *PC = cast<ParagraphComment>(Child);
11286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (PC->isWhitespace())
11386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        break;
11486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (!FirstParagraph)
11586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        FirstParagraph = PC;
11686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
11786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      MiscBlocks.push_back(PC);
11886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
11986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    }
12086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
12186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case Comment::BlockCommandCommentKind: {
12286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      const BlockCommandComment *BCC = cast<BlockCommandComment>(Child);
12386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      const CommandInfo *Info = Traits.getCommandInfo(BCC->getCommandID());
12486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (!Brief && Info->IsBriefCommand) {
12586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Brief = BCC;
12686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        break;
12786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      }
12886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (!Headerfile && Info->IsHeaderfileCommand) {
12986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Headerfile = BCC;
13086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        break;
13186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      }
13286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (Info->IsReturnsCommand) {
13386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Returns.push_back(BCC);
13486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        break;
13586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      }
13686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (Info->IsThrowsCommand) {
13786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Exceptions.push_back(BCC);
13886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        break;
13986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      }
14086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      MiscBlocks.push_back(BCC);
14186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
14286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    }
14386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
14486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case Comment::ParamCommandCommentKind: {
14586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      const ParamCommandComment *PCC = cast<ParamCommandComment>(Child);
14686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (!PCC->hasParamName())
14786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        break;
14886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
14986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (!PCC->isDirectionExplicit() && !PCC->hasNonWhitespaceParagraph())
15086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        break;
15186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
15286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Params.push_back(PCC);
15386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
15486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    }
15586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
15686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case Comment::TParamCommandCommentKind: {
15786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      const TParamCommandComment *TPCC = cast<TParamCommandComment>(Child);
15886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (!TPCC->hasParamName())
15986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        break;
16086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
16186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (!TPCC->hasNonWhitespaceParagraph())
16286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        break;
16386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
16486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      TParams.push_back(TPCC);
16586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
16686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    }
16786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
16886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case Comment::VerbatimBlockCommentKind:
16986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      MiscBlocks.push_back(cast<BlockCommandComment>(Child));
17086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
17186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
17286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case Comment::VerbatimLineCommentKind: {
17386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      const VerbatimLineComment *VLC = cast<VerbatimLineComment>(Child);
17486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      const CommandInfo *Info = Traits.getCommandInfo(VLC->getCommandID());
17586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (!Info->IsDeclarationCommand)
17686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        MiscBlocks.push_back(VLC);
17786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
17886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    }
17986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
18086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case Comment::TextCommentKind:
18186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case Comment::InlineCommandCommentKind:
18286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case Comment::HTMLStartTagCommentKind:
18386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case Comment::HTMLEndTagCommentKind:
18486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case Comment::VerbatimBlockLineCommentKind:
18586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case Comment::FullCommentKind:
18686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      llvm_unreachable("AST node of this kind can't be a child of "
18786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                       "a FullComment");
18886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    }
18986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
19086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
19186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // Sort params in order they are declared in the function prototype.
19286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // Unresolved parameters are put at the end of the list in the same order
19386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // they were seen in the comment.
19486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  std::stable_sort(Params.begin(), Params.end(),
19586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                   ParamCommandCommentCompareIndex());
19686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
19786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  std::stable_sort(TParams.begin(), TParams.end(),
19886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                   TParamCommandCommentComparePosition());
19986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
20086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
20186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid printHTMLStartTagComment(const HTMLStartTagComment *C,
20286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                              llvm::raw_svector_ostream &Result) {
20386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "<" << C->getTagName();
20486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
20586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (C->getNumAttrs() != 0) {
20686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    for (unsigned i = 0, e = C->getNumAttrs(); i != e; i++) {
20786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << " ";
20886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
20986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << Attr.Name;
21086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (!Attr.Value.empty())
21186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Result << "=\"" << Attr.Value << "\"";
21286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    }
21386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
21486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
21586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (!C->isSelfClosing())
21686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << ">";
21786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  else
21886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "/>";
21986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
22086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
22186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkoclass CommentASTToHTMLConverter :
22286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    public ConstCommentVisitor<CommentASTToHTMLConverter> {
22386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkopublic:
22486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  /// \param Str accumulator for HTML.
22586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  CommentASTToHTMLConverter(const FullComment *FC,
22686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                            SmallVectorImpl<char> &Str,
22786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                            const CommandTraits &Traits) :
22886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      FC(FC), Result(Str), Traits(Traits)
22986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  { }
23086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
23186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // Inline content.
23286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitTextComment(const TextComment *C);
23386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitInlineCommandComment(const InlineCommandComment *C);
23486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitHTMLStartTagComment(const HTMLStartTagComment *C);
23586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitHTMLEndTagComment(const HTMLEndTagComment *C);
23686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
23786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // Block content.
23886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitParagraphComment(const ParagraphComment *C);
23986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitBlockCommandComment(const BlockCommandComment *C);
24086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitParamCommandComment(const ParamCommandComment *C);
24186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitTParamCommandComment(const TParamCommandComment *C);
24286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitVerbatimBlockComment(const VerbatimBlockComment *C);
24386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
24486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitVerbatimLineComment(const VerbatimLineComment *C);
24586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
24686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitFullComment(const FullComment *C);
24786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
24886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // Helpers.
24986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
25086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  /// Convert a paragraph that is not a block by itself (an argument to some
25186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  /// command).
25286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitNonStandaloneParagraphComment(const ParagraphComment *C);
25386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
25486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void appendToResultWithHTMLEscaping(StringRef S);
25586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
25686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkoprivate:
25786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  const FullComment *FC;
25886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  /// Output stream for HTML.
25986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  llvm::raw_svector_ostream Result;
26086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
26186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  const CommandTraits &Traits;
26286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko};
26386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko} // end unnamed namespace
26486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
26586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToHTMLConverter::visitTextComment(const TextComment *C) {
26686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  appendToResultWithHTMLEscaping(C->getText());
26786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
26886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
26986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToHTMLConverter::visitInlineCommandComment(
27086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                  const InlineCommandComment *C) {
27186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // Nothing to render if no arguments supplied.
27286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (C->getNumArgs() == 0)
27386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
27486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
27586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // Nothing to render if argument is empty.
27686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  StringRef Arg0 = C->getArgText(0);
27786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (Arg0.empty())
27886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
27986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
28086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  switch (C->getRenderKind()) {
28186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case InlineCommandComment::RenderNormal:
28286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
28386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      appendToResultWithHTMLEscaping(C->getArgText(i));
28486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << " ";
28586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    }
28686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
28786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
28886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case InlineCommandComment::RenderBold:
28986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    assert(C->getNumArgs() == 1);
29086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<b>";
29186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    appendToResultWithHTMLEscaping(Arg0);
29286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</b>";
29386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
29486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case InlineCommandComment::RenderMonospaced:
29586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    assert(C->getNumArgs() == 1);
29686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<tt>";
29786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    appendToResultWithHTMLEscaping(Arg0);
29886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result<< "</tt>";
29986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
30086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case InlineCommandComment::RenderEmphasized:
30186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    assert(C->getNumArgs() == 1);
30286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<em>";
30386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    appendToResultWithHTMLEscaping(Arg0);
30486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</em>";
30586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
30686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
30786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
30886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
30986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToHTMLConverter::visitHTMLStartTagComment(
31086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                  const HTMLStartTagComment *C) {
31186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  printHTMLStartTagComment(C, Result);
31286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
31386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
31486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToHTMLConverter::visitHTMLEndTagComment(
31586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                  const HTMLEndTagComment *C) {
31686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "</" << C->getTagName() << ">";
31786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
31886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
31986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToHTMLConverter::visitParagraphComment(
32086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                  const ParagraphComment *C) {
32186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (C->isWhitespace())
32286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
32386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
32486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "<p>";
32586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
32686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko       I != E; ++I) {
32786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    visit(*I);
32886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
32986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "</p>";
33086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
33186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
33286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToHTMLConverter::visitBlockCommandComment(
33386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                  const BlockCommandComment *C) {
33486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  const CommandInfo *Info = Traits.getCommandInfo(C->getCommandID());
33586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (Info->IsBriefCommand) {
33686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<p class=\"para-brief\">";
33786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    visitNonStandaloneParagraphComment(C->getParagraph());
33886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</p>";
33986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
34086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
34186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (Info->IsReturnsCommand) {
34286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<p class=\"para-returns\">"
34386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko              "<span class=\"word-returns\">Returns</span> ";
34486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    visitNonStandaloneParagraphComment(C->getParagraph());
34586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</p>";
34686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
34786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
34886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // We don't know anything about this command.  Just render the paragraph.
34986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  visit(C->getParagraph());
35086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
35186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
35286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToHTMLConverter::visitParamCommandComment(
35386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                  const ParamCommandComment *C) {
35486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (C->isParamIndexValid()) {
35586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (C->isVarArgParam()) {
35686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<dt class=\"param-name-index-vararg\">";
35786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
35886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    } else {
35986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<dt class=\"param-name-index-"
36086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko             << C->getParamIndex()
36186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko             << "\">";
36286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      appendToResultWithHTMLEscaping(C->getParamName(FC));
36386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    }
36486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  } else {
36586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<dt class=\"param-name-index-invalid\">";
36686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
36786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
36886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "</dt>";
36986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
37086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (C->isParamIndexValid()) {
37186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (C->isVarArgParam())
37286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<dd class=\"param-descr-index-vararg\">";
37386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    else
37486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<dd class=\"param-descr-index-"
37586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko             << C->getParamIndex()
37686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko             << "\">";
37786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  } else
37886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<dd class=\"param-descr-index-invalid\">";
37986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
38086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  visitNonStandaloneParagraphComment(C->getParagraph());
38186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "</dd>";
38286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
38386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
38486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToHTMLConverter::visitTParamCommandComment(
38586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                  const TParamCommandComment *C) {
38686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (C->isPositionValid()) {
38786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (C->getDepth() == 1)
38886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<dt class=\"tparam-name-index-"
38986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko             << C->getIndex(0)
39086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko             << "\">";
39186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    else
39286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<dt class=\"tparam-name-index-other\">";
39386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    appendToResultWithHTMLEscaping(C->getParamName(FC));
39486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  } else {
39586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<dt class=\"tparam-name-index-invalid\">";
39686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
39786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
39886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
39986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "</dt>";
40086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
40186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (C->isPositionValid()) {
40286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (C->getDepth() == 1)
40386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<dd class=\"tparam-descr-index-"
40486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko             << C->getIndex(0)
40586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko             << "\">";
40686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    else
40786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<dd class=\"tparam-descr-index-other\">";
40886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  } else
40986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<dd class=\"tparam-descr-index-invalid\">";
41086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
41186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  visitNonStandaloneParagraphComment(C->getParagraph());
41286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "</dd>";
41386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
41486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
41586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToHTMLConverter::visitVerbatimBlockComment(
41686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                  const VerbatimBlockComment *C) {
41786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  unsigned NumLines = C->getNumLines();
41886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (NumLines == 0)
41986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
42086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
42186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "<pre>";
42286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  for (unsigned i = 0; i != NumLines; ++i) {
42386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    appendToResultWithHTMLEscaping(C->getText(i));
42486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (i + 1 != NumLines)
42586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << '\n';
42686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
42786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "</pre>";
42886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
42986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
43086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
43186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                  const VerbatimBlockLineComment *C) {
43286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  llvm_unreachable("should not see this AST node");
43386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
43486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
43586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToHTMLConverter::visitVerbatimLineComment(
43686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                  const VerbatimLineComment *C) {
43786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "<pre>";
43886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  appendToResultWithHTMLEscaping(C->getText());
43986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "</pre>";
44086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
44186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
44286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
44386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  FullCommentParts Parts(C, Traits);
44486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
44586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  bool FirstParagraphIsBrief = false;
44686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (Parts.Headerfile)
44786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    visit(Parts.Headerfile);
44886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (Parts.Brief)
44986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    visit(Parts.Brief);
45086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  else if (Parts.FirstParagraph) {
45186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<p class=\"para-brief\">";
45286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    visitNonStandaloneParagraphComment(Parts.FirstParagraph);
45386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</p>";
45486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    FirstParagraphIsBrief = true;
45586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
45686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
45786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
45886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    const Comment *C = Parts.MiscBlocks[i];
45986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
46086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      continue;
46186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    visit(C);
46286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
46386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
46486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (Parts.TParams.size() != 0) {
46586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<dl>";
46686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
46786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      visit(Parts.TParams[i]);
46886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</dl>";
46986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
47086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
47186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (Parts.Params.size() != 0) {
47286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<dl>";
47386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
47486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      visit(Parts.Params[i]);
47586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</dl>";
47686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
47786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
47886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (Parts.Returns.size() != 0) {
47986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<div class=\"result-discussion\">";
48086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
48186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      visit(Parts.Returns[i]);
48286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</div>";
48386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
48486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
48586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result.flush();
48686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
48786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
48886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
48986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                  const ParagraphComment *C) {
49086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (!C)
49186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
49286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
49386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
49486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko       I != E; ++I) {
49586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    visit(*I);
49686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
49786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
49886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
49986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) {
50086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
50186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    const char C = *I;
50286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    switch (C) {
50386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case '&':
50486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "&amp;";
50586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
50686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case '<':
50786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "&lt;";
50886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
50986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case '>':
51086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "&gt;";
51186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
51286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case '"':
51386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "&quot;";
51486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
51586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case '\'':
51686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "&#39;";
51786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
51886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case '/':
51986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "&#47;";
52086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
52186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    default:
52286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << C;
52386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
52486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    }
52586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
52686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
52786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
52886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkonamespace {
52986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkoclass CommentASTToXMLConverter :
53086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    public ConstCommentVisitor<CommentASTToXMLConverter> {
53186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkopublic:
53286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  /// \param Str accumulator for XML.
53386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  CommentASTToXMLConverter(const FullComment *FC,
53486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                           SmallVectorImpl<char> &Str,
53586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                           const CommandTraits &Traits,
53686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                           const SourceManager &SM,
53786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                           SimpleFormatContext &SFC,
53886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                           unsigned FUID) :
53986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      FC(FC), Result(Str), Traits(Traits), SM(SM),
54086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      FormatRewriterContext(SFC),
54186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      FormatInMemoryUniqueId(FUID) { }
54286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
54386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // Inline content.
54486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitTextComment(const TextComment *C);
54586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitInlineCommandComment(const InlineCommandComment *C);
54686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitHTMLStartTagComment(const HTMLStartTagComment *C);
54786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitHTMLEndTagComment(const HTMLEndTagComment *C);
54886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
54986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // Block content.
55086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitParagraphComment(const ParagraphComment *C);
55186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
55286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void appendParagraphCommentWithKind(const ParagraphComment *C,
55386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                      StringRef Kind);
55486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
55586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitBlockCommandComment(const BlockCommandComment *C);
55686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitParamCommandComment(const ParamCommandComment *C);
55786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitTParamCommandComment(const TParamCommandComment *C);
55886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitVerbatimBlockComment(const VerbatimBlockComment *C);
55986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
56086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitVerbatimLineComment(const VerbatimLineComment *C);
56186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
56286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void visitFullComment(const FullComment *C);
56386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
56486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // Helpers.
56586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void appendToResultWithXMLEscaping(StringRef S);
5666bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  void appendToResultWithCDATAEscaping(StringRef S);
56786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
56886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  void formatTextOfDeclaration(const DeclInfo *DI,
56986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                               SmallString<128> &Declaration);
57086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
57186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkoprivate:
57286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  const FullComment *FC;
57386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
57486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  /// Output stream for XML.
57586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  llvm::raw_svector_ostream Result;
57686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
57786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  const CommandTraits &Traits;
57886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  const SourceManager &SM;
57986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  SimpleFormatContext &FormatRewriterContext;
58086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  unsigned FormatInMemoryUniqueId;
58186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko};
58286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
58386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid getSourceTextOfDeclaration(const DeclInfo *ThisDecl,
58486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                SmallVectorImpl<char> &Str) {
58586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  ASTContext &Context = ThisDecl->CurrentDecl->getASTContext();
58686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  const LangOptions &LangOpts = Context.getLangOpts();
58786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  llvm::raw_svector_ostream OS(Str);
58886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  PrintingPolicy PPolicy(LangOpts);
58986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  PPolicy.PolishForDeclaration = true;
59086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  PPolicy.TerseOutput = true;
59186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  ThisDecl->CurrentDecl->print(OS, PPolicy,
59286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                               /*Indentation*/0, /*PrintInstantiation*/false);
59386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
59486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
59586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToXMLConverter::formatTextOfDeclaration(
59686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    const DeclInfo *DI, SmallString<128> &Declaration) {
59786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // FIXME. formatting API expects null terminated input string.
59886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // There might be more efficient way of doing this.
59986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  std::string StringDecl = Declaration.str();
60086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
60186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // Formatter specific code.
60286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // Form a unique in memory buffer name.
60386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  SmallString<128> filename;
60486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  filename += "xmldecl";
60586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  filename += llvm::utostr(FormatInMemoryUniqueId);
60686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  filename += ".xd";
60786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  FileID ID = FormatRewriterContext.createInMemoryFile(filename, StringDecl);
60886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  SourceLocation Start = FormatRewriterContext.Sources.getLocForStartOfFile(ID)
60986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      .getLocWithOffset(0);
61086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  unsigned Length = Declaration.size();
61186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
61286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  std::vector<CharSourceRange> Ranges(
61386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      1, CharSourceRange::getCharRange(Start, Start.getLocWithOffset(Length)));
61486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  ASTContext &Context = DI->CurrentDecl->getASTContext();
61586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  const LangOptions &LangOpts = Context.getLangOpts();
61686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Lexer Lex(ID, FormatRewriterContext.Sources.getBuffer(ID),
61786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko            FormatRewriterContext.Sources, LangOpts);
61886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  tooling::Replacements Replace = reformat(
61986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      format::getLLVMStyle(), Lex, FormatRewriterContext.Sources, Ranges);
62086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  applyAllReplacements(Replace, FormatRewriterContext.Rewrite);
62186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Declaration = FormatRewriterContext.getRewrittenText(ID);
62286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
62386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
62486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko} // end unnamed namespace
62586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
62686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToXMLConverter::visitTextComment(const TextComment *C) {
62786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  appendToResultWithXMLEscaping(C->getText());
62886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
62986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
63086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToXMLConverter::visitInlineCommandComment(
63186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    const InlineCommandComment *C) {
63286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // Nothing to render if no arguments supplied.
63386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (C->getNumArgs() == 0)
63486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
63586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
63686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  // Nothing to render if argument is empty.
63786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  StringRef Arg0 = C->getArgText(0);
63886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (Arg0.empty())
63986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
64086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
64186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  switch (C->getRenderKind()) {
64286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case InlineCommandComment::RenderNormal:
64386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
64486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      appendToResultWithXMLEscaping(C->getArgText(i));
64586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << " ";
64686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    }
64786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
64886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case InlineCommandComment::RenderBold:
64986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    assert(C->getNumArgs() == 1);
65086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<bold>";
65186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    appendToResultWithXMLEscaping(Arg0);
65286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</bold>";
65386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
65486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case InlineCommandComment::RenderMonospaced:
65586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    assert(C->getNumArgs() == 1);
65686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<monospaced>";
65786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    appendToResultWithXMLEscaping(Arg0);
65886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</monospaced>";
65986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
66086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case InlineCommandComment::RenderEmphasized:
66186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    assert(C->getNumArgs() == 1);
66286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<emphasized>";
66386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    appendToResultWithXMLEscaping(Arg0);
66486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</emphasized>";
66586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
66686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
66786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
66886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
66986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToXMLConverter::visitHTMLStartTagComment(
67086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    const HTMLStartTagComment *C) {
6716bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  Result << "<rawHTML";
6726bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  if (C->isMalformed())
6736bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    Result << " isMalformed=\"1\"";
6746bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  Result << ">";
6756bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  {
6766bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    SmallString<32> Tag;
6776bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    {
6786bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      llvm::raw_svector_ostream TagOS(Tag);
6796bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines      printHTMLStartTagComment(C, TagOS);
6806bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    }
6816bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    appendToResultWithCDATAEscaping(Tag);
6826bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  }
6836bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  Result << "</rawHTML>";
68486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
68586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
68686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid
68786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri GribenkoCommentASTToXMLConverter::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
6886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  Result << "<rawHTML";
6896bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  if (C->isMalformed())
6906bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    Result << " isMalformed=\"1\"";
6916bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines  Result << ">&lt;/" << C->getTagName() << "&gt;</rawHTML>";
69286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
69386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
69486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid
69586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri GribenkoCommentASTToXMLConverter::visitParagraphComment(const ParagraphComment *C) {
69686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  appendParagraphCommentWithKind(C, StringRef());
69786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
69886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
69986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToXMLConverter::appendParagraphCommentWithKind(
70086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                  const ParagraphComment *C,
70186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                  StringRef ParagraphKind) {
70286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (C->isWhitespace())
70386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
70486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
70586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (ParagraphKind.empty())
70686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<Para>";
70786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  else
70886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<Para kind=\"" << ParagraphKind << "\">";
70986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
71086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
71186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko       I != E; ++I) {
71286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    visit(*I);
71386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
71486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "</Para>";
71586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
71686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
71786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToXMLConverter::visitBlockCommandComment(
71886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    const BlockCommandComment *C) {
71986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  StringRef ParagraphKind;
72086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
72186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  switch (C->getCommandID()) {
72286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_attention:
72386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_author:
72486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_authors:
72586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_bug:
72686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_copyright:
72786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_date:
72886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_invariant:
72986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_note:
73086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_post:
73186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_pre:
73286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_remark:
73386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_remarks:
73486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_sa:
73586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_see:
73686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_since:
73786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_todo:
73886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_version:
73986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_warning:
74086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    ParagraphKind = C->getCommandName(Traits);
74186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  default:
74286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    break;
74386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
74486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
74586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  appendParagraphCommentWithKind(C->getParagraph(), ParagraphKind);
74686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
74786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
74886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToXMLConverter::visitParamCommandComment(
74986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    const ParamCommandComment *C) {
75086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "<Parameter><Name>";
75186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  appendToResultWithXMLEscaping(C->isParamIndexValid()
75286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                    ? C->getParamName(FC)
75386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                    : C->getParamNameAsWritten());
75486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "</Name>";
75586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
75686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (C->isParamIndexValid()) {
75786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (C->isVarArgParam())
75886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<IsVarArg />";
75986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    else
76086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<Index>" << C->getParamIndex() << "</Index>";
76186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
76286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
76386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "<Direction isExplicit=\"" << C->isDirectionExplicit() << "\">";
76486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  switch (C->getDirection()) {
76586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case ParamCommandComment::In:
76686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "in";
76786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    break;
76886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case ParamCommandComment::Out:
76986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "out";
77086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    break;
77186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case ParamCommandComment::InOut:
77286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "in,out";
77386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    break;
77486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
77586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "</Direction><Discussion>";
77686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  visit(C->getParagraph());
77786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "</Discussion></Parameter>";
77886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
77986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
78086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToXMLConverter::visitTParamCommandComment(
78186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                  const TParamCommandComment *C) {
78286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "<Parameter><Name>";
78386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  appendToResultWithXMLEscaping(C->isPositionValid() ? C->getParamName(FC)
78486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                : C->getParamNameAsWritten());
78586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "</Name>";
78686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
78786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (C->isPositionValid() && C->getDepth() == 1) {
78886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<Index>" << C->getIndex(0) << "</Index>";
78986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
79086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
79186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "<Discussion>";
79286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  visit(C->getParagraph());
79386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "</Discussion></Parameter>";
79486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
79586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
79686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToXMLConverter::visitVerbatimBlockComment(
79786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                  const VerbatimBlockComment *C) {
79886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  unsigned NumLines = C->getNumLines();
79986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (NumLines == 0)
80086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    return;
80186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
80286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  switch (C->getCommandID()) {
80386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  case CommandTraits::KCI_code:
80486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<Verbatim xml:space=\"preserve\" kind=\"code\">";
80586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    break;
80686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  default:
80786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
80886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    break;
80986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
81086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  for (unsigned i = 0; i != NumLines; ++i) {
81186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    appendToResultWithXMLEscaping(C->getText(i));
81286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (i + 1 != NumLines)
81386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << '\n';
81486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
81586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "</Verbatim>";
81686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
81786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
81886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToXMLConverter::visitVerbatimBlockLineComment(
81986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                  const VerbatimBlockLineComment *C) {
82086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  llvm_unreachable("should not see this AST node");
82186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
82286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
82386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToXMLConverter::visitVerbatimLineComment(
82486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                  const VerbatimLineComment *C) {
82586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
82686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  appendToResultWithXMLEscaping(C->getText());
82786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  Result << "</Verbatim>";
82886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko}
82986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
83086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenkovoid CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
83186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  FullCommentParts Parts(C, Traits);
83286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
83386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  const DeclInfo *DI = C->getDeclInfo();
83486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  StringRef RootEndTag;
83586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (DI) {
83686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    switch (DI->getKind()) {
83786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case DeclInfo::OtherKind:
83886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      RootEndTag = "</Other>";
83986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<Other";
84086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
84186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case DeclInfo::FunctionKind:
84286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      RootEndTag = "</Function>";
84386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<Function";
84486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      switch (DI->TemplateKind) {
84586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      case DeclInfo::NotTemplate:
84686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        break;
84786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      case DeclInfo::Template:
84886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Result << " templateKind=\"template\"";
84986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        break;
85086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      case DeclInfo::TemplateSpecialization:
85186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Result << " templateKind=\"specialization\"";
85286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        break;
85386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      case DeclInfo::TemplatePartialSpecialization:
85486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        llvm_unreachable("partial specializations of functions "
85586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                         "are not allowed in C++");
85686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      }
85786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (DI->IsInstanceMethod)
85886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Result << " isInstanceMethod=\"1\"";
85986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (DI->IsClassMethod)
86086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Result << " isClassMethod=\"1\"";
86186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
86286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case DeclInfo::ClassKind:
86386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      RootEndTag = "</Class>";
86486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<Class";
86586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      switch (DI->TemplateKind) {
86686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      case DeclInfo::NotTemplate:
86786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        break;
86886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      case DeclInfo::Template:
86986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Result << " templateKind=\"template\"";
87086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        break;
87186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      case DeclInfo::TemplateSpecialization:
87286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Result << " templateKind=\"specialization\"";
87386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        break;
87486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      case DeclInfo::TemplatePartialSpecialization:
87586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Result << " templateKind=\"partialSpecialization\"";
87686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        break;
87786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      }
87886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
87986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case DeclInfo::VariableKind:
88086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      RootEndTag = "</Variable>";
88186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<Variable";
88286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
88386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case DeclInfo::NamespaceKind:
88486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      RootEndTag = "</Namespace>";
88586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<Namespace";
88686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
88786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case DeclInfo::TypedefKind:
88886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      RootEndTag = "</Typedef>";
88986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<Typedef";
89086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
89186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    case DeclInfo::EnumKind:
89286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      RootEndTag = "</Enum>";
89386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<Enum";
89486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      break;
89586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    }
89686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
89786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    {
89886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      // Print line and column number.
89986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      SourceLocation Loc = DI->CurrentDecl->getLocation();
90086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
90186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      FileID FID = LocInfo.first;
90286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      unsigned FileOffset = LocInfo.second;
90386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
90486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (!FID.isInvalid()) {
90586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        if (const FileEntry *FE = SM.getFileEntryForID(FID)) {
90686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko          Result << " file=\"";
90786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko          appendToResultWithXMLEscaping(FE->getName());
90886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko          Result << "\"";
90986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        }
91086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Result << " line=\"" << SM.getLineNumber(FID, FileOffset)
91186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko               << "\" column=\"" << SM.getColumnNumber(FID, FileOffset)
91286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko               << "\"";
91386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      }
91486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    }
91586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
91686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    // Finish the root tag.
91786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << ">";
91886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
91986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    bool FoundName = false;
92086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->CommentDecl)) {
92186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (DeclarationName DeclName = ND->getDeclName()) {
92286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Result << "<Name>";
92386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        std::string Name = DeclName.getAsString();
92486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        appendToResultWithXMLEscaping(Name);
92586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        FoundName = true;
92686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Result << "</Name>";
92786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      }
92886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    }
92986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    if (!FoundName)
93086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<Name>&lt;anonymous&gt;</Name>";
93186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
93286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    {
93386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      // Print USR.
93486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      SmallString<128> USR;
93586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      generateUSRForDecl(DI->CommentDecl, USR);
93686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (!USR.empty()) {
93786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Result << "<USR>";
93886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        appendToResultWithXMLEscaping(USR);
93986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Result << "</USR>";
94086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      }
94186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    }
94286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  } else {
94386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    // No DeclInfo -- just emit some root tag and name tag.
94486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    RootEndTag = "</Other>";
94586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<Other><Name>unknown</Name>";
94686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
94786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
94886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (Parts.Headerfile) {
94986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<Headerfile>";
95086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    visit(Parts.Headerfile);
95186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</Headerfile>";
95286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
95386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
95486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  {
95586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    // Pretty-print the declaration.
95686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<Declaration>";
95786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    SmallString<128> Declaration;
95886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    getSourceTextOfDeclaration(DI, Declaration);
95986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    formatTextOfDeclaration(DI, Declaration);
96086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    appendToResultWithXMLEscaping(Declaration);
96186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</Declaration>";
96286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
96386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
96486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  bool FirstParagraphIsBrief = false;
96586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (Parts.Brief) {
96686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<Abstract>";
96786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    visit(Parts.Brief);
96886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</Abstract>";
96986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  } else if (Parts.FirstParagraph) {
97086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<Abstract>";
97186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    visit(Parts.FirstParagraph);
97286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</Abstract>";
97386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    FirstParagraphIsBrief = true;
97486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
97586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
97686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (Parts.TParams.size() != 0) {
97786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<TemplateParameters>";
97886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
97986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      visit(Parts.TParams[i]);
98086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</TemplateParameters>";
98186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
98286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
98386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (Parts.Params.size() != 0) {
98486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<Parameters>";
98586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
98686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      visit(Parts.Params[i]);
98786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</Parameters>";
98886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
98986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
99086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (Parts.Exceptions.size() != 0) {
99186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<Exceptions>";
99286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    for (unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i)
99386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      visit(Parts.Exceptions[i]);
99486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</Exceptions>";
99586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
99686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
99786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (Parts.Returns.size() != 0) {
99886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "<ResultDiscussion>";
99986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
100086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      visit(Parts.Returns[i]);
100186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    Result << "</ResultDiscussion>";
100286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  }
100386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
100486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko  if (DI->CommentDecl->hasAttrs()) {
100586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    const AttrVec &Attrs = DI->CommentDecl->getAttrs();
100686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko    for (unsigned i = 0, e = Attrs.size(); i != e; i++) {
100786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
100886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (!AA) {
100986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        if (const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
101086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko          if (DA->getMessage().empty())
101186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko            Result << "<Deprecated/>";
101286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko          else {
101386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko            Result << "<Deprecated>";
101486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko            appendToResultWithXMLEscaping(DA->getMessage());
101586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko            Result << "</Deprecated>";
101686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko          }
101786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        }
101886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        else if (const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
101986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko          if (UA->getMessage().empty())
102086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko            Result << "<Unavailable/>";
102186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko          else {
102286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko            Result << "<Unavailable>";
102386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko            appendToResultWithXMLEscaping(UA->getMessage());
102486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko            Result << "</Unavailable>";
102586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko          }
102686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        }
102786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        continue;
102886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      }
102986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko
103086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      // 'availability' attribute.
103186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << "<Availability";
103286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      StringRef Distribution;
103386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (AA->getPlatform()) {
103486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Distribution = AvailabilityAttr::getPrettyPlatformName(
103586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko                                        AA->getPlatform()->getName());
103686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        if (Distribution.empty())
103786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko          Distribution = AA->getPlatform()->getName();
103886cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      }
103986cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      Result << " distribution=\"" << Distribution << "\">";
104086cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      VersionTuple IntroducedInVersion = AA->getIntroduced();
104186cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (!IntroducedInVersion.empty()) {
104286cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko        Result << "<IntroducedInVersion>"
104386cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko               << IntroducedInVersion.getAsString()
104486cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko               << "</IntroducedInVersion>";
104586cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      }
104686cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      VersionTuple DeprecatedInVersion = AA->getDeprecated();
104786cfda2fcccc84e92fb7f27e85b58312440ca8deDmitri Gribenko      if (!DeprecatedInVersion.empty()