juliehockett updated this revision to Diff 135168.
juliehockett marked 13 inline comments as done.
juliehockett added a comment.

1. Updating mapper keys to use USRs instead of names
2. Also updating internal representation to use USRs instead of names
3. Renaming files (getting rid of the ClangDoc prefix in most cases)
4. Added bitcode version number to output
5. Put brief documentation in header files
6. Updating internal representation to generate full infos for all decls 
(regardless of if they're defined -- the reducer step will consolidate these) 
and to store the namespace as a vector instead of a string.


https://reviews.llvm.org/D41102

Files:
  CMakeLists.txt
  clang-doc/BitcodeWriter.cpp
  clang-doc/BitcodeWriter.h
  clang-doc/CMakeLists.txt
  clang-doc/ClangDoc.h
  clang-doc/Mapper.cpp
  clang-doc/Mapper.h
  clang-doc/Representation.h
  clang-doc/tool/CMakeLists.txt
  clang-doc/tool/ClangDocMain.cpp
  docs/clang-doc.rst
  test/CMakeLists.txt
  test/clang-doc/mapper-class.cpp
  test/clang-doc/mapper-enum.cpp
  test/clang-doc/mapper-function.cpp
  test/clang-doc/mapper-method.cpp
  test/clang-doc/mapper-namespace.cpp
  test/clang-doc/mapper-struct.cpp
  test/clang-doc/mapper-union.cpp

Index: test/clang-doc/mapper-union.cpp
===================================================================
--- /dev/null
+++ test/clang-doc/mapper-union.cpp
@@ -0,0 +1,29 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/c:@u...@d.bc --dump | FileCheck %s
+
+union D { int X; int Y; };
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK: <VersionBlock NumWords=1 BlockCodeSize=5>
+  // CHECK: <Version op0=0/>
+// CHECK: </VersionBlock>
+// CHECK: <RecordBlock NumWords=18 BlockCodeSize=5>
+  // CHECK: <Name abbrevid=4 op0=1/> blob data = 'D'
+  // CHECK: <IsDefinition abbrevid=6 op0=1/>
+  // CHECK: <TagType abbrevid=8 op0=2/>
+  // CHECK: <MemberTypeBlock NumWords=5 BlockCodeSize=5>
+    // CHECK: <Type abbrevid=4 op0=3/> blob data = 'int'
+    // CHECK: <Name abbrevid=5 op0=4/> blob data = 'D::X'
+    // CHECK: <Access abbrevid=6 op0=3/>
+  // CHECK: </MemberTypeBlock>
+  // CHECK: <MemberTypeBlock NumWords=5 BlockCodeSize=5>
+    // CHECK: <Type abbrevid=4 op0=3/> blob data = 'int'
+    // CHECK: <Name abbrevid=5 op0=4/> blob data = 'D::Y'
+    // CHECK: <Access abbrevid=6 op0=3/>
+  // CHECK: </MemberTypeBlock>
+// CHECK: </RecordBlock>
+
+
Index: test/clang-doc/mapper-struct.cpp
===================================================================
--- /dev/null
+++ test/clang-doc/mapper-struct.cpp
@@ -0,0 +1,23 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/c:@s...@c.bc --dump | FileCheck %s
+
+struct C { int i; };
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK: <VersionBlock NumWords=1 BlockCodeSize=5>
+  // CHECK: <Version op0=0/>
+// CHECK: </VersionBlock>
+// CHECK: <RecordBlock NumWords=11 BlockCodeSize=5>
+  // CHECK: <Name abbrevid=4 op0=1/> blob data = 'C'
+  // CHECK: <IsDefinition abbrevid=6 op0=1/>
+  // CHECK: <MemberTypeBlock NumWords=5 BlockCodeSize=5>
+    // CHECK: <Type abbrevid=4 op0=3/> blob data = 'int'
+    // CHECK: <Name abbrevid=5 op0=4/> blob data = 'C::i'
+    // CHECK: <Access abbrevid=6 op0=3/>
+  // CHECK: </MemberTypeBlock>
+// CHECK: </RecordBlock>
+
+
Index: test/clang-doc/mapper-namespace.cpp
===================================================================
--- /dev/null
+++ test/clang-doc/mapper-namespace.cpp
@@ -0,0 +1,17 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/c:@n...@a.bc --dump | FileCheck %s
+
+namespace A {}
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK: <VersionBlock NumWords=1 BlockCodeSize=5>
+  // CHECK: <Version op0=0/>
+// CHECK: </VersionBlock>
+// CHECK: <NamespaceBlock NumWords=3 BlockCodeSize=5>
+  // CHECK: <Name abbrevid=4 op0=1/> blob data = 'A'
+// CHECK: </NamespaceBlock>
+
+
Index: test/clang-doc/mapper-method.cpp
===================================================================
--- /dev/null
+++ test/clang-doc/mapper-method.cpp
@@ -0,0 +1,31 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/c:@S@G@F@Method#I#.bc --dump | FileCheck %s
+
+class G {
+public: 
+	int Method(int param) { return param; }
+};
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK: <VersionBlock NumWords=1 BlockCodeSize=5>
+  // CHECK: <Version op0=0/>
+// CHECK: </VersionBlock>
+// CHECK: <FunctionBlock NumWords=21 BlockCodeSize=5>
+  // CHECK: <Name abbrevid=4 op0=6/> blob data = 'Method'
+  // CHECK: <IsDefinition abbrevid=6 op0=1/>
+  // CHECK: <Parent abbrevid=8 op0=6 (offset mismatch: 0 vs 7477)/> blob data = 'c:@S@G'
+  // CHECK: <FieldTypeBlock NumWords=3 BlockCodeSize=5>
+    // CHECK: <Type abbrevid=4 op0=3/> blob data = 'int'
+  // CHECK: </FieldTypeBlock>
+  // CHECK: <FieldTypeBlock NumWords=6 BlockCodeSize=5>
+    // CHECK: <Type abbrevid=4 op0=3/> blob data = 'int'
+    // CHECK: <Name abbrevid=5 op0=5/> blob data = 'param'
+  // CHECK: </FieldTypeBlock>
+// CHECK: </FunctionBlock>
+
+
+
+
Index: test/clang-doc/mapper-function.cpp
===================================================================
--- /dev/null
+++ test/clang-doc/mapper-function.cpp
@@ -0,0 +1,24 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/c:@F@F#I#.bc --dump | FileCheck %s
+
+int F(int param) { return param; }
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK: <VersionBlock NumWords=1 BlockCodeSize=5>
+  // CHECK: <Version op0=0/>
+// CHECK: </VersionBlock>
+// CHECK: <FunctionBlock NumWords=17 BlockCodeSize=5>
+  // CHECK: <Name abbrevid=4 op0=1/> blob data = 'F'
+  // CHECK: <IsDefinition abbrevid=6 op0=1/>
+  // CHECK: <FieldTypeBlock NumWords=3 BlockCodeSize=5>
+    // CHECK: <Type abbrevid=4 op0=3/> blob data = 'int'
+  // CHECK: </FieldTypeBlock>
+  // CHECK: <FieldTypeBlock NumWords=6 BlockCodeSize=5>
+    // CHECK: <Type abbrevid=4 op0=3/> blob data = 'int'
+    // CHECK: <Name abbrevid=5 op0=5/> blob data = 'param'
+  // CHECK: </FieldTypeBlock>
+// CHECK: </FunctionBlock>
+
Index: test/clang-doc/mapper-enum.cpp
===================================================================
--- /dev/null
+++ test/clang-doc/mapper-enum.cpp
@@ -0,0 +1,25 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/c:@e...@b.bc --dump | FileCheck %s
+
+enum B { X, Y };
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK: <VersionBlock NumWords=1 BlockCodeSize=5>
+  // CHECK: <Version op0=0/>
+// CHECK: </VersionBlock>
+// CHECK: <EnumBlock NumWords=14 BlockCodeSize=5>
+  // CHECK: <Name abbrevid=4 op0=1/> blob data = 'B'
+  // CHECK: <IsDefinition abbrevid=6 op0=1/>
+  // CHECK: <FieldTypeBlock NumWords=3 BlockCodeSize=5>
+    // CHECK: <Type abbrevid=4 op0=1/> blob data = 'X'
+  // CHECK: </FieldTypeBlock>
+  // CHECK: <FieldTypeBlock NumWords=3 BlockCodeSize=5>
+    // CHECK: <Type abbrevid=4 op0=1/> blob data = 'Y'
+  // CHECK: </FieldTypeBlock>
+// CHECK: </EnumBlock>
+
+
+
Index: test/clang-doc/mapper-class.cpp
===================================================================
--- /dev/null
+++ test/clang-doc/mapper-class.cpp
@@ -0,0 +1,18 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/c:@s...@e.bc --dump | FileCheck %s
+
+class E {};
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK: <VersionBlock NumWords=1 BlockCodeSize=5>
+  // CHECK: <Version op0=0/>
+// CHECK: </VersionBlock>
+// CHECK: <RecordBlock NumWords=4 BlockCodeSize=5>
+  // CHECK: <Name abbrevid=4 op0=1/> blob data = 'E'
+  // CHECK: <IsDefinition abbrevid=6 op0=1/>
+  // CHECK: <TagType abbrevid=8 op0=3/>
+// CHECK: </RecordBlock>
+
Index: test/CMakeLists.txt
===================================================================
--- test/CMakeLists.txt
+++ test/CMakeLists.txt
@@ -41,6 +41,7 @@
   clang-apply-replacements
   clang-change-namespace
   clangd
+  clang-doc
   clang-include-fixer
   clang-move
   clang-query
Index: docs/clang-doc.rst
===================================================================
--- /dev/null
+++ docs/clang-doc.rst
@@ -0,0 +1,62 @@
+===================
+Clang-Doc
+===================
+
+.. contents::
+
+:program:`clang-doc` is a tool for generating C and C++ documenation from 
+source code and comments. 
+
+The tool is in a very early development stage, so you might encounter bugs and
+crashes. Submitting reports with information about how to reproduce the issue
+to `the LLVM bugtracker <https://llvm.org/bugs>`_ will definitely help the
+project. If you have any ideas or suggestions, please to put a feature request
+there.
+
+Use
+=====
+
+:program:`clang-doc` is a `LibTooling
+<http://clang.llvm.org/docs/LibTooling.html>`_-based tool, and so requires a
+compile command database for your project (for an example of how to do this 
+see `How To Setup Tooling For LLVM
+<http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html>`_).
+
+The tool can be used on a single file or multiple files as defined in 
+the compile commands database:
+
+.. code-block:: console
+
+  $ clang-doc /path/to/file.cpp -p /path/to/compile/commands
+
+This generates an intermediate representation of the declarations and their
+associated information in the specified TUs, serialized to LLVM bitcode.
+
+As currently implemented, the tool is only able to parse TUs that can be 
+stored in-memory. Future additions will extend the current framework to use
+map-reduce frameworks to allow for use with large codebases.
+
+:program:`clang-doc` offers the following options:
+
+.. code-block:: console
+
+	$ clang-doc --help
+USAGE: clang-doc [options] <source0> [... <sourceN>]
+
+OPTIONS:
+
+Generic Options:
+
+  -help                      - Display available options (-help-hidden for more)
+  -help-list                 - Display list of available options (-help-list-hidden for more)
+  -version                   - Display the version of this program
+
+clang-doc options:
+
+  -doxygen                   - Use only doxygen-style comments to generate docs.
+  -dump                      - Dump intermediate results to bitcode file.
+  -extra-arg=<string>        - Additional argument to append to the compiler command line
+  -extra-arg-before=<string> - Additional argument to prepend to the compiler command line
+  -omit-filenames            - Omit filenames in output.
+  -output=<string>           - Directory for outputting generated files.
+  -p=<string>                - Build path
Index: clang-doc/tool/ClangDocMain.cpp
===================================================================
--- /dev/null
+++ clang-doc/tool/ClangDocMain.cpp
@@ -0,0 +1,112 @@
+//===-- ClangDocMain.cpp - ClangDoc -----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tool for generating C and C++ documenation from source code
+// and comments.
+//
+//===----------------------------------------------------------------------===//
+
+#include <string>
+#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/Execution.h"
+#include "clang/Tooling/StandaloneExecution.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang::ast_matchers;
+using namespace clang::tooling;
+using namespace clang;
+using namespace llvm;
+
+namespace {
+
+static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
+static cl::OptionCategory ClangDocCategory("clang-doc options");
+
+static cl::opt<std::string> OutDirectory(
+    "output", cl::desc("Directory for outputting generated files."),
+    cl::init("docs"), cl::cat(ClangDocCategory));
+
+static cl::opt<bool> DumpResult(
+    "dump", cl::desc("Dump intermediate results to bitcode file."),
+    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", cl::desc("Use only doxygen-style comments to generate docs."),
+    cl::init(false), cl::cat(ClangDocCategory));
+
+}  // namespace
+
+int main(int argc, const char **argv) {
+  sys::PrintStackTraceOnErrorSignal(argv[0]);
+  std::error_code OK;
+
+  auto Exec = clang::tooling::createExecutorFromCommandLineArgs(
+      argc, argv, ClangDocCategory);
+
+  if (!Exec) {
+    errs() << toString(Exec.takeError()) << "\n";
+    return 1;
+  }
+
+  ArgumentsAdjuster ArgAdjuster;
+  if (!DoxygenOnly)
+    ArgAdjuster = combineAdjusters(
+        getInsertArgumentAdjuster("-fparse-all-comments",
+                                  tooling::ArgumentInsertPosition::BEGIN),
+        ArgAdjuster);
+
+  // Mapping phase
+  outs() << "Mapping decls...\n";
+  auto Err = Exec->get()->execute(
+      llvm::make_unique<doc::MapperActionFactory>(
+          Exec->get()->getExecutionContext(), OmitFilenames),
+      ArgAdjuster);
+  if (Err) errs() << toString(std::move(Err)) << "\n";
+
+  if (DumpResult) {
+    Exec->get()->getToolResults()->forEachResult([&](StringRef Key,
+                                                     StringRef Value) {
+      SmallString<128> IRRootPath;
+      sys::path::native(OutDirectory, IRRootPath);
+      std::error_code DirectoryStatus = sys::fs::create_directories(IRRootPath);
+      if (DirectoryStatus != OK) {
+        errs() << "Unable to create documentation directories.\n";
+        return;
+      }
+      sys::path::append(IRRootPath, Key + ".bc");
+      std::error_code OutErrorInfo;
+      raw_fd_ostream OS(IRRootPath, OutErrorInfo, sys::fs::F_None);
+      if (OutErrorInfo != OK) {
+        errs() << "Error opening documentation file.\n";
+        return;
+      }
+      OS << Value;
+      OS.close();
+    });
+  }
+
+  return 0;
+}
Index: clang-doc/tool/CMakeLists.txt
===================================================================
--- /dev/null
+++ clang-doc/tool/CMakeLists.txt
@@ -0,0 +1,16 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+add_clang_executable(clang-doc
+  ClangDocMain.cpp
+  )
+
+target_link_libraries(clang-doc
+  PRIVATE
+  clangAST
+  clangASTMatchers
+  clangBasic
+  clangFrontend
+  clangDoc
+  clangTooling
+  clangToolingCore
+  )
Index: clang-doc/Representation.h
===================================================================
--- /dev/null
+++ clang-doc/Representation.h
@@ -0,0 +1,129 @@
+///===-- Representation.h - ClangDoc Represenation --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the internal representations of different declaration
+// types for the clang-doc tool.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_REPRESENTATION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_REPRESENTATION_H
+
+#include <string>
+#include "clang/AST/Type.h"
+#include "clang/Basic/Specifiers.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/SHA1.h"
+
+using namespace llvm;
+
+namespace clang {
+namespace doc {
+
+// A representation of a parsed comment.
+struct CommentInfo {
+  ~CommentInfo() {
+    for (auto *Child : Children) delete Child;
+  }
+  std::string Kind;
+  std::string Text;
+  std::string Name;
+  std::string Direction;
+  std::string ParamName;
+  std::string CloseName;
+  bool SelfClosing = false;
+  bool Explicit = false;
+  llvm::SmallVector<std::string, 4> AttrKeys;
+  llvm::SmallVector<std::string, 4> AttrValues;
+  llvm::SmallVector<std::string, 4> Args;
+  llvm::SmallVector<std::string, 4> Position;
+  std::vector<CommentInfo *> Children;
+};
+
+// TODO: Pull the CommentInfo for a type out of the info's CommentInfo.
+// A base struct for TypeInfos
+struct TypeInfo {
+  TypeInfo() {}
+  TypeInfo(StringRef TypeUSR) : TypeUSR(TypeUSR) {}
+
+  std::string TypeUSR;
+  std::vector<CommentInfo> Description;
+};
+
+// Info for field types.
+struct FieldTypeInfo : public TypeInfo {
+  FieldTypeInfo() {}
+  FieldTypeInfo(StringRef TypeUSR) : TypeInfo(TypeUSR) {}
+  FieldTypeInfo(StringRef TypeUSR, StringRef Name)
+      : TypeInfo(TypeUSR), Name(Name) {}
+  std::string Name;
+};
+
+// Info for member types.
+struct MemberTypeInfo : public FieldTypeInfo {
+  MemberTypeInfo() {}
+  MemberTypeInfo(StringRef TypeUSR, StringRef Name)
+      : FieldTypeInfo(TypeUSR, Name) {}
+  AccessSpecifier Access = clang::AccessSpecifier::AS_none;
+};
+
+struct Location {
+  int LineNumber;
+  std::string Filename;
+};
+
+/// A base struct for Infos.
+struct Info {
+  std::string Name;
+  llvm::SmallVector<std::string, 4> Namespace;
+  std::vector<CommentInfo> Description;
+};
+
+struct NamespaceInfo : public Info {};
+
+struct SymbolInfo : public Info {
+  bool IsDefinition = false;
+  llvm::SmallVector<Location, 2> Loc;
+};
+
+// TODO: Expand to allow for documenting templating and default args.
+// Info for functions.
+struct FunctionInfo : public SymbolInfo {
+  std::string ParentUSR;
+  TypeInfo ReturnType;
+  llvm::SmallVector<FieldTypeInfo, 4> Params;
+  AccessSpecifier Access;
+};
+
+// TODO: Expand to allow for documenting templating, inheritance access,
+// friend classes
+// Info for types.
+struct RecordInfo : public SymbolInfo {
+  TagTypeKind TagType;
+  llvm::SmallVector<MemberTypeInfo, 4> Members;
+  llvm::SmallVector<std::string, 4> ParentUSRs;
+  llvm::SmallVector<std::string, 4> VirtualParentUSRs;
+};
+
+// TODO: Expand to allow for documenting templating.
+// Info for types.
+struct EnumInfo : public SymbolInfo {
+  bool Scoped;
+  llvm::SmallVector<TypeInfo, 4> Members;
+};
+
+// TODO: Add functionality to include separate markdown pages.
+
+}  // namespace doc
+}  // namespace clang
+
+#endif  // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_REPRESENTATION_H
Index: clang-doc/Mapper.h
===================================================================
--- /dev/null
+++ clang-doc/Mapper.h
@@ -0,0 +1,140 @@
+//===-- Mapper.h - ClangDoc Mapper ------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Mapper piece of the clang-doc tool. It implements
+// a RecursiveASTVisitor to look at each declaration and populate the info
+// into the internal representation. Each seen declaration is serialized to
+// to bitcode and written out to the ExecutionContext as a KV pair where the
+// key is the declaration's USR and the value is the serialized bitcode.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_MAPPER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_MAPPER_H
+
+#include <memory>
+#include <string>
+#include <vector>
+#include "BitcodeWriter.h"
+#include "Representation.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/CommentVisitor.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/Execution.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang::comments;
+using namespace clang::tooling;
+
+namespace clang {
+namespace doc {
+
+class ClangDocMapper : public clang::RecursiveASTVisitor<ClangDocMapper> {
+ public:
+  explicit ClangDocMapper(ASTContext *Ctx, ExecutionContext *ECtx,
+                          bool OmitFilenames)
+      : ECtx(ECtx), Serializer(OmitFilenames) {}
+
+  bool VisitNamespaceDecl(const NamespaceDecl *D);
+  bool VisitRecordDecl(const RecordDecl *D);
+  bool VisitEnumDecl(const EnumDecl *D);
+  bool VisitCXXMethodDecl(const CXXMethodDecl *D);
+  bool VisitFunctionDecl(const FunctionDecl *D);
+
+ private:
+  class ClangDocCommentVisitor
+      : public ConstCommentVisitor<ClangDocCommentVisitor> {
+   public:
+    ClangDocCommentVisitor(CommentInfo &CI) : CurrentCI(CI) {}
+
+    void parseComment(const comments::Comment *C);
+
+    void visitTextComment(const TextComment *C);
+    void visitInlineCommandComment(const InlineCommandComment *C);
+    void visitHTMLStartTagComment(const HTMLStartTagComment *C);
+    void visitHTMLEndTagComment(const HTMLEndTagComment *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);
+
+   private:
+    std::string getCommandName(unsigned CommandID) const;
+    bool isWhitespaceOnly(StringRef S) const;
+
+    CommentInfo &CurrentCI;
+  };
+
+  class ClangDocSerializer {
+   public:
+    ClangDocSerializer(bool OmitFilenames) : Writer(OmitFilenames) {}
+
+    std::string emitInfo(const NamespaceDecl *D, const FullComment *FC,
+                         int LineNumber, StringRef File);
+    std::string emitInfo(const RecordDecl *D, const FullComment *FC,
+                         int LineNumber, StringRef File);
+    std::string emitInfo(const EnumDecl *D, const FullComment *FC,
+                         int LineNumber, StringRef File);
+    std::string emitInfo(const FunctionDecl *D, const FullComment *FC,
+                         int LineNumber, StringRef File);
+    std::string emitInfo(const CXXMethodDecl *D, const FullComment *FC,
+                         int LineNumber, StringRef File);
+
+   private:
+    template <typename T>
+    std::string serialize(T &I);
+
+    void populateInfo(Info &I, const NamedDecl *D, const FullComment *C);
+    void populateSymbolInfo(SymbolInfo &I, const NamedDecl *D,
+                            const FullComment *C, int LineNumber,
+                            StringRef File);
+    void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
+                              const FullComment *C, int LineNumber,
+                              StringRef File);
+
+    void parseFields(RecordInfo &I, const RecordDecl *D) const;
+    void parseEnumerators(EnumInfo &I, const EnumDecl *D) const;
+    void parseBases(RecordInfo &I, const CXXRecordDecl *D) const;
+    void parseParameters(FunctionInfo &I, const FunctionDecl *D) const;
+    void parseFullComment(const FullComment *C, CommentInfo &CI);
+
+    template <typename T>
+    void populateParentNamespaces(llvm::SmallVector<std::string, 4> &Namespaces,
+                                  const T *D);
+    std::string getUSRForType(const Type *T) const;
+    std::string getUSRForDecl(const Decl *D) const;
+    RecordDecl *getDeclForType(const QualType &T) const;
+
+    ClangDocBinaryWriter Writer;
+  };
+
+  template <typename T>
+  bool mapDecl(const T *D);
+
+  int getLine(const NamedDecl *D, const ASTContext &Context) const;
+  StringRef getFile(const NamedDecl *D, const ASTContext &Context) const;
+  comments::FullComment *getComment(const NamedDecl *D,
+                                    const ASTContext &Context) const;
+
+  ExecutionContext *ECtx;
+  ClangDocSerializer Serializer;
+};
+
+}  // namespace doc
+}  // namespace clang
+
+#endif  // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_MAPPER_H
Index: clang-doc/Mapper.cpp
===================================================================
--- /dev/null
+++ clang-doc/Mapper.cpp
@@ -0,0 +1,371 @@
+//===-- Mapper.cpp - ClangDoc Mapper ----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Mapper.h"
+#include "clang/AST/Comment.h"
+#include "clang/AST/Mangle.h"
+#include "clang/Index/USRGeneration.h"
+
+using namespace llvm;
+using clang::comments::FullComment;
+
+namespace clang {
+namespace doc {
+
+// ClangDocMapper::ClangDocSerializer
+
+std::string ClangDocMapper::ClangDocSerializer::emitInfo(const NamespaceDecl *D,
+                                                         const FullComment *FC,
+                                                         int LineNumber,
+                                                         StringRef File) {
+  NamespaceInfo I;
+  populateInfo(I, D, FC);
+  populateParentNamespaces(I.Namespace, D);
+  return serialize(I);
+}
+
+std::string ClangDocMapper::ClangDocSerializer::emitInfo(const RecordDecl *D,
+                                                         const FullComment *FC,
+                                                         int LineNumber,
+                                                         StringRef File) {
+  RecordInfo I;
+  if (D->isThisDeclarationADefinition()) I.IsDefinition = true;
+  populateSymbolInfo(I, D, FC, LineNumber, File);
+  populateParentNamespaces(I.Namespace, D);
+  I.TagType = D->getTagKind();
+  if (const auto *CXXR = dyn_cast<CXXRecordDecl>(D)) parseBases(I, CXXR);
+  parseFields(I, D);
+  return serialize(I);
+}
+
+std::string ClangDocMapper::ClangDocSerializer::emitInfo(const FunctionDecl *D,
+                                                         const FullComment *FC,
+                                                         int LineNumber,
+                                                         StringRef File) {
+  FunctionInfo I;
+  if (D->isThisDeclarationADefinition()) I.IsDefinition = true;
+  populateFunctionInfo(I, D, FC, LineNumber, File);
+  populateParentNamespaces(I.Namespace, D);
+  I.Access = clang::AccessSpecifier::AS_none;
+  return serialize(I);
+}
+
+std::string ClangDocMapper::ClangDocSerializer::emitInfo(const CXXMethodDecl *D,
+                                                         const FullComment *FC,
+                                                         int LineNumber,
+                                                         StringRef File) {
+  FunctionInfo I;
+  if (D->isThisDeclarationADefinition()) I.IsDefinition = true;
+  populateFunctionInfo(I, D, FC, LineNumber, File);
+  populateParentNamespaces(I.Namespace, D);
+  I.ParentUSR = getUSRForDecl(D->getParent());
+  I.Access = D->getAccess();
+  return serialize(I);
+}
+
+std::string ClangDocMapper::ClangDocSerializer::emitInfo(const EnumDecl *D,
+                                                         const FullComment *FC,
+                                                         int LineNumber,
+                                                         StringRef File) {
+  EnumInfo I;
+  if (D->isThisDeclarationADefinition()) I.IsDefinition = true;
+  populateSymbolInfo(I, D, FC, LineNumber, File);
+  populateParentNamespaces(I.Namespace, D);
+  I.Scoped = D->isScoped();
+  parseEnumerators(I, D);
+  return serialize(I);
+}
+
+template <typename T>
+std::string ClangDocMapper::ClangDocSerializer::serialize(T &I) {
+  SmallString<2048> Buffer;
+  llvm::BitstreamWriter Stream(Buffer);
+  Writer.writeBitstream(I, Stream, /*writeBlockInfo=*/true);
+  return Buffer.str().str();
+}
+
+void ClangDocMapper::ClangDocSerializer::parseFullComment(const FullComment *C,
+                                                          CommentInfo &CI) {
+  ClangDocCommentVisitor Visitor(CI);
+  Visitor.parseComment(C);
+}
+
+void ClangDocMapper::ClangDocSerializer::populateInfo(Info &I,
+                                                      const NamedDecl *D,
+                                                      const FullComment *C) {
+  I.Name = D->getNameAsString();
+  if (C) {
+    I.Description.emplace_back(std::move(CommentInfo{}));
+    parseFullComment(C, I.Description.back());
+  }
+}
+
+void ClangDocMapper::ClangDocSerializer::populateSymbolInfo(
+    SymbolInfo &I, const NamedDecl *D, const FullComment *C, int LineNumber,
+    StringRef File) {
+  populateInfo(I, D, C);
+  I.Loc.emplace_back(Location{LineNumber, File});
+}
+
+void ClangDocMapper::ClangDocSerializer::populateFunctionInfo(
+    FunctionInfo &I, const FunctionDecl *D, const FullComment *FC,
+    int LineNumber, StringRef File) {
+  populateSymbolInfo(I, D, FC, LineNumber, File);
+  if (const auto *T = getDeclForType(D->getReturnType()))
+    I.ReturnType.TypeUSR = getUSRForDecl(T);
+  else
+    I.ReturnType.TypeUSR = D->getReturnType().getAsString();
+  // TODO: Populate return type comment description from info description.
+  parseParameters(I, D);
+}
+
+void ClangDocMapper::ClangDocSerializer::parseFields(
+    RecordInfo &I, const RecordDecl *D) const {
+  for (const FieldDecl *F : D->fields()) {
+    // FIXME: Set Access to the appropriate value.
+    std::string Type;
+    if (const auto *D = getDeclForType(F->getTypeSourceInfo()->getType()))
+      Type = getUSRForDecl(D);
+    else
+      Type = F->getTypeSourceInfo()->getType().getAsString();
+    I.Members.emplace_back(MemberTypeInfo{Type, F->getQualifiedNameAsString()});
+  }
+  // TODO: Populate type comment description from info description.
+}
+
+void ClangDocMapper::ClangDocSerializer::parseEnumerators(
+    EnumInfo &I, const EnumDecl *D) const {
+  for (const EnumConstantDecl *E : D->enumerators())
+    I.Members.emplace_back(TypeInfo{E->getQualifiedNameAsString()});
+  // TODO: Populate member comment description from info description.
+}
+
+void ClangDocMapper::ClangDocSerializer::parseParameters(
+    FunctionInfo &I, const FunctionDecl *D) const {
+  for (const ParmVarDecl *P : D->parameters()) {
+    std::string Type;
+    if (const auto *D = getDeclForType(P->getOriginalType()))
+      Type = getUSRForDecl(D);
+    else
+      Type = P->getOriginalType().getAsString();
+    I.Params.emplace_back(FieldTypeInfo{Type, P->getQualifiedNameAsString()});
+    // TODO: Populate field comment description from info description.
+  }
+}
+
+void ClangDocMapper::ClangDocSerializer::parseBases(
+    RecordInfo &I, const CXXRecordDecl *D) const {
+  for (const CXXBaseSpecifier &B : D->bases()) {
+    if (B.isVirtual()) continue;
+    if (const auto *P = getDeclForType(B.getType()))
+      I.ParentUSRs.emplace_back(getUSRForDecl(P));
+    else
+      I.ParentUSRs.emplace_back(B.getType().getAsString());
+  }
+  for (const CXXBaseSpecifier &B : D->vbases()) {
+    if (const auto *P = getDeclForType(B.getType()))
+      I.VirtualParentUSRs.emplace_back(getUSRForDecl(P));
+    else
+      I.ParentUSRs.emplace_back(B.getType().getAsString());
+  }
+}
+
+RecordDecl *ClangDocMapper::ClangDocSerializer::getDeclForType(
+    const QualType &T) const {
+  auto *Ty = T->getAs<RecordType>();
+  if (!Ty) return nullptr;
+  return Ty->getDecl()->getDefinition();
+}
+
+template <typename T>
+void ClangDocMapper::ClangDocSerializer::populateParentNamespaces(
+    llvm::SmallVector<std::string, 4> &Namespaces, const T *D) {
+  const NamespaceDecl *N;
+  // Get the initial namespace parent from passed-in decl.
+  if (const auto *C = dyn_cast<DeclContext>(D)) {
+    N = dyn_cast<NamespaceDecl>(C->getParent());
+    if (!N) return;
+    Namespaces.push_back(getUSRForDecl(N));
+  }
+
+  // Get all parents until the top level namespace.
+  while (const auto *C = dyn_cast<DeclContext>(N)) {
+    N = dyn_cast<NamespaceDecl>(C->getParent());
+    if (!N) break;
+    Namespaces.push_back(getUSRForDecl(N));
+  }
+}
+
+std::string ClangDocMapper::ClangDocSerializer::getUSRForDecl(
+    const Decl *D) const {
+  llvm::SmallString<128> USR;
+  if (index::generateUSRForDecl(D, USR)) return "";
+  return USR.str().str();
+}
+
+// ClangDocCommentVisitor
+
+void ClangDocMapper::ClangDocCommentVisitor::parseComment(
+    const comments::Comment *C) {
+  CurrentCI.Kind = C->getCommentKindName();
+  ConstCommentVisitor<ClangDocCommentVisitor>::visit(C);
+  for (comments::Comment *Child :
+       make_range(C->child_begin(), C->child_end())) {
+    CurrentCI.Children.emplace_back(new CommentInfo{});
+    ClangDocCommentVisitor Visitor(*CurrentCI.Children.back());
+    Visitor.parseComment(Child);
+  }
+}
+
+void ClangDocMapper::ClangDocCommentVisitor::visitTextComment(
+    const TextComment *C) {
+  if (!isWhitespaceOnly(C->getText())) CurrentCI.Text = C->getText();
+}
+
+void ClangDocMapper::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 ClangDocMapper::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.AttrKeys.push_back(Attr.Name);
+    CurrentCI.AttrValues.push_back(Attr.Value);
+  }
+}
+
+void ClangDocMapper::ClangDocCommentVisitor::visitHTMLEndTagComment(
+    const HTMLEndTagComment *C) {
+  CurrentCI.Name = C->getTagName();
+  CurrentCI.SelfClosing = true;
+}
+
+void ClangDocMapper::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 ClangDocMapper::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 ClangDocMapper::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(std::to_string(C->getIndex(i)));
+  }
+}
+
+void ClangDocMapper::ClangDocCommentVisitor::visitVerbatimBlockComment(
+    const VerbatimBlockComment *C) {
+  CurrentCI.Name = getCommandName(C->getCommandID());
+  CurrentCI.CloseName = C->getCloseName();
+}
+
+void ClangDocMapper::ClangDocCommentVisitor::visitVerbatimBlockLineComment(
+    const VerbatimBlockLineComment *C) {
+  if (!isWhitespaceOnly(C->getText())) CurrentCI.Text = C->getText();
+}
+
+void ClangDocMapper::ClangDocCommentVisitor::visitVerbatimLineComment(
+    const VerbatimLineComment *C) {
+  if (!isWhitespaceOnly(C->getText())) CurrentCI.Text = C->getText();
+}
+
+std::string ClangDocMapper::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 ClangDocMapper::ClangDocCommentVisitor::isWhitespaceOnly(
+    StringRef S) const {
+  return std::all_of(S.begin(), S.end(), isspace);
+}
+
+// ClangDocMapper
+
+template <typename T>
+bool ClangDocMapper::mapDecl(const T *D) {
+  if (!D->getASTContext().getSourceManager().isWrittenInMainFile(
+          D->getLocation()))
+    return false;
+
+  llvm::SmallString<128> USR;
+  if (index::generateUSRForDecl(D, USR)) return false;
+
+  ECtx->reportResult(USR,
+                     Serializer.emitInfo(D, getComment(D, D->getASTContext()),
+                                         getLine(D, D->getASTContext()),
+                                         getFile(D, D->getASTContext())));
+  return true;
+}
+
+bool ClangDocMapper::VisitNamespaceDecl(const NamespaceDecl *D) {
+  return mapDecl(D);
+}
+
+bool ClangDocMapper::VisitRecordDecl(const RecordDecl *D) { return mapDecl(D); }
+
+bool ClangDocMapper::VisitEnumDecl(const EnumDecl *D) { return mapDecl(D); }
+
+bool ClangDocMapper::VisitCXXMethodDecl(const CXXMethodDecl *D) {
+  return mapDecl(D);
+}
+
+bool ClangDocMapper::VisitFunctionDecl(const FunctionDecl *D) {
+  // Don't visit CXXMethodDecls twice
+  if (dyn_cast<CXXMethodDecl>(D)) return true;
+  return mapDecl(D);
+}
+
+comments::FullComment *ClangDocMapper::getComment(
+    const NamedDecl *D, const ASTContext &Context) const {
+  RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
+  // FIXME: Move setAttached to the initial comment parsing.
+  if (Comment) {
+    Comment->setAttached();
+    return Comment->parse(Context, nullptr, D);
+  }
+  return nullptr;
+}
+
+int ClangDocMapper::getLine(const NamedDecl *D,
+                            const ASTContext &Context) const {
+  return Context.getSourceManager().getPresumedLoc(D->getLocStart()).getLine();
+}
+
+StringRef ClangDocMapper::getFile(const NamedDecl *D,
+                                  const ASTContext &Context) const {
+  return Context.getSourceManager()
+      .getPresumedLoc(D->getLocStart())
+      .getFilename();
+}
+
+}  // namespace doc
+}  // namespace clang
Index: clang-doc/ClangDoc.h
===================================================================
--- /dev/null
+++ clang-doc/ClangDoc.h
@@ -0,0 +1,81 @@
+//===-- ClangDoc.h - ClangDoc -----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the main entry point for the clang-doc tool. It runs
+// the clang-doc mapper on a given set of source code files using a
+// FrontendActionFactory.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H
+
+#include <string>
+#include <vector>
+#include "BitcodeWriter.h"
+#include "Mapper.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Comment.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace doc {
+
+class MapperActionFactory : public tooling::FrontendActionFactory {
+ public:
+  MapperActionFactory(tooling::ExecutionContext *ECtx, bool OmitFilenames)
+      : ECtx(ECtx), OmitFilenames(OmitFilenames) {}
+
+  clang::FrontendAction *create() override {
+    class ClangDocConsumer : public clang::ASTConsumer {
+     public:
+      ClangDocConsumer(ASTContext *Ctx, ExecutionContext *ECtx,
+                       bool OmitFilenames)
+          : Mapper(Ctx, ECtx, OmitFilenames){};
+      virtual void HandleTranslationUnit(clang::ASTContext &Context) {
+        Mapper.TraverseDecl(Context.getTranslationUnitDecl());
+      }
+
+     private:
+      ClangDocMapper Mapper;
+    };
+
+    class ClangDocAction : public clang::ASTFrontendAction {
+     public:
+      ClangDocAction(ExecutionContext *ECtx, bool OmitFilenames)
+          : ECtx(ECtx), OmitFilenames(OmitFilenames) {}
+
+      virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
+          clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
+        return llvm::make_unique<ClangDocConsumer>(&Compiler.getASTContext(),
+                                                   ECtx, OmitFilenames);
+      }
+
+     private:
+      ExecutionContext *ECtx;
+      bool OmitFilenames;
+    };
+    return new ClangDocAction(ECtx, OmitFilenames);
+  }
+
+  tooling::ExecutionContext *ECtx;
+  bool OmitFilenames;
+};
+
+}  // namespace doc
+}  // namespace clang
+
+#endif  // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H
Index: clang-doc/CMakeLists.txt
===================================================================
--- /dev/null
+++ clang-doc/CMakeLists.txt
@@ -0,0 +1,21 @@
+set(LLVM_LINK_COMPONENTS
+  support
+  )
+
+add_clang_library(clangDoc
+  BitcodeWriter.cpp
+  Mapper.cpp
+
+  LINK_LIBS
+  clangAnalysis
+  clangAST
+  clangASTMatchers
+  clangBasic
+  clangFrontend
+  clangIndex
+  clangLex
+  clangTooling
+  clangToolingCore
+  )
+
+add_subdirectory(tool)
Index: clang-doc/BitcodeWriter.h
===================================================================
--- /dev/null
+++ clang-doc/BitcodeWriter.h
@@ -0,0 +1,168 @@
+//===--  BitcodeWriter.h - ClangDoc Bitcode Writer --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a writer for serializing the clang-doc internal
+// represeentation to LLVM bitcode. The writer takes in a stream and emits the
+// generated bitcode to that stream.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_BINARY_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_BINARY_H
+
+#include <initializer_list>
+#include <vector>
+#include "Representation.h"
+#include "clang/AST/AST.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+
+using namespace llvm;
+
+namespace clang {
+namespace doc {
+
+#define VERSION_NUMBER 0
+
+struct BitCodeConstants {
+  static constexpr int SubblockIDSize = 5;
+  static constexpr int LineNumFixedSize = 16;
+  static constexpr int SignatureBitSize = 8;
+};
+
+enum BlockId {
+  BI_VERSION_BLOCK_ID = bitc::FIRST_APPLICATION_BLOCKID,
+  BI_NAMESPACE_BLOCK_ID,
+  BI_ENUM_BLOCK_ID,
+  BI_TYPE_BLOCK_ID,
+  BI_FIELD_TYPE_BLOCK_ID,
+  BI_MEMBER_TYPE_BLOCK_ID,
+  BI_RECORD_BLOCK_ID,
+  BI_FUNCTION_BLOCK_ID,
+  BI_COMMENT_BLOCK_ID,
+  BI_FIRST = BI_VERSION_BLOCK_ID,
+  BI_LAST = BI_COMMENT_BLOCK_ID
+};
+
+#define INFORECORDS(X) X##_NAME, X##_NAMESPACE,
+
+enum RecordId {
+  VERSION = 1,
+  COMMENT_KIND,
+  COMMENT_TEXT,
+  COMMENT_NAME,
+  COMMENT_POSITION,
+  COMMENT_DIRECTION,
+  COMMENT_PARAMNAME,
+  COMMENT_CLOSENAME,
+  COMMENT_SELFCLOSING,
+  COMMENT_EXPLICIT,
+  COMMENT_ATTRKEY,
+  COMMENT_ATTRVAL,
+  COMMENT_ARG,
+  TYPE_TYPE,
+  FIELD_TYPE_TYPE,
+  FIELD_TYPE_NAME,
+  MEMBER_TYPE_TYPE,
+  MEMBER_TYPE_NAME,
+  MEMBER_TYPE_ACCESS,
+  INFORECORDS(NAMESPACE) INFORECORDS(ENUM) ENUM_ISDEFINITION,
+  ENUM_LOCATION,
+  ENUM_SCOPED,
+  INFORECORDS(RECORD) RECORD_ISDEFINITION,
+  RECORD_LOCATION,
+  RECORD_TAG_TYPE,
+  RECORD_PARENT,
+  RECORD_VPARENT,
+  INFORECORDS(FUNCTION) FUNCTION_ISDEFINITION,
+  FUNCTION_LOCATION,
+  FUNCTION_MANGLED_NAME,
+  FUNCTION_PARENT,
+  FUNCTION_ACCESS,
+  RI_FIRST = VERSION,
+  RI_LAST = FUNCTION_ACCESS
+};
+
+#undef INFORECORDS
+
+class ClangDocBinaryWriter {
+ public:
+  ClangDocBinaryWriter(bool OmitFilenames = false)
+      : OmitFilenames(OmitFilenames){};
+
+  using RecordData = SmallVector<uint64_t, 128>;
+
+  void writeBitstream(const NamespaceInfo &I, BitstreamWriter &Stream,
+                      bool writeBlockInfo = false);
+  void writeBitstream(const RecordInfo &I, BitstreamWriter &Stream,
+                      bool writeBlockInfo = false);
+  void writeBitstream(const FunctionInfo &I, BitstreamWriter &Stream,
+                      bool writeBlockInfo = false);
+  void writeBitstream(const EnumInfo &I, BitstreamWriter &Stream,
+                      bool writeBlockInfo = false);
+
+ private:
+  class AbbreviationMap {
+    llvm::DenseMap<unsigned, unsigned> Abbrevs;
+
+   public:
+    AbbreviationMap() {}
+    void add(RecordId RID, unsigned abbrevID);
+    unsigned get(RecordId RID);
+    void clear();
+  };
+
+  class StreamSubBlock {
+    BitstreamWriter &Stream;
+
+   public:
+    StreamSubBlock(BitstreamWriter &Stream_, BlockId ID) : Stream(Stream_) {
+      Stream.EnterSubblock(ID, BitCodeConstants::SubblockIDSize);
+    }
+
+    StreamSubBlock() = default;
+    StreamSubBlock(const StreamSubBlock &) = delete;
+    StreamSubBlock &operator=(const StreamSubBlock &) = delete;
+
+    ~StreamSubBlock() { Stream.ExitBlock(); }
+  };
+
+  void emitBlockInfoBlock(BitstreamWriter &Stream);
+  void emitHeader(BitstreamWriter &Stream);
+  void emitVersion(BitstreamWriter &Stream);
+  void emitRecordID(RecordId ID, BitstreamWriter &Stream);
+  void emitBlockID(BlockId ID, BitstreamWriter &Stream);
+
+  void emitStringRecord(StringRef Str, RecordId ID, BitstreamWriter &Stream);
+  void emitLocationRecord(int LineNumber, StringRef File, RecordId ID,
+                          BitstreamWriter &Stream);
+  void emitIntRecord(int Value, RecordId ID, BitstreamWriter &Stream);
+  void emitTypeBlock(const TypeInfo &N, BitstreamWriter &Stream);
+  void emitMemberTypeBlock(const MemberTypeInfo &N, BitstreamWriter &Stream);
+  void emitFieldTypeBlock(const FieldTypeInfo &N, BitstreamWriter &Stream);
+  void emitCommentBlock(const CommentInfo *I, BitstreamWriter &Stream);
+
+  template <typename Lambda>
+  void emitAbbrev(RecordId ID, BlockId Block, Lambda &&L,
+                  BitstreamWriter &Stream);
+
+  void emitStringAbbrev(RecordId ID, BlockId Block, BitstreamWriter &Stream);
+  void emitLocationAbbrev(RecordId ID, BlockId Block, BitstreamWriter &Stream);
+  void emitIntAbbrev(RecordId ID, BlockId Block, BitstreamWriter &Stream);
+
+  RecordData Record;
+  bool OmitFilenames;
+  AbbreviationMap Abbrevs;
+};
+
+}  // namespace doc
+}  // namespace clang
+
+#endif  // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_BINARY_H
Index: clang-doc/BitcodeWriter.cpp
===================================================================
--- /dev/null
+++ clang-doc/BitcodeWriter.cpp
@@ -0,0 +1,453 @@
+//===--  BitcodeWriter.cpp - ClangDoc Bitcode Writer ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BitcodeWriter.h"
+#include "llvm/ADT/IndexedMap.h"
+
+using namespace llvm;
+
+namespace clang {
+namespace doc {
+
+// Since id enums are not zero-indexed, we need to transform the given id into
+// its associated index.
+struct BlockIdToIndexFunctor {
+  using argument_type = unsigned;
+  unsigned operator()(unsigned ID) const { return ID - BI_FIRST; }
+};
+
+struct RecordIdToIndexFunctor {
+  using argument_type = unsigned;
+  unsigned operator()(unsigned ID) const { return ID - RI_FIRST; }
+};
+
+static const llvm::IndexedMap<StringRef, BlockIdToIndexFunctor> BlockIdNameMap =
+    []() {
+      llvm::IndexedMap<StringRef, BlockIdToIndexFunctor> BlockIdNameMap;
+      BlockIdNameMap.resize(BI_LAST - BI_FIRST + 1);
+
+      // There is no init-list constructor for the IndexedMap, so have to
+      // improvise
+      static const std::initializer_list<std::pair<BlockId, const char *const>>
+          inits = {{BI_VERSION_BLOCK_ID, "VersionBlock"},
+                   {BI_NAMESPACE_BLOCK_ID, "NamespaceBlock"},
+                   {BI_ENUM_BLOCK_ID, "EnumBlock"},
+                   {BI_TYPE_BLOCK_ID, "TypeBlock"},
+                   {BI_FIELD_TYPE_BLOCK_ID, "FieldTypeBlock"},
+                   {BI_MEMBER_TYPE_BLOCK_ID, "MemberTypeBlock"},
+                   {BI_RECORD_BLOCK_ID, "RecordBlock"},
+                   {BI_FUNCTION_BLOCK_ID, "FunctionBlock"},
+                   {BI_COMMENT_BLOCK_ID, "CommentBlock"}};
+      for (const auto &init : inits) {
+        BlockIdNameMap[init.first] = init.second;
+      }
+      return BlockIdNameMap;
+    }();
+
+static const llvm::IndexedMap<StringRef, RecordIdToIndexFunctor>
+    RecordIdNameMap = []() {
+      llvm::IndexedMap<StringRef, RecordIdToIndexFunctor> RecordIdNameMap;
+      RecordIdNameMap.resize(RI_LAST - RI_FIRST + 1);
+
+      // There is no init-list constructor for the IndexedMap, so have to
+      // improvise
+      static const std::initializer_list<std::pair<RecordId, const char *const>>
+          inits = {{VERSION, "Version"},
+                   {COMMENT_KIND, "Kind"},
+                   {COMMENT_TEXT, "Text"},
+                   {COMMENT_NAME, "Name"},
+                   {COMMENT_POSITION, "Position"},
+                   {COMMENT_DIRECTION, "Direction"},
+                   {COMMENT_PARAMNAME, "ParamName"},
+                   {COMMENT_CLOSENAME, "CloseName"},
+                   {COMMENT_SELFCLOSING, "SelfClosing"},
+                   {COMMENT_EXPLICIT, "Explicit"},
+                   {COMMENT_ATTRKEY, "AttrKey"},
+                   {COMMENT_ATTRVAL, "AttrVal"},
+                   {COMMENT_ARG, "Arg"},
+                   {TYPE_TYPE, "Type"},
+                   {FIELD_TYPE_TYPE, "Type"},
+                   {FIELD_TYPE_NAME, "Name"},
+                   {MEMBER_TYPE_TYPE, "Type"},
+                   {MEMBER_TYPE_NAME, "Name"},
+                   {MEMBER_TYPE_ACCESS, "Access"},
+                   {NAMESPACE_NAME, "Name"},
+                   {NAMESPACE_NAMESPACE, "Namespace"},
+                   {ENUM_NAME, "Name"},
+                   {ENUM_NAMESPACE, "Namespace"},
+                   {ENUM_ISDEFINITION, "IsDefinition"},
+                   {ENUM_LOCATION, "Location"},
+                   {ENUM_SCOPED, "Scoped"},
+                   {RECORD_NAME, "Name"},
+                   {RECORD_NAMESPACE, "Namespace"},
+                   {RECORD_ISDEFINITION, "IsDefinition"},
+                   {RECORD_LOCATION, "Location"},
+                   {RECORD_TAG_TYPE, "TagType"},
+                   {RECORD_PARENT, "Parent"},
+                   {RECORD_VPARENT, "VParent"},
+                   {FUNCTION_NAME, "Name"},
+                   {FUNCTION_NAMESPACE, "Namespace"},
+                   {FUNCTION_LOCATION, "Location"},
+                   {FUNCTION_ISDEFINITION, "IsDefinition"},
+                   {FUNCTION_PARENT, "Parent"},
+                   {FUNCTION_ACCESS, "Access"}};
+      for (const auto &init : inits) {
+        RecordIdNameMap[init.first] = init.second;
+      }
+      return RecordIdNameMap;
+    }();
+
+void ClangDocBinaryWriter::AbbreviationMap::add(RecordId RID,
+                                                unsigned AbbrevID) {
+  assert(Abbrevs.find(RID) == Abbrevs.end() && "Abbreviation already added.");
+  Abbrevs[RID] = AbbrevID;
+}
+
+unsigned ClangDocBinaryWriter::AbbreviationMap::get(RecordId RID) {
+  assert(Abbrevs.find(RID) != Abbrevs.end() && "Unknown abbreviation.");
+  return Abbrevs[RID];
+}
+
+void ClangDocBinaryWriter::AbbreviationMap::clear() { Abbrevs.clear(); }
+
+void ClangDocBinaryWriter::emitHeader(BitstreamWriter &Stream) {
+  // Emit the file header.
+  Stream.Emit((unsigned)'D', BitCodeConstants::SignatureBitSize);
+  Stream.Emit((unsigned)'O', BitCodeConstants::SignatureBitSize);
+  Stream.Emit((unsigned)'C', BitCodeConstants::SignatureBitSize);
+  Stream.Emit((unsigned)'S', BitCodeConstants::SignatureBitSize);
+}
+
+void ClangDocBinaryWriter::emitVersion(BitstreamWriter &Stream) {
+  // Emit the version number
+  StreamSubBlock Block(Stream, BI_VERSION_BLOCK_ID);
+  Stream.EmitRecord(VERSION, ArrayRef<uint64_t>{VERSION_NUMBER});
+}
+
+/// \brief Emits a block ID in the BLOCKINFO block.
+void ClangDocBinaryWriter::emitBlockID(BlockId ID, BitstreamWriter &Stream) {
+  Record.clear();
+  Record.push_back(ID);
+  Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
+
+  Record.clear();
+  for (const char C : BlockIdNameMap[ID]) Record.push_back(C);
+  Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
+}
+
+/// \brief Emits a record ID in the BLOCKINFO block.
+void ClangDocBinaryWriter::emitRecordID(RecordId ID, BitstreamWriter &Stream) {
+  Record.clear();
+  Record.push_back(ID);
+  for (const char C : RecordIdNameMap[ID]) Record.push_back(C);
+  Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
+}
+
+// Common Abbreviations
+
+template <typename Lambda>
+void ClangDocBinaryWriter::emitAbbrev(RecordId ID, BlockId Block, Lambda &&L,
+                                      BitstreamWriter &Stream) {
+  auto Abbrev = std::make_shared<BitCodeAbbrev>();
+  Abbrev->Add(BitCodeAbbrevOp(ID));
+  L(Abbrev);
+  Abbrevs.add(ID, Stream.EmitBlockInfoAbbrev(Block, std::move(Abbrev)));
+}
+
+void ClangDocBinaryWriter::emitStringAbbrev(RecordId ID, BlockId Block,
+                                            BitstreamWriter &Stream) {
+  auto EmitString = [](std::shared_ptr<BitCodeAbbrev> &Abbrev) {
+    Abbrev->Add(
+        BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
+                        BitCodeConstants::LineNumFixedSize));  // String size
+    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));       // String
+  };
+  emitAbbrev(ID, Block, EmitString, Stream);
+}
+
+void ClangDocBinaryWriter::emitLocationAbbrev(RecordId ID, BlockId Block,
+                                              BitstreamWriter &Stream) {
+  auto EmitString = [](std::shared_ptr<BitCodeAbbrev> &Abbrev) {
+    Abbrev->Add(
+        BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
+                        BitCodeConstants::LineNumFixedSize));  // Line number
+    Abbrev->Add(
+        BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
+                        BitCodeConstants::LineNumFixedSize));  // Filename size
+    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));       // Filename
+  };
+  emitAbbrev(ID, Block, EmitString, Stream);
+}
+
+void ClangDocBinaryWriter::emitIntAbbrev(RecordId ID, BlockId Block,
+                                         BitstreamWriter &Stream) {
+  auto EmitString = [](std::shared_ptr<BitCodeAbbrev> &Abbrev) {
+    Abbrev->Add(
+        BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
+                        BitCodeConstants::LineNumFixedSize));  // Integer
+  };
+  emitAbbrev(ID, Block, EmitString, Stream);
+}
+
+// Common Records
+
+void ClangDocBinaryWriter::emitStringRecord(StringRef Str, RecordId ID,
+                                            BitstreamWriter &Stream) {
+  if (Str.empty()) return;
+  Record.clear();
+  Record.push_back(ID);
+  Record.push_back(Str.size());
+  Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Str);
+}
+
+void ClangDocBinaryWriter::emitLocationRecord(int LineNumber, StringRef File,
+                                              RecordId ID,
+                                              BitstreamWriter &Stream) {
+  if (OmitFilenames) return;
+  Record.clear();
+  Record.push_back(ID);
+  Record.push_back(LineNumber);
+  Record.push_back(File.size());
+  Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, File);
+}
+
+void ClangDocBinaryWriter::emitIntRecord(int Value, RecordId ID,
+                                         BitstreamWriter &Stream) {
+  if (!Value) return;
+  Record.clear();
+  Record.push_back(ID);
+  Record.push_back(Value);
+  Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
+}
+
+// Common Blocks
+
+void ClangDocBinaryWriter::emitTypeBlock(const TypeInfo &T,
+                                         BitstreamWriter &Stream) {
+  StreamSubBlock Block(Stream, BI_FIELD_TYPE_BLOCK_ID);
+  emitStringRecord(T.TypeUSR, FIELD_TYPE_TYPE, Stream);
+  for (const auto &CI : T.Description) emitCommentBlock(&CI, Stream);
+}
+
+void ClangDocBinaryWriter::emitFieldTypeBlock(const FieldTypeInfo &T,
+                                              BitstreamWriter &Stream) {
+  StreamSubBlock Block(Stream, BI_FIELD_TYPE_BLOCK_ID);
+  emitStringRecord(T.TypeUSR, FIELD_TYPE_TYPE, Stream);
+  emitStringRecord(T.Name, FIELD_TYPE_NAME, Stream);
+  for (const auto &CI : T.Description) emitCommentBlock(&CI, Stream);
+}
+
+void ClangDocBinaryWriter::emitMemberTypeBlock(const MemberTypeInfo &T,
+                                               BitstreamWriter &Stream) {
+  StreamSubBlock Block(Stream, BI_MEMBER_TYPE_BLOCK_ID);
+  emitStringRecord(T.TypeUSR, MEMBER_TYPE_TYPE, Stream);
+  emitStringRecord(T.Name, MEMBER_TYPE_NAME, Stream);
+  emitIntRecord(T.Access, MEMBER_TYPE_ACCESS, Stream);
+  for (const auto &CI : T.Description) emitCommentBlock(&CI, Stream);
+}
+
+void ClangDocBinaryWriter::emitCommentBlock(const CommentInfo *I,
+                                            BitstreamWriter &Stream) {
+  StreamSubBlock Block(Stream, BI_COMMENT_BLOCK_ID);
+  emitStringRecord(I->Text, COMMENT_TEXT, Stream);
+  emitStringRecord(I->Name, COMMENT_NAME, Stream);
+  emitStringRecord(I->Direction, COMMENT_DIRECTION, Stream);
+  emitStringRecord(I->ParamName, COMMENT_PARAMNAME, Stream);
+  emitStringRecord(I->CloseName, COMMENT_CLOSENAME, Stream);
+  emitIntRecord(I->SelfClosing, COMMENT_SELFCLOSING, Stream);
+  emitIntRecord(I->Explicit, COMMENT_EXPLICIT, Stream);
+  for (const auto &A : I->AttrKeys)
+    emitStringRecord(A, COMMENT_ATTRKEY, Stream);
+  for (const auto &A : I->AttrValues)
+    emitStringRecord(A, COMMENT_ATTRVAL, Stream);
+  for (const auto &A : I->Args) emitStringRecord(A, COMMENT_ARG, Stream);
+  for (const auto &P : I->Position)
+    emitStringRecord(P, COMMENT_POSITION, Stream);
+  for (const auto &C : I->Children) emitCommentBlock(C, Stream);
+}
+
+void ClangDocBinaryWriter::emitBlockInfoBlock(BitstreamWriter &Stream) {
+  Abbrevs.clear();
+  emitHeader(Stream);
+  Stream.EnterBlockInfoBlock();
+
+  // Version block
+  emitBlockID(BI_VERSION_BLOCK_ID, Stream);
+  emitRecordID(VERSION, Stream);
+
+  // Comment Block
+  emitBlockID(BI_COMMENT_BLOCK_ID, Stream);
+  emitRecordID(COMMENT_KIND, Stream);
+  emitRecordID(COMMENT_TEXT, Stream);
+  emitRecordID(COMMENT_NAME, Stream);
+  emitRecordID(COMMENT_DIRECTION, Stream);
+  emitRecordID(COMMENT_PARAMNAME, Stream);
+  emitRecordID(COMMENT_CLOSENAME, Stream);
+  emitRecordID(COMMENT_SELFCLOSING, Stream);
+  emitRecordID(COMMENT_EXPLICIT, Stream);
+  emitRecordID(COMMENT_ATTRKEY, Stream);
+  emitRecordID(COMMENT_ATTRVAL, Stream);
+  emitRecordID(COMMENT_ARG, Stream);
+  emitRecordID(COMMENT_POSITION, Stream);
+  emitStringAbbrev(COMMENT_KIND, BI_COMMENT_BLOCK_ID, Stream);
+  emitStringAbbrev(COMMENT_TEXT, BI_COMMENT_BLOCK_ID, Stream);
+  emitStringAbbrev(COMMENT_NAME, BI_COMMENT_BLOCK_ID, Stream);
+  emitStringAbbrev(COMMENT_DIRECTION, BI_COMMENT_BLOCK_ID, Stream);
+  emitStringAbbrev(COMMENT_PARAMNAME, BI_COMMENT_BLOCK_ID, Stream);
+  emitStringAbbrev(COMMENT_CLOSENAME, BI_COMMENT_BLOCK_ID, Stream);
+  emitIntAbbrev(COMMENT_SELFCLOSING, BI_COMMENT_BLOCK_ID, Stream);
+  emitIntAbbrev(COMMENT_EXPLICIT, BI_COMMENT_BLOCK_ID, Stream);
+  emitStringAbbrev(COMMENT_ATTRKEY, BI_COMMENT_BLOCK_ID, Stream);
+  emitStringAbbrev(COMMENT_ATTRVAL, BI_COMMENT_BLOCK_ID, Stream);
+  emitStringAbbrev(COMMENT_ARG, BI_COMMENT_BLOCK_ID, Stream);
+  emitStringAbbrev(COMMENT_POSITION, BI_COMMENT_BLOCK_ID, Stream);
+
+  // TypeInfo Block
+  emitBlockID(BI_TYPE_BLOCK_ID, Stream);
+  emitRecordID(TYPE_TYPE, Stream);
+  emitStringAbbrev(TYPE_TYPE, BI_TYPE_BLOCK_ID, Stream);
+
+  // FieldTypeInfo Block
+  emitBlockID(BI_FIELD_TYPE_BLOCK_ID, Stream);
+  emitRecordID(FIELD_TYPE_TYPE, Stream);
+  emitRecordID(FIELD_TYPE_NAME, Stream);
+  emitStringAbbrev(FIELD_TYPE_TYPE, BI_FIELD_TYPE_BLOCK_ID, Stream);
+  emitStringAbbrev(FIELD_TYPE_NAME, BI_FIELD_TYPE_BLOCK_ID, Stream);
+
+  // MemberTypeInfo Block
+  emitBlockID(BI_MEMBER_TYPE_BLOCK_ID, Stream);
+  emitRecordID(MEMBER_TYPE_TYPE, Stream);
+  emitRecordID(MEMBER_TYPE_NAME, Stream);
+  emitRecordID(MEMBER_TYPE_ACCESS, Stream);
+  emitStringAbbrev(MEMBER_TYPE_TYPE, BI_MEMBER_TYPE_BLOCK_ID, Stream);
+  emitStringAbbrev(MEMBER_TYPE_NAME, BI_MEMBER_TYPE_BLOCK_ID, Stream);
+  emitIntAbbrev(MEMBER_TYPE_ACCESS, BI_MEMBER_TYPE_BLOCK_ID, Stream);
+
+#define INFORECORD(X)             \
+  emitRecordID(X##_NAME, Stream); \
+  emitRecordID(X##_NAMESPACE, Stream);
+
+#define INFOABBREV(X)                                    \
+  emitStringAbbrev(X##_NAME, BI_##X##_BLOCK_ID, Stream); \
+  emitStringAbbrev(X##_NAMESPACE, BI_##X##_BLOCK_ID, Stream);
+
+  // Namespace Block
+  emitBlockID(BI_NAMESPACE_BLOCK_ID, Stream);
+  INFORECORD(NAMESPACE)
+  INFOABBREV(NAMESPACE)
+
+  // Enum Block
+  emitBlockID(BI_ENUM_BLOCK_ID, Stream);
+  INFORECORD(ENUM)
+  emitRecordID(ENUM_ISDEFINITION, Stream);
+  emitRecordID(ENUM_LOCATION, Stream);
+  emitRecordID(ENUM_SCOPED, Stream);
+  INFOABBREV(ENUM)
+  emitIntAbbrev(ENUM_ISDEFINITION, BI_ENUM_BLOCK_ID, Stream);
+  emitLocationAbbrev(ENUM_LOCATION, BI_ENUM_BLOCK_ID, Stream);
+  emitIntAbbrev(ENUM_SCOPED, BI_ENUM_BLOCK_ID, Stream);
+
+  // Record Block
+  emitBlockID(BI_RECORD_BLOCK_ID, Stream);
+  INFORECORD(RECORD)
+  emitRecordID(RECORD_ISDEFINITION, Stream);
+  emitRecordID(RECORD_LOCATION, Stream);
+  emitRecordID(RECORD_TAG_TYPE, Stream);
+  emitRecordID(RECORD_PARENT, Stream);
+  emitRecordID(RECORD_VPARENT, Stream);
+  INFOABBREV(RECORD)
+  emitIntAbbrev(RECORD_ISDEFINITION, BI_RECORD_BLOCK_ID, Stream);
+  emitLocationAbbrev(RECORD_LOCATION, BI_RECORD_BLOCK_ID, Stream);
+  emitIntAbbrev(RECORD_TAG_TYPE, BI_RECORD_BLOCK_ID, Stream);
+  emitStringAbbrev(RECORD_PARENT, BI_RECORD_BLOCK_ID, Stream);
+  emitStringAbbrev(RECORD_VPARENT, BI_RECORD_BLOCK_ID, Stream);
+
+  // Function Block
+  emitBlockID(BI_FUNCTION_BLOCK_ID, Stream);
+  INFORECORD(FUNCTION)
+  emitRecordID(FUNCTION_ISDEFINITION, Stream);
+  emitRecordID(FUNCTION_LOCATION, Stream);
+  emitRecordID(FUNCTION_PARENT, Stream);
+  emitRecordID(FUNCTION_ACCESS, Stream);
+  INFOABBREV(FUNCTION)
+  emitIntAbbrev(FUNCTION_ISDEFINITION, BI_FUNCTION_BLOCK_ID, Stream);
+  emitLocationAbbrev(FUNCTION_LOCATION, BI_FUNCTION_BLOCK_ID, Stream);
+  emitStringAbbrev(FUNCTION_PARENT, BI_FUNCTION_BLOCK_ID, Stream);
+  emitIntAbbrev(FUNCTION_ACCESS, BI_FUNCTION_BLOCK_ID, Stream);
+
+#undef INFORECORDS
+#undef INFOABBREV
+
+  Stream.ExitBlock();
+  emitVersion(Stream);
+}
+
+// Info emission
+
+#define EMITINFO(X)                             \
+  emitStringRecord(I.Name, X##_NAME, Stream);   \
+  for (const auto &N : I.Namespace)             \
+    emitStringRecord(N, X##_NAMESPACE, Stream); \
+  for (const auto &CI : I.Description) emitCommentBlock(&CI, Stream);
+
+void ClangDocBinaryWriter::writeBitstream(const NamespaceInfo &I,
+                                          BitstreamWriter &Stream,
+                                          bool writeBlockInfo) {
+  if (writeBlockInfo) emitBlockInfoBlock(Stream);
+  StreamSubBlock Block(Stream, BI_NAMESPACE_BLOCK_ID);
+  EMITINFO(NAMESPACE)
+}
+
+void ClangDocBinaryWriter::writeBitstream(const EnumInfo &I,
+                                          BitstreamWriter &Stream,
+                                          bool writeBlockInfo) {
+  if (writeBlockInfo) emitBlockInfoBlock(Stream);
+  StreamSubBlock Block(Stream, BI_ENUM_BLOCK_ID);
+  EMITINFO(ENUM)
+  emitIntRecord(I.IsDefinition, ENUM_ISDEFINITION, Stream);
+  for (const auto &L : I.Loc)
+    emitLocationRecord(L.LineNumber, L.Filename, ENUM_LOCATION, Stream);
+  emitIntRecord(I.Scoped, ENUM_SCOPED, Stream);
+  for (const auto &N : I.Members) emitTypeBlock(N, Stream);
+}
+
+void ClangDocBinaryWriter::writeBitstream(const RecordInfo &I,
+                                          BitstreamWriter &Stream,
+                                          bool writeBlockInfo) {
+  if (writeBlockInfo) emitBlockInfoBlock(Stream);
+  StreamSubBlock Block(Stream, BI_RECORD_BLOCK_ID);
+  EMITINFO(RECORD)
+  emitIntRecord(I.IsDefinition, RECORD_ISDEFINITION, Stream);
+  for (const auto &L : I.Loc)
+    emitLocationRecord(L.LineNumber, L.Filename, RECORD_LOCATION, Stream);
+  emitIntRecord(I.TagType, RECORD_TAG_TYPE, Stream);
+  for (const auto &N : I.Members) emitMemberTypeBlock(N, Stream);
+  for (const auto &P : I.ParentUSRs) emitStringRecord(P, RECORD_PARENT, Stream);
+  for (const auto &P : I.VirtualParentUSRs)
+    emitStringRecord(P, RECORD_VPARENT, Stream);
+}
+
+void ClangDocBinaryWriter::writeBitstream(const FunctionInfo &I,
+                                          BitstreamWriter &Stream,
+                                          bool writeBlockInfo) {
+  if (writeBlockInfo) emitBlockInfoBlock(Stream);
+  StreamSubBlock Block(Stream, BI_FUNCTION_BLOCK_ID);
+  EMITINFO(FUNCTION)
+  emitIntRecord(I.IsDefinition, FUNCTION_ISDEFINITION, Stream);
+  for (const auto &L : I.Loc)
+    emitLocationRecord(L.LineNumber, L.Filename, FUNCTION_LOCATION, Stream);
+  emitStringRecord(I.ParentUSR, FUNCTION_PARENT, Stream);
+  emitTypeBlock(I.ReturnType, Stream);
+  for (const auto &N : I.Params) emitFieldTypeBlock(N, Stream);
+}
+
+#undef EMITINFO
+
+}  // namespace doc
+}  // namespace clang
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt
+++ CMakeLists.txt
@@ -7,6 +7,7 @@
 endif()
 
 add_subdirectory(change-namespace)
+add_subdirectory(clang-doc)
 add_subdirectory(clang-query)
 add_subdirectory(clang-move)
 add_subdirectory(clangd)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to