Skip to content

Commit

Permalink
Revert "[clang-doc] Move file layout to the generators."
Browse files Browse the repository at this point in the history
This reverts commit f8a469f.

The test in single-file-public.cpp breaks on Mac, due to an unknown
regextype in the find command.
  • Loading branch information
ilovepi committed Nov 22, 2022
1 parent 1f515f3 commit 48bb147
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 196 deletions.
14 changes: 3 additions & 11 deletions clang-tools-extra/clang-doc/Generators.h
Expand Up @@ -25,23 +25,15 @@ class Generator {
public:
virtual ~Generator() = default;

// Write out the decl info for the objects in the given map in the specified
// format.
virtual llvm::Error
generateDocs(StringRef RootDir,
llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
const ClangDocContext &CDCtx) = 0;

// Write out the decl info in the specified format.
virtual llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
const ClangDocContext &CDCtx) = 0;
// This function writes a file with the index previously constructed.
// It can be overwritten by any of the inherited generators.
// If the override method wants to run this it should call
// Generator::createResources(CDCtx);
virtual llvm::Error createResources(ClangDocContext &CDCtx);

// Write out one specific decl info to the destination stream.
virtual llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
const ClangDocContext &CDCtx) = 0;

static void addInfoToIndex(Index &Idx, const doc::Info *Info);
};

Expand Down
59 changes: 1 addition & 58 deletions clang-tools-extra/clang-doc/HTMLGenerator.cpp
Expand Up @@ -11,7 +11,6 @@
#include "clang/Basic/Version.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/Path.h"
Expand Down Expand Up @@ -840,69 +839,13 @@ class HTMLGenerator : public Generator {
public:
static const char *Format;

llvm::Error generateDocs(StringRef RootDir,
llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
const ClangDocContext &CDCtx) override;
llvm::Error createResources(ClangDocContext &CDCtx) override;
llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
const ClangDocContext &CDCtx) override;
llvm::Error createResources(ClangDocContext &CDCtx) override;
};

const char *HTMLGenerator::Format = "html";

llvm::Error
HTMLGenerator::generateDocs(StringRef RootDir,
llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
const ClangDocContext &CDCtx) {
// Track which directories we already tried to create.
llvm::StringSet<> CreatedDirs;

// Collect all output by file name and create the nexessary directories.
llvm::StringMap<std::vector<doc::Info *>> FileToInfos;
for (const auto &Group : Infos) {
doc::Info *Info = Group.getValue().get();

llvm::SmallString<128> Path;
llvm::sys::path::native(RootDir, Path);
llvm::sys::path::append(Path, Info->getRelativeFilePath(""));
if (CreatedDirs.find(Path) == CreatedDirs.end()) {
if (std::error_code Err = llvm::sys::fs::create_directories(Path);
Err != std::error_code()) {
return llvm::createStringError(Err, "Failed to create directory '%s'.",
Path.c_str());
}
CreatedDirs.insert(Path);
}

llvm::sys::path::append(Path, Info->getFileBaseName() + ".html");
FileToInfos[Path].push_back(Info);
}

for (const auto &Group : FileToInfos) {
std::error_code FileErr;
llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr,
llvm::sys::fs::OF_None);
if (FileErr) {
return llvm::createStringError(FileErr, "Error opening file '%s'",
Group.getKey().str().c_str());
}

// TODO: https://github.com/llvm/llvm-project/issues/59073
// If there are multiple Infos for this file name (for example, template
// specializations), this will generate multiple complete web pages (with
// <DOCTYPE> and <title>, etc.) concatenated together. This generator needs
// some refactoring to be able to output the headers separately from the
// contents.
for (const auto &Info : Group.getValue()) {
if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) {
return Err;
}
}
}

return llvm::Error::success();
}

llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
const ClangDocContext &CDCtx) {
std::string InfoTitle;
Expand Down
53 changes: 1 addition & 52 deletions clang-tools-extra/clang-doc/MDGenerator.cpp
Expand Up @@ -356,69 +356,18 @@ static llvm::Error genIndex(ClangDocContext &CDCtx) {
}
return llvm::Error::success();
}

/// Generator for Markdown documentation.
class MDGenerator : public Generator {
public:
static const char *Format;

llvm::Error generateDocs(StringRef RootDir,
llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
const ClangDocContext &CDCtx) override;
llvm::Error createResources(ClangDocContext &CDCtx) override;
llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
const ClangDocContext &CDCtx) override;
llvm::Error createResources(ClangDocContext &CDCtx) override;
};

const char *MDGenerator::Format = "md";

llvm::Error
MDGenerator::generateDocs(StringRef RootDir,
llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
const ClangDocContext &CDCtx) {
// 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<doc::Info *>> FileToInfos;
for (const auto &Group : Infos) {
doc::Info *Info = Group.getValue().get();

llvm::SmallString<128> Path;
llvm::sys::path::native(RootDir, Path);
llvm::sys::path::append(Path, Info->getRelativeFilePath(""));
if (CreatedDirs.find(Path) == CreatedDirs.end()) {
if (std::error_code Err = llvm::sys::fs::create_directories(Path);
Err != std::error_code()) {
return llvm::createStringError(Err, "Failed to create directory '%s'.",
Path.c_str());
}
CreatedDirs.insert(Path);
}

llvm::sys::path::append(Path, Info->getFileBaseName() + ".md");
FileToInfos[Path].push_back(Info);
}

for (const auto &Group : FileToInfos) {
std::error_code FileErr;
llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr,
llvm::sys::fs::OF_None);
if (FileErr) {
return llvm::createStringError(FileErr, "Error opening file '%s'",
Group.getKey().str().c_str());
}

for (const auto &Info : Group.getValue()) {
if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) {
return Err;
}
}
}

return llvm::Error::success();
}

llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
const ClangDocContext &CDCtx) {
switch (I->IT) {
Expand Down
36 changes: 0 additions & 36 deletions clang-tools-extra/clang-doc/YAMLGenerator.cpp
Expand Up @@ -292,48 +292,12 @@ class YAMLGenerator : public Generator {
public:
static const char *Format;

llvm::Error generateDocs(StringRef RootDir,
llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
const ClangDocContext &CDCtx) override;
llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
const ClangDocContext &CDCtx) override;
};

const char *YAMLGenerator::Format = "yaml";

llvm::Error
YAMLGenerator::generateDocs(StringRef RootDir,
llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
const ClangDocContext &CDCtx) {
for (const auto &Group : Infos) {
doc::Info *Info = Group.getValue().get();

// Output file names according to the USR except the global namesapce.
// Anonymous namespaces are taken care of in serialization, so here we can
// safely assume an unnamed namespace is the global one.
llvm::SmallString<128> Path;
llvm::sys::path::native(RootDir, Path);
if (Info->IT == InfoType::IT_namespace && Info->Name.empty()) {
llvm::sys::path::append(Path, "index.yaml");
} else {
llvm::sys::path::append(Path, Group.getKey() + ".yaml");
}

std::error_code FileErr;
llvm::raw_fd_ostream InfoOS(Path, FileErr, llvm::sys::fs::OF_None);
if (FileErr) {
return llvm::createStringError(FileErr, "Error opening file '%s'",
Path.c_str());
}

if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) {
return Err;
}
}

return llvm::Error::success();
}

llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
const ClangDocContext &CDCtx) {
llvm::yaml::Output InfoYAML(OS);
Expand Down
101 changes: 71 additions & 30 deletions clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
Expand Up @@ -43,7 +43,6 @@
#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/raw_ostream.h"
#include <atomic>
#include <mutex>
#include <string>

using namespace clang::ast_matchers;
Expand Down Expand Up @@ -131,6 +130,54 @@ std::string GetExecutablePath(const char *Argv0, void *MainAddr) {
return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
}

bool CreateDirectory(const Twine &DirName, bool ClearDirectory = false) {
std::error_code OK;
llvm::SmallString<128> DocsRootPath;
if (ClearDirectory) {
std::error_code RemoveStatus = llvm::sys::fs::remove_directories(DirName);
if (RemoveStatus != OK) {
llvm::errs() << "Unable to remove existing documentation directory for "
<< DirName << ".\n";
return true;
}
}
std::error_code DirectoryStatus = llvm::sys::fs::create_directories(DirName);
if (DirectoryStatus != OK) {
llvm::errs() << "Unable to create documentation directories.\n";
return true;
}
return false;
}

// A function to extract the appropriate file name for a given info's
// documentation. The path returned is a composite of the output directory, the
// info's relative path and name and the extension. The relative path should
// have been constructed in the serialization phase.
//
// Example: Given the below, the <ext> path for class C will be
// <root>/A/B/C.<ext>
//
// namespace A {
// namespace B {
//
// class C {};
//
// }
// }
llvm::Expected<llvm::SmallString<128>> getInfoOutputFile(StringRef Root,
StringRef RelativePath,
StringRef Name,
StringRef Ext) {
llvm::SmallString<128> Path;
llvm::sys::path::native(Root, Path);
llvm::sys::path::append(Path, RelativePath);
if (CreateDirectory(Path))
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"failed to create directory");
llvm::sys::path::append(Path, Name + Ext);
return Path;
}

int main(int argc, const char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
std::error_code OK;
Expand Down Expand Up @@ -227,11 +274,6 @@ Example usage for a project using a compile commands database:
R.first->second.emplace_back(Value);
});

// Collects all Infos according to their unique USR value. This map is added
// to from the thread pool below and is protected by the USRToInfoMutex.
llvm::sys::Mutex USRToInfoMutex;
llvm::StringMap<std::unique_ptr<doc::Info>> USRToInfo;

// First reducing phase (reduce all decls into one info per decl).
llvm::outs() << "Reducing " << USRToBitcode.size() << " infos...\n";
std::atomic<bool> Error;
Expand Down Expand Up @@ -262,17 +304,31 @@ Example usage for a project using a compile commands database:
return;
}

// Add a reference to this Info in the Index
{
std::lock_guard Guard(IndexMutex);
clang::doc::Generator::addInfoToIndex(CDCtx.Idx, Reduced.get().get());
doc::Info *I = Reduced.get().get();
auto InfoPath =
getInfoOutputFile(OutDirectory, I->getRelativeFilePath(""),
I->getFileBaseName(), "." + Format);
if (!InfoPath) {
llvm::errs() << toString(InfoPath.takeError()) << "\n";
Error = true;
return;
}

// Save in the result map (needs a lock due to threaded access).
{
std::lock_guard Guard(USRToInfoMutex);
USRToInfo[Group.getKey()] = std::move(Reduced.get());
std::error_code FileErr;
llvm::raw_fd_ostream InfoOS(InfoPath.get(), FileErr,
llvm::sys::fs::OF_None);
if (FileErr) {
llvm::errs() << "Error opening info file " << InfoPath.get() << ": "
<< FileErr.message() << "\n";
return;
}

IndexMutex.lock();
// Add a reference to this Info in the Index
clang::doc::Generator::addInfoToIndex(CDCtx.Idx, I);
IndexMutex.unlock();

if (auto Err = G->get()->generateDocForInfo(I, InfoOS, CDCtx))
llvm::errs() << toString(std::move(Err)) << "\n";
});
}

Expand All @@ -281,21 +337,6 @@ Example usage for a project using a compile commands database:
if (Error)
return 1;

// Ensure the root output directory exists.
if (std::error_code Err = llvm::sys::fs::create_directories(OutDirectory);
Err != std::error_code()) {
llvm::errs() << "Failed to create directory '" << OutDirectory << "'\n";
return 1;
}

// Run the generator.
llvm::outs() << "Generating docs...\n";
if (auto Err =
G->get()->generateDocs(OutDirectory, std::move(USRToInfo), CDCtx)) {
llvm::errs() << toString(std::move(Err)) << "\n";
return 1;
}

llvm::outs() << "Generating assets for docs...\n";
Err = G->get()->createResources(CDCtx);
if (Err) {
Expand Down

0 comments on commit 48bb147

Please sign in to comment.