11 #include "llvm/ADT/StringRef.h" 12 #include "llvm/Support/FileSystem.h" 13 #include "llvm/Support/Path.h" 40 constexpr HTMLTag(TagType Value) : Value(Value) {}
42 operator TagType()
const {
return Value; }
43 operator bool() =
delete;
45 bool IsSelfClosing()
const;
47 bool HasInlineChildren()
const;
49 llvm::SmallString<16> ToString()
const;
62 virtual ~HTMLNode() =
default;
64 virtual void Render(llvm::raw_ostream &OS,
int IndentationLevel) = 0;
68 struct TextNode :
public HTMLNode {
74 void Render(llvm::raw_ostream &OS,
int IndentationLevel)
override;
77 struct TagNode :
public HTMLNode {
79 : HTMLNode(NodeType::NODE_TAG), Tag(Tag),
82 TagNode(HTMLTag
Tag,
const Twine &Text) : TagNode(Tag) {
92 std::vector<std::unique_ptr<HTMLNode>>
Children;
93 llvm::StringMap<llvm::SmallString<16>>
96 void Render(llvm::raw_ostream &OS,
int IndentationLevel)
override;
99 constexpr
const char *kDoctypeDecl =
"<!DOCTYPE html>";
102 std::vector<std::unique_ptr<HTMLNode>>
Children;
103 void Render(llvm::raw_ostream &OS) {
104 OS << kDoctypeDecl <<
"\n";
105 for (
const auto &C : Children) {
114 bool HTMLTag::IsSelfClosing()
const {
116 case HTMLTag::TAG_META:
118 case HTMLTag::TAG_TITLE:
119 case HTMLTag::TAG_DIV:
120 case HTMLTag::TAG_H1:
121 case HTMLTag::TAG_H2:
122 case HTMLTag::TAG_H3:
124 case HTMLTag::TAG_UL:
125 case HTMLTag::TAG_LI:
129 llvm_unreachable(
"Unhandled HTMLTag::TagType");
132 bool HTMLTag::HasInlineChildren()
const {
134 case HTMLTag::TAG_META:
135 case HTMLTag::TAG_TITLE:
136 case HTMLTag::TAG_H1:
137 case HTMLTag::TAG_H2:
138 case HTMLTag::TAG_H3:
139 case HTMLTag::TAG_LI:
142 case HTMLTag::TAG_DIV:
144 case HTMLTag::TAG_UL:
147 llvm_unreachable(
"Unhandled HTMLTag::TagType");
150 llvm::SmallString<16> HTMLTag::ToString()
const {
152 case HTMLTag::TAG_META:
153 return llvm::SmallString<16>(
"meta");
154 case HTMLTag::TAG_TITLE:
155 return llvm::SmallString<16>(
"title");
156 case HTMLTag::TAG_DIV:
157 return llvm::SmallString<16>(
"div");
158 case HTMLTag::TAG_H1:
159 return llvm::SmallString<16>(
"h1");
160 case HTMLTag::TAG_H2:
161 return llvm::SmallString<16>(
"h2");
162 case HTMLTag::TAG_H3:
163 return llvm::SmallString<16>(
"h3");
165 return llvm::SmallString<16>(
"p");
166 case HTMLTag::TAG_UL:
167 return llvm::SmallString<16>(
"ul");
168 case HTMLTag::TAG_LI:
169 return llvm::SmallString<16>(
"li");
171 return llvm::SmallString<16>(
"a");
173 llvm_unreachable(
"Unhandled HTMLTag::TagType");
176 void TextNode::Render(llvm::raw_ostream &OS,
int IndentationLevel) {
178 OS.indent(IndentationLevel * 2);
182 void TagNode::Render(llvm::raw_ostream &OS,
int IndentationLevel) {
183 OS.indent(IndentationLevel * 2);
184 OS <<
"<" << Tag.ToString();
186 OS <<
" " << A.getKey() <<
"=\"" << A.getValue() <<
"\"";
194 bool NewLineRendered =
true;
195 for (
const auto &C : Children) {
196 int ChildrenIndentation =
198 C->Render(OS, ChildrenIndentation);
200 (C->Type != NodeType::NODE_TEXT ||
201 (&C + 1)->
get()->Type != NodeType::NODE_TEXT))) {
203 NewLineRendered =
true;
205 NewLineRendered =
false;
208 OS.indent(IndentationLevel * 2);
209 OS <<
"</" << Tag.ToString() <<
">";
212 template <
typename Derived,
typename Base,
213 typename = std::enable_if<std::is_base_of<Derived, Base>::value>>
215 std::vector<Base> &Original) {
216 std::move(New.begin(), New.end(), std::back_inserter(Original));
223 StringRef
Path = FilePath;
224 while (!Path.empty()) {
225 if (Directory == Path)
226 return FilePath.substr(Path.size());
227 Path = llvm::sys::path::parent_path(Path);
232 while (!Dir.empty()) {
235 Dir = llvm::sys::path::parent_path(Dir);
236 llvm::sys::path::append(Result,
"..");
238 llvm::sys::path::append(Result, FilePath.substr(Dir.size()));
244 static std::unique_ptr<TagNode>
genLink(
const Twine &Text,
const Twine &Link) {
245 auto LinkNode = llvm::make_unique<TagNode>(HTMLTag::TAG_A, Text);
246 LinkNode->Attributes.try_emplace(
"href", Link.str());
251 StringRef CurrentDirectory) {
252 if (Type.
Path.empty())
253 return llvm::make_unique<TextNode>(Type.
Name);
254 llvm::SmallString<128>
Path =
256 llvm::sys::path::append(Path, Type.
Name +
".html");
260 static std::vector<std::unique_ptr<HTMLNode>>
262 const StringRef &CurrentDirectory) {
263 std::vector<std::unique_ptr<HTMLNode>> Out;
264 for (
const auto &R : Refs) {
265 if (&R != Refs.begin())
266 Out.emplace_back(llvm::make_unique<TextNode>(
", "));
272 static std::vector<std::unique_ptr<TagNode>>
genHTML(
const EnumInfo &I);
274 StringRef ParentInfoDir);
276 static std::vector<std::unique_ptr<TagNode>>
281 std::vector<std::unique_ptr<TagNode>> Out;
282 Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H2,
"Enums"));
283 Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_DIV));
284 auto &DivBody = Out.back();
285 for (
const auto &E : Enums) {
286 std::vector<std::unique_ptr<TagNode>> Nodes =
genHTML(E);
292 static std::unique_ptr<TagNode>
297 auto List = llvm::make_unique<TagNode>(HTMLTag::TAG_UL);
298 for (
const auto &M : Members)
299 List->Children.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_LI, M));
303 static std::vector<std::unique_ptr<TagNode>>
305 StringRef ParentInfoDir) {
306 if (Functions.empty())
309 std::vector<std::unique_ptr<TagNode>> Out;
310 Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H2,
"Functions"));
311 Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_DIV));
312 auto &DivBody = Out.back();
313 for (
const auto &F : Functions) {
314 std::vector<std::unique_ptr<TagNode>> Nodes =
genHTML(F, ParentInfoDir);
320 static std::vector<std::unique_ptr<TagNode>>
322 StringRef ParentInfoDir) {
326 std::vector<std::unique_ptr<TagNode>> Out;
327 Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H2,
"Members"));
328 Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_UL));
329 auto &ULBody = Out.back();
330 for (
const auto &M : Members) {
331 std::string Access =
getAccess(M.Access);
333 Access = Access +
" ";
334 auto LIBody = llvm::make_unique<TagNode>(HTMLTag::TAG_LI);
335 LIBody->Children.emplace_back(llvm::make_unique<TextNode>(Access));
337 LIBody->Children.emplace_back(llvm::make_unique<TextNode>(
" " + M.Name));
338 ULBody->Children.emplace_back(std::move(LIBody));
343 static std::vector<std::unique_ptr<TagNode>>
345 llvm::StringRef Title) {
346 if (References.empty())
349 std::vector<std::unique_ptr<TagNode>> Out;
350 Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H2, Title));
351 Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_UL));
352 auto &ULBody = Out.back();
353 for (
const auto &R : References)
354 ULBody->Children.emplace_back(
355 llvm::make_unique<TagNode>(HTMLTag::TAG_LI, R.Name));
360 return llvm::make_unique<TagNode>(
366 if (I.
Kind ==
"FullComment") {
367 auto FullComment = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV);
368 for (
const auto &Child : I.
Children) {
369 std::unique_ptr<HTMLNode> Node =
genHTML(*Child);
371 FullComment->Children.emplace_back(std::move(Node));
373 return std::move(FullComment);
374 }
else if (I.
Kind ==
"ParagraphComment") {
375 auto ParagraphComment = llvm::make_unique<TagNode>(HTMLTag::TAG_P);
376 for (
const auto &Child : I.
Children) {
377 std::unique_ptr<HTMLNode> Node =
genHTML(*Child);
379 ParagraphComment->Children.emplace_back(std::move(Node));
381 if (ParagraphComment->Children.empty())
383 return std::move(ParagraphComment);
384 }
else if (I.
Kind ==
"TextComment") {
387 return llvm::make_unique<TextNode>(I.
Text,
true);
392 static std::unique_ptr<TagNode>
genHTML(
const std::vector<CommentInfo> &C) {
393 auto CommentBlock = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV);
394 for (
const auto &Child : C) {
395 if (std::unique_ptr<HTMLNode> Node =
genHTML(Child))
396 CommentBlock->Children.emplace_back(std::move(Node));
402 std::vector<std::unique_ptr<TagNode>> Out;
403 std::string EnumType;
405 EnumType =
"enum class ";
410 llvm::make_unique<TagNode>(HTMLTag::TAG_H3, EnumType + I.
Name));
414 Out.emplace_back(std::move(Node));
427 StringRef ParentInfoDir) {
428 std::vector<std::unique_ptr<TagNode>> Out;
429 Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H3, I.
Name));
431 Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P));
432 auto &FunctionHeader = Out.back();
436 FunctionHeader->Children.emplace_back(
437 llvm::make_unique<TextNode>(Access +
" "));
439 FunctionHeader->Children.emplace_back(
441 FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(
" "));
443 FunctionHeader->Children.emplace_back(
444 llvm::make_unique<TextNode>(I.
Name +
"("));
446 for (
const auto &P : I.
Params) {
447 if (&P != I.
Params.begin())
448 FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(
", "));
449 FunctionHeader->Children.emplace_back(
451 FunctionHeader->Children.emplace_back(
452 llvm::make_unique<TextNode>(
" " + P.Name));
454 FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(
")"));
467 std::string &InfoTitle) {
468 std::vector<std::unique_ptr<TagNode>> Out;
469 if (I.
Name.str() ==
"")
470 InfoTitle =
"Global Namespace";
472 InfoTitle = (
"namespace " + I.
Name).str();
474 Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
480 std::vector<std::unique_ptr<TagNode>> ChildNamespaces =
483 std::vector<std::unique_ptr<TagNode>> ChildRecords =
487 std::vector<std::unique_ptr<TagNode>> ChildFunctions =
490 std::vector<std::unique_ptr<TagNode>> ChildEnums =
498 std::string &InfoTitle) {
499 std::vector<std::unique_ptr<TagNode>> Out;
501 Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
510 std::vector<std::unique_ptr<HTMLNode>> Parents =
512 std::vector<std::unique_ptr<HTMLNode>> VParents =
514 if (!Parents.empty() || !VParents.empty()) {
515 Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P));
516 auto &PBody = Out.back();
517 PBody->Children.emplace_back(llvm::make_unique<TextNode>(
"Inherits from "));
520 else if (VParents.empty())
524 PBody->Children.emplace_back(llvm::make_unique<TextNode>(
", "));
529 std::vector<std::unique_ptr<TagNode>> Members =
532 std::vector<std::unique_ptr<TagNode>> ChildRecords =
536 std::vector<std::unique_ptr<TagNode>> ChildFunctions =
539 std::vector<std::unique_ptr<TagNode>> ChildEnums =
551 llvm::Error generateDocForInfo(
Info *I, llvm::raw_ostream &OS)
override;
554 const char *HTMLGenerator::Format =
"html";
556 llvm::Error HTMLGenerator::generateDocForInfo(
Info *I, llvm::raw_ostream &OS) {
559 auto MetaNode = llvm::make_unique<TagNode>(HTMLTag::TAG_META);
560 MetaNode->Attributes.try_emplace(
"charset",
"utf-8");
561 F.Children.emplace_back(std::move(MetaNode));
563 std::string InfoTitle;
565 auto MainContentNode = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV);
567 case InfoType::IT_namespace: {
568 std::vector<std::unique_ptr<TagNode>> Nodes =
569 genHTML(*static_cast<clang::doc::NamespaceInfo *>(I), InfoTitle);
570 AppendVector(std::move(Nodes), MainContentNode->Children);
573 case InfoType::IT_record: {
574 std::vector<std::unique_ptr<TagNode>> Nodes =
575 genHTML(*static_cast<clang::doc::RecordInfo *>(I), InfoTitle);
576 AppendVector(std::move(Nodes), MainContentNode->Children);
579 case InfoType::IT_enum: {
580 std::vector<std::unique_ptr<TagNode>> Nodes =
581 genHTML(*static_cast<clang::doc::EnumInfo *>(I));
582 AppendVector(std::move(Nodes), MainContentNode->Children);
585 case InfoType::IT_function: {
586 std::vector<std::unique_ptr<TagNode>> Nodes =
587 genHTML(*static_cast<clang::doc::FunctionInfo *>(I),
"");
588 AppendVector(std::move(Nodes), MainContentNode->Children);
591 case InfoType::IT_default:
592 return llvm::make_error<llvm::StringError>(
"Unexpected info type.\n",
593 llvm::inconvertibleErrorCode());
596 F.Children.emplace_back(
597 llvm::make_unique<TagNode>(HTMLTag::TAG_TITLE, InfoTitle));
598 F.Children.emplace_back(std::move(MainContentNode));
601 return llvm::Error::success();
604 static GeneratorRegistry::Add<HTMLGenerator>
HTML(HTMLGenerator::Format,
605 "Generator for HTML output.");
static std::unique_ptr< HTMLNode > genTypeReference(const Reference &Type, StringRef CurrentDirectory)
Some operations such as code completion produce a set of candidates.
llvm::StringMap< llvm::SmallString< 16 > > Attributes
volatile int HTMLGeneratorAnchorSource
static std::unique_ptr< TagNode > writeFileDefinition(const Location &L)
static SmallString< 128 > computeRelativePath(StringRef FilePath, StringRef Directory)
llvm::Optional< Location > DefLoc
std::vector< FunctionInfo > ChildFunctions
std::vector< FunctionInfo > ChildFunctions
std::vector< EnumInfo > ChildEnums
std::vector< HeaderHandle > Path
std::vector< Reference > ChildRecords
static const char * Format
static void AppendVector(std::vector< Derived > &&New, std::vector< Base > &Original)
llvm::SmallVector< Reference, 4 > VirtualParents
std::string getAccess(AccessSpecifier AS)
llvm::SmallVector< FieldTypeInfo, 4 > Params
static std::unique_ptr< TagNode > genLink(const Twine &Text, const Twine &Link)
static std::vector< std::unique_ptr< TagNode > > genHTML(const RecordInfo &I, std::string &InfoTitle)
llvm::SmallVector< SmallString< 16 >, 4 > Members
static std::vector< std::unique_ptr< TagNode > > genReferencesBlock(const std::vector< Reference > &References, llvm::StringRef Title)
std::vector< CommentInfo > Description
std::string getTagType(TagTypeKind AS)
llvm::SmallString< 128 > Path
llvm::SmallVector< Reference, 4 > Parents
static std::vector< std::unique_ptr< TagNode > > genFunctionsBlock(const std::vector< FunctionInfo > &Functions, StringRef ParentInfoDir)
Generator for HTML documentation.
llvm::StringRef Directory
std::vector< std::unique_ptr< HTMLNode > > Children
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static std::vector< std::unique_ptr< TagNode > > genEnumsBlock(const std::vector< EnumInfo > &Enums)
std::vector< Reference > ChildNamespaces
std::vector< Reference > ChildRecords
SmallString< 32 > Filename
std::vector< EnumInfo > ChildEnums
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
llvm::SmallVector< MemberTypeInfo, 4 > Members
std::unique_ptr< GlobalCompilationDatabase > Base
static GeneratorRegistry::Add< HTMLGenerator > HTML(HTMLGenerator::Format, "Generator for HTML output.")
static std::vector< std::unique_ptr< HTMLNode > > genReferenceList(const llvm::SmallVectorImpl< Reference > &Refs, const StringRef &CurrentDirectory)
static std::vector< std::unique_ptr< TagNode > > genRecordMembersBlock(const llvm::SmallVector< MemberTypeInfo, 4 > &Members, StringRef ParentInfoDir)
llvm::SmallString< 128 > Path
static std::unique_ptr< TagNode > genEnumMembersBlock(const llvm::SmallVector< SmallString< 16 >, 4 > &Members)