llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-tools-extra Author: Erick Velez (evelez7) <details> <summary>Changes</summary> Focus is shifting to the Mustache-backed Markdown generator which is now called by `--format=md`. Any potential gaps in functionality are documented in #<!-- -->201945. --- Patch is 82.39 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/209071.diff 22 Files Affected: - (modified) clang-tools-extra/clang-doc/CMakeLists.txt (-1) - (modified) clang-tools-extra/clang-doc/Generators.cpp (-2) - (modified) clang-tools-extra/clang-doc/Generators.h (-1) - (modified) clang-tools-extra/clang-doc/JSONGenerator.cpp (+1-1) - (modified) clang-tools-extra/clang-doc/MDGenerator.cpp (+82-578) - (removed) clang-tools-extra/clang-doc/MDMustacheGenerator.cpp (-121) - (modified) clang-tools-extra/clang-doc/Representation.h (+1-1) - (modified) clang-tools-extra/clang-doc/tool/ClangDocMain.cpp (+13-16) - (modified) clang-tools-extra/test/clang-doc/basic-project.mustache.test (+1-1) - (modified) clang-tools-extra/test/clang-doc/basic-project.test (+1-126) - (modified) clang-tools-extra/test/clang-doc/md/array-type.cpp (+1-4) - (modified) clang-tools-extra/test/clang-doc/md/builtin_types.cpp (+3-33) - (modified) clang-tools-extra/test/clang-doc/md/class-partial-specialization.cpp (+1-4) - (modified) clang-tools-extra/test/clang-doc/md/comments-in-macros.cpp (+4-11) - (modified) clang-tools-extra/test/clang-doc/md/enum.cpp (+21-93) - (modified) clang-tools-extra/test/clang-doc/md/function-pointer-type.cpp (+1-4) - (modified) clang-tools-extra/test/clang-doc/md/member-function-pointer-type.cpp (+1-4) - (modified) clang-tools-extra/test/clang-doc/md/namespace.cpp (+26-118) - (modified) clang-tools-extra/test/clang-doc/md/nested-pointer-qualifiers.cpp (-3) - (modified) clang-tools-extra/test/clang-doc/md/templates.cpp (+1-27) - (modified) clang-tools-extra/unittests/clang-doc/CMakeLists.txt (-1) - (removed) clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp (-428) ``````````diff diff --git a/clang-tools-extra/clang-doc/CMakeLists.txt b/clang-tools-extra/clang-doc/CMakeLists.txt index 438888c1e5e13..f4d86e8830a6b 100644 --- a/clang-tools-extra/clang-doc/CMakeLists.txt +++ b/clang-tools-extra/clang-doc/CMakeLists.txt @@ -18,7 +18,6 @@ add_clang_library(clangDoc STATIC Serialize.cpp YAMLGenerator.cpp JSONGenerator.cpp - MDMustacheGenerator.cpp DEPENDS omp_gen diff --git a/clang-tools-extra/clang-doc/Generators.cpp b/clang-tools-extra/clang-doc/Generators.cpp index 5ff1a5c0a4eb2..c0933f06c1789 100644 --- a/clang-tools-extra/clang-doc/Generators.cpp +++ b/clang-tools-extra/clang-doc/Generators.cpp @@ -252,7 +252,5 @@ void Generator::addInfoToIndex(Index &Idx, const doc::Info *Info) { [[maybe_unused]] static int MDGeneratorAnchorDest = MDGeneratorAnchorSource; [[maybe_unused]] static int HTMLGeneratorAnchorDest = HTMLGeneratorAnchorSource; [[maybe_unused]] static int JSONGeneratorAnchorDest = JSONGeneratorAnchorSource; -[[maybe_unused]] static int MDMustacheGeneratorAnchorDest = - MDMustacheGeneratorAnchorSource; } // namespace doc } // namespace clang diff --git a/clang-tools-extra/clang-doc/Generators.h b/clang-tools-extra/clang-doc/Generators.h index fc7fdb515ee4f..7b2d5c7f97f5e 100644 --- a/clang-tools-extra/clang-doc/Generators.h +++ b/clang-tools-extra/clang-doc/Generators.h @@ -144,7 +144,6 @@ extern volatile int YAMLGeneratorAnchorSource; extern volatile int MDGeneratorAnchorSource; extern volatile int HTMLGeneratorAnchorSource; extern volatile int JSONGeneratorAnchorSource; -extern volatile int MDMustacheGeneratorAnchorSource; } // namespace doc } // namespace clang diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp index 1a15618b14bf4..58995c249bd21 100644 --- a/clang-tools-extra/clang-doc/JSONGenerator.cpp +++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp @@ -1023,7 +1023,7 @@ Error JSONGenerator::generateDocumentation(StringRef RootDir, Info->DocumentationFileName = internString(FileName); } - if (CDCtx.Format == OutputFormatTy::md_mustache) { + if (CDCtx.Format == OutputFormatTy::md) { Markdown = true; if (auto Err = serializeAllFiles(CDCtx, RootDir)) return Err; diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp b/clang-tools-extra/clang-doc/MDGenerator.cpp index 2129880c890f4..f496f1fc44f9d 100644 --- a/clang-tools-extra/clang-doc/MDGenerator.cpp +++ b/clang-tools-extra/clang-doc/MDGenerator.cpp @@ -1,615 +1,119 @@ -//===-- MDGenerator.cpp - Markdown Generator --------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the implementation of the MDGenerator, which +/// generates documentation in Markdown format using Mustache templates. It +/// defines how the structured data in Info objects is mapped to template +/// tags to produce readable markdown documents. +/// +//===----------------------------------------------------------------------===// #include "Generators.h" -#include "Representation.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" -#include <string> using namespace llvm; using namespace clang::doc; -// Markdown generation - -static std::string genItalic(const Twine &Text) { - return "*" + Text.str() + "*"; -} - -static std::string genEmphasis(const Twine &Text) { - return "**" + Text.str() + "**"; -} - -static std::string genReferenceList(llvm::ArrayRef<Reference> Refs) { - std::string Buffer; - llvm::raw_string_ostream Stream(Buffer); - for (const auto &R : Refs) { - if (&R != Refs.begin()) - Stream << ", "; - Stream << R.Name; - } - return Stream.str(); -} - -static void writeLine(const Twine &Text, raw_ostream &OS) { - OS << Text << "\n\n"; -} - -static void writeNewLine(raw_ostream &OS) { OS << "\n\n"; } - -static void writeHeader(const Twine &Text, unsigned int Num, raw_ostream &OS) { - OS << std::string(Num, '#') + " " + Text << "\n\n"; -} +static std::unique_ptr<MustacheTemplateFile> RecordTemplate = nullptr; -static void writeSourceFileRef(const ClangDocContext &CDCtx, const Location &L, - raw_ostream &OS) { +static std::unique_ptr<MustacheTemplateFile> NamespaceTemplate = nullptr; - if (!CDCtx.RepositoryUrl) { - OS << "*Defined at " << L.Filename << "#" - << std::to_string(L.StartLineNumber) << "*"; - } else { +static std::unique_ptr<MustacheTemplateFile> AllFilesTemplate = nullptr; - OS << formatv("*Defined at [#{0}{1}{2}](#{0}{1}{3})*", - CDCtx.RepositoryLinePrefix.value_or(""), L.StartLineNumber, - L.Filename, *CDCtx.RepositoryUrl); - } - OS << "\n\n"; -} - -/// Writer for writing comments to a table cell in MD. -/// -/// The writer traverses the comments recursively and outputs the -/// comments into a stream. -/// The formatter inserts single/double line breaks to retain the comment -/// structure. -/// -/// Usage : -/// Initialize an object with a llvm::raw_ostream to output into. -/// Call the write(C) function with an array of Comments 'C'. -class TableCommentWriter { -public: - explicit TableCommentWriter(llvm::raw_ostream &OS) : OS(OS) {} - - void write(const DocList<CommentInfo> &Comments) { - for (const auto &C : Comments) - writeTableSafeComment(C); - - if (!Started) - OS << "--"; - } - -private: - /// This function inserts breaks into the stream. - /// - /// We add a double break in between paragraphs. - /// Inside a paragraph, a single break between lines is maintained. - void insertSeparator() { - if (!Started) - return; - if (NeedsParagraphBreak) { - OS << "<br><br>"; - NeedsParagraphBreak = false; - } else { - OS << "<br>"; - } - } - - /// This function processes every comment and its children recursively. - void writeTableSafeComment(const CommentInfo &I) { - switch (I.Kind) { - case CommentKind::CK_FullComment: - for (const auto &Child : I.Children) - writeTableSafeComment(Child); - break; - - case CommentKind::CK_ParagraphComment: - for (const auto &Child : I.Children) - writeTableSafeComment(Child); - // Next content after a paragraph needs a break - NeedsParagraphBreak = true; - break; - - case CommentKind::CK_TextComment: - if (!I.Text.empty()) { - insertSeparator(); - OS << I.Text; - Started = true; - } - break; - - // Handle other comment types (BlockCommand, InlineCommand, etc.) - default: - for (const auto &Child : I.Children) - writeTableSafeComment(Child); - break; - } - } - - llvm::raw_ostream &OS; - bool Started = false; - bool NeedsParagraphBreak = false; -}; - -static void maybeWriteSourceFileRef(llvm::raw_ostream &OS, - const ClangDocContext &CDCtx, - const std::optional<Location> &DefLoc) { - if (DefLoc) - writeSourceFileRef(CDCtx, *DefLoc, OS); -} - -static void writeDescription(const CommentInfo &I, raw_ostream &OS) { - switch (I.Kind) { - case CommentKind::CK_FullComment: - for (const auto &Child : I.Children) - writeDescription(Child, OS); - break; - - case CommentKind::CK_ParagraphComment: - for (const auto &Child : I.Children) - writeDescription(Child, OS); - writeNewLine(OS); - break; - - case CommentKind::CK_BlockCommandComment: - OS << genEmphasis(I.Name) << " "; - for (const auto &Child : I.Children) - writeDescription(Child, OS); - break; - - case CommentKind::CK_InlineCommandComment: - OS << genEmphasis(I.Name) << " " << I.Text; - break; - - case CommentKind::CK_ParamCommandComment: - case CommentKind::CK_TParamCommandComment: { - std::string Direction = I.Explicit ? (" " + I.Direction).str() : ""; - OS << genEmphasis(I.ParamName) << I.Text << Direction << " "; - for (const auto &Child : I.Children) - writeDescription(Child, OS); - break; - } - - case CommentKind::CK_VerbatimBlockComment: - for (const auto &Child : I.Children) - writeDescription(Child, OS); - break; - - case CommentKind::CK_VerbatimBlockLineComment: - case CommentKind::CK_VerbatimLineComment: - OS << I.Text; - writeNewLine(OS); - break; - - case CommentKind::CK_HTMLStartTagComment: { - if (I.AttrKeys.size() != I.AttrValues.size()) - return; - std::string Buffer; - llvm::raw_string_ostream Attrs(Buffer); - for (unsigned Idx = 0; Idx < I.AttrKeys.size(); ++Idx) - Attrs << " \"" << I.AttrKeys[Idx] << "=" << I.AttrValues[Idx] << "\""; - - std::string CloseTag = I.SelfClosing ? "/>" : ">"; - writeLine("<" + I.Name + Attrs.str() + CloseTag, OS); - break; - } - - case CommentKind::CK_HTMLEndTagComment: - writeLine("</" + I.Name + ">", OS); - break; - - case CommentKind::CK_TextComment: - OS << I.Text; - break; - - case CommentKind::CK_Unknown: - OS << "Unknown comment kind: " << static_cast<int>(I.Kind) << ".\n\n"; - break; - } -} - -static void writeNameLink(const StringRef &CurrentPath, const Reference &R, - llvm::raw_ostream &OS) { - llvm::SmallString<64> Path = R.getRelativeFilePath(CurrentPath); - // Paths in Markdown use POSIX separators. - llvm::sys::path::native(Path, llvm::sys::path::Style::posix); - llvm::sys::path::append(Path, llvm::sys::path::Style::posix, - R.getFileBaseName() + ".md"); - OS << "[" << R.Name << "](" << Path << ")"; -} - -static void genMarkdown(const ClangDocContext &CDCtx, const EnumInfo &I, - llvm::raw_ostream &OS) { - OS << "| enum "; - if (I.Scoped) - OS << "class "; - OS << (I.Name.empty() ? "(unnamed)" : StringRef(I.Name)) << " "; - if (I.BaseType && !I.BaseType->Type.QualName.empty()) { - OS << ": " << I.BaseType->Type.QualName << " "; - } - OS << "|\n\n"; - - OS << "| Name | Value |"; - if (!I.Members.empty()) { - bool HasComments = false; - for (const auto &Member : I.Members) { - if (!Member.Description.empty()) { - HasComments = true; - OS << " Comments |"; - break; - } - } - OS << "\n|---|---|"; - if (HasComments) - OS << "---|"; - OS << "\n"; - for (const auto &N : I.Members) { - OS << "| " << N.Name << " "; - if (!N.Value.empty()) - OS << "| " << N.Value << " "; - if (HasComments) { - OS << "| "; - TableCommentWriter CommentWriter(OS); - CommentWriter.write(N.Description); - OS << " "; - } - OS << "|\n"; - } - } - OS << "\n"; - - maybeWriteSourceFileRef(OS, CDCtx, I.DefLoc); - - for (const auto &C : I.Description) - writeDescription(C, OS); -} - -static void genMarkdown(const ClangDocContext &CDCtx, const FunctionInfo &I, - llvm::raw_ostream &OS) { - std::string Buffer; - llvm::raw_string_ostream Stream(Buffer); - bool First = true; - for (const auto &N : I.Params) { - if (!First) - Stream << ", "; - Stream << N.Type.QualName + " " + N.Name; - First = false; - } - writeHeader(I.Name, 3, OS); - StringRef Access = getAccessSpelling(I.Access); - writeLine(genItalic(Twine(Access) + (!Access.empty() ? " " : "") + - (I.IsStatic ? "static " : "") + - I.ReturnType.Type.QualName.str() + " " + I.Name.str() + - "(" + Twine(Stream.str()) + ")"), - OS); - - maybeWriteSourceFileRef(OS, CDCtx, I.DefLoc); - - for (const auto &C : I.Description) - writeDescription(C, OS); -} - -static void genMarkdown(const ClangDocContext &CDCtx, const NamespaceInfo &I, - llvm::raw_ostream &OS) { - if (I.Name == "") - writeHeader("Global Namespace", 1, OS); - else - writeHeader("namespace " + I.Name, 1, OS); - writeNewLine(OS); - - if (!I.Description.empty()) { - for (const auto &C : I.Description) - writeDescription(C, OS); - writeNewLine(OS); - } - - llvm::SmallString<64> BasePath = I.getRelativeFilePath(""); - - if (!I.Children.Namespaces.empty()) { - writeHeader("Namespaces", 2, OS); - for (const auto &R : I.Children.Namespaces) { - OS << "* "; - writeNameLink(BasePath, R, OS); - OS << "\n"; - } - writeNewLine(OS); - } - - if (!I.Children.Records.empty()) { - writeHeader("Records", 2, OS); - for (const auto &R : I.Children.Records) { - OS << "* "; - writeNameLink(BasePath, R, OS); - OS << "\n"; - } - writeNewLine(OS); - } - - if (!I.Children.Functions.empty()) { - writeHeader("Functions", 2, OS); - for (const auto &F : I.Children.Functions) - genMarkdown(CDCtx, F, OS); - writeNewLine(OS); - } - if (!I.Children.Enums.empty()) { - writeHeader("Enums", 2, OS); - for (const auto &E : I.Children.Enums) - genMarkdown(CDCtx, E, OS); - writeNewLine(OS); - } -} - -static void genMarkdown(const ClangDocContext &CDCtx, const RecordInfo &I, - llvm::raw_ostream &OS) { - writeHeader(getTagType(I.TagType) + " " + I.Name, 1, OS); - - maybeWriteSourceFileRef(OS, CDCtx, I.DefLoc); - - if (!I.Description.empty()) { - for (const auto &C : I.Description) - writeDescription(C, OS); - writeNewLine(OS); - } - - std::string Parents = genReferenceList(I.Parents); - std::string VParents = genReferenceList(I.VirtualParents); - if (!Parents.empty() || !VParents.empty()) { - if (Parents.empty()) - writeLine("Inherits from " + VParents, OS); - else if (VParents.empty()) - writeLine("Inherits from " + Parents, OS); - else - writeLine("Inherits from " + Parents + ", " + VParents, OS); - writeNewLine(OS); - } - - if (!I.Members.empty()) { - writeHeader("Members", 2, OS); - for (const auto &Member : I.Members) { - StringRef Access = getAccessSpelling(Member.Access); - writeLine(Twine(Access) + (Access.empty() ? "" : " ") + - (Member.IsStatic ? "static " : "") + - Member.Type.Name.str() + " " + Member.Name.str(), - OS); - } - writeNewLine(OS); - } - - if (!I.Children.Records.empty()) { - writeHeader("Records", 2, OS); - for (const auto &R : I.Children.Records) - writeLine(R->Name, OS); - writeNewLine(OS); - } - if (!I.Children.Functions.empty()) { - writeHeader("Functions", 2, OS); - for (const auto &F : I.Children.Functions) - genMarkdown(CDCtx, F, OS); - writeNewLine(OS); - } - if (!I.Children.Enums.empty()) { - writeHeader("Enums", 2, OS); - for (const auto &E : I.Children.Enums) - genMarkdown(CDCtx, E, OS); - writeNewLine(OS); - } -} - -static void genMarkdown(const ClangDocContext &CDCtx, const TypedefInfo &I, - llvm::raw_ostream &OS) { - // TODO support typedefs in markdown. -} - -static void serializeReference(llvm::raw_fd_ostream &OS, const Index &I, - int Level) { - // Write out the heading level starting at ## - OS << "##" << std::string(Level, '#') << " "; - writeNameLink("", I, OS); - OS << "\n"; -} - -static llvm::Error serializeIndex(ClangDocContext &CDCtx) { - std::error_code FileErr; - llvm::SmallString<128> FilePath; - llvm::sys::path::native(CDCtx.OutDirectory, FilePath); - llvm::sys::path::append(FilePath, "all_files.md"); - llvm::raw_fd_ostream OS(FilePath, FileErr, llvm::sys::fs::OF_Text); - if (FileErr) - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "error creating index file: " + - FileErr.message()); - - CDCtx.Idx.sort(); - OS << "# All Files"; - if (!CDCtx.ProjectName.empty()) - OS << " for " << CDCtx.ProjectName; - OS << "\n\n"; - - std::vector<const Index *> Children = CDCtx.Idx.getSortedChildren(); - for (const auto *C : Children) - serializeReference(OS, *C, 0); - - return llvm::Error::success(); -} - -static llvm::Error genIndex(ClangDocContext &CDCtx) { - std::error_code FileErr; - llvm::SmallString<128> FilePath; - llvm::sys::path::native(CDCtx.OutDirectory, FilePath); - llvm::sys::path::append(FilePath, "index.md"); - llvm::raw_fd_ostream OS(FilePath, FileErr, llvm::sys::fs::OF_Text); - if (FileErr) - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "error creating index file: " + - FileErr.message()); - CDCtx.Idx.sort(); - OS << "# " << CDCtx.ProjectName << " C/C++ Reference\n\n"; - std::vector<const Index *> Children = CDCtx.Idx.getSortedChildren(); - for (const auto *C : Children) { - if (!C->Children.empty()) { - const char *Type; - switch (C->RefType) { - case InfoType::IT_namespace: - Type = "Namespace"; - break; - case InfoType::IT_record: - Type = "Type"; - break; - case InfoType::IT_enum: - Type = "Enum"; - break; - case InfoType::IT_function: - Type = "Function"; - break; - case InfoType::IT_typedef: - Type = "Typedef"; - break; - case InfoType::IT_concept: - Type = "Concept"; - break; - case InfoType::IT_variable: - Type = "Variable"; - break; - case InfoType::IT_friend: - Type = "Friend"; - break; - case InfoType::IT_default: - Type = "Other"; - } - OS << "* " << Type << ": [" << C->Name << "]("; - if (!C->Path.empty()) - OS << C->Path << "/"; - OS << C->Name << ")\n"; - } - } - return llvm::Error::success(); -} +static std::unique_ptr<MustacheTemplateFile> IndexTemplate = nullptr; namespace { -/// Generator for Markdown documentation. -class MDGenerator : public Generator { -public: - static StringRef Format; - - llvm::Error generateDocumentation(StringRef RootDir, - llvm::StringMap<Info *> Infos, - const ClangDocContext &CDCtx, - std::string DirName) override; - llvm::Error createResources(ClangDocContext &CDCtx) override; - llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, - const ClangDocContext &CDCtx) override; +struct MDGenerator : public MustacheGenerator { + static const char *Format; + Error generateDocumentation(StringRef RootDir, StringMap<Info *> Infos, + const ClangDocContext &CDCtx, + std::string DirName) override; + Error setupTemplateFiles(const ClangDocContext &CDCtx) override; + Error generateDocForJSON(json::Value &JSON, raw_fd_ostream &OS, + const ClangDocContext &CDCtx, + StringRef ObjectTypeStr, + StringRef RelativeRootPath) override; + // This generator doesn't need this function, but it inherits from the + // original generator interface. + Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, + const ClangDocContext &CDCtx) override; }; } // namespace -StringRef MDGenerator::Format = "md"; - -llvm::Error MDGenerator::generateDocumentation(StringRef RootDir, - llvm::StringMap<Info *> Infos, - const ClangDocContext &CDCtx, - std::string DirName) { - // Track which directories we already tried to create. - llvm::StringSet<> CreatedDirs; - - // Collect all output by file name and create the necessary directories. - llvm::StringMap<std::vector<Info *>> FileToInfos; - for (const auto &Group : Infos) { - Info *Info = Group.getValue(); - - llvm::SmallString<128> Path; - llvm::sys::path::native(RootDir, Path); - llvm::sys::path::append(Path, Info->getRelativeFilePath("")); - if (!Cre... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/209071 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
