12#include "clang/Basic/Version.h"
13#include "llvm/ADT/StringExtras.h"
14#include "llvm/ADT/StringRef.h"
15#include "llvm/ADT/StringSet.h"
16#include "llvm/Support/FileSystem.h"
17#include "llvm/Support/JSON.h"
18#include "llvm/Support/Path.h"
19#include "llvm/Support/raw_ostream.h"
61 constexpr HTMLTag(TagType Value) : Value(Value) {}
63 operator TagType()
const {
return Value; }
64 operator bool() =
delete;
66 bool isSelfClosing()
const;
67 StringRef toString()
const;
79 HTMLNode(NodeType Type) : Type(Type) {}
80 virtual ~HTMLNode() =
default;
82 virtual void render(llvm::raw_ostream &OS,
int IndentationLevel) = 0;
86struct TextNode :
public HTMLNode {
87 TextNode(
const Twine &Text)
88 : HTMLNode(NodeType::NODE_TEXT), Text(Text.str()) {}
91 void render(llvm::raw_ostream &OS,
int IndentationLevel)
override;
94struct TagNode :
public HTMLNode {
95 TagNode(HTMLTag Tag) : HTMLNode(NodeType::NODE_TAG), Tag(Tag) {}
96 TagNode(HTMLTag Tag,
const Twine &Text) : TagNode(Tag) {
97 Children.emplace_back(std::make_unique<TextNode>(
Text.str()));
101 std::vector<std::unique_ptr<HTMLNode>> Children;
102 std::vector<std::pair<std::string, std::string>>
105 void render(llvm::raw_ostream &OS,
int IndentationLevel)
override;
109 std::vector<std::unique_ptr<HTMLNode>> Children;
110 void render(llvm::raw_ostream &OS) {
111 OS <<
"<!DOCTYPE html>\n";
112 for (
const auto &C : Children) {
121bool HTMLTag::isSelfClosing()
const {
123 case HTMLTag::TAG_META:
124 case HTMLTag::TAG_LINK:
127 case HTMLTag::TAG_DIV:
128 case HTMLTag::TAG_FOOTER:
129 case HTMLTag::TAG_H1:
130 case HTMLTag::TAG_H2:
131 case HTMLTag::TAG_H3:
132 case HTMLTag::TAG_HEADER:
133 case HTMLTag::TAG_LI:
134 case HTMLTag::TAG_MAIN:
135 case HTMLTag::TAG_OL:
137 case HTMLTag::TAG_SCRIPT:
138 case HTMLTag::TAG_SPAN:
139 case HTMLTag::TAG_TITLE:
140 case HTMLTag::TAG_UL:
141 case HTMLTag::TAG_TABLE:
142 case HTMLTag::TAG_THEAD:
143 case HTMLTag::TAG_TBODY:
144 case HTMLTag::TAG_TR:
145 case HTMLTag::TAG_TD:
146 case HTMLTag::TAG_TH:
149 llvm_unreachable(
"Unhandled HTMLTag::TagType");
152StringRef HTMLTag::toString()
const {
156 case HTMLTag::TAG_DIV:
158 case HTMLTag::TAG_FOOTER:
160 case HTMLTag::TAG_H1:
162 case HTMLTag::TAG_H2:
164 case HTMLTag::TAG_H3:
166 case HTMLTag::TAG_HEADER:
168 case HTMLTag::TAG_LI:
170 case HTMLTag::TAG_LINK:
172 case HTMLTag::TAG_MAIN:
174 case HTMLTag::TAG_META:
176 case HTMLTag::TAG_OL:
180 case HTMLTag::TAG_SCRIPT:
182 case HTMLTag::TAG_SPAN:
184 case HTMLTag::TAG_TITLE:
186 case HTMLTag::TAG_UL:
188 case HTMLTag::TAG_TABLE:
190 case HTMLTag::TAG_THEAD:
192 case HTMLTag::TAG_TBODY:
194 case HTMLTag::TAG_TR:
196 case HTMLTag::TAG_TD:
198 case HTMLTag::TAG_TH:
201 llvm_unreachable(
"Unhandled HTMLTag::TagType");
204void TextNode::render(llvm::raw_ostream &OS,
int IndentationLevel) {
205 OS.indent(IndentationLevel * 2);
206 printHTMLEscaped(Text, OS);
209void TagNode::render(llvm::raw_ostream &OS,
int IndentationLevel) {
211 bool InlineChildren =
true;
212 for (
const auto &C : Children)
213 if (
C->Type == NodeType::NODE_TAG) {
214 InlineChildren =
false;
217 OS.indent(IndentationLevel * 2);
218 OS <<
"<" << Tag.toString();
219 for (
const auto &A : Attributes)
220 OS <<
" " <<
A.first <<
"=\"" <<
A.second <<
"\"";
221 if (Tag.isSelfClosing()) {
228 bool NewLineRendered =
true;
229 for (
const auto &C : Children) {
230 int ChildrenIndentation =
231 InlineChildren || !NewLineRendered ? 0 : IndentationLevel + 1;
232 C->render(OS, ChildrenIndentation);
233 if (!InlineChildren && (C ==
Children.back() ||
234 (
C->Type != NodeType::NODE_TEXT ||
235 (&C + 1)->get()->Type != NodeType::NODE_TEXT))) {
237 NewLineRendered =
true;
239 NewLineRendered =
false;
242 OS.indent(IndentationLevel * 2);
243 OS <<
"</" << Tag.toString() <<
">";
246template <
typename Derived,
typename Base,
247 typename = std::enable_if<std::is_base_of<Derived, Base>::value>>
249 std::vector<Base> &Original) {
250 std::move(New.begin(), New.end(), std::back_inserter(Original));
255static std::vector<std::unique_ptr<TagNode>>
257 std::vector<std::unique_ptr<TagNode>> Out;
259 auto LinkNode = std::make_unique<TagNode>(HTMLTag::TAG_LINK);
260 LinkNode->Attributes.emplace_back(
"rel",
"stylesheet");
262 llvm::sys::path::append(StylesheetPath,
263 llvm::sys::path::filename(FilePath));
265 llvm::sys::path::native(StylesheetPath, llvm::sys::path::Style::posix);
266 LinkNode->Attributes.emplace_back(
"href", std::string(StylesheetPath));
267 Out.emplace_back(std::move(LinkNode));
272static std::vector<std::unique_ptr<TagNode>>
274 std::vector<std::unique_ptr<TagNode>> Out;
278 auto IndexJSONNode = std::make_unique<TagNode>(HTMLTag::TAG_SCRIPT);
279 llvm::sys::path::append(IndexJSONPath,
"index_json.js");
280 llvm::sys::path::native(IndexJSONPath, llvm::sys::path::Style::posix);
281 IndexJSONNode->Attributes.emplace_back(
"src", std::string(IndexJSONPath));
282 Out.emplace_back(std::move(IndexJSONNode));
284 for (
const auto &FilePath : CDCtx.
JsScripts) {
286 auto ScriptNode = std::make_unique<TagNode>(HTMLTag::TAG_SCRIPT);
287 llvm::sys::path::append(ScriptPath, llvm::sys::path::filename(FilePath));
289 llvm::sys::path::native(ScriptPath, llvm::sys::path::Style::posix);
290 ScriptNode->Attributes.emplace_back(
"src", std::string(ScriptPath));
291 Out.emplace_back(std::move(ScriptNode));
296static std::unique_ptr<TagNode>
genLink(
const Twine &Text,
const Twine &Link) {
297 auto LinkNode = std::make_unique<TagNode>(HTMLTag::TAG_A, Text);
298 LinkNode->Attributes.emplace_back(
"href", Link.str());
302static std::unique_ptr<HTMLNode>
304 std::optional<StringRef> JumpToSection = std::nullopt) {
305 if (Type.Path.empty()) {
307 return std::make_unique<TextNode>(Type.Name);
308 return genLink(Type.Name,
"#" + *JumpToSection);
310 llvm::SmallString<64> Path = Type.getRelativeFilePath(CurrentDirectory);
311 llvm::sys::path::append(Path, Type.getFileBaseName() +
".html");
314 llvm::sys::path::native(Path, llvm::sys::path::Style::posix);
316 Path += (
"#" + *JumpToSection).str();
317 return genLink(Type.Name, Path);
320static std::vector<std::unique_ptr<HTMLNode>>
322 const StringRef &CurrentDirectory) {
323 std::vector<std::unique_ptr<HTMLNode>> Out;
324 for (
const auto &R : Refs) {
325 if (&R != Refs.begin())
326 Out.emplace_back(std::make_unique<TextNode>(
", "));
332static std::vector<std::unique_ptr<TagNode>>
333genHTML(
const EnumInfo &I,
const ClangDocContext &CDCtx);
334static std::vector<std::unique_ptr<TagNode>>
335genHTML(
const FunctionInfo &I,
const ClangDocContext &CDCtx,
336 StringRef ParentInfoDir);
337static std::unique_ptr<TagNode>
genHTML(
const std::vector<CommentInfo> &C);
339static std::vector<std::unique_ptr<TagNode>>
345 std::vector<std::unique_ptr<TagNode>> Out;
346 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2,
"Enums"));
347 Out.back()->Attributes.emplace_back(
"id",
"Enums");
348 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_DIV));
349 auto &DivBody = Out.back();
350 for (
const auto &E : Enums) {
351 std::vector<std::unique_ptr<TagNode>> Nodes =
genHTML(E, CDCtx);
357static std::unique_ptr<TagNode>
362 auto List = std::make_unique<TagNode>(HTMLTag::TAG_TBODY);
364 for (
const auto &M : Members) {
365 auto TRNode = std::make_unique<TagNode>(HTMLTag::TAG_TR);
366 TRNode->Children.emplace_back(
367 std::make_unique<TagNode>(HTMLTag::TAG_TD, M.Name));
369 if (!M.ValueExpr.empty()) {
370 TRNode->Children.emplace_back(
371 std::make_unique<TagNode>(HTMLTag::TAG_TD, M.ValueExpr));
373 TRNode->Children.emplace_back(
374 std::make_unique<TagNode>(HTMLTag::TAG_TD, M.Value));
376 if (!M.Description.empty()) {
377 auto TD = std::make_unique<TagNode>(HTMLTag::TAG_TD);
378 TD->Children.emplace_back(
genHTML(M.Description));
379 TRNode->Children.emplace_back(std::move(TD));
381 List->Children.emplace_back(std::move(TRNode));
386static std::vector<std::unique_ptr<TagNode>>
389 if (Functions.empty())
392 std::vector<std::unique_ptr<TagNode>> Out;
393 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2,
"Functions"));
394 Out.back()->Attributes.emplace_back(
"id",
"Functions");
395 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_DIV));
396 auto &DivBody = Out.back();
397 for (
const auto &F : Functions) {
398 std::vector<std::unique_ptr<TagNode>> Nodes =
399 genHTML(F, CDCtx, ParentInfoDir);
405static std::vector<std::unique_ptr<TagNode>>
407 StringRef ParentInfoDir) {
411 std::vector<std::unique_ptr<TagNode>> Out;
412 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2,
"Members"));
413 Out.back()->Attributes.emplace_back(
"id",
"Members");
414 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_UL));
415 auto &ULBody = Out.back();
416 for (
const auto &M : Members) {
417 StringRef Access = getAccessSpelling(M.Access);
418 auto LIBody = std::make_unique<TagNode>(HTMLTag::TAG_LI);
419 auto MemberDecl = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
421 MemberDecl->Children.emplace_back(
422 std::make_unique<TextNode>(Access +
" "));
424 MemberDecl->Children.emplace_back(std::make_unique<TextNode>(
"static "));
425 MemberDecl->Children.emplace_back(
genReference(M.Type, ParentInfoDir));
426 MemberDecl->Children.emplace_back(std::make_unique<TextNode>(
" " + M.Name));
427 if (!M.Description.empty())
428 LIBody->Children.emplace_back(
genHTML(M.Description));
429 LIBody->Children.emplace_back(std::move(MemberDecl));
430 ULBody->Children.emplace_back(std::move(LIBody));
435static std::vector<std::unique_ptr<TagNode>>
437 llvm::StringRef Title, StringRef ParentPath) {
438 if (References.empty())
441 std::vector<std::unique_ptr<TagNode>> Out;
442 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2, Title));
443 Out.back()->Attributes.emplace_back(
"id", std::string(Title));
444 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_UL));
445 auto &ULBody = Out.back();
446 for (
const auto &R : References) {
447 auto LiNode = std::make_unique<TagNode>(HTMLTag::TAG_LI);
448 LiNode->Children.emplace_back(
genReference(R, ParentPath));
449 ULBody->Children.emplace_back(std::move(LiNode));
457 return std::make_unique<TagNode>(
458 HTMLTag::TAG_P,
"Defined at line " + std::to_string(L.
StartLineNumber) +
462 llvm::sys::path::append(
463 FileURL, llvm::sys::path::Style::posix,
467 llvm::sys::path::convert_to_slash(
472 llvm::sys::path::Style::windows));
473 auto Node = std::make_unique<TagNode>(HTMLTag::TAG_P);
474 Node->Children.emplace_back(std::make_unique<TextNode>(
"Defined at line "));
475 auto LocNumberNode = std::make_unique<TagNode>(
479 LocNumberNode->Attributes.emplace_back(
483 Node->Children.emplace_back(std::move(LocNumberNode));
484 Node->Children.emplace_back(std::make_unique<TextNode>(
" of file "));
485 auto LocFileNode = std::make_unique<TagNode>(
486 HTMLTag::TAG_A, llvm::sys::path::filename(FileURL));
487 LocFileNode->Attributes.emplace_back(
"href", std::string(FileURL));
488 Node->Children.emplace_back(std::move(LocFileNode));
494 const std::optional<Location> &DefLoc) {
499static std::vector<std::unique_ptr<TagNode>>
500genHTML(
const Index &Index, StringRef InfoPath,
bool IsOutermostList);
505static std::vector<std::unique_ptr<TagNode>>
508 std::vector<std::unique_ptr<TagNode>> Out;
509 auto MetaNode = std::make_unique<TagNode>(HTMLTag::TAG_META);
510 MetaNode->Attributes.emplace_back(
"charset",
"utf-8");
511 Out.emplace_back(std::move(MetaNode));
512 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_TITLE, Title));
513 std::vector<std::unique_ptr<TagNode>> StylesheetsNodes =
516 std::vector<std::unique_ptr<TagNode>> JsNodes =
525 auto HeaderNode = std::make_unique<TagNode>(HTMLTag::TAG_HEADER,
ProjectName);
526 HeaderNode->Attributes.emplace_back(
"id",
"project-title");
536 std::vector<std::unique_ptr<TagNode>> &MainContentInnerNodes,
537 const Index &InfoIndex) {
538 auto MainNode = std::make_unique<TagNode>(HTMLTag::TAG_MAIN);
540 auto LeftSidebarNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
541 LeftSidebarNode->Attributes.emplace_back(
"id",
"sidebar-left");
542 LeftSidebarNode->Attributes.emplace_back(
"path", std::string(InfoPath));
543 LeftSidebarNode->Attributes.emplace_back(
544 "class",
"col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left");
546 auto MainContentNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
547 MainContentNode->Attributes.emplace_back(
"id",
"main-content");
548 MainContentNode->Attributes.emplace_back(
549 "class",
"col-xs-12 col-sm-9 col-md-8 main-content");
550 appendVector(std::move(MainContentInnerNodes), MainContentNode->Children);
552 auto RightSidebarNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
553 RightSidebarNode->Attributes.emplace_back(
"id",
"sidebar-right");
554 RightSidebarNode->Attributes.emplace_back(
555 "class",
"col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right");
556 std::vector<std::unique_ptr<TagNode>> InfoIndexHTML =
557 genHTML(InfoIndex, InfoPath,
true);
558 appendVector(std::move(InfoIndexHTML), RightSidebarNode->Children);
560 MainNode->Children.emplace_back(std::move(LeftSidebarNode));
561 MainNode->Children.emplace_back(std::move(MainContentNode));
562 MainNode->Children.emplace_back(std::move(RightSidebarNode));
570 auto FooterNode = std::make_unique<TagNode>(HTMLTag::TAG_FOOTER);
571 auto SpanNode = std::make_unique<TagNode>(
572 HTMLTag::TAG_SPAN, clang::getClangToolFullVersion(
"clang-doc"));
573 SpanNode->Attributes.emplace_back(
"class",
"no-break");
574 FooterNode->Children.emplace_back(std::move(SpanNode));
581 std::vector<std::unique_ptr<TagNode>> &MainContentNodes,
585 std::vector<std::unique_ptr<TagNode>> HeadNodes =
588 std::unique_ptr<TagNode> MainNode =
593 F.Children.emplace_back(std::move(HeaderNode));
594 F.Children.emplace_back(std::move(MainNode));
595 F.Children.emplace_back(std::move(FooterNode));
601 typename = std::enable_if<std::is_base_of<T, Info>::value>>
603 Index Idx(Title, Title);
604 for (
const auto &C : Infos)
605 Idx.
Children.emplace_back(C.extractName(),
606 llvm::toHex(llvm::toStringRef(C.USR)));
610static std::vector<std::unique_ptr<TagNode>>
612 std::vector<std::unique_ptr<TagNode>> Out;
614 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_SPAN));
615 auto &SpanBody = Out.back();
619 SpanBody->Children.emplace_back(
625 HTMLTag ListHTMLTag = IsOutermostList ? HTMLTag::TAG_OL : HTMLTag::TAG_UL;
626 Out.emplace_back(std::make_unique<TagNode>(ListHTMLTag));
627 const auto &UlBody = Out.back();
629 auto LiBody = std::make_unique<TagNode>(HTMLTag::TAG_LI);
630 std::vector<std::unique_ptr<TagNode>> Nodes =
genHTML(C, InfoPath,
false);
632 UlBody->Children.emplace_back(std::move(LiBody));
640 auto FullComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
641 for (
const auto &Child : I.
Children) {
642 std::unique_ptr<HTMLNode> Node =
genHTML(*Child);
644 FullComment->Children.emplace_back(std::move(Node));
646 return std::move(FullComment);
650 auto ParagraphComment = std::make_unique<TagNode>(HTMLTag::TAG_P);
651 for (
const auto &Child : I.
Children) {
652 std::unique_ptr<HTMLNode> Node =
genHTML(*Child);
654 ParagraphComment->Children.emplace_back(std::move(Node));
656 if (ParagraphComment->Children.empty())
658 return std::move(ParagraphComment);
662 auto BlockComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
663 BlockComment->Children.emplace_back(
664 std::make_unique<TagNode>(HTMLTag::TAG_DIV, I.
Name));
665 for (
const auto &Child : I.
Children) {
666 std::unique_ptr<HTMLNode> Node =
genHTML(*Child);
668 BlockComment->Children.emplace_back(std::move(Node));
670 if (BlockComment->Children.empty())
672 return std::move(BlockComment);
678 return std::make_unique<TextNode>(I.
Text);
693 llvm_unreachable(
"Unhandled CommentKind");
696static std::unique_ptr<TagNode>
genHTML(
const std::vector<CommentInfo> &C) {
697 auto CommentBlock = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
698 for (
const auto &Child : C) {
699 if (std::unique_ptr<HTMLNode> Node =
genHTML(Child))
700 CommentBlock->Children.emplace_back(std::move(Node));
705static std::vector<std::unique_ptr<TagNode>>
707 std::vector<std::unique_ptr<TagNode>> Out;
708 std::string EnumType = I.
Scoped ?
"enum class " :
"enum ";
710 bool HasComments = llvm::any_of(
712 std::unique_ptr<TagNode> Table =
713 std::make_unique<TagNode>(HTMLTag::TAG_TABLE);
714 std::unique_ptr<TagNode> THead =
715 std::make_unique<TagNode>(HTMLTag::TAG_THEAD);
716 std::unique_ptr<TagNode> TRow = std::make_unique<TagNode>(HTMLTag::TAG_TR);
717 std::unique_ptr<TagNode> TD =
718 std::make_unique<TagNode>(HTMLTag::TAG_TH, EnumType + I.
Name);
720 TD->Attributes.emplace_back(
"colspan", HasComments ?
"3" :
"2");
722 Table->Attributes.emplace_back(
"id", llvm::toHex(llvm::toStringRef(I.
USR)));
723 TRow->Children.emplace_back(std::move(TD));
724 THead->Children.emplace_back(std::move(TRow));
725 Table->Children.emplace_back(std::move(THead));
728 Table->Children.emplace_back(std::move(Node));
730 Out.emplace_back(std::move(Table));
740static std::vector<std::unique_ptr<TagNode>>
742 StringRef ParentInfoDir) {
743 std::vector<std::unique_ptr<TagNode>> Out;
744 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H3, I.
Name));
747 Out.back()->Attributes.emplace_back(
"id",
748 llvm::toHex(llvm::toStringRef(I.
USR)));
750 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_P));
751 auto &FunctionHeader = Out.back();
753 std::string Access = getAccessSpelling(I.
Access).str();
755 FunctionHeader->Children.emplace_back(
756 std::make_unique<TextNode>(Access +
" "));
758 FunctionHeader->Children.emplace_back(
759 std::make_unique<TextNode>(
"static "));
761 FunctionHeader->Children.emplace_back(
763 FunctionHeader->Children.emplace_back(std::make_unique<TextNode>(
" "));
765 FunctionHeader->Children.emplace_back(
766 std::make_unique<TextNode>(I.
Name +
"("));
768 for (
const auto &P : I.
Params) {
769 if (&P != I.
Params.begin())
770 FunctionHeader->Children.emplace_back(std::make_unique<TextNode>(
", "));
771 FunctionHeader->Children.emplace_back(
genReference(P.Type, ParentInfoDir));
772 FunctionHeader->Children.emplace_back(
773 std::make_unique<TextNode>(
" " + P.Name));
775 FunctionHeader->Children.emplace_back(std::make_unique<TextNode>(
")"));
785static std::vector<std::unique_ptr<TagNode>>
787 std::string &InfoTitle) {
788 std::vector<std::unique_ptr<TagNode>> Out;
789 if (I.
Name.str() ==
"")
790 InfoTitle =
"Global Namespace";
792 InfoTitle = (
"namespace " + I.
Name).str();
794 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
801 std::vector<std::unique_ptr<TagNode>> ChildNamespaces =
804 std::vector<std::unique_ptr<TagNode>> ChildRecords =
808 std::vector<std::unique_ptr<TagNode>> ChildFunctions =
811 std::vector<std::unique_ptr<TagNode>> ChildEnums =
816 InfoIndex.
Children.emplace_back(
"Namespaces",
"Namespaces");
818 InfoIndex.
Children.emplace_back(
"Records",
"Records");
829static std::vector<std::unique_ptr<TagNode>>
831 std::string &InfoTitle) {
832 std::vector<std::unique_ptr<TagNode>> Out;
834 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
841 std::vector<std::unique_ptr<HTMLNode>> Parents =
843 std::vector<std::unique_ptr<HTMLNode>> VParents =
845 if (!Parents.empty() || !VParents.empty()) {
846 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_P));
847 auto &PBody = Out.back();
848 PBody->Children.emplace_back(std::make_unique<TextNode>(
"Inherits from "));
851 else if (VParents.empty())
855 PBody->Children.emplace_back(std::make_unique<TextNode>(
", "));
860 std::vector<std::unique_ptr<TagNode>> Members =
863 std::vector<std::unique_ptr<TagNode>> ChildRecords =
867 std::vector<std::unique_ptr<TagNode>> ChildFunctions =
870 std::vector<std::unique_ptr<TagNode>> ChildEnums =
875 InfoIndex.
Children.emplace_back(
"Members",
"Members");
877 InfoIndex.
Children.emplace_back(
"Records",
"Records");
888static std::vector<std::unique_ptr<TagNode>>
890 std::string &InfoTitle) {
901 llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
912 llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
915 llvm::StringSet<> CreatedDirs;
918 llvm::StringMap<std::vector<doc::Info *>> FileToInfos;
919 for (
const auto &Group : Infos) {
922 llvm::SmallString<128> Path;
923 llvm::sys::path::native(RootDir, Path);
925 if (!CreatedDirs.contains(Path)) {
926 if (std::error_code Err = llvm::sys::fs::create_directories(Path);
927 Err != std::error_code()) {
928 return llvm::createStringError(Err,
"Failed to create directory '%s'.",
931 CreatedDirs.insert(Path);
935 FileToInfos[Path].push_back(
Info);
938 for (
const auto &Group : FileToInfos) {
939 std::error_code FileErr;
940 llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr,
941 llvm::sys::fs::OF_Text);
943 return llvm::createStringError(FileErr,
"Error opening file '%s'",
944 Group.getKey().str().c_str());
953 for (
const auto &
Info : Group.getValue()) {
960 return llvm::Error::success();
965 std::string InfoTitle;
966 std::vector<std::unique_ptr<TagNode>> MainContentNodes;
971 InfoIndex, CDCtx, InfoTitle);
975 InfoIndex, CDCtx, InfoTitle);
993 return llvm::createStringError(llvm::inconvertibleErrorCode(),
994 "unexpected info type");
998 MainContentNodes, InfoIndex, CDCtx);
1001 return llvm::Error::success();
1025 llvm_unreachable(
"Unknown InfoType");
1030 std::error_code FileErr;
1031 llvm::SmallString<128> FilePath;
1033 llvm::sys::path::append(FilePath,
"index_json.js");
1034 llvm::raw_fd_ostream OS(FilePath, FileErr, llvm::sys::fs::OF_Text);
1035 if (FileErr != OK) {
1036 return llvm::createStringError(llvm::inconvertibleErrorCode(),
1037 "error creating index file: " +
1041 if (llvm::sys::path::is_relative(RootPath)) {
1042 llvm::sys::fs::make_absolute(RootPath);
1048 std::string RootPathEscaped = RootPath.str().str();
1049 llvm::replace(RootPathEscaped,
'\\',
'/');
1050 OS <<
"var RootPath = \"" << RootPathEscaped <<
"\";\n";
1052 llvm::SmallString<128> Base(CDCtx.
Base);
1053 std::string BaseEscaped = Base.str().str();
1054 llvm::replace(BaseEscaped,
'\\',
'/');
1055 OS <<
"var Base = \"" << BaseEscaped <<
"\";\n";
1058 llvm::json::OStream J(OS, 2);
1059 std::function<void(
Index)> IndexToJSON = [&](
const Index &I) {
1061 J.attribute(
"USR", toHex(llvm::toStringRef(I.USR)));
1062 J.attribute(
"Name", I.Name);
1063 J.attribute(
"RefType",
getRefType(I.RefType));
1064 J.attribute(
"Path", I.getRelativeFilePath(
""));
1065 J.attributeArray(
"Children", [&] {
1066 for (
const Index &C : I.Children)
1071 OS <<
"async function LoadIndex() {\nreturn";
1072 IndexToJSON(CDCtx.
Idx);
1074 return llvm::Error::success();
1081 auto MainNode = std::make_unique<TagNode>(HTMLTag::TAG_MAIN);
1083 auto LeftSidebarNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
1084 LeftSidebarNode->Attributes.emplace_back(
"id",
"sidebar-left");
1085 LeftSidebarNode->Attributes.emplace_back(
"path",
"");
1086 LeftSidebarNode->Attributes.emplace_back(
1087 "class",
"col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left");
1088 LeftSidebarNode->Attributes.emplace_back(
"style",
"flex: 0 100%;");
1090 MainNode->Children.emplace_back(std::move(LeftSidebarNode));
1096 std::error_code FileErr, OK;
1097 llvm::SmallString<128> IndexPath;
1098 llvm::sys::path::native(CDCtx.
OutDirectory, IndexPath);
1099 llvm::sys::path::append(IndexPath,
"index.html");
1100 llvm::raw_fd_ostream IndexOS(IndexPath, FileErr, llvm::sys::fs::OF_Text);
1101 if (FileErr != OK) {
1102 return llvm::createStringError(llvm::inconvertibleErrorCode(),
1103 "error creating main index: " +
1109 std::vector<std::unique_ptr<TagNode>> HeadNodes =
1116 F.Children.emplace_back(std::move(HeaderNode));
1117 F.Children.emplace_back(std::move(MainNode));
1118 F.Children.emplace_back(std::move(FooterNode));
1122 return llvm::Error::success();
1138 for (
const auto &FilePath : CDCtx.
JsScripts) {
1143 return llvm::Error::success();
1147 "Generator for HTML output.");
static llvm::cl::opt< std::string > ProjectName("project-name", llvm::cl::desc("Name of project."), llvm::cl::cat(ClangDocCategory))
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)
llvm::Error copyFile(llvm::StringRef FilePath, llvm::StringRef OutDirectory)
static std::unique_ptr< HTMLNode > genReference(const Reference &Type, StringRef CurrentDirectory, std::optional< StringRef > JumpToSection=std::nullopt)
std::string getTagType(TagTypeKind AS)
@ CK_InlineCommandComment
@ CK_VerbatimBlockLineComment
@ CK_VerbatimBlockComment
@ CK_TParamCommandComment
static std::vector< std::unique_ptr< TagNode > > genStylesheetsHTML(StringRef InfoPath, const ClangDocContext &CDCtx)
static void maybeWriteSourceFileRef(std::vector< std::unique_ptr< TagNode > > &Out, const ClangDocContext &CDCtx, const std::optional< Location > &DefLoc)
llvm::SmallString< 128 > computeRelativePath(llvm::StringRef Destination, llvm::StringRef Origin)
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 > writeSourceFileRef(const ClangDocContext &CDCtx, const Location &L)
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::string getRefType(InfoType IT)
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)
===– 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
std::optional< std::string > RepositoryLinePrefix
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.
SmallString< 32 > Filename
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