Documentation parsing: move comment-to-XML conversion routines to libIndex


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@194610 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 3e74128..f53e5c1 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -22,7 +22,6 @@
 #include "CXTranslationUnit.h"
 #include "CXType.h"
 #include "CursorVisitor.h"
-#include "SimpleFormatContext.h"
 #include "clang/AST/Attr.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/Diagnostic.h"
@@ -30,6 +29,7 @@
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Index/CommentToXML.h"
 #include "clang/Lex/HeaderSearch.h"
 #include "clang/Lex/Lexer.h"
 #include "clang/Lex/PreprocessingRecord.h"
@@ -68,8 +68,7 @@
   D->StringPool = new cxstring::CXStringPool();
   D->Diagnostics = 0;
   D->OverridenCursorsPool = createOverridenCXCursorsPool();
-  D->FormatContext = 0;
-  D->FormatInMemoryUniqueId = 0;
+  D->CommentToXML = 0;
   return D;
 }
 
@@ -2904,7 +2903,7 @@
     delete CTUnit->StringPool;
     delete static_cast<CXDiagnosticSetImpl *>(CTUnit->Diagnostics);
     disposeOverridenCXCursorsPool(CTUnit->OverridenCursorsPool);
-    delete CTUnit->FormatContext;
+    delete CTUnit->CommentToXML;
     delete CTUnit;
   }
 }
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index a593dfc..f84780e 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -39,7 +39,6 @@
   Indexing.cpp
   IndexingContext.cpp
   IndexingContext.h
-  SimpleFormatContext.h
   ../../include/clang-c/Index.h
   )
 
diff --git a/tools/libclang/CXComment.cpp b/tools/libclang/CXComment.cpp
index 1df6e24..21057cb 100644
--- a/tools/libclang/CXComment.cpp
+++ b/tools/libclang/CXComment.cpp
@@ -15,19 +15,11 @@
 #include "CXComment.h"
 #include "CXCursor.h"
 #include "CXString.h"
-#include "SimpleFormatContext.h"
-#include "clang/AST/Attr.h"
-#include "clang/AST/CommentCommandTraits.h"
-#include "clang/AST/CommentVisitor.h"
 #include "clang/AST/Decl.h"
-#include "clang/AST/PrettyPrinter.h"
-#include "clang/Format/Format.h"
-#include "clang/Lex/Lexer.h"
+#include "clang/Index/CommentToXML.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/TinyPtrVector.h"
 #include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
 #include <climits>
 
 using namespace clang;
@@ -352,524 +344,23 @@
   return cxstring::createRef(VLC->getText());
 }
 
-} // end extern "C"
-
 //===----------------------------------------------------------------------===//
-// Helpers for converting comment AST to HTML.
+// Converting comments to XML.
 //===----------------------------------------------------------------------===//
 
-namespace {
-
-/// This comparison will sort parameters with valid index by index, then vararg
-/// parameters, and invalid (unresolved) parameters last.
-class ParamCommandCommentCompareIndex {
-public:
-  bool operator()(const ParamCommandComment *LHS,
-                  const ParamCommandComment *RHS) const {
-    unsigned LHSIndex = UINT_MAX;
-    unsigned RHSIndex = UINT_MAX;
-
-    if (LHS->isParamIndexValid()) {
-      if (LHS->isVarArgParam())
-        LHSIndex = UINT_MAX - 1;
-      else
-        LHSIndex = LHS->getParamIndex();
-    }
-    if (RHS->isParamIndexValid()) {
-      if (RHS->isVarArgParam())
-        RHSIndex = UINT_MAX - 1;
-      else
-        RHSIndex = RHS->getParamIndex();
-    }
-    return LHSIndex < RHSIndex;
-  }
-};
-
-/// This comparison will sort template parameters in the following order:
-/// \li real template parameters (depth = 1) in index order;
-/// \li all other names (depth > 1);
-/// \li unresolved names.
-class TParamCommandCommentComparePosition {
-public:
-  bool operator()(const TParamCommandComment *LHS,
-                  const TParamCommandComment *RHS) const {
-    // Sort unresolved names last.
-    if (!LHS->isPositionValid())
-      return false;
-    if (!RHS->isPositionValid())
-      return true;
-
-    if (LHS->getDepth() > 1)
-      return false;
-    if (RHS->getDepth() > 1)
-      return true;
-
-    // Sort template parameters in index order.
-    if (LHS->getDepth() == 1 && RHS->getDepth() == 1)
-      return LHS->getIndex(0) < RHS->getIndex(0);
-
-    // Leave all other names in source order.
-    return true;
-  }
-};
-
-/// Separate parts of a FullComment.
-struct FullCommentParts {
-  /// Take a full comment apart and initialize members accordingly.
-  FullCommentParts(const FullComment *C,
-                   const CommandTraits &Traits);
-
-  const BlockContentComment *Brief;
-  const BlockContentComment *Headerfile;
-  const ParagraphComment *FirstParagraph;
-  SmallVector<const BlockCommandComment *, 4> Returns;
-  SmallVector<const ParamCommandComment *, 8> Params;
-  SmallVector<const TParamCommandComment *, 4> TParams;
-  llvm::TinyPtrVector<const BlockCommandComment *> Exceptions;
-  SmallVector<const BlockContentComment *, 8> MiscBlocks;
-};
-
-FullCommentParts::FullCommentParts(const FullComment *C,
-                                   const CommandTraits &Traits) :
-    Brief(NULL), Headerfile(NULL), FirstParagraph(NULL) {
-  for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
-       I != E; ++I) {
-    const Comment *Child = *I;
-    if (!Child)
-      continue;
-    switch (Child->getCommentKind()) {
-    case Comment::NoCommentKind:
-      continue;
-
-    case Comment::ParagraphCommentKind: {
-      const ParagraphComment *PC = cast<ParagraphComment>(Child);
-      if (PC->isWhitespace())
-        break;
-      if (!FirstParagraph)
-        FirstParagraph = PC;
-
-      MiscBlocks.push_back(PC);
-      break;
-    }
-
-    case Comment::BlockCommandCommentKind: {
-      const BlockCommandComment *BCC = cast<BlockCommandComment>(Child);
-      const CommandInfo *Info = Traits.getCommandInfo(BCC->getCommandID());
-      if (!Brief && Info->IsBriefCommand) {
-        Brief = BCC;
-        break;
-      }
-      if (!Headerfile && Info->IsHeaderfileCommand) {
-        Headerfile = BCC;
-        break;
-      }
-      if (Info->IsReturnsCommand) {
-        Returns.push_back(BCC);
-        break;
-      }
-      if (Info->IsThrowsCommand) {
-        Exceptions.push_back(BCC);
-        break;
-      }
-      MiscBlocks.push_back(BCC);
-      break;
-    }
-
-    case Comment::ParamCommandCommentKind: {
-      const ParamCommandComment *PCC = cast<ParamCommandComment>(Child);
-      if (!PCC->hasParamName())
-        break;
-
-      if (!PCC->isDirectionExplicit() && !PCC->hasNonWhitespaceParagraph())
-        break;
-
-      Params.push_back(PCC);
-      break;
-    }
-
-    case Comment::TParamCommandCommentKind: {
-      const TParamCommandComment *TPCC = cast<TParamCommandComment>(Child);
-      if (!TPCC->hasParamName())
-        break;
-
-      if (!TPCC->hasNonWhitespaceParagraph())
-        break;
-
-      TParams.push_back(TPCC);
-      break;
-    }
-
-    case Comment::VerbatimBlockCommentKind:
-      MiscBlocks.push_back(cast<BlockCommandComment>(Child));
-      break;
-
-    case Comment::VerbatimLineCommentKind: {
-      const VerbatimLineComment *VLC = cast<VerbatimLineComment>(Child);
-      const CommandInfo *Info = Traits.getCommandInfo(VLC->getCommandID());
-      if (!Info->IsDeclarationCommand)
-        MiscBlocks.push_back(VLC);
-      break;
-    }
-
-    case Comment::TextCommentKind:
-    case Comment::InlineCommandCommentKind:
-    case Comment::HTMLStartTagCommentKind:
-    case Comment::HTMLEndTagCommentKind:
-    case Comment::VerbatimBlockLineCommentKind:
-    case Comment::FullCommentKind:
-      llvm_unreachable("AST node of this kind can't be a child of "
-                       "a FullComment");
-    }
-  }
-
-  // Sort params in order they are declared in the function prototype.
-  // Unresolved parameters are put at the end of the list in the same order
-  // they were seen in the comment.
-  std::stable_sort(Params.begin(), Params.end(),
-                   ParamCommandCommentCompareIndex());
-
-  std::stable_sort(TParams.begin(), TParams.end(),
-                   TParamCommandCommentComparePosition());
-}
-
-void PrintHTMLStartTagComment(const HTMLStartTagComment *C,
-                              llvm::raw_svector_ostream &Result) {
-  Result << "<" << C->getTagName();
-
-  if (C->getNumAttrs() != 0) {
-    for (unsigned i = 0, e = C->getNumAttrs(); i != e; i++) {
-      Result << " ";
-      const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
-      Result << Attr.Name;
-      if (!Attr.Value.empty())
-        Result << "=\"" << Attr.Value << "\"";
-    }
-  }
-
-  if (!C->isSelfClosing())
-    Result << ">";
-  else
-    Result << "/>";
-}
-
-class CommentASTToHTMLConverter :
-    public ConstCommentVisitor<CommentASTToHTMLConverter> {
-public:
-  /// \param Str accumulator for HTML.
-  CommentASTToHTMLConverter(const FullComment *FC,
-                            SmallVectorImpl<char> &Str,
-                            const CommandTraits &Traits) :
-      FC(FC), Result(Str), Traits(Traits)
-  { }
-
-  // Inline content.
-  void visitTextComment(const TextComment *C);
-  void visitInlineCommandComment(const InlineCommandComment *C);
-  void visitHTMLStartTagComment(const HTMLStartTagComment *C);
-  void visitHTMLEndTagComment(const HTMLEndTagComment *C);
-
-  // Block content.
-  void visitParagraphComment(const ParagraphComment *C);
-  void visitBlockCommandComment(const BlockCommandComment *C);
-  void visitParamCommandComment(const ParamCommandComment *C);
-  void visitTParamCommandComment(const TParamCommandComment *C);
-  void visitVerbatimBlockComment(const VerbatimBlockComment *C);
-  void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
-  void visitVerbatimLineComment(const VerbatimLineComment *C);
-
-  void visitFullComment(const FullComment *C);
-
-  // Helpers.
-
-  /// Convert a paragraph that is not a block by itself (an argument to some
-  /// command).
-  void visitNonStandaloneParagraphComment(const ParagraphComment *C);
-
-  void appendToResultWithHTMLEscaping(StringRef S);
-
-private:
-  const FullComment *FC;
-  /// Output stream for HTML.
-  llvm::raw_svector_ostream Result;
-
-  const CommandTraits &Traits;
-};
-} // end unnamed namespace
-
-void CommentASTToHTMLConverter::visitTextComment(const TextComment *C) {
-  appendToResultWithHTMLEscaping(C->getText());
-}
-
-void CommentASTToHTMLConverter::visitInlineCommandComment(
-                                  const InlineCommandComment *C) {
-  // Nothing to render if no arguments supplied.
-  if (C->getNumArgs() == 0)
-    return;
-
-  // Nothing to render if argument is empty.
-  StringRef Arg0 = C->getArgText(0);
-  if (Arg0.empty())
-    return;
-
-  switch (C->getRenderKind()) {
-  case InlineCommandComment::RenderNormal:
-    for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
-      appendToResultWithHTMLEscaping(C->getArgText(i));
-      Result << " ";
-    }
-    return;
-
-  case InlineCommandComment::RenderBold:
-    assert(C->getNumArgs() == 1);
-    Result << "<b>";
-    appendToResultWithHTMLEscaping(Arg0);
-    Result << "</b>";
-    return;
-  case InlineCommandComment::RenderMonospaced:
-    assert(C->getNumArgs() == 1);
-    Result << "<tt>";
-    appendToResultWithHTMLEscaping(Arg0);
-    Result<< "</tt>";
-    return;
-  case InlineCommandComment::RenderEmphasized:
-    assert(C->getNumArgs() == 1);
-    Result << "<em>";
-    appendToResultWithHTMLEscaping(Arg0);
-    Result << "</em>";
-    return;
-  }
-}
-
-void CommentASTToHTMLConverter::visitHTMLStartTagComment(
-                                  const HTMLStartTagComment *C) {
-  PrintHTMLStartTagComment(C, Result);
-}
-
-void CommentASTToHTMLConverter::visitHTMLEndTagComment(
-                                  const HTMLEndTagComment *C) {
-  Result << "</" << C->getTagName() << ">";
-}
-
-void CommentASTToHTMLConverter::visitParagraphComment(
-                                  const ParagraphComment *C) {
-  if (C->isWhitespace())
-    return;
-
-  Result << "<p>";
-  for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
-       I != E; ++I) {
-    visit(*I);
-  }
-  Result << "</p>";
-}
-
-void CommentASTToHTMLConverter::visitBlockCommandComment(
-                                  const BlockCommandComment *C) {
-  const CommandInfo *Info = Traits.getCommandInfo(C->getCommandID());
-  if (Info->IsBriefCommand) {
-    Result << "<p class=\"para-brief\">";
-    visitNonStandaloneParagraphComment(C->getParagraph());
-    Result << "</p>";
-    return;
-  }
-  if (Info->IsReturnsCommand) {
-    Result << "<p class=\"para-returns\">"
-              "<span class=\"word-returns\">Returns</span> ";
-    visitNonStandaloneParagraphComment(C->getParagraph());
-    Result << "</p>";
-    return;
-  }
-  // We don't know anything about this command.  Just render the paragraph.
-  visit(C->getParagraph());
-}
-
-void CommentASTToHTMLConverter::visitParamCommandComment(
-                                  const ParamCommandComment *C) {
-  if (C->isParamIndexValid()) {
-    if (C->isVarArgParam()) {
-      Result << "<dt class=\"param-name-index-vararg\">";
-      appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
-    } else {
-      Result << "<dt class=\"param-name-index-"
-             << C->getParamIndex()
-             << "\">";
-      appendToResultWithHTMLEscaping(C->getParamName(FC));
-    }
-  } else {
-    Result << "<dt class=\"param-name-index-invalid\">";
-    appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
-  }
-  Result << "</dt>";
-
-  if (C->isParamIndexValid()) {
-    if (C->isVarArgParam())
-      Result << "<dd class=\"param-descr-index-vararg\">";
-    else
-      Result << "<dd class=\"param-descr-index-"
-             << C->getParamIndex()
-             << "\">";
-  } else
-    Result << "<dd class=\"param-descr-index-invalid\">";
-
-  visitNonStandaloneParagraphComment(C->getParagraph());
-  Result << "</dd>";
-}
-
-void CommentASTToHTMLConverter::visitTParamCommandComment(
-                                  const TParamCommandComment *C) {
-  if (C->isPositionValid()) {
-    if (C->getDepth() == 1)
-      Result << "<dt class=\"tparam-name-index-"
-             << C->getIndex(0)
-             << "\">";
-    else
-      Result << "<dt class=\"tparam-name-index-other\">";
-    appendToResultWithHTMLEscaping(C->getParamName(FC));
-  } else {
-    Result << "<dt class=\"tparam-name-index-invalid\">";
-    appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
-  }
-  
-  Result << "</dt>";
-
-  if (C->isPositionValid()) {
-    if (C->getDepth() == 1)
-      Result << "<dd class=\"tparam-descr-index-"
-             << C->getIndex(0)
-             << "\">";
-    else
-      Result << "<dd class=\"tparam-descr-index-other\">";
-  } else
-    Result << "<dd class=\"tparam-descr-index-invalid\">";
-
-  visitNonStandaloneParagraphComment(C->getParagraph());
-  Result << "</dd>";
-}
-
-void CommentASTToHTMLConverter::visitVerbatimBlockComment(
-                                  const VerbatimBlockComment *C) {
-  unsigned NumLines = C->getNumLines();
-  if (NumLines == 0)
-    return;
-
-  Result << "<pre>";
-  for (unsigned i = 0; i != NumLines; ++i) {
-    appendToResultWithHTMLEscaping(C->getText(i));
-    if (i + 1 != NumLines)
-      Result << '\n';
-  }
-  Result << "</pre>";
-}
-
-void CommentASTToHTMLConverter::visitVerbatimBlockLineComment(
-                                  const VerbatimBlockLineComment *C) {
-  llvm_unreachable("should not see this AST node");
-}
-
-void CommentASTToHTMLConverter::visitVerbatimLineComment(
-                                  const VerbatimLineComment *C) {
-  Result << "<pre>";
-  appendToResultWithHTMLEscaping(C->getText());
-  Result << "</pre>";
-}
-
-void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
-  FullCommentParts Parts(C, Traits);
-
-  bool FirstParagraphIsBrief = false;
-  if (Parts.Headerfile)
-    visit(Parts.Headerfile);
-  if (Parts.Brief)
-    visit(Parts.Brief);
-  else if (Parts.FirstParagraph) {
-    Result << "<p class=\"para-brief\">";
-    visitNonStandaloneParagraphComment(Parts.FirstParagraph);
-    Result << "</p>";
-    FirstParagraphIsBrief = true;
-  }
-
-  for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
-    const Comment *C = Parts.MiscBlocks[i];
-    if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
-      continue;
-    visit(C);
-  }
-
-  if (Parts.TParams.size() != 0) {
-    Result << "<dl>";
-    for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
-      visit(Parts.TParams[i]);
-    Result << "</dl>";
-  }
-
-  if (Parts.Params.size() != 0) {
-    Result << "<dl>";
-    for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
-      visit(Parts.Params[i]);
-    Result << "</dl>";
-  }
-
-  if (Parts.Returns.size() != 0) {
-    Result << "<div class=\"result-discussion\">";
-    for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
-      visit(Parts.Returns[i]);
-    Result << "</div>";
-  }
-
-  Result.flush();
-}
-
-void CommentASTToHTMLConverter::visitNonStandaloneParagraphComment(
-                                  const ParagraphComment *C) {
-  if (!C)
-    return;
-
-  for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
-       I != E; ++I) {
-    visit(*I);
-  }
-}
-
-void CommentASTToHTMLConverter::appendToResultWithHTMLEscaping(StringRef S) {
-  for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
-    const char C = *I;
-    switch (C) {
-      case '&':
-        Result << "&amp;";
-        break;
-      case '<':
-        Result << "&lt;";
-        break;
-      case '>':
-        Result << "&gt;";
-        break;
-      case '"':
-        Result << "&quot;";
-        break;
-      case '\'':
-        Result << "&#39;";
-        break;
-      case '/':
-        Result << "&#47;";
-        break;
-      default:
-        Result << C;
-        break;
-    }
-  }
-}
-
-extern "C" {
-
 CXString clang_HTMLTagComment_getAsString(CXComment CXC) {
   const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
   if (!HTC)
     return cxstring::createNull();
 
-  SmallString<128> HTML;
-  CommentASTToHTMLConverter Converter(0, HTML, getCommandTraits(CXC));
-  Converter.visit(HTC);
-  return cxstring::createDup(HTML.str());
+  CXTranslationUnit TU = CXC.TranslationUnit;
+  if (!TU->CommentToXML)
+    TU->CommentToXML = new index::CommentToXMLConverter();
+
+  SmallString<128> Text;
+  TU->CommentToXML->convertHTMLTagNodeToText(
+      HTC, Text, cxtu::getASTUnit(TU)->getASTContext());
+  return cxstring::createDup(Text.str());
 }
 
 CXString clang_FullComment_getAsHTML(CXComment CXC) {
@@ -877,608 +368,28 @@
   if (!FC)
     return cxstring::createNull();
 
+  CXTranslationUnit TU = CXC.TranslationUnit;
+  if (!TU->CommentToXML)
+    TU->CommentToXML = new index::CommentToXMLConverter();
+
   SmallString<1024> HTML;
-  CommentASTToHTMLConverter Converter(FC, HTML, getCommandTraits(CXC));
-  Converter.visit(FC);
+  TU->CommentToXML
+      ->convertCommentToHTML(FC, HTML, cxtu::getASTUnit(TU)->getASTContext());
   return cxstring::createDup(HTML.str());
 }
 
-} // end extern "C"
-
-namespace {
-class CommentASTToXMLConverter :
-    public ConstCommentVisitor<CommentASTToXMLConverter> {
-public:
-  /// \param Str accumulator for XML.
-  CommentASTToXMLConverter(const FullComment *FC,
-                           SmallVectorImpl<char> &Str,
-                           const CommandTraits &Traits,
-                           const SourceManager &SM,
-                           SimpleFormatContext &SFC,
-                           unsigned FUID) :
-      FC(FC), Result(Str), Traits(Traits), SM(SM),
-      FormatRewriterContext(SFC),
-      FormatInMemoryUniqueId(FUID) { }
-
-  // Inline content.
-  void visitTextComment(const TextComment *C);
-  void visitInlineCommandComment(const InlineCommandComment *C);
-  void visitHTMLStartTagComment(const HTMLStartTagComment *C);
-  void visitHTMLEndTagComment(const HTMLEndTagComment *C);
-
-  // Block content.
-  void visitParagraphComment(const ParagraphComment *C);
-
-  void appendParagraphCommentWithKind(const ParagraphComment *C,
-                                      StringRef Kind);
-
-  void visitBlockCommandComment(const BlockCommandComment *C);
-  void visitParamCommandComment(const ParamCommandComment *C);
-  void visitTParamCommandComment(const TParamCommandComment *C);
-  void visitVerbatimBlockComment(const VerbatimBlockComment *C);
-  void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
-  void visitVerbatimLineComment(const VerbatimLineComment *C);
-
-  void visitFullComment(const FullComment *C);
-
-  // Helpers.
-  void appendToResultWithXMLEscaping(StringRef S);
-
-  void formatTextOfDeclaration(const DeclInfo *DI,
-                               SmallString<128> &Declaration);
-
-private:
-  const FullComment *FC;
-
-  /// Output stream for XML.
-  llvm::raw_svector_ostream Result;
-
-  const CommandTraits &Traits;
-  const SourceManager &SM;
-  SimpleFormatContext &FormatRewriterContext;
-  unsigned FormatInMemoryUniqueId;
-};
-
-void getSourceTextOfDeclaration(const DeclInfo *ThisDecl,
-                                SmallVectorImpl<char> &Str) {
-  ASTContext &Context = ThisDecl->CurrentDecl->getASTContext();
-  const LangOptions &LangOpts = Context.getLangOpts();
-  llvm::raw_svector_ostream OS(Str);
-  PrintingPolicy PPolicy(LangOpts);
-  PPolicy.PolishForDeclaration = true;
-  PPolicy.TerseOutput = true;
-  ThisDecl->CurrentDecl->print(OS, PPolicy,
-                               /*Indentation*/0, /*PrintInstantiation*/false);
-}
-  
-void CommentASTToXMLConverter::formatTextOfDeclaration(
-                                              const DeclInfo *DI,
-                                              SmallString<128> &Declaration) {
-  // FIXME. formatting API expects null terminated input string.
-  // There might be more efficient way of doing this.
-  std::string StringDecl = Declaration.str();
-    
-  // Formatter specific code.
-  // Form a unique in memory buffer name.
-  SmallString<128> filename;
-  filename += "xmldecl";
-  filename += llvm::utostr(FormatInMemoryUniqueId);
-  filename += ".xd";
-  FileID ID = FormatRewriterContext.createInMemoryFile(filename, StringDecl);
-  SourceLocation Start =
-    FormatRewriterContext.Sources.getLocForStartOfFile(ID).getLocWithOffset(0);
-  unsigned Length = Declaration.size();
-    
-  std::vector<CharSourceRange>
-    Ranges(1, CharSourceRange::getCharRange(Start, Start.getLocWithOffset(Length)));
-  ASTContext &Context = DI->CurrentDecl->getASTContext();
-  const LangOptions &LangOpts = Context.getLangOpts();
-  Lexer Lex(ID, FormatRewriterContext.Sources.getBuffer(ID),
-            FormatRewriterContext.Sources, LangOpts);
-  tooling::Replacements Replace =
-    reformat(format::getLLVMStyle(), Lex, FormatRewriterContext.Sources, Ranges);
-  applyAllReplacements(Replace, FormatRewriterContext.Rewrite);
-  Declaration = FormatRewriterContext.getRewrittenText(ID);
-}
-
-} // end unnamed namespace
-
-void CommentASTToXMLConverter::visitTextComment(const TextComment *C) {
-  appendToResultWithXMLEscaping(C->getText());
-}
-
-void CommentASTToXMLConverter::visitInlineCommandComment(const InlineCommandComment *C) {
-  // Nothing to render if no arguments supplied.
-  if (C->getNumArgs() == 0)
-    return;
-
-  // Nothing to render if argument is empty.
-  StringRef Arg0 = C->getArgText(0);
-  if (Arg0.empty())
-    return;
-
-  switch (C->getRenderKind()) {
-  case InlineCommandComment::RenderNormal:
-    for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) {
-      appendToResultWithXMLEscaping(C->getArgText(i));
-      Result << " ";
-    }
-    return;
-  case InlineCommandComment::RenderBold:
-    assert(C->getNumArgs() == 1);
-    Result << "<bold>";
-    appendToResultWithXMLEscaping(Arg0);
-    Result << "</bold>";
-    return;
-  case InlineCommandComment::RenderMonospaced:
-    assert(C->getNumArgs() == 1);
-    Result << "<monospaced>";
-    appendToResultWithXMLEscaping(Arg0);
-    Result << "</monospaced>";
-    return;
-  case InlineCommandComment::RenderEmphasized:
-    assert(C->getNumArgs() == 1);
-    Result << "<emphasized>";
-    appendToResultWithXMLEscaping(Arg0);
-    Result << "</emphasized>";
-    return;
-  }
-}
-
-void CommentASTToXMLConverter::visitHTMLStartTagComment(const HTMLStartTagComment *C) {
-  Result << "<rawHTML><![CDATA[";
-  PrintHTMLStartTagComment(C, Result);
-  Result << "]]></rawHTML>";
-}
-
-void CommentASTToXMLConverter::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
-  Result << "<rawHTML>&lt;/" << C->getTagName() << "&gt;</rawHTML>";
-}
-
-void CommentASTToXMLConverter::visitParagraphComment(const ParagraphComment *C) {
-  appendParagraphCommentWithKind(C, StringRef());
-}
-
-void CommentASTToXMLConverter::appendParagraphCommentWithKind(
-                                  const ParagraphComment *C,
-                                  StringRef ParagraphKind) {
-  if (C->isWhitespace())
-    return;
-
-  if (ParagraphKind.empty())
-    Result << "<Para>";
-  else
-    Result << "<Para kind=\"" << ParagraphKind << "\">";
-
-  for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
-       I != E; ++I) {
-    visit(*I);
-  }
-  Result << "</Para>";
-}
-
-void CommentASTToXMLConverter::visitBlockCommandComment(const BlockCommandComment *C) {
-  StringRef ParagraphKind;
-
-  switch (C->getCommandID()) {
-  case CommandTraits::KCI_attention:
-  case CommandTraits::KCI_author:
-  case CommandTraits::KCI_authors:
-  case CommandTraits::KCI_bug:
-  case CommandTraits::KCI_copyright:
-  case CommandTraits::KCI_date:
-  case CommandTraits::KCI_invariant:
-  case CommandTraits::KCI_note:
-  case CommandTraits::KCI_post:
-  case CommandTraits::KCI_pre:
-  case CommandTraits::KCI_remark:
-  case CommandTraits::KCI_remarks:
-  case CommandTraits::KCI_sa:
-  case CommandTraits::KCI_see:
-  case CommandTraits::KCI_since:
-  case CommandTraits::KCI_todo:
-  case CommandTraits::KCI_version:
-  case CommandTraits::KCI_warning:
-    ParagraphKind = C->getCommandName(Traits);
-  default:
-    break;
-  }
-
-  appendParagraphCommentWithKind(C->getParagraph(), ParagraphKind);
-}
-
-void CommentASTToXMLConverter::visitParamCommandComment(const ParamCommandComment *C) {
-  Result << "<Parameter><Name>";
-  appendToResultWithXMLEscaping(C->isParamIndexValid() ? C->getParamName(FC)
-                                                       : C->getParamNameAsWritten());
-  Result << "</Name>";
-
-  if (C->isParamIndexValid()) {
-    if (C->isVarArgParam())
-      Result << "<IsVarArg />";
-    else
-      Result << "<Index>" << C->getParamIndex() << "</Index>";
-  }
-
-  Result << "<Direction isExplicit=\"" << C->isDirectionExplicit() << "\">";
-  switch (C->getDirection()) {
-  case ParamCommandComment::In:
-    Result << "in";
-    break;
-  case ParamCommandComment::Out:
-    Result << "out";
-    break;
-  case ParamCommandComment::InOut:
-    Result << "in,out";
-    break;
-  }
-  Result << "</Direction><Discussion>";
-  visit(C->getParagraph());
-  Result << "</Discussion></Parameter>";
-}
-
-void CommentASTToXMLConverter::visitTParamCommandComment(
-                                  const TParamCommandComment *C) {
-  Result << "<Parameter><Name>";
-  appendToResultWithXMLEscaping(C->isPositionValid() ? C->getParamName(FC)
-                                : C->getParamNameAsWritten());
-  Result << "</Name>";
-
-  if (C->isPositionValid() && C->getDepth() == 1) {
-    Result << "<Index>" << C->getIndex(0) << "</Index>";
-  }
-
-  Result << "<Discussion>";
-  visit(C->getParagraph());
-  Result << "</Discussion></Parameter>";
-}
-
-void CommentASTToXMLConverter::visitVerbatimBlockComment(
-                                  const VerbatimBlockComment *C) {
-  unsigned NumLines = C->getNumLines();
-  if (NumLines == 0)
-    return;
-
-  switch (C->getCommandID()) {
-  case CommandTraits::KCI_code:
-    Result << "<Verbatim xml:space=\"preserve\" kind=\"code\">";
-    break;
-  default:
-    Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
-    break;
-  }
-  for (unsigned i = 0; i != NumLines; ++i) {
-    appendToResultWithXMLEscaping(C->getText(i));
-    if (i + 1 != NumLines)
-      Result << '\n';
-  }
-  Result << "</Verbatim>";
-}
-
-void CommentASTToXMLConverter::visitVerbatimBlockLineComment(
-                                  const VerbatimBlockLineComment *C) {
-  llvm_unreachable("should not see this AST node");
-}
-
-void CommentASTToXMLConverter::visitVerbatimLineComment(
-                                  const VerbatimLineComment *C) {
-  Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
-  appendToResultWithXMLEscaping(C->getText());
-  Result << "</Verbatim>";
-}
-
-void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
-  FullCommentParts Parts(C, Traits);
-
-  const DeclInfo *DI = C->getDeclInfo();
-  StringRef RootEndTag;
-  if (DI) {
-    switch (DI->getKind()) {
-    case DeclInfo::OtherKind:
-      RootEndTag = "</Other>";
-      Result << "<Other";
-      break;
-    case DeclInfo::FunctionKind:
-      RootEndTag = "</Function>";
-      Result << "<Function";
-      switch (DI->TemplateKind) {
-      case DeclInfo::NotTemplate:
-        break;
-      case DeclInfo::Template:
-        Result << " templateKind=\"template\"";
-        break;
-      case DeclInfo::TemplateSpecialization:
-        Result << " templateKind=\"specialization\"";
-        break;
-      case DeclInfo::TemplatePartialSpecialization:
-        llvm_unreachable("partial specializations of functions "
-                         "are not allowed in C++");
-      }
-      if (DI->IsInstanceMethod)
-        Result << " isInstanceMethod=\"1\"";
-      if (DI->IsClassMethod)
-        Result << " isClassMethod=\"1\"";
-      break;
-    case DeclInfo::ClassKind:
-      RootEndTag = "</Class>";
-      Result << "<Class";
-      switch (DI->TemplateKind) {
-      case DeclInfo::NotTemplate:
-        break;
-      case DeclInfo::Template:
-        Result << " templateKind=\"template\"";
-        break;
-      case DeclInfo::TemplateSpecialization:
-        Result << " templateKind=\"specialization\"";
-        break;
-      case DeclInfo::TemplatePartialSpecialization:
-        Result << " templateKind=\"partialSpecialization\"";
-        break;
-      }
-      break;
-    case DeclInfo::VariableKind:
-      RootEndTag = "</Variable>";
-      Result << "<Variable";
-      break;
-    case DeclInfo::NamespaceKind:
-      RootEndTag = "</Namespace>";
-      Result << "<Namespace";
-      break;
-    case DeclInfo::TypedefKind:
-      RootEndTag = "</Typedef>";
-      Result << "<Typedef";
-      break;
-    case DeclInfo::EnumKind:
-      RootEndTag = "</Enum>";
-      Result << "<Enum";
-      break;
-    }
-
-    {
-      // Print line and column number.
-      SourceLocation Loc = DI->CurrentDecl->getLocation();
-      std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
-      FileID FID = LocInfo.first;
-      unsigned FileOffset = LocInfo.second;
-
-      if (!FID.isInvalid()) {
-        if (const FileEntry *FE = SM.getFileEntryForID(FID)) {
-          Result << " file=\"";
-          appendToResultWithXMLEscaping(FE->getName());
-          Result << "\"";
-        }
-        Result << " line=\"" << SM.getLineNumber(FID, FileOffset)
-               << "\" column=\"" << SM.getColumnNumber(FID, FileOffset)
-               << "\"";
-      }
-    }
-
-    // Finish the root tag.
-    Result << ">";
-
-    bool FoundName = false;
-    if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->CommentDecl)) {
-      if (DeclarationName DeclName = ND->getDeclName()) {
-        Result << "<Name>";
-        std::string Name = DeclName.getAsString();
-        appendToResultWithXMLEscaping(Name);
-        FoundName = true;
-        Result << "</Name>";
-      }
-    }
-    if (!FoundName)
-      Result << "<Name>&lt;anonymous&gt;</Name>";
-
-    {
-      // Print USR.
-      SmallString<128> USR;
-      cxcursor::getDeclCursorUSR(DI->CommentDecl, USR);
-      if (!USR.empty()) {
-        Result << "<USR>";
-        appendToResultWithXMLEscaping(USR);
-        Result << "</USR>";
-      }
-    }
-  } else {
-    // No DeclInfo -- just emit some root tag and name tag.
-    RootEndTag = "</Other>";
-    Result << "<Other><Name>unknown</Name>";
-  }
-  
-  if (Parts.Headerfile) {
-    Result << "<Headerfile>";
-    visit(Parts.Headerfile);
-    Result << "</Headerfile>";
-  }
-
-  {
-    // Pretty-print the declaration.
-    Result << "<Declaration>";
-    SmallString<128> Declaration;
-    getSourceTextOfDeclaration(DI, Declaration);
-    formatTextOfDeclaration(DI, Declaration);
-    appendToResultWithXMLEscaping(Declaration);
-    
-    Result << "</Declaration>";
-  }
-
-  bool FirstParagraphIsBrief = false;
-  if (Parts.Brief) {
-    Result << "<Abstract>";
-    visit(Parts.Brief);
-    Result << "</Abstract>";
-  } else if (Parts.FirstParagraph) {
-    Result << "<Abstract>";
-    visit(Parts.FirstParagraph);
-    Result << "</Abstract>";
-    FirstParagraphIsBrief = true;
-  }
-  
-  if (Parts.TParams.size() != 0) {
-    Result << "<TemplateParameters>";
-    for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
-      visit(Parts.TParams[i]);
-    Result << "</TemplateParameters>";
-  }
-
-  if (Parts.Params.size() != 0) {
-    Result << "<Parameters>";
-    for (unsigned i = 0, e = Parts.Params.size(); i != e; ++i)
-      visit(Parts.Params[i]);
-    Result << "</Parameters>";
-  }
-
-  if (Parts.Exceptions.size() != 0) {
-    Result << "<Exceptions>";
-    for (unsigned i = 0, e = Parts.Exceptions.size(); i != e; ++i)
-      visit(Parts.Exceptions[i]);
-    Result << "</Exceptions>";
-  }
-
-  if (Parts.Returns.size() != 0) {
-    Result << "<ResultDiscussion>";
-    for (unsigned i = 0, e = Parts.Returns.size(); i != e; ++i)
-      visit(Parts.Returns[i]);
-    Result << "</ResultDiscussion>";
-  }
-  
-  if (DI->CommentDecl->hasAttrs()) {
-    const AttrVec &Attrs = DI->CommentDecl->getAttrs();
-    for (unsigned i = 0, e = Attrs.size(); i != e; i++) {
-      const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
-      if (!AA) {
-        if (const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
-          if (DA->getMessage().empty())
-            Result << "<Deprecated/>";
-          else {
-            Result << "<Deprecated>";
-            appendToResultWithXMLEscaping(DA->getMessage());
-            Result << "</Deprecated>";
-          }
-        }
-        else if (const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
-          if (UA->getMessage().empty())
-            Result << "<Unavailable/>";
-          else {
-            Result << "<Unavailable>";
-            appendToResultWithXMLEscaping(UA->getMessage());
-            Result << "</Unavailable>";
-          }
-        }
-        continue;
-      }
-
-      // 'availability' attribute.
-      Result << "<Availability";
-      StringRef Distribution;
-      if (AA->getPlatform()) {
-        Distribution = AvailabilityAttr::getPrettyPlatformName(
-                                        AA->getPlatform()->getName());
-        if (Distribution.empty())
-          Distribution = AA->getPlatform()->getName();
-      }
-      Result << " distribution=\"" << Distribution << "\">";
-      VersionTuple IntroducedInVersion = AA->getIntroduced();
-      if (!IntroducedInVersion.empty()) {
-        Result << "<IntroducedInVersion>"
-               << IntroducedInVersion.getAsString()
-               << "</IntroducedInVersion>";
-      }
-      VersionTuple DeprecatedInVersion = AA->getDeprecated();
-      if (!DeprecatedInVersion.empty()) {
-        Result << "<DeprecatedInVersion>"
-               << DeprecatedInVersion.getAsString()
-               << "</DeprecatedInVersion>";
-      }
-      VersionTuple RemovedAfterVersion = AA->getObsoleted();
-      if (!RemovedAfterVersion.empty()) {
-        Result << "<RemovedAfterVersion>"
-               << RemovedAfterVersion.getAsString()
-               << "</RemovedAfterVersion>";
-      }
-      StringRef DeprecationSummary = AA->getMessage();
-      if (!DeprecationSummary.empty()) {
-        Result << "<DeprecationSummary>";
-        appendToResultWithXMLEscaping(DeprecationSummary);
-        Result << "</DeprecationSummary>";
-      }
-      if (AA->getUnavailable())
-        Result << "<Unavailable/>";
-      Result << "</Availability>";
-    }
-  }
-
-  {
-    bool StartTagEmitted = false;
-    for (unsigned i = 0, e = Parts.MiscBlocks.size(); i != e; ++i) {
-      const Comment *C = Parts.MiscBlocks[i];
-      if (FirstParagraphIsBrief && C == Parts.FirstParagraph)
-        continue;
-      if (!StartTagEmitted) {
-        Result << "<Discussion>";
-        StartTagEmitted = true;
-      }
-      visit(C);
-    }
-    if (StartTagEmitted)
-      Result << "</Discussion>";
-  }
-
-  Result << RootEndTag;
-
-  Result.flush();
-}
-
-void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
-  for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) {
-    const char C = *I;
-    switch (C) {
-      case '&':
-        Result << "&amp;";
-        break;
-      case '<':
-        Result << "&lt;";
-        break;
-      case '>':
-        Result << "&gt;";
-        break;
-      case '"':
-        Result << "&quot;";
-        break;
-      case '\'':
-        Result << "&apos;";
-        break;
-      default:
-        Result << C;
-        break;
-    }
-  }
-}
-
-extern "C" {
-
 CXString clang_FullComment_getAsXML(CXComment CXC) {
   const FullComment *FC = getASTNodeAs<FullComment>(CXC);
   if (!FC)
     return cxstring::createNull();
-  ASTContext &Context = FC->getDeclInfo()->CurrentDecl->getASTContext();
-  CXTranslationUnit TU = CXC.TranslationUnit;
-  SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager();
 
-  if (!TU->FormatContext) {
-    TU->FormatContext = new SimpleFormatContext(Context.getLangOpts());
-  } else if ((TU->FormatInMemoryUniqueId % 1000) == 0) {
-    // Delete after some number of iterators, so the buffers don't grow
-    // too large.
-    delete TU->FormatContext;
-    TU->FormatContext = new SimpleFormatContext(Context.getLangOpts());
-  }
+  CXTranslationUnit TU = CXC.TranslationUnit;
+  if (!TU->CommentToXML)
+    TU->CommentToXML = new index::CommentToXMLConverter();
 
   SmallString<1024> XML;
-  CommentASTToXMLConverter Converter(FC, XML, getCommandTraits(CXC), SM,
-                                     *TU->FormatContext,
-                                     TU->FormatInMemoryUniqueId++);
-  Converter.visit(FC);
+  TU->CommentToXML
+      ->convertCommentToXML(FC, XML, cxtu::getASTUnit(TU)->getASTContext());
   return cxstring::createDup(XML.str());
 }
 
diff --git a/tools/libclang/CXTranslationUnit.h b/tools/libclang/CXTranslationUnit.h
index bdc171c..c0014c0 100644
--- a/tools/libclang/CXTranslationUnit.h
+++ b/tools/libclang/CXTranslationUnit.h
@@ -20,7 +20,9 @@
 namespace clang {
   class ASTUnit;
   class CIndexer;
-  class SimpleFormatContext;
+namespace index {
+class CommentToXMLConverter;
+} // namespace index
 } // namespace clang
 
 struct CXTranslationUnitImpl {
@@ -29,8 +31,7 @@
   clang::cxstring::CXStringPool *StringPool;
   void *Diagnostics;
   void *OverridenCursorsPool;
-  clang::SimpleFormatContext *FormatContext;
-  unsigned FormatInMemoryUniqueId;
+  clang::index::CommentToXMLConverter *CommentToXML;
 };
 
 namespace clang {
diff --git a/tools/libclang/SimpleFormatContext.h b/tools/libclang/SimpleFormatContext.h
deleted file mode 100644
index 016d0b6..0000000
--- a/tools/libclang/SimpleFormatContext.h
+++ /dev/null
@@ -1,75 +0,0 @@
-//===--- SimpleFormatContext.h ----------------------------------*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-/// \file
-///
-/// \brief Defines a utility class for use of clang-format in libclang
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_SIMPLE_FORM_CONTEXT_H
-#define LLVM_CLANG_SIMPLE_FORM_CONTEXT_H
-
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/DiagnosticOptions.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Rewrite/Core/Rewriter.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace clang {
-
-/// \brief A small class to be used by libclang clients to format
-/// a declaration string in memory. This object is instantiated once
-/// and used each time a formatting is needed.
-class SimpleFormatContext {
-public:
-  SimpleFormatContext(LangOptions Options)
-      : DiagOpts(new DiagnosticOptions()),
-        Diagnostics(new DiagnosticsEngine(new DiagnosticIDs, 
-                                          DiagOpts.getPtr())),
-        Files((FileSystemOptions())),
-        Sources(*Diagnostics, Files),
-        Rewrite(Sources, Options) {
-    Diagnostics->setClient(new IgnoringDiagConsumer, true);
-  }
-
-  ~SimpleFormatContext() { }
-
-  FileID createInMemoryFile(StringRef Name, StringRef Content) {
-    const llvm::MemoryBuffer *Source =
-      llvm::MemoryBuffer::getMemBuffer(Content);
-    const FileEntry *Entry =
-      Files.getVirtualFile(Name, Source->getBufferSize(), 0);
-    Sources.overrideFileContents(Entry, Source, true);
-    assert(Entry != NULL);
-    return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
-  }
-
-  std::string getRewrittenText(FileID ID) {
-    std::string Result;
-    llvm::raw_string_ostream OS(Result);
-    Rewrite.getEditBuffer(ID).write(OS);
-    OS.flush();
-    return Result;
-  }
-
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
-  IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
-  FileManager Files;
-  SourceManager Sources;
-  Rewriter Rewrite;
-};
-
-} // end namespace clang
-
-#endif