juliehockett updated this revision to Diff 131481.
juliehockett added a comment.
Herald added a subscriber: hintonda.

Cleaning up a few unnecessary copyings


https://reviews.llvm.org/D41102

Files:
  test/CMakeLists.txt
  test/Tooling/clang-doc-basic.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,68 @@
+//===-- 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/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include <string>
+
+using namespace clang;
+using namespace llvm;
+
+namespace {
+
+cl::OptionCategory ClangDocCategory("clang-doc options");
+
+cl::opt<bool>
+    EmitLLVM("emit-llvm",
+             cl::desc("Output in LLVM bitstream format (default is YAML)."),
+             cl::init(false), cl::cat(ClangDocCategory));
+
+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);
+
+  clang::doc::OutFormat EmitFormat =
+      EmitLLVM ? doc::OutFormat::LLVM : doc::OutFormat::YAML;
+
+  // TODO: Update the source path list to only consider changed files for
+  // incremental doc updates.
+  doc::ClangDocReporter Reporter(OptionsParser.getSourcePathList());
+  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 docs...\n";
+  Reporter.serialize(EmitFormat, outs());
+
+  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,217 @@
+//===--  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"
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::CommentInfo)
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::NamedType)
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::Location)
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::Pair<clang::doc::File>)
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::Pair<clang::doc::NamespaceInfo>)
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::Pair<clang::doc::TypeInfo>)
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::Pair<clang::doc::EnumInfo>)
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::doc::Pair<clang::doc::FunctionInfo>)
+
+namespace llvm {
+namespace yaml {
+
+template <typename T> struct NormalizedMap {
+  NormalizedMap(IO &) {}
+  NormalizedMap(IO &, const StringMap<T> &Map) {
+    for (const auto &Entry : Map) {
+      clang::doc::Pair<T> Pair{Entry.getKeyData(), Entry.getValue()};
+      VectorMap.push_back(Pair);
+    }
+  }
+
+  StringMap<T> denormalize(IO &) {
+    StringMap<T> Map;
+    for (const auto &Pair : VectorMap)
+      Map[Pair.Key] = Pair.Value;
+    return Map;
+  }
+
+  std::vector<clang::doc::Pair<T>> VectorMap;
+};
+
+template <> struct ScalarEnumerationTraits<clang::AccessSpecifier> {
+  static void enumeration(IO &io, clang::AccessSpecifier &value) {
+    io.enumCase(value, "Public", clang::AccessSpecifier::AS_public);
+    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<clang::doc::Pair<std::string>> {
+  static void mapping(IO &IO, clang::doc::Pair<std::string> &Pair) {
+    IO.mapOptional("Value", Pair.Value);
+  }
+};
+
+template <> struct MappingTraits<clang::doc::Location> {
+  static void mapping(IO &IO, clang::doc::Location &Location) {
+    IO.mapOptional("LineNumber", Location.LineNumber);
+    IO.mapOptional("Filename", Location.Filename);
+  }
+};
+
+// TODO: uncomment description attrs
+template <> struct MappingTraits<clang::doc::Pair<clang::doc::NamespaceInfo>> {
+  static void mapping(IO &IO, clang::doc::Pair<clang::doc::NamespaceInfo> &Pair) {
+    if (!Pair.Value.isDefined)
+      return;
+  MappingNormalization<NormalizedMap<clang::doc::FunctionInfo>,
+                         StringMap<clang::doc::FunctionInfo>>
+        functions(IO, Pair.Value.Functions);
+
+    IO.mapOptional("Qualified Name", Pair.Value.FullyQualifiedName);
+    IO.mapOptional("Name", Pair.Value.SimpleName);
+    IO.mapOptional("Namespace", Pair.Value.Namespace);
+    IO.mapOptional("Descriptions", Pair.Value.Descriptions);
+    IO.mapOptional("Locations", Pair.Value.Locations);
+    IO.mapOptional("Functions", functions->VectorMap);
+  }
+};
+
+template <> struct MappingTraits<clang::doc::Pair<clang::doc::TypeInfo>> {
+  static void mapping(IO &IO, clang::doc::Pair<clang::doc::TypeInfo> &Pair) {
+    if (!Pair.Value.isDefined)
+      return;
+
+    MappingNormalization<NormalizedMap<clang::doc::FunctionInfo>,
+                         StringMap<clang::doc::FunctionInfo>>
+        functions(IO, Pair.Value.Functions);
+        
+    IO.mapOptional("Qualified Name", Pair.Value.FullyQualifiedName);
+    IO.mapOptional("Name", Pair.Value.SimpleName);
+    IO.mapOptional("Namespace", Pair.Value.Namespace);
+    IO.mapOptional("Descriptions", Pair.Value.Descriptions);
+    IO.mapOptional("TagType", Pair.Value.TagType);
+    IO.mapOptional("Locations", Pair.Value.Locations);
+    IO.mapOptional("Functions", functions->VectorMap);
+    IO.mapOptional("DefinitionFile", Pair.Value.DefinitionFile);
+    IO.mapOptional("Members", Pair.Value.Members);
+    IO.mapOptional("Parents", Pair.Value.Parents);
+    IO.mapOptional("VirtualParents", Pair.Value.VirtualParents);
+  }
+};
+
+template <> struct MappingTraits<clang::doc::Pair<clang::doc::EnumInfo>> {
+  static void mapping(IO &IO, clang::doc::Pair<clang::doc::EnumInfo> &Pair) {
+    if (!Pair.Value.isDefined)
+      return;
+    IO.mapOptional("Qualified Name", Pair.Value.FullyQualifiedName);
+    IO.mapOptional("Name", Pair.Value.SimpleName);
+    IO.mapOptional("Namespace", Pair.Value.Namespace);
+    IO.mapOptional("Descriptions", Pair.Value.Descriptions);
+    IO.mapOptional("Locations", Pair.Value.Locations);
+    IO.mapOptional("DefinitionFile", Pair.Value.DefinitionFile);
+    IO.mapOptional("Scoped", Pair.Value.Scoped);
+    IO.mapOptional("Members", Pair.Value.Members);  
+  }
+};
+
+template <> struct MappingTraits<clang::doc::NamedType> {
+  static void mapping(IO &IO, clang::doc::NamedType &NamedType) {
+    IO.mapOptional("Type", NamedType.Type);
+    IO.mapOptional("Name", NamedType.Name);
+    IO.mapOptional("Access", NamedType.Access);
+  }
+};
+
+template <> struct MappingTraits<clang::doc::Pair<clang::doc::FunctionInfo>> {
+  static void mapping(IO &IO,
+                      clang::doc::Pair<clang::doc::FunctionInfo> &Pair) {
+    if (!Pair.Value.isDefined)
+      return;
+    IO.mapOptional("Mangled Name", Pair.Value.MangledName);
+    IO.mapOptional("Qualified Name", Pair.Value.FullyQualifiedName);
+    IO.mapOptional("Name", Pair.Value.SimpleName);
+    IO.mapOptional("Namespace", Pair.Value.Namespace);
+    IO.mapOptional("Descriptions", Pair.Value.Descriptions);
+    IO.mapOptional("Locations", Pair.Value.Locations);
+    IO.mapOptional("DefinitionFile", Pair.Value.DefinitionFile);
+    IO.mapOptional("Params", Pair.Value.Params);
+    IO.mapOptional("ReturnType", Pair.Value.ReturnType);
+    IO.mapOptional("Access", Pair.Value.Access);
+  }
+};
+
+template <> struct MappingTraits<clang::doc::Pair<clang::doc::File>> {
+  static void mapping(IO &IO, clang::doc::Pair<clang::doc::File> &Pair) {
+    IO.mapOptional("Filename", Pair.Value.Filename);
+    IO.mapOptional("Description", Pair.Value.Description);
+  }
+};
+
+template <> struct MappingTraits<clang::doc::Documentation> {
+  static void mapping(IO &IO, clang::doc::Documentation &Docs) {
+    MappingNormalization<NormalizedMap<clang::doc::File>,
+                         StringMap<clang::doc::File>>
+        files(IO, Docs.Files);
+    MappingNormalization<NormalizedMap<clang::doc::NamespaceInfo>,
+                         StringMap<clang::doc::NamespaceInfo>>
+        namespaces(IO, Docs.Namespaces);
+    MappingNormalization<NormalizedMap<clang::doc::TypeInfo>,
+                          StringMap<clang::doc::TypeInfo>>
+        types(IO, Docs.Types);
+    MappingNormalization<NormalizedMap<clang::doc::EnumInfo>,
+                            StringMap<clang::doc::EnumInfo>>
+        enums(IO, Docs.Enums);
+
+    IO.mapOptional("Files", files->VectorMap);
+    IO.mapOptional("Namespaces", namespaces->VectorMap);
+    IO.mapOptional("Types", types->VectorMap);
+    IO.mapOptional("Enums", enums->VectorMap);
+  }
+};
+
+template <> struct MappingTraits<clang::doc::CommentInfo> {
+
+  static void mapping(IO &IO, clang::doc::CommentInfo &Info) {
+    IO.mapOptional("Kind", Info.Kind);
+    if (!Info.Text.empty())
+      IO.mapOptional("Text", Info.Text);
+    if (!Info.Name.empty())
+      IO.mapOptional("Name", Info.Name);
+    if (!Info.Direction.empty())
+      IO.mapOptional("Direction", Info.Direction);
+    if (!Info.ParamName.empty())
+      IO.mapOptional("ParamName", Info.ParamName);
+    if (!Info.CloseName.empty())
+      IO.mapOptional("CloseName", Info.CloseName);
+    if (Info.SelfClosing)
+      IO.mapOptional("SelfClosing", Info.SelfClosing);
+    if (Info.Explicit)
+      IO.mapOptional("Explicit", Info.Explicit);
+    IO.mapOptional("Args", Info.Args);
+    IO.mapOptional("Attrs", Info.Attrs);
+    IO.mapOptional("Position", Info.Position);
+    IO.mapOptional("Children", Info.Children);
+  }
+};
+
+} // 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,190 @@
+//===-- 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<CommentInfo> Children;
+};
+
+/// A source file in the project.
+struct File {
+  std::string Filename;
+  CommentInfo Description;
+  llvm::SmallVector<CommentInfo, 8> UnattachedComments;
+};
+
+/// A base struct for Infos.
+struct Info {
+  bool isDefined = false;
+  std::string FullyQualifiedName;
+  std::string SimpleName;
+  std::string Namespace;
+  std::vector<CommentInfo> Descriptions;
+  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<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<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 {
+  llvm::StringMap<File> Files;
+  llvm::StringMap<NamespaceInfo> Namespaces;
+  llvm::StringMap<TypeInfo> Types;
+  llvm::StringMap<EnumInfo> Enums;
+  // TODO: Add functionality to include separate markdown pages.
+};
+
+/// Struct with a key and a value to allow for serialization.
+template <typename T> struct Pair {
+  std::string Key;
+  T Value;
+};
+
+class ClangDocReporter : public ConstCommentVisitor<ClangDocReporter> {
+public:
+  ClangDocReporter() {}
+  ClangDocReporter(const std::vector<std::string> &Sources);
+
+  void addUnattachedComment(StringRef Filename, const 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, 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, llvm::raw_ostream &OS) const;
+
+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(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;
+
+  void serializeYAML(llvm::raw_ostream &OS) const;
+  void serializeLLVM(llvm::raw_ostream &OS) const;
+
+  const char *getCommandName(unsigned CommandID) const;
+  bool isWhitespaceOnly(StringRef S) const;
+  std::string getParentNamespace(const DeclContext *D) const;
+
+  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,350 @@
+//===-- 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/raw_ostream.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using namespace llvm;
+using clang::comments::FullComment;
+
+namespace clang {
+namespace doc {
+
+ClangDocReporter::ClangDocReporter(const std::vector<std::string> &Sources) {
+  for (const std::string &Path : Sources) {
+    assert(sys::path::is_absolute(Path) && "clang-doc expects absolute paths.");
+    addFile(Path);
+  }
+  // Create base namespace
+  NamespaceInfo I;
+  I.isDefined = true;
+  Docs.Namespaces[""] = I;
+}
+
+void ClangDocReporter::addUnattachedComment(StringRef Filename,
+                                            const CommentInfo &CI) {
+  Docs.Files[Filename].UnattachedComments.push_back(CI);
+}
+
+void ClangDocReporter::addFile(StringRef Filename) {
+  File F;
+  F.Filename = Filename;
+  Docs.Files.insert(std::make_pair(Filename, F));
+}
+
+void ClangDocReporter::createNamespaceInfo(const NamespaceDecl *D,
+                                             const FullComment *C,
+                                             int LineNumber, StringRef File) {
+  std::string Name = D->getQualifiedNameAsString();
+  llvm::StringMapIterator<NamespaceInfo> Pair = Docs.Namespaces.find(Name);
+  if (Pair == Docs.Namespaces.end()) {
+    NamespaceInfo I;
+    Docs.Namespaces[Name] = I;
+    populateBasicInfo(Docs.Namespaces[Name], Name, D->getNameAsString(), getParentNamespace(D));
+  }
+
+  addLocation(Docs.Namespaces[Name], LineNumber, File);
+  addComment(Docs.Namespaces[Name], C);
+}
+
+void ClangDocReporter::createTypeInfo(const RecordDecl *D, const FullComment *C,
+                                        int LineNumber, StringRef File) {
+
+  std::string Name = D->getQualifiedNameAsString();
+  llvm::StringMapIterator<TypeInfo> Pair = Docs.Types.find(Name);
+  if (Pair == Docs.Types.end()) {
+    TypeInfo I;
+    Docs.Types[Name] = I;
+  }
+    
+  if (D->isThisDeclarationADefinition()) 
+    populateTypeInfo(Docs.Types[Name], D, Name, File);
+  
+  addLocation(Docs.Types[Name], LineNumber, File);
+  addComment(Docs.Types[Name], C);
+}
+
+void ClangDocReporter::createEnumInfo(const EnumDecl *D, const FullComment *C,
+                                        int LineNumber, StringRef File) {
+  std::string Name = D->getQualifiedNameAsString();
+  llvm::StringMapIterator<EnumInfo> Pair = Docs.Enums.find(Name);
+  if (Pair == Docs.Enums.end()) {
+    EnumInfo I;
+    Docs.Enums[Name] = I;
+  }
+  
+  if (D->isThisDeclarationADefinition())
+    populateEnumInfo(Docs.Enums[Name], D, Name, File);
+
+  addLocation(Docs.Enums[Name], LineNumber, File);
+  addComment(Docs.Enums[Name], C);
+}
+
+void ClangDocReporter::createFunctionInfo(const FunctionDecl *D,
+                                            const FullComment *C, int LineNumber, StringRef File,
+                                            StringRef MangledName) {
+  std::string Namespace = getParentNamespace(D);
+  llvm::StringMapIterator<NamespaceInfo> NS = Docs.Namespaces.find(Namespace);
+  if (NS == Docs.Namespaces.end()) {
+    NamespaceInfo NI;;
+    NI.FullyQualifiedName = Namespace;
+    Docs.Namespaces[Namespace] = NI;
+  } 
+  
+  llvm::StringMapIterator<FunctionInfo> Pair = Docs.Namespaces[Namespace].Functions.find(MangledName);
+  if (Pair != Docs.Namespaces[Namespace].Functions.end()) {
+    FunctionInfo I;
+    Docs.Namespaces[Namespace].Functions[MangledName] = I;
+  }
+  
+  if (D->isThisDeclarationADefinition())
+    populateFunctionInfo(Docs.Namespaces[Namespace].Functions[MangledName], D, MangledName, File, clang::AccessSpecifier::AS_none);
+  
+  addLocation(Docs.Namespaces[Namespace].Functions[MangledName], LineNumber, File);
+  addComment(Docs.Namespaces[Namespace].Functions[MangledName], C);
+}
+
+void ClangDocReporter::createMethodInfo(const CXXMethodDecl *D,
+                                            const FullComment *C, int LineNumber, StringRef File,
+                                            StringRef MangledName) {
+  std::string ParentName = D->getParent()->getQualifiedNameAsString();
+  llvm::StringMapIterator<TypeInfo> T = Docs.Types.find(ParentName);
+  if (T == Docs.Types.end()) {
+    TypeInfo TI;
+    TI.FullyQualifiedName = getParentNamespace(D);
+    Docs.Types[ParentName] = TI;
+  } 
+  
+  llvm::StringMapIterator<FunctionInfo> Pair = Docs.Types[ParentName].Functions.find(MangledName);
+  if (Pair != Docs.Types[ParentName].Functions.end()) {
+    FunctionInfo I;
+    Docs.Types[ParentName].Functions[MangledName] = I;
+  }
+  
+  if (D->isThisDeclarationADefinition())
+    populateFunctionInfo(Docs.Types[ParentName].Functions[MangledName], D, MangledName, File, D->getAccess());
+  
+  addLocation(Docs.Types[ParentName].Functions[MangledName], LineNumber, File);
+  addComment(Docs.Types[ParentName].Functions[MangledName], C);
+}
+
+void ClangDocReporter::parseFullComment(const FullComment *C, 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, raw_ostream &OS) const {
+  Format == clang::doc::OutFormat::LLVM ? serializeLLVM(OS) : serializeYAML(OS);
+}
+
+void ClangDocReporter::addComment(Info &I, const FullComment *C) {
+  if (!C)
+    return;
+  CommentInfo CI;
+  parseFullComment(C, CI);
+  I.Descriptions.push_back(CI);
+}
+
+void ClangDocReporter::addLocation(Info &I, int LineNumber, StringRef File) const {
+  Location L{LineNumber, 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();
+  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;
+  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));
+  I.DefinitionFile = File;
+  I.Scoped = D->isScoped();
+  parseEnumerators(Docs.Enums[Name], D);
+}
+
+void ClangDocReporter::parseComment(CommentInfo *CI,
+                                    const comments::Comment *C) {
+  CurrentCI = CI;
+  CI->Kind = C->getCommentKindName();
+  ConstCommentVisitor<ClangDocReporter>::visit(C);
+  for (comments::Comment *Child :
+       make_range(C->child_begin(), C->child_end())) {
+    CommentInfo ChildCI;
+    parseComment(&ChildCI, Child);
+    CI->Children.push_back(ChildCI);
+  }
+}
+
+void ClangDocReporter::parseFields(TypeInfo &I, const RecordDecl *D) const {
+  for (const FieldDecl *F : D->fields()) {
+    NamedType N;
+    N.Type = F->getTypeSourceInfo()->getType().getAsString();
+    N.Name = F->getQualifiedNameAsString();
+    if (const auto *M = dyn_cast<CXXMethodDecl>(D))
+      N.Access = M->getAccess();
+    else 
+      N.Access = clang::AccessSpecifier::AS_none;
+    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());
+}
+
+void ClangDocReporter::serializeYAML(raw_ostream &OS) const {
+  yaml::Output Output(OS);
+  Documentation NonConstValue = Docs;
+  Output << NonConstValue;
+}
+
+void ClangDocReporter::serializeLLVM(raw_ostream &OS) const {
+  // TODO: Implement.
+  OS << "Not yet implemented.\n";
+}
+
+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;
+    CommentInfo CI;
+    Reporter.parseFullComment(Comment->parse(*Context, nullptr, nullptr), CI);
+    Reporter.addUnattachedComment(Manager.getFilename(Comment->getLocStart()),
+                                  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-basic.cpp
===================================================================
--- /dev/null
+++ test/Tooling/clang-doc-basic.cpp
@@ -0,0 +1,83 @@
+// 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 -p %t %t/test.cpp | FileCheck %s -DROOT=%t --implicit-check-not Skipping
+
+/// Test namespace
+namespace A {
+  
+/// A function
+void f(int x) {}
+
+} // end namespace A
+
+/// A C++ class
+class C {
+private:
+  int i;
+};
+
+// CHECK-DAG: Parsing codebase...
+// CHECK-DAG: Writing docs...
+// CHECK-DAG: ---
+// CHECK-DAG: Files:           
+// CHECK-DAG:   - Filename:        [[ROOT]]/test.cpp
+// CHECK-DAG:     Description:     
+// CHECK-DAG:       Kind:            ''
+// CHECK-DAG: Namespaces:      
+// CHECK-DAG:   - Qualified Name:  ''
+// CHECK-DAG:     Name:            ''
+// CHECK-DAG:     Namespace:       ''
+// CHECK-DAG:   - Qualified Name:  A
+// CHECK-DAG:     Name:            A
+// CHECK-DAG:     Namespace:       ''
+// CHECK-DAG:     Descriptions:    
+// CHECK-DAG:       - Kind:            FullComment
+// CHECK-DAG:         Children:        
+// CHECK-DAG:           - Kind:            ParagraphComment
+// CHECK-DAG:             Children:        
+// CHECK-DAG:               - Kind:            TextComment
+// CHECK-DAG:                 Text:            ' Test namespace'
+// CHECK-DAG:     Locations:       
+// CHECK-DAG:       - LineNumber:      8
+// CHECK-DAG:         Filename:        [[ROOT]]/test.cpp
+// CHECK-DAG:     Functions:       
+// CHECK-DAG:       - Mangled Name:    _ZN1A1fEi
+// CHECK-DAG:         Qualified Name:  'A::f'
+// CHECK-DAG:         Name:            f
+// CHECK-DAG:         Namespace:       A
+// CHECK-DAG:         Descriptions:    
+// CHECK-DAG:           - Kind:            FullComment
+// CHECK-DAG:             Children:        
+// CHECK-DAG:               - Kind:            ParagraphComment
+// CHECK-DAG:                 Children:        
+// CHECK-DAG:                   - Kind:            TextComment
+// CHECK-DAG:                     Text:            ' A function'
+// CHECK-DAG:         Locations:       
+// CHECK-DAG:           - LineNumber:      11
+// CHECK-DAG:             Filename:        [[ROOT]]/test.cpp
+// CHECK-DAG:         DefinitionFile:  [[ROOT]]/test.cpp
+// CHECK-DAG:         ReturnType:      void
+// CHECK-DAG:         Access:          None
+// CHECK-DAG: Types:           
+// CHECK-DAG:   - Qualified Name:  C
+// CHECK-DAG:     Name:            C
+// CHECK-DAG:     Namespace:       ''
+// CHECK-DAG:     Descriptions:    
+// CHECK-DAG:       - Kind:            FullComment
+// CHECK-DAG:         Children:        
+// CHECK-DAG:           - Kind:            ParagraphComment
+// CHECK-DAG:             Children:        
+// CHECK-DAG:               - Kind:            TextComment
+// CHECK-DAG:                 Text:            ' A C++ class'
+// CHECK-DAG:     TagType:         Class
+// CHECK-DAG:     Locations:       
+// CHECK-DAG:       - LineNumber:      16
+// CHECK-DAG:         Filename:        [[ROOT]]/test.cpp
+// CHECK-DAG:     DefinitionFile:  [[ROOT]]/test.cpp
+// CHECK-DAG:     Members:         
+// CHECK-DAG:       - Type:            int
+// CHECK-DAG:         Name:            'C::i'
+// CHECK-DAG:         Access:          None
+// CHECK-DAG: ...
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