diff --git a/docs/doxygen/layout-clang-uml.xml b/docs/doxygen/layout-clang-uml.xml
index 1aa2a958..7dab1e87 100644
--- a/docs/doxygen/layout-clang-uml.xml
+++ b/docs/doxygen/layout-clang-uml.xml
@@ -6,41 +6,29 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
diff --git a/src/class_diagram/model/class.cc b/src/class_diagram/model/class.cc
index dfad2f57..90d1025a 100644
--- a/src/class_diagram/model/class.cc
+++ b/src/class_diagram/model/class.cc
@@ -143,6 +143,7 @@ std::optional class_::doxygen_link() const
auto name = name_and_ns();
util::replace_all(name, "_", "__");
util::replace_all(name, "::", "_1_1");
+ util::replace_all(name, "##", "_1_1"); // nested classes
return fmt::format("{}{}.html", type, name);
}
} // namespace clanguml::class_diagram::model
diff --git a/src/common/compilation_database.cc b/src/common/compilation_database.cc
index 55972fad..0e24819e 100644
--- a/src/common/compilation_database.cc
+++ b/src/common/compilation_database.cc
@@ -17,7 +17,7 @@
*/
#include "compilation_database.h"
-
+#include "util/error.h"
#include "util/query_driver_output_extractor.h"
namespace clanguml::common {
@@ -31,7 +31,7 @@ compilation_database::auto_detect_from_directory(
cfg.compilation_database_dir(), error_message);
if (!error_message.empty())
- throw compilation_database_error(error_message);
+ throw error::compilation_database_error(error_message);
return std::make_unique(std::move(res), cfg);
}
diff --git a/src/common/compilation_database.h b/src/common/compilation_database.h
index ae7105f1..58b8c670 100644
--- a/src/common/compilation_database.h
+++ b/src/common/compilation_database.h
@@ -22,6 +22,7 @@
#include "common/model/template_parameter.h"
#include "config/config.h"
#include "types.h"
+#include "util/error.h"
#include "util/util.h"
#include
@@ -34,10 +35,6 @@
namespace clanguml::common {
-class compilation_database_error : public std::runtime_error {
- using std::runtime_error::runtime_error;
-};
-
/**
* @brief Custom compilation database class
*
diff --git a/src/main.cc b/src/main.cc
index 76095a22..b6c69d23 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -81,12 +81,12 @@ int main(int argc, const char *argv[])
cli.effective_output_directory, db, cli.verbose, cli.thread_count,
cli.progress, cli.generators, translation_units_map);
}
- catch (common::compilation_database_error &e) {
+ catch (error::compilation_database_error &e) {
LOG_ERROR("Failed to load compilation database from {} due to: {}",
cli.config.compilation_database_dir(), e.what());
return 1;
}
- catch (util::query_driver_no_paths &e) {
+ catch (error::query_driver_no_paths &e) {
LOG_ERROR("Quering provided compiler driver {} did not provide any "
"paths, please make sure the path is correct and that your "
"compiler is GCC-compatible: {}",
diff --git a/src/util/error.h b/src/util/error.h
index 434474aa..20f1ff9b 100644
--- a/src/util/error.h
+++ b/src/util/error.h
@@ -21,6 +21,10 @@
namespace clanguml::error {
+class query_driver_no_paths : public std::runtime_error {
+ using std::runtime_error::runtime_error;
+};
+
struct uml_alias_missing : public virtual std::runtime_error {
uml_alias_missing(const std::string &message)
: std::runtime_error(message)
@@ -28,4 +32,8 @@ struct uml_alias_missing : public virtual std::runtime_error {
}
};
+class compilation_database_error : public std::runtime_error {
+ using std::runtime_error::runtime_error;
+};
+
} // namespace clanguml::error
diff --git a/src/util/query_driver_output_extractor.cc b/src/util/query_driver_output_extractor.cc
index 9f4ffc4c..fd7f3765 100644
--- a/src/util/query_driver_output_extractor.cc
+++ b/src/util/query_driver_output_extractor.cc
@@ -18,6 +18,7 @@
#include "query_driver_output_extractor.h"
+#include "error.h"
#include "util.h"
#include
@@ -46,7 +47,7 @@ void query_driver_output_extractor::execute()
extract_target(driver_output);
if (system_include_paths_.empty()) {
- throw query_driver_no_paths(fmt::format(
+ throw error::query_driver_no_paths(fmt::format(
"Compiler driver {} did not report any system include paths "
"in its output: {}",
command_, driver_output));
diff --git a/src/util/query_driver_output_extractor.h b/src/util/query_driver_output_extractor.h
index f2e2c26c..dd5377c5 100644
--- a/src/util/query_driver_output_extractor.h
+++ b/src/util/query_driver_output_extractor.h
@@ -23,26 +23,58 @@
namespace clanguml::util {
-class query_driver_no_paths : public std::runtime_error {
- using std::runtime_error::runtime_error;
-};
-
+/**
+ * @brief Executed compiler frontend and extract default system paths
+ *
+ * This class - inspired by the `clangd` language server - will invoke the
+ * provided compiler command and query it for its default system paths,
+ * which then will be added to each compile command in the database.
+ */
class query_driver_output_extractor {
public:
+ /**
+ * @brief Constructor.
+ *
+ * @param command Command to execute the compiler frontend
+ * @param language Language name to query for (C or C++)
+ */
query_driver_output_extractor(std::string command, std::string language);
~query_driver_output_extractor() = default;
+ /**
+ * @brief Execute the command and extract compiler flags and include paths
+ */
void execute();
+ /**
+ * @brief Extract target name from the compiler output
+ *
+ * @param output Compiler query driver output
+ */
void extract_target(const std::string &output);
+ /**
+ * @brief Extract system include paths from the compiler output
+ *
+ * @param output Compiler query driver output
+ */
void extract_system_include_paths(const std::string &output);
- const std::vector &system_include_paths() const;
-
+ /**
+ * @brief Name of the target of the compiler command (e.g. x86_64-linux-gnu)
+ *
+ * @return Target name
+ */
const std::string &target() const;
+ /**
+ * @brief Return list of include system paths
+ *
+ * @return List of include system paths
+ */
+ const std::vector &system_include_paths() const;
+
private:
const std::string command_;
const std::string language_;
diff --git a/src/util/thread_pool_executor.h b/src/util/thread_pool_executor.h
index e8d3c12e..9e6820e9 100644
--- a/src/util/thread_pool_executor.h
+++ b/src/util/thread_pool_executor.h
@@ -23,8 +23,17 @@
#include
namespace clanguml::util {
+
+/**
+ * @brief Simple thread pool executor for parallelizing diagram generation.
+ */
class thread_pool_executor {
public:
+ /**
+ * @brief Constructor
+ *
+ * @param pool_size Number of threads in the pool
+ */
explicit thread_pool_executor(unsigned int pool_size);
thread_pool_executor(const thread_pool_executor &) = delete;
@@ -34,21 +43,31 @@ public:
~thread_pool_executor();
+ /**
+ * @brief Add a task to run on the pool.
+ *
+ * @param task Function to execute
+ * @return Future, allowing awaiting the result
+ */
std::future add(std::function &&task);
+ /**
+ * @brief Join all active threads in the pool
+ */
void stop();
private:
+ /**
+ * @brief Main worker pool thread method - take task from queue and execute
+ */
void worker();
std::packaged_task get();
std::atomic_bool done_;
-
std::deque> tasks_;
std::mutex tasks_mutex_;
std::condition_variable tasks_cond_;
-
std::vector threads_;
};
} // namespace clanguml::util
\ No newline at end of file
diff --git a/src/util/util.h b/src/util/util.h
index 5b943058..f7e2040b 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -54,28 +54,101 @@
namespace clanguml::util {
-std::string ltrim(const std::string &s);
-std::string rtrim(const std::string &s);
-std::string trim(const std::string &s);
-std::string trim_typename(const std::string &s);
-
#define FILENAME_ \
(strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
+/**
+ * @brief Left trim a string
+ *
+ * @param s Input string
+ * @return Left trimmed string
+ */
+std::string ltrim(const std::string &s);
+
+/**
+ * @brief Right trim a string
+ *
+ * @param s Input string
+ * @return Right trimmed string
+ */
+std::string rtrim(const std::string &s);
+
+/**
+ * @brief Trim a string
+ *
+ * @param s Input string
+ * @return Trimmed string
+ */
+std::string trim(const std::string &s);
+
+/**
+ * @brief Remove `typename` prefix from a string if exists
+ * @param s Input string
+ * @return String without `typename` prefix
+ */
+std::string trim_typename(const std::string &s);
+
+/**
+ * @brief Execute a shell `command` and return console output as string
+ *
+ * @param command Shell command to execute
+ * @return Console output of the command
+ */
std::string get_process_output(const std::string &command);
+/**
+ * @brief Get value of an environment variable
+ *
+ * @param name Name of the environment variable
+ * @return Value of the environment variable, or empty if it doesn't exist
+ */
std::string get_env(const std::string &name);
+/**
+ * @brief Check if `$PWD` is in a Git repository
+ *
+ * This can be overridden by exporting `CLANGUML_GIT_COMMIT` environment
+ * variable.
+ *
+ * @return True, if the current directory is in a Git repository
+ */
bool is_git_repository();
+/**
+ * @brief Get current Git branch
+ *
+ * @return Name of the current Git branch
+ */
std::string get_git_branch();
+/**
+ * @brief Get current Git revision
+ *
+ * Generates a Git revision tag using `git describe --tags --always` command
+ *
+ * @return Current repository Git revision
+ */
std::string get_git_revision();
+/**
+ * @brief Get current Git commit
+ *
+ * @return Latest Git commit hash
+ */
std::string get_git_commit();
+/**
+ * @brief Get path to the top level Git directory
+ *
+ * @return Absolut path to the nearest directory containing `.git` folder
+ */
std::string get_git_toplevel_dir();
+/**
+ * @brief Get descriptive name of the current operating system.
+ *
+ * @return Name of the operating system
+ */
std::string get_os_name();
/**
@@ -94,14 +167,37 @@ std::string get_os_name();
std::vector split(
std::string str, std::string_view delimiter, bool skip_empty = true);
+/**
+ * @brief Remove and erase elements from a vector
+ *
+ * @tparam T Element type
+ * @tparam F Functor type
+ * @param v Vector to remove elements from
+ * @param f Functor to decide which elements to remove
+ */
template void erase_if(std::vector &v, F &&f)
{
v.erase(std::remove_if(v.begin(), v.end(), std::forward(f)), v.end());
}
+/**
+ * @brief Join `toks` into string using `delimiter` as separator
+ *
+ * @param toks Elements to join into string
+ * @param delimiter Separator to use to join elements
+ * @return Concatenated elements into one string
+ */
std::string join(
const std::vector &toks, std::string_view delimiter);
+/**
+ * @brief Join `args` into string using `delimiter` as separator
+ *
+ * @tparam Args Element type
+ * @param delimiter Separator to use to join elements
+ * @param args Elements to join into string
+ * @return Arguments concatenated into one string
+ */
template
std::string join(std::string_view delimiter, Args... args)
{
@@ -287,6 +383,12 @@ template void _if(const bool condition, F &&func)
_if(condition, std::forward(func), []() {});
}
+/**
+ * @brief Generate a hash seed.
+ *
+ * @param seed Initial seed.
+ * @return Hash seed.
+ */
std::size_t hash_seed(std::size_t seed);
/**
diff --git a/tests/test_compilation_database.cc b/tests/test_compilation_database.cc
index b0a6c4f0..f3dd6e12 100644
--- a/tests/test_compilation_database.cc
+++ b/tests/test_compilation_database.cc
@@ -73,7 +73,7 @@ TEST_CASE("Test compilation_database should work", "[unit-test]")
REQUIRE(
!contains(ccs.at(0).CommandLine, "-Wno-deprecated-declarations"));
}
- catch (clanguml::common::compilation_database_error &e) {
+ catch (clanguml::error::compilation_database_error &e) {
REQUIRE(false);
}
}
@@ -81,8 +81,8 @@ TEST_CASE("Test compilation_database should work", "[unit-test]")
TEST_CASE("Test compilation_database should throw", "[unit-test]")
{
using clanguml::common::compilation_database;
- using clanguml::common::compilation_database_error;
using clanguml::common::compilation_database_ptr;
+ using clanguml::error::compilation_database_error;
using clanguml::util::contains;
auto cfg = clanguml::config::load(