DiegoAstiazaran updated this revision to Diff 206920.
DiegoAstiazaran marked 7 inline comments as done.
DiegoAstiazaran added a comment.

Fix TagType enum name and members.
Add anonymous namespace.
Separate the implementation from the definition for some functions.
Use emplace_back instead of push_back for instantiation of vector members.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D63857/new/

https://reviews.llvm.org/D63857

Files:
  clang-tools-extra/clang-doc/HTMLGenerator.cpp
  clang-tools-extra/clang-doc/MDGenerator.cpp
  clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp

Index: clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
===================================================================
--- clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
+++ clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
@@ -40,16 +40,31 @@
   llvm::raw_string_ostream Actual(Buffer);
   auto Err = G->generateDocForInfo(&I, Actual);
   assert(!Err);
-  std::string Expected = R"raw(<h1>namespace Namespace</h1>
-<h2>Namespaces</h2>
-<p>ChildNamespace</p>
-<h2>Records</h2>
-<p>ChildStruct</p>
-<h2>Functions</h2>
-<h3>OneFunction</h3>
-<p> OneFunction()</p>
-<h2>Enums</h2>
-<h3>enum OneEnum</h3>
+  std::string Expected = R"raw(<!DOCTYPE html>
+<meta charset="utf-8"/>
+<title>namespace Namespace</title>
+<div>
+  <h1>namespace Namespace</h1>
+  <h2>Namespaces</h2>
+  <ul>
+    <li>ChildNamespace</li>
+  </ul>
+  <h2>Records</h2>
+  <ul>
+    <li>ChildStruct</li>
+  </ul>
+  <h2>Functions</h2>
+  <div>
+    <h3>OneFunction</h3>
+    <p>
+       OneFunction()
+    </p>
+  </div>
+  <h2>Enums</h2>
+  <div>
+    <h3>enum OneEnum</h3>
+  </div>
+</div>
 )raw";
 
   EXPECT_EQ(Expected, Actual.str());
@@ -80,18 +95,37 @@
   llvm::raw_string_ostream Actual(Buffer);
   auto Err = G->generateDocForInfo(&I, Actual);
   assert(!Err);
-  std::string Expected = R"raw(<h1>class r</h1>
-<p>Defined at line 10 of test.cpp</p>
-<p>Inherits from F, G</p>
-<h2>Members</h2>
-<p>private int X</p>
-<h2>Records</h2>
-<p>ChildStruct</p>
-<h2>Functions</h2>
-<h3>OneFunction</h3>
-<p> OneFunction()</p>
-<h2>Enums</h2>
-<h3>enum OneEnum</h3>
+  std::string Expected = R"raw(<!DOCTYPE html>
+<meta charset="utf-8"/>
+<title>class r</title>
+<div>
+  <h1>class r</h1>
+  <p>
+    Defined at line 10 of test.cpp
+  </p>
+  <p>
+    Inherits from F, G
+  </p>
+  <h2>Members</h2>
+  <ul>
+    <li>private int X</li>
+  </ul>
+  <h2>Records</h2>
+  <ul>
+    <li>ChildStruct</li>
+  </ul>
+  <h2>Functions</h2>
+  <div>
+    <h3>OneFunction</h3>
+    <p>
+       OneFunction()
+    </p>
+  </div>
+  <h2>Enums</h2>
+  <div>
+    <h3>enum OneEnum</h3>
+  </div>
+</div>
 )raw";
 
   EXPECT_EQ(Expected, Actual.str());
@@ -116,9 +150,18 @@
   llvm::raw_string_ostream Actual(Buffer);
   auto Err = G->generateDocForInfo(&I, Actual);
   assert(!Err);
-  std::string Expected = R"raw(<h3>f</h3>
-<p>void f(int P)</p>
-<p>Defined at line 10 of test.cpp</p>
+  std::string Expected = R"raw(<!DOCTYPE html>
+<meta charset="utf-8"/>
+<title></title>
+<div>
+  <h3>f</h3>
+  <p>
+    void f(int P)
+  </p>
+  <p>
+    Defined at line 10 of test.cpp
+  </p>
+</div>
 )raw";
 
   EXPECT_EQ(Expected, Actual.str());
@@ -141,11 +184,18 @@
   llvm::raw_string_ostream Actual(Buffer);
   auto Err = G->generateDocForInfo(&I, Actual);
   assert(!Err);
-  std::string Expected = R"raw(<h3>enum class e</h3>
-<ul>
-<li>X</li>
-</ul>
-<p>Defined at line 10 of test.cpp</p>
+  std::string Expected = R"raw(<!DOCTYPE html>
+<meta charset="utf-8"/>
+<title></title>
+<div>
+  <h3>enum class e</h3>
+  <ul>
+    <li>X</li>
+  </ul>
+  <p>
+    Defined at line 10 of test.cpp
+  </p>
+</div>
 )raw";
 
   EXPECT_EQ(Expected, Actual.str());
@@ -194,12 +244,29 @@
   llvm::raw_string_ostream Actual(Buffer);
   auto Err = G->generateDocForInfo(&I, Actual);
   assert(!Err);
-  std::string Expected = R"raw(<h3>f</h3>
-<p>void f(int I, int J)</p>
-<p>Defined at line 10 of test.cpp</p>
-<p></p>
-<p> Brief description.</p>
-<p> Extended description that continues onto the next line.</p>
+  std::string Expected = R"raw(<!DOCTYPE html>
+<meta charset="utf-8"/>
+<title></title>
+<div>
+  <h3>f</h3>
+  <p>
+    void f(int I, int J)
+  </p>
+  <p>
+    Defined at line 10 of test.cpp
+  </p>
+  <div>
+    <div>
+      <p>
+         Brief description.
+      </p>
+      <p>
+         Extended description that
+         continues onto the next line.
+      </p>
+    </div>
+  </div>
+</div>
 )raw";
 
   EXPECT_EQ(Expected, Actual.str());
Index: clang-tools-extra/clang-doc/MDGenerator.cpp
===================================================================
--- clang-tools-extra/clang-doc/MDGenerator.cpp
+++ clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -20,11 +20,11 @@
 
 // Markdown generation
 
-std::string genItalic(const Twine &Text) { return "*" + Text.str() + "*"; }
+static std::string genItalic(const Twine &Text) { return "*" + Text.str() + "*"; }
 
-std::string genEmphasis(const Twine &Text) { return "**" + Text.str() + "**"; }
+static std::string genEmphasis(const Twine &Text) { return "**" + Text.str() + "**"; }
 
-std::string genLink(const Twine &Text, const Twine &Link) {
+static std::string genLink(const Twine &Text, const Twine &Link) {
   return "[" + Text.str() + "](" + Link.str() + ")";
 }
 
@@ -92,7 +92,7 @@
   }
 }
 
-void genMarkdown(const EnumInfo &I, llvm::raw_ostream &OS) {
+static void genMarkdown(const EnumInfo &I, llvm::raw_ostream &OS) {
   if (I.Scoped)
     writeLine("| enum class " + I.Name + " |", OS);
   else
@@ -112,7 +112,7 @@
     writeDescription(C, OS);
 }
 
-void genMarkdown(const FunctionInfo &I, llvm::raw_ostream &OS) {
+static void genMarkdown(const FunctionInfo &I, llvm::raw_ostream &OS) {
   std::string Buffer;
   llvm::raw_string_ostream Stream(Buffer);
   bool First = true;
@@ -139,7 +139,7 @@
     writeDescription(C, OS);
 }
 
-void genMarkdown(const NamespaceInfo &I, llvm::raw_ostream &OS) {
+static void genMarkdown(const NamespaceInfo &I, llvm::raw_ostream &OS) {
   if (I.Name == "")
     writeHeader("Global Namespace", 1, OS);
   else
@@ -178,7 +178,7 @@
   }
 }
 
-void genMarkdown(const RecordInfo &I, llvm::raw_ostream &OS) {
+static void genMarkdown(const RecordInfo &I, llvm::raw_ostream &OS) {
   writeHeader(getTagType(I.TagType) + " " + I.Name, 1, OS);
   if (I.DefLoc)
     writeFileDefinition(I.DefLoc.getValue(), OS);
Index: clang-tools-extra/clang-doc/HTMLGenerator.cpp
===================================================================
--- clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -18,67 +18,300 @@
 namespace clang {
 namespace doc {
 
+namespace {
+
+class HTMLTag {
+public:
+  // Any other tag can be added if required
+  enum TagType {
+    TAG_META,
+    TAG_TITLE,
+    TAG_DIV,
+    TAG_H1,
+    TAG_H2,
+    TAG_H3,
+    TAG_P,
+    TAG_UL,
+    TAG_LI,
+  };
+
+  HTMLTag() = default;
+  constexpr HTMLTag(TagType Value) : Value(Value) {}
+
+  operator TagType() const { return Value; }
+  operator bool() = delete;
+
+  bool IsSelfClosing() const;
+
+  bool HasInlineChildren() const;
+
+  llvm::SmallString<16> ToString() const;
+
+private:
+  TagType Value;
+};
+
+struct HTMLNode {
+  virtual ~HTMLNode() = default;
+
+  virtual void Render(llvm::raw_ostream &OS, int IndentationLevel) = 0;
+};
+
+struct TextNode : public HTMLNode {
+  TextNode(llvm::StringRef Text, bool Indented)
+      : Text(Text), Indented(Indented) {}
+
+  std::string Text; // Content of node
+  bool Indented; // Indicates if an indentation must be rendered before the text
+  void Render(llvm::raw_ostream &OS, int IndentationLevel) override;
+};
+
+struct TagNode : public HTMLNode {
+  TagNode(HTMLTag Tag)
+      : Tag(Tag), InlineChildren(Tag.HasInlineChildren()),
+        SelfClosing(Tag.IsSelfClosing()) {}
+  TagNode(HTMLTag Tag, const Twine &Text) : TagNode(Tag) {
+    Children.emplace_back(
+        llvm::make_unique<TextNode>(Text.str(), !InlineChildren));
+  }
+
+  HTMLTag Tag;         // Name of HTML Tag (p, div, h1)
+  bool InlineChildren; // Indicates if children nodes are rendered in the same
+                       // line as itself or if children must rendered in the
+                       // next line and with additional indentation
+  bool SelfClosing;    // Indicates if tag is self-closing
+  std::vector<std::unique_ptr<HTMLNode>> Children; // List of child nodes
+  llvm::StringMap<llvm::SmallString<16>>
+      Attributes; // List of key-value attributes for tag
+
+  void Render(llvm::raw_ostream &OS, int IndentationLevel) override;
+};
+
+struct HTMLFile {
+  llvm::SmallString<16> DoctypeDecl{"<!DOCTYPE html>"};
+  std::vector<std::unique_ptr<HTMLNode>> Children; // List of child nodes
+  void Render(llvm::raw_ostream &OS) {
+    OS << DoctypeDecl << "\n";
+    for (const auto &C : Children) {
+      C->Render(OS, 0);
+      OS << "\n";
+    }
+  }
+};
+
+} // namespace
+
+bool HTMLTag::IsSelfClosing() const {
+  switch (Value) {
+  case HTMLTag::TAG_META:
+    return true;
+  case HTMLTag::TAG_TITLE:
+  case HTMLTag::TAG_DIV:
+  case HTMLTag::TAG_H1:
+  case HTMLTag::TAG_H2:
+  case HTMLTag::TAG_H3:
+  case HTMLTag::TAG_P:
+  case HTMLTag::TAG_UL:
+  case HTMLTag::TAG_LI:
+    return false;
+  }
+}
+
+bool HTMLTag::HasInlineChildren() const {
+  switch (Value) {
+  case HTMLTag::TAG_META:
+  case HTMLTag::TAG_TITLE:
+  case HTMLTag::TAG_H1:
+  case HTMLTag::TAG_H2:
+  case HTMLTag::TAG_H3:
+  case HTMLTag::TAG_LI:
+    return true;
+  case HTMLTag::TAG_DIV:
+  case HTMLTag::TAG_P:
+  case HTMLTag::TAG_UL:
+    return false;
+  }
+}
+
+llvm::SmallString<16> HTMLTag::ToString() const {
+  switch (Value) {
+  case HTMLTag::TAG_META:
+    return llvm::SmallString<16>("meta");
+  case HTMLTag::TAG_TITLE:
+    return llvm::SmallString<16>("title");
+  case HTMLTag::TAG_DIV:
+    return llvm::SmallString<16>("div");
+  case HTMLTag::TAG_H1:
+    return llvm::SmallString<16>("h1");
+  case HTMLTag::TAG_H2:
+    return llvm::SmallString<16>("h2");
+  case HTMLTag::TAG_H3:
+    return llvm::SmallString<16>("h3");
+  case HTMLTag::TAG_P:
+    return llvm::SmallString<16>("p");
+  case HTMLTag::TAG_UL:
+    return llvm::SmallString<16>("ul");
+  case HTMLTag::TAG_LI:
+    return llvm::SmallString<16>("li");
+  }
+}
+
+void TextNode::Render(llvm::raw_ostream &OS, int IndentationLevel) {
+  if (Indented)
+    OS.indent(IndentationLevel * 2);
+  OS << Text;
+}
+
+void TagNode::Render(llvm::raw_ostream &OS, int IndentationLevel) {
+  OS.indent(IndentationLevel * 2);
+  OS << "<" << Tag.ToString();
+  for (const auto &A : Attributes)
+    OS << " " << A.getKey() << "=\"" << A.getValue() << "\"";
+  OS << (SelfClosing ? "/>" : ">");
+  if (!InlineChildren)
+    OS << "\n";
+  int ChildrenIndentation = InlineChildren ? 0 : IndentationLevel + 1;
+  for (const auto &C : Children) {
+    C->Render(OS, ChildrenIndentation);
+    if (!InlineChildren)
+      OS << "\n";
+  }
+  if (!InlineChildren)
+    OS.indent(IndentationLevel * 2);
+  if (!SelfClosing)
+    OS << "</" << Tag.ToString() << ">";
+}
+
 // HTML generation
 
-std::string genTag(const Twine &Text, const Twine &Tag) {
-  return "<" + Tag.str() + ">" + Text.str() + "</" + Tag.str() + ">";
+static void genHTML(const EnumInfo &I, TagNode *N);
+static void genHTML(const FunctionInfo &I, TagNode *N);
+
+static void genEnumsBlock(const std::vector<EnumInfo> &Enums, TagNode *N) {
+  if (Enums.empty())
+    return;
+
+  N->Children.emplace_back(
+      llvm::make_unique<TagNode>(HTMLTag::TAG_H2, "Enums"));
+
+  auto EnumsBlock = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV);
+  for (const auto &E : Enums)
+    genHTML(E, EnumsBlock.get());
+  N->Children.push_back(std::move(EnumsBlock));
 }
 
-static void writeLine(const Twine &Text, raw_ostream &OS) {
-  OS << genTag(Text, "p") << "\n";
+static void
+genEnumMembersBlock(const llvm::SmallVector<SmallString<16>, 4> &Members,
+                    TagNode *N) {
+  if (Members.empty())
+    return;
+  auto List = llvm::make_unique<TagNode>(HTMLTag::TAG_UL);
+  for (const auto &M : Members)
+    List->Children.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_LI, M));
+  N->Children.push_back(std::move(List));
 }
 
-static void writeHeader(const Twine &Text, const Twine &Num, raw_ostream &OS) {
-  OS << genTag(Text, "h" + Num) << "\n";
+static void genFunctionsBlock(const std::vector<FunctionInfo> &Functions,
+                              TagNode *N) {
+  if (Functions.empty())
+    return;
+
+  N->Children.emplace_back(
+      llvm::make_unique<TagNode>(HTMLTag::TAG_H2, "Functions"));
+
+  auto FunctionsBlock = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV);
+  for (const auto &F : Functions)
+    genHTML(F, FunctionsBlock.get());
+  N->Children.push_back(std::move(FunctionsBlock));
 }
 
-static void writeFileDefinition(const Location &L, raw_ostream &OS) {
-  writeLine("Defined at line " + std::to_string(L.LineNumber) + " of " +
-                L.Filename,
-            OS);
+static void
+genRecordMembersBlock(const llvm::SmallVector<MemberTypeInfo, 4> &Members,
+                      TagNode *N) {
+  if (Members.empty())
+    return;
+
+  N->Children.emplace_back(
+      llvm::make_unique<TagNode>(HTMLTag::TAG_H2, "Members"));
+
+  auto List = llvm::make_unique<TagNode>(HTMLTag::TAG_UL);
+  for (const auto &M : Members) {
+    std::string Access = getAccess(M.Access);
+    if (Access != "")
+      Access = Access + " ";
+    List->Children.emplace_back(llvm::make_unique<TagNode>(
+        HTMLTag::TAG_LI, Access + M.Type.Name + " " + M.Name));
+  }
+  N->Children.push_back(std::move(List));
 }
 
-static void writeDescription(const CommentInfo &I, raw_ostream &OS) {
+static void genReferencesBlock(const std::vector<Reference> &References,
+                               llvm::StringRef Title, TagNode *N) {
+  if (References.empty())
+    return;
+
+  N->Children.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H2, Title));
+
+  auto List = llvm::make_unique<TagNode>(HTMLTag::TAG_UL);
+  for (const auto &R : References)
+    List->Children.emplace_back(
+        llvm::make_unique<TagNode>(HTMLTag::TAG_LI, R.Name));
+  N->Children.push_back(std::move(List));
+}
+
+static void writeFileDefinition(const Location &L, TagNode *N) {
+  N->Children.emplace_back(llvm::make_unique<TagNode>(
+      HTMLTag::TAG_P,
+      "Defined at line " + std::to_string(L.LineNumber) + " of " + L.Filename));
+}
+
+static void genHTML(const CommentInfo &I, TagNode *N) {
   if (I.Kind == "FullComment") {
+    auto FullComment = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV);
     for (const auto &Child : I.Children)
-      writeDescription(*Child, OS);
+      genHTML(*Child, FullComment.get());
+    N->Children.push_back(std::move(FullComment));
   } else if (I.Kind == "ParagraphComment") {
-    OS << "<p>";
+    auto ParagraphComment = llvm::make_unique<TagNode>(HTMLTag::TAG_P);
     for (const auto &Child : I.Children)
-      writeDescription(*Child, OS);
-    OS << "</p>\n";
+      genHTML(*Child, ParagraphComment.get());
+    if (!ParagraphComment->Children.empty())
+      N->Children.push_back(std::move(ParagraphComment));
   } else if (I.Kind == "TextComment") {
     if (I.Text != "")
-      OS << I.Text;
+      N->Children.emplace_back(llvm::make_unique<TextNode>(I.Text, true));
   }
 }
 
-void genHTML(const EnumInfo &I, llvm::raw_ostream &OS) {
+static void genHTML(const std::vector<CommentInfo> &C, TagNode *N) {
+  auto CommentBlock = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV);
+  for (const auto &Child : C)
+    genHTML(Child, CommentBlock.get());
+  N->Children.push_back(std::move(CommentBlock));
+}
+
+static void genHTML(const EnumInfo &I, TagNode *N) {
   std::string EnumType;
   if (I.Scoped)
     EnumType = "enum class ";
   else
     EnumType = "enum ";
-  writeHeader(EnumType + I.Name, "3", OS);
 
-  std::string Buffer;
-  llvm::raw_string_ostream Members(Buffer);
-  if (!I.Members.empty()) {
-    Members << "\n";
-    for (const auto &N : I.Members)
-      Members << genTag(N, "li") << "\n";
-    OS << genTag(Members.str(), "ul") << "\n";
-  }
+  N->Children.emplace_back(
+      llvm::make_unique<TagNode>(HTMLTag::TAG_H3, EnumType + I.Name));
+
+  genEnumMembersBlock(I.Members, N);
 
   if (I.DefLoc)
-    writeFileDefinition(I.DefLoc.getValue(), OS);
+    writeFileDefinition(I.DefLoc.getValue(), N);
 
-  for (const auto &C : I.Description)
-    writeDescription(C, OS);
+  std::string Description;
+  if (!I.Description.empty())
+    genHTML(I.Description, N);
 }
 
-void genHTML(const FunctionInfo &I, llvm::raw_ostream &OS) {
-  writeHeader(I.Name, "3", OS);
+static void genHTML(const FunctionInfo &I, TagNode *N) {
+  N->Children.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H3, I.Name));
 
   std::string Buffer;
   llvm::raw_string_ostream Stream(Buffer);
@@ -87,101 +320,75 @@
       Stream << ", ";
     Stream << P.Type.Name + " " + P.Name;
   }
+
   std::string Access = getAccess(I.Access);
   if (Access != "")
-    writeLine(Access + " " + I.ReturnType.Type.Name + " " + I.Name + "(" +
-                  Stream.str() + ")",
-              OS);
-  else
-    writeLine(I.ReturnType.Type.Name + " " + I.Name + "(" + Stream.str() + ")",
-              OS);
+    Access = Access + " ";
+
+  N->Children.emplace_back(llvm::make_unique<TagNode>(
+      HTMLTag::TAG_P, Access + I.ReturnType.Type.Name + " " + I.Name + "(" +
+                          Stream.str() + ")"));
+
   if (I.DefLoc)
-    writeFileDefinition(I.DefLoc.getValue(), OS);
+    writeFileDefinition(I.DefLoc.getValue(), N);
 
-  for (const auto &C : I.Description)
-    writeDescription(C, OS);
+  std::string Description;
+  if (!I.Description.empty())
+    genHTML(I.Description, N);
 }
 
-void genHTML(const NamespaceInfo &I, llvm::raw_ostream &OS) {
-  if (I.Name == "")
-    writeHeader("Global Namespace", "1", OS);
+static void genHTML(const NamespaceInfo &I, TagNode *N,
+                    std::string &InfoTitle) {
+  if (I.Name.str() == "")
+    InfoTitle = "Global Namespace";
   else
-    writeHeader("namespace " + I.Name, "1", OS);
+    InfoTitle = ("namespace " + I.Name).str();
 
-  if (!I.Description.empty()) {
-    for (const auto &C : I.Description)
-      writeDescription(C, OS);
-  }
+  N->Children.emplace_back(
+      llvm::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
 
-  if (!I.ChildNamespaces.empty()) {
-    writeHeader("Namespaces", "2", OS);
-    for (const auto &R : I.ChildNamespaces)
-      writeLine(R.Name, OS);
-  }
-  if (!I.ChildRecords.empty()) {
-    writeHeader("Records", "2", OS);
-    for (const auto &R : I.ChildRecords)
-      writeLine(R.Name, OS);
-  }
-  if (!I.ChildFunctions.empty()) {
-    writeHeader("Functions", "2", OS);
-    for (const auto &F : I.ChildFunctions)
-      genHTML(F, OS);
-  }
-  if (!I.ChildEnums.empty()) {
-    writeHeader("Enums", "2", OS);
-    for (const auto &E : I.ChildEnums)
-      genHTML(E, OS);
-  }
+  std::string Description;
+  if (!I.Description.empty())
+    genHTML(I.Description, N);
+
+  genReferencesBlock(I.ChildNamespaces, "Namespaces", N);
+  genReferencesBlock(I.ChildRecords, "Records", N);
+
+  genFunctionsBlock(I.ChildFunctions, N);
+  genEnumsBlock(I.ChildEnums, N);
 }
 
-void genHTML(const RecordInfo &I, llvm::raw_ostream &OS) {
-  writeHeader(getTagType(I.TagType) + " " + I.Name, "1", OS);
+static void genHTML(const RecordInfo &I, TagNode *N, std::string &InfoTitle) {
+  InfoTitle = (getTagType(I.TagType) + " " + I.Name).str();
+  N->Children.emplace_back(
+      llvm::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
+
   if (I.DefLoc)
-    writeFileDefinition(I.DefLoc.getValue(), OS);
+    writeFileDefinition(I.DefLoc.getValue(), N);
 
-  if (!I.Description.empty()) {
-    for (const auto &C : I.Description)
-      writeDescription(C, OS);
-  }
+  std::string Description;
+  if (!I.Description.empty())
+    genHTML(I.Description, N);
 
   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);
+      N->Children.emplace_back(llvm::make_unique<TagNode>(
+          HTMLTag::TAG_P, "Inherits from " + VParents));
     else if (VParents.empty())
-      writeLine("Inherits from " + Parents, OS);
+      N->Children.emplace_back(llvm::make_unique<TagNode>(
+          HTMLTag::TAG_P, "Inherits from " + Parents));
     else
-      writeLine("Inherits from " + Parents + ", " + VParents, OS);
+      N->Children.emplace_back(llvm::make_unique<TagNode>(
+          HTMLTag::TAG_P, "Inherits from " + Parents + ", " + VParents));
   }
 
-  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);
-    }
-  }
+  genRecordMembersBlock(I.Members, N);
+  genReferencesBlock(I.ChildRecords, "Records", N);
 
-  if (!I.ChildRecords.empty()) {
-    writeHeader("Records", "2", OS);
-    for (const auto &R : I.ChildRecords)
-      writeLine(R.Name, OS);
-  }
-  if (!I.ChildFunctions.empty()) {
-    writeHeader("Functions", "2", OS);
-    for (const auto &F : I.ChildFunctions)
-      genHTML(F, OS);
-  }
-  if (!I.ChildEnums.empty()) {
-    writeHeader("Enums", "2", OS);
-    for (const auto &E : I.ChildEnums)
-      genHTML(E, OS);
-  }
+  genFunctionsBlock(I.ChildFunctions, N);
+  genEnumsBlock(I.ChildEnums, N);
 }
 
 /// Generator for HTML documentation.
@@ -195,31 +402,50 @@
 const char *HTMLGenerator::Format = "html";
 
 llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
+  HTMLFile F;
+
+  auto MetaNode = llvm::make_unique<TagNode>(HTMLTag::TAG_META);
+  MetaNode->Attributes.try_emplace("charset", "utf-8");
+  F.Children.push_back(std::move(MetaNode));
+
+  std::string InfoTitle;
+
+  auto MainContentNode = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV);
+
   switch (I->IT) {
   case InfoType::IT_namespace:
-    genHTML(*static_cast<clang::doc::NamespaceInfo *>(I), OS);
+    genHTML(*static_cast<clang::doc::NamespaceInfo *>(I), MainContentNode.get(),
+            InfoTitle);
     break;
   case InfoType::IT_record:
-    genHTML(*static_cast<clang::doc::RecordInfo *>(I), OS);
+    genHTML(*static_cast<clang::doc::RecordInfo *>(I), MainContentNode.get(),
+            InfoTitle);
     break;
   case InfoType::IT_enum:
-    genHTML(*static_cast<clang::doc::EnumInfo *>(I), OS);
+    genHTML(*static_cast<clang::doc::EnumInfo *>(I), MainContentNode.get());
     break;
   case InfoType::IT_function:
-    genHTML(*static_cast<clang::doc::FunctionInfo *>(I), OS);
+    genHTML(*static_cast<clang::doc::FunctionInfo *>(I), MainContentNode.get());
     break;
   case InfoType::IT_default:
     return llvm::make_error<llvm::StringError>("Unexpected info type.\n",
                                                llvm::inconvertibleErrorCode());
   }
+
+  F.Children.emplace_back(
+      llvm::make_unique<TagNode>(HTMLTag::TAG_TITLE, InfoTitle));
+  F.Children.push_back(std::move(MainContentNode));
+
+  F.Render(OS);
+
   return llvm::Error::success();
 }
 
 static GeneratorRegistry::Add<HTMLGenerator> HTML(HTMLGenerator::Format,
                                                   "Generator for HTML output.");
 
-// This anchor is used to force the linker to link in the generated object file
-// and thus register the generator.
+// This anchor is used to force the linker to link in the generated object
+// file and thus register the generator.
 volatile int HTMLGeneratorAnchorSource = 0;
 
 } // namespace doc
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to