juliehockett updated this revision to Diff 132306.
juliehockett marked 47 inline comments as done.
juliehockett added a comment.

1. Changing the traversal pattern from using `RecursiveASTVisitor` to using 
matchers instead. This will allow for a more flexible API (e.g. allowing access 
to individual nodes, rather than forcing all data on the user).
2. Templatizing lots of things. There was a lot of duplicated code.
3. Fixing comments

I'm going to take a stab at refactoring the serialization part of this next -- 
rather than keeping it all in memory and dumping it at the end, it should 
serialize as it goes and do some sort of reduce at the end. I'm currently 
thinking of writing it out to a file as it goes, and then reading and reducing 
from there -- thoughts?


https://reviews.llvm.org/D41102

Files:
  test/Tooling/clang-doc-basic.cpp
  test/Tooling/clang-doc-namespace.cpp
  test/Tooling/clang-doc-type.cpp
  tools/clang-doc/ClangDoc.cpp
  tools/clang-doc/ClangDoc.h
  tools/clang-doc/ClangDocReporter.cpp
  tools/clang-doc/ClangDocReporter.h
  tools/clang-doc/ClangDocYAML.h
  tools/clang-doc/tool/ClangDocMain.cpp

Index: tools/clang-doc/tool/ClangDocMain.cpp
===================================================================
--- tools/clang-doc/tool/ClangDocMain.cpp
+++ tools/clang-doc/tool/ClangDocMain.cpp
@@ -8,35 +8,44 @@
 //===----------------------------------------------------------------------===//
 
 #include "ClangDoc.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/Decl.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
 #include "clang/Driver/Options.h"
 #include "clang/Frontend/FrontendActions.h"
 #include "clang/Tooling/CommonOptionsParser.h"
 #include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/Process.h"
 #include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
 #include <string>
 
+using namespace clang::ast_matchers;
 using namespace clang;
 using namespace llvm;
 
 namespace {
 
-cl::OptionCategory ClangDocCategory("clang-doc options");
+static cl::OptionCategory ClangDocCategory("clang-doc options");
+
+static cl::opt<std::string>
+    OutDirectory("root", cl::desc("Directory for generated files."),
+                 cl::init("docs"), cl::cat(ClangDocCategory));
 
 static cl::opt<bool>
-    EmitLLVM("emit-llvm",
-             cl::desc("Output in LLVM bitstream format (default is YAML)."),
+    EmitYAML("emit-yaml",
+             cl::desc("Output in YAML format (default is clang-doc binary)."),
              cl::init(false), cl::cat(ClangDocCategory));
 
-static cl::opt<bool>
-   DumpResult("dump",
-            cl::desc("Dump results to stdout."),
-            cl::init(false), cl::cat(ClangDocCategory));
+static cl::opt<bool> DumpResult("dump", cl::desc("Dump results to stdout."),
+                                cl::init(false), cl::cat(ClangDocCategory));
 
-static cl::opt<bool>
-   OmitFilenames("omit-filenames",
-            cl::desc("Omit filenames in output."),
-            cl::init(false), cl::cat(ClangDocCategory));
+static cl::opt<bool> OmitFilenames("omit-filenames",
+                                   cl::desc("Omit filenames in output."),
+                                   cl::init(false), cl::cat(ClangDocCategory));
 
 static cl::opt<bool>
     DoxygenOnly("doxygen",
@@ -48,31 +57,73 @@
 int main(int argc, const char **argv) {
   sys::PrintStackTraceOnErrorSignal(argv[0]);
   tooling::CommonOptionsParser OptionsParser(argc, argv, ClangDocCategory);
-
-  clang::doc::OutFormat EmitFormat =
-      EmitLLVM ? doc::OutFormat::LLVM : doc::OutFormat::YAML;
-
-  doc::ClangDocReporter Reporter(OptionsParser.getSourcePathList(), OmitFilenames);
-  doc::ClangDocContext Context{EmitFormat};
+  std::error_code OK;
+
+  doc::OutFormat EmitFormat;
+  SmallString<128> IRFilePath;
+  sys::path::native(OutDirectory, IRFilePath);
+  std::string IRFilename;
+  if (EmitYAML) {
+    EmitFormat = doc::OutFormat::YAML;
+    sys::path::append(IRFilePath, "yaml");
+  } else {
+    EmitFormat = doc::OutFormat::BIN;
+    sys::path::append(IRFilePath, "bin");
+  }
+
+  std::error_code DirectoryStatus = sys::fs::create_directories(IRFilePath);
+  if (DirectoryStatus != OK) {
+    errs() << "Unable to create documentation directories.\n";
+    return 1;
+  }
+
+  std::unique_ptr<doc::ClangDocReporter> Reporter =
+      llvm::make_unique<doc::ClangDocReporter>(
+          OptionsParser.getSourcePathList(), OmitFilenames);
+  std::unique_ptr<MatchFinder> Finder = llvm::make_unique<MatchFinder>();
+
+  doc::ClangDocCallback NCallback(Reporter, "namespace");
+  DeclarationMatcher ND = namespaceDecl().bind("namespace");
+  Finder->addMatcher(ND, &NCallback);
+
+  doc::ClangDocCallback RCallback(Reporter, "record");
+  DeclarationMatcher RD = recordDecl().bind("record");
+  Finder->addMatcher(RD, &RCallback);
+
+  doc::ClangDocCallback ECallback(Reporter, "enum");
+  DeclarationMatcher ED = enumDecl().bind("enum");
+  Finder->addMatcher(ED, &ECallback);
+
+  doc::ClangDocCallback FCallback(Reporter, "function");
+  DeclarationMatcher FD =
+      functionDecl(unless(cxxMethodDecl())).bind("function");
+  Finder->addMatcher(FD, &FCallback);
+
+  doc::ClangDocCallback MCallback(Reporter, "method");
+  DeclarationMatcher MD = cxxMethodDecl().bind("method");
+  Finder->addMatcher(MD, &MCallback);
 
   tooling::ClangTool Tool(OptionsParser.getCompilations(),
                           OptionsParser.getSourcePathList());
 
   if (!DoxygenOnly)
     Tool.appendArgumentsAdjuster(tooling::getInsertArgumentAdjuster(
         "-fparse-all-comments", tooling::ArgumentInsertPosition::BEGIN));
 
-  doc::ClangDocActionFactory Factory(Context, Reporter);
+  doc::ClangDocAction ClangDocAction(std::move(Finder), Reporter);
 
   outs() << "Parsing codebase...\n";
-  int Status = Tool.run(&Factory);
+  int Status =
+      Tool.run(tooling::newFrontendActionFactory(&ClangDocAction).get());
   if (Status)
     return Status;
 
+  // TODO: Serialize each record as we see it, rather than at the end, followed
+  // by a reduce on the records to combine multiple declarations.
+  outs() << "Writing intermediate docs...\n";
   if (DumpResult)
-    Reporter.serialize(EmitFormat, outs());
-
-  outs() << "Writing docs...\n";
-  Reporter.serialize(EmitFormat, outs());
+    Reporter->serialize(EmitFormat, "");
+  else
+    Reporter->serialize(EmitFormat, IRFilePath);
   return 0;
 }
Index: tools/clang-doc/ClangDocYAML.h
===================================================================
--- tools/clang-doc/ClangDocYAML.h
+++ tools/clang-doc/ClangDocYAML.h
@@ -12,37 +12,15 @@
 
 #include "llvm/Support/YAMLTraits.h"
 
-LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::CommentInfo)
-LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::NamedType)
-LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::Location)
-LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::Pair<clang::doc::File>)
-LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::Pair<clang::doc::NamespaceInfo>)
-LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::Pair<clang::doc::TypeInfo>)
-LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::Pair<clang::doc::EnumInfo>)
-LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::Pair<clang::doc::FunctionInfo>)
+using namespace clang::doc;
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<CommentInfo>)
+LLVM_YAML_IS_SEQUENCE_VECTOR(NamedType)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Location)
 
 namespace llvm {
 namespace yaml {
 
-template <typename T> struct NormalizedMap {
-  NormalizedMap(IO &) {}
-  NormalizedMap(IO &, const StringMap<T> &Map) {
-    for (const auto &Entry : Map) {
-      clang::doc::Pair<T> Pair{Entry.getKeyData(), Entry.getValue()};
-      VectorMap.push_back(Pair);
-    }
-  }
-
-  StringMap<T> denormalize(IO &) {
-    StringMap<T> Map;
-    for (const auto &Pair : VectorMap)
-      Map[Pair.Key] = Pair.Value;
-    return Map;
-  }
-
-  std::vector<clang::doc::Pair<T>> VectorMap;
-};
-
 template <> struct ScalarEnumerationTraits<clang::AccessSpecifier> {
   static void enumeration(IO &io, clang::AccessSpecifier &value) {
     io.enumCase(value, "Public", clang::AccessSpecifier::AS_public);
@@ -62,152 +40,117 @@
   }
 };
 
-template <> struct MappingTraits<clang::doc::Pair<std::string>> {
-  static void mapping(IO &IO, clang::doc::Pair<std::string> &Pair) {
-    IO.mapOptional("Value", Pair.Value);
+template <> struct MappingTraits<Location> {
+  static void mapping(IO &IO, Location &Location) {
+    IO.mapRequired("LineNumber", Location.LineNumber);
+    IO.mapRequired("Filename", Location.Filename);
   }
 };
 
-template <> struct MappingTraits<clang::doc::Location> {
-  static void mapping(IO &IO, clang::doc::Location &Location) {
-    IO.mapOptional("LineNumber", Location.LineNumber);
-    IO.mapOptional("Filename", Location.Filename);
-  }
-};
-
-// TODO: uncomment description attrs
-template <> struct MappingTraits<clang::doc::Pair<clang::doc::NamespaceInfo>> {
-  static void mapping(IO &IO, clang::doc::Pair<clang::doc::NamespaceInfo> &Pair) {
-    if (!Pair.Value.isDefined)
+template <> struct MappingTraits<NamespaceInfo> {
+  static void mapping(IO &IO, NamespaceInfo &N) {
+    if (!N.isDefined)
       return;
-  MappingNormalization<NormalizedMap<clang::doc::FunctionInfo>,
-                         StringMap<clang::doc::FunctionInfo>>
-        functions(IO, Pair.Value.Functions);
-
-    IO.mapOptional("Qualified Name", Pair.Value.FullyQualifiedName);
-    IO.mapOptional("Name", Pair.Value.SimpleName);
-    IO.mapOptional("Namespace", Pair.Value.Namespace);
-    IO.mapOptional("Descriptions", Pair.Value.Descriptions);
-    IO.mapOptional("Locations", Pair.Value.Locations);
-    IO.mapOptional("Functions", functions->VectorMap);
+    IO.mapRequired("Qualified Name", N.FullyQualifiedName);
+    IO.mapRequired("Name", N.SimpleName);
+    IO.mapRequired("Namespace", N.Namespace);
+    IO.mapRequired("Descriptions", N.Descriptions);
+    IO.mapRequired("Locations", N.Locations);
   }
 };
 
-template <> struct MappingTraits<clang::doc::Pair<clang::doc::TypeInfo>> {
-  static void mapping(IO &IO, clang::doc::Pair<clang::doc::TypeInfo> &Pair) {
-    if (!Pair.Value.isDefined)
+template <> struct MappingTraits<TypeInfo> {
+  static void mapping(IO &IO, TypeInfo &T) {
+    if (!T.isDefined)
       return;
-
-    MappingNormalization<NormalizedMap<clang::doc::FunctionInfo>,
-                         StringMap<clang::doc::FunctionInfo>>
-        functions(IO, Pair.Value.Functions);
-        
-    IO.mapOptional("Qualified Name", Pair.Value.FullyQualifiedName);
-    IO.mapOptional("Name", Pair.Value.SimpleName);
-    IO.mapOptional("Namespace", Pair.Value.Namespace);
-    IO.mapOptional("Descriptions", Pair.Value.Descriptions);
-    IO.mapOptional("TagType", Pair.Value.TagType);
-    IO.mapOptional("Locations", Pair.Value.Locations);
-    IO.mapOptional("Functions", functions->VectorMap);
-    IO.mapOptional("DefinitionFile", Pair.Value.DefinitionFile);
-    IO.mapOptional("Members", Pair.Value.Members);
-    IO.mapOptional("Parents", Pair.Value.Parents);
-    IO.mapOptional("VirtualParents", Pair.Value.VirtualParents);
+    IO.mapRequired("Qualified Name", T.FullyQualifiedName);
+    IO.mapRequired("Name", T.SimpleName);
+    IO.mapRequired("Namespace", T.Namespace);
+    IO.mapRequired("Descriptions", T.Descriptions);
+    IO.mapRequired("TagType", T.TagType);
+    IO.mapRequired("Locations", T.Locations);
+    IO.mapRequired("DefinitionFile", T.DefinitionFile);
+    IO.mapRequired("Members", T.Members);
+    IO.mapRequired("Parents", T.Parents);
+    IO.mapRequired("VirtualParents", T.VirtualParents);
   }
 };
 
-template <> struct MappingTraits<clang::doc::Pair<clang::doc::EnumInfo>> {
-  static void mapping(IO &IO, clang::doc::Pair<clang::doc::EnumInfo> &Pair) {
-    if (!Pair.Value.isDefined)
+template <> struct MappingTraits<EnumInfo> {
+  static void mapping(IO &IO, EnumInfo &E) {
+    if (!E.isDefined)
       return;
-    IO.mapOptional("Qualified Name", Pair.Value.FullyQualifiedName);
-    IO.mapOptional("Name", Pair.Value.SimpleName);
-    IO.mapOptional("Namespace", Pair.Value.Namespace);
-    IO.mapOptional("Descriptions", Pair.Value.Descriptions);
-    IO.mapOptional("Locations", Pair.Value.Locations);
-    IO.mapOptional("DefinitionFile", Pair.Value.DefinitionFile);
-    IO.mapOptional("Scoped", Pair.Value.Scoped);
-    IO.mapOptional("Members", Pair.Value.Members);  
+    IO.mapRequired("Qualified Name", E.FullyQualifiedName);
+    IO.mapRequired("Name", E.SimpleName);
+    IO.mapRequired("Namespace", E.Namespace);
+    IO.mapRequired("Descriptions", E.Descriptions);
+    IO.mapRequired("Locations", E.Locations);
+    IO.mapRequired("DefinitionFile", E.DefinitionFile);
+    IO.mapRequired("Scoped", E.Scoped);
+    IO.mapRequired("Members", E.Members);
   }
 };
 
-template <> struct MappingTraits<clang::doc::NamedType> {
-  static void mapping(IO &IO, clang::doc::NamedType &NamedType) {
-    IO.mapOptional("Type", NamedType.Type);
-    IO.mapOptional("Name", NamedType.Name);
-    IO.mapOptional("Access", NamedType.Access);
+template <> struct MappingTraits<NamedType> {
+  static void mapping(IO &IO, NamedType &NamedType) {
+    IO.mapRequired("Type", NamedType.Type);
+    IO.mapRequired("Name", NamedType.Name);
+    IO.mapRequired("Access", NamedType.Access);
   }
 };
 
-template <> struct MappingTraits<clang::doc::Pair<clang::doc::FunctionInfo>> {
-  static void mapping(IO &IO,
-                      clang::doc::Pair<clang::doc::FunctionInfo> &Pair) {
-    if (!Pair.Value.isDefined)
+template <> struct MappingTraits<FunctionInfo> {
+  static void mapping(IO &IO, FunctionInfo &F) {
+    if (!F.isDefined)
       return;
-    IO.mapOptional("Mangled Name", Pair.Value.MangledName);
-    IO.mapOptional("Qualified Name", Pair.Value.FullyQualifiedName);
-    IO.mapOptional("Name", Pair.Value.SimpleName);
-    IO.mapOptional("Namespace", Pair.Value.Namespace);
-    IO.mapOptional("Descriptions", Pair.Value.Descriptions);
-    IO.mapOptional("Locations", Pair.Value.Locations);
-    IO.mapOptional("DefinitionFile", Pair.Value.DefinitionFile);
-    IO.mapOptional("Params", Pair.Value.Params);
-    IO.mapOptional("ReturnType", Pair.Value.ReturnType);
-    IO.mapOptional("Access", Pair.Value.Access);
+    IO.mapRequired("Mangled Name", F.MangledName);
+    IO.mapRequired("Qualified Name", F.FullyQualifiedName);
+    IO.mapRequired("Name", F.SimpleName);
+    IO.mapRequired("Namespace", F.Namespace);
+    IO.mapRequired("Descriptions", F.Descriptions);
+    IO.mapRequired("Locations", F.Locations);
+    IO.mapRequired("DefinitionFile", F.DefinitionFile);
+    IO.mapRequired("Params", F.Params);
+    IO.mapRequired("ReturnType", F.ReturnType);
+    IO.mapRequired("Access", F.Access);
   }
 };
 
-template <> struct MappingTraits<clang::doc::Pair<clang::doc::File>> {
-  static void mapping(IO &IO, clang::doc::Pair<clang::doc::File> &Pair) {
-    IO.mapOptional("Filename", Pair.Value.Filename);
-    IO.mapOptional("Description", Pair.Value.Description);
+template <> struct MappingTraits<File> {
+  static void mapping(IO &IO, File &F) {
+    IO.mapRequired("Filename", F.Filename);
+    IO.mapRequired("Description", F.Description);
   }
 };
 
-template <> struct MappingTraits<clang::doc::Documentation> {
-  static void mapping(IO &IO, clang::doc::Documentation &Docs) {
-    MappingNormalization<NormalizedMap<clang::doc::File>,
-                         StringMap<clang::doc::File>>
-        files(IO, Docs.Files);
-    MappingNormalization<NormalizedMap<clang::doc::NamespaceInfo>,
-                         StringMap<clang::doc::NamespaceInfo>>
-        namespaces(IO, Docs.Namespaces);
-    MappingNormalization<NormalizedMap<clang::doc::TypeInfo>,
-                          StringMap<clang::doc::TypeInfo>>
-        types(IO, Docs.Types);
-    MappingNormalization<NormalizedMap<clang::doc::EnumInfo>,
-                            StringMap<clang::doc::EnumInfo>>
-        enums(IO, Docs.Enums);
-
-    IO.mapOptional("Files", files->VectorMap);
-    IO.mapOptional("Namespaces", namespaces->VectorMap);
-    IO.mapOptional("Types", types->VectorMap);
-    IO.mapOptional("Enums", enums->VectorMap);
-  }
-};
+template <> struct MappingTraits<std::unique_ptr<CommentInfo>> {
 
-template <> struct MappingTraits<clang::doc::CommentInfo> {
-
-  static void mapping(IO &IO, clang::doc::CommentInfo &Info) {
-    IO.mapOptional("Kind", Info.Kind);
-    if (!Info.Text.empty())
-      IO.mapOptional("Text", Info.Text);
-    if (!Info.Name.empty())
-      IO.mapOptional("Name", Info.Name);
-    if (!Info.Direction.empty())
-      IO.mapOptional("Direction", Info.Direction);
-    if (!Info.ParamName.empty())
-      IO.mapOptional("ParamName", Info.ParamName);
-    if (!Info.CloseName.empty())
-      IO.mapOptional("CloseName", Info.CloseName);
-    if (Info.SelfClosing)
-      IO.mapOptional("SelfClosing", Info.SelfClosing);
-    if (Info.Explicit)
-      IO.mapOptional("Explicit", Info.Explicit);
-    IO.mapOptional("Args", Info.Args);
-    IO.mapOptional("Attrs", Info.Attrs);
-    IO.mapOptional("Position", Info.Position);
-    IO.mapOptional("Children", Info.Children);
+  static void mapping(IO &IO, std::unique_ptr<CommentInfo> &Info) {
+    if (!Info)
+      return;
+    IO.mapRequired("Kind", Info->Kind);
+    if (!Info->Text.empty())
+      IO.mapRequired("Text", Info->Text);
+    if (!Info->Name.empty())
+      IO.mapRequired("Name", Info->Name);
+    if (!Info->Direction.empty())
+      IO.mapRequired("Direction", Info->Direction);
+    if (!Info->ParamName.empty())
+      IO.mapRequired("ParamName", Info->ParamName);
+    if (!Info->CloseName.empty())
+      IO.mapRequired("CloseName", Info->CloseName);
+    if (Info->SelfClosing)
+      IO.mapRequired("SelfClosing", Info->SelfClosing);
+    if (Info->Explicit)
+      IO.mapRequired("Explicit", Info->Explicit);
+    if (!Info->Args.empty())
+      IO.mapRequired("Args", Info->Args);
+    if (!Info->Attrs.empty())
+      IO.mapRequired("Attrs", Info->Attrs);
+    if (!Info->Position.empty())
+      IO.mapRequired("Position", Info->Position);
+    if (!Info->Children.empty())
+      IO.mapRequired("Children", Info->Children);
   }
 };
 
Index: tools/clang-doc/ClangDocReporter.h
===================================================================
--- tools/clang-doc/ClangDocReporter.h
+++ tools/clang-doc/ClangDocReporter.h
@@ -1,4 +1,4 @@
-//===-- Doc.cpp - ClangDoc --------------------------------------*- C++ -*-===//
+//===-- ClangDocReporter.cpp - ClangDocReporter -----------------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -30,7 +30,10 @@
 namespace clang {
 namespace doc {
 
-enum class OutFormat { YAML, LLVM };
+/// Intermediate representations for the data gathered by the ClangDocReporter
+/// YAML indicates a YAML output format, and BIN indicates the clang-doc binary
+/// format.
+enum class OutFormat { YAML, BIN };
 
 // Info for named types (parameters, members).
 struct NamedType {
@@ -57,23 +60,23 @@
   llvm::SmallVector<NamedType, 4> Attrs;
   llvm::SmallVector<std::string, 4> Args;
   llvm::SmallVector<int, 4> Position;
-  std::vector<CommentInfo> Children;
+  std::vector<std::unique_ptr<CommentInfo>> Children;
 };
 
 /// A source file in the project.
 struct File {
   std::string Filename;
-  CommentInfo Description;
-  llvm::SmallVector<CommentInfo, 8> UnattachedComments;
+  std::unique_ptr<CommentInfo> Description;
+  llvm::SmallVector<std::unique_ptr<CommentInfo>, 8> UnattachedComments;
 };
 
 /// A base struct for Infos.
 struct Info {
   bool isDefined = false;
   std::string FullyQualifiedName;
   std::string SimpleName;
   std::string Namespace;
-  std::vector<CommentInfo> Descriptions;
+  std::vector<std::unique_ptr<CommentInfo>> Descriptions;
   llvm::SmallVector<Location, 2> Locations;
 };
 
@@ -88,7 +91,7 @@
 };
 
 struct NamespaceInfo : public Info {
-  llvm::StringMap<FunctionInfo> Functions;
+  llvm::StringMap<std::unique_ptr<FunctionInfo>> Functions;
 };
 
 // TODO: Expand to allow for documenting templating, inheritance access,
@@ -100,7 +103,7 @@
   llvm::SmallVector<NamedType, 8> Members;
   llvm::SmallVector<std::string, 8> Parents;
   llvm::SmallVector<std::string, 8> VirtualParents;
-  llvm::StringMap<FunctionInfo> Functions;
+  llvm::StringMap<std::unique_ptr<FunctionInfo>> Functions;
 };
 
 // TODO: Expand to allow for documenting templating.
@@ -114,37 +117,20 @@
 /// A struct encapsulating all documentation information for the project.
 struct Documentation {
   bool OmitFilenames = false;
-  llvm::StringMap<File> Files;
-  llvm::StringMap<NamespaceInfo> Namespaces;
-  llvm::StringMap<TypeInfo> Types;
-  llvm::StringMap<EnumInfo> Enums;
+  llvm::StringMap<std::unique_ptr<File>> Files;
+  llvm::StringMap<std::unique_ptr<NamespaceInfo>> Namespaces;
+  llvm::StringMap<std::unique_ptr<TypeInfo>> Types;
+  llvm::StringMap<std::unique_ptr<EnumInfo>> Enums;
   // TODO: Add functionality to include separate markdown pages.
 };
 
-/// Struct with a key and a value to allow for serialization.
-template <typename T> struct Pair {
-  std::string Key;
-  T Value;
-};
-
-class ClangDocReporter : public ConstCommentVisitor<ClangDocReporter> {
+class ClangDocCommentVisitor
+    : public ConstCommentVisitor<ClangDocCommentVisitor> {
 public:
-  ClangDocReporter() {}
-  ClangDocReporter(const std::vector<std::string> &Sources, bool OmitFilenames);
+  ClangDocCommentVisitor() {}
 
-  void addUnattachedComment(StringRef Filename, const CommentInfo &CI);
-  void addFile(StringRef Filename);
+  std::unique_ptr<CommentInfo> parseComment(const comments::Comment *C);
 
-  void createNamespaceInfo(const NamespaceDecl *D, const FullComment *C,
-                             int LineNumber, StringRef File);
-  void createTypeInfo(const RecordDecl *D, const FullComment *C, int LineNumber, StringRef File);
-  void createEnumInfo(const EnumDecl *D, const FullComment *C, int LineNumber, StringRef File);
-  void createFunctionInfo(const FunctionDecl *D, const FullComment *C,
-                        int LineNumber, StringRef File, StringRef MangledName);
-  void createMethodInfo(const CXXMethodDecl *D, const FullComment *C,
-                        int LineNumber, StringRef File, StringRef MangledName);
-                        
-  void parseFullComment(const FullComment *C, CommentInfo &CI);
   void visitTextComment(const TextComment *C);
   void visitInlineCommandComment(const InlineCommandComment *C);
   void visitHTMLStartTagComment(const HTMLStartTagComment *C);
@@ -156,32 +142,53 @@
   void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
   void visitVerbatimLineComment(const VerbatimLineComment *C);
 
+private:
+  StringRef getCommandName(unsigned CommandID) const;
+  bool isWhitespaceOnly(StringRef S) const;
+
+  CommentInfo *CurrentCI;
+};
+
+class ClangDocReporter {
+public:
+  ClangDocReporter() {}
+  ClangDocReporter(const std::vector<std::string> &Sources, bool OmitFilenames);
+
+  void addUnattachedComment(StringRef Filename, const FullComment *C);
+  void addFile(StringRef Filename);
   bool hasFile(StringRef Filename) const;
-  void serialize(clang::doc::OutFormat Format, llvm::raw_ostream &OS) const;
+  void serialize(clang::doc::OutFormat Format, StringRef RootDir);
+
+  template <class C>
+  void createInfoForDecl(const C *D, const FullComment *FC, StringRef Key,
+                         int LineNumber, StringRef File);
+  std::unique_ptr<CommentInfo> parseFullComment(const FullComment *C);
 
 private:
+  template <typename T, class C>
+  void createInfo(llvm::StringMap<std::unique_ptr<T>> &InfoMap, const C *D,
+                  const FullComment *FC, StringRef Key, int LineNumber,
+                  StringRef File);
+  template <typename T, class C>
+  void populateInfo(T &I, const C *D, StringRef Name, StringRef File);
+
   void addComment(Info &I, const FullComment *C);
   void addLocation(Info &I, int LineNumber, StringRef File) const;
-  
-  void populateBasicInfo(Info &I, StringRef Name, StringRef SimpleName, StringRef Namespace);
-  void populateTypeInfo(TypeInfo &I, const RecordDecl *D, StringRef Name, StringRef File);
-  void populateEnumInfo(EnumInfo &I, const EnumDecl *D, StringRef Name, StringRef File);
-  void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, StringRef Name, StringRef File, AccessSpecifier AS);
-
-  void parseComment(CommentInfo *CI, const comments::Comment *C);
+  void populateBasicInfo(Info &I, StringRef Name, StringRef SimpleName,
+                         StringRef Namespace);
   void parseFields(TypeInfo &I, const RecordDecl *D) const;
   void parseEnumerators(EnumInfo &I, const EnumDecl *D) const;
   void parseBases(TypeInfo &I, const CXXRecordDecl *D) const;
   void parseParameters(FunctionInfo &I, const FunctionDecl *D) const;
 
-  void serializeYAML(llvm::raw_ostream &OS) const;
-  void serializeLLVM(llvm::raw_ostream &OS) const;
+  template <typename T> void printMap(raw_ostream &OS, llvm::StringMap<T> &Map);
+  template <typename T>
+  void printMapPlusFunctions(raw_ostream &OS, llvm::StringMap<T> &Map);
+  void serializeYAML(StringRef RootDir);
+  void serializeBIN(StringRef RootDir);
 
-  const char *getCommandName(unsigned CommandID) const;
-  bool isWhitespaceOnly(StringRef S) const;
   std::string getParentNamespace(const DeclContext *D) const;
 
-  CommentInfo *CurrentCI;
   Documentation Docs;
 };
 
Index: tools/clang-doc/ClangDocReporter.cpp
===================================================================
--- tools/clang-doc/ClangDocReporter.cpp
+++ tools/clang-doc/ClangDocReporter.cpp
@@ -10,288 +10,211 @@
 #include "ClangDocReporter.h"
 #include "ClangDocYAML.h"
 #include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
 using clang::comments::FullComment;
 
 namespace clang {
 namespace doc {
 
-ClangDocReporter::ClangDocReporter(const std::vector<std::string> &Sources, bool OF) {
+ClangDocReporter::ClangDocReporter(const std::vector<std::string> &Sources,
+                                   bool OF) {
   for (const std::string &Path : Sources) {
     assert(sys::path::is_absolute(Path) && "clang-doc expects absolute paths.");
     addFile(Path);
   }
   // Create base namespace
-  NamespaceInfo I;
-  I.isDefined = true;
-  Docs.Namespaces[""] = I;
+  Docs.Namespaces[""] = llvm::make_unique<NamespaceInfo>();
   Docs.OmitFilenames = OF;
 }
 
 void ClangDocReporter::addUnattachedComment(StringRef Filename,
-                                            const CommentInfo &CI) {
-  Docs.Files[Filename].UnattachedComments.push_back(CI);
+                                            const FullComment *C) {
+  Docs.Files[Filename]->UnattachedComments.push_back(
+      std::move(parseFullComment(C)));
 }
 
 void ClangDocReporter::addFile(StringRef Filename) {
-  File F;
-  F.Filename = Filename;
-  Docs.Files.insert(std::make_pair(Filename, F));
-}
-
-void ClangDocReporter::createNamespaceInfo(const NamespaceDecl *D,
-                                             const FullComment *C,
-                                             int LineNumber, StringRef File) {
-  std::string Name = D->getQualifiedNameAsString();
-  llvm::StringMapIterator<NamespaceInfo> Pair = Docs.Namespaces.find(Name);
-  if (Pair == Docs.Namespaces.end()) {
-    NamespaceInfo I;
-    Docs.Namespaces[Name] = I;
-    populateBasicInfo(Docs.Namespaces[Name], Name, D->getNameAsString(), getParentNamespace(D));
-  }
-
-  addLocation(Docs.Namespaces[Name], LineNumber, File);
-  addComment(Docs.Namespaces[Name], C);
+  Docs.Files[Filename] = llvm::make_unique<File>();
+  Docs.Files[Filename]->Filename = Filename;
 }
 
-void ClangDocReporter::createTypeInfo(const RecordDecl *D, const FullComment *C,
-                                        int LineNumber, StringRef File) {
-
-  std::string Name = D->getQualifiedNameAsString();
-  llvm::StringMapIterator<TypeInfo> Pair = Docs.Types.find(Name);
-  if (Pair == Docs.Types.end()) {
-    TypeInfo I;
-    Docs.Types[Name] = I;
-  }
-    
-  if (D->isThisDeclarationADefinition()) 
-    populateTypeInfo(Docs.Types[Name], D, Name, File);
-  
-  addLocation(Docs.Types[Name], LineNumber, File);
-  addComment(Docs.Types[Name], C);
-}
-
-void ClangDocReporter::createEnumInfo(const EnumDecl *D, const FullComment *C,
-                                        int LineNumber, StringRef File) {
-  std::string Name = D->getQualifiedNameAsString();
-  llvm::StringMapIterator<EnumInfo> Pair = Docs.Enums.find(Name);
-  if (Pair == Docs.Enums.end()) {
-    EnumInfo I;
-    Docs.Enums[Name] = I;
-  }
-  
-  if (D->isThisDeclarationADefinition())
-    populateEnumInfo(Docs.Enums[Name], D, Name, File);
-
-  addLocation(Docs.Enums[Name], LineNumber, File);
-  addComment(Docs.Enums[Name], C);
+template <>
+void ClangDocReporter::populateInfo(NamespaceInfo &I, const NamespaceDecl *D,
+                                    StringRef Name, StringRef File) {
+  populateBasicInfo(I, Name, D->getNameAsString(), getParentNamespace(D));
 }
 
-void ClangDocReporter::createFunctionInfo(const FunctionDecl *D,
-                                            const FullComment *C, int LineNumber, StringRef File,
-                                            StringRef MangledName) {
-  std::string Namespace = getParentNamespace(D);
-  llvm::StringMapIterator<NamespaceInfo> NS = Docs.Namespaces.find(Namespace);
-  if (NS == Docs.Namespaces.end()) {
-    NamespaceInfo NI;;
-    NI.FullyQualifiedName = Namespace;
-    Docs.Namespaces[Namespace] = NI;
-  } 
-  
-  llvm::StringMapIterator<FunctionInfo> Pair = Docs.Namespaces[Namespace].Functions.find(MangledName);
-  if (Pair != Docs.Namespaces[Namespace].Functions.end()) {
-    FunctionInfo I;
-    Docs.Namespaces[Namespace].Functions[MangledName] = I;
-  }
-  
-  if (D->isThisDeclarationADefinition())
-    populateFunctionInfo(Docs.Namespaces[Namespace].Functions[MangledName], D, MangledName, File, clang::AccessSpecifier::AS_none);
-  
-  addLocation(Docs.Namespaces[Namespace].Functions[MangledName], LineNumber, File);
-  addComment(Docs.Namespaces[Namespace].Functions[MangledName], C);
+template <>
+void ClangDocReporter::populateInfo(TypeInfo &I, const RecordDecl *D,
+                                    StringRef Name, StringRef File) {
+  if (!D->isThisDeclarationADefinition())
+    return;
+  populateBasicInfo(I, Name, D->getNameAsString(), getParentNamespace(D));
+  I.TagType = D->getTagKind();
+  if (!Docs.OmitFilenames)
+    I.DefinitionFile = File;
+  if (const auto *CXXR = dyn_cast<CXXRecordDecl>(D))
+    parseBases(I, CXXR);
+  parseFields(I, D);
 }
 
-void ClangDocReporter::createMethodInfo(const CXXMethodDecl *D,
-                                            const FullComment *C, int LineNumber, StringRef File,
-                                            StringRef MangledName) {
-  std::string ParentName = D->getParent()->getQualifiedNameAsString();
-  llvm::StringMapIterator<TypeInfo> T = Docs.Types.find(ParentName);
-  if (T == Docs.Types.end()) {
-    TypeInfo TI;
-    TI.FullyQualifiedName = getParentNamespace(D);
-    Docs.Types[ParentName] = TI;
-  } 
-  
-  llvm::StringMapIterator<FunctionInfo> Pair = Docs.Types[ParentName].Functions.find(MangledName);
-  if (Pair != Docs.Types[ParentName].Functions.end()) {
-    FunctionInfo I;
-    Docs.Types[ParentName].Functions[MangledName] = I;
-  }
-  
-  if (D->isThisDeclarationADefinition())
-    populateFunctionInfo(Docs.Types[ParentName].Functions[MangledName], D, MangledName, File, D->getAccess());
-  
-  addLocation(Docs.Types[ParentName].Functions[MangledName], LineNumber, File);
-  addComment(Docs.Types[ParentName].Functions[MangledName], C);
+template <>
+void ClangDocReporter::populateInfo(FunctionInfo &I, const FunctionDecl *D,
+                                    StringRef Name, StringRef File) {
+  if (!D->isThisDeclarationADefinition())
+    return;
+  populateBasicInfo(I, D->getQualifiedNameAsString(), D->getNameAsString(),
+                    getParentNamespace(D));
+  I.MangledName = Name;
+  if (!Docs.OmitFilenames)
+    I.DefinitionFile = File;
+  I.ReturnType = D->getReturnType().getAsString();
+  I.Access = clang::AccessSpecifier::AS_none;
+  parseParameters(I, D);
 }
 
-void ClangDocReporter::parseFullComment(const FullComment *C, CommentInfo &CI) {
-  parseComment(&CI, C);
+template <>
+void ClangDocReporter::populateInfo(FunctionInfo &I, const CXXMethodDecl *D,
+                                    StringRef Name, StringRef File) {
+  if (!D->isThisDeclarationADefinition())
+    return;
+  populateBasicInfo(I, D->getQualifiedNameAsString(), D->getNameAsString(),
+                    getParentNamespace(D));
+  I.MangledName = Name;
+  if (!Docs.OmitFilenames)
+    I.DefinitionFile = File;
+  I.ReturnType = D->getReturnType().getAsString();
+  I.Access = D->getAccess();
+  parseParameters(I, D);
 }
 
-void ClangDocReporter::visitTextComment(const TextComment *C) {
-  if (!isWhitespaceOnly(C->getText()))
-    CurrentCI->Text = C->getText();
+template <>
+void ClangDocReporter::populateInfo(EnumInfo &I, const EnumDecl *D,
+                                    StringRef Name, StringRef File) {
+  if (!D->isThisDeclarationADefinition())
+    return;
+  populateBasicInfo(I, Name, D->getNameAsString(), getParentNamespace(D));
+  if (!Docs.OmitFilenames)
+    I.DefinitionFile = File;
+  I.Scoped = D->isScoped();
+  parseEnumerators(I, D);
 }
 
-void ClangDocReporter::visitInlineCommandComment(
-    const InlineCommandComment *C) {
-  CurrentCI->Name = getCommandName(C->getCommandID());
-  for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
-    CurrentCI->Args.push_back(C->getArgText(i));
+template <>
+void ClangDocReporter::createInfoForDecl(const EnumDecl *D,
+                                         const FullComment *FC, StringRef Key,
+                                         int LineNumber, StringRef File) {
+  createInfo<EnumInfo, EnumDecl>(Docs.Enums, D, FC, Key, LineNumber, File);
 }
 
-void ClangDocReporter::visitHTMLStartTagComment(const HTMLStartTagComment *C) {
-  CurrentCI->Name = C->getTagName();
-  CurrentCI->SelfClosing = C->isSelfClosing();
-  for (unsigned i = 0, e = C->getNumAttrs(); i < e; ++i) {
-    const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
-    NamedType T{Attr.Name, Attr.Value, clang::AccessSpecifier::AS_none};
-    CurrentCI->Attrs.push_back(T);
-  }
+template <>
+void ClangDocReporter::createInfoForDecl(const RecordDecl *D,
+                                         const FullComment *FC, StringRef Key,
+                                         int LineNumber, StringRef File) {
+  createInfo<TypeInfo, RecordDecl>(Docs.Types, D, FC, Key, LineNumber, File);
 }
 
-void ClangDocReporter::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
-  CurrentCI->Name = C->getTagName();
-  CurrentCI->SelfClosing = true;
-}
-
-void ClangDocReporter::visitBlockCommandComment(const BlockCommandComment *C) {
-  CurrentCI->Name = getCommandName(C->getCommandID());
-  for (unsigned i = 0, e = C->getNumArgs(); i < e; ++i)
-    CurrentCI->Args.push_back(C->getArgText(i));
+template <>
+void ClangDocReporter::createInfoForDecl(const NamespaceDecl *D,
+                                         const FullComment *FC, StringRef Key,
+                                         int LineNumber, StringRef File) {
+  createInfo<NamespaceInfo, NamespaceDecl>(Docs.Namespaces, D, FC, Key,
+                                           LineNumber, File);
 }
 
-void ClangDocReporter::visitParamCommandComment(const ParamCommandComment *C) {
-  CurrentCI->Direction =
-      ParamCommandComment::getDirectionAsString(C->getDirection());
-  CurrentCI->Explicit = C->isDirectionExplicit();
-  if (C->hasParamName() && C->isParamIndexValid())
-    CurrentCI->ParamName = C->getParamNameAsWritten();
+template <>
+void ClangDocReporter::createInfoForDecl(const FunctionDecl *D,
+                                         const FullComment *FC, StringRef Key,
+                                         int LineNumber, StringRef File) {
+  std::string Namespace = getParentNamespace(D);
+  llvm::StringMapIterator<std::unique_ptr<NamespaceInfo>> NS =
+      Docs.Namespaces.find(Namespace);
+  if (NS == Docs.Namespaces.end()) {
+    Docs.Namespaces[Namespace] = llvm::make_unique<NamespaceInfo>();
+    Docs.Namespaces[Namespace]->FullyQualifiedName = Namespace;
+  }
+  createInfo<FunctionInfo, FunctionDecl>(Docs.Namespaces[Namespace]->Functions,
+                                         D, FC, Key, LineNumber, File);
 }
 
-void ClangDocReporter::visitTParamCommandComment(
-    const TParamCommandComment *C) {
-  if (C->hasParamName() && C->isPositionValid())
-    CurrentCI->ParamName = C->getParamNameAsWritten();
-
-  if (C->isPositionValid()) {
-    for (unsigned i = 0, e = C->getDepth(); i < e; ++i)
-      CurrentCI->Position.push_back(C->getIndex(i));
+template <>
+void ClangDocReporter::createInfoForDecl(const CXXMethodDecl *D,
+                                         const FullComment *FC, StringRef Key,
+                                         int LineNumber, StringRef File) {
+  std::string ParentName = D->getParent()->getQualifiedNameAsString();
+  llvm::StringMapIterator<std::unique_ptr<TypeInfo>> T =
+      Docs.Types.find(ParentName);
+  if (T == Docs.Types.end()) {
+    Docs.Types[ParentName] = llvm::make_unique<TypeInfo>();
+    Docs.Types[ParentName]->FullyQualifiedName = getParentNamespace(D);
   }
+  createInfo<FunctionInfo, CXXMethodDecl>(Docs.Types[ParentName]->Functions, D,
+                                          FC, Key, LineNumber, File);
 }
 
-void ClangDocReporter::visitVerbatimBlockComment(
-    const VerbatimBlockComment *C) {
-  CurrentCI->Name = getCommandName(C->getCommandID());
-  CurrentCI->CloseName = C->getCloseName();
-}
+template <typename T, class C>
+void ClangDocReporter::createInfo(StringMap<std::unique_ptr<T>> &InfoMap,
+                                  const C *D, const FullComment *FC,
+                                  StringRef Key, int LineNumber,
+                                  StringRef File) {
+  llvm::StringMapIterator<std::unique_ptr<T>> Pair = InfoMap.find(Key);
+  if (Pair == InfoMap.end())
+    InfoMap[Key] = llvm::make_unique<T>();
 
-void ClangDocReporter::visitVerbatimBlockLineComment(
-    const VerbatimBlockLineComment *C) {
-  if (!isWhitespaceOnly(C->getText()))
-    CurrentCI->Text = C->getText();
+  populateInfo(*InfoMap[Key], D, Key, File);
+  addLocation(*InfoMap[Key], LineNumber, File);
+  addComment(*InfoMap[Key], FC);
 }
 
-void ClangDocReporter::visitVerbatimLineComment(const VerbatimLineComment *C) {
-  if (!isWhitespaceOnly(C->getText()))
-    CurrentCI->Text = C->getText();
+std::unique_ptr<CommentInfo>
+ClangDocReporter::parseFullComment(const FullComment *C) {
+  ClangDocCommentVisitor Visitor;
+  return Visitor.parseComment(C);
 }
 
 bool ClangDocReporter::hasFile(StringRef Filename) const {
   return Docs.Files.find(Filename) != Docs.Files.end();
 }
 
-void ClangDocReporter::serialize(OutFormat Format, raw_ostream &OS) const {
-  Format == clang::doc::OutFormat::LLVM ? serializeLLVM(OS) : serializeYAML(OS);
+void ClangDocReporter::serialize(OutFormat Format, StringRef RootDir) {
+  Format == clang::doc::OutFormat::BIN ? serializeBIN(RootDir)
+                                       : serializeYAML(RootDir);
 }
 
 void ClangDocReporter::addComment(Info &I, const FullComment *C) {
   if (!C)
     return;
-  CommentInfo CI;
-  parseFullComment(C, CI);
-  I.Descriptions.push_back(CI);
+  I.Descriptions.push_back(std::move(parseFullComment(C)));
 }
 
-void ClangDocReporter::addLocation(Info &I, int LineNumber, StringRef File) const {
+void ClangDocReporter::addLocation(Info &I, int LineNumber,
+                                   StringRef File) const {
   Location L;
   L.LineNumber = LineNumber;
   if (!Docs.OmitFilenames)
     L.Filename = File;
   I.Locations.push_back(L);
 }
 
-void ClangDocReporter::populateBasicInfo(Info &I, StringRef Name, StringRef SimpleName, StringRef Namespace) {
+void ClangDocReporter::populateBasicInfo(Info &I, StringRef Name,
+                                         StringRef SimpleName,
+                                         StringRef Namespace) {
   I.FullyQualifiedName = Name;
   I.SimpleName = SimpleName;
   I.Namespace = Namespace;
   I.isDefined = true;
 }
 
-void ClangDocReporter::populateTypeInfo(TypeInfo &I, const RecordDecl * D, StringRef Name, StringRef File) {
-  populateBasicInfo(I, Name, D->getNameAsString(), getParentNamespace(D));
-  I.TagType = D->getTagKind();
-  if (!Docs.OmitFilenames)
-    I.DefinitionFile = File;
-  if (const auto *CXXR = dyn_cast<CXXRecordDecl>(D))
-    parseBases(I, CXXR);
-  parseFields(I, D);
-}
-
-void ClangDocReporter::populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, StringRef Name, StringRef File, AccessSpecifier AS) {
-  populateBasicInfo(I, D->getQualifiedNameAsString(), D->getNameAsString(), getParentNamespace(D));
-  I.MangledName = Name;
-  if (!Docs.OmitFilenames)
-    I.DefinitionFile = File;
-  I.ReturnType = D->getReturnType().getAsString();
-  I.Access = AS;
-  parseParameters(I, D);
-}
-
-void ClangDocReporter::populateEnumInfo(EnumInfo &I, const EnumDecl *D, StringRef Name, StringRef File) {
-  populateBasicInfo(I, Name, D->getNameAsString(), getParentNamespace(D));
-  if (!Docs.OmitFilenames)
-    I.DefinitionFile = File;
-  I.Scoped = D->isScoped();
-  parseEnumerators(Docs.Enums[Name], D);
-}
-
-void ClangDocReporter::parseComment(CommentInfo *CI,
-                                    const comments::Comment *C) {
-  CurrentCI = CI;
-  CI->Kind = C->getCommentKindName();
-  ConstCommentVisitor<ClangDocReporter>::visit(C);
-  for (comments::Comment *Child :
-       make_range(C->child_begin(), C->child_end())) {
-    CommentInfo ChildCI;
-    parseComment(&ChildCI, Child);
-    CI->Children.push_back(ChildCI);
-  }
-}
-
 void ClangDocReporter::parseFields(TypeInfo &I, const RecordDecl *D) const {
   for (const FieldDecl *F : D->fields()) {
     NamedType N;
     N.Type = F->getTypeSourceInfo()->getType().getAsString();
     N.Name = F->getQualifiedNameAsString();
-    if (const auto *M = dyn_cast<CXXMethodDecl>(D))
-      N.Access = M->getAccess();
-    else 
-      N.Access = clang::AccessSpecifier::AS_none;
+    // FIXME: Set Access to the appropriate value.
+    N.Access = clang::AccessSpecifier::AS_none;
     I.Members.push_back(N);
   }
 }
@@ -318,40 +241,191 @@
 
 void ClangDocReporter::parseBases(TypeInfo &I, const CXXRecordDecl *D) const {
   for (const CXXBaseSpecifier &B : D->bases()) {
-    if (!B.isVirtual()) I.Parents.push_back(B.getType().getAsString());
+    if (!B.isVirtual())
+      I.Parents.push_back(B.getType().getAsString());
   }
   for (const CXXBaseSpecifier &B : D->vbases())
     I.VirtualParents.push_back(B.getType().getAsString());
 }
 
-void ClangDocReporter::serializeYAML(raw_ostream &OS) const {
-  yaml::Output Output(OS);
-  Documentation NonConstValue = Docs;
-  Output << NonConstValue;
+template <typename T>
+void ClangDocReporter::printMap(raw_ostream &OS, StringMap<T> &Map) {
+  yaml::Output YOut(OS);
+  for (const auto &I : Map)
+    YOut << *(I.second);
 }
 
-void ClangDocReporter::serializeLLVM(raw_ostream &OS) const {
-  // TODO: Implement.
-  OS << "Not yet implemented.\n";
+template <typename T>
+void ClangDocReporter::printMapPlusFunctions(raw_ostream &OS,
+                                             StringMap<T> &Map) {
+  yaml::Output YOut(OS);
+  for (const auto &I : Map) {
+    YOut << *(I.second);
+    for (const auto &F : I.second->Functions)
+      YOut << *(F.second);
+  }
 }
 
-const char *ClangDocReporter::getCommandName(unsigned CommandID) const {
-  const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
-  if (Info)
-    return Info->Name;
-  // TODO: Add parsing for \file command.
-  return "<not a builtin command>";
+void ClangDocReporter::serializeYAML(StringRef RootDir) {
+  if (RootDir.empty()) {
+    printMap(outs(), Docs.Files);
+    printMapPlusFunctions(outs(), Docs.Namespaces);
+    printMapPlusFunctions(outs(), Docs.Types);
+    printMap(outs(), Docs.Enums);
+    return;
+  }
+  std::error_code OK;
+  std::error_code OutErrorInfo;
+  SmallString<128> FilePath;
+
+  sys::path::native(RootDir, FilePath);
+  sys::path::append(FilePath, "files.yaml");
+  raw_fd_ostream FileOS(FilePath, OutErrorInfo, sys::fs::F_None);
+  if (OutErrorInfo != OK) {
+    errs() << OutErrorInfo.message();
+    errs() << " Error opening documentation file.\n";
+    return;
+  }
+  printMap(FileOS, Docs.Files);
+
+  sys::path::native(RootDir, FilePath);
+  sys::path::append(FilePath, "namespaces.yaml");
+  raw_fd_ostream NamespaceOS(FilePath, OutErrorInfo, sys::fs::F_None);
+  if (OutErrorInfo != OK) {
+    errs() << "Error opening documentation file.\n";
+    return;
+  }
+  printMapPlusFunctions(NamespaceOS, Docs.Namespaces);
+
+  sys::path::native(RootDir, FilePath);
+  sys::path::append(FilePath, "types.yaml");
+  raw_fd_ostream TypeOS(FilePath, OutErrorInfo, sys::fs::F_None);
+  if (OutErrorInfo != OK) {
+    errs() << "Error opening documentation file.\n";
+    return;
+  }
+  printMapPlusFunctions(TypeOS, Docs.Types);
+
+  sys::path::native(RootDir, FilePath);
+  sys::path::append(FilePath, "enums.yaml");
+  raw_fd_ostream EnumOS(FilePath, OutErrorInfo, sys::fs::F_None);
+  if (OutErrorInfo != OK) {
+    errs() << "Error opening documentation file.\n";
+    return;
+  }
+  printMap(EnumOS, Docs.Enums);
 }
 
-bool ClangDocReporter::isWhitespaceOnly(StringRef S) const {
-  return S.find_first_not_of(" \t\n\v\f\r") == std::string::npos || S.empty();
+void ClangDocReporter::serializeBIN(StringRef RootDir) {
+  // TODO: Implement.
+  outs() << "Not yet implemented.\n";
 }
 
 std::string ClangDocReporter::getParentNamespace(const DeclContext *D) const {
   if (const auto *N = dyn_cast<NamedDecl>(D->getParent()))
     return N->getQualifiedNameAsString();
   return "";
 }
 
+// TODO: Remove raw pointer to CurrentCI.
+std::unique_ptr<CommentInfo>
+ClangDocCommentVisitor::parseComment(const comments::Comment *C) {
+  std::unique_ptr<CommentInfo> RootCI = llvm::make_unique<CommentInfo>();
+  RootCI->Kind = C->getCommentKindName();
+  CurrentCI = RootCI.get();
+  ConstCommentVisitor<ClangDocCommentVisitor>::visit(C);
+  for (comments::Comment *Child :
+       make_range(C->child_begin(), C->child_end())) {
+    RootCI->Children.push_back(std::move(parseComment(Child)));
+  }
+  return RootCI;
+}
+
+void ClangDocCommentVisitor::visitTextComment(const TextComment *C) {
+  if (!isWhitespaceOnly(C->getText()))
+    CurrentCI->Text = C->getText();
+}
+
+void ClangDocCommentVisitor::visitInlineCommandComment(
+    const InlineCommandComment *C) {
+  CurrentCI->Name = getCommandName(C->getCommandID());
+  for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
+    CurrentCI->Args.push_back(C->getArgText(i));
+}
+
+void ClangDocCommentVisitor::visitHTMLStartTagComment(
+    const HTMLStartTagComment *C) {
+  CurrentCI->Name = C->getTagName();
+  CurrentCI->SelfClosing = C->isSelfClosing();
+  for (unsigned i = 0, e = C->getNumAttrs(); i < e; ++i) {
+    const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
+    CurrentCI->Attrs.emplace_back(
+        NamedType{Attr.Name, Attr.Value, clang::AccessSpecifier::AS_none});
+  }
+}
+
+void ClangDocCommentVisitor::visitHTMLEndTagComment(
+    const HTMLEndTagComment *C) {
+  CurrentCI->Name = C->getTagName();
+  CurrentCI->SelfClosing = true;
+}
+
+void ClangDocCommentVisitor::visitBlockCommandComment(
+    const BlockCommandComment *C) {
+  CurrentCI->Name = getCommandName(C->getCommandID());
+  for (unsigned i = 0, e = C->getNumArgs(); i < e; ++i)
+    CurrentCI->Args.push_back(C->getArgText(i));
+}
+
+void ClangDocCommentVisitor::visitParamCommandComment(
+    const ParamCommandComment *C) {
+  CurrentCI->Direction =
+      ParamCommandComment::getDirectionAsString(C->getDirection());
+  CurrentCI->Explicit = C->isDirectionExplicit();
+  if (C->hasParamName() && C->isParamIndexValid())
+    CurrentCI->ParamName = C->getParamNameAsWritten();
+}
+
+void ClangDocCommentVisitor::visitTParamCommandComment(
+    const TParamCommandComment *C) {
+  if (C->hasParamName() && C->isPositionValid())
+    CurrentCI->ParamName = C->getParamNameAsWritten();
+
+  if (C->isPositionValid()) {
+    for (unsigned i = 0, e = C->getDepth(); i < e; ++i)
+      CurrentCI->Position.push_back(C->getIndex(i));
+  }
+}
+
+void ClangDocCommentVisitor::visitVerbatimBlockComment(
+    const VerbatimBlockComment *C) {
+  CurrentCI->Name = getCommandName(C->getCommandID());
+  CurrentCI->CloseName = C->getCloseName();
+}
+
+void ClangDocCommentVisitor::visitVerbatimBlockLineComment(
+    const VerbatimBlockLineComment *C) {
+  if (!isWhitespaceOnly(C->getText()))
+    CurrentCI->Text = C->getText();
+}
+
+void ClangDocCommentVisitor::visitVerbatimLineComment(
+    const VerbatimLineComment *C) {
+  if (!isWhitespaceOnly(C->getText()))
+    CurrentCI->Text = C->getText();
+}
+
+StringRef ClangDocCommentVisitor::getCommandName(unsigned CommandID) const {
+  const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
+  if (Info)
+    return Info->Name;
+  // TODO: Add parsing for \file command.
+  return "<not a builtin command>";
+}
+
+bool ClangDocCommentVisitor::isWhitespaceOnly(StringRef S) const {
+  return S.find_first_not_of(" \t\n\v\f\r") == std::string::npos;
+}
+
 } // namespace doc
 } // namespace clang
Index: tools/clang-doc/ClangDoc.h
===================================================================
--- tools/clang-doc/ClangDoc.h
+++ tools/clang-doc/ClangDoc.h
@@ -14,81 +14,81 @@
 #include "clang/AST/AST.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/Comment.h"
+#include "clang/AST/Mangle.h"
 #include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
 #include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendActions.h"
 #include "clang/Tooling/Tooling.h"
 #include <string>
 #include <vector>
 
+using namespace clang::ast_matchers;
+
 namespace clang {
 namespace doc {
 
-// A Context which contains extra options which are used in ClangMoveTool.
-struct ClangDocContext {
-  // Which format in which to emit representation.
-  OutFormat EmitFormat;
-};
-
-class ClangDocVisitor : public RecursiveASTVisitor<ClangDocVisitor> {
+/// Callback function for matcher.
+/// Parses each match and sends it along to the reporter for serialization.
+class ClangDocCallback : public MatchFinder::MatchCallback {
 public:
-  explicit ClangDocVisitor(ASTContext *Ctx, ClangDocReporter &Reporter)
-      : Context(Ctx), Manager(Ctx->getSourceManager()),
-        MC(Ctx->createMangleContext()), Reporter(Reporter) {}
+  ClangDocCallback(std::unique_ptr<ClangDocReporter> &Reporter,
+                   StringRef BoundName)
+      : Reporter(Reporter), BoundName(BoundName) {}
 
-  bool VisitTagDecl(const TagDecl *D);
-  bool VisitNamespaceDecl(const NamespaceDecl *D);
-  bool VisitFunctionDecl(const FunctionDecl *D);
+  virtual void run(const MatchFinder::MatchResult &Result) override;
   void parseUnattachedComments();
 
 private:
+  template <class T>
+  void processMatchedDecl(const T *D, const MatchFinder::MatchResult &Result);
+
   bool isUnparsed(SourceLocation Loc) const;
   int getLine(const Decl *D) const;
-  std::string getFile(const Decl *D) const;
-  comments::FullComment* getComment(const Decl *D);
-  std::string mangleName(const FunctionDecl *D);
+  StringRef getFile(const Decl *D) const;
+  comments::FullComment *getComment(const Decl *D);
+  std::string mangleName(const FunctionDecl *D) const;
 
   ASTContext *Context;
-  SourceManager &Manager;
-  MangleContext *MC;
-  ClangDocReporter &Reporter;
+  mutable MangleContext *MC;
+  std::unique_ptr<ClangDocReporter> &Reporter;
+  StringRef BoundName;
 };
 
+/// AST consumer for the clang-doc action.
+/// Runs the given matchers on the TU, triggering the callback for each match.
 class ClangDocConsumer : public clang::ASTConsumer {
 public:
-  explicit ClangDocConsumer(ASTContext *Ctx, ClangDocReporter &Reporter)
-      : Visitor(Ctx, Reporter), Reporter(Reporter) {}
-
-  virtual void HandleTranslationUnit(clang::ASTContext &Context);
+  explicit ClangDocConsumer(std::unique_ptr<ast_matchers::MatchFinder> Finder,
+                            std::unique_ptr<ClangDocReporter> &Reporter)
+      : Finder(std::move(Finder)), Reporter(Reporter) {}
 
-private:
-  ClangDocVisitor Visitor;
-  ClangDocReporter &Reporter;
-};
-
-class ClangDocAction : public clang::ASTFrontendAction {
-public:
-  ClangDocAction(ClangDocReporter &Reporter) : Reporter(Reporter) {}
-
-  virtual std::unique_ptr<clang::ASTConsumer>
-  CreateASTConsumer(clang::CompilerInstance &C, llvm::StringRef InFile);
+  virtual void HandleTranslationUnit(clang::ASTContext &Context) {
+    Finder->matchAST(Context);
+  }
 
 private:
-  ClangDocReporter &Reporter;
+  std::unique_ptr<ast_matchers::MatchFinder> Finder;
+  std::unique_ptr<ClangDocReporter> &Reporter;
 };
 
-class ClangDocActionFactory : public tooling::FrontendActionFactory {
+/// Frontend action to initiate a clang-doc run on a source file.
+class ClangDocAction {
 public:
-  ClangDocActionFactory(ClangDocContext &Ctx, ClangDocReporter &Reporter)
-      : Context(Ctx), Reporter(Reporter) {}
+  ClangDocAction(std::unique_ptr<ast_matchers::MatchFinder> Finder,
+                 std::unique_ptr<ClangDocReporter> &Reporter)
+      : Finder(std::move(Finder)), Reporter(Reporter) {}
 
-  clang::FrontendAction *create() override {
-    return new ClangDocAction(Reporter);
+  std::unique_ptr<clang::ASTConsumer> newASTConsumer() {
+    return llvm::make_unique<ClangDocConsumer>(std::move(Finder), Reporter);
   }
 
 private:
-  ClangDocContext &Context;
-  ClangDocReporter &Reporter;
+  std::unique_ptr<ast_matchers::MatchFinder> Finder;
+  std::unique_ptr<ClangDocReporter> &Reporter;
 };
 
 } // namespace doc
Index: tools/clang-doc/ClangDoc.cpp
===================================================================
--- tools/clang-doc/ClangDoc.cpp
+++ tools/clang-doc/ClangDoc.cpp
@@ -8,56 +8,64 @@
 //===----------------------------------------------------------------------===//
 
 #include "ClangDoc.h"
+#include "clang/AST/AST.h"
 #include "clang/AST/Comment.h"
 #include "clang/AST/Mangle.h"
-#include "clang/Frontend/CompilerInstance.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
 
 using namespace clang;
+using namespace clang::ast_matchers;
 using namespace clang::tooling;
 using namespace llvm;
 
 namespace clang {
 namespace doc {
 
-bool ClangDocVisitor::VisitTagDecl(const TagDecl *D) {
+template <typename T>
+void ClangDocCallback::processMatchedDecl(
+    const T *D, const MatchFinder::MatchResult &Result) {
   if (!isUnparsed(D->getLocation()))
-    return true;
-
-  if (const auto *E = dyn_cast<EnumDecl>(D)) {
-    Reporter.createEnumInfo(E, getComment(E), getLine(E), getFile(E));
-    return true;
-  }
-  if (const auto *R = dyn_cast<RecordDecl>(D)) {
-    Reporter.createTypeInfo(R, getComment(R), getLine(R), getFile(R));
-    return true;
-  }
-  
-  // Error?
-  return true;
+    return;
+  Reporter->createInfoForDecl(D, getComment(D), D->getQualifiedNameAsString(),
+                              getLine(D), getFile(D));
 }
 
-bool ClangDocVisitor::VisitNamespaceDecl(const NamespaceDecl *D) {
+template <>
+void ClangDocCallback::processMatchedDecl(
+    const CXXMethodDecl *D, const MatchFinder::MatchResult &Result) {
+  MC = Context->createMangleContext();
   if (!isUnparsed(D->getLocation()))
-    return true;
-  Reporter.createNamespaceInfo(D, getComment(D), getLine(D), getFile(D));
-  return true;
+    return;
+  Reporter->createInfoForDecl(D, getComment(D), mangleName(D), getLine(D),
+                              getFile(D));
 }
 
-bool ClangDocVisitor::VisitFunctionDecl(const FunctionDecl *D) {
+template <>
+void ClangDocCallback::processMatchedDecl(
+    const FunctionDecl *D, const MatchFinder::MatchResult &Result) {
+  MC = Context->createMangleContext();
   if (!isUnparsed(D->getLocation()))
-    return true;
-  if (const auto *C = dyn_cast<CXXMethodDecl>(D)) {
-    Reporter.createMethodInfo(C, getComment(C), getLine(C), getFile(C), 
-                                  mangleName(C));
-    return true;
-  }
-  
-  Reporter.createFunctionInfo(D, getComment(D), getLine(D), getFile(D), 
-                                mangleName(D));
-  return true;
+    return;
+  Reporter->createInfoForDecl(D, getComment(D), mangleName(D), getLine(D),
+                              getFile(D));
 }
 
-comments::FullComment *ClangDocVisitor::getComment(const Decl *D) {
+void ClangDocCallback::run(const MatchFinder::MatchResult &Result) {
+  Context = Result.Context;
+  if (const auto *D = Result.Nodes.getNodeAs<NamespaceDecl>(BoundName))
+    processMatchedDecl(D, Result);
+  else if (const auto *D = Result.Nodes.getNodeAs<RecordDecl>(BoundName))
+    processMatchedDecl(D, Result);
+  else if (const auto *D = Result.Nodes.getNodeAs<EnumDecl>(BoundName))
+    processMatchedDecl(D, Result);
+  else if (const auto *D = Result.Nodes.getNodeAs<CXXMethodDecl>(BoundName))
+    processMatchedDecl(D, Result);
+  else if (const auto *D = Result.Nodes.getNodeAs<FunctionDecl>(BoundName))
+    processMatchedDecl(D, Result);
+}
+
+comments::FullComment *ClangDocCallback::getComment(const Decl *D) {
   RawComment *Comment = Context->getRawCommentForDeclNoCache(D);
 
   // FIXME: Move setAttached to the initial comment parsing.
@@ -68,59 +76,51 @@
   return nullptr;
 }
 
-int ClangDocVisitor::getLine(const Decl *D) const {
-  PresumedLoc PLoc = Manager.getPresumedLoc(D->getLocStart());
-  return PLoc.getLine();
+int ClangDocCallback::getLine(const Decl *D) const {
+  return Context->getSourceManager().getPresumedLoc(D->getLocStart()).getLine();
 }
 
-std::string ClangDocVisitor::getFile(const Decl *D) const {
-  PresumedLoc PLoc = Manager.getPresumedLoc(D->getLocStart());
-  return PLoc.getFilename();
+StringRef ClangDocCallback::getFile(const Decl *D) const {
+  return Context->getSourceManager()
+      .getPresumedLoc(D->getLocStart())
+      .getFilename();
 }
 
-void ClangDocVisitor::parseUnattachedComments() {
+void ClangDocCallback::parseUnattachedComments() {
   for (RawComment *Comment : Context->getRawCommentList().getComments()) {
     if (!isUnparsed(Comment->getLocStart()) || Comment->isAttached())
       continue;
-    CommentInfo CI;
-    Reporter.parseFullComment(Comment->parse(*Context, nullptr, nullptr), CI);
-    Reporter.addUnattachedComment(Manager.getFilename(Comment->getLocStart()),
-                                  CI);
+    Reporter->addUnattachedComment(
+        Context->getSourceManager().getFilename(Comment->getLocStart()),
+        Comment->parse(*Context, nullptr, nullptr));
   }
 }
 
-bool ClangDocVisitor::isUnparsed(SourceLocation Loc) const {
+// Function to check if the particular file has already been parsed.
+// TODO: Move this check to the consumer, not the callback.
+bool ClangDocCallback::isUnparsed(SourceLocation Loc) const {
   if (!Loc.isValid())
     return false;
-  const std::string &Filename = Manager.getFilename(Loc);
+  const std::string &Filename = Context->getSourceManager().getFilename(Loc);
 
-  if (!Reporter.hasFile(Filename))
+  if (!Reporter->hasFile(Filename))
     return false;
-  if (Manager.isInSystemHeader(Loc) || Manager.isInExternCSystemHeader(Loc))
+  if (Context->getSourceManager().isInSystemHeader(Loc) ||
+      Context->getSourceManager().isInExternCSystemHeader(Loc))
     return false;
   return true;
 }
 
-std::string ClangDocVisitor::mangleName(const FunctionDecl *D) {
+std::string ClangDocCallback::mangleName(const FunctionDecl *D) const {
   std::string S;
   llvm::raw_string_ostream MangledName(S);
   if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(D))
     MC->mangleCXXCtor(Ctor, CXXCtorType::Ctor_Complete, MangledName);
   else if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(D))
     MC->mangleCXXDtor(Dtor, CXXDtorType::Dtor_Complete, MangledName);
   else
     MC->mangleName(D, MangledName);
-  return MangledName.str();
-}
-
-void ClangDocConsumer::HandleTranslationUnit(ASTContext &Context) {
-  Visitor.TraverseDecl(Context.getTranslationUnitDecl());
-  Visitor.parseUnattachedComments();
-}
-
-std::unique_ptr<ASTConsumer>
-ClangDocAction::CreateASTConsumer(CompilerInstance &C, StringRef InFile) {
-  return make_unique<ClangDocConsumer>(&C.getASTContext(), Reporter);
+  return S;
 }
 
 } // namespace doc
Index: test/Tooling/clang-doc-type.cpp
===================================================================
--- test/Tooling/clang-doc-type.cpp
+++ test/Tooling/clang-doc-type.cpp
@@ -1,8 +1,8 @@
 // RUN: rm -rf %t
 // RUN: mkdir %t
-// RUN: echo '[{"directory":"%t","command":"clang++ -c %t/test.cpp","file":"%t/test.cpp"}]' | sed -e 's/\\/\//g' > %t/compile_commands.json
+// RUN: echo "" > %t/compile_flags.txt
 // RUN: cp "%s" "%t/test.cpp"
-// RUN: clang-doc --dump --omit-filenames -p %t %t/test.cpp | FileCheck %s
+// RUN: clang-doc --emit-yaml --dump --omit-filenames -p %t %t/test.cpp | FileCheck %s
 
 /// A union.
 union A { int X; int Y; };
@@ -21,14 +21,8 @@
 public:
   E() {}
   ~E() {}
-  int PublicVal;
-  
 protected:
-  int ProtectedVal;
   void ProtectedMethod();
-  
-private: 
-  int PrivateVal();
 };
 
 void E::ProtectedMethod() {}
@@ -38,171 +32,197 @@
 class G : virtual private D, public E {};
 
  // CHECK: ---
- // CHECK: Namespaces:      
- // CHECK:   - Qualified Name:  ''
- // CHECK:     Name:            ''
- // CHECK:     Namespace:       ''
- // CHECK: Types:           
- // CHECK:   - Qualified Name:  A
- // CHECK:     Name:            A
- // CHECK:     Namespace:       ''
- // CHECK:     Descriptions:    
- // CHECK:       - Kind:            FullComment
+ // CHECK: Qualified Name:  A
+ // CHECK: Name:            A
+ // CHECK: Namespace:       ''
+ // CHECK: Descriptions:    
+ // CHECK:   - Kind:            FullComment
+ // CHECK:     Children:        
+ // CHECK:       - Kind:            ParagraphComment
  // CHECK:         Children:        
- // CHECK:           - Kind:            ParagraphComment
- // CHECK:             Children:        
- // CHECK:               - Kind:            TextComment
- // CHECK:                 Text:            ' A union.'
- // CHECK:     TagType:         Union
- // CHECK:     Locations:       
- // CHECK:       - LineNumber:      8
- // CHECK:         Filename:        ''
- // CHECK:     DefinitionFile:  ''
- // CHECK:     Members:         
- // CHECK:       - Type:            int
- // CHECK:         Name:            'A::X'
- // CHECK:         Access:          None
- // CHECK:       - Type:            int
- // CHECK:         Name:            'A::Y'
- // CHECK:         Access:          None
- // CHECK:   - Qualified Name:  C
- // CHECK:     Name:            C
- // CHECK:     Namespace:       ''
- // CHECK:     Descriptions:    
- // CHECK:       - Kind:            FullComment
+ // CHECK:           - Kind:            TextComment
+ // CHECK:             Text:            ' A union.'
+ // CHECK: TagType:         Union
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      8
+ // CHECK:     Filename:        ''
+ // CHECK: DefinitionFile:  ''
+ // CHECK: Members:         
+ // CHECK:   - Type:            int
+ // CHECK:     Name:            'A::X'
+ // CHECK:     Access:          None
+ // CHECK:   - Type:            int
+ // CHECK:     Name:            'A::Y'
+ // CHECK:     Access:          None
+ // CHECK: Parents:         
+ // CHECK: VirtualParents:  
+ // CHECK: ...
+ // CHECK: ---
+ // CHECK: Qualified Name:  C
+ // CHECK: Name:            C
+ // CHECK: Namespace:       ''
+ // CHECK: Descriptions:    
+ // CHECK:   - Kind:            FullComment
+ // CHECK:     Children:        
+ // CHECK:       - Kind:            ParagraphComment
  // CHECK:         Children:        
- // CHECK:           - Kind:            ParagraphComment
- // CHECK:             Children:        
- // CHECK:               - Kind:            TextComment
- // CHECK:                 Text:            ' A struct.'
- // CHECK:     TagType:         Struct
- // CHECK:     Locations:       
- // CHECK:       - LineNumber:      14
- // CHECK:         Filename:        ''
- // CHECK:     DefinitionFile:  ''
- // CHECK:     Members:         
- // CHECK:       - Type:            int
- // CHECK:         Name:            'C::i'
- // CHECK:         Access:          None
- // CHECK:   - Qualified Name:  D
- // CHECK:     Name:            D
- // CHECK:     Namespace:       ''
- // CHECK:     Descriptions:    
- // CHECK:       - Kind:            FullComment
+ // CHECK:           - Kind:            TextComment
+ // CHECK:             Text:            ' A struct.'
+ // CHECK: TagType:         Struct
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      14
+ // CHECK:     Filename:        ''
+ // CHECK: DefinitionFile:  ''
+ // CHECK: Members:         
+ // CHECK:   - Type:            int
+ // CHECK:     Name:            'C::i'
+ // CHECK:     Access:          None
+ // CHECK: Parents:         
+ // CHECK: VirtualParents:  
+ // CHECK: ...
+ // CHECK: ---
+ // CHECK: Qualified Name:  D
+ // CHECK: Name:            D
+ // CHECK: Namespace:       ''
+ // CHECK: Descriptions:    
+ // CHECK:   - Kind:            FullComment
+ // CHECK:     Children:        
+ // CHECK:       - Kind:            ParagraphComment
  // CHECK:         Children:        
- // CHECK:           - Kind:            ParagraphComment
- // CHECK:             Children:        
- // CHECK:               - Kind:            TextComment
- // CHECK:                 Text:            ' An empty class.'
- // CHECK:     TagType:         Class
- // CHECK:     Locations:       
- // CHECK:       - LineNumber:      17
- // CHECK:         Filename:        ''
- // CHECK:     DefinitionFile:  ''
- // CHECK:   - Qualified Name:  E
- // CHECK:     Name:            E
- // CHECK:     Namespace:       ''
- // CHECK:     Descriptions:    
- // CHECK:       - Kind:            FullComment
+ // CHECK:           - Kind:            TextComment
+ // CHECK:             Text:            ' An empty class.'
+ // CHECK: TagType:         Class
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      17
+ // CHECK:     Filename:        ''
+ // CHECK: DefinitionFile:  ''
+ // CHECK: Members:         
+ // CHECK: Parents:         
+ // CHECK: VirtualParents:  
+ // CHECK: ...
+ // CHECK: ---
+ // CHECK: Qualified Name:  E
+ // CHECK: Name:            E
+ // CHECK: Namespace:       ''
+ // CHECK: Descriptions:    
+ // CHECK:   - Kind:            FullComment
+ // CHECK:     Children:        
+ // CHECK:       - Kind:            ParagraphComment
  // CHECK:         Children:        
- // CHECK:           - Kind:            ParagraphComment
- // CHECK:             Children:        
- // CHECK:               - Kind:            TextComment
- // CHECK:                 Text:            ' An example class.'
- // CHECK:     TagType:         Class
- // CHECK:     Locations:       
- // CHECK:       - LineNumber:      20
- // CHECK:         Filename:        ''
- // CHECK:     Functions:       
- // CHECK:       - Mangled Name:    _ZN1E15ProtectedMethodEv
- // CHECK:         Qualified Name:  'E::ProtectedMethod'
- // CHECK:         Name:            ProtectedMethod
- // CHECK:         Namespace:       E
- // CHECK:         Locations:       
- // CHECK:           - LineNumber:      34
- // CHECK:             Filename:        ''
- // CHECK:         DefinitionFile:  ''
- // CHECK:         ReturnType:      void
- // CHECK:         Access:          Protected
- // CHECK:       - Mangled Name:    _ZN1EC1Ev
- // CHECK:         Qualified Name:  'E::E'
- // CHECK:         Name:            E
- // CHECK:         Namespace:       E
- // CHECK:         Locations:       
- // CHECK:           - LineNumber:      22
- // CHECK:             Filename:        ''
- // CHECK:         DefinitionFile:  ''
- // CHECK:         ReturnType:      void
- // CHECK:         Access:          Public
- // CHECK:       - Mangled Name:    _ZN1ED1Ev
- // CHECK:         Qualified Name:  'E::~E'
- // CHECK:         Name:            '~E'
- // CHECK:         Namespace:       E
- // CHECK:         Locations:       
- // CHECK:           - LineNumber:      23
- // CHECK:             Filename:        ''
- // CHECK:         DefinitionFile:  ''
- // CHECK:         ReturnType:      void
- // CHECK:         Access:          Public
- // CHECK:     DefinitionFile:  ''
- // CHECK:     Members:         
- // CHECK:       - Type:            int
- // CHECK:         Name:            'E::PublicVal'
- // CHECK:         Access:          None
- // CHECK:       - Type:            int
- // CHECK:         Name:            'E::ProtectedVal'
- // CHECK:         Access:          None
- // CHECK:   - Qualified Name:  F
- // CHECK:     Name:            F
- // CHECK:     Namespace:       ''
- // CHECK:     Descriptions:    
- // CHECK:       - Kind:            FullComment
+ // CHECK:           - Kind:            TextComment
+ // CHECK:             Text:            ' An example class.'
+ // CHECK: TagType:         Class
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      20
+ // CHECK:     Filename:        ''
+ // CHECK: DefinitionFile:  ''
+ // CHECK: Members:         
+ // CHECK: Parents:         
+ // CHECK: VirtualParents:  
+ // CHECK: ...
+ // CHECK: ---
+ // CHECK: Mangled Name:    _ZN1E15ProtectedMethodEv
+ // CHECK: Qualified Name:  'E::ProtectedMethod'
+ // CHECK: Name:            ProtectedMethod
+ // CHECK: Namespace:       E
+ // CHECK: Descriptions:    
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      25
+ // CHECK:     Filename:        ''
+ // CHECK:   - LineNumber:      28
+ // CHECK:     Filename:        ''
+ // CHECK: DefinitionFile:  ''
+ // CHECK: Params:          
+ // CHECK: ReturnType:      void
+ // CHECK: Access:          Protected
+ // CHECK: ...
+ // CHECK: ---
+ // CHECK: Mangled Name:    _ZN1EC1Ev
+ // CHECK: Qualified Name:  'E::E'
+ // CHECK: Name:            E
+ // CHECK: Namespace:       E
+ // CHECK: Descriptions:    
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      22
+ // CHECK:     Filename:        ''
+ // CHECK: DefinitionFile:  ''
+ // CHECK: Params:          
+ // CHECK: ReturnType:      void
+ // CHECK: Access:          Public
+ // CHECK: ...
+ // CHECK: ---
+ // CHECK: Mangled Name:    _ZN1ED1Ev
+ // CHECK: Qualified Name:  'E::~E'
+ // CHECK: Name:            '~E'
+ // CHECK: Namespace:       E
+ // CHECK: Descriptions:    
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      23
+ // CHECK:     Filename:        ''
+ // CHECK: DefinitionFile:  ''
+ // CHECK: Params:          
+ // CHECK: ReturnType:      void
+ // CHECK: Access:          Public
+ // CHECK: ...
+ // CHECK: ---
+ // CHECK: Qualified Name:  F
+ // CHECK: Name:            F
+ // CHECK: Namespace:       ''
+ // CHECK: Descriptions:    
+ // CHECK:   - Kind:            FullComment
+ // CHECK:     Children:        
+ // CHECK:       - Kind:            ParagraphComment
  // CHECK:         Children:        
- // CHECK:           - Kind:            ParagraphComment
- // CHECK:             Children:        
- // CHECK:               - Kind:            TextComment
- // CHECK:                 Text:            ' An inherited class.'
- // CHECK:     TagType:         Class
- // CHECK:     Locations:       
- // CHECK:       - LineNumber:      37
- // CHECK:         Filename:        ''
- // CHECK:     DefinitionFile:  ''
- // CHECK:     Parents:         
- // CHECK:       - class D
- // CHECK:       - class E
- // CHECK:   - Qualified Name:  G
- // CHECK:     Name:            G
- // CHECK:     Namespace:       ''
- // CHECK:     TagType:         Class
- // CHECK:     Locations:       
- // CHECK:       - LineNumber:      38
- // CHECK:         Filename:        ''
- // CHECK:     DefinitionFile:  ''
- // CHECK:     Parents:         
- // CHECK:       - class E
- // CHECK:     VirtualParents:  
- // CHECK:       - class D
- // CHECK: Enums:           
- // CHECK:   - Qualified Name:  B
- // CHECK:     Name:            B
- // CHECK:     Namespace:       ''
- // CHECK:     Descriptions:    
- // CHECK:       - Kind:            FullComment
+ // CHECK:           - Kind:            TextComment
+ // CHECK:             Text:            ' An inherited class.'
+ // CHECK: TagType:         Class
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      31
+ // CHECK:     Filename:        ''
+ // CHECK: DefinitionFile:  ''
+ // CHECK: Members:         
+ // CHECK: Parents:         
+ // CHECK:   - class D
+ // CHECK:   - class E
+ // CHECK: VirtualParents:  
+ // CHECK: ...
+ // CHECK: ---
+ // CHECK: Qualified Name:  G
+ // CHECK: Name:            G
+ // CHECK: Namespace:       ''
+ // CHECK: Descriptions:    
+ // CHECK: TagType:         Class
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      32
+ // CHECK:     Filename:        ''
+ // CHECK: DefinitionFile:  ''
+ // CHECK: Members:         
+ // CHECK: Parents:         
+ // CHECK:   - class E
+ // CHECK: VirtualParents:  
+ // CHECK:   - class D
+ // CHECK: ...
+ // CHECK: ---
+ // CHECK: Qualified Name:  B
+ // CHECK: Name:            B
+ // CHECK: Namespace:       ''
+ // CHECK: Descriptions:    
+ // CHECK:   - Kind:            FullComment
+ // CHECK:     Children:        
+ // CHECK:       - Kind:            ParagraphComment
  // CHECK:         Children:        
- // CHECK:           - Kind:            ParagraphComment
- // CHECK:             Children:        
- // CHECK:               - Kind:            TextComment
- // CHECK:                 Text:            ' An enum.'
- // CHECK:     Locations:       
- // CHECK:       - LineNumber:      11
- // CHECK:         Filename:        ''
- // CHECK:     DefinitionFile:  ''
- // CHECK:     Scoped:          false
- // CHECK:     Members:         
- // CHECK:       - Type:            X
- // CHECK:         Name:            ''
- // CHECK:         Access:          None
- // CHECK:       - Type:            Y
- // CHECK:         Name:            ''
- // CHECK:         Access:          None
+ // CHECK:           - Kind:            TextComment
+ // CHECK:             Text:            ' An enum.'
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      11
+ // CHECK:     Filename:        ''
+ // CHECK: DefinitionFile:  ''
+ // CHECK: Scoped:          false
+ // CHECK: Members:         
+ // CHECK:   - Type:            X
+ // CHECK:     Name:            ''
+ // CHECK:     Access:          None
+ // CHECK:   - Type:            Y
+ // CHECK:     Name:            ''
+ // CHECK:     Access:          None
  // CHECK: ...
Index: test/Tooling/clang-doc-namespace.cpp
===================================================================
--- test/Tooling/clang-doc-namespace.cpp
+++ test/Tooling/clang-doc-namespace.cpp
@@ -1,8 +1,8 @@
 // RUN: rm -rf %t
 // RUN: mkdir %t
-// RUN: echo '[{"directory":"%t","command":"clang++ -c %t/test.cpp","file":"%t/test.cpp"}]' | sed -e 's/\\/\//g' > %t/compile_commands.json
+// RUN: echo "" > %t/compile_flags.txt
 // RUN: cp "%s" "%t/test.cpp"
-// RUN: clang-doc --dump --omit-filenames -p %t %t/test.cpp | FileCheck %s
+// RUN: clang-doc --emit-yaml --dump --omit-filenames -p %t %t/test.cpp | FileCheck %s
 
 /// Test namespace
 namespace A {}
@@ -17,52 +17,61 @@
   void f() {};
 }
 
- // CHECK: Namespaces:      
- // CHECK:   - Qualified Name:  ''
- // CHECK:     Name:            ''
- // CHECK:     Namespace:       ''
- // CHECK:   - Qualified Name:  A
- // CHECK:     Name:            A
- // CHECK:     Namespace:       ''
- // CHECK:     Descriptions:    
- // CHECK:       - Kind:            FullComment
+ // CHECK: ---
+ // CHECK: Qualified Name:  A
+ // CHECK: Name:            A
+ // CHECK: Namespace:       ''
+ // CHECK: Descriptions:    
+ // CHECK:   - Kind:            FullComment
+ // CHECK:     Children:        
+ // CHECK:       - Kind:            ParagraphComment
  // CHECK:         Children:        
- // CHECK:           - Kind:            ParagraphComment
- // CHECK:             Children:        
- // CHECK:               - Kind:            TextComment
- // CHECK:                 Text:            ' Test namespace'
- // CHECK:     Locations:       
- // CHECK:       - LineNumber:      8
- // CHECK:         Filename:        ''
- // CHECK:       - LineNumber:      16
- // CHECK:         Filename:        ''
- // CHECK:     Functions:       
- // CHECK:       - Mangled Name:    _ZN1A1fEv
- // CHECK:         Qualified Name:  'A::f'
- // CHECK:         Name:            f
- // CHECK:         Namespace:       A
- // CHECK:         Locations:       
- // CHECK:           - LineNumber:      17
- // CHECK:             Filename:        ''
- // CHECK:         DefinitionFile:  ''
- // CHECK:         ReturnType:      void
- // CHECK:         Access:          None
- // CHECK:   - Qualified Name:  B
- // CHECK:     Name:            B
- // CHECK:     Namespace:       ''
- // CHECK:     Locations:       
- // CHECK:       - LineNumber:      10
- // CHECK:         Filename:        ''
- // CHECK:   - Qualified Name:  'B::C::D'
- // CHECK:     Name:            D
- // CHECK:     Namespace:       'B::C'
- // CHECK:     Locations:       
- // CHECK:       - LineNumber:      12
- // CHECK:         Filename:        ''
- // CHECK:   - Qualified Name:  'B::C'
- // CHECK:     Name:            C
- // CHECK:     Namespace:       B
- // CHECK:     Locations:       
- // CHECK:       - LineNumber:      11
- // CHECK:         Filename:        ''
+ // CHECK:           - Kind:            TextComment
+ // CHECK:             Text:            ' Test namespace'
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      8
+ // CHECK:     Filename:        ''
+ // CHECK:   - LineNumber:      16
+ // CHECK:     Filename:        ''
+ // CHECK: ...
+ // CHECK: ---
+ // CHECK: Mangled Name:    _ZN1A1fEv
+ // CHECK: Qualified Name:  'A::f'
+ // CHECK: Name:            f
+ // CHECK: Namespace:       A
+ // CHECK: Descriptions:    
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      17
+ // CHECK:     Filename:        ''
+ // CHECK: DefinitionFile:  ''
+ // CHECK: Params:          
+ // CHECK: ReturnType:      void
+ // CHECK: Access:          None
+ // CHECK: ...
+ // CHECK: ---
+ // CHECK: Qualified Name:  B
+ // CHECK: Name:            B
+ // CHECK: Namespace:       ''
+ // CHECK: Descriptions:    
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      10
+ // CHECK:     Filename:        ''
+ // CHECK: ...
+ // CHECK: ---
+ // CHECK: Qualified Name:  'B::C::D'
+ // CHECK: Name:            D
+ // CHECK: Namespace:       'B::C'
+ // CHECK: Descriptions:    
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      12
+ // CHECK:     Filename:        ''
+ // CHECK: ...
+ // CHECK: ---
+ // CHECK: Qualified Name:  'B::C'
+ // CHECK: Name:            C
+ // CHECK: Namespace:       B
+ // CHECK: Descriptions:    
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      11
+ // CHECK:     Filename:        ''
  // CHECK: ...
Index: test/Tooling/clang-doc-basic.cpp
===================================================================
--- test/Tooling/clang-doc-basic.cpp
+++ test/Tooling/clang-doc-basic.cpp
@@ -1,8 +1,8 @@
 // RUN: rm -rf %t
 // RUN: mkdir %t
-// RUN: echo '[{"directory":"%t","command":"clang++ -c %t/test.cpp","file":"%t/test.cpp"}]' | sed -e 's/\\/\//g' > %t/compile_commands.json
+// RUN: echo "" > %t/compile_flags.txt
 // RUN: cp "%s" "%t/test.cpp"
-// RUN: clang-doc --dump --omit-filenames -p %t %t/test.cpp | FileCheck %s
+// RUN: clang-doc --emit-yaml --dump --omit-filenames -p %t %t/test.cpp | FileCheck %s
 
 /// Test namespace
 namespace A {
@@ -18,55 +18,64 @@
   int i;
 };
 
-// CHECK-DAG: ---
-// CHECK-DAG: Namespaces:      
-// CHECK-DAG:   - Qualified Name:  ''
-// CHECK-DAG:     Name:            ''
-// CHECK-DAG:     Namespace:       ''
-// CHECK-DAG:   - Qualified Name:  A
-// CHECK-DAG:     Name:            A
-// CHECK-DAG:     Namespace:       ''
-// CHECK-DAG:     Descriptions:    
-// CHECK-DAG:       - Kind:            FullComment
-// CHECK-DAG:         Children:        
-// CHECK-DAG:           - Kind:            ParagraphComment
-// CHECK-DAG:             Children:        
-// CHECK-DAG:               - Kind:            TextComment
-// CHECK-DAG:                 Text:            ' Test namespace'
-// CHECK-DAG:     Locations:       
-// CHECK-DAG:       - LineNumber:      8
-// CHECK-DAG:     Functions:       
-// CHECK-DAG:       - Mangled Name:    _ZN1A1fEi
-// CHECK-DAG:         Qualified Name:  'A::f'
-// CHECK-DAG:         Name:            f
-// CHECK-DAG:         Namespace:       A
-// CHECK-DAG:         Descriptions:    
-// CHECK-DAG:           - Kind:            FullComment
-// CHECK-DAG:             Children:        
-// CHECK-DAG:               - Kind:            ParagraphComment
-// CHECK-DAG:                 Children:        
-// CHECK-DAG:                   - Kind:            TextComment
-// CHECK-DAG:                     Text:            ' A function'
-// CHECK-DAG:         Locations:       
-// CHECK-DAG:           - LineNumber:      11
-// CHECK-DAG:         ReturnType:      void
-// CHECK-DAG:         Access:          None
-// CHECK-DAG: Types:           
-// CHECK-DAG:   - Qualified Name:  C
-// CHECK-DAG:     Name:            C
-// CHECK-DAG:     Namespace:       ''
-// CHECK-DAG:     Descriptions:    
-// CHECK-DAG:       - Kind:            FullComment
-// CHECK-DAG:         Children:        
-// CHECK-DAG:           - Kind:            ParagraphComment
-// CHECK-DAG:             Children:        
-// CHECK-DAG:               - Kind:            TextComment
-// CHECK-DAG:                 Text:            ' A C++ class'
-// CHECK-DAG:     TagType:         Class
-// CHECK-DAG:     Locations:       
-// CHECK-DAG:       - LineNumber:      16
-// CHECK-DAG:     Members:         
-// CHECK-DAG:       - Type:            int
-// CHECK-DAG:         Name:            'C::i'
-// CHECK-DAG:         Access:          None
-// CHECK-DAG: ...
+ // CHECK: ---
+ // CHECK: Qualified Name:  A
+ // CHECK: Name:            A
+ // CHECK: Namespace:       ''
+ // CHECK: Descriptions:    
+ // CHECK:   - Kind:            FullComment
+ // CHECK:     Children:        
+ // CHECK:       - Kind:            ParagraphComment
+ // CHECK:         Children:        
+ // CHECK:           - Kind:            TextComment
+ // CHECK:             Text:            ' Test namespace'
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      8
+ // CHECK:     Filename:        ''
+ // CHECK: ...
+ // CHECK: ---
+ // CHECK: Mangled Name:    _ZN1A1fEi
+ // CHECK: Qualified Name:  'A::f'
+ // CHECK: Name:            f
+ // CHECK: Namespace:       A
+ // CHECK: Descriptions:    
+ // CHECK:   - Kind:            FullComment
+ // CHECK:     Children:        
+ // CHECK:       - Kind:            ParagraphComment
+ // CHECK:         Children:        
+ // CHECK:           - Kind:            TextComment
+ // CHECK:             Text:            ' A function'
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      11
+ // CHECK:     Filename:        ''
+ // CHECK: DefinitionFile:  ''
+ // CHECK: Params:          
+ // CHECK:   - Type:            int
+ // CHECK:     Name:            x
+ // CHECK:     Access:          None
+ // CHECK: ReturnType:      void
+ // CHECK: Access:          None
+ // CHECK: ...
+ // CHECK: ---
+ // CHECK: Qualified Name:  C
+ // CHECK: Name:            C
+ // CHECK: Namespace:       ''
+ // CHECK: Descriptions:    
+ // CHECK:   - Kind:            FullComment
+ // CHECK:     Children:        
+ // CHECK:       - Kind:            ParagraphComment
+ // CHECK:         Children:        
+ // CHECK:           - Kind:            TextComment
+ // CHECK:             Text:            ' A C++ class'
+ // CHECK: TagType:         Class
+ // CHECK: Locations:       
+ // CHECK:   - LineNumber:      16
+ // CHECK:     Filename:        ''
+ // CHECK: DefinitionFile:  ''
+ // CHECK: Members:         
+ // CHECK:   - Type:            int
+ // CHECK:     Name:            'C::i'
+ // CHECK:     Access:          None
+ // CHECK: Parents:         
+ // CHECK: VirtualParents:  
+ // CHECK: ...
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to