Refactored class_relationship

This commit is contained in:
Bartek Kryza
2021-09-27 23:16:46 +02:00
parent b24d0f4837
commit 9629f9a49d
4 changed files with 174 additions and 121 deletions

View File

@@ -187,34 +187,34 @@ void generator::generate(const class_ &c, std::ostream &ostr) const
std::stringstream all_relations_str; std::stringstream all_relations_str;
std::set<std::string> unique_relations; std::set<std::string> unique_relations;
for (const auto &r : c.relationships()) { for (const auto &r : c.relationships()) {
if (!m_config.should_include_relationship(name(r.type))) if (!m_config.should_include_relationship(name(r.type())))
continue; continue;
LOG_DBG("== Processing relationship {}", to_string(r.type)); LOG_DBG("== Processing relationship {}", to_string(r.type()));
std::stringstream relstr; std::stringstream relstr;
std::string destination; std::string destination;
try { try {
destination = r.destination; destination = r.destination();
LOG_DBG("=== Destination is: {}", destination); LOG_DBG("=== Destination is: {}", destination);
std::string puml_relation; std::string puml_relation;
if (!r.multiplicity_source.empty()) if (!r.multiplicity_source().empty())
puml_relation += "\"" + r.multiplicity_source + "\" "; puml_relation += "\"" + r.multiplicity_source() + "\" ";
puml_relation += to_string(r.type, r.style()); puml_relation += to_string(r.type(), r.style());
if (!r.multiplicity_destination.empty()) if (!r.multiplicity_destination().empty())
puml_relation += " \"" + r.multiplicity_destination + "\""; puml_relation += " \"" + r.multiplicity_destination() + "\"";
relstr << m_model.to_alias(ns_relative(uns, c.full_name())) << " " relstr << m_model.to_alias(ns_relative(uns, c.full_name())) << " "
<< puml_relation << " " << puml_relation << " "
<< m_model.to_alias(ns_relative(uns, destination)); << m_model.to_alias(ns_relative(uns, destination));
if (!r.label.empty()) { if (!r.label().empty()) {
relstr << " : " << to_string(r.scope) << r.label; relstr << " : " << to_string(r.scope()) << r.label();
rendered_relations.emplace(r.label); rendered_relations.emplace(r.label());
} }
if (unique_relations.count(relstr.str()) == 0) { if (unique_relations.count(relstr.str()) == 0) {
@@ -230,7 +230,7 @@ void generator::generate(const class_ &c, std::ostream &ostr) const
catch (error::uml_alias_missing &e) { catch (error::uml_alias_missing &e) {
LOG_ERROR("=== Skipping {} relation from {} to {} due " LOG_ERROR("=== Skipping {} relation from {} to {} due "
"to: {}", "to: {}",
to_string(r.type), c.full_name(), destination, e.what()); to_string(r.type()), c.full_name(), destination, e.what());
} }
} }
@@ -303,23 +303,23 @@ void generator::generate(const enum_ &e, std::ostream &ostr) const
ostr << "}" << '\n'; ostr << "}" << '\n';
for (const auto &r : e.relationships()) { for (const auto &r : e.relationships()) {
if (!m_config.should_include_relationship(name(r.type))) if (!m_config.should_include_relationship(name(r.type())))
continue; continue;
std::string destination; std::string destination;
std::stringstream relstr; std::stringstream relstr;
try { try {
destination = r.destination; destination = r.destination();
relstr << m_model.to_alias( relstr << m_model.to_alias(
ns_relative(m_config.using_namespace, e.name())) ns_relative(m_config.using_namespace, e.name()))
<< " " << to_string(r.type) << " " << " " << to_string(r.type()) << " "
<< m_model.to_alias( << m_model.to_alias(
ns_relative(m_config.using_namespace, destination)); ns_relative(m_config.using_namespace, destination));
if (!r.label.empty()) if (!r.label().empty())
relstr << " : " << r.label; relstr << " : " << r.label();
relstr << '\n'; relstr << '\n';
@@ -328,7 +328,7 @@ void generator::generate(const enum_ &e, std::ostream &ostr) const
catch (error::uml_alias_missing &ex) { catch (error::uml_alias_missing &ex) {
LOG_ERROR("Skipping {} relation from {} to {} due " LOG_ERROR("Skipping {} relation from {} to {} due "
"to: {}", "to: {}",
to_string(r.type), e.full_name(), destination, ex.what()); to_string(r.type()), e.full_name(), destination, ex.what());
} }
} }

View File

@@ -173,10 +173,10 @@ std::string element::alias() const { return fmt::format("C_{:010}", m_id); }
void element::add_relationship(class_relationship &&cr) void element::add_relationship(class_relationship &&cr)
{ {
if (cr.destination.empty()) { if (cr.destination().empty()) {
LOG_WARN("Skipping relationship '{}' - {} - '{}' due empty " LOG_WARN("Skipping relationship '{}' - {} - '{}' due empty "
"destination", "destination",
cr.destination, to_string(cr.type), full_name(true)); cr.destination(), to_string(cr.type()), full_name(true));
return; return;
} }
@@ -300,11 +300,67 @@ class_parent::access_t class_parent::access() const { return access_; }
// //
// class_relationship // class_relationship
// //
class_relationship::class_relationship(relationship_t type,
const std::string &destination, scope_t scope, const std::string &label,
const std::string &multiplicity_source,
const std::string &multiplicity_destination)
: type_{type}
, destination_{destination}
, scope_{scope}
, label_{label}
, multiplicity_source_{multiplicity_source}
, multiplicity_destination_{multiplicity_destination}
{
}
void class_relationship::set_type(relationship_t type) noexcept
{
type_ = type;
}
relationship_t class_relationship::type() const noexcept { return type_; }
void class_relationship::set_destination(const std::string &destination)
{
destination_ = destination;
}
std::string class_relationship::destination() const { return destination_; }
void class_relationship::set_multiplicity_source(
const std::string &multiplicity_source)
{
multiplicity_source_ = multiplicity_source;
}
std::string class_relationship::multiplicity_source() const
{
return multiplicity_source_;
}
void class_relationship::set_multiplicity_destination(
const std::string &multiplicity_destination)
{
multiplicity_destination_ = multiplicity_destination;
}
std::string class_relationship::multiplicity_destination() const
{
return multiplicity_destination_;
}
void class_relationship::set_label(const std::string &label) { label_ = label; }
std::string class_relationship::label() const { return label_; }
void class_relationship::set_scope(scope_t scope) noexcept { scope_ = scope; }
scope_t class_relationship::scope() const noexcept { return scope_; }
bool operator==(const class_relationship &l, const class_relationship &r) bool operator==(const class_relationship &l, const class_relationship &r)
{ {
return l.type == r.type && l.destination == r.destination && return l.type() == r.type() && l.destination() == r.destination() &&
l.label == r.label; l.label() == r.label();
} }
// //

View File

@@ -185,16 +185,44 @@ private:
access_t access_; access_t access_;
}; };
struct class_relationship : public decorated_element, public stylable_element { class class_relationship : public decorated_element, public stylable_element {
relationship_t type{relationship_t::kAssociation}; public:
std::string destination; class_relationship(relationship_t type, const std::string &destination,
std::string multiplicity_source; scope_t scope = scope_t::kNone, const std::string &label = "",
std::string multiplicity_destination; const std::string &multiplicity_source = "",
std::string label; const std::string &multiplicity_destination = "");
scope_t scope{scope_t::kNone};
virtual ~class_relationship() = default;
void set_type(relationship_t type) noexcept;
relationship_t type() const noexcept;
void set_destination(const std::string &destination);
std::string destination() const;
void set_multiplicity_source(const std::string &multiplicity_source);
std::string multiplicity_source() const;
void set_multiplicity_destination(
const std::string &multiplicity_destination);
std::string multiplicity_destination() const;
void set_label(const std::string &label);
std::string label() const;
void set_scope(scope_t scope) noexcept;
scope_t scope() const noexcept;
friend bool operator==( friend bool operator==(
const class_relationship &l, const class_relationship &r); const class_relationship &l, const class_relationship &r);
private:
relationship_t type_{relationship_t::kAssociation};
std::string destination_;
std::string multiplicity_source_;
std::string multiplicity_destination_;
std::string label_;
scope_t scope_{scope_t::kNone};
}; };
struct class_template { struct class_template {

View File

@@ -304,15 +304,10 @@ void tu_visitor::process_enum_declaration(const cppast::cpp_enum &enm)
for (auto cur = enm.parent(); cur; cur = cur.value().parent()) { for (auto cur = enm.parent(); cur; cur = cur.value().parent()) {
// find nearest parent class, if any // find nearest parent class, if any
if (cur.value().kind() == cppast::cpp_entity_kind::class_t) { if (cur.value().kind() == cppast::cpp_entity_kind::class_t) {
class_relationship containment; e.add_relationship({relationship_t::kContainment,
containment.type = relationship_t::kContainment; cx::util::full_name(ctx.namespace_, cur.value())});
containment.destination =
cx::util::full_name(ctx.namespace_, cur.value());
containment.scope = scope_t::kNone;
e.add_relationship(std::move(containment));
LOG_DBG("Added relationship {} +-- {}", e.name(), LOG_DBG("Added containment relationship {} +-- {}", e.name());
containment.destination);
break; break;
} }
} }
@@ -518,12 +513,8 @@ void tu_visitor::process_class_declaration(const cppast::cpp_class &cls,
base_template_full_name); base_template_full_name);
// Add template specialization/instantiation // Add template specialization/instantiation
// relationship // relationship
class_relationship r; c.add_relationship({relationship_t::kInstantiation,
r.type = relationship_t::kInstantiation; base_template_full_name});
r.label = "";
r.destination = base_template_full_name;
r.scope = scope_t::kNone;
c.add_relationship(std::move(r));
} }
else { else {
LOG_WARN("No user data for base template {}", LOG_WARN("No user data for base template {}",
@@ -582,14 +573,10 @@ void tu_visitor::process_class_declaration(const cppast::cpp_class &cls,
for (auto cur = cls.parent(); cur; cur = cur.value().parent()) { for (auto cur = cls.parent(); cur; cur = cur.value().parent()) {
// find nearest parent class, if any // find nearest parent class, if any
if (cur.value().kind() == cppast::cpp_entity_kind::class_t) { if (cur.value().kind() == cppast::cpp_entity_kind::class_t) {
class_relationship containment; c.add_relationship({relationship_t::kContainment,
containment.type = relationship_t::kContainment; cx::util::full_name(ctx.namespace_, cur.value())});
containment.destination =
cx::util::full_name(ctx.namespace_, cur.value());
c.add_relationship(std::move(containment));
LOG_DBG("Added relationship {} +-- {}", c.full_name(), LOG_DBG("Added containment relationship {}", c.full_name());
containment.destination);
break; break;
} }
@@ -624,32 +611,33 @@ bool tu_visitor::process_field_with_template_instantiation(
// Infer the relationship of this field to the template // Infer the relationship of this field to the template
// instantiation // instantiation
class_relationship rr; relationship_t relationship_type{};
rr.destination = tinst.full_name();
if (mv.type().kind() == cppast::cpp_type_kind::pointer_t || if (mv.type().kind() == cppast::cpp_type_kind::pointer_t ||
mv.type().kind() == cppast::cpp_type_kind::reference_t) mv.type().kind() == cppast::cpp_type_kind::reference_t)
rr.type = relationship_t::kAssociation; relationship_type = relationship_t::kAssociation;
else else
rr.type = relationship_t::kAggregation; relationship_type = relationship_t::kAggregation;
rr.label = mv.name();
rr.scope = detail::cpp_access_specifier_to_scope(as); class_relationship rr{relationship_type, tinst.full_name(),
detail::cpp_access_specifier_to_scope(as), mv.name()};
rr.set_style(m.style_spec()); rr.set_style(m.style_spec());
// Process field decorators // Process field decorators
auto [decorator_rtype, decorator_rmult] = m.relationship(); auto [decorator_rtype, decorator_rmult] = m.relationship();
if (decorator_rtype != relationship_t::kNone) { if (decorator_rtype != relationship_t::kNone) {
rr.type = decorator_rtype; rr.set_type(decorator_rtype);
auto mult = util::split(decorator_rmult, ":"); auto mult = util::split(decorator_rmult, ":");
if (mult.size() == 2) { if (mult.size() == 2) {
rr.multiplicity_source = mult[0]; rr.set_multiplicity_source(mult[0]);
rr.multiplicity_destination = mult[1]; rr.set_multiplicity_destination(mult[1]);
} }
} }
if (ctx.config.should_include(tinst.name())) { if (ctx.config.should_include(tinst.name())) {
LOG_DBG("Adding field instantiation relationship {} {} {} : {}", LOG_DBG("Adding field instantiation relationship {} {} {} : {}",
rr.destination, model::class_diagram::to_string(rr.type), rr.destination(), model::class_diagram::to_string(rr.type()),
c.full_name(), rr.label); c.full_name(), rr.label());
c.add_relationship(std::move(rr)); c.add_relationship(std::move(rr));
@@ -710,26 +698,23 @@ void tu_visitor::process_field(const cppast::cpp_member_variable &mv, class_ &c,
for (const auto &[type, relationship_type] : relationships) { for (const auto &[type, relationship_type] : relationships) {
if (relationship_type != relationship_t::kNone) { if (relationship_type != relationship_t::kNone) {
class_relationship r; class_relationship r{
r.destination = type; relationship_type, type, m.scope(), m.name()};
r.type = relationship_type;
r.label = m.name();
r.scope = m.scope();
r.set_style(m.style_spec()); r.set_style(m.style_spec());
auto [decorator_rtype, decorator_rmult] = m.relationship(); auto [decorator_rtype, decorator_rmult] = m.relationship();
if (decorator_rtype != relationship_t::kNone) { if (decorator_rtype != relationship_t::kNone) {
r.type = decorator_rtype; r.set_type(decorator_rtype);
auto mult = util::split(decorator_rmult, ":"); auto mult = util::split(decorator_rmult, ":");
if (mult.size() == 2) { if (mult.size() == 2) {
r.multiplicity_source = mult[0]; r.set_multiplicity_source(mult[0]);
r.multiplicity_destination = mult[1]; r.set_multiplicity_destination(mult[1]);
} }
} }
LOG_DBG("Adding field relationship {} {} {} : {}", LOG_DBG("Adding field relationship {} {} {} : {}",
r.destination, model::class_diagram::to_string(r.type), r.destination(), model::class_diagram::to_string(r.type()),
c.full_name(), r.label); c.full_name(), r.label());
c.add_relationship(std::move(r)); c.add_relationship(std::move(r));
} }
@@ -949,14 +934,11 @@ void tu_visitor::process_function_parameter(
for (const auto &[type, relationship_type] : relationships) { for (const auto &[type, relationship_type] : relationships) {
if ((relationship_type != relationship_t::kNone) && if ((relationship_type != relationship_t::kNone) &&
(type != c.name())) { (type != c.name())) {
class_relationship r; class_relationship r{relationship_t::kDependency, type};
r.destination = type;
r.type = relationship_t::kDependency;
r.label = "";
LOG_DBG("Adding field relationship {} {} {} : {}", LOG_DBG("Adding field relationship {} {} {} : {}",
r.destination, model::class_diagram::to_string(r.type), r.destination(), model::class_diagram::to_string(r.type()),
c.full_name(), r.label); c.full_name(), r.label());
c.add_relationship(std::move(r)); c.add_relationship(std::move(r));
} }
@@ -1004,17 +986,15 @@ void tu_visitor::process_function_parameter(
"only adding reference to template {}", "only adding reference to template {}",
cx::util::full_name( cx::util::full_name(
cppast::remove_cv(t), ctx.entity_index, false)); cppast::remove_cv(t), ctx.entity_index, false));
class_relationship rr; class_relationship rr{relationship_t::kDependency,
rr.destination = cx::util::full_name( cx::util::full_name(
cppast::remove_cv(t), ctx.entity_index, false); cppast::remove_cv(t), ctx.entity_index, false)};
rr.type = relationship_t::kDependency;
rr.label = "";
LOG_DBG("Adding field template dependency relationship " LOG_DBG("Adding field template dependency relationship "
"{} {} {} " "{} {} {} "
": {}", ": {}",
rr.destination, rr.destination(),
model::class_diagram::to_string(rr.type), model::class_diagram::to_string(rr.type()),
c.full_name(), rr.label); c.full_name(), rr.label());
c.add_relationship(std::move(rr)); c.add_relationship(std::move(rr));
} }
else { else {
@@ -1022,16 +1002,14 @@ void tu_visitor::process_function_parameter(
class_ tinst = build_template_instantiation( class_ tinst = build_template_instantiation(
template_instantiation_type); template_instantiation_type);
class_relationship rr; class_relationship rr{
rr.destination = tinst.full_name(); relationship_t::kDependency, tinst.full_name()};
rr.type = relationship_t::kDependency;
rr.label = "";
LOG_DBG("Adding field dependency relationship {} {} {} " LOG_DBG("Adding field dependency relationship {} {} {} "
": {}", ": {}",
rr.destination, rr.destination(),
model::class_diagram::to_string(rr.type), model::class_diagram::to_string(rr.type()),
c.full_name(), rr.label); c.full_name(), rr.label());
c.add_relationship(std::move(rr)); c.add_relationship(std::move(rr));
@@ -1090,9 +1068,8 @@ void tu_visitor::process_friend(const cppast::cpp_friend &f, class_ &parent)
cppast::cpp_entity_kind::class_template_t)) cppast::cpp_entity_kind::class_template_t))
return; return;
class_relationship r; class_relationship r{
r.type = relationship_t::kFriendship; relationship_t::kFriendship, "", scope_t::kNone, "<<friend>>"};
r.label = "<<friend>>";
if (f.comment().has_value()) if (f.comment().has_value())
r.add_decorators(decorators::parse(f.comment().value())); r.add_decorators(decorators::parse(f.comment().value()));
@@ -1108,7 +1085,7 @@ void tu_visitor::process_friend(const cppast::cpp_friend &f, class_ &parent)
LOG_DBG("Type friend declaration {}", name); LOG_DBG("Type friend declaration {}", name);
r.destination = name; r.set_destination(name);
} }
else if (f.entity()) { else if (f.entity()) {
std::string name{}; std::string name{};
@@ -1144,7 +1121,7 @@ void tu_visitor::process_friend(const cppast::cpp_friend &f, class_ &parent)
if (!ctx.config.should_include(name)) if (!ctx.config.should_include(name))
return; return;
r.destination = name; r.set_destination(name);
} }
else { else {
LOG_DBG("Friend declaration points neither to type or entity."); LOG_DBG("Friend declaration points neither to type or entity.");
@@ -1216,7 +1193,7 @@ bool tu_visitor::find_relationships(const cppast::cpp_type &t_,
} }
} }
else if (t.kind() == cppast::cpp_type_kind::template_instantiation_t) { else if (t.kind() == cppast::cpp_type_kind::template_instantiation_t) {
class_relationship r; // class_relationship r;
auto &tinst = auto &tinst =
static_cast<const cppast::cpp_template_instantiation_type &>(t); static_cast<const cppast::cpp_template_instantiation_type &>(t);
@@ -1427,10 +1404,6 @@ class_ tu_visitor::build_template_instantiation(
const cppast::cpp_template_instantiation_type &>( const cppast::cpp_template_instantiation_type &>(
targ.type().value()); targ.type().value());
class_relationship tinst_dependency;
tinst_dependency.type = relationship_t::kDependency;
tinst_dependency.label = "";
std::string nnn{"empty"}; std::string nnn{"empty"};
if (parent) if (parent)
nnn = (*parent)->name(); nnn = (*parent)->name();
@@ -1441,7 +1414,8 @@ class_ tu_visitor::build_template_instantiation(
? std::make_optional(&tinst) ? std::make_optional(&tinst)
: parent); : parent);
tinst_dependency.destination = nested_tinst.full_name(); class_relationship tinst_dependency{
relationship_t::kDependency, nested_tinst.full_name()};
auto nested_tinst_full_name = nested_tinst.full_name(); auto nested_tinst_full_name = nested_tinst.full_name();
@@ -1452,7 +1426,7 @@ class_ tu_visitor::build_template_instantiation(
if (ctx.config.should_include(tinst.full_name(false))) { if (ctx.config.should_include(tinst.full_name(false))) {
LOG_DBG("Creating nested template dependency to template " LOG_DBG("Creating nested template dependency to template "
"instantiation {}, {} -> {}", "instantiation {}, {} -> {}",
fn, tinst.full_name(), tinst_dependency.destination); fn, tinst.full_name(), tinst_dependency.destination());
tinst.add_relationship(std::move(tinst_dependency)); tinst.add_relationship(std::move(tinst_dependency));
} }
@@ -1461,30 +1435,27 @@ class_ tu_visitor::build_template_instantiation(
"template " "template "
"instantiation {}, {} -> {}", "instantiation {}, {} -> {}",
fn, (*parent)->full_name(), fn, (*parent)->full_name(),
tinst_dependency.destination); tinst_dependency.destination());
(*parent)->add_relationship(std::move(tinst_dependency)); (*parent)->add_relationship(std::move(tinst_dependency));
} }
else { else {
LOG_DBG("No nested template dependency to template " LOG_DBG("No nested template dependency to template "
"instantiation: {}, {} -> {}", "instantiation: {}, {} -> {}",
fn, tinst.full_name(), tinst_dependency.destination); fn, tinst.full_name(), tinst_dependency.destination());
} }
} }
else if (targ.type().value().kind() == else if (targ.type().value().kind() ==
cppast::cpp_type_kind::user_defined_t) { cppast::cpp_type_kind::user_defined_t) {
class_relationship tinst_dependency; class_relationship tinst_dependency{relationship_t::kDependency,
tinst_dependency.type = relationship_t::kDependency; cx::util::full_name(
tinst_dependency.label = ""; cppast::remove_cv(
cx::util::unreferenced(targ.type().value())),
tinst_dependency.destination = cx::util::full_name( ctx.entity_index, false)};
cppast::remove_cv(
cx::util::unreferenced(targ.type().value())),
ctx.entity_index, false);
LOG_DBG("Creating nested template dependency to user defined " LOG_DBG("Creating nested template dependency to user defined "
"type {} -> {}", "type {} -> {}",
tinst.full_name(), tinst_dependency.destination); tinst.full_name(), tinst_dependency.destination());
if (ctx.config.should_include(fn)) { if (ctx.config.should_include(fn)) {
tinst.add_relationship(std::move(tinst_dependency)); tinst.add_relationship(std::move(tinst_dependency));
@@ -1541,23 +1512,21 @@ class_ tu_visitor::build_template_instantiation(
// Add instantiation relationship to primary template of this // Add instantiation relationship to primary template of this
// instantiation // instantiation
class_relationship r;
const auto &tt = cppast::remove_cv(cx::util::unreferenced(t)); const auto &tt = cppast::remove_cv(cx::util::unreferenced(t));
auto fn = cx::util::full_name(tt, ctx.entity_index, false); auto fn = cx::util::full_name(tt, ctx.entity_index, false);
fn = util::split(fn, "<")[0]; fn = util::split(fn, "<")[0];
std::string destination;
if (ctx.has_type_alias(fn)) { if (ctx.has_type_alias(fn)) {
// If this is a template alias - set the instantiation // If this is a template alias - set the instantiation
// relationship to the first alias target // relationship to the first alias target
r.destination = cppast::to_string(ctx.get_type_alias(fn).get()); destination = cppast::to_string(ctx.get_type_alias(fn).get());
} }
else { else {
// Otherwise point to the base template // Otherwise point to the base template
r.destination = tinst.base_template(); destination = tinst.base_template();
} }
r.type = relationship_t::kInstantiation; class_relationship r{relationship_t::kInstantiation, destination};
r.label = "";
r.scope = scope_t::kNone;
tinst.add_relationship(std::move(r)); tinst.add_relationship(std::move(r));
return tinst; return tinst;