Skip to content

Commit

Permalink
Added default diagram generation error for empty diagrams (#246)
Browse files Browse the repository at this point in the history
  • Loading branch information
bkryza committed Mar 4, 2024
1 parent cb44c3d commit baef768
Show file tree
Hide file tree
Showing 27 changed files with 315 additions and 10 deletions.
5 changes: 5 additions & 0 deletions src/class_diagram/model/diagram.cc
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,11 @@ void diagram::remove_redundant_dependencies()
}
}

bool diagram::is_empty() const
{
return element_view<class_>::is_empty() &&
element_view<enum_>::is_empty() && element_view<concept_>::is_empty();
}
} // namespace clanguml::class_diagram::model

namespace clanguml::common::model {
Expand Down
7 changes: 7 additions & 0 deletions src/class_diagram/model/diagram.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,13 @@ class diagram : public common::model::diagram,
*/
inja::json context() const override;

/**
* @brief Check whether the diagram is empty
*
* @return True, if diagram is empty
*/
bool is_empty() const override;

private:
template <typename ElementT>
bool add_with_namespace_path(std::unique_ptr<ElementT> &&e);
Expand Down
6 changes: 6 additions & 0 deletions src/cli/cli_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ cli_flow_t cli_handler::parse(int argc, const char **argv)
"Query the specific compiler driver to extract system paths and add to "
"compile commands (e.g. arm-none-eabi-g++)");
#endif
app.add_flag("--allow-empty-diagrams", allow_empty_diagrams,
"Do not raise an error when generated diagram model is empty");
app.add_option(
"--add-class-diagram", add_class_diagram, "Add class diagram config");
app.add_option("--add-sequence-diagram", add_sequence_diagram,
Expand Down Expand Up @@ -302,6 +304,10 @@ cli_flow_t cli_handler::handle_post_config_options()

LOG_INFO("Loaded clang-uml config from {}", config_path);

if (allow_empty_diagrams) {
config.allow_empty_diagrams.set(true);
}

//
// Override selected config options from command line
//
Expand Down
1 change: 1 addition & 0 deletions src/cli/cli_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ class cli_handler {
bool list_diagrams{false};
bool quiet{false};
bool initialize{false};
bool allow_empty_diagrams{false};
std::optional<std::vector<std::string>> add_compile_flag;
std::optional<std::vector<std::string>> remove_compile_flag;
#if !defined(_WIN32)
Expand Down
13 changes: 10 additions & 3 deletions src/common/generators/generators.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,17 @@ void generate_diagram_select_generator(const std::string &od,
using diagram_generator =
typename diagram_generator_t<DiagramConfig, GeneratorTag>::type;

std::stringstream buffer;
buffer << diagram_generator(
dynamic_cast<DiagramConfig &>(*diagram), *model);

// Only open the file after the diagram has been generated successfully
// in order not to overwrite previous diagram in case of failure
auto path = std::filesystem::path{od} /
fmt::format("{}.{}", name, GeneratorTag::extension);
std::ofstream ofs;
ofs.open(path, std::ofstream::out | std::ofstream::trunc);
ofs << diagram_generator(dynamic_cast<DiagramConfig &>(*diagram), *model);
ofs << buffer.str();

ofs.close();

Expand Down Expand Up @@ -258,11 +264,12 @@ void generate_diagrams(const std::vector<std::string> &diagram_names,
if (indicator)
indicator->complete(name);
}
catch (std::exception &e) {
catch (const std::exception &e) {
if (indicator)
indicator->fail(name);

LOG_ERROR(e.what());
LOG_ERROR(
"ERROR: Failed to generate diagram {}: {}", name, e.what());
}
};

Expand Down
16 changes: 12 additions & 4 deletions src/common/generators/json/generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,19 @@ std::ostream &operator<<(
template <typename C, typename D>
void generator<C, D>::generate(std::ostream &ostr) const
{
const auto &config = generators::generator<C, D>::config();
const auto &model = generators::generator<C, D>::model();

if (!config.allow_empty_diagrams() && model.is_empty()) {
throw clanguml::error::empty_diagram_error{
"Diagram configuration resulted in empty diagram."};
}

nlohmann::json j;
j["name"] = generators::generator<C, D>::model().name();
j["diagram_type"] = to_string(generators::generator<C, D>::model().type());
if (generators::generator<C, D>::config().title) {
j["title"] = generators::generator<C, D>::config().title();
j["name"] = model.name();
j["diagram_type"] = to_string(model.type());
if (config.title) {
j["title"] = config.title();
}

generate_diagram(j);
Expand Down
7 changes: 7 additions & 0 deletions src/common/generators/mermaid/generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,13 @@ template <typename C, typename D>
void generator<C, D>::generate(std::ostream &ostr) const
{
const auto &config = generators::generator<C, D>::config();
const auto &model = generators::generator<C, D>::model();

if (!config.allow_empty_diagrams() && model.is_empty() &&
config.mermaid().before.empty() && config.mermaid().after.empty()) {
throw clanguml::error::empty_diagram_error{
"Diagram configuration resulted in empty diagram."};
}

update_context();

Expand Down
8 changes: 8 additions & 0 deletions src/common/generators/plantuml/generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "common/model/diagram_filter.h"
#include "common/model/relationship.h"
#include "config/config.h"
#include "error.h"
#include "util/error.h"
#include "util/util.h"
#include "version.h"
Expand Down Expand Up @@ -265,9 +266,16 @@ template <typename C, typename D>
void generator<C, D>::generate(std::ostream &ostr) const
{
const auto &config = generators::generator<C, D>::config();
const auto &model = generators::generator<C, D>::model();

update_context();

if (!config.allow_empty_diagrams() && model.is_empty() &&
config.puml().before.empty() && config.puml().after.empty()) {
throw clanguml::error::empty_diagram_error{
"Diagram configuration resulted in empty diagram."};
}

ostr << "@startuml" << '\n';

generate_title(ostr);
Expand Down
7 changes: 7 additions & 0 deletions src/common/model/diagram.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,13 @@ class diagram {
*/
virtual inja::json context() const = 0;

/**
* @brief Check whether the diagram is empty
*
* @return True, if diagram is empty
*/
virtual bool is_empty() const = 0;

private:
std::string name_;
std::unique_ptr<diagram_filter> filter_;
Expand Down
7 changes: 7 additions & 0 deletions src/common/model/element_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ template <typename T> class element_view {
return {};
}

/**
* @brief Check whether the element view is empty
*
* @return True, if the view does not contain any elements
*/
bool is_empty() const { return elements_.empty(); }

private:
reference_vector<T> elements_;
};
Expand Down
1 change: 1 addition & 0 deletions src/config/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ void inheritable_diagram_options::inherit(
parent.generate_condition_statements);
debug_mode.override(parent.debug_mode);
generate_metadata.override(parent.generate_metadata);
allow_empty_diagrams.override(parent.allow_empty_diagrams);
type_aliases.override(parent.type_aliases);
}

Expand Down
1 change: 1 addition & 0 deletions src/config/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,7 @@ struct inheritable_diagram_options {
"message_comment_width", clanguml::util::kDefaultMessageCommentWidth};
option<bool> debug_mode{"debug_mode", false};
option<bool> generate_metadata{"generate_metadata", true};
option<bool> allow_empty_diagrams{"allow_empty_diagrams", false};

protected:
// This is the relative path with respect to the `base_directory`,
Expand Down
1 change: 1 addition & 0 deletions src/config/schema.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ const std::string schema_str = R"(
query_driver: !optional string
add_compile_flags: !optional [string]
remove_compile_flags: !optional [string]
allow_empty_diagrams: !optional bool
diagram_templates: !optional diagram_templates_t
diagrams: !required map_t<string;diagram_t>
#
Expand Down
1 change: 1 addition & 0 deletions src/config/yaml_decoders.cc
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,7 @@ template <> struct convert<config> {
get_option(node, rhs.using_module);
get_option(node, rhs.output_directory);
get_option(node, rhs.query_driver);
get_option(node, rhs.allow_empty_diagrams);
get_option(node, rhs.compilation_database_dir);
get_option(node, rhs.add_compile_flags);
get_option(node, rhs.remove_compile_flags);
Expand Down
3 changes: 3 additions & 0 deletions src/include_diagram/model/diagram.cc
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ inja::json diagram::context() const

return ctx;
}

bool diagram::is_empty() const { return element_view<source_file>::is_empty(); }

} // namespace clanguml::include_diagram::model

namespace clanguml::common::model {
Expand Down
7 changes: 7 additions & 0 deletions src/include_diagram/model/diagram.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@ class diagram : public clanguml::common::model::diagram,
const common::model::namespace_ &ns) const override;

inja::json context() const override;

/**
* @brief Check whether the diagram is empty
*
* @return True, if diagram is empty
*/
bool is_empty() const override;
};

template <typename ElementT>
Expand Down
2 changes: 2 additions & 0 deletions src/package_diagram/model/diagram.cc
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ inja::json diagram::context() const

return ctx;
}

bool diagram::is_empty() const { return element_view<package>::is_empty(); }
} // namespace clanguml::package_diagram::model

namespace clanguml::common::model {
Expand Down
7 changes: 7 additions & 0 deletions src/package_diagram/model/diagram.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,13 @@ class diagram : public clanguml::common::model::diagram,
*/
inja::json context() const override;

/**
* @brief Check whether the diagram is empty
*
* @return True, if diagram is empty
*/
bool is_empty() const override;

private:
/**
* @brief Add element using module as diagram path
Expand Down
5 changes: 5 additions & 0 deletions src/sequence_diagram/model/diagram.cc
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,11 @@ std::vector<message_chain_t> diagram::get_all_from_to_message_chains(
return message_chains_unique;
}

bool diagram::is_empty() const
{
return sequences_.empty() || participants_.empty();
}

void diagram::print() const
{
LOG_TRACE(" --- Participants ---");
Expand Down
7 changes: 7 additions & 0 deletions src/sequence_diagram/model/diagram.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,13 @@ class diagram : public clanguml::common::model::diagram {
*/
void finalize() override;

/**
* @brief Check whether the diagram is empty
*
* @return True, if diagram is empty
*/
bool is_empty() const override;

private:
/**
* This method checks the last messages in sequence (current_messages),
Expand Down
4 changes: 4 additions & 0 deletions src/util/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,8 @@ class compilation_database_error : public std::runtime_error {
using std::runtime_error::runtime_error;
};

class empty_diagram_error : public std::runtime_error {
using std::runtime_error::runtime_error;
};

} // namespace clanguml::error
1 change: 1 addition & 0 deletions tests/t90000/.clang-uml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
allow_empty_diagrams: true
diagrams:
t90000_class:
type: class
Expand Down
24 changes: 24 additions & 0 deletions tests/t90001/.clang-uml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
diagrams:
t90001_class:
type: class
include:
namespaces:
- no_such_namespace
t90001_sequence:
type: sequence
include:
namespaces:
- no_such_namespace
from:
- function: "nowhere"
t90001_include:
type: include
include:
namespaces:
- no_such_namespace
t90001_package:
type: package
include:
namespaces:
- no_such_namespace

Loading

0 comments on commit baef768

Please sign in to comment.