Improved skipping of empty packages in class diagrams

This commit is contained in:
Bartek Kryza
2023-05-28 18:09:01 +02:00
parent 5c4a98ba79
commit 81c7ce71df
15 changed files with 121 additions and 53 deletions

View File

@@ -721,9 +721,14 @@ void generator::generate_relationships(
{
for (const auto &subpackage : p) {
if (dynamic_cast<package *>(subpackage.get()) != nullptr) {
// TODO: add option - generate_empty_packages
// TODO: add option - generate_empty_packages, currently
// packages which do not contain anything but other packages
// are skipped
const auto &sp = dynamic_cast<package &>(*subpackage);
if (!sp.is_empty())
if (!sp.is_empty() &&
!sp.all_of([this](const common::model::element &e) {
return !m_model.should_include(e);
}))
generate_relationships(sp, ostr);
}
else if (dynamic_cast<class_ *>(subpackage.get()) != nullptr) {
@@ -774,7 +779,10 @@ void generator::generate_top_level_elements(std::ostream &ostr) const
{
for (const auto &p : m_model) {
if (auto *pkg = dynamic_cast<package *>(p.get()); pkg) {
if (!pkg->is_empty())
if (!pkg->is_empty() &&
!pkg->all_of([this](const common::model::element &e) {
return !m_model.should_include(e);
}))
generate(*pkg, ostr);
}
else if (auto *cls = dynamic_cast<class_ *>(p.get()); cls) {

View File

@@ -187,7 +187,6 @@ bool diagram::add_with_filesystem_path(
const auto base_name = e->name();
const auto full_name = e->full_name(false);
const auto id = e->id();
auto &e_ref = *e;
if (add_element(parent_path, std::move(e))) {
@@ -195,9 +194,6 @@ bool diagram::add_with_filesystem_path(
return true;
}
LOG_WARN(
"Cannot add {} {} with id {} due to: {}", element_type, base_name, id);
return false;
}

View File

@@ -1044,6 +1044,8 @@ template_builder::try_as_template_specialization_type(
}
if (diagram().should_include(nested_template_instantiation_full_name)) {
visitor_.set_source_location(
*template_decl, *nested_template_instantiation);
visitor_.add_class(std::move(nested_template_instantiation));
}
@@ -1155,7 +1157,7 @@ std::optional<template_parameter> template_builder::try_as_record_type(
if (parent.has_value())
parent.value()->add_relationship(
{relationship_t::kDependency, tag_argument->id()});
visitor_.set_source_location(*template_decl, *tag_argument);
visitor_.add_class(std::move(tag_argument));
}
}

View File

@@ -736,4 +736,19 @@ std::vector<std::string> tokenize_unexposed_template_parameter(
return result;
}
bool parse_source_location(const std::string &location_str, std::string &file,
unsigned &line, unsigned &column)
{
auto tokens = util::split(location_str, ":");
if (tokens.size() < 3)
return false;
file = tokens.at(0);
line = std::stoi(tokens.at(1));
column = std::stoi(tokens.at(2));
return true;
}
} // namespace clanguml::common

View File

@@ -170,6 +170,9 @@ void if_dyn_cast(P pointer, F &&func)
}
}
bool parse_source_location(const std::string &location_str, std::string &file,
unsigned &line, unsigned &column);
bool is_type_parameter(const std::string &t);
bool is_qualifier(const std::string &q);

View File

@@ -70,7 +70,9 @@ public:
if (parent && dynamic_cast<nested_trait<T, Path> *>(&parent.value()))
return dynamic_cast<nested_trait<T, Path> &>(parent.value())
.template add_element<V>(std::move(p));
spdlog::info("No parent element found at: {}", path.to_string());
LOG_INFO("No parent element found at: {}", path.to_string());
throw std::runtime_error(
"No parent element found for " + path.to_string());
}
@@ -135,7 +137,29 @@ public:
elements_.end();
}
bool is_empty() const { return elements_.empty(); }
template <typename F> bool all_of(F &&f) const
{
return std::all_of(
elements_.cbegin(), elements_.cend(), [f](const auto &e) {
const auto *package_ptr =
dynamic_cast<nested_trait<T, Path> *>(e.get());
if (package_ptr != nullptr)
return package_ptr->all_of(f);
return f(*e);
});
}
bool is_empty() const
{
return elements_.empty() ||
std::all_of(elements_.cbegin(), elements_.cend(), [](auto &e) {
const auto *package_ptr =
dynamic_cast<nested_trait<T, Path> *>(e.get());
return package_ptr != nullptr && package_ptr->is_empty();
});
}
auto begin() { return elements_.begin(); }
auto end() { return elements_.end(); }

View File

@@ -85,14 +85,36 @@ void translation_unit_visitor::set_source_location(
const clang::SourceLocation &location,
clanguml::common::model::source_location &element)
{
std::string file;
unsigned line{};
[[maybe_unused]] unsigned column{};
if (location.isValid()) {
element.set_file(source_manager_.getFilename(location).str());
element.set_file_relative(util::path_to_url(
std::filesystem::relative(element.file(), relative_to_path_)
.string()));
element.set_line(source_manager_.getSpellingLineNumber(location));
element.set_location_id(location.getHashValue());
file = source_manager_.getFilename(location).str();
line = source_manager_.getSpellingLineNumber(location);
column = source_manager_.getSpellingColumnNumber(location);
if (file.empty()) {
// Why do I have to do this?
parse_source_location(
location.printToString(source_manager()), file, line, column);
}
}
else {
auto success = parse_source_location(
location.printToString(source_manager()), file, line, column);
if (!success) {
LOG_DBG("Failed to extract source location for element from {}",
location.printToString(source_manager_));
return;
}
}
element.set_file(file);
element.set_file_relative(util::path_to_url(
std::filesystem::relative(element.file(), relative_to_path_).string()));
element.set_line(line);
element.set_location_id(location.getHashValue());
}
} // namespace clanguml::common::visitor

View File

@@ -19,7 +19,6 @@
#include "cli/cli_handler.h"
#include "common/compilation_database.h"
#include "common/generators/generators.h"
#include "include_diagram/generators/plantuml/include_diagram_generator.h"
#include "util/query_driver_output_extractor.h"
#include "util/util.h"
@@ -33,8 +32,6 @@
#include <spdlog/spdlog.h>
#include <cstring>
#include <iostream>
#include <util/thread_pool_executor.h>
#ifdef ENABLE_BACKWARD_CPP
namespace backward {
@@ -55,6 +52,12 @@ int main(int argc, const char *argv[])
if (res == cli::cli_flow_t::kError)
return 1;
#if !defined(NDEBUG)
// Catch invalid logger message formats, e.g. missing arguments
spdlog::set_error_handler(
[](const std::string & /*msg*/) { assert(0 == 1); });
#endif
try {
const auto db =
clanguml::common::compilation_database::auto_detect_from_directory(