diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.cc b/src/class_diagram/generators/plantuml/class_diagram_generator.cc index ff458769..b0922237 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.cc +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.cc @@ -184,6 +184,11 @@ void generator::generate(const class_ &c, std::ostream &ostr) const try { destination = r.destination(); + // TODO: Refactor destination to a namespace qualified entity + // name + if (util::starts_with(destination, std::string{"::"})) + destination = destination.substr(2, destination.size()); + LOG_DBG("=== Destination is: {}", destination); std::string puml_relation; @@ -263,6 +268,11 @@ void generator::generate_relationships( try { destination = r.destination(); + // TODO: Refactor destination to a namespace qualified entity + // name + if (util::starts_with(destination, std::string{"::"})) + destination = destination.substr(2, destination.size()); + LOG_DBG("=== Destination is: {}", destination); std::string puml_relation; @@ -402,7 +412,7 @@ void generator::generate(const package &p, std::ostream &ostr) const // Don't generate packages from namespaces filtered out by // using_namespace - if (!uns.starts_with(p.full_name(false))) { + if (!uns.starts_with({p.full_name(false)})) { ostr << "package [" << p.name() << "] "; ostr << "as " << p.alias(); @@ -440,7 +450,7 @@ void generator::generate(const package &p, std::ostream &ostr) const if (m_config.generate_packages()) { // Don't generate packages from namespaces filtered out by // using_namespace - if (!uns.starts_with(p.full_name(false))) { + if (!uns.starts_with({p.full_name(false)})) { ostr << "}" << '\n'; } } diff --git a/src/class_diagram/visitor/translation_unit_visitor.cc b/src/class_diagram/visitor/translation_unit_visitor.cc index 1573a2f8..f52f3544 100644 --- a/src/class_diagram/visitor/translation_unit_visitor.cc +++ b/src/class_diagram/visitor/translation_unit_visitor.cc @@ -594,12 +594,12 @@ void translation_unit_visitor::process_class_bases( { for (auto &base : cls.bases()) { class_parent cp; - auto base_ns = common::model::namespace_{ - cx::util::ns(base.type(), ctx.entity_index())}; + auto ns = cx::util::ns(base.type(), ctx.entity_index()); + common::model::namespace_ base_ns; + if(!ns.empty()) + base_ns = common::model::namespace_{ns}; base_ns = base_ns | common::model::namespace_{base.name()}.name(); - cp.set_name( - // base_ns.relative_to(ctx.config().using_namespace()).to_string()); - base_ns.to_string()); + cp.set_name(base_ns.to_string()); cp.is_virtual(base.is_virtual()); switch (base.access_specifier()) { @@ -758,7 +758,7 @@ bool translation_unit_visitor::process_field_with_template_instantiation( auto [decorator_rtype, decorator_rmult] = member.get_relationship(); if (decorator_rtype != relationship_t::kNone) { rr.set_type(decorator_rtype); - auto mult = util::split(decorator_rmult, ":"); + auto mult = util::split(decorator_rmult, ":", false); if (mult.size() == 2) { rr.set_multiplicity_source(mult[0]); rr.set_multiplicity_destination(mult[1]); @@ -811,6 +811,8 @@ bool translation_unit_visitor::add_nested_template_relationships( template_argument.find_nested_relationships(nested_relationships, relationship_type, [&d = ctx.diagram()](const std::string &full_name) { + if(full_name.empty()) + return false; auto [ns, name] = cx::util::split_ns(full_name); return d.should_include(ns, name); }); @@ -823,7 +825,7 @@ bool translation_unit_visitor::add_nested_template_relationships( nested_relationship.set_style(m.style_spec()); if (decorator_rtype != relationship_t::kNone) { nested_relationship.set_type(decorator_rtype); - auto mult = util::split(decorator_rmult, ":"); + auto mult = util::split(decorator_rmult, ":", false); if (mult.size() == 2) { nested_relationship.set_multiplicity_source(mult[0]); nested_relationship.set_multiplicity_destination(mult[1]); @@ -914,7 +916,7 @@ void translation_unit_visitor::process_field( auto [decorator_rtype, decorator_rmult] = m.get_relationship(); if (decorator_rtype != relationship_t::kNone) { r.set_type(decorator_rtype); - auto mult = util::split(decorator_rmult, ":"); + auto mult = util::split(decorator_rmult, ":", false); if (mult.size() == 2) { r.set_multiplicity_source(mult[0]); r.set_multiplicity_destination(mult[1]); diff --git a/src/common/model/path.h b/src/common/model/path.h index c447f384..912d66f5 100644 --- a/src/common/model/path.h +++ b/src/common/model/path.h @@ -31,7 +31,13 @@ public: path() = default; - path(const std::string &ns) { path_ = util::split(ns, Sep::value); } + explicit path(const std::string &ns) + { + if (ns.empty()) + return; + + path_ = util::split(ns, Sep::value); + } path(container_type::const_iterator begin, container_type::const_iterator end) @@ -49,16 +55,22 @@ public: path(std::initializer_list ns) { - if ((ns.size() == 1) && util::contains(*ns.begin(), Sep::value)) + if ((ns.size() == 1) && util::contains(*ns.begin(), Sep::value)) { path_ = util::split(*ns.begin(), Sep::value); + } + else if ((ns.size() == 1) && ns.begin()->empty()) { + } else path_ = ns; } explicit path(const std::vector &ns) { - if ((ns.size() == 1) && util::contains(*ns.begin(), Sep::value)) + if ((ns.size() == 1) && util::contains(*ns.begin(), Sep::value)) { path_ = util::split(*ns.begin(), Sep::value); + } + else if ((ns.size() == 1) && ns.begin()->empty()) { + } else path_ = ns; } diff --git a/src/common/model/source_file.h b/src/common/model/source_file.h index af34ff55..be99de07 100644 --- a/src/common/model/source_file.h +++ b/src/common/model/source_file.h @@ -52,7 +52,7 @@ public: source_file(const std::filesystem::path &p) { - set_path(p.parent_path().string()); + set_path({p.parent_path().string()}); set_name(p.filename()); is_absolute_ = p.is_absolute(); } diff --git a/src/config/config.cc b/src/config/config.cc index bbdeacb7..3b0a8457 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -215,10 +215,10 @@ void get_option(const Node &node, { if (node[option.name]) { if (node[option.name].Type() == NodeType::Scalar) - option.set(node[option.name].template as()); + option.set({node[option.name].template as()}); else if (node[option.name].Type() == NodeType::Sequence) - option.set( - node[option.name].template as>()[0]); + option.set({ + node[option.name].template as>()[0]}); else throw std::runtime_error("Invalid using_namespace value"); } @@ -406,7 +406,7 @@ template <> struct convert { auto namespace_list = node["namespaces"].as>(); for (const auto &ns : namespace_list) - rhs.namespaces.push_back(ns); + rhs.namespaces.push_back({ns}); } if (node["relationships"]) diff --git a/src/cx/util.cc b/src/cx/util.cc index 8cb0f785..1b069205 100644 --- a/src/cx/util.cc +++ b/src/cx/util.cc @@ -129,6 +129,8 @@ bool is_inside_class(const cppast::cpp_entity &e) std::pair split_ns( const std::string &full_name) { + assert(!full_name.empty()); + auto name_before_template = ::clanguml::util::split(full_name, "<")[0]; auto ns = common::model::namespace_{ ::clanguml::util::split(name_before_template, "::")}; diff --git a/src/package_diagram/generators/plantuml/package_diagram_generator.cc b/src/package_diagram/generators/plantuml/package_diagram_generator.cc index b99640c1..38c2bd55 100644 --- a/src/package_diagram/generators/plantuml/package_diagram_generator.cc +++ b/src/package_diagram/generators/plantuml/package_diagram_generator.cc @@ -67,7 +67,7 @@ void generator::generate(const package &p, std::ostream &ostr) const // Don't generate packages from namespaces filtered out by // using_namespace - if (!uns.starts_with(p.full_name(false))) { + if (!uns.starts_with({p.full_name(false)})) { ostr << "package [" << p.name() << "] "; ostr << "as " << p.alias(); @@ -89,7 +89,7 @@ void generator::generate(const package &p, std::ostream &ostr) const generate(dynamic_cast(*subpackage), ostr); } - if (!uns.starts_with(p.full_name(false))) { + if (!uns.starts_with({p.full_name(false)})) { ostr << "}" << '\n'; } diff --git a/src/util/util.cc b/src/util/util.cc index cefa989f..6e40d347 100644 --- a/src/util/util.cc +++ b/src/util/util.cc @@ -136,7 +136,8 @@ std::string rtrim(const std::string &s) std::string trim(const std::string &s) { return rtrim(ltrim(s)); } -std::vector split(std::string str, std::string_view delimiter) +std::vector split( + std::string str, std::string_view delimiter, bool skip_empty) { std::vector result; @@ -146,11 +147,13 @@ std::vector split(std::string str, std::string_view delimiter) while (str.size()) { auto index = str.find(delimiter); if (index != std::string::npos) { - result.push_back(str.substr(0, index)); + auto tok = str.substr(0, index); + if (!tok.empty() || !skip_empty) + result.push_back(std::move(tok)); str = str.substr(index + delimiter.size()); } else { - if (!str.empty()) + if (!str.empty() || !skip_empty) result.push_back(str); str = ""; } diff --git a/src/util/util.h b/src/util/util.h index b01e17f8..0c6cbe2d 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -83,10 +83,12 @@ std::string get_git_toplevel_dir(); * * @param str String to split * @param delimiter Delimiter string + * @param skip_empty Skip empty toks between delimiters if true * * @return Vector of string tokens. */ -std::vector split(std::string str, std::string_view delimiter); +std::vector split( + std::string str, std::string_view delimiter, bool skip_empty = true); std::string join( const std::vector &toks, std::string_view delimiter);