HTMLGenerator.cpp 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088
  1. //===-- HTMLGenerator.cpp - HTML Generator ----------------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "Generators.h"
  9. #include "Representation.h"
  10. #include "clang/Basic/Version.h"
  11. #include "llvm/ADT/StringExtras.h"
  12. #include "llvm/ADT/StringRef.h"
  13. #include "llvm/ADT/StringSet.h"
  14. #include "llvm/Support/FileSystem.h"
  15. #include "llvm/Support/JSON.h"
  16. #include "llvm/Support/Path.h"
  17. #include "llvm/Support/raw_ostream.h"
  18. #include <optional>
  19. #include <string>
  20. using namespace llvm;
  21. namespace clang {
  22. namespace doc {
  23. namespace {
  24. class HTMLTag {
  25. public:
  26. // Any other tag can be added if required
  27. enum TagType {
  28. TAG_A,
  29. TAG_DIV,
  30. TAG_FOOTER,
  31. TAG_H1,
  32. TAG_H2,
  33. TAG_H3,
  34. TAG_HEADER,
  35. TAG_LI,
  36. TAG_LINK,
  37. TAG_MAIN,
  38. TAG_META,
  39. TAG_OL,
  40. TAG_P,
  41. TAG_SCRIPT,
  42. TAG_SPAN,
  43. TAG_TITLE,
  44. TAG_UL,
  45. };
  46. HTMLTag() = default;
  47. constexpr HTMLTag(TagType Value) : Value(Value) {}
  48. operator TagType() const { return Value; }
  49. operator bool() = delete;
  50. bool IsSelfClosing() const;
  51. llvm::SmallString<16> ToString() const;
  52. private:
  53. TagType Value;
  54. };
  55. enum NodeType {
  56. NODE_TEXT,
  57. NODE_TAG,
  58. };
  59. struct HTMLNode {
  60. HTMLNode(NodeType Type) : Type(Type) {}
  61. virtual ~HTMLNode() = default;
  62. virtual void Render(llvm::raw_ostream &OS, int IndentationLevel) = 0;
  63. NodeType Type; // Type of node
  64. };
  65. struct TextNode : public HTMLNode {
  66. TextNode(const Twine &Text)
  67. : HTMLNode(NodeType::NODE_TEXT), Text(Text.str()) {}
  68. std::string Text; // Content of node
  69. void Render(llvm::raw_ostream &OS, int IndentationLevel) override;
  70. };
  71. struct TagNode : public HTMLNode {
  72. TagNode(HTMLTag Tag) : HTMLNode(NodeType::NODE_TAG), Tag(Tag) {}
  73. TagNode(HTMLTag Tag, const Twine &Text) : TagNode(Tag) {
  74. Children.emplace_back(std::make_unique<TextNode>(Text.str()));
  75. }
  76. HTMLTag Tag; // Name of HTML Tag (p, div, h1)
  77. std::vector<std::unique_ptr<HTMLNode>> Children; // List of child nodes
  78. std::vector<std::pair<std::string, std::string>>
  79. Attributes; // List of key-value attributes for tag
  80. void Render(llvm::raw_ostream &OS, int IndentationLevel) override;
  81. };
  82. constexpr const char *kDoctypeDecl = "<!DOCTYPE html>";
  83. struct HTMLFile {
  84. std::vector<std::unique_ptr<HTMLNode>> Children; // List of child nodes
  85. void Render(llvm::raw_ostream &OS) {
  86. OS << kDoctypeDecl << "\n";
  87. for (const auto &C : Children) {
  88. C->Render(OS, 0);
  89. OS << "\n";
  90. }
  91. }
  92. };
  93. } // namespace
  94. bool HTMLTag::IsSelfClosing() const {
  95. switch (Value) {
  96. case HTMLTag::TAG_META:
  97. case HTMLTag::TAG_LINK:
  98. return true;
  99. case HTMLTag::TAG_A:
  100. case HTMLTag::TAG_DIV:
  101. case HTMLTag::TAG_FOOTER:
  102. case HTMLTag::TAG_H1:
  103. case HTMLTag::TAG_H2:
  104. case HTMLTag::TAG_H3:
  105. case HTMLTag::TAG_HEADER:
  106. case HTMLTag::TAG_LI:
  107. case HTMLTag::TAG_MAIN:
  108. case HTMLTag::TAG_OL:
  109. case HTMLTag::TAG_P:
  110. case HTMLTag::TAG_SCRIPT:
  111. case HTMLTag::TAG_SPAN:
  112. case HTMLTag::TAG_TITLE:
  113. case HTMLTag::TAG_UL:
  114. return false;
  115. }
  116. llvm_unreachable("Unhandled HTMLTag::TagType");
  117. }
  118. llvm::SmallString<16> HTMLTag::ToString() const {
  119. switch (Value) {
  120. case HTMLTag::TAG_A:
  121. return llvm::SmallString<16>("a");
  122. case HTMLTag::TAG_DIV:
  123. return llvm::SmallString<16>("div");
  124. case HTMLTag::TAG_FOOTER:
  125. return llvm::SmallString<16>("footer");
  126. case HTMLTag::TAG_H1:
  127. return llvm::SmallString<16>("h1");
  128. case HTMLTag::TAG_H2:
  129. return llvm::SmallString<16>("h2");
  130. case HTMLTag::TAG_H3:
  131. return llvm::SmallString<16>("h3");
  132. case HTMLTag::TAG_HEADER:
  133. return llvm::SmallString<16>("header");
  134. case HTMLTag::TAG_LI:
  135. return llvm::SmallString<16>("li");
  136. case HTMLTag::TAG_LINK:
  137. return llvm::SmallString<16>("link");
  138. case HTMLTag::TAG_MAIN:
  139. return llvm::SmallString<16>("main");
  140. case HTMLTag::TAG_META:
  141. return llvm::SmallString<16>("meta");
  142. case HTMLTag::TAG_OL:
  143. return llvm::SmallString<16>("ol");
  144. case HTMLTag::TAG_P:
  145. return llvm::SmallString<16>("p");
  146. case HTMLTag::TAG_SCRIPT:
  147. return llvm::SmallString<16>("script");
  148. case HTMLTag::TAG_SPAN:
  149. return llvm::SmallString<16>("span");
  150. case HTMLTag::TAG_TITLE:
  151. return llvm::SmallString<16>("title");
  152. case HTMLTag::TAG_UL:
  153. return llvm::SmallString<16>("ul");
  154. }
  155. llvm_unreachable("Unhandled HTMLTag::TagType");
  156. }
  157. void TextNode::Render(llvm::raw_ostream &OS, int IndentationLevel) {
  158. OS.indent(IndentationLevel * 2);
  159. printHTMLEscaped(Text, OS);
  160. }
  161. void TagNode::Render(llvm::raw_ostream &OS, int IndentationLevel) {
  162. // Children nodes are rendered in the same line if all of them are text nodes
  163. bool InlineChildren = true;
  164. for (const auto &C : Children)
  165. if (C->Type == NodeType::NODE_TAG) {
  166. InlineChildren = false;
  167. break;
  168. }
  169. OS.indent(IndentationLevel * 2);
  170. OS << "<" << Tag.ToString();
  171. for (const auto &A : Attributes)
  172. OS << " " << A.first << "=\"" << A.second << "\"";
  173. if (Tag.IsSelfClosing()) {
  174. OS << "/>";
  175. return;
  176. }
  177. OS << ">";
  178. if (!InlineChildren)
  179. OS << "\n";
  180. bool NewLineRendered = true;
  181. for (const auto &C : Children) {
  182. int ChildrenIndentation =
  183. InlineChildren || !NewLineRendered ? 0 : IndentationLevel + 1;
  184. C->Render(OS, ChildrenIndentation);
  185. if (!InlineChildren && (C == Children.back() ||
  186. (C->Type != NodeType::NODE_TEXT ||
  187. (&C + 1)->get()->Type != NodeType::NODE_TEXT))) {
  188. OS << "\n";
  189. NewLineRendered = true;
  190. } else
  191. NewLineRendered = false;
  192. }
  193. if (!InlineChildren)
  194. OS.indent(IndentationLevel * 2);
  195. OS << "</" << Tag.ToString() << ">";
  196. }
  197. template <typename Derived, typename Base,
  198. typename = std::enable_if<std::is_base_of<Derived, Base>::value>>
  199. static void AppendVector(std::vector<Derived> &&New,
  200. std::vector<Base> &Original) {
  201. std::move(New.begin(), New.end(), std::back_inserter(Original));
  202. }
  203. // Compute the relative path from an Origin directory to a Destination directory
  204. static SmallString<128> computeRelativePath(StringRef Destination,
  205. StringRef Origin) {
  206. // If Origin is empty, the relative path to the Destination is its complete
  207. // path.
  208. if (Origin.empty())
  209. return Destination;
  210. // The relative path is an empty path if both directories are the same.
  211. if (Destination == Origin)
  212. return {};
  213. // These iterators iterate through each of their parent directories
  214. llvm::sys::path::const_iterator FileI = llvm::sys::path::begin(Destination);
  215. llvm::sys::path::const_iterator FileE = llvm::sys::path::end(Destination);
  216. llvm::sys::path::const_iterator DirI = llvm::sys::path::begin(Origin);
  217. llvm::sys::path::const_iterator DirE = llvm::sys::path::end(Origin);
  218. // Advance both iterators until the paths differ. Example:
  219. // Destination = A/B/C/D
  220. // Origin = A/B/E/F
  221. // FileI will point to C and DirI to E. The directories behind them is the
  222. // directory they share (A/B).
  223. while (FileI != FileE && DirI != DirE && *FileI == *DirI) {
  224. ++FileI;
  225. ++DirI;
  226. }
  227. SmallString<128> Result; // This will hold the resulting path.
  228. // Result has to go up one directory for each of the remaining directories in
  229. // Origin
  230. while (DirI != DirE) {
  231. llvm::sys::path::append(Result, "..");
  232. ++DirI;
  233. }
  234. // Result has to append each of the remaining directories in Destination
  235. while (FileI != FileE) {
  236. llvm::sys::path::append(Result, *FileI);
  237. ++FileI;
  238. }
  239. return Result;
  240. }
  241. // HTML generation
  242. static std::vector<std::unique_ptr<TagNode>>
  243. genStylesheetsHTML(StringRef InfoPath, const ClangDocContext &CDCtx) {
  244. std::vector<std::unique_ptr<TagNode>> Out;
  245. for (const auto &FilePath : CDCtx.UserStylesheets) {
  246. auto LinkNode = std::make_unique<TagNode>(HTMLTag::TAG_LINK);
  247. LinkNode->Attributes.emplace_back("rel", "stylesheet");
  248. SmallString<128> StylesheetPath = computeRelativePath("", InfoPath);
  249. llvm::sys::path::append(StylesheetPath,
  250. llvm::sys::path::filename(FilePath));
  251. // Paths in HTML must be in posix-style
  252. llvm::sys::path::native(StylesheetPath, llvm::sys::path::Style::posix);
  253. LinkNode->Attributes.emplace_back("href", std::string(StylesheetPath.str()));
  254. Out.emplace_back(std::move(LinkNode));
  255. }
  256. return Out;
  257. }
  258. static std::vector<std::unique_ptr<TagNode>>
  259. genJsScriptsHTML(StringRef InfoPath, const ClangDocContext &CDCtx) {
  260. std::vector<std::unique_ptr<TagNode>> Out;
  261. for (const auto &FilePath : CDCtx.JsScripts) {
  262. auto ScriptNode = std::make_unique<TagNode>(HTMLTag::TAG_SCRIPT);
  263. SmallString<128> ScriptPath = computeRelativePath("", InfoPath);
  264. llvm::sys::path::append(ScriptPath, llvm::sys::path::filename(FilePath));
  265. // Paths in HTML must be in posix-style
  266. llvm::sys::path::native(ScriptPath, llvm::sys::path::Style::posix);
  267. ScriptNode->Attributes.emplace_back("src", std::string(ScriptPath.str()));
  268. Out.emplace_back(std::move(ScriptNode));
  269. }
  270. return Out;
  271. }
  272. static std::unique_ptr<TagNode> genLink(const Twine &Text, const Twine &Link) {
  273. auto LinkNode = std::make_unique<TagNode>(HTMLTag::TAG_A, Text);
  274. LinkNode->Attributes.emplace_back("href", Link.str());
  275. return LinkNode;
  276. }
  277. static std::unique_ptr<HTMLNode>
  278. genReference(const Reference &Type, StringRef CurrentDirectory,
  279. std::optional<StringRef> JumpToSection = std::nullopt) {
  280. if (Type.Path.empty()) {
  281. if (!JumpToSection)
  282. return std::make_unique<TextNode>(Type.Name);
  283. else
  284. return genLink(Type.Name, "#" + *JumpToSection);
  285. }
  286. llvm::SmallString<64> Path = Type.getRelativeFilePath(CurrentDirectory);
  287. llvm::sys::path::append(Path, Type.getFileBaseName() + ".html");
  288. // Paths in HTML must be in posix-style
  289. llvm::sys::path::native(Path, llvm::sys::path::Style::posix);
  290. if (JumpToSection)
  291. Path += ("#" + *JumpToSection).str();
  292. return genLink(Type.Name, Path);
  293. }
  294. static std::vector<std::unique_ptr<HTMLNode>>
  295. genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs,
  296. const StringRef &CurrentDirectory) {
  297. std::vector<std::unique_ptr<HTMLNode>> Out;
  298. for (const auto &R : Refs) {
  299. if (&R != Refs.begin())
  300. Out.emplace_back(std::make_unique<TextNode>(", "));
  301. Out.emplace_back(genReference(R, CurrentDirectory));
  302. }
  303. return Out;
  304. }
  305. static std::vector<std::unique_ptr<TagNode>>
  306. genHTML(const EnumInfo &I, const ClangDocContext &CDCtx);
  307. static std::vector<std::unique_ptr<TagNode>>
  308. genHTML(const FunctionInfo &I, const ClangDocContext &CDCtx,
  309. StringRef ParentInfoDir);
  310. static std::vector<std::unique_ptr<TagNode>>
  311. genEnumsBlock(const std::vector<EnumInfo> &Enums,
  312. const ClangDocContext &CDCtx) {
  313. if (Enums.empty())
  314. return {};
  315. std::vector<std::unique_ptr<TagNode>> Out;
  316. Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2, "Enums"));
  317. Out.back()->Attributes.emplace_back("id", "Enums");
  318. Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_DIV));
  319. auto &DivBody = Out.back();
  320. for (const auto &E : Enums) {
  321. std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(E, CDCtx);
  322. AppendVector(std::move(Nodes), DivBody->Children);
  323. }
  324. return Out;
  325. }
  326. static std::unique_ptr<TagNode>
  327. genEnumMembersBlock(const llvm::SmallVector<EnumValueInfo, 4> &Members) {
  328. if (Members.empty())
  329. return nullptr;
  330. auto List = std::make_unique<TagNode>(HTMLTag::TAG_UL);
  331. for (const auto &M : Members)
  332. List->Children.emplace_back(
  333. std::make_unique<TagNode>(HTMLTag::TAG_LI, M.Name));
  334. return List;
  335. }
  336. static std::vector<std::unique_ptr<TagNode>>
  337. genFunctionsBlock(const std::vector<FunctionInfo> &Functions,
  338. const ClangDocContext &CDCtx, StringRef ParentInfoDir) {
  339. if (Functions.empty())
  340. return {};
  341. std::vector<std::unique_ptr<TagNode>> Out;
  342. Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2, "Functions"));
  343. Out.back()->Attributes.emplace_back("id", "Functions");
  344. Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_DIV));
  345. auto &DivBody = Out.back();
  346. for (const auto &F : Functions) {
  347. std::vector<std::unique_ptr<TagNode>> Nodes =
  348. genHTML(F, CDCtx, ParentInfoDir);
  349. AppendVector(std::move(Nodes), DivBody->Children);
  350. }
  351. return Out;
  352. }
  353. static std::vector<std::unique_ptr<TagNode>>
  354. genRecordMembersBlock(const llvm::SmallVector<MemberTypeInfo, 4> &Members,
  355. StringRef ParentInfoDir) {
  356. if (Members.empty())
  357. return {};
  358. std::vector<std::unique_ptr<TagNode>> Out;
  359. Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2, "Members"));
  360. Out.back()->Attributes.emplace_back("id", "Members");
  361. Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_UL));
  362. auto &ULBody = Out.back();
  363. for (const auto &M : Members) {
  364. std::string Access = getAccessSpelling(M.Access).str();
  365. if (Access != "")
  366. Access = Access + " ";
  367. auto LIBody = std::make_unique<TagNode>(HTMLTag::TAG_LI);
  368. LIBody->Children.emplace_back(std::make_unique<TextNode>(Access));
  369. LIBody->Children.emplace_back(genReference(M.Type, ParentInfoDir));
  370. LIBody->Children.emplace_back(std::make_unique<TextNode>(" " + M.Name));
  371. ULBody->Children.emplace_back(std::move(LIBody));
  372. }
  373. return Out;
  374. }
  375. static std::vector<std::unique_ptr<TagNode>>
  376. genReferencesBlock(const std::vector<Reference> &References,
  377. llvm::StringRef Title, StringRef ParentPath) {
  378. if (References.empty())
  379. return {};
  380. std::vector<std::unique_ptr<TagNode>> Out;
  381. Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2, Title));
  382. Out.back()->Attributes.emplace_back("id", std::string(Title));
  383. Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_UL));
  384. auto &ULBody = Out.back();
  385. for (const auto &R : References) {
  386. auto LiNode = std::make_unique<TagNode>(HTMLTag::TAG_LI);
  387. LiNode->Children.emplace_back(genReference(R, ParentPath));
  388. ULBody->Children.emplace_back(std::move(LiNode));
  389. }
  390. return Out;
  391. }
  392. static std::unique_ptr<TagNode>
  393. writeFileDefinition(const Location &L,
  394. std::optional<StringRef> RepositoryUrl = std::nullopt) {
  395. if (!L.IsFileInRootDir || !RepositoryUrl)
  396. return std::make_unique<TagNode>(
  397. HTMLTag::TAG_P, "Defined at line " + std::to_string(L.LineNumber) +
  398. " of file " + L.Filename);
  399. SmallString<128> FileURL(*RepositoryUrl);
  400. llvm::sys::path::append(FileURL, llvm::sys::path::Style::posix, L.Filename);
  401. auto Node = std::make_unique<TagNode>(HTMLTag::TAG_P);
  402. Node->Children.emplace_back(std::make_unique<TextNode>("Defined at line "));
  403. auto LocNumberNode =
  404. std::make_unique<TagNode>(HTMLTag::TAG_A, std::to_string(L.LineNumber));
  405. // The links to a specific line in the source code use the github /
  406. // googlesource notation so it won't work for all hosting pages.
  407. LocNumberNode->Attributes.emplace_back(
  408. "href", (FileURL + "#" + std::to_string(L.LineNumber)).str());
  409. Node->Children.emplace_back(std::move(LocNumberNode));
  410. Node->Children.emplace_back(std::make_unique<TextNode>(" of file "));
  411. auto LocFileNode = std::make_unique<TagNode>(
  412. HTMLTag::TAG_A, llvm::sys::path::filename(FileURL));
  413. LocFileNode->Attributes.emplace_back("href", std::string(FileURL.str()));
  414. Node->Children.emplace_back(std::move(LocFileNode));
  415. return Node;
  416. }
  417. static std::vector<std::unique_ptr<TagNode>>
  418. genHTML(const Index &Index, StringRef InfoPath, bool IsOutermostList);
  419. // Generates a list of child nodes for the HTML head tag
  420. // It contains a meta node, link nodes to import CSS files, and script nodes to
  421. // import JS files
  422. static std::vector<std::unique_ptr<TagNode>>
  423. genFileHeadNodes(StringRef Title, StringRef InfoPath,
  424. const ClangDocContext &CDCtx) {
  425. std::vector<std::unique_ptr<TagNode>> Out;
  426. auto MetaNode = std::make_unique<TagNode>(HTMLTag::TAG_META);
  427. MetaNode->Attributes.emplace_back("charset", "utf-8");
  428. Out.emplace_back(std::move(MetaNode));
  429. Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_TITLE, Title));
  430. std::vector<std::unique_ptr<TagNode>> StylesheetsNodes =
  431. genStylesheetsHTML(InfoPath, CDCtx);
  432. AppendVector(std::move(StylesheetsNodes), Out);
  433. std::vector<std::unique_ptr<TagNode>> JsNodes =
  434. genJsScriptsHTML(InfoPath, CDCtx);
  435. AppendVector(std::move(JsNodes), Out);
  436. return Out;
  437. }
  438. // Generates a header HTML node that can be used for any file
  439. // It contains the project name
  440. static std::unique_ptr<TagNode> genFileHeaderNode(StringRef ProjectName) {
  441. auto HeaderNode = std::make_unique<TagNode>(HTMLTag::TAG_HEADER, ProjectName);
  442. HeaderNode->Attributes.emplace_back("id", "project-title");
  443. return HeaderNode;
  444. }
  445. // Generates a main HTML node that has all the main content of an info file
  446. // It contains both indexes and the info's documented information
  447. // This function should only be used for the info files (not for the file that
  448. // only has the general index)
  449. static std::unique_ptr<TagNode> genInfoFileMainNode(
  450. StringRef InfoPath,
  451. std::vector<std::unique_ptr<TagNode>> &MainContentInnerNodes,
  452. const Index &InfoIndex) {
  453. auto MainNode = std::make_unique<TagNode>(HTMLTag::TAG_MAIN);
  454. auto LeftSidebarNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
  455. LeftSidebarNode->Attributes.emplace_back("id", "sidebar-left");
  456. LeftSidebarNode->Attributes.emplace_back("path", std::string(InfoPath));
  457. LeftSidebarNode->Attributes.emplace_back(
  458. "class", "col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left");
  459. auto MainContentNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
  460. MainContentNode->Attributes.emplace_back("id", "main-content");
  461. MainContentNode->Attributes.emplace_back(
  462. "class", "col-xs-12 col-sm-9 col-md-8 main-content");
  463. AppendVector(std::move(MainContentInnerNodes), MainContentNode->Children);
  464. auto RightSidebarNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
  465. RightSidebarNode->Attributes.emplace_back("id", "sidebar-right");
  466. RightSidebarNode->Attributes.emplace_back(
  467. "class", "col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right");
  468. std::vector<std::unique_ptr<TagNode>> InfoIndexHTML =
  469. genHTML(InfoIndex, InfoPath, true);
  470. AppendVector(std::move(InfoIndexHTML), RightSidebarNode->Children);
  471. MainNode->Children.emplace_back(std::move(LeftSidebarNode));
  472. MainNode->Children.emplace_back(std::move(MainContentNode));
  473. MainNode->Children.emplace_back(std::move(RightSidebarNode));
  474. return MainNode;
  475. }
  476. // Generates a footer HTML node that can be used for any file
  477. // It contains clang-doc's version
  478. static std::unique_ptr<TagNode> genFileFooterNode() {
  479. auto FooterNode = std::make_unique<TagNode>(HTMLTag::TAG_FOOTER);
  480. auto SpanNode = std::make_unique<TagNode>(
  481. HTMLTag::TAG_SPAN, clang::getClangToolFullVersion("clang-doc"));
  482. SpanNode->Attributes.emplace_back("class", "no-break");
  483. FooterNode->Children.emplace_back(std::move(SpanNode));
  484. return FooterNode;
  485. }
  486. // Generates a complete HTMLFile for an Info
  487. static HTMLFile
  488. genInfoFile(StringRef Title, StringRef InfoPath,
  489. std::vector<std::unique_ptr<TagNode>> &MainContentNodes,
  490. const Index &InfoIndex, const ClangDocContext &CDCtx) {
  491. HTMLFile F;
  492. std::vector<std::unique_ptr<TagNode>> HeadNodes =
  493. genFileHeadNodes(Title, InfoPath, CDCtx);
  494. std::unique_ptr<TagNode> HeaderNode = genFileHeaderNode(CDCtx.ProjectName);
  495. std::unique_ptr<TagNode> MainNode =
  496. genInfoFileMainNode(InfoPath, MainContentNodes, InfoIndex);
  497. std::unique_ptr<TagNode> FooterNode = genFileFooterNode();
  498. AppendVector(std::move(HeadNodes), F.Children);
  499. F.Children.emplace_back(std::move(HeaderNode));
  500. F.Children.emplace_back(std::move(MainNode));
  501. F.Children.emplace_back(std::move(FooterNode));
  502. return F;
  503. }
  504. template <typename T,
  505. typename = std::enable_if<std::is_base_of<T, Info>::value>>
  506. static Index genInfoIndexItem(const std::vector<T> &Infos, StringRef Title) {
  507. Index Idx(Title, Title);
  508. for (const auto &C : Infos)
  509. Idx.Children.emplace_back(C.extractName(),
  510. llvm::toHex(llvm::toStringRef(C.USR)));
  511. return Idx;
  512. }
  513. static std::vector<std::unique_ptr<TagNode>>
  514. genHTML(const Index &Index, StringRef InfoPath, bool IsOutermostList) {
  515. std::vector<std::unique_ptr<TagNode>> Out;
  516. if (!Index.Name.empty()) {
  517. Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_SPAN));
  518. auto &SpanBody = Out.back();
  519. if (!Index.JumpToSection)
  520. SpanBody->Children.emplace_back(genReference(Index, InfoPath));
  521. else
  522. SpanBody->Children.emplace_back(
  523. genReference(Index, InfoPath, Index.JumpToSection->str()));
  524. }
  525. if (Index.Children.empty())
  526. return Out;
  527. // Only the outermost list should use ol, the others should use ul
  528. HTMLTag ListHTMLTag = IsOutermostList ? HTMLTag::TAG_OL : HTMLTag::TAG_UL;
  529. Out.emplace_back(std::make_unique<TagNode>(ListHTMLTag));
  530. const auto &UlBody = Out.back();
  531. for (const auto &C : Index.Children) {
  532. auto LiBody = std::make_unique<TagNode>(HTMLTag::TAG_LI);
  533. std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(C, InfoPath, false);
  534. AppendVector(std::move(Nodes), LiBody->Children);
  535. UlBody->Children.emplace_back(std::move(LiBody));
  536. }
  537. return Out;
  538. }
  539. static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) {
  540. if (I.Kind == "FullComment") {
  541. auto FullComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
  542. for (const auto &Child : I.Children) {
  543. std::unique_ptr<HTMLNode> Node = genHTML(*Child);
  544. if (Node)
  545. FullComment->Children.emplace_back(std::move(Node));
  546. }
  547. return std::move(FullComment);
  548. } else if (I.Kind == "ParagraphComment") {
  549. auto ParagraphComment = std::make_unique<TagNode>(HTMLTag::TAG_P);
  550. for (const auto &Child : I.Children) {
  551. std::unique_ptr<HTMLNode> Node = genHTML(*Child);
  552. if (Node)
  553. ParagraphComment->Children.emplace_back(std::move(Node));
  554. }
  555. if (ParagraphComment->Children.empty())
  556. return nullptr;
  557. return std::move(ParagraphComment);
  558. } else if (I.Kind == "TextComment") {
  559. if (I.Text == "")
  560. return nullptr;
  561. return std::make_unique<TextNode>(I.Text);
  562. }
  563. return nullptr;
  564. }
  565. static std::unique_ptr<TagNode> genHTML(const std::vector<CommentInfo> &C) {
  566. auto CommentBlock = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
  567. for (const auto &Child : C) {
  568. if (std::unique_ptr<HTMLNode> Node = genHTML(Child))
  569. CommentBlock->Children.emplace_back(std::move(Node));
  570. }
  571. return CommentBlock;
  572. }
  573. static std::vector<std::unique_ptr<TagNode>>
  574. genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) {
  575. std::vector<std::unique_ptr<TagNode>> Out;
  576. std::string EnumType;
  577. if (I.Scoped)
  578. EnumType = "enum class ";
  579. else
  580. EnumType = "enum ";
  581. Out.emplace_back(
  582. std::make_unique<TagNode>(HTMLTag::TAG_H3, EnumType + I.Name));
  583. Out.back()->Attributes.emplace_back("id",
  584. llvm::toHex(llvm::toStringRef(I.USR)));
  585. std::unique_ptr<TagNode> Node = genEnumMembersBlock(I.Members);
  586. if (Node)
  587. Out.emplace_back(std::move(Node));
  588. if (I.DefLoc) {
  589. if (!CDCtx.RepositoryUrl)
  590. Out.emplace_back(writeFileDefinition(*I.DefLoc));
  591. else
  592. Out.emplace_back(writeFileDefinition(
  593. *I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
  594. }
  595. std::string Description;
  596. if (!I.Description.empty())
  597. Out.emplace_back(genHTML(I.Description));
  598. return Out;
  599. }
  600. static std::vector<std::unique_ptr<TagNode>>
  601. genHTML(const FunctionInfo &I, const ClangDocContext &CDCtx,
  602. StringRef ParentInfoDir) {
  603. std::vector<std::unique_ptr<TagNode>> Out;
  604. Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H3, I.Name));
  605. // USR is used as id for functions instead of name to disambiguate function
  606. // overloads.
  607. Out.back()->Attributes.emplace_back("id",
  608. llvm::toHex(llvm::toStringRef(I.USR)));
  609. Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_P));
  610. auto &FunctionHeader = Out.back();
  611. std::string Access = getAccessSpelling(I.Access).str();
  612. if (Access != "")
  613. FunctionHeader->Children.emplace_back(
  614. std::make_unique<TextNode>(Access + " "));
  615. if (I.ReturnType.Type.Name != "") {
  616. FunctionHeader->Children.emplace_back(
  617. genReference(I.ReturnType.Type, ParentInfoDir));
  618. FunctionHeader->Children.emplace_back(std::make_unique<TextNode>(" "));
  619. }
  620. FunctionHeader->Children.emplace_back(
  621. std::make_unique<TextNode>(I.Name + "("));
  622. for (const auto &P : I.Params) {
  623. if (&P != I.Params.begin())
  624. FunctionHeader->Children.emplace_back(std::make_unique<TextNode>(", "));
  625. FunctionHeader->Children.emplace_back(genReference(P.Type, ParentInfoDir));
  626. FunctionHeader->Children.emplace_back(
  627. std::make_unique<TextNode>(" " + P.Name));
  628. }
  629. FunctionHeader->Children.emplace_back(std::make_unique<TextNode>(")"));
  630. if (I.DefLoc) {
  631. if (!CDCtx.RepositoryUrl)
  632. Out.emplace_back(writeFileDefinition(*I.DefLoc));
  633. else
  634. Out.emplace_back(writeFileDefinition(
  635. *I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
  636. }
  637. std::string Description;
  638. if (!I.Description.empty())
  639. Out.emplace_back(genHTML(I.Description));
  640. return Out;
  641. }
  642. static std::vector<std::unique_ptr<TagNode>>
  643. genHTML(const NamespaceInfo &I, Index &InfoIndex, const ClangDocContext &CDCtx,
  644. std::string &InfoTitle) {
  645. std::vector<std::unique_ptr<TagNode>> Out;
  646. if (I.Name.str() == "")
  647. InfoTitle = "Global Namespace";
  648. else
  649. InfoTitle = ("namespace " + I.Name).str();
  650. Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
  651. std::string Description;
  652. if (!I.Description.empty())
  653. Out.emplace_back(genHTML(I.Description));
  654. llvm::SmallString<64> BasePath = I.getRelativeFilePath("");
  655. std::vector<std::unique_ptr<TagNode>> ChildNamespaces =
  656. genReferencesBlock(I.Children.Namespaces, "Namespaces", BasePath);
  657. AppendVector(std::move(ChildNamespaces), Out);
  658. std::vector<std::unique_ptr<TagNode>> ChildRecords =
  659. genReferencesBlock(I.Children.Records, "Records", BasePath);
  660. AppendVector(std::move(ChildRecords), Out);
  661. std::vector<std::unique_ptr<TagNode>> ChildFunctions =
  662. genFunctionsBlock(I.Children.Functions, CDCtx, BasePath);
  663. AppendVector(std::move(ChildFunctions), Out);
  664. std::vector<std::unique_ptr<TagNode>> ChildEnums =
  665. genEnumsBlock(I.Children.Enums, CDCtx);
  666. AppendVector(std::move(ChildEnums), Out);
  667. if (!I.Children.Namespaces.empty())
  668. InfoIndex.Children.emplace_back("Namespaces", "Namespaces");
  669. if (!I.Children.Records.empty())
  670. InfoIndex.Children.emplace_back("Records", "Records");
  671. if (!I.Children.Functions.empty())
  672. InfoIndex.Children.emplace_back(
  673. genInfoIndexItem(I.Children.Functions, "Functions"));
  674. if (!I.Children.Enums.empty())
  675. InfoIndex.Children.emplace_back(
  676. genInfoIndexItem(I.Children.Enums, "Enums"));
  677. return Out;
  678. }
  679. static std::vector<std::unique_ptr<TagNode>>
  680. genHTML(const RecordInfo &I, Index &InfoIndex, const ClangDocContext &CDCtx,
  681. std::string &InfoTitle) {
  682. std::vector<std::unique_ptr<TagNode>> Out;
  683. InfoTitle = (getTagType(I.TagType) + " " + I.Name).str();
  684. Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
  685. if (I.DefLoc) {
  686. if (!CDCtx.RepositoryUrl)
  687. Out.emplace_back(writeFileDefinition(*I.DefLoc));
  688. else
  689. Out.emplace_back(writeFileDefinition(
  690. *I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
  691. }
  692. std::string Description;
  693. if (!I.Description.empty())
  694. Out.emplace_back(genHTML(I.Description));
  695. std::vector<std::unique_ptr<HTMLNode>> Parents =
  696. genReferenceList(I.Parents, I.Path);
  697. std::vector<std::unique_ptr<HTMLNode>> VParents =
  698. genReferenceList(I.VirtualParents, I.Path);
  699. if (!Parents.empty() || !VParents.empty()) {
  700. Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_P));
  701. auto &PBody = Out.back();
  702. PBody->Children.emplace_back(std::make_unique<TextNode>("Inherits from "));
  703. if (Parents.empty())
  704. AppendVector(std::move(VParents), PBody->Children);
  705. else if (VParents.empty())
  706. AppendVector(std::move(Parents), PBody->Children);
  707. else {
  708. AppendVector(std::move(Parents), PBody->Children);
  709. PBody->Children.emplace_back(std::make_unique<TextNode>(", "));
  710. AppendVector(std::move(VParents), PBody->Children);
  711. }
  712. }
  713. std::vector<std::unique_ptr<TagNode>> Members =
  714. genRecordMembersBlock(I.Members, I.Path);
  715. AppendVector(std::move(Members), Out);
  716. std::vector<std::unique_ptr<TagNode>> ChildRecords =
  717. genReferencesBlock(I.Children.Records, "Records", I.Path);
  718. AppendVector(std::move(ChildRecords), Out);
  719. std::vector<std::unique_ptr<TagNode>> ChildFunctions =
  720. genFunctionsBlock(I.Children.Functions, CDCtx, I.Path);
  721. AppendVector(std::move(ChildFunctions), Out);
  722. std::vector<std::unique_ptr<TagNode>> ChildEnums =
  723. genEnumsBlock(I.Children.Enums, CDCtx);
  724. AppendVector(std::move(ChildEnums), Out);
  725. if (!I.Members.empty())
  726. InfoIndex.Children.emplace_back("Members", "Members");
  727. if (!I.Children.Records.empty())
  728. InfoIndex.Children.emplace_back("Records", "Records");
  729. if (!I.Children.Functions.empty())
  730. InfoIndex.Children.emplace_back(
  731. genInfoIndexItem(I.Children.Functions, "Functions"));
  732. if (!I.Children.Enums.empty())
  733. InfoIndex.Children.emplace_back(
  734. genInfoIndexItem(I.Children.Enums, "Enums"));
  735. return Out;
  736. }
  737. static std::vector<std::unique_ptr<TagNode>>
  738. genHTML(const TypedefInfo &I, const ClangDocContext &CDCtx,
  739. std::string &InfoTitle) {
  740. // TODO support typedefs in HTML.
  741. return {};
  742. }
  743. /// Generator for HTML documentation.
  744. class HTMLGenerator : public Generator {
  745. public:
  746. static const char *Format;
  747. llvm::Error generateDocs(StringRef RootDir,
  748. llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
  749. const ClangDocContext &CDCtx) override;
  750. llvm::Error createResources(ClangDocContext &CDCtx) override;
  751. llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
  752. const ClangDocContext &CDCtx) override;
  753. };
  754. const char *HTMLGenerator::Format = "html";
  755. llvm::Error
  756. HTMLGenerator::generateDocs(StringRef RootDir,
  757. llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
  758. const ClangDocContext &CDCtx) {
  759. // Track which directories we already tried to create.
  760. llvm::StringSet<> CreatedDirs;
  761. // Collect all output by file name and create the nexessary directories.
  762. llvm::StringMap<std::vector<doc::Info *>> FileToInfos;
  763. for (const auto &Group : Infos) {
  764. doc::Info *Info = Group.getValue().get();
  765. llvm::SmallString<128> Path;
  766. llvm::sys::path::native(RootDir, Path);
  767. llvm::sys::path::append(Path, Info->getRelativeFilePath(""));
  768. if (CreatedDirs.find(Path) == CreatedDirs.end()) {
  769. if (std::error_code Err = llvm::sys::fs::create_directories(Path);
  770. Err != std::error_code()) {
  771. return llvm::createStringError(Err, "Failed to create directory '%s'.",
  772. Path.c_str());
  773. }
  774. CreatedDirs.insert(Path);
  775. }
  776. llvm::sys::path::append(Path, Info->getFileBaseName() + ".html");
  777. FileToInfos[Path].push_back(Info);
  778. }
  779. for (const auto &Group : FileToInfos) {
  780. std::error_code FileErr;
  781. llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr,
  782. llvm::sys::fs::OF_None);
  783. if (FileErr) {
  784. return llvm::createStringError(FileErr, "Error opening file '%s'",
  785. Group.getKey().str().c_str());
  786. }
  787. // TODO: https://github.com/llvm/llvm-project/issues/59073
  788. // If there are multiple Infos for this file name (for example, template
  789. // specializations), this will generate multiple complete web pages (with
  790. // <DOCTYPE> and <title>, etc.) concatenated together. This generator needs
  791. // some refactoring to be able to output the headers separately from the
  792. // contents.
  793. for (const auto &Info : Group.getValue()) {
  794. if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) {
  795. return Err;
  796. }
  797. }
  798. }
  799. return llvm::Error::success();
  800. }
  801. llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
  802. const ClangDocContext &CDCtx) {
  803. std::string InfoTitle;
  804. std::vector<std::unique_ptr<TagNode>> MainContentNodes;
  805. Index InfoIndex;
  806. switch (I->IT) {
  807. case InfoType::IT_namespace:
  808. MainContentNodes = genHTML(*static_cast<clang::doc::NamespaceInfo *>(I),
  809. InfoIndex, CDCtx, InfoTitle);
  810. break;
  811. case InfoType::IT_record:
  812. MainContentNodes = genHTML(*static_cast<clang::doc::RecordInfo *>(I),
  813. InfoIndex, CDCtx, InfoTitle);
  814. break;
  815. case InfoType::IT_enum:
  816. MainContentNodes = genHTML(*static_cast<clang::doc::EnumInfo *>(I), CDCtx);
  817. break;
  818. case InfoType::IT_function:
  819. MainContentNodes =
  820. genHTML(*static_cast<clang::doc::FunctionInfo *>(I), CDCtx, "");
  821. break;
  822. case InfoType::IT_typedef:
  823. MainContentNodes =
  824. genHTML(*static_cast<clang::doc::TypedefInfo *>(I), CDCtx, InfoTitle);
  825. break;
  826. case InfoType::IT_default:
  827. return llvm::createStringError(llvm::inconvertibleErrorCode(),
  828. "unexpected info type");
  829. }
  830. HTMLFile F = genInfoFile(InfoTitle, I->getRelativeFilePath(""),
  831. MainContentNodes, InfoIndex, CDCtx);
  832. F.Render(OS);
  833. return llvm::Error::success();
  834. }
  835. static std::string getRefType(InfoType IT) {
  836. switch (IT) {
  837. case InfoType::IT_default:
  838. return "default";
  839. case InfoType::IT_namespace:
  840. return "namespace";
  841. case InfoType::IT_record:
  842. return "record";
  843. case InfoType::IT_function:
  844. return "function";
  845. case InfoType::IT_enum:
  846. return "enum";
  847. case InfoType::IT_typedef:
  848. return "typedef";
  849. }
  850. llvm_unreachable("Unknown InfoType");
  851. }
  852. static llvm::Error SerializeIndex(ClangDocContext &CDCtx) {
  853. std::error_code OK;
  854. std::error_code FileErr;
  855. llvm::SmallString<128> FilePath;
  856. llvm::sys::path::native(CDCtx.OutDirectory, FilePath);
  857. llvm::sys::path::append(FilePath, "index_json.js");
  858. llvm::raw_fd_ostream OS(FilePath, FileErr, llvm::sys::fs::OF_None);
  859. if (FileErr != OK) {
  860. return llvm::createStringError(llvm::inconvertibleErrorCode(),
  861. "error creating index file: " +
  862. FileErr.message());
  863. }
  864. CDCtx.Idx.sort();
  865. llvm::json::OStream J(OS, 2);
  866. std::function<void(Index)> IndexToJSON = [&](const Index &I) {
  867. J.object([&] {
  868. J.attribute("USR", toHex(llvm::toStringRef(I.USR)));
  869. J.attribute("Name", I.Name);
  870. J.attribute("RefType", getRefType(I.RefType));
  871. J.attribute("Path", I.getRelativeFilePath(""));
  872. J.attributeArray("Children", [&] {
  873. for (const Index &C : I.Children)
  874. IndexToJSON(C);
  875. });
  876. });
  877. };
  878. OS << "var JsonIndex = `\n";
  879. IndexToJSON(CDCtx.Idx);
  880. OS << "`;\n";
  881. return llvm::Error::success();
  882. }
  883. // Generates a main HTML node that has the main content of the file that shows
  884. // only the general index
  885. // It contains the general index with links to all the generated files
  886. static std::unique_ptr<TagNode> genIndexFileMainNode() {
  887. auto MainNode = std::make_unique<TagNode>(HTMLTag::TAG_MAIN);
  888. auto LeftSidebarNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
  889. LeftSidebarNode->Attributes.emplace_back("id", "sidebar-left");
  890. LeftSidebarNode->Attributes.emplace_back("path", "");
  891. LeftSidebarNode->Attributes.emplace_back(
  892. "class", "col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left");
  893. LeftSidebarNode->Attributes.emplace_back("style", "flex: 0 100%;");
  894. MainNode->Children.emplace_back(std::move(LeftSidebarNode));
  895. return MainNode;
  896. }
  897. static llvm::Error GenIndex(const ClangDocContext &CDCtx) {
  898. std::error_code FileErr, OK;
  899. llvm::SmallString<128> IndexPath;
  900. llvm::sys::path::native(CDCtx.OutDirectory, IndexPath);
  901. llvm::sys::path::append(IndexPath, "index.html");
  902. llvm::raw_fd_ostream IndexOS(IndexPath, FileErr, llvm::sys::fs::OF_None);
  903. if (FileErr != OK) {
  904. return llvm::createStringError(llvm::inconvertibleErrorCode(),
  905. "error creating main index: " +
  906. FileErr.message());
  907. }
  908. HTMLFile F;
  909. std::vector<std::unique_ptr<TagNode>> HeadNodes =
  910. genFileHeadNodes("Index", "", CDCtx);
  911. std::unique_ptr<TagNode> HeaderNode = genFileHeaderNode(CDCtx.ProjectName);
  912. std::unique_ptr<TagNode> MainNode = genIndexFileMainNode();
  913. std::unique_ptr<TagNode> FooterNode = genFileFooterNode();
  914. AppendVector(std::move(HeadNodes), F.Children);
  915. F.Children.emplace_back(std::move(HeaderNode));
  916. F.Children.emplace_back(std::move(MainNode));
  917. F.Children.emplace_back(std::move(FooterNode));
  918. F.Render(IndexOS);
  919. return llvm::Error::success();
  920. }
  921. static llvm::Error CopyFile(StringRef FilePath, StringRef OutDirectory) {
  922. llvm::SmallString<128> PathWrite;
  923. llvm::sys::path::native(OutDirectory, PathWrite);
  924. llvm::sys::path::append(PathWrite, llvm::sys::path::filename(FilePath));
  925. llvm::SmallString<128> PathRead;
  926. llvm::sys::path::native(FilePath, PathRead);
  927. std::error_code OK;
  928. std::error_code FileErr = llvm::sys::fs::copy_file(PathRead, PathWrite);
  929. if (FileErr != OK) {
  930. return llvm::createStringError(llvm::inconvertibleErrorCode(),
  931. "error creating file " +
  932. llvm::sys::path::filename(FilePath) +
  933. ": " + FileErr.message() + "\n");
  934. }
  935. return llvm::Error::success();
  936. }
  937. llvm::Error HTMLGenerator::createResources(ClangDocContext &CDCtx) {
  938. auto Err = SerializeIndex(CDCtx);
  939. if (Err)
  940. return Err;
  941. Err = GenIndex(CDCtx);
  942. if (Err)
  943. return Err;
  944. for (const auto &FilePath : CDCtx.UserStylesheets) {
  945. Err = CopyFile(FilePath, CDCtx.OutDirectory);
  946. if (Err)
  947. return Err;
  948. }
  949. for (const auto &FilePath : CDCtx.FilesToCopy) {
  950. Err = CopyFile(FilePath, CDCtx.OutDirectory);
  951. if (Err)
  952. return Err;
  953. }
  954. return llvm::Error::success();
  955. }
  956. static GeneratorRegistry::Add<HTMLGenerator> HTML(HTMLGenerator::Format,
  957. "Generator for HTML output.");
  958. // This anchor is used to force the linker to link in the generated object
  959. // file and thus register the generator.
  960. volatile int HTMLGeneratorAnchorSource = 0;
  961. } // namespace doc
  962. } // namespace clang