diff options
Diffstat (limited to 'clang-tools-extra/clang-doc/HTMLGenerator.cpp')
-rw-r--r-- | clang-tools-extra/clang-doc/HTMLGenerator.cpp | 178 |
1 files changed, 135 insertions, 43 deletions
diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp index bed27f0e41e..e47119336ab 100644 --- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp +++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp @@ -18,13 +18,6 @@ using namespace llvm; namespace clang { namespace doc { -template <typename Derived, typename Base, - typename = std::enable_if<std::is_base_of<Derived, Base>::value>> -static void AppendVector(std::vector<Derived> &&New, - std::vector<Base> &Original) { - std::move(New.begin(), New.end(), std::back_inserter(Original)); -} - namespace { class HTMLTag { @@ -40,6 +33,7 @@ public: TAG_P, TAG_UL, TAG_LI, + TAG_A, }; HTMLTag() = default; @@ -58,15 +52,22 @@ private: TagType Value; }; +enum NodeType { + NODE_TEXT, + NODE_TAG, +}; + struct HTMLNode { + HTMLNode(NodeType Type) : Type(Type) {} virtual ~HTMLNode() = default; virtual void Render(llvm::raw_ostream &OS, int IndentationLevel) = 0; + NodeType Type; // Type of node }; struct TextNode : public HTMLNode { - TextNode(llvm::StringRef Text, bool Indented) - : Text(Text), Indented(Indented) {} + TextNode(const Twine &Text, bool Indented = true) + : HTMLNode(NodeType::NODE_TEXT), Text(Text.str()), Indented(Indented) {} std::string Text; // Content of node bool Indented; // Indicates if an indentation must be rendered before the text @@ -75,7 +76,8 @@ struct TextNode : public HTMLNode { struct TagNode : public HTMLNode { TagNode(HTMLTag Tag) - : Tag(Tag), InlineChildren(Tag.HasInlineChildren()), + : HTMLNode(NodeType::NODE_TAG), Tag(Tag), + InlineChildren(Tag.HasInlineChildren()), SelfClosing(Tag.IsSelfClosing()) {} TagNode(HTMLTag Tag, const Twine &Text) : TagNode(Tag) { Children.emplace_back( @@ -121,6 +123,7 @@ bool HTMLTag::IsSelfClosing() const { case HTMLTag::TAG_P: case HTMLTag::TAG_UL: case HTMLTag::TAG_LI: + case HTMLTag::TAG_A: return false; } llvm_unreachable("Unhandled HTMLTag::TagType"); @@ -134,6 +137,7 @@ bool HTMLTag::HasInlineChildren() const { case HTMLTag::TAG_H2: case HTMLTag::TAG_H3: case HTMLTag::TAG_LI: + case HTMLTag::TAG_A: return true; case HTMLTag::TAG_DIV: case HTMLTag::TAG_P: @@ -163,6 +167,8 @@ llvm::SmallString<16> HTMLTag::ToString() const { return llvm::SmallString<16>("ul"); case HTMLTag::TAG_LI: return llvm::SmallString<16>("li"); + case HTMLTag::TAG_A: + return llvm::SmallString<16>("a"); } llvm_unreachable("Unhandled HTMLTag::TagType"); } @@ -185,21 +191,87 @@ void TagNode::Render(llvm::raw_ostream &OS, int IndentationLevel) { OS << ">"; if (!InlineChildren) OS << "\n"; - int ChildrenIndentation = InlineChildren ? 0 : IndentationLevel + 1; + bool NewLineRendered = true; for (const auto &C : Children) { + int ChildrenIndentation = + InlineChildren || !NewLineRendered ? 0 : IndentationLevel + 1; C->Render(OS, ChildrenIndentation); - if (!InlineChildren) + if (!InlineChildren && (C == Children.back() || + (C->Type != NodeType::NODE_TEXT || + (&C + 1)->get()->Type != NodeType::NODE_TEXT))) { OS << "\n"; + NewLineRendered = true; + } else + NewLineRendered = false; } if (!InlineChildren) OS.indent(IndentationLevel * 2); OS << "</" << Tag.ToString() << ">"; } +template <typename Derived, typename Base, + typename = std::enable_if<std::is_base_of<Derived, Base>::value>> +static void AppendVector(std::vector<Derived> &&New, + std::vector<Base> &Original) { + std::move(New.begin(), New.end(), std::back_inserter(Original)); +} + +// Compute the relative path that names the file path relative to the given +// directory. +static SmallString<128> computeRelativePath(StringRef FilePath, + StringRef Directory) { + StringRef Path = FilePath; + while (!Path.empty()) { + if (Directory == Path) + return FilePath.substr(Path.size()); + Path = llvm::sys::path::parent_path(Path); + } + + StringRef Dir = Directory; + SmallString<128> Result; + while (!Dir.empty()) { + if (Dir == FilePath) + break; + Dir = llvm::sys::path::parent_path(Dir); + llvm::sys::path::append(Result, ".."); + } + llvm::sys::path::append(Result, FilePath.substr(Dir.size())); + return Result; +} + // HTML generation +static std::unique_ptr<TagNode> genLink(const Twine &Text, const Twine &Link) { + auto LinkNode = llvm::make_unique<TagNode>(HTMLTag::TAG_A, Text); + LinkNode->Attributes.try_emplace("href", Link.str()); + return LinkNode; +} + +static std::unique_ptr<HTMLNode> genTypeReference(const Reference &Type, + StringRef CurrentDirectory) { + if (Type.Path.empty()) + return llvm::make_unique<TextNode>(Type.Name); + llvm::SmallString<128> Path = + computeRelativePath(Type.Path, CurrentDirectory); + llvm::sys::path::append(Path, Type.Name + ".html"); + return genLink(Type.Name, Path); +} + +static std::vector<std::unique_ptr<HTMLNode>> +genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs, + const StringRef &CurrentDirectory) { + std::vector<std::unique_ptr<HTMLNode>> Out; + for (const auto &R : Refs) { + if (&R != Refs.begin()) + Out.emplace_back(llvm::make_unique<TextNode>(", ")); + Out.emplace_back(genTypeReference(R, CurrentDirectory)); + } + return Out; +} + static std::vector<std::unique_ptr<TagNode>> genHTML(const EnumInfo &I); -static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I); +static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I, + StringRef ParentInfoDir); static std::vector<std::unique_ptr<TagNode>> genEnumsBlock(const std::vector<EnumInfo> &Enums) { @@ -229,7 +301,8 @@ genEnumMembersBlock(const llvm::SmallVector<SmallString<16>, 4> &Members) { } static std::vector<std::unique_ptr<TagNode>> -genFunctionsBlock(const std::vector<FunctionInfo> &Functions) { +genFunctionsBlock(const std::vector<FunctionInfo> &Functions, + StringRef ParentInfoDir) { if (Functions.empty()) return {}; @@ -238,14 +311,15 @@ genFunctionsBlock(const std::vector<FunctionInfo> &Functions) { Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_DIV)); auto &DivBody = Out.back(); for (const auto &F : Functions) { - std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(F); + std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(F, ParentInfoDir); AppendVector(std::move(Nodes), DivBody->Children); } return Out; } static std::vector<std::unique_ptr<TagNode>> -genRecordMembersBlock(const llvm::SmallVector<MemberTypeInfo, 4> &Members) { +genRecordMembersBlock(const llvm::SmallVector<MemberTypeInfo, 4> &Members, + StringRef ParentInfoDir) { if (Members.empty()) return {}; @@ -257,8 +331,11 @@ genRecordMembersBlock(const llvm::SmallVector<MemberTypeInfo, 4> &Members) { std::string Access = getAccess(M.Access); if (Access != "") Access = Access + " "; - ULBody->Children.emplace_back(llvm::make_unique<TagNode>( - HTMLTag::TAG_LI, Access + M.Type.Name + " " + M.Name)); + auto LIBody = llvm::make_unique<TagNode>(HTMLTag::TAG_LI); + LIBody->Children.emplace_back(llvm::make_unique<TextNode>(Access)); + LIBody->Children.emplace_back(genTypeReference(M.Type, ParentInfoDir)); + LIBody->Children.emplace_back(llvm::make_unique<TextNode>(" " + M.Name)); + ULBody->Children.emplace_back(std::move(LIBody)); } return Out; } @@ -346,25 +423,35 @@ static std::vector<std::unique_ptr<TagNode>> genHTML(const EnumInfo &I) { return Out; } -static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I) { +static std::vector<std::unique_ptr<TagNode>> genHTML(const FunctionInfo &I, + StringRef ParentInfoDir) { std::vector<std::unique_ptr<TagNode>> Out; Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_H3, I.Name)); - std::string Buffer; - llvm::raw_string_ostream Stream(Buffer); - for (const auto &P : I.Params) { - if (&P != I.Params.begin()) - Stream << ", "; - Stream << P.Type.Name + " " + P.Name; - } + Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P)); + auto &FunctionHeader = Out.back(); std::string Access = getAccess(I.Access); if (Access != "") - Access = Access + " "; + FunctionHeader->Children.emplace_back( + llvm::make_unique<TextNode>(Access + " ")); + if (I.ReturnType.Type.Name != "") { + FunctionHeader->Children.emplace_back( + genTypeReference(I.ReturnType.Type, ParentInfoDir)); + FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(" ")); + } + FunctionHeader->Children.emplace_back( + llvm::make_unique<TextNode>(I.Name + "(")); - Out.emplace_back(llvm::make_unique<TagNode>( - HTMLTag::TAG_P, Access + I.ReturnType.Type.Name + " " + I.Name + "(" + - Stream.str() + ")")); + for (const auto &P : I.Params) { + if (&P != I.Params.begin()) + FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(", ")); + FunctionHeader->Children.emplace_back( + genTypeReference(P.Type, ParentInfoDir)); + FunctionHeader->Children.emplace_back( + llvm::make_unique<TextNode>(" " + P.Name)); + } + FunctionHeader->Children.emplace_back(llvm::make_unique<TextNode>(")")); if (I.DefLoc) Out.emplace_back(writeFileDefinition(I.DefLoc.getValue())); @@ -398,7 +485,7 @@ static std::vector<std::unique_ptr<TagNode>> genHTML(const NamespaceInfo &I, AppendVector(std::move(ChildRecords), Out); std::vector<std::unique_ptr<TagNode>> ChildFunctions = - genFunctionsBlock(I.ChildFunctions); + genFunctionsBlock(I.ChildFunctions, I.Path); AppendVector(std::move(ChildFunctions), Out); std::vector<std::unique_ptr<TagNode>> ChildEnums = genEnumsBlock(I.ChildEnums); @@ -420,29 +507,34 @@ static std::vector<std::unique_ptr<TagNode>> genHTML(const RecordInfo &I, if (!I.Description.empty()) Out.emplace_back(genHTML(I.Description)); - std::string Parents = genReferenceList(I.Parents); - std::string VParents = genReferenceList(I.VirtualParents); + std::vector<std::unique_ptr<HTMLNode>> Parents = + genReferenceList(I.Parents, I.Path); + std::vector<std::unique_ptr<HTMLNode>> VParents = + genReferenceList(I.VirtualParents, I.Path); if (!Parents.empty() || !VParents.empty()) { + Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P)); + auto &PBody = Out.back(); + PBody->Children.emplace_back(llvm::make_unique<TextNode>("Inherits from ")); if (Parents.empty()) - Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P, - "Inherits from " + VParents)); + AppendVector(std::move(VParents), PBody->Children); else if (VParents.empty()) - Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_P, - "Inherits from " + Parents)); - else - Out.emplace_back(llvm::make_unique<TagNode>( - HTMLTag::TAG_P, "Inherits from " + Parents + ", " + VParents)); + AppendVector(std::move(Parents), PBody->Children); + else { + AppendVector(std::move(Parents), PBody->Children); + PBody->Children.emplace_back(llvm::make_unique<TextNode>(", ")); + AppendVector(std::move(VParents), PBody->Children); + } } std::vector<std::unique_ptr<TagNode>> Members = - genRecordMembersBlock(I.Members); + genRecordMembersBlock(I.Members, I.Path); AppendVector(std::move(Members), Out); std::vector<std::unique_ptr<TagNode>> ChildRecords = genReferencesBlock(I.ChildRecords, "Records"); AppendVector(std::move(ChildRecords), Out); std::vector<std::unique_ptr<TagNode>> ChildFunctions = - genFunctionsBlock(I.ChildFunctions); + genFunctionsBlock(I.ChildFunctions, I.Path); AppendVector(std::move(ChildFunctions), Out); std::vector<std::unique_ptr<TagNode>> ChildEnums = genEnumsBlock(I.ChildEnums); @@ -492,7 +584,7 @@ llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) { } case InfoType::IT_function: { std::vector<std::unique_ptr<TagNode>> Nodes = - genHTML(*static_cast<clang::doc::FunctionInfo *>(I)); + genHTML(*static_cast<clang::doc::FunctionInfo *>(I), ""); AppendVector(std::move(Nodes), MainContentNode->Children); break; } |