11#include "clang/Basic/Version.h"
12#include "llvm/ADT/StringExtras.h"
13#include "llvm/ADT/StringRef.h"
14#include "llvm/ADT/StringSet.h"
15#include "llvm/Support/FileSystem.h"
16#include "llvm/Support/JSON.h"
17#include "llvm/Support/Path.h"
18#include "llvm/Support/raw_ostream.h"
60 constexpr HTMLTag(TagType Value) : Value(Value) {}
62 operator TagType()
const {
return Value; }
63 operator bool() =
delete;
65 bool isSelfClosing()
const;
66 StringRef toString()
const;
78 HTMLNode(NodeType Type) :
Type(
Type) {}
79 virtual ~HTMLNode() =
default;
81 virtual void render(llvm::raw_ostream &
OS,
int IndentationLevel) = 0;
85struct TextNode :
public HTMLNode {
86 TextNode(
const Twine &
Text)
87 : HTMLNode(NodeType::NODE_TEXT),
Text(
Text.str()) {}
90 void render(llvm::raw_ostream &
OS,
int IndentationLevel)
override;
93struct TagNode :
public HTMLNode {
94 TagNode(HTMLTag Tag) : HTMLNode(NodeType::NODE_TAG),
Tag(
Tag) {}
95 TagNode(HTMLTag Tag,
const Twine &
Text) : TagNode(
Tag) {
96 Children.emplace_back(std::make_unique<TextNode>(
Text.str()));
101 std::vector<std::pair<std::string, std::string>>
104 void render(llvm::raw_ostream &
OS,
int IndentationLevel)
override;
107constexpr const char *kDoctypeDecl =
"<!DOCTYPE html>";
110 std::vector<std::unique_ptr<HTMLNode>>
Children;
111 void render(llvm::raw_ostream &
OS) {
112 OS << kDoctypeDecl <<
"\n";
113 for (
const auto &
C : Children) {
122bool HTMLTag::isSelfClosing()
const {
124 case HTMLTag::TAG_META:
125 case HTMLTag::TAG_LINK:
128 case HTMLTag::TAG_DIV:
129 case HTMLTag::TAG_FOOTER:
130 case HTMLTag::TAG_H1:
131 case HTMLTag::TAG_H2:
132 case HTMLTag::TAG_H3:
133 case HTMLTag::TAG_HEADER:
134 case HTMLTag::TAG_LI:
135 case HTMLTag::TAG_MAIN:
136 case HTMLTag::TAG_OL:
138 case HTMLTag::TAG_SCRIPT:
139 case HTMLTag::TAG_SPAN:
140 case HTMLTag::TAG_TITLE:
141 case HTMLTag::TAG_UL:
142 case HTMLTag::TAG_TABLE:
143 case HTMLTag::TAG_THEAD:
144 case HTMLTag::TAG_TBODY:
145 case HTMLTag::TAG_TR:
146 case HTMLTag::TAG_TD:
147 case HTMLTag::TAG_TH:
150 llvm_unreachable(
"Unhandled HTMLTag::TagType");
153StringRef HTMLTag::toString()
const {
157 case HTMLTag::TAG_DIV:
159 case HTMLTag::TAG_FOOTER:
161 case HTMLTag::TAG_H1:
163 case HTMLTag::TAG_H2:
165 case HTMLTag::TAG_H3:
167 case HTMLTag::TAG_HEADER:
169 case HTMLTag::TAG_LI:
171 case HTMLTag::TAG_LINK:
173 case HTMLTag::TAG_MAIN:
175 case HTMLTag::TAG_META:
177 case HTMLTag::TAG_OL:
181 case HTMLTag::TAG_SCRIPT:
183 case HTMLTag::TAG_SPAN:
185 case HTMLTag::TAG_TITLE:
187 case HTMLTag::TAG_UL:
189 case HTMLTag::TAG_TABLE:
191 case HTMLTag::TAG_THEAD:
193 case HTMLTag::TAG_TBODY:
195 case HTMLTag::TAG_TR:
197 case HTMLTag::TAG_TD:
199 case HTMLTag::TAG_TH:
202 llvm_unreachable(
"Unhandled HTMLTag::TagType");
205void TextNode::render(llvm::raw_ostream &
OS,
int IndentationLevel) {
206 OS.indent(IndentationLevel * 2);
207 printHTMLEscaped(
Text,
OS);
210void TagNode::render(llvm::raw_ostream &
OS,
int IndentationLevel) {
212 bool InlineChildren =
true;
214 if (
C->Type == NodeType::NODE_TAG) {
215 InlineChildren =
false;
218 OS.indent(IndentationLevel * 2);
219 OS <<
"<" <<
Tag.toString();
221 OS <<
" " <<
A.first <<
"=\"" <<
A.second <<
"\"";
222 if (
Tag.isSelfClosing()) {
229 bool NewLineRendered =
true;
231 int ChildrenIndentation =
232 InlineChildren || !NewLineRendered ? 0 : IndentationLevel + 1;
233 C->render(
OS, ChildrenIndentation);
234 if (!InlineChildren && (
C ==
Children.back() ||
235 (
C->Type != NodeType::NODE_TEXT ||
236 (&
C + 1)->get()->Type != NodeType::NODE_TEXT))) {
238 NewLineRendered =
true;
240 NewLineRendered =
false;
243 OS.indent(IndentationLevel * 2);
244 OS <<
"</" <<
Tag.toString() <<
">";
247template <
typename Derived,
typename Base,
248 typename = std::enable_if<std::is_base_of<Derived, Base>::value>>
250 std::vector<Base> &Original) {
251 std::move(New.begin(), New.end(), std::back_inserter(Original));
263 if (Destination == Origin)
267 llvm::sys::path::const_iterator FileI = llvm::sys::path::begin(Destination);
268 llvm::sys::path::const_iterator FileE = llvm::sys::path::end(Destination);
269 llvm::sys::path::const_iterator DirI = llvm::sys::path::begin(Origin);
270 llvm::sys::path::const_iterator DirE = llvm::sys::path::end(Origin);
276 while (FileI != FileE && DirI != DirE && *FileI == *DirI) {
280 SmallString<128> Result;
283 while (DirI != DirE) {
284 llvm::sys::path::append(Result,
"..");
288 while (FileI != FileE) {
289 llvm::sys::path::append(Result, *FileI);
297static std::vector<std::unique_ptr<TagNode>>
299 std::vector<std::unique_ptr<TagNode>>
Out;
301 auto LinkNode = std::make_unique<TagNode>(HTMLTag::TAG_LINK);
302 LinkNode->Attributes.emplace_back(
"rel",
"stylesheet");
304 llvm::sys::path::append(StylesheetPath,
305 llvm::sys::path::filename(FilePath));
307 llvm::sys::path::native(StylesheetPath, llvm::sys::path::Style::posix);
308 LinkNode->Attributes.emplace_back(
"href", std::string(StylesheetPath));
309 Out.emplace_back(std::move(LinkNode));
314static std::vector<std::unique_ptr<TagNode>>
316 std::vector<std::unique_ptr<TagNode>>
Out;
320 auto IndexJSONNode = std::make_unique<TagNode>(HTMLTag::TAG_SCRIPT);
321 llvm::sys::path::append(IndexJSONPath,
"index_json.js");
322 llvm::sys::path::native(IndexJSONPath, llvm::sys::path::Style::posix);
323 IndexJSONNode->Attributes.emplace_back(
"src", std::string(IndexJSONPath));
324 Out.emplace_back(std::move(IndexJSONNode));
326 for (
const auto &FilePath : CDCtx.
JsScripts) {
328 auto ScriptNode = std::make_unique<TagNode>(HTMLTag::TAG_SCRIPT);
329 llvm::sys::path::append(ScriptPath, llvm::sys::path::filename(FilePath));
331 llvm::sys::path::native(ScriptPath, llvm::sys::path::Style::posix);
332 ScriptNode->Attributes.emplace_back(
"src", std::string(ScriptPath));
333 Out.emplace_back(std::move(ScriptNode));
338static std::unique_ptr<TagNode>
genLink(
const Twine &
Text,
const Twine &Link) {
339 auto LinkNode = std::make_unique<TagNode>(HTMLTag::TAG_A,
Text);
340 LinkNode->Attributes.emplace_back(
"href", Link.str());
344static std::unique_ptr<HTMLNode>
346 std::optional<StringRef> JumpToSection = std::nullopt) {
347 if (
Type.Path.empty()) {
349 return std::make_unique<TextNode>(
Type.Name);
352 llvm::SmallString<64>
Path =
Type.getRelativeFilePath(CurrentDirectory);
353 llvm::sys::path::append(
Path,
Type.getFileBaseName() +
".html");
356 llvm::sys::path::native(
Path, llvm::sys::path::Style::posix);
358 Path += (
"#" + *JumpToSection).str();
362static std::vector<std::unique_ptr<HTMLNode>>
364 const StringRef &CurrentDirectory) {
365 std::vector<std::unique_ptr<HTMLNode>>
Out;
366 for (
const auto &R : Refs) {
367 if (&R != Refs.begin())
368 Out.emplace_back(std::make_unique<TextNode>(
", "));
374static std::vector<std::unique_ptr<TagNode>>
375genHTML(
const EnumInfo &I,
const ClangDocContext &CDCtx);
376static std::vector<std::unique_ptr<TagNode>>
377genHTML(
const FunctionInfo &I,
const ClangDocContext &CDCtx,
378 StringRef ParentInfoDir);
379static std::unique_ptr<TagNode>
genHTML(
const std::vector<CommentInfo> &
C);
381static std::vector<std::unique_ptr<TagNode>>
387 std::vector<std::unique_ptr<TagNode>>
Out;
388 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2,
"Enums"));
389 Out.back()->Attributes.emplace_back(
"id",
"Enums");
390 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_DIV));
391 auto &DivBody =
Out.back();
392 for (
const auto &
E : Enums) {
393 std::vector<std::unique_ptr<TagNode>> Nodes =
genHTML(
E, CDCtx);
399static std::unique_ptr<TagNode>
404 auto List = std::make_unique<TagNode>(HTMLTag::TAG_TBODY);
406 for (
const auto &
M : Members) {
407 auto TRNode = std::make_unique<TagNode>(HTMLTag::TAG_TR);
408 TRNode->Children.emplace_back(
409 std::make_unique<TagNode>(HTMLTag::TAG_TD,
M.Name));
411 if (!
M.ValueExpr.empty()) {
412 TRNode->Children.emplace_back(
413 std::make_unique<TagNode>(HTMLTag::TAG_TD,
M.ValueExpr));
415 TRNode->Children.emplace_back(
416 std::make_unique<TagNode>(HTMLTag::TAG_TD,
M.Value));
418 if (!
M.Description.empty()) {
419 auto TD = std::make_unique<TagNode>(HTMLTag::TAG_TD);
420 TD->Children.emplace_back(
genHTML(
M.Description));
421 TRNode->Children.emplace_back(std::move(TD));
423 List->Children.emplace_back(std::move(TRNode));
428static std::vector<std::unique_ptr<TagNode>>
431 if (Functions.empty())
434 std::vector<std::unique_ptr<TagNode>>
Out;
435 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2,
"Functions"));
436 Out.back()->Attributes.emplace_back(
"id",
"Functions");
437 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_DIV));
438 auto &DivBody =
Out.back();
439 for (
const auto &F : Functions) {
440 std::vector<std::unique_ptr<TagNode>> Nodes =
441 genHTML(F, CDCtx, ParentInfoDir);
447static std::vector<std::unique_ptr<TagNode>>
449 StringRef ParentInfoDir) {
453 std::vector<std::unique_ptr<TagNode>>
Out;
454 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2,
"Members"));
455 Out.back()->Attributes.emplace_back(
"id",
"Members");
456 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_UL));
457 auto &ULBody =
Out.back();
458 for (
const auto &
M : Members) {
459 std::string Access = getAccessSpelling(
M.Access).str();
461 Access = Access +
" ";
462 auto LIBody = std::make_unique<TagNode>(HTMLTag::TAG_LI);
463 auto MemberDecl = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
464 MemberDecl->Children.emplace_back(std::make_unique<TextNode>(Access));
465 MemberDecl->Children.emplace_back(
genReference(
M.Type, ParentInfoDir));
466 MemberDecl->Children.emplace_back(std::make_unique<TextNode>(
" " +
M.Name));
467 if (!
M.Description.empty())
468 LIBody->Children.emplace_back(
genHTML(
M.Description));
469 LIBody->Children.emplace_back(std::move(MemberDecl));
470 ULBody->Children.emplace_back(std::move(LIBody));
475static std::vector<std::unique_ptr<TagNode>>
477 llvm::StringRef Title, StringRef ParentPath) {
481 std::vector<std::unique_ptr<TagNode>>
Out;
482 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2, Title));
483 Out.back()->Attributes.emplace_back(
"id", std::string(Title));
484 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_UL));
485 auto &ULBody =
Out.back();
487 auto LiNode = std::make_unique<TagNode>(HTMLTag::TAG_LI);
488 LiNode->Children.emplace_back(
genReference(R, ParentPath));
489 ULBody->Children.emplace_back(std::move(LiNode));
494static std::unique_ptr<TagNode>
498 return std::make_unique<TagNode>(
499 HTMLTag::TAG_P,
"Defined at line " + std::to_string(L.LineNumber) +
500 " of file " + L.Filename);
502 llvm::sys::path::append(FileURL, llvm::sys::path::Style::posix, L.Filename);
503 auto Node = std::make_unique<TagNode>(HTMLTag::TAG_P);
504 Node->Children.emplace_back(std::make_unique<TextNode>(
"Defined at line "));
506 std::make_unique<TagNode>(HTMLTag::TAG_A, std::to_string(L.LineNumber));
509 LocNumberNode->Attributes.emplace_back(
510 "href", (FileURL +
"#" + std::to_string(L.LineNumber)).str());
511 Node->Children.emplace_back(std::move(LocNumberNode));
512 Node->Children.emplace_back(std::make_unique<TextNode>(
" of file "));
513 auto LocFileNode = std::make_unique<TagNode>(
514 HTMLTag::TAG_A, llvm::sys::path::filename(FileURL));
515 LocFileNode->Attributes.emplace_back(
"href", std::string(FileURL));
516 Node->Children.emplace_back(std::move(LocFileNode));
520static std::vector<std::unique_ptr<TagNode>>
521genHTML(
const Index &Index, StringRef InfoPath,
bool IsOutermostList);
526static std::vector<std::unique_ptr<TagNode>>
529 std::vector<std::unique_ptr<TagNode>>
Out;
530 auto MetaNode = std::make_unique<TagNode>(HTMLTag::TAG_META);
531 MetaNode->Attributes.emplace_back(
"charset",
"utf-8");
532 Out.emplace_back(std::move(MetaNode));
533 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_TITLE, Title));
534 std::vector<std::unique_ptr<TagNode>> StylesheetsNodes =
537 std::vector<std::unique_ptr<TagNode>> JsNodes =
546 auto HeaderNode = std::make_unique<TagNode>(HTMLTag::TAG_HEADER,
ProjectName);
547 HeaderNode->Attributes.emplace_back(
"id",
"project-title");
557 std::vector<std::unique_ptr<TagNode>> &MainContentInnerNodes,
558 const Index &InfoIndex) {
559 auto MainNode = std::make_unique<TagNode>(HTMLTag::TAG_MAIN);
561 auto LeftSidebarNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
562 LeftSidebarNode->Attributes.emplace_back(
"id",
"sidebar-left");
563 LeftSidebarNode->Attributes.emplace_back(
"path", std::string(InfoPath));
564 LeftSidebarNode->Attributes.emplace_back(
565 "class",
"col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left");
567 auto MainContentNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
568 MainContentNode->Attributes.emplace_back(
"id",
"main-content");
569 MainContentNode->Attributes.emplace_back(
570 "class",
"col-xs-12 col-sm-9 col-md-8 main-content");
571 appendVector(std::move(MainContentInnerNodes), MainContentNode->Children);
573 auto RightSidebarNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
574 RightSidebarNode->Attributes.emplace_back(
"id",
"sidebar-right");
575 RightSidebarNode->Attributes.emplace_back(
576 "class",
"col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right");
577 std::vector<std::unique_ptr<TagNode>> InfoIndexHTML =
578 genHTML(InfoIndex, InfoPath,
true);
579 appendVector(std::move(InfoIndexHTML), RightSidebarNode->Children);
581 MainNode->Children.emplace_back(std::move(LeftSidebarNode));
582 MainNode->Children.emplace_back(std::move(MainContentNode));
583 MainNode->Children.emplace_back(std::move(RightSidebarNode));
591 auto FooterNode = std::make_unique<TagNode>(HTMLTag::TAG_FOOTER);
592 auto SpanNode = std::make_unique<TagNode>(
593 HTMLTag::TAG_SPAN, clang::getClangToolFullVersion(
"clang-doc"));
594 SpanNode->Attributes.emplace_back(
"class",
"no-break");
595 FooterNode->Children.emplace_back(std::move(SpanNode));
602 std::vector<std::unique_ptr<TagNode>> &MainContentNodes,
606 std::vector<std::unique_ptr<TagNode>> HeadNodes =
609 std::unique_ptr<TagNode> MainNode =
614 F.Children.emplace_back(std::move(HeaderNode));
615 F.Children.emplace_back(std::move(MainNode));
616 F.Children.emplace_back(std::move(FooterNode));
622 typename = std::enable_if<std::is_base_of<T, Info>::value>>
624 Index Idx(Title, Title);
625 for (
const auto &
C : Infos)
626 Idx.
Children.emplace_back(
C.extractName(),
627 llvm::toHex(llvm::toStringRef(
C.USR)));
631static std::vector<std::unique_ptr<TagNode>>
633 std::vector<std::unique_ptr<TagNode>>
Out;
635 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_SPAN));
636 auto &SpanBody =
Out.back();
640 SpanBody->Children.emplace_back(
646 HTMLTag ListHTMLTag = IsOutermostList ? HTMLTag::TAG_OL : HTMLTag::TAG_UL;
647 Out.emplace_back(std::make_unique<TagNode>(ListHTMLTag));
648 const auto &UlBody =
Out.back();
650 auto LiBody = std::make_unique<TagNode>(HTMLTag::TAG_LI);
651 std::vector<std::unique_ptr<TagNode>> Nodes =
genHTML(
C, InfoPath,
false);
653 UlBody->Children.emplace_back(std::move(LiBody));
659 if (I.
Kind ==
"FullComment") {
660 auto FullComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
661 for (
const auto &Child : I.
Children) {
664 FullComment->Children.emplace_back(std::move(
Node));
666 return std::move(FullComment);
669 if (I.
Kind ==
"ParagraphComment") {
670 auto ParagraphComment = std::make_unique<TagNode>(HTMLTag::TAG_P);
671 for (
const auto &Child : I.
Children) {
674 ParagraphComment->Children.emplace_back(std::move(
Node));
676 if (ParagraphComment->Children.empty())
678 return std::move(ParagraphComment);
681 if (I.
Kind ==
"BlockCommandComment") {
682 auto BlockComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
683 BlockComment->Children.emplace_back(
684 std::make_unique<TagNode>(HTMLTag::TAG_DIV, I.
Name));
685 for (
const auto &Child : I.
Children) {
688 BlockComment->Children.emplace_back(std::move(
Node));
690 if (BlockComment->Children.empty())
692 return std::move(BlockComment);
694 if (I.
Kind ==
"TextComment") {
697 return std::make_unique<TextNode>(I.
Text);
702static std::unique_ptr<TagNode>
genHTML(
const std::vector<CommentInfo> &
C) {
703 auto CommentBlock = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
704 for (
const auto &Child :
C) {
705 if (std::unique_ptr<HTMLNode>
Node =
genHTML(Child))
706 CommentBlock->Children.emplace_back(std::move(
Node));
711static std::vector<std::unique_ptr<TagNode>>
713 std::vector<std::unique_ptr<TagNode>>
Out;
714 std::string EnumType = I.
Scoped ?
"enum class " :
"enum ";
716 bool HasComments = std::any_of(
719 std::unique_ptr<TagNode> Table =
720 std::make_unique<TagNode>(HTMLTag::TAG_TABLE);
721 std::unique_ptr<TagNode> THead =
722 std::make_unique<TagNode>(HTMLTag::TAG_THEAD);
723 std::unique_ptr<TagNode> TRow = std::make_unique<TagNode>(HTMLTag::TAG_TR);
724 std::unique_ptr<TagNode> TD =
725 std::make_unique<TagNode>(HTMLTag::TAG_TH, EnumType + I.
Name);
727 TD->Attributes.emplace_back(
"colspan", HasComments ?
"3" :
"2");
729 Table->Attributes.emplace_back(
"id", llvm::toHex(llvm::toStringRef(I.
USR)));
730 TRow->Children.emplace_back(std::move(TD));
731 THead->Children.emplace_back(std::move(TRow));
732 Table->Children.emplace_back(std::move(THead));
735 Table->Children.emplace_back(std::move(
Node));
737 Out.emplace_back(std::move(Table));
747 std::string Description;
754static std::vector<std::unique_ptr<TagNode>>
756 StringRef ParentInfoDir) {
757 std::vector<std::unique_ptr<TagNode>>
Out;
758 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H3, I.
Name));
761 Out.back()->Attributes.emplace_back(
"id",
762 llvm::toHex(llvm::toStringRef(I.
USR)));
764 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_P));
765 auto &FunctionHeader =
Out.back();
767 std::string Access = getAccessSpelling(I.
Access).str();
769 FunctionHeader->Children.emplace_back(
770 std::make_unique<TextNode>(Access +
" "));
772 FunctionHeader->Children.emplace_back(
774 FunctionHeader->Children.emplace_back(std::make_unique<TextNode>(
" "));
776 FunctionHeader->Children.emplace_back(
777 std::make_unique<TextNode>(I.
Name +
"("));
779 for (
const auto &P : I.
Params) {
780 if (&P != I.
Params.begin())
781 FunctionHeader->Children.emplace_back(std::make_unique<TextNode>(
", "));
782 FunctionHeader->Children.emplace_back(
genReference(P.Type, ParentInfoDir));
783 FunctionHeader->Children.emplace_back(
784 std::make_unique<TextNode>(
" " + P.Name));
786 FunctionHeader->Children.emplace_back(std::make_unique<TextNode>(
")"));
793 *I.
DefLoc, StringRef{*CDCtx.RepositoryUrl}));
796 std::string Description;
803static std::vector<std::unique_ptr<TagNode>>
805 std::string &InfoTitle) {
806 std::vector<std::unique_ptr<TagNode>>
Out;
807 if (I.
Name.str() ==
"")
808 InfoTitle =
"Global Namespace";
810 InfoTitle = (
"namespace " + I.
Name).str();
812 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
814 std::string Description;
820 std::vector<std::unique_ptr<TagNode>> ChildNamespaces =
823 std::vector<std::unique_ptr<TagNode>> ChildRecords =
827 std::vector<std::unique_ptr<TagNode>> ChildFunctions =
830 std::vector<std::unique_ptr<TagNode>> ChildEnums =
835 InfoIndex.
Children.emplace_back(
"Namespaces",
"Namespaces");
837 InfoIndex.
Children.emplace_back(
"Records",
"Records");
848static std::vector<std::unique_ptr<TagNode>>
850 std::string &InfoTitle) {
851 std::vector<std::unique_ptr<TagNode>>
Out;
853 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
860 *I.
DefLoc, StringRef{*CDCtx.RepositoryUrl}));
863 std::string Description;
867 std::vector<std::unique_ptr<HTMLNode>> Parents =
869 std::vector<std::unique_ptr<HTMLNode>> VParents =
871 if (!Parents.empty() || !VParents.empty()) {
872 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_P));
873 auto &PBody =
Out.back();
874 PBody->Children.emplace_back(std::make_unique<TextNode>(
"Inherits from "));
877 else if (VParents.empty())
881 PBody->Children.emplace_back(std::make_unique<TextNode>(
", "));
886 std::vector<std::unique_ptr<TagNode>> Members =
889 std::vector<std::unique_ptr<TagNode>> ChildRecords =
893 std::vector<std::unique_ptr<TagNode>> ChildFunctions =
896 std::vector<std::unique_ptr<TagNode>> ChildEnums =
901 InfoIndex.
Children.emplace_back(
"Members",
"Members");
903 InfoIndex.
Children.emplace_back(
"Records",
"Records");
914static std::vector<std::unique_ptr<TagNode>>
916 std::string &InfoTitle) {
927 llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
938 llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
941 llvm::StringSet<> CreatedDirs;
944 llvm::StringMap<std::vector<doc::Info *>> FileToInfos;
945 for (
const auto &Group : Infos) {
948 llvm::SmallString<128>
Path;
949 llvm::sys::path::native(RootDir,
Path);
951 if (!CreatedDirs.contains(
Path)) {
952 if (std::error_code Err = llvm::sys::fs::create_directories(
Path);
953 Err != std::error_code()) {
954 return llvm::createStringError(Err,
"Failed to create directory '%s'.",
957 CreatedDirs.insert(
Path);
964 for (
const auto &Group : FileToInfos) {
965 std::error_code FileErr;
966 llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr,
967 llvm::sys::fs::OF_None);
969 return llvm::createStringError(FileErr,
"Error opening file '%s'",
970 Group.getKey().str().c_str());
979 for (
const auto &
Info : Group.getValue()) {
986 return llvm::Error::success();
991 std::string InfoTitle;
992 std::vector<std::unique_ptr<TagNode>> MainContentNodes;
997 InfoIndex, CDCtx, InfoTitle);
1001 InfoIndex, CDCtx, InfoTitle);
1015 return llvm::createStringError(llvm::inconvertibleErrorCode(),
1016 "unexpected info type");
1020 MainContentNodes, InfoIndex, CDCtx);
1023 return llvm::Error::success();
1041 llvm_unreachable(
"Unknown InfoType");
1046 std::error_code FileErr;
1047 llvm::SmallString<128> FilePath;
1049 llvm::sys::path::append(FilePath,
"index_json.js");
1050 llvm::raw_fd_ostream
OS(FilePath, FileErr, llvm::sys::fs::OF_None);
1051 if (FileErr != OK) {
1052 return llvm::createStringError(llvm::inconvertibleErrorCode(),
1053 "error creating index file: " +
1057 if (llvm::sys::path::is_relative(RootPath)) {
1058 llvm::sys::fs::make_absolute(RootPath);
1064 std::string RootPathEscaped = RootPath.str().str();
1065 std::replace(RootPathEscaped.begin(), RootPathEscaped.end(),
'\\',
'/');
1066 OS <<
"var RootPath = \"" << RootPathEscaped <<
"\";\n";
1069 llvm::json::OStream J(
OS, 2);
1070 std::function<void(
Index)> IndexToJSON = [&](
const Index &I) {
1072 J.attribute(
"USR", toHex(llvm::toStringRef(I.USR)));
1073 J.attribute(
"Name", I.Name);
1074 J.attribute(
"RefType",
getRefType(I.RefType));
1075 J.attribute(
"Path", I.getRelativeFilePath(
""));
1076 J.attributeArray(
"Children", [&] {
1077 for (
const Index &
C : I.Children)
1082 OS <<
"async function LoadIndex() {\nreturn";
1083 IndexToJSON(CDCtx.
Idx);
1085 return llvm::Error::success();
1092 auto MainNode = std::make_unique<TagNode>(HTMLTag::TAG_MAIN);
1094 auto LeftSidebarNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
1095 LeftSidebarNode->Attributes.emplace_back(
"id",
"sidebar-left");
1096 LeftSidebarNode->Attributes.emplace_back(
"path",
"");
1097 LeftSidebarNode->Attributes.emplace_back(
1098 "class",
"col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left");
1099 LeftSidebarNode->Attributes.emplace_back(
"style",
"flex: 0 100%;");
1101 MainNode->Children.emplace_back(std::move(LeftSidebarNode));
1107 std::error_code FileErr, OK;
1108 llvm::SmallString<128> IndexPath;
1109 llvm::sys::path::native(CDCtx.
OutDirectory, IndexPath);
1110 llvm::sys::path::append(IndexPath,
"index.html");
1111 llvm::raw_fd_ostream IndexOS(IndexPath, FileErr, llvm::sys::fs::OF_None);
1112 if (FileErr != OK) {
1113 return llvm::createStringError(llvm::inconvertibleErrorCode(),
1114 "error creating main index: " +
1120 std::vector<std::unique_ptr<TagNode>> HeadNodes =
1127 F.Children.emplace_back(std::move(HeaderNode));
1128 F.Children.emplace_back(std::move(MainNode));
1129 F.Children.emplace_back(std::move(FooterNode));
1133 return llvm::Error::success();
1137 llvm::SmallString<128> PathWrite;
1139 llvm::sys::path::append(PathWrite, llvm::sys::path::filename(FilePath));
1140 llvm::SmallString<128> PathRead;
1141 llvm::sys::path::native(FilePath, PathRead);
1143 std::error_code FileErr = llvm::sys::fs::copy_file(PathRead, PathWrite);
1144 if (FileErr != OK) {
1145 return llvm::createStringError(llvm::inconvertibleErrorCode(),
1146 "error creating file " +
1147 llvm::sys::path::filename(FilePath) +
1148 ": " + FileErr.message() +
"\n");
1150 return llvm::Error::success();
1166 for (
const auto &FilePath : CDCtx.
JsScripts) {
1171 return llvm::Error::success();
1175 "Generator for HTML output.");
static llvm::cl::opt< std::string > ProjectName("project-name", llvm::cl::desc("Name of project."), llvm::cl::cat(ClangDocCategory))
static llvm::cl::opt< std::string > OutDirectory("output", llvm::cl::desc("Directory for outputting generated files."), llvm::cl::init("docs"), llvm::cl::cat(ClangDocCategory))
static llvm::cl::opt< std::string > RepositoryUrl("repository", llvm::cl::desc(R"(
URL of repository that hosts code.
Used for links to definition locations.)"), llvm::cl::cat(ClangDocCategory))
CompiledFragmentImpl & Out
std::vector< std::pair< std::string, std::string > > Attributes
std::vector< std::unique_ptr< HTMLNode > > Children
std::vector< HeaderHandle > Path
::clang::DynTypedNode Node
const google::protobuf::Message & M
llvm::raw_string_ostream OS
Generator for HTML documentation.
static const char * Format
llvm::Error createResources(ClangDocContext &CDCtx) override
llvm::Error generateDocs(StringRef RootDir, llvm::StringMap< std::unique_ptr< doc::Info > > Infos, const ClangDocContext &CDCtx) override
llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, const ClangDocContext &CDCtx) override
static std::unique_ptr< TagNode > genInfoFileMainNode(StringRef InfoPath, std::vector< std::unique_ptr< TagNode > > &MainContentInnerNodes, const Index &InfoIndex)
static std::vector< std::unique_ptr< TagNode > > genHTML(const EnumInfo &I, const ClangDocContext &CDCtx)
static std::unique_ptr< HTMLNode > genReference(const Reference &Type, StringRef CurrentDirectory, std::optional< StringRef > JumpToSection=std::nullopt)
std::string getTagType(TagTypeKind AS)
static std::vector< std::unique_ptr< TagNode > > genStylesheetsHTML(StringRef InfoPath, const ClangDocContext &CDCtx)
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)
static std::vector< std::unique_ptr< TagNode > > genReferencesBlock(const std::vector< Reference > &References, llvm::StringRef Title, StringRef ParentPath)
static std::unique_ptr< TagNode > genFileHeaderNode(StringRef ProjectName)
static llvm::Error serializeIndex(ClangDocContext &CDCtx)
static std::unique_ptr< TagNode > genLink(const Twine &Text, const Twine &Link)
static GeneratorRegistry::Add< HTMLGenerator > HTML(HTMLGenerator::Format, "Generator for HTML output.")
static std::unique_ptr< TagNode > genFileFooterNode()
volatile int HTMLGeneratorAnchorSource
static std::vector< std::unique_ptr< TagNode > > genFileHeadNodes(StringRef Title, StringRef InfoPath, const ClangDocContext &CDCtx)
static llvm::Error genIndex(const ClangDocContext &CDCtx)
static Index genInfoIndexItem(const std::vector< T > &Infos, StringRef Title)
static std::unique_ptr< TagNode > writeFileDefinition(const Location &L, std::optional< StringRef > RepositoryUrl=std::nullopt)
static std::string getRefType(InfoType IT)
static llvm::Error copyFile(StringRef FilePath, StringRef OutDirectory)
static std::vector< std::unique_ptr< TagNode > > genJsScriptsHTML(StringRef InfoPath, const ClangDocContext &CDCtx)
static HTMLFile genInfoFile(StringRef Title, StringRef InfoPath, std::vector< std::unique_ptr< TagNode > > &MainContentNodes, const Index &InfoIndex, const ClangDocContext &CDCtx)
static std::unique_ptr< TagNode > genIndexFileMainNode()
static std::vector< std::unique_ptr< TagNode > > genFunctionsBlock(const std::vector< FunctionInfo > &Functions, const ClangDocContext &CDCtx, StringRef ParentInfoDir)
static std::unique_ptr< TagNode > genEnumMembersBlock(const llvm::SmallVector< EnumValueInfo, 4 > &Members)
static std::vector< std::unique_ptr< TagNode > > genEnumsBlock(const std::vector< EnumInfo > &Enums, const ClangDocContext &CDCtx)
static void appendVector(std::vector< Derived > &&New, std::vector< Base > &Original)
static SmallString< 128 > computeRelativePath(StringRef Destination, StringRef Origin)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Some operations such as code completion produce a set of candidates.
std::optional< std::string > RepositoryUrl
std::vector< std::string > UserStylesheets
std::vector< std::string > JsScripts
llvm::SmallVector< EnumValueInfo, 4 > Members
llvm::SmallVector< FieldTypeInfo, 4 > Params
std::optional< SmallString< 16 > > JumpToSection
std::vector< Index > Children
llvm::SmallString< 16 > getFileBaseName() const
Returns the basename that should be used for this Info.
std::vector< CommentInfo > Description
llvm::SmallString< 128 > Path
llvm::SmallString< 64 > getRelativeFilePath(const StringRef &CurrentPath) const
Returns the file path for this Info relative to CurrentPath.
llvm::SmallVector< MemberTypeInfo, 4 > Members
llvm::SmallVector< Reference, 4 > VirtualParents
llvm::SmallVector< Reference, 4 > Parents
std::vector< Reference > Records
std::vector< FunctionInfo > Functions
std::vector< Reference > Namespaces
std::vector< EnumInfo > Enums
std::optional< Location > DefLoc