DiegoAstiazaran created this revision. DiegoAstiazaran added reviewers: juliehockett, jakehehrlich, lebedev.ri. DiegoAstiazaran added a project: clang-tools-extra. Herald added subscribers: kadircet, arphaman, mgrang, mgorny.
An index structure is created while reducing the infos. This is then passed to the HTML generator so it's included in each file created. Paths in the index are fixed (relative to the current file) for each file. Index is currently rendered on top of the info content, this will be fixed later with CSS. https://reviews.llvm.org/D65003 Files: clang-tools-extra/clang-doc/Generators.cpp clang-tools-extra/clang-doc/Generators.h clang-tools-extra/clang-doc/HTMLGenerator.cpp clang-tools-extra/clang-doc/MDGenerator.cpp clang-tools-extra/clang-doc/Representation.cpp clang-tools-extra/clang-doc/Representation.h clang-tools-extra/clang-doc/YAMLGenerator.cpp clang-tools-extra/clang-doc/tool/ClangDocMain.cpp clang-tools-extra/unittests/clang-doc/CMakeLists.txt clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp clang-tools-extra/unittests/clang-doc/ClangDocTest.h clang-tools-extra/unittests/clang-doc/GeneratorTest.cpp clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
Index: clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp =================================================================== --- clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp +++ clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp @@ -40,7 +40,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(--- @@ -94,7 +94,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(--- @@ -158,7 +158,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(--- @@ -206,7 +206,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(--- @@ -343,7 +343,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(--- Index: clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp =================================================================== --- clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp +++ clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp @@ -38,7 +38,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(# namespace Namespace @@ -101,7 +101,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(# class r @@ -162,7 +162,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(### f @@ -190,7 +190,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(| enum class e | @@ -320,7 +320,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(### f Index: clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp =================================================================== --- clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp +++ clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp @@ -9,6 +9,7 @@ #include "ClangDocTest.h" #include "Generators.h" #include "Representation.h" +#include "Serialize.h" #include "gtest/gtest.h" namespace clang { @@ -38,7 +39,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(<!DOCTYPE html> <meta charset="utf-8"/> @@ -96,7 +97,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); SmallString<16> PathToF; llvm::sys::path::native("../../../path/to/F.html", PathToF); @@ -161,7 +162,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); SmallString<16> PathToFloat; llvm::sys::path::native("path/to/float.html", PathToFloat); @@ -204,7 +205,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(<!DOCTYPE html> <meta charset="utf-8"/> @@ -264,7 +265,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(<!DOCTYPE html> <meta charset="utf-8"/> @@ -293,5 +294,64 @@ EXPECT_EQ(Expected, Actual.str()); } +TEST(HTMLGeneratorTest, emitIndexHTML) { + RecordInfo I; + I.Path = ""; + ClangDocContext CDCtx; + std::vector<std::unique_ptr<Info>> Infos; + Infos.emplace_back(llvm::make_unique<Info>()); + Info *InfoA = Infos.back().get(); + InfoA->Name = "A"; + InfoA->USR = serialize::hashUSR("1"); + Infos.emplace_back(llvm::make_unique<Info>()); + Info *InfoC = Infos.back().get(); + InfoC->Name = "C"; + InfoC->USR = serialize::hashUSR("3"); + Reference RefB = Reference("B"); + RefB.USR = serialize::hashUSR("2"); + InfoC->Namespace = {std::move(RefB)}; + Infos.emplace_back(llvm::make_unique<Info>()); + Info *InfoD = Infos.back().get(); + InfoD->Name = "D"; + InfoD->USR = serialize::hashUSR("4"); + Infos.emplace_back(llvm::make_unique<Info>()); + Info *InfoF = Infos.back().get(); + InfoF->Name = "F"; + InfoF->USR = serialize::hashUSR("6"); + Reference RefD = Reference("D"); + RefD.USR = serialize::hashUSR("4"); + Reference RefE = Reference("E"); + RefE.USR = serialize::hashUSR("5"); + InfoF->Namespace = {std::move(RefE), std::move(RefD)}; + CDCtx.Idx = Generator::genIndex(Infos); + + auto G = getHTMLGenerator(); + assert(G); + std::string Buffer; + llvm::raw_string_ostream Actual(Buffer); + auto Err = G->generateDocForInfo(&I, Actual, CDCtx); + assert(!Err); + std::string Expected = R"raw(<!DOCTYPE html> +<meta charset="utf-8"/> +<title>struct </title> +<ul> + <li><span>A</span></li> + <li><span>B</span><ul> + <li><span>C</span></li> +</ul></li> + <li><span>D</span><ul> + <li><span>E</span><ul> + <li><span>F</span></li> +</ul></li> +</ul></li> +</ul> +<div> + <h1>struct </h1> +</div> +)raw"; + + EXPECT_EQ(Expected, Actual.str()); +} + } // namespace doc } // namespace clang Index: clang-tools-extra/unittests/clang-doc/GeneratorTest.cpp =================================================================== --- /dev/null +++ clang-tools-extra/unittests/clang-doc/GeneratorTest.cpp @@ -0,0 +1,70 @@ +//===-- clang-doc/GeneratorTest.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ClangDocTest.h" +#include "Generators.h" +#include "Representation.h" +#include "Serialize.h" +#include "gtest/gtest.h" + +namespace clang { +namespace doc { + +TEST(GeneratorTest, emitIndex) { + std::vector<std::unique_ptr<Info>> Infos; + Infos.emplace_back(llvm::make_unique<Info>()); + Info *InfoA = Infos.back().get(); + InfoA->Name = "A"; + InfoA->USR = serialize::hashUSR("1"); + Infos.emplace_back(llvm::make_unique<Info>()); + Info *InfoC = Infos.back().get(); + InfoC->Name = "C"; + InfoC->USR = serialize::hashUSR("3"); + Reference RefB = Reference("B"); + RefB.USR = serialize::hashUSR("2"); + InfoC->Namespace = {std::move(RefB)}; + Infos.emplace_back(llvm::make_unique<Info>()); + Info *InfoD = Infos.back().get(); + InfoD->Name = "D"; + InfoD->USR = serialize::hashUSR("4"); + Infos.emplace_back(llvm::make_unique<Info>()); + Info *InfoF = Infos.back().get(); + InfoF->Name = "F"; + InfoF->USR = serialize::hashUSR("6"); + Reference RefD = Reference("D"); + RefD.USR = serialize::hashUSR("4"); + Reference RefE = Reference("E"); + RefE.USR = serialize::hashUSR("5"); + InfoF->Namespace = {std::move(RefE), std::move(RefD)}; + Index Idx = Generator::genIndex(Infos); + + Index ExpectedIdx; + Index IndexA; + IndexA.Name = "A"; + ExpectedIdx.Children.emplace_back(std::move(IndexA)); + Index IndexB; + IndexB.Name = "B"; + Index IndexC; + IndexC.Name = "C"; + IndexB.Children.emplace_back(std::move(IndexC)); + ExpectedIdx.Children.emplace_back(std::move(IndexB)); + Index IndexD; + IndexD.Name = "D"; + Index IndexE; + IndexE.Name = "E"; + Index IndexF; + IndexF.Name = "F"; + IndexE.Children.emplace_back(std::move(IndexF)); + IndexD.Children.emplace_back(std::move(IndexE)); + ExpectedIdx.Children.emplace_back(std::move(IndexD)); + + CheckIndex(ExpectedIdx, Idx); +} + +} // namespace doc +} // namespace clang Index: clang-tools-extra/unittests/clang-doc/ClangDocTest.h =================================================================== --- clang-tools-extra/unittests/clang-doc/ClangDocTest.h +++ clang-tools-extra/unittests/clang-doc/ClangDocTest.h @@ -44,6 +44,8 @@ void CheckNamespaceInfo(NamespaceInfo *Expected, NamespaceInfo *Actual); void CheckRecordInfo(RecordInfo *Expected, RecordInfo *Actual); +void CheckIndex(Index &Expected, Index &Actual); + } // namespace doc } // namespace clang Index: clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp =================================================================== --- clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp +++ clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp @@ -63,6 +63,7 @@ void CheckReference(Reference &Expected, Reference &Actual) { EXPECT_EQ(Expected.Name, Actual.Name); EXPECT_EQ(Expected.RefType, Actual.RefType); + EXPECT_EQ(Expected.Path, Actual.Path); } void CheckTypeInfo(TypeInfo *Expected, TypeInfo *Actual) { @@ -180,5 +181,12 @@ CheckEnumInfo(&Expected->ChildEnums[Idx], &Actual->ChildEnums[Idx]); } +void CheckIndex(Index &Expected, Index &Actual) { + CheckReference(Expected, Actual); + ASSERT_EQ(Expected.Children.size(), Actual.Children.size()); + for (size_t Idx = 0; Idx < Actual.Children.size(); ++Idx) + CheckIndex(Expected.Children[Idx], Actual.Children[Idx]); +} + } // namespace doc } // namespace clang Index: clang-tools-extra/unittests/clang-doc/CMakeLists.txt =================================================================== --- clang-tools-extra/unittests/clang-doc/CMakeLists.txt +++ clang-tools-extra/unittests/clang-doc/CMakeLists.txt @@ -12,6 +12,7 @@ add_extra_unittest(ClangDocTests BitcodeTest.cpp ClangDocTest.cpp + GeneratorTest.cpp HTMLGeneratorTest.cpp MDGeneratorTest.cpp MergeTest.cpp Index: clang-tools-extra/clang-doc/tool/ClangDocMain.cpp =================================================================== --- clang-tools-extra/clang-doc/tool/ClangDocMain.cpp +++ clang-tools-extra/clang-doc/tool/ClangDocMain.cpp @@ -214,16 +214,23 @@ // First reducing phase (reduce all decls into one info per decl). llvm::outs() << "Reducing " << USRToInfos.size() << " infos...\n"; + std::vector<std::unique_ptr<clang::doc::Info>> ReducedInfos; for (auto &Group : USRToInfos) { auto Reduced = doc::mergeInfos(Group.getValue()); if (!Reduced) { llvm::errs() << llvm::toString(Reduced.takeError()); continue; } + ReducedInfos.emplace_back(std::move(Reduced.get())); + } + + llvm::outs() << "Constructing index...\n"; + CDCtx.Idx = clang::doc::Generator::genIndex(ReducedInfos); - doc::Info *I = Reduced.get().get(); - auto InfoPath = getInfoOutputFile(OutDirectory, I->Path, I->extractName(), - "." + Format); + llvm::outs() << "Generating docs...\n"; + for (auto &Info : ReducedInfos) { + auto InfoPath = getInfoOutputFile(OutDirectory, Info->Path, + Info->extractName(), "." + Format); if (!InfoPath) { llvm::errs() << toString(InfoPath.takeError()) << "\n"; return 1; @@ -235,7 +242,7 @@ continue; } - if (auto Err = G->get()->generateDocForInfo(I, InfoOS)) + if (auto Err = G->get()->generateDocForInfo(Info.get(), InfoOS, CDCtx)) llvm::errs() << toString(std::move(Err)) << "\n"; } Index: clang-tools-extra/clang-doc/YAMLGenerator.cpp =================================================================== --- clang-tools-extra/clang-doc/YAMLGenerator.cpp +++ clang-tools-extra/clang-doc/YAMLGenerator.cpp @@ -243,12 +243,14 @@ public: static const char *Format; - llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override; + llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, + const ClangDocContext &CDCtx) override; }; const char *YAMLGenerator::Format = "yaml"; -llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) { +llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS, + const ClangDocContext &CDCtx) { llvm::yaml::Output InfoYAML(OS); switch (I->IT) { case InfoType::IT_namespace: Index: clang-tools-extra/clang-doc/Representation.h =================================================================== --- clang-tools-extra/clang-doc/Representation.h +++ clang-tools-extra/clang-doc/Representation.h @@ -338,6 +338,18 @@ llvm::SmallVector<SmallString<16>, 4> Members; // List of enum members. }; +struct Index : public Reference { + Index() = default; + Index(SymbolID USR, StringRef Name, InfoType IT, StringRef Path) + : Reference(USR, Name, IT, Path) {} + bool operator==(const SymbolID &Other) const { return USR == Other; } + bool operator<(const Index &Other) const { return Name < Other.Name; } + + std::vector<Index> Children; + + void sort(); +}; + // TODO: Add functionality to include separate markdown pages. // A standalone function to call to merge a vector of infos into one. @@ -347,8 +359,12 @@ mergeInfos(std::vector<std::unique_ptr<Info>> &Values); struct ClangDocContext { + ClangDocContext() = default; + ClangDocContext(tooling::ExecutionContext *ECtx, bool PublicOnly) + : ECtx(ECtx), PublicOnly(PublicOnly) {} tooling::ExecutionContext *ECtx; bool PublicOnly; + Index Idx; }; } // namespace doc Index: clang-tools-extra/clang-doc/Representation.cpp =================================================================== --- clang-tools-extra/clang-doc/Representation.cpp +++ clang-tools-extra/clang-doc/Representation.cpp @@ -229,5 +229,11 @@ return llvm::SmallString<16>(""); } +void Index::sort() { + std::sort(Children.begin(), Children.end()); + for (auto &C : Children) + C.sort(); +} + } // namespace doc } // namespace clang Index: clang-tools-extra/clang-doc/MDGenerator.cpp =================================================================== --- clang-tools-extra/clang-doc/MDGenerator.cpp +++ clang-tools-extra/clang-doc/MDGenerator.cpp @@ -250,12 +250,14 @@ public: static const char *Format; - llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override; + llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, + const ClangDocContext &CDCtx) override; }; const char *MDGenerator::Format = "md"; -llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) { +llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS, + const ClangDocContext &CDCtx) { switch (I->IT) { case InfoType::IT_namespace: genMarkdown(*static_cast<clang::doc::NamespaceInfo *>(I), OS); Index: clang-tools-extra/clang-doc/HTMLGenerator.cpp =================================================================== --- clang-tools-extra/clang-doc/HTMLGenerator.cpp +++ clang-tools-extra/clang-doc/HTMLGenerator.cpp @@ -24,16 +24,17 @@ public: // Any other tag can be added if required enum TagType { - TAG_META, - TAG_TITLE, + TAG_A, TAG_DIV, TAG_H1, TAG_H2, TAG_H3, + TAG_LI, + TAG_META, TAG_P, + TAG_SPAN, + TAG_TITLE, TAG_UL, - TAG_LI, - TAG_A, }; HTMLTag() = default; @@ -115,15 +116,16 @@ switch (Value) { case HTMLTag::TAG_META: return true; - case HTMLTag::TAG_TITLE: + case HTMLTag::TAG_A: case HTMLTag::TAG_DIV: case HTMLTag::TAG_H1: case HTMLTag::TAG_H2: case HTMLTag::TAG_H3: + case HTMLTag::TAG_LI: case HTMLTag::TAG_P: + case HTMLTag::TAG_SPAN: + case HTMLTag::TAG_TITLE: case HTMLTag::TAG_UL: - case HTMLTag::TAG_LI: - case HTMLTag::TAG_A: return false; } llvm_unreachable("Unhandled HTMLTag::TagType"); @@ -131,13 +133,14 @@ bool HTMLTag::HasInlineChildren() const { switch (Value) { - case HTMLTag::TAG_META: - case HTMLTag::TAG_TITLE: + case HTMLTag::TAG_A: case HTMLTag::TAG_H1: case HTMLTag::TAG_H2: case HTMLTag::TAG_H3: case HTMLTag::TAG_LI: - case HTMLTag::TAG_A: + case HTMLTag::TAG_META: + case HTMLTag::TAG_SPAN: + case HTMLTag::TAG_TITLE: return true; case HTMLTag::TAG_DIV: case HTMLTag::TAG_P: @@ -149,10 +152,8 @@ llvm::SmallString<16> HTMLTag::ToString() const { switch (Value) { - case HTMLTag::TAG_META: - return llvm::SmallString<16>("meta"); - case HTMLTag::TAG_TITLE: - return llvm::SmallString<16>("title"); + case HTMLTag::TAG_A: + return llvm::SmallString<16>("a"); case HTMLTag::TAG_DIV: return llvm::SmallString<16>("div"); case HTMLTag::TAG_H1: @@ -161,14 +162,18 @@ return llvm::SmallString<16>("h2"); case HTMLTag::TAG_H3: return llvm::SmallString<16>("h3"); + case HTMLTag::TAG_LI: + return llvm::SmallString<16>("li"); + case HTMLTag::TAG_META: + return llvm::SmallString<16>("meta"); case HTMLTag::TAG_P: return llvm::SmallString<16>("p"); + case HTMLTag::TAG_SPAN: + return llvm::SmallString<16>("span"); + case HTMLTag::TAG_TITLE: + return llvm::SmallString<16>("title"); case HTMLTag::TAG_UL: 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"); } @@ -362,6 +367,37 @@ "Defined at line " + std::to_string(L.LineNumber) + " of " + L.Filename); } +static std::vector<std::unique_ptr<TagNode>> +genCommonFileNodes(StringRef Title) { + std::vector<std::unique_ptr<TagNode>> Out; + auto MetaNode = llvm::make_unique<TagNode>(HTMLTag::TAG_META); + MetaNode->Attributes.try_emplace("charset", "utf-8"); + Out.emplace_back(std::move(MetaNode)); + Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_TITLE, Title)); + return Out; +} + +static std::vector<std::unique_ptr<TagNode>> genHTML(const Index &Index, + StringRef InfoPath) { + std::vector<std::unique_ptr<TagNode>> Out; + if (!Index.Name.empty()) { + Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_SPAN)); + auto &SpanBody = Out.back(); + SpanBody->Children.emplace_back(genTypeReference(Index, InfoPath)); + } + if (Index.Children.empty()) + return Out; + Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_UL)); + const auto &UlBody = Out.back(); + for (const auto &C : Index.Children) { + auto LiBody = llvm::make_unique<TagNode>(HTMLTag::TAG_LI); + std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(C, InfoPath); + AppendVector(std::move(Nodes), LiBody->Children); + UlBody->Children.emplace_back(std::move(LiBody)); + } + return Out; +} + static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) { if (I.Kind == "FullComment") { auto FullComment = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV); @@ -548,20 +584,16 @@ public: static const char *Format; - llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override; + llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, + const ClangDocContext &CDCtx) override; }; const char *HTMLGenerator::Format = "html"; -llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) { +llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS, + const ClangDocContext &CDCtx) { HTMLFile F; - - auto MetaNode = llvm::make_unique<TagNode>(HTMLTag::TAG_META); - MetaNode->Attributes.try_emplace("charset", "utf-8"); - F.Children.emplace_back(std::move(MetaNode)); - std::string InfoTitle; - Info CastedInfo; auto MainContentNode = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV); switch (I->IT) { case InfoType::IT_namespace: { @@ -593,8 +625,11 @@ llvm::inconvertibleErrorCode()); } - F.Children.emplace_back( - llvm::make_unique<TagNode>(HTMLTag::TAG_TITLE, InfoTitle)); + std::vector<std::unique_ptr<TagNode>> BasicNodes = + genCommonFileNodes(InfoTitle); + AppendVector(std::move(BasicNodes), F.Children); + std::vector<std::unique_ptr<TagNode>> Index = genHTML(CDCtx.Idx, I->Path); + AppendVector(std::move(Index), F.Children); F.Children.emplace_back(std::move(MainContentNode)); F.Render(OS); Index: clang-tools-extra/clang-doc/Generators.h =================================================================== --- clang-tools-extra/clang-doc/Generators.h +++ clang-tools-extra/clang-doc/Generators.h @@ -25,8 +25,11 @@ public: virtual ~Generator() = default; + static Index genIndex(const std::vector<std::unique_ptr<Info>> &Infos); + // Write out the decl info in the specified format. - virtual llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) = 0; + virtual llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, + const ClangDocContext &CDCtx) = 0; }; typedef llvm::Registry<Generator> GeneratorRegistry; Index: clang-tools-extra/clang-doc/Generators.cpp =================================================================== --- clang-tools-extra/clang-doc/Generators.cpp +++ clang-tools-extra/clang-doc/Generators.cpp @@ -13,6 +13,30 @@ namespace clang { namespace doc { +Index Generator::genIndex(const std::vector<std::unique_ptr<Info>> &Infos) { + Index Idx; + for (const auto &Info : Infos) { + Index *I = &Idx; + for (auto R = Info->Namespace.rbegin(), E = Info->Namespace.rend(); R != E; + ++R) { + auto It = std::find(I->Children.begin(), I->Children.end(), R->USR); + if (It != I->Children.end()) + I = &*It; + else { + I->Children.emplace_back(R->USR, R->Name, R->RefType, R->Path); + I = &I->Children.back(); + } + } + auto It = std::find(I->Children.begin(), I->Children.end(), Info->USR); + if (It == I->Children.end()) + I->Children.emplace_back(Info->USR, Info->Name, Info->IT, Info->Path); + else if (It->Path.empty()) + It->Path = I->Path; + } + Idx.sort(); + return Idx; +} + llvm::Expected<std::unique_ptr<Generator>> findGeneratorByName(llvm::StringRef Format) { for (auto I = GeneratorRegistry::begin(), E = GeneratorRegistry::end();
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits