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())
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   return genLink(Type.Name, Path);
256 }
257 
258 static std::vector<std::unique_ptr<HTMLNode>>
259 genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs,
260                  const StringRef &CurrentDirectory) {
261   std::vector<std::unique_ptr<HTMLNode>> Out;
262   for (const auto &R : Refs) {
263     if (&R != Refs.begin())
264       Out.emplace_back(llvm::make_unique<TextNode>(", "));
265     Out.emplace_back(genTypeReference(R, CurrentDirectory));
266   }
267   return Out;
268 }
269 
270 static std::vector<std::unique_ptr<TagNode>> genHTML(const EnumInfo &I);
271 static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I,
272                                                      StringRef ParentInfoDir);
273 
274 static std::vector<std::unique_ptr<TagNode>>
275 genEnumsBlock(const std::vector<EnumInfo> &Enums) {
276   if (Enums.empty())
277     return {};
278 
279   std::vector<std::unique_ptr<TagNode>> Out;
280   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H2, "Enums"));
281   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_DIV));
282   auto &DivBody = Out.back();
283   for (const auto &E : Enums) {
284     std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(E);
285     AppendVector(std::move(Nodes), DivBody->Children);
286   }
287   return Out;
288 }
289 
290 static std::unique_ptr<TagNode>
291 genEnumMembersBlock(const llvm::SmallVector<SmallString<16>, 4> &Members) {
292   if (Members.empty())
293     return nullptr;
294 
295   auto List = llvm::make_unique<TagNode>(HTMLTag::TAG_UL);
296   for (const auto &M : Members)
297     List->Children.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_LI, M));
298   return List;
299 }
300 
301 static std::vector<std::unique_ptr<TagNode>>
302 genFunctionsBlock(const std::vector<FunctionInfo> &Functions,
303                   StringRef ParentInfoDir) {
304   if (Functions.empty())
305     return {};
306 
307   std::vector<std::unique_ptr<TagNode>> Out;
308   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H2, "Functions"));
309   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_DIV));
310   auto &DivBody = Out.back();
311   for (const auto &F : Functions) {
312     std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(F, ParentInfoDir);
313     AppendVector(std::move(Nodes), DivBody->Children);
314   }
315   return Out;
316 }
317 
318 static std::vector<std::unique_ptr<TagNode>>
319 genRecordMembersBlock(const llvm::SmallVector<MemberTypeInfo, 4> &Members,
320                       StringRef ParentInfoDir) {
321   if (Members.empty())
322     return {};
323 
324   std::vector<std::unique_ptr<TagNode>> Out;
325   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H2, "Members"));
326   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_UL));
327   auto &ULBody = Out.back();
328   for (const auto &M : Members) {
329     std::string Access = getAccess(M.Access);
330     if (Access != "")
331       Access = Access + " ";
332     auto LIBody = llvm::make_unique<TagNode>(HTMLTag::TAG_LI);
333     LIBody->Children.emplace_back(llvm::make_unique<TextNode>(Access));
334     LIBody->Children.emplace_back(genTypeReference(M.Type, ParentInfoDir));
335     LIBody->Children.emplace_back(llvm::make_unique<TextNode>(" " + M.Name));
336     ULBody->Children.emplace_back(std::move(LIBody));
337   }
338   return Out;
339 }
340 
341 static std::vector<std::unique_ptr<TagNode>>
342 genReferencesBlock(const std::vector<Reference> &References,
343                    llvm::StringRef Title) {
344   if (References.empty())
345     return {};
346 
347   std::vector<std::unique_ptr<TagNode>> Out;
348   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H2, Title));
349   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_UL));
350   auto &ULBody = Out.back();
351   for (const auto &R : References)
352     ULBody->Children.emplace_back(
353         llvm::make_unique<TagNode>(HTMLTag::TAG_LI, R.Name));
354   return Out;
355 }
356 
357 static std::unique_ptr<TagNode> writeFileDefinition(const Location &L) {
358   return llvm::make_unique<TagNode>(
359       HTMLTag::TAG_P,
360       "Defined at line " + std::to_string(L.LineNumber) + " of " + L.Filename);
361 }
362 
363 static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) {
364   if (I.Kind == "FullComment") {
365     auto FullComment = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV);
366     for (const auto &Child : I.Children) {
367       std::unique_ptr<HTMLNode> Node = genHTML(*Child);
368       if (Node)
369         FullComment->Children.emplace_back(std::move(Node));
370     }
371     return std::move(FullComment);
372   } else if (I.Kind == "ParagraphComment") {
373     auto ParagraphComment = llvm::make_unique<TagNode>(HTMLTag::TAG_P);
374     for (const auto &Child : I.Children) {
375       std::unique_ptr<HTMLNode> Node = genHTML(*Child);
376       if (Node)
377         ParagraphComment->Children.emplace_back(std::move(Node));
378     }
379     if (ParagraphComment->Children.empty())
380       return nullptr;
381     return std::move(ParagraphComment);
382   } else if (I.Kind == "TextComment") {
383     if (I.Text == "")
384       return nullptr;
385     return llvm::make_unique<TextNode>(I.Text);
386   }
387   return nullptr;
388 }
389 
390 static std::unique_ptr<TagNode> genHTML(const std::vector<CommentInfo> &C) {
391   auto CommentBlock = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV);
392   for (const auto &Child : C) {
393     if (std::unique_ptr<HTMLNode> Node = genHTML(Child))
394       CommentBlock->Children.emplace_back(std::move(Node));
395   }
396   return CommentBlock;
397 }
398 
399 static std::vector<std::unique_ptr<TagNode>> genHTML(const EnumInfo &I) {
400   std::vector<std::unique_ptr<TagNode>> Out;
401   std::string EnumType;
402   if (I.Scoped)
403     EnumType = "enum class ";
404   else
405     EnumType = "enum ";
406 
407   Out.emplace_back(
408       llvm::make_unique<TagNode>(HTMLTag::TAG_H3, EnumType + I.Name));
409 
410   std::unique_ptr<TagNode> Node = genEnumMembersBlock(I.Members);
411   if (Node)
412     Out.emplace_back(std::move(Node));
413 
414   if (I.DefLoc)
415     Out.emplace_back(writeFileDefinition(I.DefLoc.getValue()));
416 
417   std::string Description;
418   if (!I.Description.empty())
419     Out.emplace_back(genHTML(I.Description));
420 
421   return Out;
422 }
423 
424 static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I,
425                                                      StringRef ParentInfoDir) {
426   std::vector<std::unique_ptr<TagNode>> Out;
427   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H3, I.Name));
428 
429   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P));
430   auto &FunctionHeader = Out.back();
431 
432   std::string Access = getAccess(I.Access);
433   if (Access != "")
434     FunctionHeader->Children.emplace_back(
435         llvm::make_unique<TextNode>(Access + " "));
436   if (I.ReturnType.Type.Name != "") {
437     FunctionHeader->Children.emplace_back(
438         genTypeReference(I.ReturnType.Type, ParentInfoDir));
439     FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(" "));
440   }
441   FunctionHeader->Children.emplace_back(
442       llvm::make_unique<TextNode>(I.Name + "("));
443 
444   for (const auto &P : I.Params) {
445     if (&P != I.Params.begin())
446       FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(", "));
447     FunctionHeader->Children.emplace_back(
448         genTypeReference(P.Type, ParentInfoDir));
449     FunctionHeader->Children.emplace_back(
450         llvm::make_unique<TextNode>(" " + P.Name));
451   }
452   FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(")"));
453 
454   if (I.DefLoc)
455     Out.emplace_back(writeFileDefinition(I.DefLoc.getValue()));
456 
457   std::string Description;
458   if (!I.Description.empty())
459     Out.emplace_back(genHTML(I.Description));
460 
461   return Out;
462 }
463 
464 static std::vector<std::unique_ptr<TagNode>> genHTML(const NamespaceInfo &I,
465                                                      std::string &InfoTitle) {
466   std::vector<std::unique_ptr<TagNode>> Out;
467   if (I.Name.str() == "")
468     InfoTitle = "Global Namespace";
469   else
470     InfoTitle = ("namespace " + I.Name).str();
471 
472   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
473 
474   std::string Description;
475   if (!I.Description.empty())
476     Out.emplace_back(genHTML(I.Description));
477 
478   std::vector<std::unique_ptr<TagNode>> ChildNamespaces =
479       genReferencesBlock(I.ChildNamespaces, "Namespaces");
480   AppendVector(std::move(ChildNamespaces), Out);
481   std::vector<std::unique_ptr<TagNode>> ChildRecords =
482       genReferencesBlock(I.ChildRecords, "Records");
483   AppendVector(std::move(ChildRecords), Out);
484 
485   std::vector<std::unique_ptr<TagNode>> ChildFunctions =
486       genFunctionsBlock(I.ChildFunctions, I.Path);
487   AppendVector(std::move(ChildFunctions), Out);
488   std::vector<std::unique_ptr<TagNode>> ChildEnums =
489       genEnumsBlock(I.ChildEnums);
490   AppendVector(std::move(ChildEnums), Out);
491 
492   return Out;
493 }
494 
495 static std::vector<std::unique_ptr<TagNode>> genHTML(const RecordInfo &I,
496                                                      std::string &InfoTitle) {
497   std::vector<std::unique_ptr<TagNode>> Out;
498   InfoTitle = (getTagType(I.TagType) + " " + I.Name).str();
499   Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
500 
501   if (I.DefLoc)
502     Out.emplace_back(writeFileDefinition(I.DefLoc.getValue()));
503 
504   std::string Description;
505   if (!I.Description.empty())
506     Out.emplace_back(genHTML(I.Description));
507 
508   std::vector<std::unique_ptr<HTMLNode>> Parents =
509       genReferenceList(I.Parents, I.Path);
510   std::vector<std::unique_ptr<HTMLNode>> VParents =
511       genReferenceList(I.VirtualParents, I.Path);
512   if (!Parents.empty() || !VParents.empty()) {
513     Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P));
514     auto &PBody = Out.back();
515     PBody->Children.emplace_back(llvm::make_unique<TextNode>("Inherits from "));
516     if (Parents.empty())
517       AppendVector(std::move(VParents), PBody->Children);
518     else if (VParents.empty())
519       AppendVector(std::move(Parents), PBody->Children);
520     else {
521       AppendVector(std::move(Parents), PBody->Children);
522       PBody->Children.emplace_back(llvm::make_unique<TextNode>(", "));
523       AppendVector(std::move(VParents), PBody->Children);
524     }
525   }
526 
527   std::vector<std::unique_ptr<TagNode>> Members =
528       genRecordMembersBlock(I.Members, I.Path);
529   AppendVector(std::move(Members), Out);
530   std::vector<std::unique_ptr<TagNode>> ChildRecords =
531       genReferencesBlock(I.ChildRecords, "Records");
532   AppendVector(std::move(ChildRecords), Out);
533 
534   std::vector<std::unique_ptr<TagNode>> ChildFunctions =
535       genFunctionsBlock(I.ChildFunctions, I.Path);
536   AppendVector(std::move(ChildFunctions), Out);
537   std::vector<std::unique_ptr<TagNode>> ChildEnums =
538       genEnumsBlock(I.ChildEnums);
539   AppendVector(std::move(ChildEnums), Out);
540 
541   return Out;
542 }
543 
544 /// Generator for HTML documentation.
545 class HTMLGenerator : public Generator {
546 public:
547   static const char *Format;
548 
549   llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
550                                  const ClangDocContext &CDCtx) override;
551   bool createResources(ClangDocContext CDCtx) override;
552 };
553 
554 const char *HTMLGenerator::Format = "html";
555 
556 llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
557                                               const ClangDocContext &CDCtx) {
558   HTMLFile F;
559 
560   auto MetaNode = llvm::make_unique<TagNode>(HTMLTag::TAG_META);
561   MetaNode->Attributes.try_emplace("charset", "utf-8");
562   F.Children.emplace_back(std::move(MetaNode));
563 
564   std::string InfoTitle;
565   Info CastedInfo;
566   auto MainContentNode = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV);
567   switch (I->IT) {
568   case InfoType::IT_namespace: {
569     std::vector<std::unique_ptr<TagNode>> Nodes =
570         genHTML(*static_cast<clang::doc::NamespaceInfo *>(I), InfoTitle);
571     AppendVector(std::move(Nodes), MainContentNode->Children);
572     break;
573   }
574   case InfoType::IT_record: {
575     std::vector<std::unique_ptr<TagNode>> Nodes =
576         genHTML(*static_cast<clang::doc::RecordInfo *>(I), InfoTitle);
577     AppendVector(std::move(Nodes), MainContentNode->Children);
578     break;
579   }
580   case InfoType::IT_enum: {
581     std::vector<std::unique_ptr<TagNode>> Nodes =
582         genHTML(*static_cast<clang::doc::EnumInfo *>(I));
583     AppendVector(std::move(Nodes), MainContentNode->Children);
584     break;
585   }
586   case InfoType::IT_function: {
587     std::vector<std::unique_ptr<TagNode>> Nodes =
588         genHTML(*static_cast<clang::doc::FunctionInfo *>(I), "");
589     AppendVector(std::move(Nodes), MainContentNode->Children);
590     break;
591   }
592   case InfoType::IT_default:
593     return llvm::make_error<llvm::StringError>("Unexpected info type.\n",
594                                                llvm::inconvertibleErrorCode());
595   }
596 
597   F.Children.emplace_back(
598       llvm::make_unique<TagNode>(HTMLTag::TAG_TITLE, InfoTitle));
599   std::vector<std::unique_ptr<TagNode>> StylesheetsNodes =
600       genStylesheetsHTML(I->Path, CDCtx);
601   AppendVector(std::move(StylesheetsNodes), F.Children);
602   F.Children.emplace_back(std::move(MainContentNode));
603   F.Render(OS);
604 
605   return llvm::Error::success();
606 }
607 
608 bool HTMLGenerator::createResources(ClangDocContext CDCtx) {
609   llvm::outs() << "Generating stylesheet for docs...\n";
610   for (const auto &FilePath : CDCtx.UserStylesheets) {
611     llvm::SmallString<128> StylesheetPathWrite;
612     llvm::sys::path::native(CDCtx.OutDirectory, StylesheetPathWrite);
613     llvm::sys::path::append(StylesheetPathWrite,
614                             llvm::sys::path::filename(FilePath));
615     llvm::SmallString<128> StylesheetPathRead;
616     llvm::sys::path::native(FilePath, StylesheetPathRead);
617     std::error_code OK;
618     std::error_code FileErr =
619         llvm::sys::fs::copy_file(StylesheetPathRead, StylesheetPathWrite);
620     if (FileErr != OK) {
621       llvm::errs() << "Error creating stylesheet file "
622                    << llvm::sys::path::filename(FilePath) << ": "
623                    << FileErr.message() << "\n";
624       return false;
625     }
626   }
627   return true;
628 }
629 
630 static GeneratorRegistry::Add<HTMLGenerator> HTML(HTMLGenerator::Format,
631                                                   "Generator for HTML output.");
632 
633 // This anchor is used to force the linker to link in the generated object
634 // file and thus register the generator.
635 volatile int HTMLGeneratorAnchorSource = 0;
636 
637 } // namespace doc
638 } // namespace clang
639