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

Updating based on parent revision changes -- still rough, will continue to 
improve.


https://reviews.llvm.org/D43424

Files:
  clang-doc/generators/CMakeLists.txt
  clang-doc/generators/Generators.h
  clang-doc/generators/MDGenerator.cpp
  clang-doc/tool/ClangDocMain.cpp

Index: clang-doc/tool/ClangDocMain.cpp
===================================================================
--- clang-doc/tool/ClangDocMain.cpp
+++ clang-doc/tool/ClangDocMain.cpp
@@ -49,7 +49,7 @@
     cl::init("docs"), cl::cat(ClangDocCategory));
 
 static cl::opt<std::string> Format(
-    "format", cl::desc("Format for outputted docs (Current options are yaml)."),
+    "format", cl::desc("Format for outputted docs (Current options are yaml, md)."),
     cl::init("yaml"), cl::cat(ClangDocCategory));
 
 static cl::opt<bool> DumpResult(
Index: clang-doc/generators/MDGenerator.cpp
===================================================================
--- /dev/null
+++ clang-doc/generators/MDGenerator.cpp
@@ -0,0 +1,366 @@
+//===-- 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 "../Representation.h"
+#include "Generators.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+using namespace llvm;
+
+namespace clang {
+namespace doc {
+
+int MDGenerator::generate() {
+  if (buildDirTree() && writeNamespaces() && writeClasses()) return 0;
+  return 1;
+}
+
+// File creation and I/O
+
+int MDGenerator::buildDirTree() {
+  removeExistingDirectory(Root);
+  sys::path::native(Root, NamespacesPath);
+  sys::path::append(NamespacesPath, "namespaces");
+  sys::path::native(Root, ClassPath);
+  sys::path::append(ClassPath, "classes");
+  return buildDirectory(NamespacesPath) && buildDirectory(ClassPath);
+}
+
+// Documentation generation
+
+bool MDGenerator::writeNamespaces() {
+  // TODO: Generate summary page
+  bool Success = true;
+  for (const auto &I : IS->getNamespaceInfos()) Success = writeNamespacePage(I);
+  return Success;
+}
+
+bool MDGenerator::writeClasses() {
+  bool Success = true;
+  for (const auto &I : IS->getRecordInfos()) {
+    if (I->TagType == TagTypeKind::TTK_Class) Success = writeClassPage(I);
+  }
+  return Success;
+}
+
+bool MDGenerator::writeNamespacePage(const std::unique_ptr<NamespaceInfo> &I) {
+  SmallString<128> Path;
+  sys::path::native(NamespacesPath, Path);
+  // for (const auto &Namespace : I->Namespace)
+  //   sys::path::append(Path, IS->find<NamespaceInfo>(Namespace)->Name);
+  // std::error_code DirectoryStatus = sys::fs::create_directories(Path);
+  // if (DirectoryStatus != OK) {
+  //   errs() << "Unable to create class directories.\n";
+  //   return 1;
+  // }
+  sys::path::append(Path, I->Name + ".md");
+  std::error_code OutErrorInfo;
+  raw_fd_ostream OS(Path, OutErrorInfo, sys::fs::F_None);
+  if (OutErrorInfo != OK) {
+    errs() << "Error opening class file.\n";
+    return false;
+  }
+
+  writeLine(genH1("namespace " + I->Name), OS);
+  writeBlankLine(OS);
+
+  for (const auto &C : I->Description) writeDescription(C, OS);
+
+  // TODO: Write subnamespaces
+
+  // Write functions.
+  bool wroteFunctionHeader = false;
+  for (const auto &F : IS->getFunctionInfos()) {
+    if (!F->Namespace.empty() && F->Namespace[0] == I->Name) {
+      if (!wroteFunctionHeader) {
+        wroteFunctionHeader = true;
+        writeLine(genH2("Functions"), OS);
+      }
+      writeFunction(F, OS);
+      writeBlankLine(OS);
+    }
+  }
+
+  // Fetch and sort records.
+  llvm::SmallVector<const RecordInfo *, 8> Structs;
+  llvm::SmallVector<const RecordInfo *, 8> Classes;
+  llvm::SmallVector<const RecordInfo *, 8> Unions;
+  for (const auto &R : IS->getRecordInfos()) {
+    if (!R->Namespace.empty() && R->Namespace[0] == I->Name) {
+      switch (R->TagType) {
+        case TagTypeKind::TTK_Class:
+          Classes.push_back(R.get());
+          break;
+        case TagTypeKind::TTK_Struct:
+          Structs.push_back(R.get());
+          break;
+        case TagTypeKind::TTK_Union:
+          Unions.push_back(R.get());
+          break;
+        default:
+          continue;
+      }
+    }
+  }
+
+  // Write structs.
+  bool wroteHeader = false;
+  sortRecordInfos(Structs);
+  for (const auto &S : Structs) {
+    if (!wroteHeader) {
+      wroteHeader = true;
+      writeLine(genH2("Structs"), OS);
+    }
+    writeRecordSummary(*S, OS);
+    writeBlankLine(OS);
+  }
+
+  // Write classes.
+  wroteHeader = false;
+  sortRecordInfos(Classes);
+  for (const auto &C : Classes) {
+    if (!wroteHeader) {
+      wroteHeader = true;
+      writeLine(genH2("Classes"), OS);
+    }
+    writeRecordSummary(*C, OS);
+    writeBlankLine(OS);
+  }
+
+  // Write unions.
+  wroteHeader = false;
+  sortRecordInfos(Unions);
+  for (const auto &U : Unions) {
+    if (!wroteHeader) {
+      wroteHeader = true;
+      writeLine(genH2("Unions"), OS);
+    }
+    writeRecordSummary(*U, OS);
+    writeBlankLine(OS);
+  }
+
+  // Write enums.
+  wroteHeader = false;
+  for (const auto &E : IS->getEnumInfos()) {
+    if (!E->Namespace.empty() && E->Namespace[0] == I->Name) {
+      if (!wroteHeader) {
+        wroteHeader = true;
+        writeLine(genH2("Enums"), OS);
+      }
+      writeEnum(E, OS);
+      writeBlankLine(OS);
+    }
+  }
+  return true;
+}
+
+bool MDGenerator::writeClassPage(const std::unique_ptr<RecordInfo> &I) {
+  SmallString<128> Path;
+  sys::path::native(ClassPath, Path);
+  // for (const auto &Namespace : I->Namespace)
+  //   sys::path::append(Path, IS->find<NamespaceInfo>(Namespace)->Name);
+  // std::error_code DirectoryStatus = sys::fs::create_directories(Path);
+  // if (DirectoryStatus != OK) {
+  //   errs() << "Unable to create class directories.\n";
+  //   return 1;
+  // }
+  sys::path::append(Path, I->Name + ".md");
+  std::error_code OutErrorInfo;
+  raw_fd_ostream OS(Path, OutErrorInfo, sys::fs::F_None);
+  if (OutErrorInfo != OK) {
+    errs() << "Error opening class file.\n";
+    return false;
+  }
+
+  writeLine(genH1("class " + I->Name), OS);
+  writeFileDefinition(I->DefLoc, OS);
+  writeBlankLine(OS);
+
+  for (const auto &C : I->Description) writeDescription(C, OS);
+
+  bool wroteMethodHeader = false;
+  for (const auto &F : IS->getFunctionInfos()) {
+    if (F->ParentUSR == I->Name) {
+      if (!wroteMethodHeader) {
+        wroteMethodHeader = true;
+        writeLine(genH2("Methods"), OS);
+      }
+      writeFunction(F, OS);
+      writeBlankLine(OS);
+    }
+  }
+
+  if (!I->Members.empty()) writeLine(genH2("Members"), OS);
+  for (const auto &M : I->Members) {
+    writeMemberType(M, OS);
+    writeBlankLine(OS);
+  }
+
+  bool wroteEnumHeader = false;
+  for (const auto &E : IS->getEnumInfos()) {
+    if (!E->Namespace.empty() && E->Namespace[0] == I->Name) {
+      if (!wroteEnumHeader) {
+        wroteEnumHeader = true;
+        writeLine(genH2("Enums"), OS);
+      }
+      writeEnum(E, OS);
+      writeBlankLine(OS);
+    }
+  }
+
+  OS.close();
+  return true;
+}
+
+void MDGenerator::writeRecordSummary(const RecordInfo &I,
+                                     raw_ostream &OS) {
+  // TODO: Add brief comment.
+  switch (I.TagType) {
+    case TagTypeKind::TTK_Class:
+      writeLine("class " + I.Name, OS);
+      break;
+    case TagTypeKind::TTK_Struct:
+      writeLine("struct " + I.Name, OS);
+      break;
+    case TagTypeKind::TTK_Union:
+      writeLine("union " + I.Name, OS);
+      break;
+    default:
+      return;
+  }
+}
+
+void MDGenerator::writeFunction(const std::unique_ptr<FunctionInfo> &I,
+                                raw_ostream &OS) {
+  std::string Params;
+  llvm::raw_string_ostream Stream(Params);
+  for (const auto &N : I->Params) Stream << N->TypeUSR + " " + N->Name << ", ";
+  writeLine(I->ReturnType->TypeUSR + " " + I->Name + "(" + Params + ")", OS);
+  for (const auto &C : I->Description) writeDescription(C, OS);
+  writeFileDefinition(I->DefLoc, OS);
+}
+
+void MDGenerator::writeEnum(const std::unique_ptr<EnumInfo> &I,
+                            raw_ostream &OS) {
+  writeLine(genTableCell(I->Name), OS);
+  writeLine(genTableCell("--"), OS);
+  for (const auto &M : I->Members) writeLine(genTableCell(M->TypeUSR), OS);
+  for (const auto &C : I->Description) writeDescription(C, OS);
+  writeFileDefinition(I->DefLoc, OS);
+}
+
+void MDGenerator::writeType(const std::unique_ptr<TypeInfo> &N,
+                            raw_ostream &OS) {
+  writeLine(N->TypeUSR, OS);
+  for (const auto &C : N->Description) writeDescription(C, OS);
+}
+
+void MDGenerator::writeFieldType(const std::unique_ptr<FieldTypeInfo> &N,
+                                 raw_ostream &OS) {
+  writeLine(N->TypeUSR + " " + N->Name, OS);
+  for (const auto &C : N->Description) writeDescription(C, OS);
+}
+
+void MDGenerator::writeMemberType(const std::unique_ptr<MemberTypeInfo> &N,
+                                  raw_ostream &OS) {
+  // TODO: Add access output.
+  writeLine(N->TypeUSR + " " + N->Name, OS);
+  for (const auto &C : N->Description) writeDescription(C, OS);
+}
+
+void MDGenerator::writeDescription(const std::unique_ptr<CommentInfo> &I,
+                                   raw_ostream &OS) {}
+
+void MDGenerator::writeFileDefinition(const Location &L, raw_ostream &OS) {
+  writeLine(genItalic("Defined at line " + std::to_string(L.LineNumber) +
+                      " of " + L.Filename + "."),
+            OS);
+}
+
+// Helper functions
+
+void MDGenerator::sortRecordInfos(
+    llvm::SmallVector<const RecordInfo *, 8> Records) {
+  std::sort(Records.begin(), Records.end(),
+            [](const RecordInfo *A, const RecordInfo *B) {
+              return A->Name.compare(B->Name) > 0 ? false : true;
+            });
+}
+
+// Markdown generation
+
+void MDGenerator::writeLine(StringRef Text, raw_ostream &OS) {
+  OS << Text << "\n";
+}
+
+void MDGenerator::writeBlankLine(raw_ostream &OS) { OS << "\n"; }
+
+std::string MDGenerator::genItalic(const Twine &Text) {
+  return "*" + Text.str() + "*";
+}
+
+std::string MDGenerator::genEmphasis(const Twine &Text) {
+  return "**" + Text.str() + "**";
+}
+
+std::string MDGenerator::genStrikethrough(const Twine &Text) {
+  return "~~" + Text.str() + "~~";
+}
+
+std::string MDGenerator::genH1(const Twine &Text) { return "# " + Text.str(); }
+
+std::string MDGenerator::genH2(const Twine &Text) { return "## " + Text.str(); }
+
+std::string MDGenerator::genH3(const Twine &Text) {
+  return "### " + Text.str();
+}
+
+std::string MDGenerator::genH4(const Twine &Text) {
+  return "#### " + Text.str();
+}
+
+std::string MDGenerator::genH5(const Twine &Text) {
+  return "##### " + Text.str();
+}
+
+std::string MDGenerator::genH6(const Twine &Text) {
+  return "###### " + Text.str();
+}
+
+std::string MDGenerator::genTableCell(const Twine &Text) {
+  return "| " + Text.str() + " |";
+}
+
+std::string MDGenerator::genUnorderedItem(const Twine &Text, int Indent) {
+  return ' ' * Indent + "- " + Text.str();
+}
+
+std::string MDGenerator::genOrderedItem(const Twine &Text, int Pos,
+                                        int Indent) {
+  return ' ' * Indent + Pos + ". " + Text.str();
+}
+
+std::string MDGenerator::genLink(const Twine &Text, const Twine &Link) {
+  return "[" + Text.str() + "](" + Link.str() + ")";
+}
+
+std::string MDGenerator::genLinkWithTooltip(const Twine &Text,
+                                            const Twine &Link,
+                                            const Twine &Tooltip) {
+  return "[" + Text.str() + "](" + Link.str() + " \"" + Tooltip.str() + "\")";
+}
+
+std::string MDGenerator::genInlineCode(const Twine &Text) {
+  return "`" + Text.str() + "`";
+}
+
+}  // namespace doc
+}  // namespace clang
Index: clang-doc/generators/Generators.h
===================================================================
--- clang-doc/generators/Generators.h
+++ clang-doc/generators/Generators.h
@@ -41,6 +41,54 @@
   std::error_code OK;
 };
 
+class MDGenerator : public Generator {
+public:
+  MDGenerator(std::unique_ptr<InfoSet> &IS, StringRef Root, StringRef Format) : Generator(IS, Root, Format) {};
+  virtual ~MDGenerator() {};
+  
+  virtual int generate();
+  
+private:
+  int buildDirTree();
+  
+  bool writeNamespaces();
+  bool writeClasses();
+  bool writeNamespacePage(const std::unique_ptr<NamespaceInfo> &I);
+  bool writeClassPage(const std::unique_ptr<RecordInfo> &I);
+  
+  void writeRecordSummary(const RecordInfo &I, raw_ostream &OS);
+  void writeType(const std::unique_ptr<TypeInfo> &N, raw_ostream &OS);
+  void writeFieldType(const std::unique_ptr<FieldTypeInfo> &N, raw_ostream &OS);
+  void writeMemberType(const std::unique_ptr<MemberTypeInfo> &N, raw_ostream &OS);
+  void writeEnum(const std::unique_ptr<EnumInfo> &I, raw_ostream &OS);
+  void writeFunction(const std::unique_ptr<FunctionInfo> &I, raw_ostream &OS);
+  void writeDescription(const std::unique_ptr<CommentInfo> &I, raw_ostream &OS);
+  void writeFileDefinition(const Location &L, raw_ostream &OS);
+
+  void sortRecordInfos(llvm::SmallVector<const RecordInfo *, 8> Records);
+
+  void writeLine(StringRef Text, raw_ostream &OS);
+  void writeBlankLine(raw_ostream &OS);
+  std::string genItalic(const Twine &Text);
+  std::string genEmphasis(const Twine &Text);
+  std::string genStrikethrough(const Twine &Text);
+  std::string genH1(const Twine &Text);
+  std::string genH2(const Twine &Text);
+  std::string genH3(const Twine &Text);
+  std::string genH4(const Twine &Text);
+  std::string genH5(const Twine &Text);
+  std::string genH6(const Twine &Text);
+  std::string genTableCell(const Twine &Text);
+  std::string genUnorderedItem(const Twine &Text, int Indent=0);
+  std::string genOrderedItem(const Twine &Text, int Pos, int Indent=0);
+  std::string genLink(const Twine &Text, const Twine &Link);
+  std::string genLinkWithTooltip(const Twine &Text, const Twine &Link, const Twine &Tooltip);
+  std::string genInlineCode(const Twine &Text);
+
+  SmallString<128> NamespacesPath;
+  SmallString<128> ClassPath;
+};
+
 class YAMLGenerator : public Generator {
  public:
   YAMLGenerator(std::unique_ptr<InfoSet> &IS, StringRef Root, StringRef Format)
@@ -56,7 +104,8 @@
                                            StringRef Root, StringRef Format) {
     if (Format == "yaml")
       return llvm::make_unique<YAMLGenerator>(IS, Root, Format);
-
+    if (Format == "md")
+      return llvm::make_unique<MDGenerator>(IS, Root, Format);
     errs() << "Unsupported documentation format.\n";
     return nullptr;
   }
Index: clang-doc/generators/CMakeLists.txt
===================================================================
--- clang-doc/generators/CMakeLists.txt
+++ clang-doc/generators/CMakeLists.txt
@@ -3,6 +3,7 @@
 add_clang_library(clangDocGenerators
   GeneratorBase.cpp
   YAMLGenerator.cpp
+  MDGenerator.cpp
 
   LINK_LIBS
   clangDoc
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to