juliehockett updated this revision to Diff 152135.
juliehockett added a comment.

Updating to reflect changes to the framework (and make it work).


https://reviews.llvm.org/D43424

Files:
  clang-tools-extra/clang-doc/CMakeLists.txt
  clang-tools-extra/clang-doc/Generators.cpp
  clang-tools-extra/clang-doc/Generators.h
  clang-tools-extra/clang-doc/MDGenerator.cpp
  clang-tools-extra/clang-doc/Representation.cpp
  clang-tools-extra/clang-doc/Representation.h
  clang-tools-extra/clang-doc/YAMLGenerator.cpp
  clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
  clang-tools-extra/test/clang-doc/md-comments.cpp
  clang-tools-extra/test/clang-doc/md-namespace.cpp
  clang-tools-extra/test/clang-doc/md-record.cpp

Index: clang-tools-extra/test/clang-doc/md-record.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-doc/md-record.cpp
@@ -0,0 +1,101 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc -doxygen -format=md -p %t %t/test.cpp -output=%t/docs
+// RUN: cat %t/docs/A.md | FileCheck %s --check-prefix=CHECK-A
+// RUN: cat %t/docs/Bc.md | FileCheck %s --check-prefix=CHECK-BC
+// RUN: cat %t/docs/B.md | FileCheck %s --check-prefix=CHECK-B
+// RUN: cat %t/docs/C.md | FileCheck %s --check-prefix=CHECK-C
+// RUN: cat %t/docs/D.md | FileCheck %s --check-prefix=CHECK-D
+// RUN: cat %t/docs/E.md | FileCheck %s --check-prefix=CHECK-E
+// RUN: cat %t/docs/E/ProtectedMethod.md | FileCheck %s --check-prefix=CHECK-EPM
+// RUN: cat %t/docs/E/E.md | FileCheck %s --check-prefix=CHECK-ECON
+// RUN: cat %t/docs/E/'~E.md' | FileCheck %s --check-prefix=CHECK-EDES
+// RUN: cat %t/docs/F.md | FileCheck %s --check-prefix=CHECK-F
+// RUN: cat %t/docs/X.md | FileCheck %s --check-prefix=CHECK-X
+// RUN: cat %t/docs/X/Y.md | FileCheck %s --check-prefix=CHECK-Y
+// RUN: cat %t/docs/H.md | FileCheck %s --check-prefix=CHECK-H
+// RUN: cat %t/docs/H/I.md | FileCheck %s --check-prefix=CHECK-I
+
+union A { int X; int Y; };
+
+// CHECK-A: # union A
+// CHECK-A-NEXT: *Defined at line 21 of {{.*}}*
+// CHECK-A: ## Members 
+// CHECK-A-NEXT: int X
+// CHECK-A-NEXT: int Y
+
+enum B { X, Y };
+
+// CHECK-B: | enum B |
+// CHECK-B-NEXT: --
+// CHECK-B-NEXT: | X |
+// CHECK-B-NEXT: | Y |
+
+enum class Bc { A, B };
+
+// CHECK-BC: | enum class Bc |
+// CHECK-BC-NEXT: --
+// CHECK-BC-NEXT: | A |
+// CHECK-BC-NEXT: | B |
+
+struct C { int i; };
+
+// CHECK-C: # struct C
+// CHECK-C-NEXT: *Defined at line 43 of {{.*}}*
+// CHECK-C: ## Members 
+// CHECK-C-NEXT: int i
+
+class D {};
+
+// CHECK-D: # class D
+// CHECK-D-NEXT: *Defined at line 50 of {{.*}}*
+
+class E {
+public:
+  E() {}
+  ~E() {}
+
+protected:
+  void ProtectedMethod();
+};
+
+// CHECK-E: # class E
+// CHECK-E-NEXT: *Defined at line 55 of {{.*}}*
+
+// CHECK-ECON: ## void E()
+// CHECK-ECON-NEXT: *Defined at line 57 of {{.*}}*
+
+// CHECK-EDES: ## void ~E()
+// CHECK-EDES-NEXT: *Defined at line 58 of {{.*}}*
+
+void E::ProtectedMethod() {}
+
+// CHECK-EPM: ## void ProtectedMethod()
+// CHECK-EPM-NEXT: *Defined at line 73 of {{.*}}*
+
+class F : virtual private D, public E {};
+
+// CHECK-F: # class F
+// CHECK-F-NEXT: *Defined at line 78 of {{.*}}*
+
+class X {
+  class Y {};
+};
+
+// CHECK-X: # class X
+// CHECK-X-NEXT: *Defined at line 83 of {{.*}}*
+
+// CHECK-Y: # class Y
+// CHECK-Y-NEXT: *Defined at line 84 of {{.*}}*
+
+void H() {
+  class I {};
+}
+
+// CHECK-H: ## void H()
+// CHECK-H-NEXT: *Defined at line 93 of {{.*}}*
+
+// CHECK-I: # class I
+// CHECK-I-NEXT: *Defined at line 94 of {{.*}}*
Index: clang-tools-extra/test/clang-doc/md-namespace.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-doc/md-namespace.cpp
@@ -0,0 +1,43 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc -doxygen -format=md -p %t %t/test.cpp -output=%t/docs
+// RUN: cat %t/docs/A.md | FileCheck %s --check-prefix=CHECK-A
+// RUN: cat %t/docs/A/B.md | FileCheck %s --check-prefix=CHECK-B
+// RUN: cat %t/docs/A/f.md | FileCheck %s --check-prefix=CHECK-F
+// RUN: cat %t/docs/A/B/E.md | FileCheck %s --check-prefix=CHECK-E
+// RUN: cat %t/docs/A/B/func.md | FileCheck %s --check-prefix=CHECK-FUNC
+
+namespace A {
+  
+// CHECK-A: # namespace A
+
+void f();
+
+}  // namespace A
+
+namespace A {
+
+void f(){};
+
+// CHECK-F: ## void f()
+// CHECK-F-NEXT: *Defined at line 22 of {{.*}}*
+
+namespace B {
+
+// CHECK-B: # namespace B
+
+enum E { X };
+
+// CHECK-E:      | enum E |
+// CHECK-E-NEXT: --
+// CHECK-E-NEXT: | X |
+
+E func(int i) { return X; }
+
+// CHECK-FUNC: enum A::B::E func(int i)
+// CHECK-FUNC-NEXT: *Defined at line 37 of {{.*}}*
+
+}  // namespace B
+}  // namespace A
Index: clang-tools-extra/test/clang-doc/md-comments.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-doc/md-comments.cpp
@@ -0,0 +1,45 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc -doxygen -format=md -p %t %t/test.cpp -output=%t/docs
+// RUN: cat %t/docs/F.md | FileCheck %s
+
+/// \brief Brief description.
+///
+/// Extended description that
+/// continues onto the next line.
+/// 
+/// <ul class="test">
+///   <li> Testing. </li>
+/// </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:       ## void F(int I, int J)
+// CHECK-NEXT: *Defined at line 27 of {{.*}}*
+
+
+// CHECK:      **brief** Brief description.
+// CHECK-NEXT:  Extended description that continues onto the next line.
+// CHECK-NEXT: <ul "class=test">
+// CHECK-NEXT: <li>
+// CHECK-NEXT:  Testing. </li>
+// CHECK-NEXT: </ul>
+
+// CHECK:       The description continues.
+
+// CHECK:      **I** [out]
+// CHECK-NEXT: **J**
+// CHECK-NEXT: **return** void
+// CHECK-NEXT:  Bonus comment on definition
Index: clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
===================================================================
--- clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -34,6 +34,7 @@
 #include "clang/Tooling/StandaloneExecution.h"
 #include "clang/Tooling/Tooling.h"
 #include "llvm/ADT/APFloat.h"
+#include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
@@ -64,14 +65,19 @@
     llvm::cl::desc("Dump intermediate results to bitcode file."),
     llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));
 
-enum OutputFormatTy {
+enum class OutputFormatTy {
+  md,
   yaml,
 };
 
-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<OutputFormatTy>
+    FormatEnum("format", llvm::cl::desc("Format for outputted docs."),
+               llvm::cl::values(clEnumValN(OutputFormatTy::yaml, "yaml",
+                                           "Documentation in YAML format."),
+                                clEnumValN(OutputFormatTy::md, "md",
+                                           "Documentation in MD format.")),
+               llvm::cl::init(OutputFormatTy::yaml),
+               llvm::cl::cat(ClangDocCategory));
 
 static llvm::cl::opt<bool> DoxygenOnly(
     "doxygen",
@@ -134,34 +140,37 @@
   return Path;
 }
 
-std::string getFormatString(OutputFormatTy Ty) {
-  switch (Ty) {
-  case yaml:
+std::string getFormatString() {
+  switch (FormatEnum) {
+  case OutputFormatTy::yaml:
     return "yaml";
+  case OutputFormatTy::md:
+    return "md";
   }
   llvm_unreachable("Unknown OutputFormatTy");
 }
 
 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);
 
   if (!Exec) {
     llvm::errs() << toString(Exec.takeError()) << "\n";
     return 1;
   }
 
+  // Fail early if an invalid format was provided.
+  std::string Format = getFormatString();
+  llvm::outs() << "Emiting docs in " << Format << " format.\n";
+  auto G = doc::findGeneratorByName(Format);
+  if (!G) {
+    llvm::errs() << toString(G.takeError()) << "\n";
+    return 1;
+  }
+
   ArgumentsAdjuster ArgAdjuster;
   if (!DoxygenOnly)
     ArgAdjuster = combineAdjusters(
@@ -240,8 +249,8 @@
       continue;
     }
 
-    if (G->get()->generateDocForInfo(I, InfoOS))
-      llvm::errs() << "Unable to generate docs for info.\n";
+    if (auto Err = G->get()->generateDocForInfo(I, InfoOS))
+      llvm::errs() << toString(std::move(Err)) << "\n";
   }
 
   return 0;
Index: clang-tools-extra/clang-doc/YAMLGenerator.cpp
===================================================================
--- clang-tools-extra/clang-doc/YAMLGenerator.cpp
+++ clang-tools-extra/clang-doc/YAMLGenerator.cpp
@@ -230,12 +230,12 @@
 public:
   static const char *Format;
 
-  bool generateDocForInfo(Info *I, llvm::raw_ostream &OS) override;
+  llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override;
 };
 
 const char *YAMLGenerator::Format = "yaml";
 
-bool YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
+llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
   llvm::yaml::Output InfoYAML(OS);
   switch (I->IT) {
   case InfoType::IT_namespace:
@@ -251,10 +251,10 @@
     InfoYAML << *static_cast<clang::doc::FunctionInfo *>(I);
     break;
   case InfoType::IT_default:
-    llvm::errs() << "Unexpected info type in index.\n";
-    return true;
+    return llvm::make_error<llvm::StringError>("Unexpected info type.\n",
+                                               llvm::inconvertibleErrorCode());
   }
-  return false;
+  return llvm::Error::success();
 }
 
 static GeneratorRegistry::Add<YAMLGenerator> YAML(YAMLGenerator::Format,
Index: clang-tools-extra/clang-doc/Representation.h
===================================================================
--- clang-tools-extra/clang-doc/Representation.h
+++ clang-tools-extra/clang-doc/Representation.h
@@ -44,13 +44,14 @@
   CommentInfo(CommentInfo &Other) = delete;
   CommentInfo(CommentInfo &&Other) = default;
 
-  SmallString<16> Kind; // Kind of comment (TextComment, InlineCommandComment,
-                        // HTMLStartTagComment, HTMLEndTagComment,
-                        // BlockCommandComment, ParamCommandComment,
-                        // TParamCommandComment, VerbatimBlockComment,
-                        // VerbatimBlockLineComment, VerbatimLineComment).
-  SmallString<64> Text; // Text of the comment.
-  SmallString<16> Name; // Name of the comment (for Verbatim and HTML).
+  SmallString<16>
+      Kind; // Kind of comment (FullComment, ParagraphComment, TextComment,
+            // InlineCommandComment, HTMLStartTagComment, HTMLEndTagComment,
+            // BlockCommandComment, ParamCommandComment,
+            // TParamCommandComment, VerbatimBlockComment,
+            // VerbatimBlockLineComment, VerbatimLineComment).
+  SmallString<64> Text;      // Text of the comment.
+  SmallString<16> Name;      // Name of the comment (for Verbatim and HTML).
   SmallString<8> Direction;  // Parameter direction (for (T)ParamCommand).
   SmallString<16> ParamName; // Parameter name (for (T)ParamCommand).
   SmallString<16> CloseName; // Closing tag name (for VerbatimBlock).
Index: clang-tools-extra/clang-doc/Representation.cpp
===================================================================
--- clang-tools-extra/clang-doc/Representation.cpp
+++ clang-tools-extra/clang-doc/Representation.cpp
@@ -42,7 +42,7 @@
 mergeInfos(std::vector<std::unique_ptr<Info>> &Values) {
   if (Values.empty())
     return llvm::make_error<llvm::StringError>("No info values to merge.\n",
-                                             llvm::inconvertibleErrorCode());
+                                               llvm::inconvertibleErrorCode());
 
   switch (Values[0]->IT) {
   case InfoType::IT_namespace:
Index: clang-tools-extra/clang-doc/MDGenerator.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -0,0 +1,257 @@
+//===-- MDGenerator.cpp - Markdown Generator --------------------*- 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"
+#include "Representation.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include <string>
+
+using namespace llvm;
+
+namespace clang {
+namespace doc {
+
+// Enum conversion
+
+std::string getAccess(AccessSpecifier AS) {
+  switch (AS) {
+  case AccessSpecifier::AS_public:
+    return "public";
+  case AccessSpecifier::AS_protected:
+    return "protected";
+  case AccessSpecifier::AS_private:
+    return "private";
+  case AccessSpecifier::AS_none:
+    return "";
+  }
+}
+
+std::string getTagType(TagTypeKind AS) {
+  switch (AS) {
+  case TagTypeKind::TTK_Class:
+    return "class";
+  case TagTypeKind::TTK_Union:
+    return "union";
+  case TagTypeKind::TTK_Interface:
+    return "interface";
+  case TagTypeKind::TTK_Struct:
+    return "struct";
+  case TagTypeKind::TTK_Enum:
+    return "enum";
+  }
+}
+
+// Markdown generation
+
+std::string genItalic(const Twine &Text) { return "*" + Text.str() + "*"; }
+
+std::string genEmphasis(const Twine &Text) { return "**" + Text.str() + "**"; }
+
+std::string genLink(const Twine &Text, const Twine &Link) {
+  return "[" + Text.str() + "](" + Link.str() + ")";
+}
+
+std::string genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs) {
+  std::string Buffer;
+  llvm::raw_string_ostream Stream(Buffer);
+  bool First = true;
+  for (const auto &R : Refs) {
+    if (!First)
+      Stream << ", ";
+    Stream << R.Name;
+    First = false;
+  }
+  return Stream.str();
+}
+
+void writeLine(const Twine &Text, raw_ostream &OS) { OS << Text << "\n"; }
+
+void writeNewLine(raw_ostream &OS) { OS << "\n"; }
+
+void writeHeader(const Twine &Text, int Num, raw_ostream &OS) {
+  OS << std::string(Num, '#') + " " + Text << "\n";
+}
+
+void writeFileDefinition(const Location &L, raw_ostream &OS) {
+  OS << genItalic("Defined at line " + std::to_string(L.LineNumber) + " of " +
+                  L.Filename)
+     << "\n";
+}
+
+void writeDescription(const CommentInfo &I, raw_ostream &OS) {
+  if (I.Kind == "FullComment") {
+    for (const auto &Child : I.Children)
+      writeDescription(*Child, OS);
+  } else if (I.Kind == "ParagraphComment") {
+    for (const auto &Child : I.Children)
+      writeDescription(*Child, OS);
+    writeNewLine(OS);
+  } else if (I.Kind == "BlockCommandComment") {
+    OS << genEmphasis(I.Name);
+    for (const auto &Child : I.Children)
+      writeDescription(*Child, OS);
+  } else if (I.Kind == "InlineCommandComment") {
+    OS << genEmphasis(I.Name) << " " << I.Text;
+  } else if (I.Kind == "ParamCommandComment") {
+    std::string Direction = I.Explicit ? (" " + I.Direction).str() : "";
+    OS << genEmphasis(I.ParamName) << I.Text << Direction << "\n";
+  } else if (I.Kind == "TParamCommandComment") {
+    std::string Direction = I.Explicit ? (" " + I.Direction).str() : "";
+    OS << genEmphasis(I.ParamName) << I.Text << Direction << "\n";
+  } else if (I.Kind == "VerbatimBlockComment") {
+    for (const auto &Child : I.Children)
+      writeDescription(*Child, OS);
+  } else if (I.Kind == "VerbatimBlockLineComment") {
+    OS << I.Text;
+    writeNewLine(OS);
+  } else if (I.Kind == "VerbatimLineComment") {
+    OS << I.Text;
+    writeNewLine(OS);
+  } else if (I.Kind == "HTMLStartTagComment") {
+    if (I.AttrKeys.size() != I.AttrValues.size())
+      return;
+    std::string Buffer;
+    llvm::raw_string_ostream Attrs(Buffer);
+    for (unsigned Idx = 0; Idx < I.AttrKeys.size(); ++Idx)
+      Attrs << " \"" << I.AttrKeys[Idx] << "=" << I.AttrValues[Idx] << "\"";
+
+    std::string CloseTag = I.SelfClosing ? "/>" : ">";
+    writeLine("<" + I.Name + Attrs.str() + CloseTag, OS);
+  } else if (I.Kind == "HTMLEndTagComment") {
+    writeLine("</" + I.Name + ">", OS);
+  } else if (I.Kind == "TextComment") {
+    OS << I.Text;
+  } else {
+    OS << "Unknown comment kind: " << I.Kind << ".\n";
+  }
+}
+
+void genMarkdown(const NamespaceInfo &I, llvm::raw_ostream &OS) {
+  writeHeader("namespace " + I.Name, 1, OS);
+  writeNewLine(OS);
+  for (const auto &C : I.Description)
+    writeDescription(C, OS);
+}
+
+void genMarkdown(const RecordInfo &I, llvm::raw_ostream &OS) {
+  writeHeader(getTagType(I.TagType) + " " + I.Name, 1, OS);
+  for (const auto &C : I.Description)
+    writeDescription(C, OS);
+  writeFileDefinition(I.DefLoc.getValue(), OS);
+
+  writeNewLine(OS);
+  std::string Parents = genReferenceList(I.Parents);
+  std::string VParents = genReferenceList(I.VirtualParents);
+  if (!Parents.empty() || !VParents.empty()) {
+    if (Parents.empty())
+      writeLine("Inherits from " + VParents, OS);
+    else if (VParents.empty())
+      writeLine("Inherits from " + Parents, OS);
+    else
+      writeLine("Inherits from " + Parents + ", " + VParents, OS);
+  }
+
+  writeNewLine(OS);
+  if (!I.Members.empty()) {
+    writeHeader("Members", 2, OS);
+    for (const auto Member : I.Members) {
+      std::string Access = getAccess(Member.Access);
+      if (Access != "")
+        writeLine(Access + " " + Member.Type.Name + " " + Member.Name, OS);
+      else
+        writeLine(Member.Type.Name + " " + Member.Name, OS);
+    }
+  }
+}
+
+void genMarkdown(const EnumInfo &I, llvm::raw_ostream &OS) {
+  if (I.Scoped)
+    writeLine("| enum class " + I.Name + " |", OS);
+  else
+    writeLine("| enum " + I.Name + " |", OS);
+  writeLine("--", OS);
+
+  std::string Buffer;
+  llvm::raw_string_ostream Members(Buffer);
+  if (!I.Members.empty())
+    for (const auto &N : I.Members)
+      Members << "| " << N << " |\n";
+  writeLine(Members.str(), OS);
+  writeFileDefinition(I.DefLoc.getValue(), OS);
+  writeNewLine(OS);
+  for (const auto &C : I.Description)
+    writeDescription(C, OS);
+}
+
+void genMarkdown(const FunctionInfo &I, llvm::raw_ostream &OS) {
+  std::string Buffer;
+  llvm::raw_string_ostream Stream(Buffer);
+  bool First = true;
+  for (const auto &N : I.Params) {
+    if (!First)
+      Stream << ", ";
+    Stream << N.Type.Name + " " + N.Name;
+    First = false;
+  }
+  Twine Signature =
+      I.ReturnType.Type.Name + " " + I.Name + "(" + Stream.str() + ")";
+  std::string Access = getAccess(I.Access);
+  if (Access != "")
+    writeHeader(genItalic(Access) + " " + Signature, 2, OS);
+  else
+    writeHeader(Signature, 2, OS);
+  writeFileDefinition(I.DefLoc.getValue(), OS);
+  writeNewLine(OS);
+  for (const auto &C : I.Description)
+    writeDescription(C, OS);
+  writeNewLine(OS);
+}
+
+/// Generator for Markdown documentation.
+class MDGenerator : public Generator {
+public:
+  static const char *Format;
+
+  llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override;
+};
+
+const char *MDGenerator::Format = "md";
+
+llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
+  switch (I->IT) {
+  case InfoType::IT_namespace:
+    genMarkdown(*static_cast<clang::doc::NamespaceInfo *>(I), OS);
+    break;
+  case InfoType::IT_record:
+    genMarkdown(*static_cast<clang::doc::RecordInfo *>(I), OS);
+    break;
+  case InfoType::IT_enum:
+    genMarkdown(*static_cast<clang::doc::EnumInfo *>(I), OS);
+    break;
+  case InfoType::IT_function:
+    genMarkdown(*static_cast<clang::doc::FunctionInfo *>(I), OS);
+    break;
+  case InfoType::IT_default:
+    return llvm::make_error<llvm::StringError>("Unexpected info type.\n",
+                                               llvm::inconvertibleErrorCode());
+  }
+  return llvm::Error::success();
+}
+
+static GeneratorRegistry::Add<MDGenerator> MD(MDGenerator::Format,
+                                              "Generator for MD output.");
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the generator.
+volatile int MDGeneratorAnchorSource = 0;
+
+} // namespace doc
+} // namespace clang
Index: clang-tools-extra/clang-doc/Generators.h
===================================================================
--- clang-tools-extra/clang-doc/Generators.h
+++ clang-tools-extra/clang-doc/Generators.h
@@ -27,7 +27,7 @@
   virtual ~Generator() = default;
 
   // Write out the decl info in the specified format.
-  virtual bool generateDocForInfo(Info *I, llvm::raw_ostream &OS) = 0;
+  virtual llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) = 0;
 };
 
 typedef llvm::Registry<Generator> GeneratorRegistry;
Index: clang-tools-extra/clang-doc/Generators.cpp
===================================================================
--- clang-tools-extra/clang-doc/Generators.cpp
+++ clang-tools-extra/clang-doc/Generators.cpp
@@ -29,8 +29,11 @@
 // This anchor is used to force the linker to link in the generated object file
 // and thus register the generators.
 extern volatile int YAMLGeneratorAnchorSource;
+extern volatile int MDGeneratorAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED YAMLGeneratorAnchorDest =
     YAMLGeneratorAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED MDGeneratorAnchorDest =
+    MDGeneratorAnchorSource;
 
 } // namespace doc
 } // namespace clang
Index: clang-tools-extra/clang-doc/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-doc/CMakeLists.txt
+++ clang-tools-extra/clang-doc/CMakeLists.txt
@@ -10,6 +10,7 @@
   ClangDoc.cpp
   Generators.cpp
   Mapper.cpp
+  MDGenerator.cpp
   Representation.cpp
   Serialize.cpp
   YAMLGenerator.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D43424: [clang-doc]... Julie Hockett via Phabricator via cfe-commits

Reply via email to