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::set<std::string> unique_relations;
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;
LOG_DBG("== Processing relationship {}", to_string(r.type));
LOG_DBG("== Processing relationship {}", to_string(r.type()));
std::stringstream relstr;
std::string destination;
try {
destination = r.destination;
destination = r.destination();
LOG_DBG("=== Destination is: {}", destination);
std::string puml_relation;
if (!r.multiplicity_source.empty())
puml_relation += "\"" + r.multiplicity_source + "\" ";
if (!r.multiplicity_source().empty())
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())
puml_relation += " \"" + r.multiplicity_destination + "\"";
if (!r.multiplicity_destination().empty())
puml_relation += " \"" + r.multiplicity_destination() + "\"";
relstr << m_model.to_alias(ns_relative(uns, c.full_name())) << " "
<< puml_relation << " "
<< m_model.to_alias(ns_relative(uns, destination));
if (!r.label.empty()) {
relstr << " : " << to_string(r.scope) << r.label;
rendered_relations.emplace(r.label);
if (!r.label().empty()) {
relstr << " : " << to_string(r.scope()) << r.label();
rendered_relations.emplace(r.label());
}
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) {
LOG_ERROR("=== Skipping {} relation from {} to {} due "
"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';
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;
std::string destination;
std::stringstream relstr;
try {
destination = r.destination;
destination = r.destination();
relstr << m_model.to_alias(
ns_relative(m_config.using_namespace, e.name()))
<< " " << to_string(r.type) << " "
<< " " << to_string(r.type()) << " "
<< m_model.to_alias(
ns_relative(m_config.using_namespace, destination));
if (!r.label.empty())
relstr << " : " << r.label;
if (!r.label().empty())
relstr << " : " << r.label();
relstr << '\n';
@@ -328,7 +328,7 @@ void generator::generate(const enum_ &e, std::ostream &ostr) const
catch (error::uml_alias_missing &ex) {
LOG_ERROR("Skipping {} relation from {} to {} due "
"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)
{
if (cr.destination.empty()) {
if (cr.destination().empty()) {
LOG_WARN("Skipping relationship '{}' - {} - '{}' due empty "
"destination",
cr.destination, to_string(cr.type), full_name(true));
cr.destination(), to_string(cr.type()), full_name(true));
return;
}
@@ -300,11 +300,67 @@ class_parent::access_t class_parent::access() const { return access_; }
//
// 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)
{
return l.type == r.type && l.destination == r.destination &&
l.label == r.label;
return l.type() == r.type() && l.destination() == r.destination() &&
l.label() == r.label();
}
//

View File

@@ -185,16 +185,44 @@ private:
access_t access_;
};
struct class_relationship : public decorated_element, public stylable_element {
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};
class class_relationship : public decorated_element, public stylable_element {
public:
class_relationship(relationship_t type, const std::string &destination,
scope_t scope = scope_t::kNone, const std::string &label = "",
const std::string &multiplicity_source = "",
const std::string &multiplicity_destination = "");
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==(
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 {

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()) {
// find nearest parent class, if any
if (cur.value().kind() == cppast::cpp_entity_kind::class_t) {
class_relationship containment;
containment.type = relationship_t::kContainment;
containment.destination =
cx::util::full_name(ctx.namespace_, cur.value());
containment.scope = scope_t::kNone;
e.add_relationship(std::move(containment));
e.add_relationship({relationship_t::kContainment,
cx::util::full_name(ctx.namespace_, cur.value())});
LOG_DBG("Added relationship {} +-- {}", e.name(),
containment.destination);
LOG_DBG("Added containment relationship {} +-- {}", e.name());
break;
}
}
@@ -518,12 +513,8 @@ void tu_visitor::process_class_declaration(const cppast::cpp_class &cls,
base_template_full_name);
// Add template specialization/instantiation
// relationship
class_relationship r;
r.type = relationship_t::kInstantiation;
r.label = "";
r.destination = base_template_full_name;
r.scope = scope_t::kNone;
c.add_relationship(std::move(r));
c.add_relationship({relationship_t::kInstantiation,
base_template_full_name});
}
else {
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()) {
// find nearest parent class, if any
if (cur.value().kind() == cppast::cpp_entity_kind::class_t) {
class_relationship containment;
containment.type = relationship_t::kContainment;
containment.destination =
cx::util::full_name(ctx.namespace_, cur.value());
c.add_relationship(std::move(containment));
c.add_relationship({relationship_t::kContainment,
cx::util::full_name(ctx.namespace_, cur.value())});
LOG_DBG("Added relationship {} +-- {}", c.full_name(),
containment.destination);
LOG_DBG("Added containment relationship {}", c.full_name());
break;
}
@@ -624,32 +611,33 @@ bool tu_visitor::process_field_with_template_instantiation(
// Infer the relationship of this field to the template
// instantiation
class_relationship rr;
rr.destination = tinst.full_name();
relationship_t relationship_type{};
if (mv.type().kind() == cppast::cpp_type_kind::pointer_t ||
mv.type().kind() == cppast::cpp_type_kind::reference_t)
rr.type = relationship_t::kAssociation;
relationship_type = relationship_t::kAssociation;
else
rr.type = relationship_t::kAggregation;
rr.label = mv.name();
rr.scope = detail::cpp_access_specifier_to_scope(as);
relationship_type = relationship_t::kAggregation;
class_relationship rr{relationship_type, tinst.full_name(),
detail::cpp_access_specifier_to_scope(as), mv.name()};
rr.set_style(m.style_spec());
// Process field decorators
auto [decorator_rtype, decorator_rmult] = m.relationship();
if (decorator_rtype != relationship_t::kNone) {
rr.type = decorator_rtype;
rr.set_type(decorator_rtype);
auto mult = util::split(decorator_rmult, ":");
if (mult.size() == 2) {
rr.multiplicity_source = mult[0];
rr.multiplicity_destination = mult[1];
rr.set_multiplicity_source(mult[0]);
rr.set_multiplicity_destination(mult[1]);
}
}
if (ctx.config.should_include(tinst.name())) {
LOG_DBG("Adding field instantiation relationship {} {} {} : {}",
rr.destination, model::class_diagram::to_string(rr.type),
c.full_name(), rr.label);
rr.destination(), model::class_diagram::to_string(rr.type()),
c.full_name(), rr.label());
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) {
if (relationship_type != relationship_t::kNone) {
class_relationship r;
r.destination = type;
r.type = relationship_type;
r.label = m.name();
r.scope = m.scope();
class_relationship r{
relationship_type, type, m.scope(), m.name()};
r.set_style(m.style_spec());
auto [decorator_rtype, decorator_rmult] = m.relationship();
if (decorator_rtype != relationship_t::kNone) {
r.type = decorator_rtype;
r.set_type(decorator_rtype);
auto mult = util::split(decorator_rmult, ":");
if (mult.size() == 2) {
r.multiplicity_source = mult[0];
r.multiplicity_destination = mult[1];
r.set_multiplicity_source(mult[0]);
r.set_multiplicity_destination(mult[1]);
}
}
LOG_DBG("Adding field relationship {} {} {} : {}",
r.destination, model::class_diagram::to_string(r.type),
c.full_name(), r.label);
r.destination(), model::class_diagram::to_string(r.type()),
c.full_name(), r.label());
c.add_relationship(std::move(r));
}
@@ -949,14 +934,11 @@ void tu_visitor::process_function_parameter(
for (const auto &[type, relationship_type] : relationships) {
if ((relationship_type != relationship_t::kNone) &&
(type != c.name())) {
class_relationship r;
r.destination = type;
r.type = relationship_t::kDependency;
r.label = "";
class_relationship r{relationship_t::kDependency, type};
LOG_DBG("Adding field relationship {} {} {} : {}",
r.destination, model::class_diagram::to_string(r.type),
c.full_name(), r.label);
r.destination(), model::class_diagram::to_string(r.type()),
c.full_name(), r.label());
c.add_relationship(std::move(r));
}
@@ -1004,17 +986,15 @@ void tu_visitor::process_function_parameter(
"only adding reference to template {}",
cx::util::full_name(
cppast::remove_cv(t), ctx.entity_index, false));
class_relationship rr;
rr.destination = cx::util::full_name(
cppast::remove_cv(t), ctx.entity_index, false);
rr.type = relationship_t::kDependency;
rr.label = "";
class_relationship rr{relationship_t::kDependency,
cx::util::full_name(
cppast::remove_cv(t), ctx.entity_index, false)};
LOG_DBG("Adding field template dependency relationship "
"{} {} {} "
": {}",
rr.destination,
model::class_diagram::to_string(rr.type),
c.full_name(), rr.label);
rr.destination(),
model::class_diagram::to_string(rr.type()),
c.full_name(), rr.label());
c.add_relationship(std::move(rr));
}
else {
@@ -1022,16 +1002,14 @@ void tu_visitor::process_function_parameter(
class_ tinst = build_template_instantiation(
template_instantiation_type);
class_relationship rr;
rr.destination = tinst.full_name();
rr.type = relationship_t::kDependency;
rr.label = "";
class_relationship rr{
relationship_t::kDependency, tinst.full_name()};
LOG_DBG("Adding field dependency relationship {} {} {} "
": {}",
rr.destination,
model::class_diagram::to_string(rr.type),
c.full_name(), rr.label);
rr.destination(),
model::class_diagram::to_string(rr.type()),
c.full_name(), rr.label());
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))
return;
class_relationship r;
r.type = relationship_t::kFriendship;
r.label = "<<friend>>";
class_relationship r{
relationship_t::kFriendship, "", scope_t::kNone, "<<friend>>"};
if (f.comment().has_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);
r.destination = name;
r.set_destination(name);
}
else if (f.entity()) {
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))
return;
r.destination = name;
r.set_destination(name);
}
else {
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) {
class_relationship r;
// class_relationship r;
auto &tinst =
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 &>(
targ.type().value());
class_relationship tinst_dependency;
tinst_dependency.type = relationship_t::kDependency;
tinst_dependency.label = "";
std::string nnn{"empty"};
if (parent)
nnn = (*parent)->name();
@@ -1441,7 +1414,8 @@ class_ tu_visitor::build_template_instantiation(
? std::make_optional(&tinst)
: 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();
@@ -1452,7 +1426,7 @@ class_ tu_visitor::build_template_instantiation(
if (ctx.config.should_include(tinst.full_name(false))) {
LOG_DBG("Creating nested template dependency to template "
"instantiation {}, {} -> {}",
fn, tinst.full_name(), tinst_dependency.destination);
fn, tinst.full_name(), tinst_dependency.destination());
tinst.add_relationship(std::move(tinst_dependency));
}
@@ -1461,30 +1435,27 @@ class_ tu_visitor::build_template_instantiation(
"template "
"instantiation {}, {} -> {}",
fn, (*parent)->full_name(),
tinst_dependency.destination);
tinst_dependency.destination());
(*parent)->add_relationship(std::move(tinst_dependency));
}
else {
LOG_DBG("No nested template dependency to template "
"instantiation: {}, {} -> {}",
fn, tinst.full_name(), tinst_dependency.destination);
fn, tinst.full_name(), tinst_dependency.destination());
}
}
else if (targ.type().value().kind() ==
cppast::cpp_type_kind::user_defined_t) {
class_relationship tinst_dependency;
tinst_dependency.type = relationship_t::kDependency;
tinst_dependency.label = "";
tinst_dependency.destination = cx::util::full_name(
cppast::remove_cv(
cx::util::unreferenced(targ.type().value())),
ctx.entity_index, false);
class_relationship tinst_dependency{relationship_t::kDependency,
cx::util::full_name(
cppast::remove_cv(
cx::util::unreferenced(targ.type().value())),
ctx.entity_index, false)};
LOG_DBG("Creating nested template dependency to user defined "
"type {} -> {}",
tinst.full_name(), tinst_dependency.destination);
tinst.full_name(), tinst_dependency.destination());
if (ctx.config.should_include(fn)) {
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
// instantiation
class_relationship r;
const auto &tt = cppast::remove_cv(cx::util::unreferenced(t));
auto fn = cx::util::full_name(tt, ctx.entity_index, false);
fn = util::split(fn, "<")[0];
std::string destination;
if (ctx.has_type_alias(fn)) {
// If this is a template alias - set the instantiation
// 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 {
// Otherwise point to the base template
r.destination = tinst.base_template();
destination = tinst.base_template();
}
r.type = relationship_t::kInstantiation;
r.label = "";
r.scope = scope_t::kNone;
class_relationship r{relationship_t::kInstantiation, destination};
tinst.add_relationship(std::move(r));
return tinst;