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

Dmitri Gribenko gribozavr at gmail.com
Wed Nov 13 14:16:51 PST 2013


Author: gribozavr
Date: Wed Nov 13 16:16:51 2013
New Revision: 194610

URL: http://llvm.org/viewvc/llvm-project?rev=194610&view=rev
Log:
Documentation parsing: move comment-to-XML conversion routines to libIndex

Added:
    cfe/trunk/include/clang/Index/CommentToXML.h
    cfe/trunk/lib/Index/CommentToXML.cpp
    cfe/trunk/lib/Index/SimpleFormatContext.h
      - copied, changed from r194522, cfe/trunk/tools/libclang/SimpleFormatContext.h
Removed:
    cfe/trunk/tools/libclang/SimpleFormatContext.h
Modified:
    cfe/trunk/lib/Index/CMakeLists.txt
    cfe/trunk/tools/libclang/CIndex.cpp
    cfe/trunk/tools/libclang/CMakeLists.txt
    cfe/trunk/tools/libclang/CXComment.cpp
    cfe/trunk/tools/libclang/CXTranslationUnit.h

Added: cfe/trunk/include/clang/Index/CommentToXML.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Index/CommentToXML.h?rev=194610&view=auto
==============================================================================
--- cfe/trunk/include/clang/Index/CommentToXML.h (added)
+++ cfe/trunk/include/clang/Index/CommentToXML.h Wed Nov 13 16:16:51 2013
@@ -0,0 +1,50 @@
+//===--- CommentToXML.h - Convert comments to XML representation ----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_COMMENTTOXML_H
+#define LLVM_CLANG_INDEX_COMMENTTOXML_H
+
+#include "clang/Basic/LLVM.h"
+
+namespace clang {
+class ASTContext;
+
+namespace comments {
+class FullComment;
+class HTMLTagComment;
+}
+
+namespace index {
+class SimpleFormatContext;
+
+class CommentToXMLConverter {
+  SimpleFormatContext *FormatContext;
+  unsigned FormatInMemoryUniqueId;
+
+public:
+  CommentToXMLConverter() : FormatContext(0), FormatInMemoryUniqueId(0) {}
+
+  void convertCommentToHTML(const comments::FullComment *FC,
+                            SmallVectorImpl<char> &HTML,
+                            const ASTContext &Context);
+
+  void convertHTMLTagNodeToText(const comments::HTMLTagComment *HTC,
+                                SmallVectorImpl<char> &Text,
+                                const ASTContext &Context);
+
+  void convertCommentToXML(const comments::FullComment *FC,
+                           SmallVectorImpl<char> &XML,
+                           const ASTContext &Context);
+};
+
+} // namespace index
+} // namespace clang
+
+#endif // LLVM_CLANG_INDEX_COMMENTTOXML_H
+

Modified: cfe/trunk/lib/Index/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Index/CMakeLists.txt?rev=194610&r1=194609&r2=194610&view=diff
==============================================================================
--- cfe/trunk/lib/Index/CMakeLists.txt (original)
+++ cfe/trunk/lib/Index/CMakeLists.txt Wed Nov 13 16:16:51 2013
@@ -1,4 +1,6 @@
 add_clang_library(clangIndex
+  CommentToXML.cpp
+  SimpleFormatContext.h
   USRGeneration.cpp
   )
 

Added: cfe/trunk/lib/Index/CommentToXML.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Index/CommentToXML.cpp?rev=194610&view=auto
==============================================================================
--- cfe/trunk/lib/Index/CommentToXML.cpp (added)
+++ cfe/trunk/lib/Index/CommentToXML.cpp Wed Nov 13 16:16:51 2013
@@ -0,0 +1,1136 @@
+//===--- CommentToXML.cpp - Convert comments to XML representation --------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/CommentToXML.h"
+#include "SimpleFormatContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Comment.h"
+#include "clang/AST/CommentVisitor.h"
+#include "clang/Format/Format.h"
+#include "clang/Index/USRGeneration.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/TinyPtrVector.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::comments;
+using namespace clang::index;
+
+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 << "&";
+      break;
+    case '<':
+      Result << "<";
+      break;
+    case '>':
+      Result << ">";
+      break;
+    case '"':
+      Result << """;
+      break;
+    case '\'':
+      Result << "'";
+      break;
+    case '/':
+      Result << "/";
+      break;
+    default:
+      Result << C;
+      break;
+    }
+  }
+}
+
+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></" << C->getTagName() << "></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><anonymous></Name>";
+
+    {
+      // Print USR.
+      SmallString<128> USR;
+      generateUSRForDecl(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 << "&";
+      break;
+    case '<':
+      Result << "<";
+      break;
+    case '>':
+      Result << ">";
+      break;
+    case '"':
+      Result << """;
+      break;
+    case '\'':
+      Result << "'";
+      break;
+    default:
+      Result << C;
+      break;
+    }
+  }
+}
+
+void CommentToXMLConverter::convertCommentToHTML(const FullComment *FC,
+                                                 SmallVectorImpl<char> &HTML,
+                                                 const ASTContext &Context) {
+  CommentASTToHTMLConverter Converter(FC, HTML,
+                                      Context.getCommentCommandTraits());
+  Converter.visit(FC);
+}
+
+void CommentToXMLConverter::convertHTMLTagNodeToText(
+    const comments::HTMLTagComment *HTC, SmallVectorImpl<char> &Text,
+    const ASTContext &Context) {
+  CommentASTToHTMLConverter Converter(0, Text,
+                                      Context.getCommentCommandTraits());
+  Converter.visit(HTC);
+}
+
+void CommentToXMLConverter::convertCommentToXML(const FullComment *FC,
+                                                SmallVectorImpl<char> &XML,
+                                                const ASTContext &Context) {
+  if (!FormatContext) {
+    FormatContext = new SimpleFormatContext(Context.getLangOpts());
+  } else if ((FormatInMemoryUniqueId % 1000) == 0) {
+    // Delete after some number of iterations, so the buffers don't grow
+    // too large.
+    delete FormatContext;
+    FormatContext = new SimpleFormatContext(Context.getLangOpts());
+  }
+
+  CommentASTToXMLConverter Converter(FC, XML, Context.getCommentCommandTraits(),
+                                     Context.getSourceManager(), *FormatContext,
+                                     FormatInMemoryUniqueId++);
+  Converter.visit(FC);
+}
+

Copied: cfe/trunk/lib/Index/SimpleFormatContext.h (from r194522, cfe/trunk/tools/libclang/SimpleFormatContext.h)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Index/SimpleFormatContext.h?p2=cfe/trunk/lib/Index/SimpleFormatContext.h&p1=cfe/trunk/tools/libclang/SimpleFormatContext.h&r1=194522&r2=194610&rev=194610&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/SimpleFormatContext.h (original)
+++ cfe/trunk/lib/Index/SimpleFormatContext.h Wed Nov 13 16:16:51 2013
@@ -27,6 +27,7 @@
 #include "llvm/Support/raw_ostream.h"
 
 namespace clang {
+namespace index {
 
 /// \brief A small class to be used by libclang clients to format
 /// a declaration string in memory. This object is instantiated once
@@ -35,7 +36,7 @@ class SimpleFormatContext {
 public:
   SimpleFormatContext(LangOptions Options)
       : DiagOpts(new DiagnosticOptions()),
-        Diagnostics(new DiagnosticsEngine(new DiagnosticIDs, 
+        Diagnostics(new DiagnosticsEngine(new DiagnosticIDs,
                                           DiagOpts.getPtr())),
         Files((FileSystemOptions())),
         Sources(*Diagnostics, Files),
@@ -47,9 +48,9 @@ public:
 
   FileID createInMemoryFile(StringRef Name, StringRef Content) {
     const llvm::MemoryBuffer *Source =
-      llvm::MemoryBuffer::getMemBuffer(Content);
+        llvm::MemoryBuffer::getMemBuffer(Content);
     const FileEntry *Entry =
-      Files.getVirtualFile(Name, Source->getBufferSize(), 0);
+        Files.getVirtualFile(Name, Source->getBufferSize(), 0);
     Sources.overrideFileContents(Entry, Source, true);
     assert(Entry != NULL);
     return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
@@ -70,6 +71,7 @@ public:
   Rewriter Rewrite;
 };
 
+} // end namespace index
 } // end namespace clang
 
 #endif

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=194610&r1=194609&r2=194610&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Wed Nov 13 16:16:51 2013
@@ -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 @@ CXTranslationUnit cxtu::MakeCXTranslatio
   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 @@ void clang_disposeTranslationUnit(CXTran
     delete CTUnit->StringPool;
     delete static_cast<CXDiagnosticSetImpl *>(CTUnit->Diagnostics);
     disposeOverridenCXCursorsPool(CTUnit->OverridenCursorsPool);
-    delete CTUnit->FormatContext;
+    delete CTUnit->CommentToXML;
     delete CTUnit;
   }
 }

Modified: cfe/trunk/tools/libclang/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CMakeLists.txt?rev=194610&r1=194609&r2=194610&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CMakeLists.txt (original)
+++ cfe/trunk/tools/libclang/CMakeLists.txt Wed Nov 13 16:16:51 2013
@@ -39,7 +39,6 @@ set(SOURCES
   Indexing.cpp
   IndexingContext.cpp
   IndexingContext.h
-  SimpleFormatContext.h
   ../../include/clang-c/Index.h
   )
 

Modified: cfe/trunk/tools/libclang/CXComment.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXComment.cpp?rev=194610&r1=194609&r2=194610&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXComment.cpp (original)
+++ cfe/trunk/tools/libclang/CXComment.cpp Wed Nov 13 16:16:51 2013
@@ -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 @@ CXString clang_VerbatimLineComment_getTe
   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 << "&";
-        break;
-      case '<':
-        Result << "<";
-        break;
-      case '>':
-        Result << ">";
-        break;
-      case '"':
-        Result << """;
-        break;
-      case '\'':
-        Result << "'";
-        break;
-      case '/':
-        Result << "/";
-        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 @@ CXString clang_FullComment_getAsHTML(CXC
   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></" << C->getTagName() << "></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><anonymous></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 << "&";
-        break;
-      case '<':
-        Result << "<";
-        break;
-      case '>':
-        Result << ">";
-        break;
-      case '"':
-        Result << """;
-        break;
-      case '\'':
-        Result << "'";
-        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());
 }
 

Modified: cfe/trunk/tools/libclang/CXTranslationUnit.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXTranslationUnit.h?rev=194610&r1=194609&r2=194610&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXTranslationUnit.h (original)
+++ cfe/trunk/tools/libclang/CXTranslationUnit.h Wed Nov 13 16:16:51 2013
@@ -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 @@ struct CXTranslationUnitImpl {
   clang::cxstring::CXStringPool *StringPool;
   void *Diagnostics;
   void *OverridenCursorsPool;
-  clang::SimpleFormatContext *FormatContext;
-  unsigned FormatInMemoryUniqueId;
+  clang::index::CommentToXMLConverter *CommentToXML;
 };
 
 namespace clang {

Removed: cfe/trunk/tools/libclang/SimpleFormatContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/SimpleFormatContext.h?rev=194609&view=auto
==============================================================================
--- cfe/trunk/tools/libclang/SimpleFormatContext.h (original)
+++ cfe/trunk/tools/libclang/SimpleFormatContext.h (removed)
@@ -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





More information about the cfe-commits mailing list