
The *Info object (for the copy of the AST") constructors had many duplicated variants. Many of the variants seemed to be in an attempt to avoid default arguments. But default arguments are not prohibited and using them allows most of the variants to be removed which improves readability. Remove the IsInGlobalNamespace flag on a Reference. This is set when the path is empty, and only read once in the HTML generator with the identical condition. The constructor cleanup exposed a problem where this was set to false when the constructor with no path was used, but true when the path was set to empty. There should be no observable change with the exception that IsInGlobalNamespace is no longer emitted in YAML. Reviewed By: paulkirth, haowei Differential Revision: https://reviews.llvm.org/D134235
458 lines
14 KiB
C++
458 lines
14 KiB
C++
//===-- clang-doc/HTMLGeneratorTest.cpp -----------------------------------===//
|
|
//
|
|
// 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 "ClangDocTest.h"
|
|
#include "Generators.h"
|
|
#include "Representation.h"
|
|
#include "Serialize.h"
|
|
#include "clang/Basic/Version.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
namespace clang {
|
|
namespace doc {
|
|
|
|
static const std::string ClangDocVersion =
|
|
clang::getClangToolFullVersion("clang-doc");
|
|
|
|
std::unique_ptr<Generator> getHTMLGenerator() {
|
|
auto G = doc::findGeneratorByName("html");
|
|
if (!G)
|
|
return nullptr;
|
|
return std::move(G.get());
|
|
}
|
|
|
|
ClangDocContext
|
|
getClangDocContext(std::vector<std::string> UserStylesheets = {},
|
|
StringRef RepositoryUrl = "") {
|
|
ClangDocContext CDCtx{
|
|
{}, "test-project", {}, {}, {}, RepositoryUrl, UserStylesheets, {}};
|
|
CDCtx.UserStylesheets.insert(
|
|
CDCtx.UserStylesheets.begin(),
|
|
"../share/clang/clang-doc-default-stylesheet.css");
|
|
CDCtx.JsScripts.emplace_back("index.js");
|
|
return CDCtx;
|
|
}
|
|
|
|
TEST(HTMLGeneratorTest, emitNamespaceHTML) {
|
|
NamespaceInfo I;
|
|
I.Name = "Namespace";
|
|
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
|
|
|
|
I.ChildNamespaces.emplace_back(EmptySID, "ChildNamespace",
|
|
InfoType::IT_namespace, "Namespace");
|
|
I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
|
|
"Namespace");
|
|
I.ChildFunctions.emplace_back();
|
|
I.ChildFunctions.back().Access = AccessSpecifier::AS_none;
|
|
I.ChildFunctions.back().Name = "OneFunction";
|
|
I.ChildEnums.emplace_back();
|
|
I.ChildEnums.back().Name = "OneEnum";
|
|
|
|
auto G = getHTMLGenerator();
|
|
assert(G);
|
|
std::string Buffer;
|
|
llvm::raw_string_ostream Actual(Buffer);
|
|
ClangDocContext CDCtx = getClangDocContext({"user-provided-stylesheet.css"});
|
|
auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
|
|
assert(!Err);
|
|
std::string Expected = R"raw(<!DOCTYPE html>
|
|
<meta charset="utf-8"/>
|
|
<title>namespace Namespace</title>
|
|
<link rel="stylesheet" href="../clang-doc-default-stylesheet.css"/>
|
|
<link rel="stylesheet" href="../user-provided-stylesheet.css"/>
|
|
<script src="../index.js"></script>
|
|
<header id="project-title">test-project</header>
|
|
<main>
|
|
<div id="sidebar-left" path="Namespace" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>
|
|
<div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">
|
|
<h1>namespace Namespace</h1>
|
|
<h2 id="Namespaces">Namespaces</h2>
|
|
<ul>
|
|
<li>
|
|
<a href="ChildNamespace/index.html">ChildNamespace</a>
|
|
</li>
|
|
</ul>
|
|
<h2 id="Records">Records</h2>
|
|
<ul>
|
|
<li>
|
|
<a href="ChildStruct.html">ChildStruct</a>
|
|
</li>
|
|
</ul>
|
|
<h2 id="Functions">Functions</h2>
|
|
<div>
|
|
<h3 id="0000000000000000000000000000000000000000">OneFunction</h3>
|
|
<p>OneFunction()</p>
|
|
</div>
|
|
<h2 id="Enums">Enums</h2>
|
|
<div>
|
|
<h3 id="0000000000000000000000000000000000000000">enum OneEnum</h3>
|
|
</div>
|
|
</div>
|
|
<div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right">
|
|
<ol>
|
|
<li>
|
|
<span>
|
|
<a href="#Namespaces">Namespaces</a>
|
|
</span>
|
|
</li>
|
|
<li>
|
|
<span>
|
|
<a href="#Records">Records</a>
|
|
</span>
|
|
</li>
|
|
<li>
|
|
<span>
|
|
<a href="#Functions">Functions</a>
|
|
</span>
|
|
<ul>
|
|
<li>
|
|
<span>
|
|
<a href="#0000000000000000000000000000000000000000">OneFunction</a>
|
|
</span>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<span>
|
|
<a href="#Enums">Enums</a>
|
|
</span>
|
|
<ul>
|
|
<li>
|
|
<span>
|
|
<a href="#0000000000000000000000000000000000000000">OneEnum</a>
|
|
</span>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
</main>
|
|
<footer>
|
|
<span class="no-break">)raw" +
|
|
ClangDocVersion + R"raw(</span>
|
|
</footer>
|
|
)raw";
|
|
|
|
EXPECT_EQ(Expected, Actual.str());
|
|
}
|
|
|
|
TEST(HTMLGeneratorTest, emitRecordHTML) {
|
|
RecordInfo I;
|
|
I.Name = "r";
|
|
I.Path = "X/Y/Z";
|
|
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
|
|
|
|
I.DefLoc = Location(10, llvm::SmallString<16>{"dir/test.cpp"}, true);
|
|
I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
|
|
|
|
SmallString<16> PathTo;
|
|
llvm::sys::path::native("path/to", PathTo);
|
|
I.Members.emplace_back(TypeInfo("int", "X/Y"), "X",
|
|
AccessSpecifier::AS_private);
|
|
I.TagType = TagTypeKind::TTK_Class;
|
|
I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, PathTo);
|
|
I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
|
|
|
|
I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
|
|
"X/Y/Z/r");
|
|
I.ChildFunctions.emplace_back();
|
|
I.ChildFunctions.back().Name = "OneFunction";
|
|
I.ChildEnums.emplace_back();
|
|
I.ChildEnums.back().Name = "OneEnum";
|
|
|
|
auto G = getHTMLGenerator();
|
|
assert(G);
|
|
std::string Buffer;
|
|
llvm::raw_string_ostream Actual(Buffer);
|
|
ClangDocContext CDCtx = getClangDocContext({}, "http://www.repository.com");
|
|
auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
|
|
assert(!Err);
|
|
std::string Expected = R"raw(<!DOCTYPE html>
|
|
<meta charset="utf-8"/>
|
|
<title>class r</title>
|
|
<link rel="stylesheet" href="../../../clang-doc-default-stylesheet.css"/>
|
|
<script src="../../../index.js"></script>
|
|
<header id="project-title">test-project</header>
|
|
<main>
|
|
<div id="sidebar-left" path="X/Y/Z" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>
|
|
<div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">
|
|
<h1>class r</h1>
|
|
<p>
|
|
Defined at line
|
|
<a href="http://www.repository.com/dir/test.cpp#10">10</a>
|
|
of file
|
|
<a href="http://www.repository.com/dir/test.cpp">test.cpp</a>
|
|
</p>
|
|
<p>
|
|
Inherits from
|
|
<a href="../../../path/to/F.html">F</a>
|
|
, G
|
|
</p>
|
|
<h2 id="Members">Members</h2>
|
|
<ul>
|
|
<li>
|
|
private
|
|
<a href="../../../X/Y/int.html">int</a>
|
|
X
|
|
</li>
|
|
</ul>
|
|
<h2 id="Records">Records</h2>
|
|
<ul>
|
|
<li>
|
|
<a href="../../../X/Y/Z/r/ChildStruct.html">ChildStruct</a>
|
|
</li>
|
|
</ul>
|
|
<h2 id="Functions">Functions</h2>
|
|
<div>
|
|
<h3 id="0000000000000000000000000000000000000000">OneFunction</h3>
|
|
<p>public OneFunction()</p>
|
|
</div>
|
|
<h2 id="Enums">Enums</h2>
|
|
<div>
|
|
<h3 id="0000000000000000000000000000000000000000">enum OneEnum</h3>
|
|
</div>
|
|
</div>
|
|
<div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right">
|
|
<ol>
|
|
<li>
|
|
<span>
|
|
<a href="#Members">Members</a>
|
|
</span>
|
|
</li>
|
|
<li>
|
|
<span>
|
|
<a href="#Records">Records</a>
|
|
</span>
|
|
</li>
|
|
<li>
|
|
<span>
|
|
<a href="#Functions">Functions</a>
|
|
</span>
|
|
<ul>
|
|
<li>
|
|
<span>
|
|
<a href="#0000000000000000000000000000000000000000">OneFunction</a>
|
|
</span>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<span>
|
|
<a href="#Enums">Enums</a>
|
|
</span>
|
|
<ul>
|
|
<li>
|
|
<span>
|
|
<a href="#0000000000000000000000000000000000000000">OneEnum</a>
|
|
</span>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
</main>
|
|
<footer>
|
|
<span class="no-break">)raw" +
|
|
ClangDocVersion + R"raw(</span>
|
|
</footer>
|
|
)raw";
|
|
|
|
EXPECT_EQ(Expected, Actual.str());
|
|
}
|
|
|
|
TEST(HTMLGeneratorTest, emitFunctionHTML) {
|
|
FunctionInfo I;
|
|
I.Name = "f";
|
|
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
|
|
|
|
I.DefLoc = Location(10, llvm::SmallString<16>{"dir/test.cpp"}, false);
|
|
I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
|
|
|
|
I.Access = AccessSpecifier::AS_none;
|
|
|
|
SmallString<16> PathTo;
|
|
llvm::sys::path::native("path/to", PathTo);
|
|
I.ReturnType =
|
|
TypeInfo(Reference(EmptySID, "float", InfoType::IT_default, PathTo));
|
|
I.Params.emplace_back(TypeInfo("int", PathTo), "P");
|
|
I.IsMethod = true;
|
|
I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
|
|
|
|
auto G = getHTMLGenerator();
|
|
assert(G);
|
|
std::string Buffer;
|
|
llvm::raw_string_ostream Actual(Buffer);
|
|
ClangDocContext CDCtx = getClangDocContext({}, "https://www.repository.com");
|
|
auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
|
|
assert(!Err);
|
|
std::string Expected = R"raw(<!DOCTYPE html>
|
|
<meta charset="utf-8"/>
|
|
<title></title>
|
|
<link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
|
|
<script src="index.js"></script>
|
|
<header id="project-title">test-project</header>
|
|
<main>
|
|
<div id="sidebar-left" path="" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>
|
|
<div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">
|
|
<h3 id="0000000000000000000000000000000000000000">f</h3>
|
|
<p>
|
|
<a href="path/to/float.html">float</a>
|
|
f(
|
|
<a href="path/to/int.html">int</a>
|
|
P)
|
|
</p>
|
|
<p>Defined at line 10 of file dir/test.cpp</p>
|
|
</div>
|
|
<div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right"></div>
|
|
</main>
|
|
<footer>
|
|
<span class="no-break">)raw" +
|
|
ClangDocVersion + R"raw(</span>
|
|
</footer>
|
|
)raw";
|
|
|
|
EXPECT_EQ(Expected, Actual.str());
|
|
}
|
|
|
|
TEST(HTMLGeneratorTest, emitEnumHTML) {
|
|
EnumInfo I;
|
|
I.Name = "e";
|
|
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
|
|
|
|
I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"}, true);
|
|
I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
|
|
|
|
I.Members.emplace_back("X");
|
|
I.Scoped = true;
|
|
|
|
auto G = getHTMLGenerator();
|
|
assert(G);
|
|
std::string Buffer;
|
|
llvm::raw_string_ostream Actual(Buffer);
|
|
ClangDocContext CDCtx = getClangDocContext({}, "www.repository.com");
|
|
auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
|
|
assert(!Err);
|
|
std::string Expected = R"raw(<!DOCTYPE html>
|
|
<meta charset="utf-8"/>
|
|
<title></title>
|
|
<link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
|
|
<script src="index.js"></script>
|
|
<header id="project-title">test-project</header>
|
|
<main>
|
|
<div id="sidebar-left" path="" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>
|
|
<div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">
|
|
<h3 id="0000000000000000000000000000000000000000">enum class e</h3>
|
|
<ul>
|
|
<li>X</li>
|
|
</ul>
|
|
<p>
|
|
Defined at line
|
|
<a href="https://www.repository.com/test.cpp#10">10</a>
|
|
of file
|
|
<a href="https://www.repository.com/test.cpp">test.cpp</a>
|
|
</p>
|
|
</div>
|
|
<div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right"></div>
|
|
</main>
|
|
<footer>
|
|
<span class="no-break">)raw" +
|
|
ClangDocVersion + R"raw(</span>
|
|
</footer>
|
|
)raw";
|
|
|
|
EXPECT_EQ(Expected, Actual.str());
|
|
}
|
|
|
|
TEST(HTMLGeneratorTest, emitCommentHTML) {
|
|
FunctionInfo I;
|
|
I.Name = "f";
|
|
I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
|
|
I.ReturnType = TypeInfo("void");
|
|
I.Params.emplace_back(TypeInfo("int"), "I");
|
|
I.Params.emplace_back(TypeInfo("int"), "J");
|
|
I.Access = AccessSpecifier::AS_none;
|
|
|
|
CommentInfo Top;
|
|
Top.Kind = "FullComment";
|
|
|
|
Top.Children.emplace_back(std::make_unique<CommentInfo>());
|
|
CommentInfo *BlankLine = Top.Children.back().get();
|
|
BlankLine->Kind = "ParagraphComment";
|
|
BlankLine->Children.emplace_back(std::make_unique<CommentInfo>());
|
|
BlankLine->Children.back()->Kind = "TextComment";
|
|
|
|
Top.Children.emplace_back(std::make_unique<CommentInfo>());
|
|
CommentInfo *Brief = Top.Children.back().get();
|
|
Brief->Kind = "ParagraphComment";
|
|
Brief->Children.emplace_back(std::make_unique<CommentInfo>());
|
|
Brief->Children.back()->Kind = "TextComment";
|
|
Brief->Children.back()->Name = "ParagraphComment";
|
|
Brief->Children.back()->Text = " Brief description.";
|
|
|
|
Top.Children.emplace_back(std::make_unique<CommentInfo>());
|
|
CommentInfo *Extended = Top.Children.back().get();
|
|
Extended->Kind = "ParagraphComment";
|
|
Extended->Children.emplace_back(std::make_unique<CommentInfo>());
|
|
Extended->Children.back()->Kind = "TextComment";
|
|
Extended->Children.back()->Text = " Extended description that";
|
|
Extended->Children.emplace_back(std::make_unique<CommentInfo>());
|
|
Extended->Children.back()->Kind = "TextComment";
|
|
Extended->Children.back()->Text = " continues onto the next line.";
|
|
|
|
Top.Children.emplace_back(std::make_unique<CommentInfo>());
|
|
CommentInfo *Entities = Top.Children.back().get();
|
|
Entities->Kind = "ParagraphComment";
|
|
Entities->Children.emplace_back(std::make_unique<CommentInfo>());
|
|
Entities->Children.back()->Kind = "TextComment";
|
|
Entities->Children.back()->Name = "ParagraphComment";
|
|
Entities->Children.back()->Text =
|
|
" Comment with html entities: &, <, >, \", \'.";
|
|
|
|
I.Description.emplace_back(std::move(Top));
|
|
|
|
auto G = getHTMLGenerator();
|
|
assert(G);
|
|
std::string Buffer;
|
|
llvm::raw_string_ostream Actual(Buffer);
|
|
ClangDocContext CDCtx = getClangDocContext();
|
|
auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
|
|
assert(!Err);
|
|
std::string Expected = R"raw(<!DOCTYPE html>
|
|
<meta charset="utf-8"/>
|
|
<title></title>
|
|
<link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
|
|
<script src="index.js"></script>
|
|
<header id="project-title">test-project</header>
|
|
<main>
|
|
<div id="sidebar-left" path="" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>
|
|
<div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">
|
|
<h3 id="0000000000000000000000000000000000000000">f</h3>
|
|
<p>void f(int I, int J)</p>
|
|
<p>Defined at line 10 of file test.cpp</p>
|
|
<div>
|
|
<div>
|
|
<p> Brief description.</p>
|
|
<p> Extended description that continues onto the next line.</p>
|
|
<p> Comment with html entities: &, <, >, ", '.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right"></div>
|
|
</main>
|
|
<footer>
|
|
<span class="no-break">)raw" +
|
|
ClangDocVersion + R"raw(</span>
|
|
</footer>
|
|
)raw";
|
|
|
|
EXPECT_EQ(Expected, Actual.str());
|
|
}
|
|
|
|
} // namespace doc
|
|
} // namespace clang
|