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 
9 #include "Generators.h"
10 #include "Representation.h"
11 #include "llvm/ADT/StringExtras.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/Support/FileSystem.h"
14 #include "llvm/Support/Path.h"
15 #include <string>
16 
17 using namespace llvm;
18 
19 namespace clang {
20 namespace doc {
21 
22 namespace {
23 
24 class HTMLTag {
25 public:
26   // Any other tag can be added if required
27   enum TagType {
28     TAG_META,
29     TAG_TITLE,
30     TAG_DIV,
31     TAG_H1,
32     TAG_H2,
33     TAG_H3,
34     TAG_P,
35     TAG_UL,
36     TAG_LI,
37     TAG_A,
38     TAG_LINK,
39   };
40 
41   HTMLTag() = default;
42   constexpr HTMLTag(TagType Value) : Value(Value) {}
43 
44   operator TagType() const { return Value; }
45   operator bool() = delete;
46 
47   bool IsSelfClosing() const;
48   llvm::SmallString<16> ToString() const;
49 
50 private:
51   TagType Value;
52 };
53 
54 enum NodeType {
55   NODE_TEXT,
56   NODE_TAG,
57 };
58 
59 struct HTMLNode {
60   HTMLNode(NodeType Type) : Type(Type) {}
61   virtual ~HTMLNode() = default;
62 
63   virtual void Render(llvm::raw_ostream &OS, int IndentationLevel) = 0;
64   NodeType Type; // Type of node
65 };
66 
67 struct TextNode : public HTMLNode {
68   TextNode(const Twine &Text)
69       : HTMLNode(NodeType::NODE_TEXT), Text(Text.str()) {}
70 
71   std::string Text; // Content of node
72   void Render(llvm::raw_ostream &OS, int IndentationLevel) override;
73 };
74 
75 struct TagNode : public HTMLNode {
76   TagNode(HTMLTag Tag) : HTMLNode(NodeType::NODE_TAG), Tag(Tag) {}
77   TagNode(HTMLTag Tag, const Twine &Text) : TagNode(Tag) {
78     Children.emplace_back(llvm::make_unique<TextNode>(Text.str()));
79   }
80 
81   HTMLTag Tag; // Name of HTML Tag (p, div, h1)
82   std::vector<std::unique_ptr<HTMLNode>> Children; // List of child nodes
83   llvm::StringMap<llvm::SmallString<16>>
84       Attributes; // List of key-value attributes for tag
85 
86   void Render(llvm::raw_ostream &OS, int IndentationLevel) override;
87 };
88 
89 constexpr const char *kDoctypeDecl = "<!DOCTYPE html>";
90 
91 struct HTMLFile {
92   std::vector<std::unique_ptr<HTMLNode>> Children; // List of child nodes
93   void Render(llvm::raw_ostream &OS) {
94     OS << kDoctypeDecl << "\n";
95     for (const auto &C : Children) {
96       C->Render(OS, 0);
97       OS << "\n";
98     }
99   }
100 };
101 
102 } // namespace
103 
104 bool HTMLTag::IsSelfClosing() const {
105   switch (Value) {
106   case HTMLTag::TAG_META:
107   case HTMLTag::TAG_LINK:
108     return true;
109   case HTMLTag::TAG_TITLE:
110   case HTMLTag::TAG_DIV:
111   case HTMLTag::TAG_H1:
112   case HTMLTag::TAG_H2:
113   case HTMLTag::TAG_H3:
114   case HTMLTag::TAG_P:
115   case HTMLTag::TAG_UL:
116   case HTMLTag::TAG_LI:
117   case HTMLTag::TAG_A:
118     return false;
119   }
120   llvm_unreachable("Unhandled HTMLTag::TagType");
121 }
122 
123 llvm::SmallString<16> HTMLTag::ToString() const {
124   switch (Value) {
125   case HTMLTag::TAG_META:
126     return llvm::SmallString<16>("meta");
127   case HTMLTag::TAG_TITLE:
128     return llvm::SmallString<16>("title");
129   case HTMLTag::TAG_DIV:
130     return llvm::SmallString<16>("div");
131   case HTMLTag::TAG_H1:
132     return llvm::SmallString<16>("h1");
133   case HTMLTag::TAG_H2:
134     return llvm::SmallString<16>("h2");
135   case HTMLTag::TAG_H3:
136     return llvm::SmallString<16>("h3");
137   case HTMLTag::TAG_P:
138     return llvm::SmallString<16>("p");
139   case HTMLTag::TAG_UL:
140     return llvm::SmallString<16>("ul");
141   case HTMLTag::TAG_LI:
142     return llvm::SmallString<16>("li");
143   case HTMLTag::TAG_A:
144     return llvm::SmallString<16>("a");
145   case HTMLTag::TAG_LINK:
146     return llvm::SmallString<16>("link");
147   }
148   llvm_unreachable("Unhandled HTMLTag::TagType");
149 }
150 
151 void TextNode::Render(llvm::raw_ostream &OS, int IndentationLevel) {
152   OS.indent(IndentationLevel * 2);
153   printHTMLEscaped(Text, OS);
154 }
155 
156 void TagNode::Render(llvm::raw_ostream &OS, int IndentationLevel) {
157   // Children nodes are rendered in the same line if all of them are text nodes
158   bool InlineChildren = true;
159   for (const auto &C : Children)
160     if (C->Type == NodeType::NODE_TAG) {
161       InlineChildren = false;
162       break;
163     }
164   OS.indent(IndentationLevel * 2);
165   OS << "<" << Tag.ToString();
166   for (const auto &A : Attributes)
167     OS << " " << A.getKey() << "=\"" << A.getValue() << "\"";
168   if (Tag.IsSelfClosing()) {
169     OS << "/>";
170     return;
171   }
172   OS << ">";
173   if (!InlineChildren)
174     OS << "\n";
175   bool NewLineRendered = true;
176   for (const auto &C : Children) {
177     int ChildrenIndentation =
178         InlineChildren || !NewLineRendered ? 0 : IndentationLevel + 1;
179     C->Render(OS, ChildrenIndentation);
180     if (!InlineChildren && (C == Children.back() ||
181                             (C->Type != NodeType::NODE_TEXT ||
182                              (&C + 1)->get()->Type != NodeType::NODE_TEXT))) {
183       OS << "\n";
184       NewLineRendered = true;
185     } else
186       NewLineRendered = false;
187   }
188   if (!InlineChildren)
189     OS.indent(IndentationLevel * 2);
190   OS << "</" << Tag.ToString() << ">";
191 }
192 
193 template <typename Derived, typename Base,
194           typename = std::enable_if<std::is_base_of<Derived, Base>::value>>
195 static void AppendVector(std::vector<Derived> &&New,
196                          std::vector<Base> &Original) {
197   std::move(New.begin(), New.end(), std::back_inserter(Original));
198 }
199 
200 // Compute the relative path that names the file path relative to the given
201 // directory.
202 static SmallString<128> computeRelativePath(StringRef FilePath,
203                                             StringRef Directory) {
204   StringRef Path = FilePath;
205   while (!Path.empty()) {
206     if (Directory == Path)
207       return FilePath.substr(Path.size());
208     Path = llvm::sys::path::parent_path(Path);
209   }
210 
211   StringRef Dir = Directory;
212   SmallString<128> Result;
213   while (!Dir.empty()) {
214     if (Dir == FilePath)
215       break;
216     Dir = llvm::sys::path::parent_path(Dir);
217     llvm::sys::path::append(Result, "..");
218   }
219   llvm::sys::path::append(Result, FilePath.substr(Dir.size()));
220   return Result;
221 }
222 
223 // HTML generation
224 
225 std::vector<std::unique_ptr<TagNode>>
226 genStylesheetsHTML(StringRef InfoPath, const ClangDocContext &CDCtx) {
227   std::vector<std::unique_ptr<TagNode>> Out;
228   for (const auto &FilePath : CDCtx.UserStylesheets) {
229     auto LinkNode = llvm::make_unique<TagNode>(HTMLTag::TAG_LINK);
230     LinkNode->Attributes.try_emplace("rel", "stylesheet");
231     SmallString<128> StylesheetPath = computeRelativePath("", InfoPath);
232     llvm::sys::path::append(StylesheetPath,
233                             llvm::sys::path::filename(FilePath));
234     // Paths in HTML must be in posix-style
235     llvm::sys::path::native(StylesheetPath, llvm::sys::path::Style::posix);
236     LinkNode->Attributes.try_emplace("href", StylesheetPath);
237     Out.emplace_back(std::move(LinkNode));
238   }
239   return Out;
240 }
241 
242 static std::unique_ptr<TagNode> genLink(const Twine &Text, const Twine &Link) {
243   auto LinkNode = llvm::make_unique<TagNode>(HTMLTag::TAG_A, Text);
244   LinkNode->Attributes.try_emplace("href", Link.str());
245   return LinkNode;
246 }
247 
248 static std::unique_ptr<HTMLNode> genTypeReference(const Reference &Type,
249                                                   StringRef CurrentDirectory) {
250   if (Type.Path.empty() && !Type.IsInGlobalNamespace)
251     return llvm::make_unique<TextNode>(Type.Name);
252   llvm::SmallString<128> Path =
253       computeRelativePath(Type.Path, CurrentDirectory);
254   llvm::sys::path::append(Path, Type.Name + ".html");
255   // Paths in HTML must be in posix-style
256   llvm::sys::path::native(Path, llvm::sys::path::Style::posix);
257   return genLink(Type.Name, Path);
258 }
259 
260 static std::vector<std::unique_ptr<HTMLNode>>
261 genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs,
262                  const StringRef &CurrentDirectory) {
263   std::vector<std::unique_ptr<HTMLNode>> Out;
264   for (const auto &R : Refs) {
265     if (&R != Refs.begin())
266       Out.emplace_back(llvm::make_unique<TextNode>(", "));
267     Out.emplace_back(genTypeReference(R, CurrentDirectory));
268   }
269   return Out;
270 }
271 
272 static std::vector<std::unique_ptr<TagNode>> genHTML(const EnumInfo &I);
273 static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I,
274                                                      StringRef ParentInfoDir);
275 
276 static std::vector<std::unique_ptr<TagNode>>
277 genEnumsBlock(const std::vector<EnumInfo> &Enums) {
278   if (Enums.empty())
279     return {};
280 
281   std::vector<std::unique_ptr<TagNode>> Out;
282   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H2, "Enums"));
283   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_DIV));
284   auto &DivBody = Out.back();
285   for (const auto &E : Enums) {
286     std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(E);
287     AppendVector(std::move(Nodes), DivBody->Children);
288   }
289   return Out;
290 }
291 
292 static std::unique_ptr<TagNode>
293 genEnumMembersBlock(const llvm::SmallVector<SmallString<16>, 4> &Members) {
294   if (Members.empty())
295     return nullptr;
296 
297   auto List = llvm::make_unique<TagNode>(HTMLTag::TAG_UL);
298   for (const auto &M : Members)
299     List->Children.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_LI, M));
300   return List;
301 }
302 
303 static std::vector<std::unique_ptr<TagNode>>
304 genFunctionsBlock(const std::vector<FunctionInfo> &Functions,
305                   StringRef ParentInfoDir) {
306   if (Functions.empty())
307     return {};
308 
309   std::vector<std::unique_ptr<TagNode>> Out;
310   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H2, "Functions"));
311   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_DIV));
312   auto &DivBody = Out.back();
313   for (const auto &F : Functions) {
314     std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(F, ParentInfoDir);
315     AppendVector(std::move(Nodes), DivBody->Children);
316   }
317   return Out;
318 }
319 
320 static std::vector<std::unique_ptr<TagNode>>
321 genRecordMembersBlock(const llvm::SmallVector<MemberTypeInfo, 4> &Members,
322                       StringRef ParentInfoDir) {
323   if (Members.empty())
324     return {};
325 
326   std::vector<std::unique_ptr<TagNode>> Out;
327   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H2, "Members"));
328   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_UL));
329   auto &ULBody = Out.back();
330   for (const auto &M : Members) {
331     std::string Access = getAccess(M.Access);
332     if (Access != "")
333       Access = Access + " ";
334     auto LIBody = llvm::make_unique<TagNode>(HTMLTag::TAG_LI);
335     LIBody->Children.emplace_back(llvm::make_unique<TextNode>(Access));
336     LIBody->Children.emplace_back(genTypeReference(M.Type, ParentInfoDir));
337     LIBody->Children.emplace_back(llvm::make_unique<TextNode>(" " + M.Name));
338     ULBody->Children.emplace_back(std::move(LIBody));
339   }
340   return Out;
341 }
342 
343 static std::vector<std::unique_ptr<TagNode>>
344 genReferencesBlock(const std::vector<Reference> &References,
345                    llvm::StringRef Title) {
346   if (References.empty())
347     return {};
348 
349   std::vector<std::unique_ptr<TagNode>> Out;
350   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H2, Title));
351   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_UL));
352   auto &ULBody = Out.back();
353   for (const auto &R : References)
354     ULBody->Children.emplace_back(
355         llvm::make_unique<TagNode>(HTMLTag::TAG_LI, R.Name));
356   return Out;
357 }
358 
359 static std::unique_ptr<TagNode> writeFileDefinition(const Location &L) {
360   return llvm::make_unique<TagNode>(
361       HTMLTag::TAG_P,
362       "Defined at line " + std::to_string(L.LineNumber) + " of " + L.Filename);
363 }
364 
365 static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) {
366   if (I.Kind == "FullComment") {
367     auto FullComment = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV);
368     for (const auto &Child : I.Children) {
369       std::unique_ptr<HTMLNode> Node = genHTML(*Child);
370       if (Node)
371         FullComment->Children.emplace_back(std::move(Node));
372     }
373     return std::move(FullComment);
374   } else if (I.Kind == "ParagraphComment") {
375     auto ParagraphComment = llvm::make_unique<TagNode>(HTMLTag::TAG_P);
376     for (const auto &Child : I.Children) {
377       std::unique_ptr<HTMLNode> Node = genHTML(*Child);
378       if (Node)
379         ParagraphComment->Children.emplace_back(std::move(Node));
380     }
381     if (ParagraphComment->Children.empty())
382       return nullptr;
383     return std::move(ParagraphComment);
384   } else if (I.Kind == "TextComment") {
385     if (I.Text == "")
386       return nullptr;
387     return llvm::make_unique<TextNode>(I.Text);
388   }
389   return nullptr;
390 }
391 
392 static std::unique_ptr<TagNode> genHTML(const std::vector<CommentInfo> &C) {
393   auto CommentBlock = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV);
394   for (const auto &Child : C) {
395     if (std::unique_ptr<HTMLNode> Node = genHTML(Child))
396       CommentBlock->Children.emplace_back(std::move(Node));
397   }
398   return CommentBlock;
399 }
400 
401 static std::vector<std::unique_ptr<TagNode>> genHTML(const EnumInfo &I) {
402   std::vector<std::unique_ptr<TagNode>> Out;
403   std::string EnumType;
404   if (I.Scoped)
405     EnumType = "enum class ";
406   else
407     EnumType = "enum ";
408 
409   Out.emplace_back(
410       llvm::make_unique<TagNode>(HTMLTag::TAG_H3, EnumType + I.Name));
411 
412   std::unique_ptr<TagNode> Node = genEnumMembersBlock(I.Members);
413   if (Node)
414     Out.emplace_back(std::move(Node));
415 
416   if (I.DefLoc)
417     Out.emplace_back(writeFileDefinition(I.DefLoc.getValue()));
418 
419   std::string Description;
420   if (!I.Description.empty())
421     Out.emplace_back(genHTML(I.Description));
422 
423   return Out;
424 }
425 
426 static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I,
427                                                      StringRef ParentInfoDir) {
428   std::vector<std::unique_ptr<TagNode>> Out;
429   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H3, I.Name));
430 
431   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P));
432   auto &FunctionHeader = Out.back();
433 
434   std::string Access = getAccess(I.Access);
435   if (Access != "")
436     FunctionHeader->Children.emplace_back(
437         llvm::make_unique<TextNode>(Access + " "));
438   if (I.ReturnType.Type.Name != "") {
439     FunctionHeader->Children.emplace_back(
440         genTypeReference(I.ReturnType.Type, ParentInfoDir));
441     FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(" "));
442   }
443   FunctionHeader->Children.emplace_back(
444       llvm::make_unique<TextNode>(I.Name + "("));
445 
446   for (const auto &P : I.Params) {
447     if (&P != I.Params.begin())
448       FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(", "));
449     FunctionHeader->Children.emplace_back(
450         genTypeReference(P.Type, ParentInfoDir));
451     FunctionHeader->Children.emplace_back(
452         llvm::make_unique<TextNode>(" " + P.Name));
453   }
454   FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(")"));
455 
456   if (I.DefLoc)
457     Out.emplace_back(writeFileDefinition(I.DefLoc.getValue()));
458 
459   std::string Description;
460   if (!I.Description.empty())
461     Out.emplace_back(genHTML(I.Description));
462 
463   return Out;
464 }
465 
466 static std::vector<std::unique_ptr<TagNode>> genHTML(const NamespaceInfo &I,
467                                                      std::string &InfoTitle) {
468   std::vector<std::unique_ptr<TagNode>> Out;
469   if (I.Name.str() == "")
470     InfoTitle = "Global Namespace";
471   else
472     InfoTitle = ("namespace " + I.Name).str();
473 
474   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
475 
476   std::string Description;
477   if (!I.Description.empty())
478     Out.emplace_back(genHTML(I.Description));
479 
480   std::vector<std::unique_ptr<TagNode>> ChildNamespaces =
481       genReferencesBlock(I.ChildNamespaces, "Namespaces");
482   AppendVector(std::move(ChildNamespaces), Out);
483   std::vector<std::unique_ptr<TagNode>> ChildRecords =
484       genReferencesBlock(I.ChildRecords, "Records");
485   AppendVector(std::move(ChildRecords), Out);
486 
487   std::vector<std::unique_ptr<TagNode>> ChildFunctions =
488       genFunctionsBlock(I.ChildFunctions, I.Path);
489   AppendVector(std::move(ChildFunctions), Out);
490   std::vector<std::unique_ptr<TagNode>> ChildEnums =
491       genEnumsBlock(I.ChildEnums);
492   AppendVector(std::move(ChildEnums), Out);
493 
494   return Out;
495 }
496 
497 static std::vector<std::unique_ptr<TagNode>> genHTML(const RecordInfo &I,
498                                                      std::string &InfoTitle) {
499   std::vector<std::unique_ptr<TagNode>> Out;
500   InfoTitle = (getTagType(I.TagType) + " " + I.Name).str();
501   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
502 
503   if (I.DefLoc)
504     Out.emplace_back(writeFileDefinition(I.DefLoc.getValue()));
505 
506   std::string Description;
507   if (!I.Description.empty())
508     Out.emplace_back(genHTML(I.Description));
509 
510   std::vector<std::unique_ptr<HTMLNode>> Parents =
511       genReferenceList(I.Parents, I.Path);
512   std::vector<std::unique_ptr<HTMLNode>> VParents =
513       genReferenceList(I.VirtualParents, I.Path);
514   if (!Parents.empty() || !VParents.empty()) {
515     Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P));
516     auto &PBody = Out.back();
517     PBody->Children.emplace_back(llvm::make_unique<TextNode>("Inherits from "));
518     if (Parents.empty())
519       AppendVector(std::move(VParents), PBody->Children);
520     else if (VParents.empty())
521       AppendVector(std::move(Parents), PBody->Children);
522     else {
523       AppendVector(std::move(Parents), PBody->Children);
524       PBody->Children.emplace_back(llvm::make_unique<TextNode>(", "));
525       AppendVector(std::move(VParents), PBody->Children);
526     }
527   }
528 
529   std::vector<std::unique_ptr<TagNode>> Members =
530       genRecordMembersBlock(I.Members, I.Path);
531   AppendVector(std::move(Members), Out);
532   std::vector<std::unique_ptr<TagNode>> ChildRecords =
533       genReferencesBlock(I.ChildRecords, "Records");
534   AppendVector(std::move(ChildRecords), Out);
535 
536   std::vector<std::unique_ptr<TagNode>> ChildFunctions =
537       genFunctionsBlock(I.ChildFunctions, I.Path);
538   AppendVector(std::move(ChildFunctions), Out);
539   std::vector<std::unique_ptr<TagNode>> ChildEnums =
540       genEnumsBlock(I.ChildEnums);
541   AppendVector(std::move(ChildEnums), Out);
542 
543   return Out;
544 }
545 
546 /// Generator for HTML documentation.
547 class HTMLGenerator : public Generator {
548 public:
549   static const char *Format;
550 
551   llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
552                                  const ClangDocContext &CDCtx) override;
553   bool createResources(ClangDocContext CDCtx) override;
554 };
555 
556 const char *HTMLGenerator::Format = "html";
557 
558 llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
559                                               const ClangDocContext &CDCtx) {
560   HTMLFile F;
561 
562   auto MetaNode = llvm::make_unique<TagNode>(HTMLTag::TAG_META);
563   MetaNode->Attributes.try_emplace("charset", "utf-8");
564   F.Children.emplace_back(std::move(MetaNode));
565 
566   std::string InfoTitle;
567   Info CastedInfo;
568   auto MainContentNode = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV);
569   switch (I->IT) {
570   case InfoType::IT_namespace: {
571     std::vector<std::unique_ptr<TagNode>> Nodes =
572         genHTML(*static_cast<clang::doc::NamespaceInfo *>(I), InfoTitle);
573     AppendVector(std::move(Nodes), MainContentNode->Children);
574     break;
575   }
576   case InfoType::IT_record: {
577     std::vector<std::unique_ptr<TagNode>> Nodes =
578         genHTML(*static_cast<clang::doc::RecordInfo *>(I), InfoTitle);
579     AppendVector(std::move(Nodes), MainContentNode->Children);
580     break;
581   }
582   case InfoType::IT_enum: {
583     std::vector<std::unique_ptr<TagNode>> Nodes =
584         genHTML(*static_cast<clang::doc::EnumInfo *>(I));
585     AppendVector(std::move(Nodes), MainContentNode->Children);
586     break;
587   }
588   case InfoType::IT_function: {
589     std::vector<std::unique_ptr<TagNode>> Nodes =
590         genHTML(*static_cast<clang::doc::FunctionInfo *>(I), "");
591     AppendVector(std::move(Nodes), MainContentNode->Children);
592     break;
593   }
594   case InfoType::IT_default:
595     return llvm::make_error<llvm::StringError>("Unexpected info type.\n",
596                                                llvm::inconvertibleErrorCode());
597   }
598 
599   F.Children.emplace_back(
600       llvm::make_unique<TagNode>(HTMLTag::TAG_TITLE, InfoTitle));
601   std::vector<std::unique_ptr<TagNode>> StylesheetsNodes =
602       genStylesheetsHTML(I->Path, CDCtx);
603   AppendVector(std::move(StylesheetsNodes), F.Children);
604   F.Children.emplace_back(std::move(MainContentNode));
605   F.Render(OS);
606 
607   return llvm::Error::success();
608 }
609 
610 bool HTMLGenerator::createResources(ClangDocContext CDCtx) {
611   llvm::outs() << "Generating stylesheet for docs...\n";
612   for (const auto &FilePath : CDCtx.UserStylesheets) {
613     llvm::SmallString<128> StylesheetPathWrite;
614     llvm::sys::path::native(CDCtx.OutDirectory, StylesheetPathWrite);
615     llvm::sys::path::append(StylesheetPathWrite,
616                             llvm::sys::path::filename(FilePath));
617     llvm::SmallString<128> StylesheetPathRead;
618     llvm::sys::path::native(FilePath, StylesheetPathRead);
619     std::error_code OK;
620     std::error_code FileErr =
621         llvm::sys::fs::copy_file(StylesheetPathRead, StylesheetPathWrite);
622     if (FileErr != OK) {
623       llvm::errs() << "Error creating stylesheet file "
624                    << llvm::sys::path::filename(FilePath) << ": "
625                    << FileErr.message() << "\n";
626       return false;
627     }
628   }
629   return true;
630 }
631 
632 static GeneratorRegistry::Add<HTMLGenerator> HTML(HTMLGenerator::Format,
633                                                   "Generator for HTML output.");
634 
635 // This anchor is used to force the linker to link in the generated object
636 // file and thus register the generator.
637 volatile int HTMLGeneratorAnchorSource = 0;
638 
639 } // namespace doc
640 } // namespace clang
641