DiegoAstiazaran updated this revision to Diff 206103.
DiegoAstiazaran marked 4 inline comments as done.
DiegoAstiazaran added a comment.

Add FIXME comments for llvm::SmallString to std::string transition.
Add check so ParagraphComment template is not generated if its content would be 
empty.
Fix the VerbatimBlockComment template, open/close commands shouldn't be 
rendered.
Remove empty assignments in string declarations.


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

https://reviews.llvm.org/D63666

Files:
  clang-tools-extra/clang-doc/CMakeLists.txt
  clang-tools-extra/clang-doc/HTMLGenerator.cpp
  clang-tools-extra/clang-doc/HTMLTemplates.cpp
  clang-tools-extra/clang-doc/HTMLTemplates.h
  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,23 +40,25 @@
   llvm::raw_string_ostream Actual(Buffer);
   auto Err = G->generateDocForInfo(&I, Actual);
   assert(!Err);
-  std::string Expected = R"raw(<h1>namespace Namespace</h1>
-<br>
+  std::string Expected = R"raw(<!DOCTYPE html>
+<meta charset="utf-8">
+<title>namespace Namespace</title>
+<div>
+<h1>namespace Namespace</h1>
 <h2>Namespaces</h2>
-<p>ChildNamespace</p>
-<br>
+<li>ChildNamespace</li>
 <h2>Records</h2>
-<p>ChildStruct</p>
-<br>
+<li>ChildStruct</li>
 <h2>Functions</h2>
+<div>
 <h3>OneFunction</h3>
-<p><em> OneFunction()</em></p>
-<br>
+<p> OneFunction()</p>
+</div>
 <h2>Enums</h2>
-<p>| enum OneEnum |</p>
-<p>--</p>
-<p></p>
-<br>
+<div>
+<h3>enum OneEnum</h3>
+</div>
+</div>
 )raw";
 
   EXPECT_EQ(Expected, Actual.str());
@@ -87,25 +89,29 @@
   llvm::raw_string_ostream Actual(Buffer);
   auto Err = G->generateDocForInfo(&I, Actual);
   assert(!Err);
-  std::string Expected = R"raw(<h1>class r</h1>
-<p><em>Defined at line 10 of test.cpp</em></p>
+  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>
-<br>
 <h2>Members</h2>
-<p>private int X</p>
-<br>
+<ul>
+<li>private int X</li>
+</ul>
 <h2>Records</h2>
-<p>ChildStruct</p>
-<br>
+<li>ChildStruct</li>
 <h2>Functions</h2>
+<div>
 <h3>OneFunction</h3>
-<p><em> OneFunction()</em></p>
-<br>
+<p> OneFunction()</p>
+</div>
 <h2>Enums</h2>
-<p>| enum OneEnum |</p>
-<p>--</p>
-<p></p>
-<br>
+<div>
+<h3>enum OneEnum</h3>
+</div>
+</div>
 )raw";
 
   EXPECT_EQ(Expected, Actual.str());
@@ -130,9 +136,16 @@
   llvm::raw_string_ostream Actual(Buffer);
   auto Err = G->generateDocForInfo(&I, Actual);
   assert(!Err);
-  std::string Expected = R"raw(<h3>f</h3>
-<p><em>void f(int P)</em></p>
-<p><em>Defined at line 10 of test.cpp</em></p>
+  std::string Expected = R"raw(<!DOCTYPE html>
+<meta charset="utf-8">
+<title></title>
+<div>
+<div>
+<h3>f</h3>
+<p>void f(int P)</p>
+<p>Defined at line 10 of test.cpp</p>
+</div>
+</div>
 )raw";
 
   EXPECT_EQ(Expected, Actual.str());
@@ -155,11 +168,18 @@
   llvm::raw_string_ostream Actual(Buffer);
   auto Err = G->generateDocForInfo(&I, Actual);
   assert(!Err);
-  std::string Expected = R"raw(<p>| enum class e |</p>
-<p>--</p>
-<p>| X |
-</p>
-<p><em>Defined at line 10 of test.cpp</em></p>
+  std::string Expected = R"raw(<!DOCTYPE html>
+<meta charset="utf-8">
+<title></title>
+<div>
+<div>
+<h3>enum class e</h3>
+<ul>
+<li>X</li>
+</ul>
+<p>Defined at line 10 of test.cpp</p>
+</div>
+</div>
 )raw";
 
   EXPECT_EQ(Expected, Actual.str());
@@ -281,22 +301,33 @@
   llvm::raw_string_ostream Actual(Buffer);
   auto Err = G->generateDocForInfo(&I, Actual);
   assert(!Err);
-  std::string Expected = R"raw(<h3>f</h3>
-<p><em>void f(int I, int J)</em></p>
-<p><em>Defined at line 10 of test.cpp</em></p>
-<br>
- Brief description.<br>
- Extended description that continues onto the next line.<br>
-<p><ul "class=test"></p>
-<p><li></p>
- Testing.<p></ul></p>
-<br>
- The description continues.<br>
-<strong>I</strong> [out]
-
-<strong>J</strong>
-
-<strong>return</strong>void<br>
+  std::string Expected = R"raw(<!DOCTYPE html>
+<meta charset="utf-8">
+<title></title>
+<div>
+<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>
+<p><ul "class=test"><li> Testing.</ul></p>
+<div>
+<p> The description continues.</p>
+</div>
+<div>
+<em>I</em> [out] <p> is a parameter.</p>
+</div>
+<div>
+<em>J</em> <p> is a parameter.</p>
+</div>
+<em>return</em> <p>void</p>
+</div>
+</div>
+</div>
+</div>
 )raw";
 
   EXPECT_EQ(Expected, Actual.str());
Index: clang-tools-extra/clang-doc/HTMLTemplates.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-doc/HTMLTemplates.h
@@ -0,0 +1,61 @@
+///===-- HTMLTemplates.h - ClangDoc Representation --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the HTML templates used to generate HTML documentation
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_HTMLTEMPLATES_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_HTMLTEMPLATES_H
+
+#include <string>
+
+namespace clang {
+namespace doc {
+
+struct HTMLTemplates {
+    static const char *NamespaceBlock;
+    static const char *RecordBlock;
+    static const char *CommentBlock;
+    static const char *FunctionBlock;
+    static const char *EnumBlock;
+    static const char *TopLevelInfoHeader;
+    static const char *RecordInfoName;
+    static const char *NamespaceInfoName;
+    static const char *GlobalNamespaceName;
+    static const char *HeaderDataBlock;
+    static const char *FileDefinition;
+    static const char *RecordInheritance;
+    static const char *FunctionEnumHeader;
+    static const char *EnumInfoName;
+    static const char *FunctionDefHeader;
+    static const char *SectionHeader;
+    static const char *BlockList;
+    static const char *BlockItem;
+    static const char *RecordMemberContent;
+    static const char *FullComment;
+    static const char *ParagraphComment;
+    static const char *BlockCommandComment;
+    static const char *InlineCommandComment;
+    static const char *ParamCommandComment;
+    static const char *TParamCommandComment;
+    static const char *VerbatimBlockComment;
+    static const char *VerbatimBlockLineComment;
+    static const char *VerbatimLineComment;
+    static const char *HTMLStartTagAttribute;
+    static const char *HTMLStartTagComment;
+    static const char *HTMLEndTagComment;
+    static const char *UnknownComment;
+    static const char *HTMLDoc;
+    static const char *MainContent;
+};
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_HTMLTEMPLATES_H
Index: clang-tools-extra/clang-doc/HTMLTemplates.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-doc/HTMLTemplates.cpp
@@ -0,0 +1,209 @@
+///===-- HTMLTemplates.cpp - ClangDoc Representation ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "HTMLTemplates.h"
+
+namespace clang {
+namespace doc {
+
+// Used for NamespaceInfo
+// - Main header (string), use TopLevelInfoHeader template
+// - Description (string), use CommentBlock template or empty string
+// - ChildNamespaces (string), use HeaderDataBlock or empty string
+// - ChildRecords (string), use HeaderDataBlock or empty string
+// - ChildFunctions (string), use HeaderDataBlock or empty string
+// - ChildEnums (string), use HeaderDataBlock or empty string
+const char *HTMLTemplates::NamespaceBlock = "%s%s%s%s%s%s";
+
+// Used for RecordInfo
+// - Main header (string), use TopLevelInfoHeader template
+// - Definition Location (string), use FileDefinition template or empty string
+// - Description (string), use CommentBlock template or empty string
+// - Parents (string), use RecordInheritance template or empty string
+// - Members (string), use HeaderDataBlock template or empty string
+// - ChildRecords (string), use HeaderDataBlock or empty string
+// - ChildFunctions (string), use HeaderDataBlock or empty string
+// - ChildEnums (string), use HeaderDataBlock or empty string
+const char *HTMLTemplates::RecordBlock = "%s%s%s%s%s%s%s%s";
+
+// Used for CommentInfo
+// - CommentInfo content (string), use the concatenation of multiple Comment
+// templates
+const char *HTMLTemplates::CommentBlock = "<div>\n%s</div>\n";
+
+// Used for FunctionInfo
+// - Main header (string), use FunctionEnumHeader template
+// - Function header (string), use FunctionDefHeader template
+// - Definition Location (string), use FileDefinition template or empty string
+// - Description (string), use CommentBlock template or empty string
+const char *HTMLTemplates::FunctionBlock = "<div>\n%s%s%s%s</div>\n";
+
+// Used for EnumInfo
+// - Main header (string), use FunctionEnumHeader template
+// - Members (string), use BlockList template or empty string
+// - Definition Location (string), use FileDefinition template or empty string
+// - Description (string), use CommentBlock template or empty string
+const char *HTMLTemplates::EnumBlock = "<div>\n%s%s%s%s</div>\n";
+
+// Used for the header of a top level Info (namespace or record)
+// - Content of header (string), use RecordInfoName, NamespaceInfoName, or
+// GlobalNamespaceName template
+const char *HTMLTemplates::TopLevelInfoHeader = "<h1>%s</h1>\n";
+
+// Used for the title of a RecordInfo
+// - Tag type (string), use any return value of getTagType()
+// - Record name (string), use Name attribute of Info
+const char *HTMLTemplates::RecordInfoName = "%s %s";
+
+// Used for the title of a NamespaceInfo
+// - Namespace name (string), use Name attribute of Info
+const char *HTMLTemplates::NamespaceInfoName = "namespace %s";
+
+// Constant to be used as the title of the global namespace
+const char *HTMLTemplates::GlobalNamespaceName = "Global Namespace";
+
+// Used for a block that contains a header and data
+// - Header (string), use SectionHeader template
+// - Data (string), use BlockList template
+const char *HTMLTemplates::HeaderDataBlock = "%s%s";
+
+// Used for the definition location of an Info
+// - Line number (integer), use LineNumber attribute of a Location object
+// - File name (string), use Filename attribute of a Location object
+const char *HTMLTemplates::FileDefinition = "<p>Defined at line %d of %s</p>\n";
+
+// Used for the inheritance of a RecordInfo
+// - Parents (string), use return value of genReferenceList()
+const char *HTMLTemplates::RecordInheritance = "<p>Inherits from %s</p>\n";
+
+// Used for the header of a FunctionInfo or EnumInfo
+// - Content of header (string), use EnumInfoName template if Info is an Enum
+// and Name attribute of Info if it a Function
+const char *HTMLTemplates::FunctionEnumHeader = "<h3>%s</h3>\n";
+
+// Used for the title of a EnumInfo
+// - Enum type (string), use "enum class" or "enum"
+// - Enum name (string), use Name attribute of Info
+const char *HTMLTemplates::EnumInfoName = "%s %s";
+
+// Used for the header of a FunctionInfo
+// - Access level (string), use return value of getAccess() with an appended
+// space at the end or an empty string
+// - Return type (string), use .ReturnType.Type.Name of Function
+// - Function name (string), use Name attribute of Info
+// - Parameters (string), use list of parameters that includes type and name
+const char *HTMLTemplates::FunctionDefHeader = "<p>%s%s %s(%s)</p>\n";
+
+// Used for the header of record's members and child namespaces, records,
+// functions, enums
+// - Content of header (string), use "Members", "Namespaces", "Records",
+// "Functions", or "Enums"
+const char *HTMLTemplates::SectionHeader = "<h2>%s</h2>\n";
+
+// Used to generate an unlisted list
+// - Items (string), use concatenation of BlockItem templates
+const char *HTMLTemplates::BlockList = "<ul>\n%s</ul>\n";
+
+// Used to generate a list item
+// - Content (string)
+const char *HTMLTemplates::BlockItem = "<li>%s</li>\n";
+
+// Used for a member of a RecordInfo
+// - Access level (string), use return value of getAccess() with an appended
+// space at the end or an empty string
+// - Member type (string), use .Type.Name of Member
+// - Member name (string), use Name attribute of Member
+const char *HTMLTemplates::RecordMemberContent = "%s%s %s";
+
+// Used for FullComment CommentInfo
+// - Content of comment (string), use concatenated return value of genHTML() for
+// each child of Info
+const char *HTMLTemplates::FullComment = "<div>\n%s</div>\n";
+
+// Used for ParagraphComment CommentInfo
+// - Content of comment (string), use concatenated return value of genHTML() for
+// each child of Info
+const char *HTMLTemplates::ParagraphComment = "<p>%s</p>\n";
+
+// Used for BlockCommandComment CommentInfo
+// - Argument (string), use Name attribute of Info
+// - Content of comment (string), use concatenated return value of genHTML() for
+// each child of Info
+const char *HTMLTemplates::BlockCommandComment = "<em>%s</em> %s";
+
+// Used for InlineCommandComment CommentInfo
+// - Argument (string), use Name attribute of Info
+// - Content of comment (string), use Text attribute of Info
+const char *HTMLTemplates::InlineCommandComment = "<em>%s</em> %s";
+
+// Used for ParamCommandComment CommentInfo
+// - Param name (string), use ParamName attribute of Info
+// - Direction (string), use Direction attribute of Info with an appended space
+// at the end or empty string
+// - Content of comment (string), use concatenated return value of genHTML() for
+// each child of Info
+const char *HTMLTemplates::ParamCommandComment =
+    "<div>\n<em>%s</em>%s %s</div>\n";
+
+// Used for ParamCommandComment CommentInfo
+// - Param name (string), use ParamName attribute of Info
+// - Direction (string), use Direction attribute of Info with an appended space
+// at the end or empty string
+// - Content of comment (string), use concatenated return value of genHTML() for
+// each child of Info
+const char *HTMLTemplates::TParamCommandComment =
+    "<div>\n<em>%s</em>%s %s</div>\n";
+
+// Used for VerbatimBlockComment CommentInfo
+// - Content of comment (string), use concatenated return value of genHTML() for
+// each child of Info
+const char *HTMLTemplates::VerbatimBlockComment = "<div>\n%s</div>\n";
+
+// Used for VerbatimBlockLineComment CommentInfo
+// - Content of comment (string), use Text attribute of Info
+const char *HTMLTemplates::VerbatimBlockLineComment = "<p>%s</p>\n";
+
+// Used for VerbatimBlockLineComment CommentInfo
+// - Content of comment (string), use Text attribute of Info
+const char *HTMLTemplates::VerbatimLineComment = "<div>%s</div>\n";
+
+// Used for an attribute of an opening HTML tag
+// - Key (string), use an element of the AttrKeys attribute of Info
+// - Value (string), use an element of the AttrValues attribute of Info
+const char *HTMLTemplates::HTMLStartTagAttribute = " \"%s=%s\"";
+
+// Use for HTMLStartTagComment CommentInfo
+// - Name of tag (string), use Name attribute of Info
+// - Attributes of tag (string), use concatenation of HTMLStartTagAttribute
+// templates
+// - CloseTag (string), use ">" or "/>"
+const char *HTMLTemplates::HTMLStartTagComment = "<%s%s%s";
+
+// Use for HTMLEndTagComment CommentInfo
+// - Name of tag (string), use Name attribute of Info
+const char *HTMLTemplates::HTMLEndTagComment = "</%s>";
+
+// Use for unexpected kind of CommentInfo
+const char *HTMLTemplates::UnknownComment =
+    "<p>Unknown comment kind: %s.</p>\n";
+
+// Used for the complete HTML file to be generated.
+// - Page title (string)
+// - Page main content (string)
+const char *HTMLTemplates::HTMLDoc = R"raw(<!DOCTYPE html>
+<meta charset="utf-8">
+<title>%s</title>
+%s)raw";
+
+// Used for the main content of the page, the top level Info's documentation.
+// Navbar, footer, index should not be included.
+// - Top level info (string)
+const char *HTMLTemplates::MainContent = "<div>\n%s</div>\n";
+
+} // namespace doc
+} // namespace clang
Index: clang-tools-extra/clang-doc/HTMLGenerator.cpp
===================================================================
--- clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -7,10 +7,12 @@
 //===----------------------------------------------------------------------===//
 
 #include "Generators.h"
+#include "HTMLTemplates.h"
 #include "Representation.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
+#include <stdio.h>
 #include <string>
 
 using namespace llvm;
@@ -18,105 +20,237 @@
 namespace clang {
 namespace doc {
 
-namespace {
+std::string genHTML(const EnumInfo &I);
+std::string genHTML(const FunctionInfo &I);
 
-// HTML generation
-
-std::string genTag(const Twine &Text, const Twine &Tag) {
-  return "<" + Tag.str() + ">" + Text.str() + "</" + Tag.str() + ">";
+template <typename... Args>
+char *applyHTMLTemplate(const char *Template, Args... TemplateArguments) {
+  // Get the buffer size required
+  int Size = snprintf(NULL, 0, Template, TemplateArguments...);
+  char *Output = new char[Size + 1];
+  sprintf(Output, Template, TemplateArguments...);
+  return std::move(Output);
 }
 
-std::string genItalic(const Twine &Text) { return genTag(Text, "em"); }
+std::string genEnumsBlock(const std::vector<EnumInfo> &Children) {
+  std::string Output;
+  if (!Children.empty()) {
+    std::string Header =
+        applyHTMLTemplate(HTMLTemplates::SectionHeader, "Enums");
+    std::string Items;
+    for (const auto &C : Children) {
+      Items += genHTML(C);
+    }
+    std::string List =
+        applyHTMLTemplate(HTMLTemplates::BlockList, Items.c_str());
+    Output = applyHTMLTemplate(HTMLTemplates::HeaderDataBlock, Header.c_str(),
+                               Items.c_str());
+  }
+  return Output;
+}
 
-std::string genEmphasis(const Twine &Text) { return genTag(Text, "strong"); }
+std::string
+genEnumMembersBlock(const llvm::SmallVector<SmallString<16>, 4> &Members) {
+  std::string Output;
+  if (!Members.empty()) {
+    std::string Items;
+    for (const auto &M : Members) {
+      // FIXME: Transition EnumInfos's Members from llvm::SmallString to
+      // std::string
+      Items +=
+          applyHTMLTemplate(HTMLTemplates::BlockItem, M.str().str().c_str());
+    }
+    Output = applyHTMLTemplate(HTMLTemplates::BlockList, Items.c_str());
+  }
+  return Output;
+}
 
-void writeLine(const Twine &Text, raw_ostream &OS) {
-  OS << genTag(Text, "p") << "\n";
+std::string genFunctionsBlock(const std::vector<FunctionInfo> &Children) {
+  std::string Output;
+  if (!Children.empty()) {
+    std::string Header =
+        applyHTMLTemplate(HTMLTemplates::SectionHeader, "Functions");
+    std::string Items;
+    for (const auto &C : Children) {
+      Items += genHTML(C);
+    }
+    std::string List =
+        applyHTMLTemplate(HTMLTemplates::BlockList, Items.c_str());
+    Output = applyHTMLTemplate(HTMLTemplates::HeaderDataBlock, Header.c_str(),
+                               Items.c_str());
+  }
+  return Output;
 }
 
-void writeNewLine(raw_ostream &OS) { OS << "<br>\n"; }
+std::string
+genRecordMembersBlock(const llvm::SmallVector<MemberTypeInfo, 4> &Members) {
+  std::string Output;
+  if (!Members.empty()) {
+    std::string Header =
+        applyHTMLTemplate(HTMLTemplates::SectionHeader, "Members");
+    std::string Items;
+    for (const auto &M : Members) {
+      std::string Access = getAccess(M.Access);
+      if (Access != "")
+        Access = Access + " ";
+      // FIXME: Transition Reference's Name from llvm::SmallString to
+      // std::string
+      // FIXME: Transition FieldTypeInfo's Name from llvm::SmallString to
+      // std::string
+      std::string Content = applyHTMLTemplate(
+          HTMLTemplates::RecordMemberContent, Access.c_str(),
+          M.Type.Name.str().str().c_str(), M.Name.str().str().c_str());
+      Items += applyHTMLTemplate(HTMLTemplates::BlockItem, Content.c_str());
+    }
+    std::string List =
+        applyHTMLTemplate(HTMLTemplates::BlockList, Items.c_str());
+    Output = applyHTMLTemplate(HTMLTemplates::HeaderDataBlock, Header.c_str(),
+                               List.c_str());
+  }
+  return Output;
+}
 
-void writeHeader(const Twine &Text, const Twine &Num, raw_ostream &OS) {
-  OS << genTag(Text, "h" + Num) << "\n";
+std::string genReferencesBlock(const std::vector<Reference> &References,
+                               const char *Title) {
+  std::string Output;
+  if (!References.empty()) {
+    std::string Header = applyHTMLTemplate(HTMLTemplates::SectionHeader, Title);
+    std::string Items;
+    for (const auto &R : References) {
+      Items += applyHTMLTemplate(HTMLTemplates::BlockItem,
+                                 R.Name.str().str().c_str());
+      ;
+    }
+    std::string List =
+        applyHTMLTemplate(HTMLTemplates::BlockList, Items.c_str());
+    Output = applyHTMLTemplate(HTMLTemplates::HeaderDataBlock, Header.c_str(),
+                               Items.c_str());
+  }
+  return Output;
 }
 
-void writeFileDefinition(const Location &L, raw_ostream &OS) {
-  writeLine(genItalic("Defined at line " + std::to_string(L.LineNumber) +
-                      " of " + L.Filename),
-            OS);
+std::string writeFileDefinition(const Location &L) {
+  // FIXME: Transition Location's Filename from llvm::SmallString to std::string
+  return applyHTMLTemplate(HTMLTemplates::FileDefinition, L.LineNumber,
+                           L.Filename.str().str().c_str());
 }
 
-void writeDescription(const CommentInfo &I, raw_ostream &OS) {
+std::string genHTML(const CommentInfo &I) {
   if (I.Kind == "FullComment") {
+    std::string Output;
     for (const auto &Child : I.Children)
-      writeDescription(*Child, OS);
+      Output += genHTML(*Child);
+    return applyHTMLTemplate(HTMLTemplates::FullComment, Output.c_str());
   } else if (I.Kind == "ParagraphComment") {
+    std::string Output;
     for (const auto &Child : I.Children)
-      writeDescription(*Child, OS);
-    writeNewLine(OS);
+      Output += genHTML(*Child);
+    if (Output == "")
+      return {};
+    return applyHTMLTemplate(HTMLTemplates::ParagraphComment, Output.c_str());
   } else if (I.Kind == "BlockCommandComment") {
-    OS << genEmphasis(I.Name);
+    std::string Output;
     for (const auto &Child : I.Children)
-      writeDescription(*Child, OS);
+      Output += genHTML(*Child);
+    // FIXME: Transition CommentInfo's Name from llvm::SmallString to
+    // std::string
+    return applyHTMLTemplate(HTMLTemplates::BlockCommandComment,
+                             I.Name.str().str().c_str(), Output.c_str());
   } else if (I.Kind == "InlineCommandComment") {
-    OS << genEmphasis(I.Name) << " " << I.Text;
+    // FIXME: Transition CommentInfo's Text from llvm::SmallString to
+    // std::string
+    return applyHTMLTemplate(HTMLTemplates::InlineCommandComment,
+                             I.Name.str().str().c_str(),
+                             I.Text.str().str().c_str());
   } else if (I.Kind == "ParamCommandComment") {
     std::string Direction = I.Explicit ? (" " + I.Direction).str() : "";
-    OS << genEmphasis(I.ParamName) << I.Text << Direction << "\n\n";
+    std::string Output;
+    for (const auto &Child : I.Children)
+      Output += genHTML(*Child);
+    // FIXME: Transition CommentInfo's ParamName from llvm::SmallString to
+    // std::string
+    return applyHTMLTemplate(HTMLTemplates::ParamCommandComment,
+                             I.ParamName.str().str().c_str(), Direction.c_str(),
+                             Output.c_str());
   } else if (I.Kind == "TParamCommandComment") {
     std::string Direction = I.Explicit ? (" " + I.Direction).str() : "";
-    OS << genEmphasis(I.ParamName) << I.Text << Direction << "\n\n";
+    std::string Output;
+    for (const auto &Child : I.Children)
+      Output += genHTML(*Child);
+    return applyHTMLTemplate(HTMLTemplates::TParamCommandComment,
+                             I.ParamName.str().str().c_str(), Direction.c_str(),
+                             Output.c_str());
   } else if (I.Kind == "VerbatimBlockComment") {
+    std::string Output;
     for (const auto &Child : I.Children)
-      writeDescription(*Child, OS);
+      Output += genHTML(*Child);
+    return applyHTMLTemplate(HTMLTemplates::VerbatimBlockComment,
+                             Output.c_str());
   } else if (I.Kind == "VerbatimBlockLineComment") {
-    OS << I.Text;
-    writeNewLine(OS);
+    return applyHTMLTemplate(HTMLTemplates::VerbatimBlockLineComment,
+                             I.Text.str().str().c_str());
   } else if (I.Kind == "VerbatimLineComment") {
-    OS << I.Text;
-    writeNewLine(OS);
+    return applyHTMLTemplate(HTMLTemplates::VerbatimLineComment,
+                             I.Text.str().str().c_str());
   } else if (I.Kind == "HTMLStartTagComment") {
     if (I.AttrKeys.size() != I.AttrValues.size())
-      return;
-    std::string Buffer;
-    llvm::raw_string_ostream Attrs(Buffer);
+      return {};
+    std::string Attrs;
     for (unsigned Idx = 0; Idx < I.AttrKeys.size(); ++Idx)
-      Attrs << " \"" << I.AttrKeys[Idx] << "=" << I.AttrValues[Idx] << "\"";
-
+      // FIXME: Transition CommentInfo's AttrKeys and AttrValues from
+      // llvm::SmallString to std::string
+      Attrs += applyHTMLTemplate(HTMLTemplates::HTMLStartTagAttribute,
+                                 I.AttrKeys[Idx].str().str().c_str(),
+                                 I.AttrValues[Idx].str().str().c_str());
     std::string CloseTag = I.SelfClosing ? "/>" : ">";
-    writeLine("<" + I.Name + Attrs.str() + CloseTag, OS);
+    return applyHTMLTemplate(HTMLTemplates::HTMLStartTagComment,
+                             I.Name.str().str().c_str(), Attrs.c_str(),
+                             CloseTag.c_str());
   } else if (I.Kind == "HTMLEndTagComment") {
-    writeLine("</" + I.Name + ">", OS);
+    return applyHTMLTemplate(HTMLTemplates::HTMLEndTagComment,
+                             I.Name.str().str().c_str());
   } else if (I.Kind == "TextComment") {
-    OS << I.Text;
+    return I.Text.str();
   } else {
-    OS << "Unknown comment kind: " << I.Kind << ".\n\n";
+    // FIXME: Transition CommentInfo's Kind from llvm::SmallString to
+    // std::string
+    return applyHTMLTemplate(HTMLTemplates::UnknownComment,
+                             I.Kind.str().str().c_str());
   }
 }
 
-} // namespace
-
-void genHTML(const EnumInfo &I, llvm::raw_ostream &OS) {
+std::string genHTML(const EnumInfo &I) {
+  std::string EnumType;
   if (I.Scoped)
-    writeLine("| enum class " + I.Name + " |", OS);
+    EnumType = "enum class";
   else
-    writeLine("| enum " + I.Name + " |", OS);
-  writeLine("--", OS);
+    EnumType = "enum";
+  std::string Header =
+      applyHTMLTemplate(HTMLTemplates::EnumInfoName, EnumType.c_str(),
+                        I.Name.str().str().c_str());
+  Header = applyHTMLTemplate(HTMLTemplates::FunctionEnumHeader, Header.c_str());
 
-  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);
-  if (I.DefLoc)
-    writeFileDefinition(I.DefLoc.getValue(), OS);
+  std::string Members = genEnumMembersBlock(I.Members);
 
-  for (const auto &C : I.Description)
-    writeDescription(C, OS);
+  std::string DefLoc = I.DefLoc ? writeFileDefinition(I.DefLoc.getValue()) : "";
+
+  std::string Description;
+  if (!I.Description.empty()) {
+    for (const auto &C : I.Description)
+      Description += genHTML(C);
+    Description =
+        applyHTMLTemplate(HTMLTemplates::CommentBlock, Description.c_str());
+  }
+
+  return applyHTMLTemplate(HTMLTemplates::EnumBlock, Header.c_str(),
+                           Members.c_str(), DefLoc.c_str(),
+                           Description.c_str());
 }
 
-void genHTML(const FunctionInfo &I, llvm::raw_ostream &OS) {
+std::string genHTML(const FunctionInfo &I) {
+  std::string Header = applyHTMLTemplate(HTMLTemplates::FunctionEnumHeader,
+                                         I.Name.str().str().c_str());
+
   std::string Buffer;
   llvm::raw_string_ostream Stream(Buffer);
   bool First = true;
@@ -126,115 +260,105 @@
     Stream << N.Type.Name + " " + N.Name;
     First = false;
   }
-  writeHeader(I.Name, "3", OS);
+
   std::string Access = getAccess(I.Access);
   if (Access != "")
-    writeLine(genItalic(Access + " " + I.ReturnType.Type.Name + " " + I.Name +
-                        "(" + Stream.str() + ")"),
-              OS);
-  else
-    writeLine(genItalic(I.ReturnType.Type.Name + " " + I.Name + "(" +
-                        Stream.str() + ")"),
-              OS);
-  if (I.DefLoc)
-    writeFileDefinition(I.DefLoc.getValue(), OS);
+    Access = Access + " ";
+
+  std::string DefHeader =
+      applyHTMLTemplate(HTMLTemplates::FunctionDefHeader, Access.c_str(),
+                        I.ReturnType.Type.Name.str().str().c_str(),
+                        I.Name.str().str().c_str(), Stream.str().c_str());
+
+  std::string DefLoc = I.DefLoc ? writeFileDefinition(I.DefLoc.getValue()) : "";
+
+  std::string Description;
+  if (!I.Description.empty()) {
+    for (const auto &C : I.Description)
+      Description += genHTML(C);
+    Description =
+        applyHTMLTemplate(HTMLTemplates::CommentBlock, Description.c_str());
+  }
 
-  for (const auto &C : I.Description)
-    writeDescription(C, OS);
+  return applyHTMLTemplate(HTMLTemplates::FunctionBlock, Header.c_str(),
+                           DefHeader.c_str(), DefLoc.c_str(),
+                           Description.c_str());
 }
 
-void genHTML(const NamespaceInfo &I, llvm::raw_ostream &OS) {
-  if (I.Name == "")
-    writeHeader("Global Namespace", "1", OS);
+std::string genHTML(const NamespaceInfo &I, std::string &InfoTitle) {
+  if (I.Name.str() == "")
+    InfoTitle = HTMLTemplates::GlobalNamespaceName;
   else
-    writeHeader("namespace " + I.Name, "1", OS);
-  writeNewLine(OS);
+    InfoTitle = applyHTMLTemplate(HTMLTemplates::NamespaceInfoName,
+                                  I.Name.str().str().c_str());
 
+  std::string Header =
+      applyHTMLTemplate(HTMLTemplates::TopLevelInfoHeader, InfoTitle.c_str());
+
+  std::string Description;
   if (!I.Description.empty()) {
     for (const auto &C : I.Description)
-      writeDescription(C, OS);
-    writeNewLine(OS);
+      Description += genHTML(C);
+    Description =
+        applyHTMLTemplate(HTMLTemplates::CommentBlock, Description.c_str());
   }
 
-  if (!I.ChildNamespaces.empty()) {
-    writeHeader("Namespaces", "2", OS);
-    for (const auto &R : I.ChildNamespaces)
-      writeLine(R.Name, OS);
-    writeNewLine(OS);
-  }
-  if (!I.ChildRecords.empty()) {
-    writeHeader("Records", "2", OS);
-    for (const auto &R : I.ChildRecords)
-      writeLine(R.Name, OS);
-    writeNewLine(OS);
-  }
-  if (!I.ChildFunctions.empty()) {
-    writeHeader("Functions", "2", OS);
-    for (const auto &F : I.ChildFunctions)
-      genHTML(F, OS);
-    writeNewLine(OS);
-  }
-  if (!I.ChildEnums.empty()) {
-    writeHeader("Enums", "2", OS);
-    for (const auto &E : I.ChildEnums)
-      genHTML(E, OS);
-    writeNewLine(OS);
-  }
+  std::string ChildNamespaces =
+      genReferencesBlock(I.ChildNamespaces, "Namespaces");
+  std::string ChildRecords = genReferencesBlock(I.ChildRecords, "Records");
+
+  std::string ChildFunctions = genFunctionsBlock(I.ChildFunctions);
+  std::string ChildEnums = genEnumsBlock(I.ChildEnums);
+
+  return applyHTMLTemplate(HTMLTemplates::NamespaceBlock, Header.c_str(),
+                           Description.c_str(), ChildNamespaces.c_str(),
+                           ChildRecords.c_str(), ChildFunctions.c_str(),
+                           ChildEnums.c_str());
 }
 
-void genHTML(const RecordInfo &I, llvm::raw_ostream &OS) {
-  writeHeader(getTagType(I.TagType) + " " + I.Name, "1", OS);
+std::string genHTML(const RecordInfo &I, std::string &InfoTitle) {
+  InfoTitle = applyHTMLTemplate(HTMLTemplates::RecordInfoName,
+                                getTagType(I.TagType).c_str(),
+                                I.Name.str().str().c_str());
+  std::string Header =
+      applyHTMLTemplate(HTMLTemplates::TopLevelInfoHeader, InfoTitle.c_str());
+
+  std::string DefLoc;
   if (I.DefLoc)
-    writeFileDefinition(I.DefLoc.getValue(), OS);
+    DefLoc = writeFileDefinition(I.DefLoc.getValue());
 
+  std::string Description;
   if (!I.Description.empty()) {
     for (const auto &C : I.Description)
-      writeDescription(C, OS);
-    writeNewLine(OS);
+      Description += genHTML(C);
+    Description =
+        applyHTMLTemplate(HTMLTemplates::CommentBlock, Description.c_str());
   }
 
+  std::string Inheritance;
   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);
+      Inheritance = VParents;
     else if (VParents.empty())
-      writeLine("Inherits from " + Parents, OS);
+      Inheritance = Parents;
     else
-      writeLine("Inherits from " + Parents + ", " + VParents, OS);
-    writeNewLine(OS);
+      Inheritance = Parents + ", " + VParents;
+    Inheritance = applyHTMLTemplate(HTMLTemplates::RecordInheritance,
+                                    Inheritance.c_str());
   }
 
-  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);
-    }
-    writeNewLine(OS);
-  }
+  std::string Members = genRecordMembersBlock(I.Members);
+  std::string ChildRecords = genReferencesBlock(I.ChildRecords, "Records");
 
-  if (!I.ChildRecords.empty()) {
-    writeHeader("Records", "2", OS);
-    for (const auto &R : I.ChildRecords)
-      writeLine(R.Name, OS);
-    writeNewLine(OS);
-  }
-  if (!I.ChildFunctions.empty()) {
-    writeHeader("Functions", "2", OS);
-    for (const auto &F : I.ChildFunctions)
-      genHTML(F, OS);
-    writeNewLine(OS);
-  }
-  if (!I.ChildEnums.empty()) {
-    writeHeader("Enums", "2", OS);
-    for (const auto &E : I.ChildEnums)
-      genHTML(E, OS);
-    writeNewLine(OS);
-  }
+  std::string ChildFunctions = genFunctionsBlock(I.ChildFunctions);
+  std::string ChildEnums = genEnumsBlock(I.ChildEnums);
+
+  return applyHTMLTemplate(
+      HTMLTemplates::RecordBlock, Header.c_str(), DefLoc.c_str(),
+      Description.c_str(), Inheritance.c_str(), Members.c_str(),
+      ChildRecords.c_str(), ChildFunctions.c_str(), ChildEnums.c_str());
 }
 
 /// Generator for HTML documentation.
@@ -248,23 +372,32 @@
 const char *HTMLGenerator::Format = "html";
 
 llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
+  std::string Output;
+  std::string InfoTitle;
+
   switch (I->IT) {
   case InfoType::IT_namespace:
-    genHTML(*static_cast<clang::doc::NamespaceInfo *>(I), OS);
+    Output = genHTML(*static_cast<clang::doc::NamespaceInfo *>(I), InfoTitle);
     break;
   case InfoType::IT_record:
-    genHTML(*static_cast<clang::doc::RecordInfo *>(I), OS);
+    Output = genHTML(*static_cast<clang::doc::RecordInfo *>(I), InfoTitle);
     break;
   case InfoType::IT_enum:
-    genHTML(*static_cast<clang::doc::EnumInfo *>(I), OS);
+    Output = genHTML(*static_cast<clang::doc::EnumInfo *>(I));
     break;
   case InfoType::IT_function:
-    genHTML(*static_cast<clang::doc::FunctionInfo *>(I), OS);
+    Output = genHTML(*static_cast<clang::doc::FunctionInfo *>(I));
     break;
   case InfoType::IT_default:
     return llvm::make_error<llvm::StringError>("Unexpected info type.\n",
                                                llvm::inconvertibleErrorCode());
   }
+
+  Output = applyHTMLTemplate(HTMLTemplates::MainContent, Output.c_str());
+  Output = applyHTMLTemplate(HTMLTemplates::HTMLDoc, InfoTitle.c_str(),
+                             Output.c_str());
+  OS << Output;
+
   return llvm::Error::success();
 }
 
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
   HTMLGenerator.cpp
+  HTMLTemplates.cpp
   Mapper.cpp
   MDGenerator.cpp
   Representation.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to