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"
53 constexpr HTMLTag(TagType Value) : Value(Value) {}
55 operator TagType()
const {
return Value; }
56 operator bool() =
delete;
58 bool IsSelfClosing()
const;
59 llvm::SmallString<16> ToString()
const;
71 HTMLNode(NodeType Type) :
Type(
Type) {}
72 virtual ~HTMLNode() =
default;
74 virtual void Render(llvm::raw_ostream &
OS,
int IndentationLevel) = 0;
78struct TextNode :
public HTMLNode {
79 TextNode(
const Twine &
Text)
80 : HTMLNode(NodeType::NODE_TEXT),
Text(
Text.str()) {}
83 void Render(llvm::raw_ostream &
OS,
int IndentationLevel)
override;
86struct TagNode :
public HTMLNode {
87 TagNode(HTMLTag Tag) : HTMLNode(NodeType::NODE_TAG),
Tag(
Tag) {}
88 TagNode(HTMLTag Tag,
const Twine &
Text) : TagNode(
Tag) {
89 Children.emplace_back(std::make_unique<TextNode>(
Text.str()));
93 std::vector<std::unique_ptr<HTMLNode>>
Children;
94 std::vector<std::pair<std::string, std::string>>
97 void Render(llvm::raw_ostream &
OS,
int IndentationLevel)
override;
100constexpr const char *kDoctypeDecl =
"<!DOCTYPE html>";
103 std::vector<std::unique_ptr<HTMLNode>>
Children;
104 void Render(llvm::raw_ostream &
OS) {
105 OS << kDoctypeDecl <<
"\n";
106 for (
const auto &
C : Children) {
115bool HTMLTag::IsSelfClosing()
const {
117 case HTMLTag::TAG_META:
118 case HTMLTag::TAG_LINK:
121 case HTMLTag::TAG_DIV:
122 case HTMLTag::TAG_FOOTER:
123 case HTMLTag::TAG_H1:
124 case HTMLTag::TAG_H2:
125 case HTMLTag::TAG_H3:
126 case HTMLTag::TAG_HEADER:
127 case HTMLTag::TAG_LI:
128 case HTMLTag::TAG_MAIN:
129 case HTMLTag::TAG_OL:
131 case HTMLTag::TAG_SCRIPT:
132 case HTMLTag::TAG_SPAN:
133 case HTMLTag::TAG_TITLE:
134 case HTMLTag::TAG_UL:
137 llvm_unreachable(
"Unhandled HTMLTag::TagType");
140llvm::SmallString<16> HTMLTag::ToString()
const {
143 return llvm::SmallString<16>(
"a");
144 case HTMLTag::TAG_DIV:
145 return llvm::SmallString<16>(
"div");
146 case HTMLTag::TAG_FOOTER:
147 return llvm::SmallString<16>(
"footer");
148 case HTMLTag::TAG_H1:
149 return llvm::SmallString<16>(
"h1");
150 case HTMLTag::TAG_H2:
151 return llvm::SmallString<16>(
"h2");
152 case HTMLTag::TAG_H3:
153 return llvm::SmallString<16>(
"h3");
154 case HTMLTag::TAG_HEADER:
155 return llvm::SmallString<16>(
"header");
156 case HTMLTag::TAG_LI:
157 return llvm::SmallString<16>(
"li");
158 case HTMLTag::TAG_LINK:
159 return llvm::SmallString<16>(
"link");
160 case HTMLTag::TAG_MAIN:
161 return llvm::SmallString<16>(
"main");
162 case HTMLTag::TAG_META:
163 return llvm::SmallString<16>(
"meta");
164 case HTMLTag::TAG_OL:
165 return llvm::SmallString<16>(
"ol");
167 return llvm::SmallString<16>(
"p");
168 case HTMLTag::TAG_SCRIPT:
169 return llvm::SmallString<16>(
"script");
170 case HTMLTag::TAG_SPAN:
171 return llvm::SmallString<16>(
"span");
172 case HTMLTag::TAG_TITLE:
173 return llvm::SmallString<16>(
"title");
174 case HTMLTag::TAG_UL:
175 return llvm::SmallString<16>(
"ul");
177 llvm_unreachable(
"Unhandled HTMLTag::TagType");
180void TextNode::Render(llvm::raw_ostream &
OS,
int IndentationLevel) {
181 OS.indent(IndentationLevel * 2);
182 printHTMLEscaped(
Text,
OS);
185void TagNode::Render(llvm::raw_ostream &
OS,
int IndentationLevel) {
187 bool InlineChildren =
true;
189 if (
C->Type == NodeType::NODE_TAG) {
190 InlineChildren =
false;
193 OS.indent(IndentationLevel * 2);
194 OS <<
"<" <<
Tag.ToString();
196 OS <<
" " <<
A.first <<
"=\"" <<
A.second <<
"\"";
197 if (
Tag.IsSelfClosing()) {
204 bool NewLineRendered =
true;
206 int ChildrenIndentation =
207 InlineChildren || !NewLineRendered ? 0 : IndentationLevel + 1;
208 C->Render(
OS, ChildrenIndentation);
209 if (!InlineChildren && (
C ==
Children.back() ||
210 (
C->Type != NodeType::NODE_TEXT ||
211 (&
C + 1)->get()->Type != NodeType::NODE_TEXT))) {
213 NewLineRendered =
true;
215 NewLineRendered =
false;
218 OS.indent(IndentationLevel * 2);
219 OS <<
"</" <<
Tag.ToString() <<
">";
222template <
typename Derived,
typename Base,
223 typename = std::enable_if<std::is_base_of<Derived, Base>::value>>
225 std::vector<Base> &Original) {
226 std::move(New.begin(), New.end(), std::back_inserter(Original));
238 if (Destination == Origin)
242 llvm::sys::path::const_iterator FileI = llvm::sys::path::begin(Destination);
243 llvm::sys::path::const_iterator FileE = llvm::sys::path::end(Destination);
244 llvm::sys::path::const_iterator DirI = llvm::sys::path::begin(Origin);
245 llvm::sys::path::const_iterator DirE = llvm::sys::path::end(Origin);
251 while (FileI != FileE && DirI != DirE && *FileI == *DirI) {
255 SmallString<128> Result;
258 while (DirI != DirE) {
259 llvm::sys::path::append(Result,
"..");
263 while (FileI != FileE) {
264 llvm::sys::path::append(Result, *FileI);
272static std::vector<std::unique_ptr<TagNode>>
274 std::vector<std::unique_ptr<TagNode>>
Out;
276 auto LinkNode = std::make_unique<TagNode>(HTMLTag::TAG_LINK);
277 LinkNode->Attributes.emplace_back(
"rel",
"stylesheet");
279 llvm::sys::path::append(StylesheetPath,
280 llvm::sys::path::filename(FilePath));
282 llvm::sys::path::native(StylesheetPath, llvm::sys::path::Style::posix);
283 LinkNode->Attributes.emplace_back(
"href", std::string(StylesheetPath));
284 Out.emplace_back(std::move(LinkNode));
289static std::vector<std::unique_ptr<TagNode>>
291 std::vector<std::unique_ptr<TagNode>>
Out;
292 for (
const auto &FilePath : CDCtx.
JsScripts) {
293 auto ScriptNode = std::make_unique<TagNode>(HTMLTag::TAG_SCRIPT);
295 llvm::sys::path::append(ScriptPath, llvm::sys::path::filename(FilePath));
297 llvm::sys::path::native(ScriptPath, llvm::sys::path::Style::posix);
298 ScriptNode->Attributes.emplace_back(
"src", std::string(ScriptPath));
299 Out.emplace_back(std::move(ScriptNode));
304static std::unique_ptr<TagNode>
genLink(
const Twine &
Text,
const Twine &Link) {
305 auto LinkNode = std::make_unique<TagNode>(HTMLTag::TAG_A,
Text);
306 LinkNode->Attributes.emplace_back(
"href", Link.str());
310static std::unique_ptr<HTMLNode>
312 std::optional<StringRef> JumpToSection = std::nullopt) {
313 if (
Type.Path.empty()) {
315 return std::make_unique<TextNode>(
Type.Name);
319 llvm::SmallString<64>
Path =
Type.getRelativeFilePath(CurrentDirectory);
320 llvm::sys::path::append(
Path,
Type.getFileBaseName() +
".html");
323 llvm::sys::path::native(
Path, llvm::sys::path::Style::posix);
325 Path += (
"#" + *JumpToSection).str();
329static std::vector<std::unique_ptr<HTMLNode>>
331 const StringRef &CurrentDirectory) {
332 std::vector<std::unique_ptr<HTMLNode>>
Out;
333 for (
const auto &R : Refs) {
334 if (&R != Refs.begin())
335 Out.emplace_back(std::make_unique<TextNode>(
", "));
341static std::vector<std::unique_ptr<TagNode>>
342genHTML(
const EnumInfo &I,
const ClangDocContext &CDCtx);
343static std::vector<std::unique_ptr<TagNode>>
344genHTML(
const FunctionInfo &I,
const ClangDocContext &CDCtx,
345 StringRef ParentInfoDir);
347static std::vector<std::unique_ptr<TagNode>>
353 std::vector<std::unique_ptr<TagNode>>
Out;
354 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2,
"Enums"));
355 Out.back()->Attributes.emplace_back(
"id",
"Enums");
356 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_DIV));
357 auto &DivBody =
Out.back();
358 for (
const auto &
E : Enums) {
359 std::vector<std::unique_ptr<TagNode>> Nodes =
genHTML(
E, CDCtx);
365static std::unique_ptr<TagNode>
370 auto List = std::make_unique<TagNode>(HTMLTag::TAG_UL);
371 for (
const auto &
M : Members)
372 List->Children.emplace_back(
373 std::make_unique<TagNode>(HTMLTag::TAG_LI,
M.Name));
377static std::vector<std::unique_ptr<TagNode>>
380 if (Functions.empty())
383 std::vector<std::unique_ptr<TagNode>>
Out;
384 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2,
"Functions"));
385 Out.back()->Attributes.emplace_back(
"id",
"Functions");
386 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_DIV));
387 auto &DivBody =
Out.back();
388 for (
const auto &F : Functions) {
389 std::vector<std::unique_ptr<TagNode>> Nodes =
390 genHTML(F, CDCtx, ParentInfoDir);
396static std::vector<std::unique_ptr<TagNode>>
398 StringRef ParentInfoDir) {
402 std::vector<std::unique_ptr<TagNode>>
Out;
403 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2,
"Members"));
404 Out.back()->Attributes.emplace_back(
"id",
"Members");
405 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_UL));
406 auto &ULBody =
Out.back();
407 for (
const auto &
M : Members) {
408 std::string Access = getAccessSpelling(
M.Access).str();
410 Access = Access +
" ";
411 auto LIBody = std::make_unique<TagNode>(HTMLTag::TAG_LI);
412 LIBody->Children.emplace_back(std::make_unique<TextNode>(Access));
413 LIBody->Children.emplace_back(
genReference(
M.Type, ParentInfoDir));
414 LIBody->Children.emplace_back(std::make_unique<TextNode>(
" " +
M.Name));
415 ULBody->Children.emplace_back(std::move(LIBody));
420static std::vector<std::unique_ptr<TagNode>>
422 llvm::StringRef Title, StringRef ParentPath) {
426 std::vector<std::unique_ptr<TagNode>>
Out;
427 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2, Title));
428 Out.back()->Attributes.emplace_back(
"id", std::string(Title));
429 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_UL));
430 auto &ULBody =
Out.back();
432 auto LiNode = std::make_unique<TagNode>(HTMLTag::TAG_LI);
433 LiNode->Children.emplace_back(
genReference(R, ParentPath));
434 ULBody->Children.emplace_back(std::move(LiNode));
439static std::unique_ptr<TagNode>
443 return std::make_unique<TagNode>(
444 HTMLTag::TAG_P,
"Defined at line " + std::to_string(L.LineNumber) +
445 " of file " + L.Filename);
447 llvm::sys::path::append(FileURL, llvm::sys::path::Style::posix, L.Filename);
448 auto Node = std::make_unique<TagNode>(HTMLTag::TAG_P);
449 Node->Children.emplace_back(std::make_unique<TextNode>(
"Defined at line "));
451 std::make_unique<TagNode>(HTMLTag::TAG_A, std::to_string(L.LineNumber));
454 LocNumberNode->Attributes.emplace_back(
455 "href", (FileURL +
"#" + std::to_string(L.LineNumber)).str());
456 Node->Children.emplace_back(std::move(LocNumberNode));
457 Node->Children.emplace_back(std::make_unique<TextNode>(
" of file "));
458 auto LocFileNode = std::make_unique<TagNode>(
459 HTMLTag::TAG_A, llvm::sys::path::filename(FileURL));
460 LocFileNode->Attributes.emplace_back(
"href", std::string(FileURL));
461 Node->Children.emplace_back(std::move(LocFileNode));
465static std::vector<std::unique_ptr<TagNode>>
466genHTML(
const Index &Index, StringRef InfoPath,
bool IsOutermostList);
471static std::vector<std::unique_ptr<TagNode>>
474 std::vector<std::unique_ptr<TagNode>>
Out;
475 auto MetaNode = std::make_unique<TagNode>(HTMLTag::TAG_META);
476 MetaNode->Attributes.emplace_back(
"charset",
"utf-8");
477 Out.emplace_back(std::move(MetaNode));
478 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_TITLE, Title));
479 std::vector<std::unique_ptr<TagNode>> StylesheetsNodes =
482 std::vector<std::unique_ptr<TagNode>> JsNodes =
491 auto HeaderNode = std::make_unique<TagNode>(HTMLTag::TAG_HEADER,
ProjectName);
492 HeaderNode->Attributes.emplace_back(
"id",
"project-title");
502 std::vector<std::unique_ptr<TagNode>> &MainContentInnerNodes,
503 const Index &InfoIndex) {
504 auto MainNode = std::make_unique<TagNode>(HTMLTag::TAG_MAIN);
506 auto LeftSidebarNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
507 LeftSidebarNode->Attributes.emplace_back(
"id",
"sidebar-left");
508 LeftSidebarNode->Attributes.emplace_back(
"path", std::string(InfoPath));
509 LeftSidebarNode->Attributes.emplace_back(
510 "class",
"col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left");
512 auto MainContentNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
513 MainContentNode->Attributes.emplace_back(
"id",
"main-content");
514 MainContentNode->Attributes.emplace_back(
515 "class",
"col-xs-12 col-sm-9 col-md-8 main-content");
516 AppendVector(std::move(MainContentInnerNodes), MainContentNode->Children);
518 auto RightSidebarNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
519 RightSidebarNode->Attributes.emplace_back(
"id",
"sidebar-right");
520 RightSidebarNode->Attributes.emplace_back(
521 "class",
"col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right");
522 std::vector<std::unique_ptr<TagNode>> InfoIndexHTML =
523 genHTML(InfoIndex, InfoPath,
true);
524 AppendVector(std::move(InfoIndexHTML), RightSidebarNode->Children);
526 MainNode->Children.emplace_back(std::move(LeftSidebarNode));
527 MainNode->Children.emplace_back(std::move(MainContentNode));
528 MainNode->Children.emplace_back(std::move(RightSidebarNode));
536 auto FooterNode = std::make_unique<TagNode>(HTMLTag::TAG_FOOTER);
537 auto SpanNode = std::make_unique<TagNode>(
538 HTMLTag::TAG_SPAN, clang::getClangToolFullVersion(
"clang-doc"));
539 SpanNode->Attributes.emplace_back(
"class",
"no-break");
540 FooterNode->Children.emplace_back(std::move(SpanNode));
547 std::vector<std::unique_ptr<TagNode>> &MainContentNodes,
551 std::vector<std::unique_ptr<TagNode>> HeadNodes =
554 std::unique_ptr<TagNode> MainNode =
559 F.Children.emplace_back(std::move(HeaderNode));
560 F.Children.emplace_back(std::move(MainNode));
561 F.Children.emplace_back(std::move(FooterNode));
567 typename = std::enable_if<std::is_base_of<T, Info>::value>>
569 Index Idx(Title, Title);
570 for (
const auto &
C : Infos)
571 Idx.
Children.emplace_back(
C.extractName(),
572 llvm::toHex(llvm::toStringRef(
C.USR)));
576static std::vector<std::unique_ptr<TagNode>>
578 std::vector<std::unique_ptr<TagNode>>
Out;
580 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_SPAN));
581 auto &SpanBody =
Out.back();
585 SpanBody->Children.emplace_back(
591 HTMLTag ListHTMLTag = IsOutermostList ? HTMLTag::TAG_OL : HTMLTag::TAG_UL;
592 Out.emplace_back(std::make_unique<TagNode>(ListHTMLTag));
593 const auto &UlBody =
Out.back();
595 auto LiBody = std::make_unique<TagNode>(HTMLTag::TAG_LI);
596 std::vector<std::unique_ptr<TagNode>> Nodes =
genHTML(
C, InfoPath,
false);
598 UlBody->Children.emplace_back(std::move(LiBody));
604 if (I.
Kind ==
"FullComment") {
605 auto FullComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
606 for (
const auto &Child : I.
Children) {
609 FullComment->Children.emplace_back(std::move(
Node));
611 return std::move(FullComment);
612 }
else if (I.
Kind ==
"ParagraphComment") {
613 auto ParagraphComment = std::make_unique<TagNode>(HTMLTag::TAG_P);
614 for (
const auto &Child : I.
Children) {
617 ParagraphComment->Children.emplace_back(std::move(
Node));
619 if (ParagraphComment->Children.empty())
621 return std::move(ParagraphComment);
622 }
else if (I.
Kind ==
"TextComment") {
625 return std::make_unique<TextNode>(I.
Text);
630static std::unique_ptr<TagNode>
genHTML(
const std::vector<CommentInfo> &
C) {
631 auto CommentBlock = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
632 for (
const auto &Child :
C) {
633 if (std::unique_ptr<HTMLNode>
Node =
genHTML(Child))
634 CommentBlock->Children.emplace_back(std::move(
Node));
639static std::vector<std::unique_ptr<TagNode>>
641 std::vector<std::unique_ptr<TagNode>>
Out;
642 std::string EnumType;
644 EnumType =
"enum class ";
649 std::make_unique<TagNode>(HTMLTag::TAG_H3, EnumType + I.
Name));
650 Out.back()->Attributes.emplace_back(
"id",
651 llvm::toHex(llvm::toStringRef(I.
USR)));
655 Out.emplace_back(std::move(
Node));
662 *I.
DefLoc, StringRef{*CDCtx.RepositoryUrl}));
665 std::string Description;
672static std::vector<std::unique_ptr<TagNode>>
674 StringRef ParentInfoDir) {
675 std::vector<std::unique_ptr<TagNode>>
Out;
676 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H3, I.
Name));
679 Out.back()->Attributes.emplace_back(
"id",
680 llvm::toHex(llvm::toStringRef(I.
USR)));
682 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_P));
683 auto &FunctionHeader =
Out.back();
685 std::string Access = getAccessSpelling(I.
Access).str();
687 FunctionHeader->Children.emplace_back(
688 std::make_unique<TextNode>(Access +
" "));
690 FunctionHeader->Children.emplace_back(
692 FunctionHeader->Children.emplace_back(std::make_unique<TextNode>(
" "));
694 FunctionHeader->Children.emplace_back(
695 std::make_unique<TextNode>(I.
Name +
"("));
697 for (
const auto &P : I.
Params) {
698 if (&P != I.
Params.begin())
699 FunctionHeader->Children.emplace_back(std::make_unique<TextNode>(
", "));
700 FunctionHeader->Children.emplace_back(
genReference(P.Type, ParentInfoDir));
701 FunctionHeader->Children.emplace_back(
702 std::make_unique<TextNode>(
" " + P.Name));
704 FunctionHeader->Children.emplace_back(std::make_unique<TextNode>(
")"));
711 *I.
DefLoc, StringRef{*CDCtx.RepositoryUrl}));
714 std::string Description;
721static std::vector<std::unique_ptr<TagNode>>
723 std::string &InfoTitle) {
724 std::vector<std::unique_ptr<TagNode>>
Out;
725 if (I.
Name.str() ==
"")
726 InfoTitle =
"Global Namespace";
728 InfoTitle = (
"namespace " + I.
Name).str();
730 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
732 std::string Description;
738 std::vector<std::unique_ptr<TagNode>> ChildNamespaces =
741 std::vector<std::unique_ptr<TagNode>> ChildRecords =
745 std::vector<std::unique_ptr<TagNode>> ChildFunctions =
748 std::vector<std::unique_ptr<TagNode>> ChildEnums =
753 InfoIndex.
Children.emplace_back(
"Namespaces",
"Namespaces");
755 InfoIndex.
Children.emplace_back(
"Records",
"Records");
766static std::vector<std::unique_ptr<TagNode>>
768 std::string &InfoTitle) {
769 std::vector<std::unique_ptr<TagNode>>
Out;
771 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
778 *I.
DefLoc, StringRef{*CDCtx.RepositoryUrl}));
781 std::string Description;
785 std::vector<std::unique_ptr<HTMLNode>> Parents =
787 std::vector<std::unique_ptr<HTMLNode>> VParents =
789 if (!Parents.empty() || !VParents.empty()) {
790 Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_P));
791 auto &PBody =
Out.back();
792 PBody->Children.emplace_back(std::make_unique<TextNode>(
"Inherits from "));
795 else if (VParents.empty())
799 PBody->Children.emplace_back(std::make_unique<TextNode>(
", "));
804 std::vector<std::unique_ptr<TagNode>> Members =
807 std::vector<std::unique_ptr<TagNode>> ChildRecords =
811 std::vector<std::unique_ptr<TagNode>> ChildFunctions =
814 std::vector<std::unique_ptr<TagNode>> ChildEnums =
819 InfoIndex.
Children.emplace_back(
"Members",
"Members");
821 InfoIndex.
Children.emplace_back(
"Records",
"Records");
832static std::vector<std::unique_ptr<TagNode>>
834 std::string &InfoTitle) {
845 llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
856 llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
859 llvm::StringSet<> CreatedDirs;
862 llvm::StringMap<std::vector<doc::Info *>> FileToInfos;
863 for (
const auto &Group : Infos) {
866 llvm::SmallString<128>
Path;
867 llvm::sys::path::native(RootDir,
Path);
869 if (!CreatedDirs.contains(
Path)) {
870 if (std::error_code Err = llvm::sys::fs::create_directories(
Path);
871 Err != std::error_code()) {
872 return llvm::createStringError(Err,
"Failed to create directory '%s'.",
875 CreatedDirs.insert(
Path);
882 for (
const auto &Group : FileToInfos) {
883 std::error_code FileErr;
884 llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr,
885 llvm::sys::fs::OF_None);
887 return llvm::createStringError(FileErr,
"Error opening file '%s'",
888 Group.getKey().str().c_str());
897 for (
const auto &
Info : Group.getValue()) {
904 return llvm::Error::success();
909 std::string InfoTitle;
910 std::vector<std::unique_ptr<TagNode>> MainContentNodes;
915 InfoIndex, CDCtx, InfoTitle);
919 InfoIndex, CDCtx, InfoTitle);
933 return llvm::createStringError(llvm::inconvertibleErrorCode(),
934 "unexpected info type");
938 MainContentNodes, InfoIndex, CDCtx);
941 return llvm::Error::success();
959 llvm_unreachable(
"Unknown InfoType");
964 std::error_code FileErr;
965 llvm::SmallString<128> FilePath;
967 llvm::sys::path::append(FilePath,
"index_json.js");
968 llvm::raw_fd_ostream
OS(FilePath, FileErr, llvm::sys::fs::OF_None);
970 return llvm::createStringError(llvm::inconvertibleErrorCode(),
971 "error creating index file: " +
975 llvm::json::OStream J(
OS, 2);
976 std::function<void(
Index)> IndexToJSON = [&](
const Index &I) {
978 J.attribute(
"USR", toHex(llvm::toStringRef(I.USR)));
979 J.attribute(
"Name", I.Name);
980 J.attribute(
"RefType",
getRefType(I.RefType));
981 J.attribute(
"Path", I.getRelativeFilePath(
""));
982 J.attributeArray(
"Children", [&] {
983 for (
const Index &
C : I.Children)
988 OS <<
"var JsonIndex = `\n";
989 IndexToJSON(CDCtx.
Idx);
991 return llvm::Error::success();
998 auto MainNode = std::make_unique<TagNode>(HTMLTag::TAG_MAIN);
1000 auto LeftSidebarNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
1001 LeftSidebarNode->Attributes.emplace_back(
"id",
"sidebar-left");
1002 LeftSidebarNode->Attributes.emplace_back(
"path",
"");
1003 LeftSidebarNode->Attributes.emplace_back(
1004 "class",
"col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left");
1005 LeftSidebarNode->Attributes.emplace_back(
"style",
"flex: 0 100%;");
1007 MainNode->Children.emplace_back(std::move(LeftSidebarNode));
1013 std::error_code FileErr, OK;
1014 llvm::SmallString<128> IndexPath;
1015 llvm::sys::path::native(CDCtx.
OutDirectory, IndexPath);
1016 llvm::sys::path::append(IndexPath,
"index.html");
1017 llvm::raw_fd_ostream IndexOS(IndexPath, FileErr, llvm::sys::fs::OF_None);
1018 if (FileErr != OK) {
1019 return llvm::createStringError(llvm::inconvertibleErrorCode(),
1020 "error creating main index: " +
1026 std::vector<std::unique_ptr<TagNode>> HeadNodes =
1033 F.Children.emplace_back(std::move(HeaderNode));
1034 F.Children.emplace_back(std::move(MainNode));
1035 F.Children.emplace_back(std::move(FooterNode));
1039 return llvm::Error::success();
1043 llvm::SmallString<128> PathWrite;
1045 llvm::sys::path::append(PathWrite, llvm::sys::path::filename(FilePath));
1046 llvm::SmallString<128> PathRead;
1047 llvm::sys::path::native(FilePath, PathRead);
1049 std::error_code FileErr = llvm::sys::fs::copy_file(PathRead, PathWrite);
1050 if (FileErr != OK) {
1051 return llvm::createStringError(llvm::inconvertibleErrorCode(),
1052 "error creating file " +
1053 llvm::sys::path::filename(FilePath) +
1054 ": " + FileErr.message() +
"\n");
1056 return llvm::Error::success();
1077 return llvm::Error::success();
1081 "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 llvm::Error SerializeIndex(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 llvm::Error GenIndex(const ClangDocContext &CDCtx)
static std::vector< std::unique_ptr< HTMLNode > > genReferenceList(const llvm::SmallVectorImpl< Reference > &Refs, const StringRef &CurrentDirectory)
static llvm::Error CopyFile(StringRef FilePath, StringRef OutDirectory)
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 void AppendVector(std::vector< Derived > &&New, std::vector< Base > &Original)
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 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 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 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
std::vector< std::string > FilesToCopy
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