[clang-tools-extra] r334103 - [clang-doc] Implement a YAML generator

Julie Hockett via cfe-commits cfe-commits at lists.llvm.org
Wed Jun 6 09:13:18 PDT 2018


Author: juliehockett
Date: Wed Jun  6 09:13:17 2018
New Revision: 334103

URL: http://llvm.org/viewvc/llvm-project?rev=334103&view=rev
Log:
[clang-doc] Implement a YAML generator

Implmenting a YAML generator from the emitted bitcode summary of
declarations. Emits one YAML file for each declaration information.

For a more detailed overview of the tool, see the design document on the mailing list: http://lists.llvm.org/pipermail/cfe-dev/2017-December/056203.html

Added:
    clang-tools-extra/trunk/clang-doc/Generators.cpp
    clang-tools-extra/trunk/clang-doc/Generators.h
    clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp
    clang-tools-extra/trunk/test/clang-doc/yaml-comments.cpp
    clang-tools-extra/trunk/test/clang-doc/yaml-namespace.cpp
    clang-tools-extra/trunk/test/clang-doc/yaml-record.cpp
Modified:
    clang-tools-extra/trunk/clang-doc/CMakeLists.txt
    clang-tools-extra/trunk/clang-doc/Representation.h
    clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp

Modified: clang-tools-extra/trunk/clang-doc/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/CMakeLists.txt?rev=334103&r1=334102&r2=334103&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-doc/CMakeLists.txt Wed Jun  6 09:13:17 2018
@@ -8,9 +8,11 @@ add_clang_library(clangDoc
   BitcodeReader.cpp
   BitcodeWriter.cpp
   ClangDoc.cpp
+  Generators.cpp
   Mapper.cpp
   Representation.cpp
   Serialize.cpp
+  YAMLGenerator.cpp
 
   LINK_LIBS
   clangAnalysis

Added: clang-tools-extra/trunk/clang-doc/Generators.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Generators.cpp?rev=334103&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Generators.cpp (added)
+++ clang-tools-extra/trunk/clang-doc/Generators.cpp Wed Jun  6 09:13:17 2018
@@ -0,0 +1,36 @@
+//===---- Generator.cpp - Generator Registry ---------------------*- C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Generators.h"
+
+LLVM_INSTANTIATE_REGISTRY(clang::doc::GeneratorRegistry)
+
+namespace clang {
+namespace doc {
+
+llvm::Expected<std::unique_ptr<Generator>>
+findGeneratorByName(llvm::StringRef Format) {
+  for (auto I = GeneratorRegistry::begin(), E = GeneratorRegistry::end();
+       I != E; ++I) {
+    if (I->getName() != Format)
+      continue;
+    return I->instantiate();
+  }
+  return llvm::make_error<llvm::StringError>("Can't find generator: " + Format,
+                                             llvm::inconvertibleErrorCode());
+}
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the generators.
+extern volatile int YAMLGeneratorAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED YAMLGeneratorAnchorDest =
+    YAMLGeneratorAnchorSource;
+
+} // namespace doc
+} // namespace clang

Added: clang-tools-extra/trunk/clang-doc/Generators.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Generators.h?rev=334103&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Generators.h (added)
+++ clang-tools-extra/trunk/clang-doc/Generators.h Wed Jun  6 09:13:17 2018
@@ -0,0 +1,41 @@
+//===-- Generators.h - ClangDoc Generator ----------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Generator classes for converting declaration information into documentation
+// in a specified format.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_GENERATOR_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_GENERATOR_H
+
+#include "Representation.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Registry.h"
+
+namespace clang {
+namespace doc {
+
+// Abstract base class for generators.
+// This is expected to be implemented and exposed via the GeneratorRegistry.
+class Generator {
+public:
+  virtual ~Generator() = default;
+
+  // Write out the decl info in the specified format.
+  virtual bool generateDocForInfo(Info *I, llvm::raw_ostream &OS) = 0;
+};
+
+typedef llvm::Registry<Generator> GeneratorRegistry;
+
+llvm::Expected<std::unique_ptr<Generator>>
+findGeneratorByName(llvm::StringRef Format);
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_GENERATOR_H

Modified: clang-tools-extra/trunk/clang-doc/Representation.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Representation.h?rev=334103&r1=334102&r2=334103&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/Representation.h (original)
+++ clang-tools-extra/trunk/clang-doc/Representation.h Wed Jun  6 09:13:17 2018
@@ -73,6 +73,11 @@ struct Reference {
   Reference(SymbolID USR, StringRef Name, InfoType IT)
       : USR(USR), Name(Name), RefType(IT) {}
 
+  bool operator==(const Reference &Other) const {
+    return std::tie(USR, Name, RefType) ==
+           std::tie(Other.USR, Other.Name, Other.RefType);
+  }
+
   SymbolID USR = SymbolID(); // Unique identifer for referenced decl
   SmallString<16> Name;      // Name of type (possibly unresolved).
   InfoType RefType = InfoType::IT_default; // Indicates the type of this
@@ -87,6 +92,8 @@ struct TypeInfo {
       : Type(Type, Field, IT) {}
   TypeInfo(llvm::StringRef RefName) : Type(RefName) {}
 
+  bool operator==(const TypeInfo &Other) const { return Type == Other.Type; }
+
   Reference Type; // Referenced type in this info.
 };
 
@@ -99,6 +106,10 @@ struct FieldTypeInfo : public TypeInfo {
   FieldTypeInfo(llvm::StringRef RefName, llvm::StringRef Name)
       : TypeInfo(RefName), Name(Name) {}
 
+  bool operator==(const FieldTypeInfo &Other) const {
+    return std::tie(Type, Name) == std::tie(Other.Type, Other.Name);
+  }
+
   SmallString<16> Name; // Name associated with this info.
 };
 
@@ -112,6 +123,11 @@ struct MemberTypeInfo : public FieldType
                  AccessSpecifier Access)
       : FieldTypeInfo(RefName, Name), Access(Access) {}
 
+  bool operator==(const MemberTypeInfo &Other) const {
+    return std::tie(Type, Name, Access) ==
+           std::tie(Other.Type, Other.Name, Other.Access);
+  }
+
   AccessSpecifier Access = AccessSpecifier::AS_none; // Access level associated
                                                      // with this info (public,
                                                      // protected, private,
@@ -123,6 +139,11 @@ struct Location {
   Location(int LineNumber, SmallString<16> Filename)
       : LineNumber(LineNumber), Filename(std::move(Filename)) {}
 
+  bool operator==(const Location &Other) const {
+    return std::tie(LineNumber, Filename) ==
+           std::tie(Other.LineNumber, Other.Filename);
+  }
+
   int LineNumber;           // Line number of this Location.
   SmallString<32> Filename; // File for this Location.
 };
@@ -173,10 +194,9 @@ struct FunctionInfo : public SymbolInfo
   bool IsMethod = false; // Indicates whether this function is a class method.
   Reference Parent;      // Reference to the parent class decl for this method.
   TypeInfo ReturnType;   // Info about the return type of this function.
-  llvm::SmallVector<FieldTypeInfo, 4> Params;        // List of parameters.
-  AccessSpecifier Access = AccessSpecifier::AS_none; // Access level for this
-                                                     // method (public, private,
-                                                     // protected, none).
+  llvm::SmallVector<FieldTypeInfo, 4> Params; // List of parameters.
+  // Access level for this method (public, private, protected, none).
+  AccessSpecifier Access = AccessSpecifier::AS_none;
 };
 
 // TODO: Expand to allow for documenting templating, inheritance access,

Added: clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp?rev=334103&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp (added)
+++ clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp Wed Jun  6 09:13:17 2018
@@ -0,0 +1,268 @@
+//===--  ClangDocYAML.cpp - ClangDoc YAML -----------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Implementation of the YAML generator, converting decl info into YAML output.
+//===----------------------------------------------------------------------===//
+
+#include "Generators.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang::doc;
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(FieldTypeInfo)
+LLVM_YAML_IS_SEQUENCE_VECTOR(MemberTypeInfo)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Reference)
+LLVM_YAML_IS_SEQUENCE_VECTOR(Location)
+LLVM_YAML_IS_SEQUENCE_VECTOR(CommentInfo)
+LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<CommentInfo>)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::SmallString<16>)
+
+namespace llvm {
+namespace yaml {
+
+// Enumerations to YAML output.
+
+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 ScalarEnumerationTraits<InfoType> {
+  static void enumeration(IO &IO, InfoType &Value) {
+    IO.enumCase(Value, "Namespace", InfoType::IT_namespace);
+    IO.enumCase(Value, "Record", InfoType::IT_record);
+    IO.enumCase(Value, "Function", InfoType::IT_function);
+    IO.enumCase(Value, "Enum", InfoType::IT_enum);
+    IO.enumCase(Value, "Default", InfoType::IT_default);
+  }
+};
+
+// Scalars to YAML output.
+template <unsigned U> struct ScalarTraits<SmallString<U>> {
+
+  static void output(const SmallString<U> &S, void *, llvm::raw_ostream &OS) {
+    for (const auto &C : S)
+      OS << C;
+  }
+
+  static StringRef input(StringRef Scalar, void *, SmallString<U> &Value) {
+    Value.assign(Scalar.begin(), Scalar.end());
+    return StringRef();
+  }
+
+  static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
+};
+
+template <> struct ScalarTraits<std::array<unsigned char, 20>> {
+
+  static void output(const std::array<unsigned char, 20> &S, void *,
+                     llvm::raw_ostream &OS) {
+    OS << toHex(toStringRef(S));
+  }
+
+  static StringRef input(StringRef Scalar, void *,
+                         std::array<unsigned char, 20> &Value) {
+    if (Scalar.size() != 40)
+      return "Error: Incorrect scalar size for USR.";
+    Value = StringToSymbol(Scalar);
+    return StringRef();
+  }
+
+  static SymbolID StringToSymbol(llvm::StringRef Value) {
+    SymbolID USR;
+    std::string HexString = fromHex(Value);
+    std::copy(HexString.begin(), HexString.end(), USR.begin());
+    return SymbolID(USR);
+  }
+
+  static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
+};
+
+// Helper functions to map infos to YAML.
+
+static void TypeInfoMapping(IO &IO, TypeInfo &I) {
+  IO.mapOptional("Type", I.Type, Reference());
+}
+
+static void FieldTypeInfoMapping(IO &IO, FieldTypeInfo &I) {
+  TypeInfoMapping(IO, I);
+  IO.mapOptional("Name", I.Name, SmallString<16>());
+}
+
+static void InfoMapping(IO &IO, Info &I) {
+  IO.mapRequired("USR", I.USR);
+  IO.mapOptional("Name", I.Name, SmallString<16>());
+  IO.mapOptional("Namespace", I.Namespace, llvm::SmallVector<Reference, 4>());
+  IO.mapOptional("Description", I.Description);
+}
+
+static void SymbolInfoMapping(IO &IO, SymbolInfo &I) {
+  InfoMapping(IO, I);
+  IO.mapOptional("DefLocation", I.DefLoc, Optional<Location>());
+  IO.mapOptional("Location", I.Loc, llvm::SmallVector<Location, 2>());
+}
+
+static void CommentInfoMapping(IO &IO, CommentInfo &I) {
+  IO.mapOptional("Kind", I.Kind, SmallString<16>());
+  IO.mapOptional("Text", I.Text, SmallString<64>());
+  IO.mapOptional("Name", I.Name, SmallString<16>());
+  IO.mapOptional("Direction", I.Direction, SmallString<8>());
+  IO.mapOptional("ParamName", I.ParamName, SmallString<16>());
+  IO.mapOptional("CloseName", I.CloseName, SmallString<16>());
+  IO.mapOptional("SelfClosing", I.SelfClosing, false);
+  IO.mapOptional("Explicit", I.Explicit, false);
+  IO.mapOptional("Args", I.Args, llvm::SmallVector<SmallString<16>, 4>());
+  IO.mapOptional("AttrKeys", I.AttrKeys,
+                 llvm::SmallVector<SmallString<16>, 4>());
+  IO.mapOptional("AttrValues", I.AttrValues,
+                 llvm::SmallVector<SmallString<16>, 4>());
+  IO.mapOptional("Children", I.Children);
+}
+
+// Template specialization to YAML traits for Infos.
+
+template <> struct MappingTraits<Location> {
+  static void mapping(IO &IO, Location &Loc) {
+    IO.mapOptional("LineNumber", Loc.LineNumber, 0);
+    IO.mapOptional("Filename", Loc.Filename, SmallString<32>());
+  }
+};
+
+template <> struct MappingTraits<Reference> {
+  static void mapping(IO &IO, Reference &Ref) {
+    IO.mapOptional("Type", Ref.RefType, InfoType::IT_default);
+    IO.mapOptional("Name", Ref.Name, SmallString<16>());
+    IO.mapOptional("USR", Ref.USR, SymbolID());
+  }
+};
+
+template <> struct MappingTraits<TypeInfo> {
+  static void mapping(IO &IO, TypeInfo &I) { TypeInfoMapping(IO, I); }
+};
+
+template <> struct MappingTraits<FieldTypeInfo> {
+  static void mapping(IO &IO, FieldTypeInfo &I) {
+    TypeInfoMapping(IO, I);
+    IO.mapOptional("Name", I.Name, SmallString<16>());
+  }
+};
+
+template <> struct MappingTraits<MemberTypeInfo> {
+  static void mapping(IO &IO, MemberTypeInfo &I) {
+    FieldTypeInfoMapping(IO, I);
+    IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none);
+  }
+};
+
+template <> struct MappingTraits<NamespaceInfo> {
+  static void mapping(IO &IO, NamespaceInfo &I) { InfoMapping(IO, I); }
+};
+
+template <> struct MappingTraits<RecordInfo> {
+  static void mapping(IO &IO, RecordInfo &I) {
+    SymbolInfoMapping(IO, I);
+    IO.mapOptional("TagType", I.TagType, clang::TagTypeKind::TTK_Struct);
+    IO.mapOptional("Members", I.Members);
+    IO.mapOptional("Parents", I.Parents, llvm::SmallVector<Reference, 4>());
+    IO.mapOptional("VirtualParents", I.VirtualParents,
+                   llvm::SmallVector<Reference, 4>());
+  }
+};
+
+template <> struct MappingTraits<EnumInfo> {
+  static void mapping(IO &IO, EnumInfo &I) {
+    SymbolInfoMapping(IO, I);
+    IO.mapOptional("Scoped", I.Scoped, false);
+    IO.mapOptional("Members", I.Members);
+  }
+};
+
+template <> struct MappingTraits<FunctionInfo> {
+  static void mapping(IO &IO, FunctionInfo &I) {
+    SymbolInfoMapping(IO, I);
+    IO.mapOptional("IsMethod", I.IsMethod, false);
+    IO.mapOptional("Parent", I.Parent, Reference());
+    IO.mapOptional("Params", I.Params);
+    IO.mapOptional("ReturnType", I.ReturnType);
+    IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none);
+  }
+};
+
+template <> struct MappingTraits<CommentInfo> {
+  static void mapping(IO &IO, CommentInfo &I) { CommentInfoMapping(IO, I); }
+};
+
+template <> struct MappingTraits<std::unique_ptr<CommentInfo>> {
+  static void mapping(IO &IO, std::unique_ptr<CommentInfo> &I) {
+    if (I)
+      CommentInfoMapping(IO, *I);
+  }
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+namespace clang {
+namespace doc {
+
+/// Generator for YAML documentation.
+class YAMLGenerator : public Generator {
+public:
+  static const char *Format;
+
+  bool generateDocForInfo(Info *I, llvm::raw_ostream &OS) override;
+};
+
+const char *YAMLGenerator::Format = "yaml";
+
+bool YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
+  llvm::yaml::Output InfoYAML(OS);
+  switch (I->IT) {
+  case InfoType::IT_namespace:
+    InfoYAML << *static_cast<clang::doc::NamespaceInfo *>(I);
+    break;
+  case InfoType::IT_record:
+    InfoYAML << *static_cast<clang::doc::RecordInfo *>(I);
+    break;
+  case InfoType::IT_enum:
+    InfoYAML << *static_cast<clang::doc::EnumInfo *>(I);
+    break;
+  case InfoType::IT_function:
+    InfoYAML << *static_cast<clang::doc::FunctionInfo *>(I);
+    break;
+  case InfoType::IT_default:
+    llvm::errs() << "Unexpected info type in index.\n";
+    return true;
+  }
+  return false;
+}
+
+static GeneratorRegistry::Add<YAMLGenerator> YAML(YAMLGenerator::Format,
+                                                  "Generator for YAML output.");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the generator.
+volatile int YAMLGeneratorAnchorSource = 0;
+
+} // namespace doc
+} // namespace clang

Modified: clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp?rev=334103&r1=334102&r2=334103&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp (original)
+++ clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp Wed Jun  6 09:13:17 2018
@@ -21,6 +21,7 @@
 #include "BitcodeReader.h"
 #include "BitcodeWriter.h"
 #include "ClangDoc.h"
+#include "Generators.h"
 #include "Representation.h"
 #include "clang/AST/AST.h"
 #include "clang/AST/Decl.h"
@@ -67,10 +68,10 @@ enum OutputFormatTy {
   yaml,
 };
 
-static llvm::cl::opt<OutputFormatTy>
-    Format("format", llvm::cl::desc("Format for outputted docs."),
-           llvm::cl::values(clEnumVal(yaml, "Documentation in YAML format.")),
-           llvm::cl::init(yaml), llvm::cl::cat(ClangDocCategory));
+static llvm::cl::opt<OutputFormatTy> FormatEnum(
+    "format", llvm::cl::desc("Format for outputted docs."),
+    llvm::cl::values(clEnumVal(yaml, "Documentation in YAML format.")),
+    llvm::cl::init(yaml), llvm::cl::cat(ClangDocCategory));
 
 static llvm::cl::opt<bool> DoxygenOnly(
     "doxygen",
@@ -116,8 +117,41 @@ bool DumpResultToFile(const Twine &DirNa
   return false;
 }
 
+llvm::Expected<llvm::SmallString<128>>
+getPath(StringRef Root, StringRef Ext, StringRef Name,
+        llvm::SmallVectorImpl<doc::Reference> &Namespaces) {
+  std::error_code OK;
+  llvm::SmallString<128> Path;
+  llvm::sys::path::native(Root, Path);
+  for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R)
+    llvm::sys::path::append(Path, R->Name);
+
+  if (CreateDirectory(Path))
+    return llvm::make_error<llvm::StringError>("Unable to create directory.\n",
+                                               llvm::inconvertibleErrorCode());
+
+  llvm::sys::path::append(Path, Name + Ext);
+  return Path;
+}
+
+std::string getFormatString(OutputFormatTy Ty) {
+  switch (Ty) {
+  case yaml:
+    return "yaml";
+  }
+}
+
 int main(int argc, const char **argv) {
   llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+  std::error_code OK;
+
+  // Fail early if an invalid format was provided.
+  std::string Format = getFormatString(FormatEnum);
+  auto G = doc::findGeneratorByName(Format);
+  if (!G) {
+    llvm::errs() << toString(G.takeError()) << "\n";
+    return 1;
+  }
 
   auto Exec = clang::tooling::createExecutorFromCommandLineArgs(
       argc, argv, ClangDocCategory);
@@ -173,7 +207,7 @@ int main(int argc, const char **argv) {
     }
   });
 
-  // Reducing phase
+  // Reducing and generation phases
   llvm::outs() << "Reducing " << MapOutput.size() << " infos...\n";
   llvm::StringMap<std::unique_ptr<doc::Info>> ReduceOutput;
   for (auto &Group : MapOutput) {
@@ -186,16 +220,27 @@ int main(int argc, const char **argv) {
       llvm::BitstreamWriter Stream(Buffer);
       doc::ClangDocBitcodeWriter Writer(Stream);
       Writer.dispatchInfoForWrite(Reduced.get().get());
-      if (DumpResultToFile("bc", Group.getKey() + ".bc", Buffer)) {
-        llvm::errs() << "Error writing " << Group.getKey() << " to file.\n";
-        continue;
-      }
+      if (DumpResultToFile("bc", Group.getKey() + ".bc", Buffer))
+        llvm::errs() << "Error dumping to bitcode.\n";
+      continue;
     }
 
-    ReduceOutput.insert(
-        std::make_pair(Group.getKey(), std::move(Reduced.get())));
+    // Create the relevant ostream and emit the documentation for this decl.
+    doc::Info *I = Reduced.get().get();
+    auto InfoPath = getPath(OutDirectory, "." + Format, I->Name, I->Namespace);
+    if (!InfoPath) {
+      llvm::errs() << toString(InfoPath.takeError()) << "\n";
+      continue;
+    }
+    std::error_code FileErr;
+    llvm::raw_fd_ostream InfoOS(InfoPath.get(), FileErr, llvm::sys::fs::F_None);
+    if (FileErr != OK) {
+      llvm::errs() << "Error opening index file: " << FileErr.message() << "\n";
+      continue;
+    }
 
-    // FIXME: Add support for emitting different output formats.
+    if (G->get()->generateDocForInfo(I, InfoOS))
+      llvm::errs() << "Unable to generate docs for info.\n";
   }
 
   return 0;

Added: clang-tools-extra/trunk/test/clang-doc/yaml-comments.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-doc/yaml-comments.cpp?rev=334103&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-doc/yaml-comments.cpp (added)
+++ clang-tools-extra/trunk/test/clang-doc/yaml-comments.cpp Wed Jun  6 09:13:17 2018
@@ -0,0 +1,129 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: cat %t/docs/F.yaml | FileCheck %s
+
+/// \brief Brief description.
+///
+/// Extended description that
+/// continues onto the next line.
+/// 
+/// <ul class="test">
+///   <li> Testing.
+/// </ul>
+///
+/// \verbatim
+/// The description continues.
+/// \endverbatim
+///
+/// \param [out] I is a parameter.
+/// \param J is a parameter.
+/// \return void
+void F(int I, int J);
+
+/// Bonus comment on definition
+void F(int I, int J) {}
+
+// CHECK: ---
+// CHECK-NEXT: USR:             '7574630614A535710E5A6ABCFFF98BCA2D06A4CA'
+// CHECK-NEXT: Name:            'F'
+// CHECK-NEXT: Description:     
+// CHECK-NEXT:   - Kind:            'FullComment'
+// CHECK-NEXT:     Children:        
+// CHECK-NEXT:       - Kind:            'ParagraphComment'
+// CHECK-NEXT:         Children:        
+// CHECK-NEXT:           - Kind:            'TextComment'
+// CHECK-NEXT:       - Kind:            'BlockCommandComment'
+// CHECK-NEXT:         Name:            'brief'
+// CHECK-NEXT:         Children:        
+// CHECK-NEXT:           - Kind:            'ParagraphComment'
+// CHECK-NEXT:             Children:        
+// CHECK-NEXT:               - Kind:            'TextComment'
+// CHECK-NEXT:                 Text:            ' Brief description.'
+// CHECK-NEXT:       - Kind:            'ParagraphComment'
+// CHECK-NEXT:         Children:        
+// CHECK-NEXT:           - Kind:            'TextComment'
+// CHECK-NEXT:             Text:            ' Extended description that'
+// CHECK-NEXT:           - Kind:            'TextComment'
+// CHECK-NEXT:             Text:            ' continues onto the next line.'
+// CHECK-NEXT:       - Kind:            'ParagraphComment'
+// CHECK-NEXT:         Children:        
+// CHECK-NEXT:           - Kind:            'TextComment'
+// CHECK-NEXT:           - Kind:            'HTMLStartTagComment'
+// CHECK-NEXT:             Name:            'ul'
+// CHECK-NEXT:             AttrKeys:        
+// CHECK-NEXT:               - 'class'
+// CHECK-NEXT:             AttrValues:      
+// CHECK-NEXT:               - 'test'
+// CHECK-NEXT:           - Kind:            'TextComment'
+// CHECK-NEXT:           - Kind:            'HTMLStartTagComment'
+// CHECK-NEXT:             Name:            'li'
+// CHECK-NEXT:           - Kind:            'TextComment'
+// CHECK-NEXT:             Text:            ' Testing.'
+// CHECK-NEXT:           - Kind:            'TextComment'
+// CHECK-NEXT:           - Kind:            'HTMLEndTagComment'
+// CHECK-NEXT:             Name:            'ul'
+// CHECK-NEXT:             SelfClosing:     true
+// CHECK-NEXT:       - Kind:            'ParagraphComment'
+// CHECK-NEXT:         Children:        
+// CHECK-NEXT:           - Kind:            'TextComment'
+// CHECK-NEXT:       - Kind:            'VerbatimBlockComment'
+// CHECK-NEXT:         Name:            'verbatim'
+// CHECK-NEXT:         CloseName:       'endverbatim'
+// CHECK-NEXT:         Children:        
+// CHECK-NEXT:           - Kind:            'VerbatimBlockLineComment'
+// CHECK-NEXT:             Text:            ' The description continues.'
+// CHECK-NEXT:       - Kind:            'ParagraphComment'
+// CHECK-NEXT:         Children:        
+// CHECK-NEXT:           - Kind:            'TextComment'
+// CHECK-NEXT:       - Kind:            'ParamCommandComment'
+// CHECK-NEXT:         Direction:       '[out]'
+// CHECK-NEXT:         ParamName:       'I'
+// CHECK-NEXT:         Explicit:        true
+// CHECK-NEXT:         Children:        
+// CHECK-NEXT:           - Kind:            'ParagraphComment'
+// CHECK-NEXT:             Children:        
+// CHECK-NEXT:               - Kind:            'TextComment'
+// CHECK-NEXT:                 Text:            ' is a parameter.'
+// CHECK-NEXT:               - Kind:            'TextComment'
+// CHECK-NEXT:       - Kind:            'ParamCommandComment'
+// CHECK-NEXT:         Direction:       '[in]'
+// CHECK-NEXT:         ParamName:       'J'
+// CHECK-NEXT:         Children:        
+// CHECK-NEXT:           - Kind:            'ParagraphComment'
+// CHECK-NEXT:             Children:        
+// CHECK-NEXT:               - Kind:            'TextComment'
+// CHECK-NEXT:                 Text:            ' is a parameter.'
+// CHECK-NEXT:               - Kind:            'TextComment'
+// CHECK-NEXT:       - Kind:            'BlockCommandComment'
+// CHECK-NEXT:         Name:            'return'
+// CHECK-NEXT:         Children:        
+// CHECK-NEXT:           - Kind:            'ParagraphComment'
+// CHECK-NEXT:             Children:        
+// CHECK-NEXT:               - Kind:            'TextComment'
+// CHECK-NEXT:                 Text:            ' void'
+// CHECK-NEXT:   - Kind:            'FullComment'
+// CHECK-NEXT:     Children:        
+// CHECK-NEXT:       - Kind:            'ParagraphComment'
+// CHECK-NEXT:         Children:        
+// CHECK-NEXT:           - Kind:            'TextComment'
+// CHECK-NEXT:             Text:            ' Bonus comment on definition'
+// CHECK-NEXT: DefLocation:     
+// CHECK-NEXT:   LineNumber:      27
+// CHECK-NEXT:   Filename:        '{{.*}}'
+// CHECK-NEXT: Location:        
+// CHECK-NEXT:   - LineNumber:      24
+// CHECK-NEXT:     Filename:        '{{.*}}'
+// CHECK-NEXT: Params:          
+// CHECK-NEXT:   - Type:            
+// CHECK-NEXT:       Name:            'int'
+// CHECK-NEXT:     Name:            'I'
+// CHECK-NEXT:   - Type:            
+// CHECK-NEXT:       Name:            'int'
+// CHECK-NEXT:     Name:            'J'
+// CHECK-NEXT: ReturnType:      
+// CHECK-NEXT:   Type:            
+// CHECK-NEXT:     Name:            'void'
+// CHECK-NEXT: ...

Added: clang-tools-extra/trunk/test/clang-doc/yaml-namespace.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-doc/yaml-namespace.cpp?rev=334103&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-doc/yaml-namespace.cpp (added)
+++ clang-tools-extra/trunk/test/clang-doc/yaml-namespace.cpp Wed Jun  6 09:13:17 2018
@@ -0,0 +1,102 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: cat %t/docs/A.yaml | FileCheck %s --check-prefix=CHECK-A
+// RUN: cat %t/docs/A/B.yaml | FileCheck %s --check-prefix=CHECK-B
+// RUN: cat %t/docs/A/f.yaml | FileCheck %s --check-prefix=CHECK-F
+// RUN: cat %t/docs/A/B/E.yaml | FileCheck %s --check-prefix=CHECK-E
+// RUN: cat %t/docs/A/B/func.yaml | FileCheck %s --check-prefix=CHECK-FUNC
+
+namespace A {
+  
+// CHECK-A: ---
+// CHECK-A-NEXT: USR:             '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
+// CHECK-A-NEXT: Name:            'A'
+// CHECK-A-NEXT: ...
+
+
+void f();
+
+}  // namespace A
+
+namespace A {
+
+void f(){};
+
+// CHECK-F: ---
+// CHECK-F-NEXT: USR:             '39D3C95A5F7CE2BA4937BD7B01BAE09EBC2AD8AC'
+// CHECK-F-NEXT: Name:            'f'
+// CHECK-F-NEXT: Namespace:       
+// CHECK-F-NEXT:   - Type:            Namespace
+// CHECK-F-NEXT:     Name:            'A'
+// CHECK-F-NEXT:     USR:             '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
+// CHECK-F-NEXT: DefLocation:     
+// CHECK-F-NEXT:   LineNumber:      26
+// CHECK-F-NEXT:   Filename:        '{{.*}}'
+// CHECK-F-NEXT: Location:        
+// CHECK-F-NEXT:   - LineNumber:      20
+// CHECK-F-NEXT:     Filename:        'test'
+// CHECK-F-NEXT: ReturnType:      
+// CHECK-F-NEXT:   Type:            
+// CHECK-F-NEXT:     Name:            'void'
+// CHECK-F-NEXT: ...
+
+namespace B {
+  
+// CHECK-B: ---
+// CHECK-B-NEXT: USR:             'E21AF79E2A9D02554BA090D10DF39FE273F5CDB5'
+// CHECK-B-NEXT: Name:            'B'
+// CHECK-B-NEXT: Namespace:       
+// CHECK-B-NEXT:   - Type:            Namespace
+// CHECK-B-NEXT:     Name:            'A'
+// CHECK-B-NEXT:     USR:             '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
+// CHECK-B-NEXT: ...
+
+
+enum E { X };
+
+// CHECK-E: ---
+// CHECK-E-NEXT: USR:             'E9ABF7E7E2425B626723D41E76E4BC7E7A5BD775'
+// CHECK-E-NEXT: Name:            'E'
+// CHECK-E-NEXT: Namespace:       
+// CHECK-E-NEXT:   - Type:            Namespace
+// CHECK-E-NEXT:     Name:            'B'
+// CHECK-E-NEXT:     USR:             'E21AF79E2A9D02554BA090D10DF39FE273F5CDB5'
+// CHECK-E-NEXT:   - Type:            Namespace
+// CHECK-E-NEXT:     Name:            'A'
+// CHECK-E-NEXT:     USR:             '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
+// CHECK-E-NEXT: DefLocation:     
+// CHECK-E-NEXT:   LineNumber:      58
+// CHECK-E-NEXT:   Filename:        '{{.*}}'
+// CHECK-E-NEXT: Members:         
+// CHECK-E-NEXT:   - 'X'
+// CHECK-E-NEXT: ...
+
+E func(int i) { return X; }
+
+// CHECK-FUNC: ---
+// CHECK-FUNC-NEXT: USR:             '9A82CB33ED0FDF81EE383D31CD0957D153C5E840'
+// CHECK-FUNC-NEXT: Name:            'func'
+// CHECK-FUNC-NEXT: Namespace:       
+// CHECK-FUNC-NEXT:   - Type:            Namespace
+// CHECK-FUNC-NEXT:     Name:            'B'
+// CHECK-FUNC-NEXT:     USR:             'E21AF79E2A9D02554BA090D10DF39FE273F5CDB5'
+// CHECK-FUNC-NEXT:   - Type:            Namespace
+// CHECK-FUNC-NEXT:     Name:            'A'
+// CHECK-FUNC-NEXT:     USR:             '8D042EFFC98B373450BC6B5B90A330C25A150E9C'
+// CHECK-FUNC-NEXT: DefLocation:     
+// CHECK-FUNC-NEXT:   LineNumber:      77
+// CHECK-FUNC-NEXT:   Filename:        '{{.*}}'
+// CHECK-FUNC-NEXT: Params:          
+// CHECK-FUNC-NEXT:   - Type:            
+// CHECK-FUNC-NEXT:       Name:            'int'
+// CHECK-FUNC-NEXT:     Name:            'i'
+// CHECK-FUNC-NEXT: ReturnType:      
+// CHECK-FUNC-NEXT:   Type:            
+// CHECK-FUNC-NEXT:     Name:            'enum A::B::E'
+// CHECK-FUNC-NEXT: ...
+
+}  // namespace B
+}  // namespace A

Added: clang-tools-extra/trunk/test/clang-doc/yaml-record.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-doc/yaml-record.cpp?rev=334103&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-doc/yaml-record.cpp (added)
+++ clang-tools-extra/trunk/test/clang-doc/yaml-record.cpp Wed Jun  6 09:13:17 2018
@@ -0,0 +1,250 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: cat %t/docs/A.yaml | FileCheck %s --check-prefix=CHECK-A
+// RUN: cat %t/docs/Bc.yaml | FileCheck %s --check-prefix=CHECK-BC
+// RUN: cat %t/docs/B.yaml | FileCheck %s --check-prefix=CHECK-B
+// RUN: cat %t/docs/C.yaml | FileCheck %s --check-prefix=CHECK-C
+// RUN: cat %t/docs/D.yaml | FileCheck %s --check-prefix=CHECK-D
+// RUN: cat %t/docs/E.yaml | FileCheck %s --check-prefix=CHECK-E
+// RUN: cat %t/docs/E/ProtectedMethod.yaml | FileCheck %s --check-prefix=CHECK-EPM
+// RUN: cat %t/docs/E/E.yaml | FileCheck %s --check-prefix=CHECK-ECON
+// RUN: cat %t/docs/E/'~E.yaml' | FileCheck %s --check-prefix=CHECK-EDES
+// RUN: cat %t/docs/F.yaml | FileCheck %s --check-prefix=CHECK-F
+// RUN: cat %t/docs/X.yaml | FileCheck %s --check-prefix=CHECK-X
+// RUN: cat %t/docs/X/Y.yaml | FileCheck %s --check-prefix=CHECK-Y
+// RUN: cat %t/docs/H.yaml | FileCheck %s --check-prefix=CHECK-H
+// RUN: cat %t/docs/H/I.yaml | FileCheck %s --check-prefix=CHECK-I
+
+union A { int X; int Y; };
+
+// CHECK-A: ---
+// CHECK-A-NEXT: USR:             'ACE81AFA6627B4CEF2B456FB6E1252925674AF7E'
+// CHECK-A-NEXT: Name:            'A'
+// CHECK-A-NEXT: DefLocation:     
+// CHECK-A-NEXT:   LineNumber:      21
+// CHECK-A-NEXT:   Filename:        '{{.*}}'
+// CHECK-A-NEXT: TagType:         Union
+// CHECK-A-NEXT: Members:         
+// CHECK-A-NEXT:   - Type:            
+// CHECK-A-NEXT:       Name:            'int'
+// CHECK-A-NEXT:     Name:            'X'
+// CHECK-A-NEXT:   - Type:            
+// CHECK-A-NEXT:       Name:            'int'
+// CHECK-A-NEXT:     Name:            'Y'
+// CHECK-A-NEXT: ...
+
+
+enum B { X, Y };
+
+// CHECK-B: ---
+// CHECK-B-NEXT: USR:             'FC07BD34D5E77782C263FA944447929EA8753740'
+// CHECK-B-NEXT: Name:            'B'
+// CHECK-B-NEXT: DefLocation:     
+// CHECK-B-NEXT:   LineNumber:      40
+// CHECK-B-NEXT:   Filename:        '{{.*}}'
+// CHECK-B-NEXT: Members:         
+// CHECK-B-NEXT:   - 'X'
+// CHECK-B-NEXT:   - 'Y'
+// CHECK-B-NEXT: ...
+
+enum class Bc { A, B };
+
+// CHECK-BC: ---
+// CHECK-BC-NEXT: USR:             '1E3438A08BA22025C0B46289FF0686F92C8924C5'
+// CHECK-BC-NEXT: Name:            'Bc'
+// CHECK-BC-NEXT: DefLocation:     
+// CHECK-BC-NEXT:   LineNumber:      53
+// CHECK-BC-NEXT:   Filename:        '{{.*}}'
+// CHECK-BC-NEXT: Scoped:          true
+// CHECK-BC-NEXT: Members:         
+// CHECK-BC-NEXT:   - 'A'
+// CHECK-BC-NEXT:   - 'B'
+// CHECK-BC-NEXT: ...
+
+struct C { int i; };
+
+// CHECK-C: ---
+// CHECK-C-NEXT: USR:             '06B5F6A19BA9F6A832E127C9968282B94619B210'
+// CHECK-C-NEXT: Name:            'C'
+// CHECK-C-NEXT: DefLocation:     
+// CHECK-C-NEXT:   LineNumber:      67
+// CHECK-C-NEXT:   Filename:        '{{.*}}'
+// CHECK-C-NEXT: Members:         
+// CHECK-C-NEXT:   - Type:            
+// CHECK-C-NEXT:       Name:            'int'
+// CHECK-C-NEXT:     Name:            'i'
+// CHECK-C-NEXT: ...
+
+class D {};
+
+// CHECK-D: ---
+// CHECK-D-NEXT: USR:             '0921737541208B8FA9BB42B60F78AC1D779AA054'
+// CHECK-D-NEXT: Name:            'D'
+// CHECK-D-NEXT: DefLocation:     
+// CHECK-D-NEXT:   LineNumber:      81
+// CHECK-D-NEXT:   Filename:        '{{.*}}'
+// CHECK-D-NEXT: TagType:         Class
+// CHECK-D-NEXT: ...
+
+class E {
+public:
+  E() {}
+
+// CHECK-ECON: ---
+// CHECK-ECON-NEXT: USR:             'DEB4AC1CD9253CD9EF7FBE6BCAC506D77984ABD4'
+// CHECK-ECON-NEXT: Name:            'E'
+// CHECK-ECON-NEXT: Namespace:       
+// CHECK-ECON-NEXT:   - Type:            Record
+// CHECK-ECON-NEXT:     Name:            'E'
+// CHECK-ECON-NEXT:     USR:             '289584A8E0FF4178A794622A547AA622503967A1'
+// CHECK-ECON-NEXT: DefLocation:
+// CHECK-ECON-NEXT:   LineNumber:      94
+// CHECK-ECON-NEXT:   Filename:        '{{.*}}'
+// CHECK-ECON-NEXT: IsMethod:        true
+// CHECK-ECON-NEXT: Parent:          
+// CHECK-ECON-NEXT:   Type:            Record
+// CHECK-ECON-NEXT:   Name:            'E'
+// CHECK-ECON-NEXT:   USR:             '289584A8E0FF4178A794622A547AA622503967A1'
+// CHECK-ECON-NEXT: ReturnType:      
+// CHECK-ECON-NEXT:   Type:            
+// CHECK-ECON-NEXT:     Name:            'void'
+// CHECK-ECON-NEXT: ...
+  
+  ~E() {}
+  
+// CHECK-EDES: ---
+// CHECK-EDES-NEXT: USR:             'BD2BDEBD423F80BACCEA75DE6D6622D355FC2D17'
+// CHECK-EDES-NEXT: Name:            '~E'
+// CHECK-EDES-NEXT: Namespace:       
+// CHECK-EDES-NEXT:   - Type:            Record
+// CHECK-EDES-NEXT:     Name:            'E'
+// CHECK-EDES-NEXT:     USR:             '289584A8E0FF4178A794622A547AA622503967A1'
+// CHECK-EDES-NEXT: DefLocation:     
+// CHECK-EDES-NEXT:   LineNumber:      116
+// CHECK-EDES-NEXT:   Filename:        '{{.*}}'
+// CHECK-EDES-NEXT: IsMethod:        true
+// CHECK-EDES-NEXT: Parent:          
+// CHECK-EDES-NEXT:   Type:            Record
+// CHECK-EDES-NEXT:   Name:            'E'
+// CHECK-EDES-NEXT:   USR:             '289584A8E0FF4178A794622A547AA622503967A1'
+// CHECK-EDES-NEXT: ReturnType:      
+// CHECK-EDES-NEXT:   Type:            
+// CHECK-EDES-NEXT:     Name:            'void'
+// CHECK-EDES-NEXT: ...
+
+
+protected:
+  void ProtectedMethod();
+};
+
+// CHECK-E: ---
+// CHECK-E-NEXT: USR:             '289584A8E0FF4178A794622A547AA622503967A1'
+// CHECK-E-NEXT: Name:            'E'
+// CHECK-E-NEXT: DefLocation:     
+// CHECK-E-NEXT:   LineNumber:      92
+// CHECK-E-NEXT:   Filename:        '{{.*}}'
+// CHECK-E-NEXT: TagType:         Class
+// CHECK-E-NEXT: ...
+
+void E::ProtectedMethod() {}
+
+// CHECK-EPM: ---
+// CHECK-EPM-NEXT: USR:             '5093D428CDC62096A67547BA52566E4FB9404EEE'
+// CHECK-EPM-NEXT: Name:            'ProtectedMethod'
+// CHECK-EPM-NEXT: Namespace:       
+// CHECK-EPM-NEXT:   - Type:            Record
+// CHECK-EPM-NEXT:     Name:            'E'
+// CHECK-EPM-NEXT:     USR:             '289584A8E0FF4178A794622A547AA622503967A1'
+// CHECK-EPM-NEXT: DefLocation:     
+// CHECK-EPM-NEXT:   LineNumber:      152
+// CHECK-EPM-NEXT:   Filename:        '{{.*}}'
+// CHECK-EPM-NEXT: Location:        
+// CHECK-EPM-NEXT:   - LineNumber:      140
+// CHECK-EPM-NEXT:     Filename:        '{{.*}}'
+// CHECK-EPM-NEXT: IsMethod:        true
+// CHECK-EPM-NEXT: Parent:          
+// CHECK-EPM-NEXT:   Type:            Record
+// CHECK-EPM-NEXT:   Name:            'E'
+// CHECK-EPM-NEXT:   USR:             '289584A8E0FF4178A794622A547AA622503967A1'
+// CHECK-EPM-NEXT: ReturnType:      
+// CHECK-EPM-NEXT:   Type:            
+// CHECK-EPM-NEXT:     Name:            'void'
+// CHECK-EPM-NEXT: ...
+
+class F : virtual private D, public E {};
+
+// CHECK-F: ---
+// CHECK-F-NEXT: USR:             'E3B54702FABFF4037025BA194FC27C47006330B5'
+// CHECK-F-NEXT: Name:            'F'
+// CHECK-F-NEXT: DefLocation:     
+// CHECK-F-NEXT:   LineNumber:      177
+// CHECK-F-NEXT:   Filename:        '{{.*}}'
+// CHECK-F-NEXT: TagType:         Class
+// CHECK-F-NEXT: Parents:         
+// CHECK-F-NEXT:   - Type:            Record
+// CHECK-F-NEXT:     Name:            'E'
+// CHECK-F-NEXT:     USR:             '289584A8E0FF4178A794622A547AA622503967A1'
+// CHECK-F-NEXT: VirtualParents:  
+// CHECK-F-NEXT:   - Type:            Record
+// CHECK-F-NEXT:     Name:            'D'
+// CHECK-F-NEXT:     USR:             '0921737541208B8FA9BB42B60F78AC1D779AA054'
+// CHECK-F-NEXT: ...
+
+class X {
+  class Y {};
+  
+// CHECK-Y: ---
+// CHECK-Y-NEXT: USR:             '641AB4A3D36399954ACDE29C7A8833032BF40472'
+// CHECK-Y-NEXT: Name:            'Y'
+// CHECK-Y-NEXT: Namespace:       
+// CHECK-Y-NEXT:   - Type:            Record
+// CHECK-Y-NEXT:     Name:            'X'
+// CHECK-Y-NEXT:     USR:             'CA7C7935730B5EACD25F080E9C83FA087CCDC75E'
+// CHECK-Y-NEXT: DefLocation:     
+// CHECK-Y-NEXT:   LineNumber:      197
+// CHECK-Y-NEXT:   Filename:        '{{.*}}'
+// CHECK-Y-NEXT: TagType:         Class
+// CHECK-Y-NEXT: ...
+
+};
+
+// CHECK-X: ---
+// CHECK-X-NEXT: USR:             'CA7C7935730B5EACD25F080E9C83FA087CCDC75E'
+// CHECK-X-NEXT: Name:            'X'
+// CHECK-X-NEXT: DefLocation:     
+// CHECK-X-NEXT:   LineNumber:      196
+// CHECK-X-NEXT:   Filename:        '{{.*}}'
+// CHECK-X-NEXT: TagType:         Class
+// CHECK-X-NEXT: ...
+
+void H() {
+  class I {};
+  
+// CHECK-I: ---
+// CHECK-I-NEXT: USR:             '{{.*}}'
+// CHECK-I-NEXT: Name:            'I'
+// CHECK-I-NEXT: Namespace:       
+// CHECK-I-NEXT:   - Type:            Function
+// CHECK-I-NEXT:     Name:            'H'
+// CHECK-I-NEXT:     USR:             'B6AC4C5C9F2EA3F2B3ECE1A33D349F4EE502B24E'
+// CHECK-I-NEXT: DefLocation:     
+// CHECK-I-NEXT:   LineNumber:      224
+// CHECK-I-NEXT:   Filename:        'test'
+// CHECK-I-NEXT: TagType:         Class
+// CHECK-I-NEXT: ...
+
+}
+
+// CHECK-H: ---
+// CHECK-H-NEXT: USR:             'B6AC4C5C9F2EA3F2B3ECE1A33D349F4EE502B24E'
+// CHECK-H-NEXT: Name:            'H'
+// CHECK-H-NEXT: DefLocation:     
+// CHECK-H-NEXT:   LineNumber:      223
+// CHECK-H-NEXT:   Filename:        'test'
+// CHECK-H-NEXT: ReturnType:      
+// CHECK-H-NEXT:   Type:            
+// CHECK-H-NEXT:     Name:            'void'
+// CHECK-H-NEXT: ...




More information about the cfe-commits mailing list