juliehockett updated this revision to Diff 132075.
juliehockett edited the summary of this revision.
juliehockett added a reviewer: jakehehrlich.
juliehockett added a comment.

1. Updating and expanding tests
2. Updating output options (can now write to files)
3. Cleaning up pointers and whatnot




https://reviews.llvm.org/D41102

Files:
  test/CMakeLists.txt
  test/Tooling/clang-doc-basic.cpp
  test/Tooling/clang-doc-namespace.cpp
  test/Tooling/clang-doc-type.cpp
  test/lit.cfg.py
  tools/CMakeLists.txt
  tools/clang-doc/CMakeLists.txt
  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/CMakeLists.txt
  tools/clang-doc/tool/ClangDocMain.cpp

Index: tools/clang-doc/tool/ClangDocMain.cpp
===================================================================
--- /dev/null
+++ tools/clang-doc/tool/ClangDocMain.cpp
@@ -0,0 +1,103 @@
+//===-- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangDoc.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;
+using namespace llvm;
+
+namespace {
+
+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)."),
+             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>
+    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]);
+  tooling::CommonOptionsParser OptionsParser(argc, argv, ClangDocCategory);
+  std::error_code OK;
+
+  doc::OutFormat EmitFormat;
+  SmallString<128> IRFilePath;
+  sys::path::native(OutDirectory, IRFilePath);
+  std::string IRFilename;
+  if (EmitLLVM) {
+    EmitFormat = doc::OutFormat::LLVM;
+    sys::path::append(IRFilePath, "llvm");
+    IRFilename = "docs.bc";
+  } else {
+    EmitFormat = doc::OutFormat::YAML;
+    sys::path::append(IRFilePath, "yaml");
+    IRFilename = "docs.yaml";
+  }
+
+  std::error_code DirectoryStatus = sys::fs::create_directories(IRFilePath);
+  if (DirectoryStatus != OK) {
+    errs() << "Unable to create documentation directories.\n";
+    return 1;
+  }
+
+  sys::path::append(IRFilePath, IRFilename);
+
+  doc::ClangDocReporter Reporter(OptionsParser.getSourcePathList(),
+                                 OmitFilenames);
+  doc::ClangDocContext Context{EmitFormat};
+
+  tooling::ClangTool Tool(OptionsParser.getCompilations(),
+                          OptionsParser.getSourcePathList());
+
+  if (!DoxygenOnly)
+    Tool.appendArgumentsAdjuster(tooling::getInsertArgumentAdjuster(
+        "-fparse-all-comments", tooling::ArgumentInsertPosition::BEGIN));
+
+  doc::ClangDocActionFactory Factory(Context, Reporter);
+
+  outs() << "Parsing codebase...\n";
+  int Status = Tool.run(&Factory);
+  if (Status)
+    return Status;
+
+  outs() << "Writing intermediate docs...\n";
+  if (DumpResult)
+    Reporter.serialize(EmitFormat, "");
+  else
+    Reporter.serialize(EmitFormat, IRFilePath);
+  return 0;
+}
Index: tools/clang-doc/tool/CMakeLists.txt
===================================================================
--- /dev/null
+++ tools/clang-doc/tool/CMakeLists.txt
@@ -0,0 +1,18 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+add_clang_executable(clang-doc
+  ClangDocMain.cpp
+  )
+
+target_link_libraries(clang-doc
+  PRIVATE
+  clangAST
+  clangASTMatchers
+  clangBasic
+  clangFormat
+  clangFrontend
+  clangDoc
+  clangRewrite
+  clangTooling
+  clangToolingCore
+  )
Index: tools/clang-doc/ClangDocYAML.h
===================================================================
--- /dev/null
+++ tools/clang-doc/ClangDocYAML.h
@@ -0,0 +1,160 @@
+//===--  ClangDocYAML.h - ClangDoc YAML -------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_YAML_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_YAML_H
+
+#include "llvm/Support/YAMLTraits.h"
+
+using namespace clang::doc;
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(std::shared_ptr<CommentInfo>)
+LLVM_YAML_IS_SEQUENCE_VECTOR(NamedType)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Location)
+
+namespace llvm {
+namespace yaml {
+
+template <> struct ScalarEnumerationTraits<clang::AccessSpecifier> {
+  static void enumeration(IO &io, clang::AccessSpecifier &value) {
+    io.enumCase(value, "Public", clang::AccessSpecifier::AS_public);
+    io.enumCase(value, "Protected", clang::AccessSpecifier::AS_protected);
+    io.enumCase(value, "Private", clang::AccessSpecifier::AS_private);
+    io.enumCase(value, "None", clang::AccessSpecifier::AS_none);
+  }
+};
+
+template <> struct ScalarEnumerationTraits<clang::TagTypeKind> {
+  static void enumeration(IO &io, clang::TagTypeKind &value) {
+    io.enumCase(value, "Struct", clang::TagTypeKind::TTK_Struct);
+    io.enumCase(value, "Interface", clang::TagTypeKind::TTK_Interface);
+    io.enumCase(value, "Union", clang::TagTypeKind::TTK_Union);
+    io.enumCase(value, "Class", clang::TagTypeKind::TTK_Class);
+    io.enumCase(value, "Enum", clang::TagTypeKind::TTK_Enum);
+  }
+};
+
+template <> struct MappingTraits<Location> {
+  static void mapping(IO &IO, Location &Location) {
+    IO.mapRequired("LineNumber", Location.LineNumber);
+    IO.mapRequired("Filename", Location.Filename);
+  }
+};
+
+template <> struct MappingTraits<NamespaceInfo> {
+  static void mapping(IO &IO, NamespaceInfo &N) {
+    if (!N.isDefined)
+      return;
+    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<TypeInfo> {
+  static void mapping(IO &IO, TypeInfo &T) {
+    if (!T.isDefined)
+      return;
+    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<EnumInfo> {
+  static void mapping(IO &IO, EnumInfo &E) {
+    if (!E.isDefined)
+      return;
+    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<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<FunctionInfo> {
+  static void mapping(IO &IO, FunctionInfo &F) {
+    if (!F.isDefined)
+      return;
+    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<File> {
+  static void mapping(IO &IO, File &F) {
+    IO.mapRequired("Filename", F.Filename);
+    IO.mapRequired("Description", F.Description);
+  }
+};
+
+template <> struct MappingTraits<std::shared_ptr<CommentInfo>> {
+
+  static void mapping(IO &IO, std::shared_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);
+  }
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_YAML_H
Index: tools/clang-doc/ClangDocReporter.h
===================================================================
--- /dev/null
+++ tools/clang-doc/ClangDocReporter.h
@@ -0,0 +1,197 @@
+//===-- Doc.cpp - ClangDoc --------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_REPORTER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_REPORTER_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/Tooling.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+using namespace clang::comments;
+
+namespace clang {
+namespace doc {
+
+enum class OutFormat { YAML, LLVM };
+
+// Info for named types (parameters, members).
+struct NamedType {
+  std::string Type;
+  std::string Name;
+  AccessSpecifier Access;
+};
+
+struct Location {
+  int LineNumber;
+  std::string Filename;
+};
+
+/// A representation of a parsed comment.
+struct CommentInfo {
+  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<NamedType, 4> Attrs;
+  llvm::SmallVector<std::string, 4> Args;
+  llvm::SmallVector<int, 4> Position;
+  std::vector<std::shared_ptr<CommentInfo>> Children;
+};
+
+/// A source file in the project.
+struct File {
+  std::string Filename;
+  std::shared_ptr<CommentInfo> Description;
+  llvm::SmallVector<std::shared_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<std::shared_ptr<CommentInfo>> Descriptions;
+  llvm::SmallVector<Location, 2> Locations;
+};
+
+// TODO: Expand to allow for documenting templating.
+// Info for functions.
+struct FunctionInfo : public Info {
+  std::string MangledName;
+  std::string DefinitionFile;
+  std::string ReturnType;
+  llvm::SmallVector<NamedType, 4> Params;
+  AccessSpecifier Access;
+};
+
+struct NamespaceInfo : public Info {
+  llvm::StringMap<std::unique_ptr<FunctionInfo>> Functions;
+};
+
+// TODO: Expand to allow for documenting templating, inheritance access,
+// friend classes
+// Info for types.
+struct TypeInfo : public Info {
+  std::string DefinitionFile;
+  TagTypeKind TagType;
+  llvm::SmallVector<NamedType, 8> Members;
+  llvm::SmallVector<std::string, 8> Parents;
+  llvm::SmallVector<std::string, 8> VirtualParents;
+  llvm::StringMap<std::unique_ptr<FunctionInfo>> Functions;
+};
+
+// TODO: Expand to allow for documenting templating.
+// Info for types.
+struct EnumInfo : public Info {
+  std::string DefinitionFile;
+  bool Scoped;
+  llvm::SmallVector<NamedType, 8> Members;
+};
+
+/// A struct encapsulating all documentation information for the project.
+struct Documentation {
+  bool OmitFilenames = false;
+  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.
+};
+
+class ClangDocReporter : public ConstCommentVisitor<ClangDocReporter> {
+public:
+  ClangDocReporter() {}
+  ClangDocReporter(const std::vector<std::string> &Sources, bool OmitFilenames);
+
+  void addUnattachedComment(StringRef Filename,
+                            std::shared_ptr<CommentInfo> CI);
+  void addFile(StringRef Filename);
+
+  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, std::shared_ptr<CommentInfo> &CI);
+  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);
+
+  bool hasFile(StringRef Filename) const;
+  void serialize(clang::doc::OutFormat Format, StringRef RootDir);
+
+private:
+  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(std::shared_ptr<CommentInfo> &CI,
+                    const comments::Comment *C);
+  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;
+
+  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 serializeLLVM(StringRef RootDir);
+
+  const char *getCommandName(unsigned CommandID) const;
+  bool isWhitespaceOnly(StringRef S) const;
+  std::string getParentNamespace(const DeclContext *D) const;
+
+  std::shared_ptr<CommentInfo> CurrentCI;
+  Documentation Docs;
+};
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANG_DOC_REPORTER_H
Index: tools/clang-doc/ClangDocReporter.cpp
===================================================================
--- /dev/null
+++ tools/clang-doc/ClangDocReporter.cpp
@@ -0,0 +1,444 @@
+//===-- ClangDocReporter.cpp - ClangDoc Reporter ----------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangDocReporter.h"
+#include "ClangDocYAML.h"
+#include "llvm/Support/Path.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) {
+  for (const std::string &Path : Sources) {
+    assert(sys::path::is_absolute(Path) && "clang-doc expects absolute paths.");
+    addFile(Path);
+  }
+  // Create base namespace
+  std::unique_ptr<NamespaceInfo> I = make_unique<NamespaceInfo>();
+  I->isDefined = true;
+  Docs.Namespaces[""] = std::move(I);
+  Docs.OmitFilenames = OF;
+}
+
+void ClangDocReporter::addUnattachedComment(StringRef Filename,
+                                            std::shared_ptr<CommentInfo> CI) {
+  Docs.Files[Filename]->UnattachedComments.push_back(std::move(CI));
+}
+
+void ClangDocReporter::addFile(StringRef Filename) {
+  std::unique_ptr<File> F = make_unique<File>();
+  F->Filename = Filename;
+  Docs.Files.insert(std::make_pair(Filename, std::move(F)));
+}
+
+void ClangDocReporter::createNamespaceInfo(const NamespaceDecl *D,
+                                           const FullComment *C, int LineNumber,
+                                           StringRef File) {
+  std::string Name = D->getQualifiedNameAsString();
+  llvm::StringMapIterator<std::unique_ptr<NamespaceInfo>> Pair =
+      Docs.Namespaces.find(Name);
+  if (Pair == Docs.Namespaces.end()) {
+    std::unique_ptr<NamespaceInfo> I = make_unique<NamespaceInfo>();
+    Docs.Namespaces[Name] = std::move(I);
+    populateBasicInfo(*Docs.Namespaces[Name], Name, D->getNameAsString(),
+                      getParentNamespace(D));
+  }
+
+  addLocation(*Docs.Namespaces[Name], LineNumber, File);
+  addComment(*Docs.Namespaces[Name], C);
+}
+
+void ClangDocReporter::createTypeInfo(const RecordDecl *D, const FullComment *C,
+                                      int LineNumber, StringRef File) {
+
+  std::string Name = D->getQualifiedNameAsString();
+  llvm::StringMapIterator<std::unique_ptr<TypeInfo>> Pair =
+      Docs.Types.find(Name);
+  if (Pair == Docs.Types.end()) {
+    std::unique_ptr<TypeInfo> I = make_unique<TypeInfo>();
+    Docs.Types[Name] = std::move(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<std::unique_ptr<EnumInfo>> Pair =
+      Docs.Enums.find(Name);
+  if (Pair == Docs.Enums.end()) {
+    std::unique_ptr<EnumInfo> I = make_unique<EnumInfo>();
+    Docs.Enums[Name] = std::move(I);
+  }
+
+  if (D->isThisDeclarationADefinition())
+    populateEnumInfo(*Docs.Enums[Name], D, Name, File);
+
+  addLocation(*Docs.Enums[Name], LineNumber, File);
+  addComment(*Docs.Enums[Name], C);
+}
+
+void ClangDocReporter::createFunctionInfo(const FunctionDecl *D,
+                                          const FullComment *C, int LineNumber,
+                                          StringRef File,
+                                          StringRef MangledName) {
+  std::string Namespace = getParentNamespace(D);
+  llvm::StringMapIterator<std::unique_ptr<NamespaceInfo>> NS =
+      Docs.Namespaces.find(Namespace);
+  if (NS == Docs.Namespaces.end()) {
+    std::unique_ptr<NamespaceInfo> NI = make_unique<NamespaceInfo>();
+    NI->FullyQualifiedName = Namespace;
+    Docs.Namespaces[Namespace] = std::move(NI);
+  }
+
+  llvm::StringMapIterator<std::unique_ptr<FunctionInfo>> Pair =
+      Docs.Namespaces[Namespace]->Functions.find(MangledName);
+  if (Pair == Docs.Namespaces[Namespace]->Functions.end()) {
+    std::unique_ptr<FunctionInfo> I = make_unique<FunctionInfo>();
+    Docs.Namespaces[Namespace]->Functions[MangledName] = std::move(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);
+}
+
+void ClangDocReporter::createMethodInfo(const CXXMethodDecl *D,
+                                        const FullComment *C, int LineNumber,
+                                        StringRef File, StringRef MangledName) {
+  std::string ParentName = D->getParent()->getQualifiedNameAsString();
+  llvm::StringMapIterator<std::unique_ptr<TypeInfo>> T =
+      Docs.Types.find(ParentName);
+  if (T == Docs.Types.end()) {
+    std::unique_ptr<TypeInfo> TI = make_unique<TypeInfo>();
+    TI->FullyQualifiedName = getParentNamespace(D);
+    Docs.Types[ParentName] = std::move(TI);
+  }
+
+  llvm::StringMapIterator<std::unique_ptr<FunctionInfo>> Pair =
+      Docs.Types[ParentName]->Functions.find(MangledName);
+  if (Pair == Docs.Types[ParentName]->Functions.end()) {
+    std::unique_ptr<FunctionInfo> I = make_unique<FunctionInfo>();
+    Docs.Types[ParentName]->Functions[MangledName] = std::move(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);
+}
+
+void ClangDocReporter::parseFullComment(const FullComment *C,
+                                        std::shared_ptr<CommentInfo> &CI) {
+  parseComment(CI, C);
+}
+
+void ClangDocReporter::visitTextComment(const TextComment *C) {
+  if (!isWhitespaceOnly(C->getText()))
+    CurrentCI->Text = C->getText();
+}
+
+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));
+}
+
+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);
+  }
+}
+
+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));
+}
+
+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();
+}
+
+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));
+  }
+}
+
+void ClangDocReporter::visitVerbatimBlockComment(
+    const VerbatimBlockComment *C) {
+  CurrentCI->Name = getCommandName(C->getCommandID());
+  CurrentCI->CloseName = C->getCloseName();
+}
+
+void ClangDocReporter::visitVerbatimBlockLineComment(
+    const VerbatimBlockLineComment *C) {
+  if (!isWhitespaceOnly(C->getText()))
+    CurrentCI->Text = C->getText();
+}
+
+void ClangDocReporter::visitVerbatimLineComment(const VerbatimLineComment *C) {
+  if (!isWhitespaceOnly(C->getText()))
+    CurrentCI->Text = C->getText();
+}
+
+bool ClangDocReporter::hasFile(StringRef Filename) const {
+  return Docs.Files.find(Filename) != Docs.Files.end();
+}
+
+void ClangDocReporter::serialize(OutFormat Format, StringRef RootDir) {
+  Format == clang::doc::OutFormat::LLVM ? serializeLLVM(RootDir)
+                                        : serializeYAML(RootDir);
+}
+
+void ClangDocReporter::addComment(Info &I, const FullComment *C) {
+  if (!C)
+    return;
+  std::shared_ptr<CommentInfo> CI = std::make_shared<CommentInfo>();
+  parseFullComment(C, CI);
+  I.Descriptions.push_back(std::move(CI));
+}
+
+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) {
+  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(I, D);
+}
+
+// TODO: finish converting comment info to unique_ptr
+void ClangDocReporter::parseComment(std::shared_ptr<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())) {
+    std::shared_ptr<CommentInfo> ChildCI = std::make_shared<CommentInfo>();
+    parseComment(ChildCI, Child);
+    CI->Children.push_back(std::move(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();
+    // FIXME: Set Access to the appropriate value.
+    N.Access = clang::AccessSpecifier::AS_none;
+    I.Members.push_back(N);
+  }
+}
+
+void ClangDocReporter::parseEnumerators(EnumInfo &I, const EnumDecl *D) const {
+  for (const EnumConstantDecl *E : D->enumerators()) {
+    NamedType N;
+    N.Type = E->getQualifiedNameAsString();
+    N.Access = clang::AccessSpecifier::AS_none;
+    I.Members.push_back(N);
+  }
+}
+
+void ClangDocReporter::parseParameters(FunctionInfo &I,
+                                       const FunctionDecl *D) const {
+  for (const ParmVarDecl *P : D->parameters()) {
+    NamedType Parm;
+    Parm.Type = P->getOriginalType().getAsString();
+    Parm.Access = clang::AccessSpecifier::AS_none;
+    Parm.Name = P->getQualifiedNameAsString();
+    I.Params.push_back(Parm);
+  }
+}
+
+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());
+  }
+  for (const CXXBaseSpecifier &B : D->vbases())
+    I.VirtualParents.push_back(B.getType().getAsString());
+}
+
+template <typename T>
+void ClangDocReporter::printMap(raw_ostream &OS, StringMap<T> &Map) {
+  yaml::Output YOut(OS);
+  for (auto &I : Map)
+    YOut << *(I.second);
+}
+
+template <typename T>
+void ClangDocReporter::printMapPlusFunctions(raw_ostream &OS,
+                                             StringMap<T> &Map) {
+  yaml::Output YOut(OS);
+  for (auto &I : Map) {
+    YOut << *(I.second);
+    for (auto &F : I.second->Functions)
+      YOut << *(F.second);
+  }
+}
+
+void ClangDocReporter::serializeYAML(StringRef RootDir) {
+  if (RootDir.empty()) {
+    printMap<std::unique_ptr<File>>(outs(), Docs.Files);
+    printMapPlusFunctions<std::unique_ptr<NamespaceInfo>>(outs(),
+                                                          Docs.Namespaces);
+    printMapPlusFunctions<std::unique_ptr<TypeInfo>>(outs(), Docs.Types);
+    printMap<std::unique_ptr<EnumInfo>>(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() << "Error opening documentation file.\n";
+    return;
+  }
+  printMap<std::unique_ptr<File>>(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<std::unique_ptr<NamespaceInfo>>(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<std::unique_ptr<TypeInfo>>(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<std::unique_ptr<EnumInfo>>(EnumOS, Docs.Enums);
+}
+
+void ClangDocReporter::serializeLLVM(StringRef RootDir) {
+  // TODO: Implement.
+}
+
+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>";
+}
+
+bool ClangDocReporter::isWhitespaceOnly(StringRef S) const {
+  return S.find_first_not_of(" \t\n\v\f\r") == std::string::npos || S.empty();
+}
+
+std::string ClangDocReporter::getParentNamespace(const DeclContext *D) const {
+  if (const auto *N = dyn_cast<NamedDecl>(D->getParent()))
+    return N->getQualifiedNameAsString();
+  return "";
+}
+
+} // namespace doc
+} // namespace clang
Index: tools/clang-doc/ClangDoc.h
===================================================================
--- /dev/null
+++ tools/clang-doc/ClangDoc.h
@@ -0,0 +1,97 @@
+//===-- ClangDoc.cpp - ClangDoc ---------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H
+
+#include "ClangDocReporter.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/Tooling.h"
+#include <string>
+#include <vector>
+
+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> {
+public:
+  explicit ClangDocVisitor(ASTContext *Ctx, ClangDocReporter &Reporter)
+      : Context(Ctx), Manager(Ctx->getSourceManager()),
+        MC(Ctx->createMangleContext()), Reporter(Reporter) {}
+
+  bool VisitTagDecl(const TagDecl *D);
+  bool VisitNamespaceDecl(const NamespaceDecl *D);
+  bool VisitFunctionDecl(const FunctionDecl *D);
+  void parseUnattachedComments();
+
+private:
+  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);
+
+  ASTContext *Context;
+  SourceManager &Manager;
+  MangleContext *MC;
+  ClangDocReporter &Reporter;
+};
+
+class ClangDocConsumer : public clang::ASTConsumer {
+public:
+  explicit ClangDocConsumer(ASTContext *Ctx, ClangDocReporter &Reporter)
+      : Visitor(Ctx, Reporter), Reporter(Reporter) {}
+
+  virtual void HandleTranslationUnit(clang::ASTContext &Context);
+
+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);
+
+private:
+  ClangDocReporter &Reporter;
+};
+
+class ClangDocActionFactory : public tooling::FrontendActionFactory {
+public:
+  ClangDocActionFactory(ClangDocContext &Ctx, ClangDocReporter &Reporter)
+      : Context(Ctx), Reporter(Reporter) {}
+
+  clang::FrontendAction *create() override {
+    return new ClangDocAction(Reporter);
+  }
+
+private:
+  ClangDocContext &Context;
+  ClangDocReporter &Reporter;
+};
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H
Index: tools/clang-doc/ClangDoc.cpp
===================================================================
--- /dev/null
+++ tools/clang-doc/ClangDoc.cpp
@@ -0,0 +1,127 @@
+//===-- ClangDoc.cpp - ClangDoc ---------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangDoc.h"
+#include "clang/AST/Comment.h"
+#include "clang/AST/Mangle.h"
+#include "clang/Frontend/CompilerInstance.h"
+
+using namespace clang;
+using namespace clang::tooling;
+using namespace llvm;
+
+namespace clang {
+namespace doc {
+
+bool ClangDocVisitor::VisitTagDecl(const TagDecl *D) {
+  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;
+}
+
+bool ClangDocVisitor::VisitNamespaceDecl(const NamespaceDecl *D) {
+  if (!isUnparsed(D->getLocation()))
+    return true;
+  Reporter.createNamespaceInfo(D, getComment(D), getLine(D), getFile(D));
+  return true;
+}
+
+bool ClangDocVisitor::VisitFunctionDecl(const FunctionDecl *D) {
+  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;
+}
+
+comments::FullComment *ClangDocVisitor::getComment(const Decl *D) {
+  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 ClangDocVisitor::getLine(const Decl *D) const {
+  PresumedLoc PLoc = Manager.getPresumedLoc(D->getLocStart());
+  return PLoc.getLine();
+}
+
+std::string ClangDocVisitor::getFile(const Decl *D) const {
+  PresumedLoc PLoc = Manager.getPresumedLoc(D->getLocStart());
+  return PLoc.getFilename();
+}
+
+void ClangDocVisitor::parseUnattachedComments() {
+  for (RawComment *Comment : Context->getRawCommentList().getComments()) {
+    if (!isUnparsed(Comment->getLocStart()) || Comment->isAttached())
+      continue;
+    std::shared_ptr<CommentInfo> CI = std::make_shared<CommentInfo>();
+    Reporter.parseFullComment(Comment->parse(*Context, nullptr, nullptr), CI);
+    Reporter.addUnattachedComment(Manager.getFilename(Comment->getLocStart()),
+                                  std::move(CI));
+  }
+}
+
+bool ClangDocVisitor::isUnparsed(SourceLocation Loc) const {
+  if (!Loc.isValid())
+    return false;
+  const std::string &Filename = Manager.getFilename(Loc);
+
+  if (!Reporter.hasFile(Filename))
+    return false;
+  if (Manager.isInSystemHeader(Loc) || Manager.isInExternCSystemHeader(Loc))
+    return false;
+  return true;
+}
+
+std::string ClangDocVisitor::mangleName(const FunctionDecl *D) {
+  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);
+}
+
+} // namespace doc
+} // namespace clang
Index: tools/clang-doc/CMakeLists.txt
===================================================================
--- /dev/null
+++ tools/clang-doc/CMakeLists.txt
@@ -0,0 +1,21 @@
+set(LLVM_LINK_COMPONENTS
+  support
+  )
+
+add_clang_library(clangDoc
+  ClangDoc.cpp
+  ClangDocReporter.cpp
+
+  LINK_LIBS
+  clangAnalysis
+  clangAST
+  clangASTMatchers
+  clangBasic
+  clangFormat
+  clangFrontend
+  clangLex
+  clangTooling
+  clangToolingCore
+  )
+
+add_subdirectory(tool)
Index: tools/CMakeLists.txt
===================================================================
--- tools/CMakeLists.txt
+++ tools/CMakeLists.txt
@@ -3,6 +3,7 @@
 add_clang_subdirectory(diagtool)
 add_clang_subdirectory(driver)
 add_clang_subdirectory(clang-diff)
+add_clang_subdirectory(clang-doc)
 add_clang_subdirectory(clang-format)
 add_clang_subdirectory(clang-format-vs)
 add_clang_subdirectory(clang-fuzzer)
Index: test/lit.cfg.py
===================================================================
--- test/lit.cfg.py
+++ test/lit.cfg.py
@@ -57,9 +57,9 @@
 tool_dirs = [config.clang_tools_dir, config.llvm_tools_dir]
 
 tools = [
-    'c-index-test', 'clang-check', 'clang-diff', 'clang-format', 'opt',
-    ToolSubst('%clang_func_map', command=FindTool(
-        'clang-func-mapping'), unresolved='ignore'),
+    'c-index-test', 'clang-check', 'clang-diff', 'clang-doc', 'clang-format', 
+    'opt', ToolSubst('%clang_func_map', command=FindTool(
+            'clang-func-mapping'), unresolved='ignore'),
 ]
 
 if config.clang_examples:
Index: test/Tooling/clang-doc-type.cpp
===================================================================
--- /dev/null
+++ test/Tooling/clang-doc-type.cpp
@@ -0,0 +1,235 @@
+// 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: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -p %t %t/test.cpp | FileCheck %s
+
+/// A union.
+union A { int X; int Y; };
+
+/// An enum.
+enum B { X, Y };
+
+/// A struct.
+struct C { int i; };
+
+/// An empty class.
+class D {};
+
+/// An example class.
+class E {
+public:
+  E() {}
+  ~E() {}
+protected:
+  void ProtectedMethod();
+};
+
+void E::ProtectedMethod() {}
+
+/// An inherited class.
+class F : public D, public E {};
+class G : virtual private D, public E {};
+
+ // CHECK: ---
+ // CHECK: Qualified Name:  ''
+ // CHECK: Name:            ''
+ // CHECK: Namespace:       ''
+ // CHECK: Descriptions:    
+ // CHECK: Locations:       
+ // CHECK: ...
+ // 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:            ' 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:            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:            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:            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:            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:            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
===================================================================
--- /dev/null
+++ test/Tooling/clang-doc-namespace.cpp
@@ -0,0 +1,84 @@
+// 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: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -p %t %t/test.cpp | FileCheck %s
+
+/// Test namespace
+namespace A {}
+
+namespace B {
+namespace C {
+namespace D {}
+}
+}
+
+namespace A {
+  void f() {};
+}
+
+ // CHECK: ---
+ // CHECK: Qualified Name:  ''
+ // CHECK: Name:            ''
+ // CHECK: Namespace:       ''
+ // CHECK: Descriptions:    
+ // CHECK: Locations:       
+ // CHECK: ...
+ // 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:   - 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
===================================================================
--- /dev/null
+++ test/Tooling/clang-doc-basic.cpp
@@ -0,0 +1,88 @@
+// 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: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump --omit-filenames -p %t %t/test.cpp | FileCheck %s
+
+/// Test namespace
+namespace A {
+  
+/// A function
+void f(int x) {}
+
+} // end namespace A
+
+/// A C++ class
+class C {
+private:
+  int i;
+};
+
+ // CHECK: ---
+ // CHECK: Qualified Name:  ''
+ // CHECK: Name:            ''
+ // CHECK: Namespace:       ''
+ // CHECK: Descriptions:    
+ // CHECK: Locations:       
+ // CHECK: ...
+ // 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: ...
Index: test/CMakeLists.txt
===================================================================
--- test/CMakeLists.txt
+++ test/CMakeLists.txt
@@ -54,6 +54,7 @@
   clang-rename
   clang-refactor
   clang-diff
+  clang-doc
   )
   
 if(CLANG_ENABLE_STATIC_ANALYZER)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to