https://github.com/ilovepi updated https://github.com/llvm/llvm-project/pull/138064
>From 72da18f86f4ce50cbd804ae47feb6baeb275e159 Mon Sep 17 00:00:00 2001 From: Paul Kirth <paulki...@google.com> Date: Wed, 30 Apr 2025 08:13:46 -0700 Subject: [PATCH] [clang-doc] Implement setupTemplateValue for HTMLMustacheGenerator This patch implements the business logic for setupTemplateValue, which was split from #133161. The implementation configures the relative path relationships between the various HTML components, and prepares them prior to their use in the generator. The tests here are disabled by default until we can use lit tests via tool support, since we cannot read files in the unit tests. Co-authored-by: Peter Chou <peter.c...@mail.utoronto.ca> --- .../clang-doc/HTMLMustacheGenerator.cpp | 27 ++- .../clang-doc/HTMLMustacheGeneratorTest.cpp | 193 ++++++++++++++++-- 2 files changed, 199 insertions(+), 21 deletions(-) diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp index 18ee3b8d0fc43..65dc2e93582e8 100644 --- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp +++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp @@ -397,7 +397,7 @@ static json::Value extractValue(const RecordInfo &I, maybeInsertLocation(I.DefLoc, CDCtx, RecordValue); - StringRef BasePath = I.getRelativeFilePath(""); + SmallString<64> BasePath = I.getRelativeFilePath(""); extractScopeChildren(I.Children, RecordValue, BasePath, CDCtx); json::Value PublicMembers = Array(); json::Array &PubMemberRef = *PublicMembers.getAsArray(); @@ -431,8 +431,28 @@ static json::Value extractValue(const RecordInfo &I, static Error setupTemplateValue(const ClangDocContext &CDCtx, json::Value &V, Info *I) { - return createStringError(inconvertibleErrorCode(), - "setupTemplateValue is unimplemented"); + V.getAsObject()->insert({"ProjectName", CDCtx.ProjectName}); + json::Value StylesheetArr = Array(); + auto InfoPath = I->getRelativeFilePath(""); + SmallString<128> RelativePath = computeRelativePath("", InfoPath); + sys::path::native(RelativePath, sys::path::Style::posix); + for (const auto &FilePath : CDCtx.UserStylesheets) { + SmallString<128> StylesheetPath = RelativePath; + sys::path::append(StylesheetPath, sys::path::Style::posix, + sys::path::filename(FilePath)); + StylesheetArr.getAsArray()->emplace_back(StylesheetPath); + } + V.getAsObject()->insert({"Stylesheets", StylesheetArr}); + + json::Value ScriptArr = Array(); + for (auto Script : CDCtx.JsScripts) { + SmallString<128> JsPath = RelativePath; + sys::path::append(JsPath, sys::path::Style::posix, + sys::path::filename(Script)); + ScriptArr.getAsArray()->emplace_back(JsPath); + } + V.getAsObject()->insert({"Scripts", ScriptArr}); + return Error::success(); } Error MustacheHTMLGenerator::generateDocForInfo(Info *I, raw_ostream &OS, @@ -443,6 +463,7 @@ Error MustacheHTMLGenerator::generateDocForInfo(Info *I, raw_ostream &OS, extractValue(*static_cast<clang::doc::NamespaceInfo *>(I), CDCtx); if (auto Err = setupTemplateValue(CDCtx, V, I)) return Err; + assert(NamespaceTemplate && "NamespaceTemplate is nullptr."); NamespaceTemplate->render(V, OS); break; } diff --git a/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp index 4c8cf4fa7e460..95acd363a958e 100644 --- a/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp +++ b/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp @@ -20,10 +20,14 @@ using namespace llvm; using namespace testing; +using namespace clang; using namespace clang::doc; -static const std::string ClangDocVersion = - clang::getClangToolFullVersion("clang-doc"); +// FIXME: Don't enable unit tests that can read files. Remove once we can use +// lit to test these properties. +#define ENABLE_LOCAL_TEST 0 + +static const std::string ClangDocVersion = getClangToolFullVersion("clang-doc"); static std::unique_ptr<Generator> getHTMLMustacheGenerator() { auto G = findGeneratorByName("mustache"); @@ -91,37 +95,190 @@ TEST(HTMLMustacheGeneratorTest, generateDocs) { unittest::TempDir RootTestDirectory("generateDocsTest", /*Unique=*/true); CDCtx.OutDirectory = RootTestDirectory.path(); +#if ENABLE_LOCAL_TEST // FIXME: We can't read files during unit tests. Migrate to lit once // tool support lands. - // getMustacheHtmlFiles(CLANG_DOC_TEST_ASSET_DIR, CDCtx); + getMustacheHtmlFiles(CLANG_DOC_TEST_ASSET_DIR, CDCtx); + EXPECT_THAT_ERROR(G->generateDocs(RootTestDirectory.path(), {}, CDCtx), + Succeeded()) + << "Failed to generate docs."; +#else EXPECT_THAT_ERROR(G->generateDocs(RootTestDirectory.path(), {}, CDCtx), Failed()) << "Failed to generate docs."; +#endif } -TEST(HTMLMustacheGeneratorTest, generateDocsForInfo) { +TEST(HTMLGeneratorTest, emitFunctionHTML) { +#if ENABLE_LOCAL_TEST auto G = getHTMLMustacheGenerator(); assert(G && "Could not find HTMLMustacheGenerator"); ClangDocContext CDCtx = getClangDocContext(); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - NamespaceInfo I; - I.Name = "Namespace"; + + unittest::TempDir RootTestDirectory("emitRecordHTML", + /*Unique=*/true); + CDCtx.OutDirectory = RootTestDirectory.path(); + + getMustacheHtmlFiles(CLANG_DOC_TEST_ASSET_DIR, CDCtx); + + // FIXME: This is a terrible hack, since we can't initialize the templates + // directly. We'll need to update the interfaces so that we can call + // SetupTemplateFiles() from outsize of HTMLMustacheGenerator.cpp + EXPECT_THAT_ERROR(G->generateDocs(RootTestDirectory.path(), {}, CDCtx), + Succeeded()) + << "Failed to generate docs."; + + CDCtx.RepositoryUrl = "http://www.repository.com"; + + FunctionInfo I; + I.Name = "f"; I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace); - I.Children.Namespaces.emplace_back(EmptySID, "ChildNamespace", - InfoType::IT_namespace, - "Namespace::ChildNamespace", "Namespace"); - I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record, - "Namespace::ChildStruct", "Namespace"); - I.Children.Functions.emplace_back(); - I.Children.Functions.back().Access = clang::AccessSpecifier::AS_none; - I.Children.Functions.back().Name = "OneFunction"; - I.Children.Enums.emplace_back(); + I.DefLoc = Location(10, 10, "dir/test.cpp", true); + I.Loc.emplace_back(12, 12, "test.cpp"); + + I.Access = AccessSpecifier::AS_none; + + SmallString<16> PathTo; + llvm::sys::path::native("path/to", PathTo); + I.ReturnType = doc::TypeInfo( + Reference(EmptySID, "float", InfoType::IT_default, "float", PathTo)); + I.Params.emplace_back(doc::TypeInfo("int", PathTo), "P"); + I.IsMethod = true; + I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record); + + auto Err = G->generateDocForInfo(&I, Actual, CDCtx); + assert(!Err); + std::string Expected = R"raw(IT_Function +)raw"; + + // FIXME: Functions are not handled yet. + EXPECT_EQ(Expected, Actual.str()); +#endif +} + +TEST(HTMLMustacheGeneratorTest, emitEnumHTML) { +#if ENABLE_LOCAL_TEST + auto G = getHTMLMustacheGenerator(); + assert(G && "Could not find HTMLMustacheGenerator"); + ClangDocContext CDCtx = getClangDocContext(); + std::string Buffer; + llvm::raw_string_ostream Actual(Buffer); + + unittest::TempDir RootTestDirectory("emitEnumHTML", + /*Unique=*/true); + CDCtx.OutDirectory = RootTestDirectory.path(); + + getMustacheHtmlFiles(CLANG_DOC_TEST_ASSET_DIR, CDCtx); + + // FIXME: This is a terrible hack, since we can't initialize the templates + // directly. We'll need to update the interfaces so that we can call + // SetupTemplateFiles() from outsize of HTMLMustacheGenerator.cpp + EXPECT_THAT_ERROR(G->generateDocs(RootTestDirectory.path(), {}, CDCtx), + Succeeded()) + << "Failed to generate docs."; + + CDCtx.RepositoryUrl = "http://www.repository.com"; + + EnumInfo I; + I.Name = "e"; + I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace); + + I.DefLoc = Location(10, 10, "test.cpp", true); + I.Loc.emplace_back(12, 12, "test.cpp"); + + I.Members.emplace_back("X"); + I.Scoped = true; + + auto Err = G->generateDocForInfo(&I, Actual, CDCtx); + assert(!Err); + + std::string Expected = R"raw(IT_enum +)raw"; + + // FIXME: Enums are not handled yet. + EXPECT_EQ(Expected, Actual.str()); +#endif +} + +TEST(HTMLMustacheGeneratorTest, emitCommentHTML) { +#if ENABLE_LOCAL_TEST + auto G = getHTMLMustacheGenerator(); + assert(G && "Could not find HTMLMustacheGenerator"); + ClangDocContext CDCtx = getClangDocContext(); + std::string Buffer; + llvm::raw_string_ostream Actual(Buffer); + + unittest::TempDir RootTestDirectory("emitCommentHTML", + /*Unique=*/true); + CDCtx.OutDirectory = RootTestDirectory.path(); + + getMustacheHtmlFiles(CLANG_DOC_TEST_ASSET_DIR, CDCtx); + + // FIXME: This is a terrible hack, since we can't initialize the templates + // directly. We'll need to update the interfaces so that we can call + // SetupTemplateFiles() from outsize of HTMLMustacheGenerator.cpp + EXPECT_THAT_ERROR(G->generateDocs(RootTestDirectory.path(), {}, CDCtx), + Succeeded()) + << "Failed to generate docs."; + + CDCtx.RepositoryUrl = "http://www.repository.com"; + + FunctionInfo I; + I.Name = "f"; + I.DefLoc = Location(10, 10, "test.cpp", true); + I.ReturnType = doc::TypeInfo("void"); + I.Params.emplace_back(doc::TypeInfo("int"), "I"); + I.Params.emplace_back(doc::TypeInfo("int"), "J"); + I.Access = AccessSpecifier::AS_none; + + CommentInfo Top; + Top.Kind = "FullComment"; + + Top.Children.emplace_back(std::make_unique<CommentInfo>()); + CommentInfo *BlankLine = Top.Children.back().get(); + BlankLine->Kind = "ParagraphComment"; + BlankLine->Children.emplace_back(std::make_unique<CommentInfo>()); + BlankLine->Children.back()->Kind = "TextComment"; + + Top.Children.emplace_back(std::make_unique<CommentInfo>()); + CommentInfo *Brief = Top.Children.back().get(); + Brief->Kind = "ParagraphComment"; + Brief->Children.emplace_back(std::make_unique<CommentInfo>()); + Brief->Children.back()->Kind = "TextComment"; + Brief->Children.back()->Name = "ParagraphComment"; + Brief->Children.back()->Text = " Brief description."; + + Top.Children.emplace_back(std::make_unique<CommentInfo>()); + CommentInfo *Extended = Top.Children.back().get(); + Extended->Kind = "ParagraphComment"; + Extended->Children.emplace_back(std::make_unique<CommentInfo>()); + Extended->Children.back()->Kind = "TextComment"; + Extended->Children.back()->Text = " Extended description that"; + Extended->Children.emplace_back(std::make_unique<CommentInfo>()); + Extended->Children.back()->Kind = "TextComment"; + Extended->Children.back()->Text = " continues onto the next line."; + + Top.Children.emplace_back(std::make_unique<CommentInfo>()); + CommentInfo *Entities = Top.Children.back().get(); + Entities->Kind = "ParagraphComment"; + Entities->Children.emplace_back(std::make_unique<CommentInfo>()); + Entities->Children.back()->Kind = "TextComment"; + Entities->Children.back()->Name = "ParagraphComment"; + Entities->Children.back()->Text = + " Comment with html entities: &, <, >, \", \'."; + + I.Description.emplace_back(std::move(Top)); - EXPECT_THAT_ERROR(G->generateDocForInfo(&I, Actual, CDCtx), Failed()); + auto Err = G->generateDocForInfo(&I, Actual, CDCtx); + assert(!Err); + std::string Expected = R"raw(IT_Function +)raw"; - std::string Expected = R"raw()raw"; - EXPECT_THAT(Actual.str(), Eq(Expected)); + // FIXME: Functions are not handled yet. + EXPECT_EQ(Expected, Actual.str()); +#endif } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits