Refactored class, include and package diagrams visitor to output filtered intermediate diagram (#289)

This commit is contained in:
Bartek Kryza
2024-07-23 14:33:21 +02:00
parent cadbeba82c
commit 2004d25bdd
30 changed files with 403 additions and 358 deletions

View File

@@ -158,26 +158,17 @@ void generator::generate_top_level_elements(nlohmann::json &parent) const
{
for (const auto &p : model()) {
if (auto *pkg = dynamic_cast<package *>(p.get()); pkg) {
if (!pkg->is_empty() &&
!pkg->all_of([this](const common::model::element &e) {
return !model().should_include(e);
}))
if (!pkg->is_empty())
generate(*pkg, parent);
}
else if (auto *cls = dynamic_cast<class_ *>(p.get()); cls) {
if (model().should_include(*cls)) {
generate(*cls, parent);
}
generate(*cls, parent);
}
else if (auto *enm = dynamic_cast<enum_ *>(p.get()); enm) {
if (model().should_include(*enm)) {
generate(*enm, parent);
}
generate(*enm, parent);
}
else if (auto *cpt = dynamic_cast<concept_ *>(p.get()); cpt) {
if (model().should_include(*cpt)) {
generate(*cpt, parent);
}
generate(*cpt, parent);
}
}
}
@@ -203,10 +194,7 @@ void generator::generate(const package &p, nlohmann::json &parent) const
for (const auto &subpackage : p) {
if (dynamic_cast<package *>(subpackage.get()) != nullptr) {
const auto &sp = dynamic_cast<package &>(*subpackage);
if (!sp.is_empty() &&
!sp.all_of([this](const common::model::element &e) {
return !model().should_include(e);
})) {
if (!sp.is_empty()) {
if (config().generate_packages())
generate(sp, package_object);
else
@@ -214,28 +202,22 @@ void generator::generate(const package &p, nlohmann::json &parent) const
}
}
else if (auto *cls = dynamic_cast<class_ *>(subpackage.get()); cls) {
if (model().should_include(*cls)) {
if (config().generate_packages())
generate(*cls, package_object);
else
generate(*cls, parent);
}
if (config().generate_packages())
generate(*cls, package_object);
else
generate(*cls, parent);
}
else if (auto *enm = dynamic_cast<enum_ *>(subpackage.get()); enm) {
if (model().should_include(*enm)) {
if (config().generate_packages())
generate(*enm, package_object);
else
generate(*enm, parent);
}
if (config().generate_packages())
generate(*enm, package_object);
else
generate(*enm, parent);
}
else if (auto *cpt = dynamic_cast<concept_ *>(subpackage.get()); cpt) {
if (model().should_include(*cpt)) {
if (config().generate_packages())
generate(*cpt, package_object);
else
generate(*cpt, parent);
}
if (config().generate_packages())
generate(*cpt, package_object);
else
generate(*cpt, parent);
}
}
@@ -301,19 +283,13 @@ void generator::generate_relationships(nlohmann::json &parent) const
generate_relationships(*pkg, parent);
}
else if (auto *cls = dynamic_cast<class_ *>(p.get()); cls) {
if (model().should_include(*cls)) {
generate_relationships(*cls, parent);
}
generate_relationships(*cls, parent);
}
else if (auto *enm = dynamic_cast<enum_ *>(p.get()); enm) {
if (model().should_include(*enm)) {
generate_relationships(*enm, parent);
}
generate_relationships(*enm, parent);
}
else if (auto *cpt = dynamic_cast<concept_ *>(p.get()); cpt) {
if (model().should_include(*cpt)) {
generate_relationships(*cpt, parent);
}
generate_relationships(*cpt, parent);
}
}
}
@@ -322,9 +298,6 @@ void generator::generate_relationships(
const class_ &c, nlohmann::json &parent) const
{
for (const auto &r : c.relationships()) {
if (!model().should_include(r))
continue;
auto target_element = model().get(r.destination());
if (!target_element.has_value()) {
LOG_DBG("Skipping {} relation from {} to {} due "
@@ -353,9 +326,6 @@ void generator::generate_relationships(
const enum_ &c, nlohmann::json &parent) const
{
for (const auto &r : c.relationships()) {
if (!model().should_include(r))
continue;
auto target_element = model().get(r.destination());
if (!target_element.has_value()) {
LOG_DBG("Skipping {} relation from {} to {} due "
@@ -374,9 +344,6 @@ void generator::generate_relationships(
const concept_ &c, nlohmann::json &parent) const
{
for (const auto &r : c.relationships()) {
if (!model().should_include(r))
continue;
auto target_element = model().get(r.destination());
if (!target_element.has_value()) {
LOG_DBG("Skipping {} relation from {} to {} due "

View File

@@ -89,9 +89,6 @@ void generator::generate(const class_ &c, std::ostream &ostr) const
std::stringstream all_relations_str;
for (const auto &r : c.relationships()) {
if (!model().should_include(r.type()))
continue;
try {
generate_relationship(r, rendered_relations);
}
@@ -111,9 +108,6 @@ void generator::generate(const class_ &c, std::ostream &ostr) const
sort_class_elements(members);
for (const auto &m : members) {
if (!model().should_include(m))
continue;
if (!config().include_relations_also_as_members() &&
rendered_relations.find(m.name()) != rendered_relations.end())
continue;
@@ -156,11 +150,7 @@ void generator::generate_methods(
sort_class_elements(sorted_methods);
for (const auto &m : sorted_methods) {
if (!model().should_include(m))
continue;
generate_method(m, ostr);
ostr << '\n';
}
}
@@ -170,17 +160,11 @@ generator::method_groups_t generator::group_methods(
{
std::map<std::string, std::vector<class_method>> result;
// First get rid of methods which don't pass the filters
std::vector<class_method> filtered_methods;
std::copy_if(methods.cbegin(), methods.cend(),
std::back_inserter(filtered_methods),
[this](auto &m) { return model().should_include(m); });
for (const auto &g : method_groups_) {
result[g] = {};
}
for (const auto &m : filtered_methods) {
for (const auto &m : methods) {
if (m.is_constructor() || m.is_destructor()) {
result["constructors"].push_back(m);
}
@@ -333,19 +317,13 @@ void generator::generate_relationships(std::ostream &ostr) const
generate_relationships(*pkg, ostr);
}
else if (auto *cls = dynamic_cast<class_ *>(p.get()); cls) {
if (model().should_include(*cls)) {
generate_relationships(*cls, ostr);
}
generate_relationships(*cls, ostr);
}
else if (auto *enm = dynamic_cast<enum_ *>(p.get()); enm) {
if (model().should_include(*enm)) {
generate_relationships(*enm, ostr);
}
generate_relationships(*enm, ostr);
}
else if (auto *cpt = dynamic_cast<concept_ *>(p.get()); cpt) {
if (model().should_include(*cpt)) {
generate_relationships(*cpt, ostr);
}
generate_relationships(*cpt, ostr);
}
}
}
@@ -401,9 +379,6 @@ void generator::generate_relationships(
std::set<std::string> unique_relations;
for (const auto &r : c.relationships()) {
if (!model().should_include(r.type()))
continue;
LOG_DBG("== Processing relationship {}", to_string(r.type()));
std::stringstream relstr;
@@ -509,9 +484,6 @@ void generator::generate_relationships(
std::set<std::string> unique_relations;
for (const auto &r : c.relationships()) {
if (!model().should_include(r.type()))
continue;
LOG_DBG("== Processing relationship {}", to_string(r.type()));
std::stringstream relstr;
@@ -583,9 +555,6 @@ void generator::generate_relationships(
void generator::generate_relationships(const enum_ &e, std::ostream &ostr) const
{
for (const auto &r : e.relationships()) {
if (!model().should_include(r.type()))
continue;
eid_t destination{};
std::stringstream relstr;
try {
@@ -718,10 +687,7 @@ void generator::generate_relationships(
// packages which do not contain anything but other
// packages are skipped
const auto &sp = dynamic_cast<package &>(*subpackage);
if (!sp.is_empty() &&
!sp.all_of([this](const common::model::element &e) {
return !model().should_include(e);
}))
if (!sp.is_empty())
generate_relationships(sp, ostr);
}
else if (dynamic_cast<class_ *>(subpackage.get()) != nullptr) {
@@ -758,52 +724,43 @@ void generator::generate_top_level_elements(std::ostream &ostr) const
{
for (const auto &p : model()) {
if (auto *pkg = dynamic_cast<package *>(p.get()); pkg) {
if (!pkg->is_empty() &&
!pkg->all_of([this](const common::model::element &e) {
return !model().should_include(e);
}))
if (!pkg->is_empty())
generate(*pkg, ostr);
}
else if (auto *cls = dynamic_cast<class_ *>(p.get()); cls) {
if (model().should_include(*cls)) {
auto together_group =
config().get_together_group(cls->full_name(false));
if (together_group) {
together_group_stack_.group_together(
together_group.value(), cls);
}
else {
generate_alias(*cls, ostr);
generate(*cls, ostr);
}
auto together_group =
config().get_together_group(cls->full_name(false));
if (together_group) {
together_group_stack_.group_together(
together_group.value(), cls);
}
else {
generate_alias(*cls, ostr);
generate(*cls, ostr);
}
}
else if (auto *enm = dynamic_cast<enum_ *>(p.get()); enm) {
if (model().should_include(*enm)) {
auto together_group =
config().get_together_group(enm->full_name(false));
if (together_group) {
together_group_stack_.group_together(
together_group.value(), enm);
}
else {
generate_alias(*enm, ostr);
generate(*enm, ostr);
}
auto together_group =
config().get_together_group(enm->full_name(false));
if (together_group) {
together_group_stack_.group_together(
together_group.value(), enm);
}
else {
generate_alias(*enm, ostr);
generate(*enm, ostr);
}
}
else if (auto *cpt = dynamic_cast<concept_ *>(p.get()); cpt) {
if (model().should_include(*cpt)) {
auto together_group =
config().get_together_group(cpt->full_name(false));
if (together_group) {
together_group_stack_.group_together(
together_group.value(), cpt);
}
else {
generate_alias(*cpt, ostr);
generate(*cpt, ostr);
}
auto together_group =
config().get_together_group(cpt->full_name(false));
if (together_group) {
together_group_stack_.group_together(
together_group.value(), cpt);
}
else {
generate_alias(*cpt, ostr);
generate(*cpt, ostr);
}
}
}

View File

@@ -157,9 +157,6 @@ void generator::generate(const class_ &c, std::ostream &ostr) const
std::stringstream all_relations_str;
for (const auto &r : c.relationships()) {
if (!model().should_include(r.type()))
continue;
try {
generate_relationship(r, rendered_relations);
}
@@ -182,9 +179,6 @@ void generator::generate(const class_ &c, std::ostream &ostr) const
ostr << "__\n";
for (const auto &m : members) {
if (!model().should_include(m))
continue;
if (!config().include_relations_also_as_members() &&
rendered_relations.find(m.name()) != rendered_relations.end())
continue;
@@ -228,11 +222,7 @@ void generator::generate_methods(
sort_class_elements(sorted_methods);
for (const auto &m : sorted_methods) {
if (!model().should_include(m))
continue;
generate_method(m, ostr);
ostr << '\n';
}
}
@@ -242,17 +232,11 @@ generator::method_groups_t generator::group_methods(
{
std::map<std::string, std::vector<class_method>> result;
// First get rid of methods which don't pass the filters
std::vector<class_method> filtered_methods;
std::copy_if(methods.cbegin(), methods.cend(),
std::back_inserter(filtered_methods),
[this](auto &m) { return model().should_include(m); });
for (const auto &g : method_groups_) {
result[g] = {};
}
for (const auto &m : filtered_methods) {
for (const auto &m : methods) {
if (m.is_constructor() || m.is_destructor()) {
result["constructors"].push_back(m);
}
@@ -417,19 +401,13 @@ void generator::generate_relationships(std::ostream &ostr) const
generate_relationships(*pkg, ostr);
}
else if (auto *cls = dynamic_cast<class_ *>(p.get()); cls) {
if (model().should_include(*cls)) {
generate_relationships(*cls, ostr);
}
generate_relationships(*cls, ostr);
}
else if (auto *enm = dynamic_cast<enum_ *>(p.get()); enm) {
if (model().should_include(*enm)) {
generate_relationships(*enm, ostr);
}
generate_relationships(*enm, ostr);
}
else if (auto *cpt = dynamic_cast<concept_ *>(p.get()); cpt) {
if (model().should_include(*cpt)) {
generate_relationships(*cpt, ostr);
}
generate_relationships(*cpt, ostr);
}
}
}
@@ -481,9 +459,6 @@ void generator::generate_relationships(
std::set<std::string> unique_relations;
for (const auto &r : c.relationships()) {
if (!model().should_include(r.type()))
continue;
LOG_DBG("== Processing relationship {}",
plantuml_common::to_plantuml(r, config()));
@@ -661,9 +636,6 @@ void generator::generate(const enum_ &e, std::ostream &ostr) const
void generator::generate_relationships(const enum_ &e, std::ostream &ostr) const
{
for (const auto &r : e.relationships()) {
if (!model().should_include(r.type()))
continue;
eid_t destination{};
std::stringstream relstr;
try {
@@ -724,10 +696,7 @@ void generator::generate(const package &p, std::ostream &ostr) const
if (dynamic_cast<package *>(subpackage.get()) != nullptr) {
// TODO: add option - generate_empty_packages
const auto &sp = dynamic_cast<package &>(*subpackage);
if (!sp.is_empty() &&
!sp.all_of([this](const common::model::element &e) {
return !model().should_include(e);
})) {
if (!sp.is_empty()) {
together_group_stack_.enter();
generate(sp, ostr);
@@ -822,10 +791,7 @@ void generator::generate_relationships(
// packages which do not contain anything but other
// packages are skipped
const auto &sp = dynamic_cast<package &>(*subpackage);
if (!sp.is_empty() &&
!sp.all_of([this](const common::model::element &e) {
return !model().should_include(e);
}))
if (!sp.is_empty())
generate_relationships(sp, ostr);
}
else if (dynamic_cast<class_ *>(subpackage.get()) != nullptr) {
@@ -864,52 +830,43 @@ void generator::generate_top_level_elements(std::ostream &ostr) const
{
for (const auto &p : model()) {
if (auto *pkg = dynamic_cast<package *>(p.get()); pkg) {
if (!pkg->is_empty() &&
!pkg->all_of([this](const common::model::element &e) {
return !model().should_include(e);
}))
if (!pkg->is_empty())
generate(*pkg, ostr);
}
else if (auto *cls = dynamic_cast<class_ *>(p.get()); cls) {
if (model().should_include(*cls)) {
auto together_group =
config().get_together_group(cls->full_name(false));
if (together_group) {
together_group_stack_.group_together(
together_group.value(), cls);
}
else {
generate_alias(*cls, ostr);
generate(*cls, ostr);
}
auto together_group =
config().get_together_group(cls->full_name(false));
if (together_group) {
together_group_stack_.group_together(
together_group.value(), cls);
}
else {
generate_alias(*cls, ostr);
generate(*cls, ostr);
}
}
else if (auto *enm = dynamic_cast<enum_ *>(p.get()); enm) {
if (model().should_include(*enm)) {
auto together_group =
config().get_together_group(enm->full_name(false));
if (together_group) {
together_group_stack_.group_together(
together_group.value(), enm);
}
else {
generate_alias(*enm, ostr);
generate(*enm, ostr);
}
auto together_group =
config().get_together_group(enm->full_name(false));
if (together_group) {
together_group_stack_.group_together(
together_group.value(), enm);
}
else {
generate_alias(*enm, ostr);
generate(*enm, ostr);
}
}
else if (auto *cpt = dynamic_cast<concept_ *>(p.get()); cpt) {
if (model().should_include(*cpt)) {
auto together_group =
config().get_together_group(cpt->full_name(false));
if (together_group) {
together_group_stack_.group_together(
together_group.value(), cpt);
}
else {
generate_alias(*cpt, ostr);
generate(*cpt, ostr);
}
auto together_group =
config().get_together_group(cpt->full_name(false));
if (together_group) {
together_group_stack_.group_together(
together_group.value(), cpt);
}
else {
generate_alias(*cpt, ostr);
generate(*cpt, ostr);
}
}
}

View File

@@ -18,6 +18,7 @@
#include "class.h"
#include "common/model/filters/diagram_filter.h"
#include "util/util.h"
#include <sstream>
@@ -63,6 +64,7 @@ const std::vector<class_member> &class_::members() const { return members_; }
const std::vector<class_method> &class_::methods() const { return methods_; }
const std::vector<class_parent> &class_::parents() const { return bases_; }
std::vector<class_parent> &class_::parents() { return bases_; }
bool operator==(const class_ &l, const class_ &r) { return l.id() == r.id(); }
@@ -111,6 +113,21 @@ bool class_::is_abstract() const
[](const auto &method) { return method.is_pure_virtual(); });
}
void class_::apply_filter(
const common::model::diagram_filter &filter, const std::set<eid_t> &removed)
{
diagram_element::apply_filter(filter, removed);
common::model::apply_filter(members_, filter);
common::model::apply_filter(methods_, filter);
// Remove class bases which are no longer in the diagram
parents().erase(
std::remove_if(parents().begin(), parents().end(),
[&removed](auto &&p) { return removed.count(p.id()) > 0; }),
parents().end());
}
std::optional<std::string> class_::doxygen_link() const
{
const auto *type = is_struct() ? "struct" : "class";

View File

@@ -30,6 +30,10 @@
#include <string>
#include <vector>
namespace clanguml::common::model {
class diagram_filter;
}
namespace clanguml::class_diagram::model {
/**
@@ -126,6 +130,7 @@ public:
* @return Reference to class parents.
*/
const std::vector<class_parent> &parents() const;
std::vector<class_parent> &parents();
/**
* @brief Get class full name.
@@ -166,6 +171,9 @@ public:
*/
std::optional<std::string> doxygen_link() const override;
void apply_filter(const common::model::diagram_filter &filter,
const std::set<eid_t> &removed) override;
private:
bool is_struct_{false};
bool is_union_{false};

View File

@@ -256,6 +256,39 @@ void diagram::remove_redundant_dependencies()
}
}
void diagram::apply_filter()
{
// First find all element ids which should be removed
std::set<eid_t> to_remove;
for (const auto &c : element_view<class_>::view())
if (!filter().should_include(c.get()))
to_remove.emplace(c.get().id());
for (const auto &e : element_view<enum_>::view())
if (!filter().should_include(e.get()))
to_remove.emplace(e.get().id());
for (const auto &c : element_view<concept_>::view())
if (!filter().should_include(c.get()))
to_remove.emplace(c.get().id());
nested_trait_ns::remove(to_remove);
element_view<class_>::remove(to_remove);
element_view<enum_>::remove(to_remove);
element_view<concept_>::remove(to_remove);
for (auto &c : element_view<class_>::view())
c.get().apply_filter(filter(), to_remove);
for (auto &e : element_view<enum_>::view())
e.get().apply_filter(filter(), to_remove);
for (auto &c : element_view<concept_>::view())
c.get().apply_filter(filter(), to_remove);
}
bool diagram::is_empty() const
{
return element_view<class_>::is_empty() &&

View File

@@ -256,6 +256,8 @@ public:
*/
bool is_empty() const override;
void apply_filter() override;
private:
template <typename ElementT>
bool add_with_namespace_path(std::unique_ptr<ElementT> &&e);

View File

@@ -941,12 +941,27 @@ bool parse_source_location(const std::string &location_str, std::string &file,
clang::RawComment *get_expression_raw_comment(const clang::SourceManager &sm,
const clang::ASTContext &context, const clang::Stmt *stmt)
{
// First get the first line of the expression
auto expr_begin = stmt->getSourceRange().getBegin();
return get_raw_comment(sm, context, stmt->getSourceRange());
}
clang::RawComment *get_declaration_raw_comment(const clang::SourceManager &sm,
const clang::ASTContext &context, const clang::Decl *decl)
{
return get_raw_comment(sm, context, decl->getSourceRange());
}
clang::RawComment *get_raw_comment(const clang::SourceManager &sm,
const clang::ASTContext &context, const clang::SourceRange &source_range)
{
auto expr_begin = source_range.getBegin();
const auto expr_begin_line = sm.getSpellingLineNumber(expr_begin);
std::string file_Path = sm.getFilename(expr_begin).str();
auto file_id = sm.getFileID(expr_begin);
if (!context.Comments.empty() &&
context.Comments.getCommentsInFile(sm.getFileID(expr_begin)) != nullptr)
context.Comments.getCommentsInFile(file_id) != nullptr) {
for (const auto [offset, raw_comment] :
*context.Comments.getCommentsInFile(sm.getFileID(expr_begin))) {
const auto comment_end_line = sm.getSpellingLineNumber(
@@ -956,6 +971,7 @@ clang::RawComment *get_expression_raw_comment(const clang::SourceManager &sm,
expr_begin_line == comment_end_line + 1)
return raw_comment;
}
}
return {};
}

View File

@@ -299,6 +299,12 @@ consume_type_context(clang::QualType type);
clang::RawComment *get_expression_raw_comment(const clang::SourceManager &sm,
const clang::ASTContext &context, const clang::Stmt *stmt);
clang::RawComment *get_declaration_raw_comment(const clang::SourceManager &sm,
const clang::ASTContext &context, const clang::Decl *decl);
clang::RawComment *get_raw_comment(const clang::SourceManager &sm,
const clang::ASTContext &context, const clang::SourceRange &source_range);
/**
* Check if function or method declaration is a C++20 coroutine.
*

View File

@@ -59,10 +59,18 @@ void diagram::set_complete(bool complete) { complete_ = complete; }
bool diagram::complete() const { return complete_; }
void diagram::finalize() { }
void diagram::finalize()
{
// Remove elements that do not match the filter
apply_filter();
filtered_ = true;
}
bool diagram::should_include(const element &e) const
{
if (filtered_)
return true;
if (filter_.get() == nullptr)
return true;
@@ -77,6 +85,9 @@ bool diagram::should_include(const element &e) const
bool diagram::should_include(const namespace_ &ns) const
{
if (filtered_)
return true;
if (filter_.get() == nullptr)
return true;

View File

@@ -171,10 +171,13 @@ public:
*/
virtual bool is_empty() const = 0;
virtual void apply_filter() { }
private:
std::string name_;
std::unique_ptr<diagram_filter> filter_;
bool complete_{false};
bool filtered_{false};
};
template <typename DiagramT> bool check_diagram_type(diagram_t t);

View File

@@ -18,6 +18,7 @@
#include "diagram_element.h"
#include "common/model/filters/diagram_filter.h"
#include "util/util.h"
#include <ostream>
@@ -102,6 +103,19 @@ bool diagram_element::complete() const { return complete_; }
void diagram_element::complete(bool completed) { complete_ = completed; }
void diagram_element::apply_filter(
const diagram_filter &filter, const std::set<eid_t> &removed)
{
common::model::apply_filter(relationships(), filter);
auto &rels = relationships();
rels.erase(std::remove_if(std::begin(rels), std::end(rels),
[&removed](auto &&r) {
return removed.count(r.destination()) > 0;
}),
std::end(rels));
}
bool operator==(const diagram_element &l, const diagram_element &r)
{
return l.id() == r.id();

View File

@@ -26,11 +26,14 @@
#include <atomic>
#include <exception>
#include <set>
#include <string>
#include <vector>
namespace clanguml::common::model {
class diagram_filter;
/**
* @brief Base class for standalone diagram elements.
*
@@ -184,6 +187,9 @@ public:
*/
void complete(bool completed);
virtual void apply_filter(
const diagram_filter &filter, const std::set<eid_t> &removed);
private:
eid_t id_{};
std::optional<eid_t> parent_element_id_{};

View File

@@ -78,6 +78,15 @@ public:
*/
bool is_empty() const { return elements_.empty(); }
void remove(const std::set<eid_t> &element_ids)
{
elements_.erase(std::remove_if(elements_.begin(), elements_.end(),
[&element_ids](auto &&e) {
return element_ids.count(e.get().id()) > 0;
}),
elements_.end());
}
private:
reference_vector<T> elements_;
};

View File

@@ -99,6 +99,12 @@ tvl::value_t filter_visitor::match(
return {};
}
tvl::value_t filter_visitor::match(
const diagram &d, const common::model::relationship &r) const
{
return match(d, r.type());
}
tvl::value_t filter_visitor::match(
const diagram & /*d*/, const common::model::relationship_t & /*r*/) const
{
@@ -997,7 +1003,7 @@ tvl::value_t paths_filter::match(
return {};
}
// Matching source paths doesn't make sens if they are not absolute
// Matching source paths doesn't make sense if they are not absolute
if (!p.is_absolute()) {
return {};
}
@@ -1071,7 +1077,7 @@ tvl::value_t class_member_filter::match(
}
diagram_filter::diagram_filter(const common::model::diagram &d,
const config::diagram &c, private_constructor_tag_t /*unused*/)
const config::diagram & /*c*/, private_constructor_tag_t /*unused*/)
: diagram_{d}
{
}

View File

@@ -86,6 +86,9 @@ public:
virtual tvl::value_t match(
const diagram &d, const common::model::element &e) const;
virtual tvl::value_t match(
const diagram &d, const common::model::relationship &r) const;
virtual tvl::value_t match(
const diagram &d, const common::model::relationship_t &r) const;
@@ -815,15 +818,6 @@ public:
friend class diagram_filter_factory;
private:
/**
* @brief Initialize filters.
*
* Some filters require initialization.
*
* @param c Diagram config.
*/
// void init_filters(const config::diagram &c);
/*! List of inclusive filters */
std::vector<std::unique_ptr<filter_visitor>> inclusive_;
@@ -834,6 +828,27 @@ private:
const common::model::diagram &diagram_;
};
template <typename Collection>
void apply_filter(Collection &col, const diagram_filter &filter)
{
col.erase(std::remove_if(col.begin(), col.end(),
[&filter](auto &&element) {
return !filter.should_include(element);
}),
col.end());
}
template <typename T>
void apply_filter(
std::vector<std::reference_wrapper<T>> &col, const diagram_filter &filter)
{
col.erase(std::remove_if(col.begin(), col.end(),
[&filter](auto &&element) {
return !filter.should_include(element.get());
}),
col.end());
}
template <>
bool diagram_filter::should_include<std::string>(const std::string &name) const;
} // namespace clanguml::common::model

View File

@@ -253,8 +253,10 @@ template <>
void advanced_diagram_filter_initializer::add_filter<
source_file_dependency_filter_t>(const filter_t &filter_type,
const std::vector<common::string_or_regex> &filter_config,
std::vector<std::unique_ptr<filter_visitor>> &result, relationship_t &&rt,
bool &&direction)
std::vector<std::unique_ptr<filter_visitor>> &result,
relationship_t &&rt, // NOLINT
bool &&direction // NOLINT
)
{
std::vector<std::string> deps;
for (auto &&path : filter_config) {

View File

@@ -51,6 +51,8 @@ public:
{
}
virtual ~diagram_filter_initializer() = default;
virtual void initialize() = 0;
protected:
@@ -62,6 +64,8 @@ class basic_diagram_filter_initializer : public diagram_filter_initializer {
public:
using diagram_filter_initializer::diagram_filter_initializer;
~basic_diagram_filter_initializer() override = default;
void initialize() override;
};
@@ -69,6 +73,8 @@ class advanced_diagram_filter_initializer : public diagram_filter_initializer {
public:
using diagram_filter_initializer::diagram_filter_initializer;
~advanced_diagram_filter_initializer() override = default;
void initialize() override;
private:

View File

@@ -21,6 +21,7 @@
#include <iostream>
#include <optional>
#include <set>
#include <string>
#include <vector>
@@ -245,6 +246,23 @@ public:
}
}
void remove(const std::set<eid_t> &element_ids)
{
// First remove all matching elements on this level
elements_.erase(std::remove_if(elements_.begin(), elements_.end(),
[&element_ids](auto &&e) {
return element_ids.count(e->id()) > 0;
}),
elements_.end());
// Now recurse to any packages on this level
for (auto &p : elements_) {
if (dynamic_cast<nested_trait<T, Path> *>(p.get()))
dynamic_cast<nested_trait<T, Path> *>(p.get())->remove(
element_ids);
}
}
private:
std::vector<std::unique_ptr<T>> elements_;
};

View File

@@ -253,8 +253,12 @@ public:
comment_visitor_->visit(decl, e);
const auto *comment =
decl.getASTContext().getRawCommentForDeclNoCache(&decl);
auto *comment = decl.getASTContext().getRawCommentForDeclNoCache(&decl);
if (comment == nullptr) {
comment = clanguml::common::get_declaration_raw_comment(
source_manager(), decl.getASTContext(), &decl);
}
process_comment(comment, decl.getASTContext().getDiagnostics(), e);
}

View File

@@ -39,14 +39,11 @@ void generator::generate_relationships(
});
}
else {
util::for_each_if(
f.relationships(),
[this](const auto &r) { return model().should_include(r.type()); },
[&f, &parent](const auto &r) {
nlohmann::json rel = r;
rel["source"] = std::to_string(f.id().value());
parent["relationships"].push_back(std::move(rel));
});
for (const auto &r : f.relationships()) {
nlohmann::json rel = r;
rel["source"] = std::to_string(f.id().value());
parent["relationships"].push_back(std::move(rel));
}
}
}
@@ -73,17 +70,15 @@ void generator::generate(const source_file &f, nlohmann::json &parent) const
parent["elements"].push_back(std::move(j));
}
else {
if (model().should_include(f)) {
LOG_DBG("Generating file {}", f.name());
LOG_DBG("Generating file {}", f.name());
j["type"] = "file";
j["file_kind"] = to_string(f.type());
if (f.type() == common::model::source_file_t::kHeader) {
j["is_system"] = f.is_system_header();
}
parent["elements"].push_back(std::move(j));
j["type"] = "file";
j["file_kind"] = to_string(f.type());
if (f.type() == common::model::source_file_t::kHeader) {
j["is_system"] = f.is_system_header();
}
parent["elements"].push_back(std::move(j));
}
}

View File

@@ -49,21 +49,13 @@ void generator::generate_relationships(
});
}
else {
util::for_each_if(
f.relationships(),
[this](const auto &r) {
return model().should_include(r.type()) &&
util::contains(m_generated_aliases,
model().get(r.destination()).value().alias());
},
[&f, &ostr, this](const auto &r) {
ostr << indent(1) << f.alias() << " "
<< (r.type() == common::model::relationship_t::kDependency
? "-.->"
: "-->")
<< " " << model().get(r.destination()).value().alias()
<< '\n';
});
for (const auto &r : f.relationships()) {
ostr << indent(1) << f.alias() << " "
<< (r.type() == common::model::relationship_t::kDependency
? "-.->"
: "-->")
<< " " << model().get(r.destination()).value().alias() << '\n';
}
}
}
@@ -86,11 +78,9 @@ void generator::generate(const source_file &f, std::ostream &ostr) const
else {
LOG_DBG("Generating file {}", f.name());
if (model().should_include(f)) {
ostr << indent(1) << f.alias() << "[" << f.name() << "]\n";
ostr << indent(1) << f.alias() << "[" << f.name() << "]\n";
m_generated_aliases.emplace(f.alias());
}
m_generated_aliases.emplace(f.alias());
}
if (config().generate_links) {

View File

@@ -44,18 +44,11 @@ void generator::generate_relationships(
});
}
else {
util::for_each_if(
f.relationships(),
[this](const auto &r) {
return model().should_include(r.type()) &&
util::contains(m_generated_aliases,
model().get(r.destination()).value().alias());
},
[&f, &ostr, this](const auto &r) {
ostr << f.alias() << " "
<< plantuml_common::to_plantuml(r, config()) << " "
<< model().get(r.destination()).value().alias() << '\n';
});
for (const auto &r : f.relationships()) {
ostr << f.alias() << " "
<< plantuml_common::to_plantuml(r, config()) << " "
<< model().get(r.destination()).value().alias() << '\n';
}
}
}
@@ -79,17 +72,15 @@ void generator::generate(const source_file &f, std::ostream &ostr) const
else {
LOG_DBG("Generating file {}", f.name());
if (model().should_include(f)) {
ostr << "file \"" << f.name() << "\" as " << f.alias();
ostr << "file \"" << f.name() << "\" as " << f.alias();
if (config().generate_links) {
generate_link(ostr, f);
}
ostr << '\n';
m_generated_aliases.emplace(f.alias());
if (config().generate_links) {
generate_link(ostr, f);
}
ostr << '\n';
m_generated_aliases.emplace(f.alias());
}
}

View File

@@ -18,6 +18,7 @@
#include "diagram.h"
#include "common/model/filters/diagram_filter.h"
#include "util/error.h"
#include "util/util.h"
@@ -53,8 +54,6 @@ void diagram::add_file(std::unique_ptr<common::model::source_file> &&f)
assert(!ff.name().empty());
assert(ff.id().value() != 0);
element_view<source_file>::add(ff);
auto p = ff.path();
if (!f->path().is_empty()) {
@@ -86,7 +85,8 @@ void diagram::add_file(std::unique_ptr<common::model::source_file> &&f)
assert(p.type() == common::model::path_type::kFilesystem);
add_element(p, std::move(f));
if (add_element(p, std::move(f)))
element_view<source_file>::add(ff);
}
const common::reference_vector<common::model::source_file> &
@@ -133,6 +133,25 @@ inja::json diagram::context() const
return ctx;
}
void diagram::apply_filter()
{
// First find all element ids which should be removed
std::set<eid_t> to_remove;
for (auto &f : element_view<source_file>::view())
if (f.get().type() != common::model::source_file_t::kDirectory &&
!filter().should_include(f.get())) {
to_remove.emplace(f.get().id());
}
for (auto &sf : element_view<source_file>::view())
sf.get().apply_filter(filter(), to_remove);
element_view<source_file>::remove(to_remove);
nested_trait_fspath::remove(to_remove);
}
bool diagram::is_empty() const { return element_view<source_file>::is_empty(); }
} // namespace clanguml::include_diagram::model

View File

@@ -33,13 +33,15 @@ using clanguml::common::opt_ref;
using clanguml::common::model::diagram_element;
using clanguml::common::model::source_file;
using nested_trait_fspath = clanguml::common::model::nested_trait<source_file,
clanguml::common::model::filesystem_path>;
/**
* @brief Class representing an include diagram model.
*/
class diagram : public clanguml::common::model::diagram,
public clanguml::common::model::element_view<source_file>,
public clanguml::common::model::nested_trait<source_file,
clanguml::common::model::filesystem_path> {
public nested_trait_fspath {
public:
diagram() = default;
@@ -128,6 +130,8 @@ public:
* @return True, if diagram is empty
*/
bool is_empty() const override;
void apply_filter() override;
};
template <typename ElementT>

View File

@@ -39,9 +39,7 @@ void generator::generate_relationships(
auto destination_package = model().get(r.destination());
if (!destination_package ||
!model().should_include(
dynamic_cast<const package &>(*destination_package)))
if (!destination_package)
continue;
rel["source"] = std::to_string(p.id().value());
@@ -88,9 +86,7 @@ void generator::generate(const package &p, nlohmann::json &parent) const
for (const auto &subpackage : p) {
auto &pkg = dynamic_cast<package &>(*subpackage);
if (model().should_include(pkg)) {
generate(pkg, j);
}
generate(pkg, j);
}
parent["elements"].push_back(std::move(j));
@@ -98,9 +94,7 @@ void generator::generate(const package &p, nlohmann::json &parent) const
else {
for (const auto &subpackage : p) {
auto &pkg = dynamic_cast<package &>(*subpackage);
if (model().should_include(pkg)) {
generate(pkg, parent);
}
generate(pkg, parent);
}
}
}
@@ -120,15 +114,12 @@ void generator::generate_diagram(nlohmann::json &parent) const
for (const auto &p : model()) {
auto &pkg = dynamic_cast<package &>(*p);
if (model().should_include(pkg)) {
generate(pkg, parent);
}
generate(pkg, parent);
}
// Process package relationships
for (const auto &p : model()) {
if (model().should_include(dynamic_cast<package &>(*p)))
generate_relationships(dynamic_cast<package &>(*p), parent);
generate_relationships(dynamic_cast<package &>(*p), parent);
}
}

View File

@@ -47,9 +47,7 @@ void generator::generate_relationships(
try {
auto destination_package = model().get(r.destination());
if (!destination_package ||
!model().should_include(
dynamic_cast<const package &>(*destination_package)))
if (!destination_package)
continue;
auto destination_alias = model().to_alias(r.destination());
@@ -94,16 +92,12 @@ void generator::generate(const package &p, std::ostream &ostr) const
for (const auto &subpackage : p) {
auto &pkg = dynamic_cast<package &>(*subpackage);
if (model().should_include(pkg)) {
auto together_group =
config().get_together_group(pkg.full_name(false));
if (together_group) {
together_group_stack_.group_together(
together_group.value(), &pkg);
}
else {
generate(pkg, ostr);
}
auto together_group = config().get_together_group(pkg.full_name(false));
if (together_group) {
together_group_stack_.group_together(together_group.value(), &pkg);
}
else {
generate(pkg, ostr);
}
}
@@ -159,16 +153,12 @@ void generator::generate_diagram(std::ostream &ostr) const
{
for (const auto &p : model()) {
auto &pkg = dynamic_cast<package &>(*p);
if (model().should_include(pkg)) {
auto together_group =
config().get_together_group(pkg.full_name(false));
if (together_group) {
together_group_stack_.group_together(
together_group.value(), &pkg);
}
else {
generate(pkg, ostr);
}
auto together_group = config().get_together_group(pkg.full_name(false));
if (together_group) {
together_group_stack_.group_together(together_group.value(), &pkg);
}
else {
generate(pkg, ostr);
}
}
@@ -176,8 +166,7 @@ void generator::generate_diagram(std::ostream &ostr) const
// Process package relationships
for (const auto &p : model()) {
if (model().should_include(dynamic_cast<package &>(*p)))
generate_relationships(dynamic_cast<package &>(*p), ostr);
generate_relationships(dynamic_cast<package &>(*p), ostr);
}
}

View File

@@ -39,10 +39,7 @@ void generator::generate_relationships(
std::stringstream relstr;
try {
auto destination_package = model().get(r.destination());
if (!destination_package ||
!model().should_include(
dynamic_cast<const package &>(*destination_package)))
if (!destination_package)
continue;
auto destination_alias = model().to_alias(r.destination());
@@ -62,9 +59,8 @@ void generator::generate_relationships(
// Process it's subpackages relationships
for (const auto &subpackage : p) {
if (model().should_include(dynamic_cast<const package &>(*subpackage)))
generate_relationships(
dynamic_cast<const package &>(*subpackage), ostr);
generate_relationships(
dynamic_cast<const package &>(*subpackage), ostr);
}
}
@@ -96,16 +92,12 @@ void generator::generate(const package &p, std::ostream &ostr) const
for (const auto &subpackage : p) {
auto &pkg = dynamic_cast<package &>(*subpackage);
if (model().should_include(pkg)) {
auto together_group =
config().get_together_group(pkg.full_name(false));
if (together_group) {
together_group_stack_.group_together(
together_group.value(), &pkg);
}
else {
generate(pkg, ostr);
}
auto together_group = config().get_together_group(pkg.full_name(false));
if (together_group) {
together_group_stack_.group_together(together_group.value(), &pkg);
}
else {
generate(pkg, ostr);
}
}
@@ -138,16 +130,12 @@ void generator::generate_diagram(std::ostream &ostr) const
{
for (const auto &p : model()) {
auto &pkg = dynamic_cast<package &>(*p);
if (model().should_include(pkg)) {
auto together_group =
config().get_together_group(pkg.full_name(false));
if (together_group) {
together_group_stack_.group_together(
together_group.value(), &pkg);
}
else {
generate(pkg, ostr);
}
auto together_group = config().get_together_group(pkg.full_name(false));
if (together_group) {
together_group_stack_.group_together(together_group.value(), &pkg);
}
else {
generate(pkg, ostr);
}
}
@@ -155,8 +143,7 @@ void generator::generate_diagram(std::ostream &ostr) const
// Process package relationships
for (const auto &p : model()) {
if (model().should_include(dynamic_cast<package &>(*p)))
generate_relationships(dynamic_cast<package &>(*p), ostr);
generate_relationships(dynamic_cast<package &>(*p), ostr);
}
generate_config_layout_hints(ostr);

View File

@@ -18,6 +18,7 @@
#include "diagram.h"
#include "common/model/filters/diagram_filter.h"
#include "util/error.h"
#include "util/util.h"
@@ -74,6 +75,23 @@ inja::json diagram::context() const
return ctx;
}
void diagram::apply_filter()
{
// First find all element ids which should be removed
std::set<eid_t> to_remove;
for (const auto &c : packages())
if (!filter().should_include(c.get()))
to_remove.emplace(c.get().id());
nested_trait_ns::remove(to_remove);
element_view<package>::remove(to_remove);
for (auto &c : element_view<package>::view())
c.get().apply_filter(filter(), to_remove);
}
bool diagram::is_empty() const { return element_view<package>::is_empty(); }
} // namespace clanguml::package_diagram::model

View File

@@ -32,14 +32,16 @@ using clanguml::common::model::diagram_element;
using clanguml::common::model::package;
using clanguml::common::model::path;
using nested_trait_ns =
clanguml::common::model::nested_trait<clanguml::common::model::element,
clanguml::common::model::namespace_>;
/**
* @brief Package diagram model.
*/
class diagram : public clanguml::common::model::diagram,
public clanguml::common::model::element_view<package>,
public clanguml::common::model::nested_trait<
clanguml::common::model::element,
clanguml::common::model::namespace_> {
public nested_trait_ns {
public:
diagram() = default;
@@ -165,6 +167,8 @@ public:
*/
bool is_empty() const override;
void apply_filter() override;
private:
/**
* @brief Add element using module as diagram path