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