[llvm-branch-commits] [clang-tools-extra] [clang-doc] Add HTMLMustacheGenerator methods (PR #138061)
Paul Kirth via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri May 9 15:30:04 PDT 2025
https://github.com/ilovepi updated https://github.com/llvm/llvm-project/pull/138061
>From 71b00d168afcbe63964ea4aa99074a6a152daddb Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Wed, 30 Apr 2025 08:09:41 -0700
Subject: [PATCH] [clang-doc] Add HTMLMustacheGenerator methods
Split from #133161. This patch fills in the implementation for a number
of the MustacheHTMLGenerator methods. Many of these APIs are just
stubbed out, and will have their implementation filled in by later
patches.
Co-authored-by: Peter Chou <peter.chou at mail.utoronto.ca>
---
.../clang-doc/HTMLMustacheGenerator.cpp | 102 ++++++++++++++++++
.../unittests/clang-doc/CMakeLists.txt | 1 +
.../clang-doc/HTMLMustacheGeneratorTest.cpp | 37 ++++++-
3 files changed, 137 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index 229ea50bceb15..d198eaf0b6a70 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -41,6 +41,7 @@ class MustacheHTMLGenerator : public Generator {
const ClangDocContext &CDCtx) override;
};
+
class MustacheTemplateFile : public Template {
public:
static Expected<std::unique_ptr<MustacheTemplateFile>>
@@ -68,20 +69,121 @@ class MustacheTemplateFile : public Template {
}
MustacheTemplateFile(StringRef TemplateStr) : Template(TemplateStr) {}
+private:
};
+static std::unique_ptr<MustacheTemplateFile> NamespaceTemplate = nullptr;
+
+static std::unique_ptr<MustacheTemplateFile> RecordTemplate = nullptr;
+
+static Error setupTemplateFiles(const clang::doc::ClangDocContext &CDCtx) {
+ return Error::success();
+}
+
Error MustacheHTMLGenerator::generateDocs(
StringRef RootDir, StringMap<std::unique_ptr<doc::Info>> Infos,
const clang::doc::ClangDocContext &CDCtx) {
+ if (auto Err = setupTemplateFiles(CDCtx))
+ return Err;
+ // Track which directories we already tried to create.
+ StringSet<> CreatedDirs;
+ // Collect all output by file name and create the necessary directories.
+ StringMap<std::vector<doc::Info *>> FileToInfos;
+ for (const auto &Group : Infos) {
+ doc::Info *Info = Group.getValue().get();
+
+ SmallString<128> Path;
+ sys::path::native(RootDir, Path);
+ sys::path::append(Path, Info->getRelativeFilePath(""));
+ if (!CreatedDirs.contains(Path)) {
+ if (std::error_code Err = sys::fs::create_directories(Path);
+ Err != std::error_code())
+ return createStringError(Err, "failed to create directory '%s'.",
+ Path.c_str());
+ CreatedDirs.insert(Path);
+ }
+
+ sys::path::append(Path, Info->getFileBaseName() + ".html");
+ FileToInfos[Path].push_back(Info);
+ }
+
+ for (const auto &Group : FileToInfos) {
+ std::error_code FileErr;
+ raw_fd_ostream InfoOS(Group.getKey(), FileErr, sys::fs::OF_None);
+ if (FileErr)
+ return createStringError(FileErr, "Error opening file '%s'",
+ Group.getKey().data());
+
+ for (const auto &Info : Group.getValue()) {
+ if (Error Err = generateDocForInfo(Info, InfoOS, CDCtx))
+ return Err;
+ }
+ }
return Error::success();
}
+static json::Value extractValue(const NamespaceInfo &I,
+ const ClangDocContext &CDCtx) {
+ Object NamespaceValue = Object();
+ return NamespaceValue;
+}
+
+static json::Value extractValue(const RecordInfo &I,
+ const ClangDocContext &CDCtx) {
+ Object RecordValue = Object();
+ return RecordValue;
+}
+
+static Error setupTemplateValue(const ClangDocContext &CDCtx, json::Value &V,
+ Info *I) {
+ return createStringError(inconvertibleErrorCode(),
+ "setupTemplateValue is unimplemented");
+}
+
Error MustacheHTMLGenerator::generateDocForInfo(Info *I, raw_ostream &OS,
const ClangDocContext &CDCtx) {
+ switch (I->IT) {
+ case InfoType::IT_namespace: {
+ json::Value V =
+ extractValue(*static_cast<clang::doc::NamespaceInfo *>(I), CDCtx);
+ if (auto Err = setupTemplateValue(CDCtx, V, I))
+ return Err;
+ NamespaceTemplate->render(V, OS);
+ break;
+ }
+ case InfoType::IT_record: {
+ json::Value V =
+ extractValue(*static_cast<clang::doc::RecordInfo *>(I), CDCtx);
+ if (auto Err = setupTemplateValue(CDCtx, V, I))
+ return Err;
+ // Serialize the JSON value to the output stream in a readable format.
+ RecordTemplate->render(V, OS);
+ break;
+ }
+ case InfoType::IT_enum:
+ OS << "IT_enum\n";
+ break;
+ case InfoType::IT_function:
+ OS << "IT_Function\n";
+ break;
+ case InfoType::IT_typedef:
+ OS << "IT_typedef\n";
+ break;
+ case InfoType::IT_default:
+ return createStringError(inconvertibleErrorCode(), "unexpected InfoType");
+ }
return Error::success();
}
Error MustacheHTMLGenerator::createResources(ClangDocContext &CDCtx) {
+ for (const auto &FilePath : CDCtx.UserStylesheets) {
+ if (Error Err = copyFile(FilePath, CDCtx.OutDirectory))
+ return Err;
+ }
+ for (const auto &FilePath : CDCtx.JsScripts) {
+ if (Error Err = copyFile(FilePath, CDCtx.OutDirectory))
+ return Err;
+ }
return Error::success();
}
diff --git a/clang-tools-extra/unittests/clang-doc/CMakeLists.txt b/clang-tools-extra/unittests/clang-doc/CMakeLists.txt
index 81c18e6014072..fd14d85c63485 100644
--- a/clang-tools-extra/unittests/clang-doc/CMakeLists.txt
+++ b/clang-tools-extra/unittests/clang-doc/CMakeLists.txt
@@ -34,6 +34,7 @@ clang_target_link_libraries(ClangDocTests
clangTooling
clangToolingCore
)
+
target_link_libraries(ClangDocTests
PRIVATE
clangDoc
diff --git a/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp
index 2d54c26fee570..e1b06380cd25a 100644
--- a/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp
@@ -10,7 +10,9 @@
#include "Generators.h"
#include "Representation.h"
#include "clang/Basic/Version.h"
+#include "llvm/Support/Path.h"
#include "llvm/Testing/Support/Error.h"
+#include "llvm/Testing/Support/SupportHelpers.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -40,13 +42,43 @@ getClangDocContext(std::vector<std::string> UserStylesheets = {},
return CDCtx;
}
+static void verifyFileContents(const Twine &Path, StringRef Contents) {
+ auto Buffer = MemoryBuffer::getFile(Path);
+ ASSERT_TRUE((bool)Buffer);
+ StringRef Data = Buffer.get()->getBuffer();
+ ASSERT_EQ(Data, Contents);
+}
+
TEST(HTMLMustacheGeneratorTest, createResources) {
auto G = getHTMLMustacheGenerator();
ASSERT_THAT(G, NotNull()) << "Could not find HTMLMustacheGenerator";
ClangDocContext CDCtx = getClangDocContext();
+ EXPECT_THAT_ERROR(G->createResources(CDCtx), Failed())
+ << "Empty UserStylesheets or JsScripts should fail!";
+
+ unittest::TempDir RootTestDirectory("createResourcesTest", /*Unique=*/true);
+ CDCtx.OutDirectory = RootTestDirectory.path();
+
+ unittest::TempFile CSS("clang-doc-mustache", "css", "CSS");
+ unittest::TempFile JS("mustache", "js", "JavaScript");
+
+ CDCtx.UserStylesheets[0] = CSS.path();
+ CDCtx.JsScripts[0] = JS.path();
EXPECT_THAT_ERROR(G->createResources(CDCtx), Succeeded())
- << "Failed to create resources.";
+ << "Failed to create resources with valid UserStylesheets and JsScripts";
+ {
+ SmallString<256> PathBuff;
+ llvm::sys::path::append(PathBuff, RootTestDirectory.path(),
+ "clang-doc-mustache.css");
+ verifyFileContents(PathBuff, "CSS");
+ }
+
+ {
+ SmallString<256> PathBuff;
+ llvm::sys::path::append(PathBuff, RootTestDirectory.path(), "mustache.js");
+ verifyFileContents(PathBuff, "JavaScript");
+ }
}
TEST(HTMLMustacheGeneratorTest, generateDocs) {
@@ -79,8 +111,7 @@ TEST(HTMLMustacheGeneratorTest, generateDocsForInfo) {
I.Children.Functions.back().Name = "OneFunction";
I.Children.Enums.emplace_back();
- EXPECT_THAT_ERROR(G->generateDocForInfo(&I, Actual, CDCtx), Succeeded())
- << "Failed to generate docs.";
+ EXPECT_THAT_ERROR(G->generateDocForInfo(&I, Actual, CDCtx), Failed());
std::string Expected = R"raw()raw";
EXPECT_THAT(Actual.str(), Eq(Expected));
More information about the llvm-branch-commits
mailing list