Initial refactor of namespace handling

This commit is contained in:
Bartek Kryza
2022-03-04 23:38:18 +01:00
parent bee20e7f26
commit a67b459437
40 changed files with 620 additions and 201 deletions

View File

@@ -118,7 +118,7 @@ void generator::generate(
if (m.is_defaulted()) if (m.is_defaulted())
ostr << " = default"; ostr << " = default";
ostr << " : " << ns_relative(uns, type); ostr << " : " << uns.relative(type);
ostr << '\n'; ostr << '\n';
} }
@@ -154,9 +154,9 @@ void generator::generate(
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(uns.relative(c.full_name())) << " "
<< puml_relation << " " << puml_relation << " "
<< m_model.to_alias(ns_relative(uns, destination)); << m_model.to_alias(uns.relative(destination));
if (!r.label().empty()) { if (!r.label().empty()) {
relstr << " : " << plantuml_common::to_plantuml(r.scope()) relstr << " : " << plantuml_common::to_plantuml(r.scope())
@@ -197,7 +197,7 @@ void generator::generate(
ostr << "{static} "; ostr << "{static} ";
ostr << plantuml_common::to_plantuml(m.scope()) << m.name() << " : " ostr << plantuml_common::to_plantuml(m.scope()) << m.name() << " : "
<< ns_relative(uns, m.type()) << '\n'; << uns.relative(m.type()) << '\n';
} }
ostr << "}" << '\n'; ostr << "}" << '\n';
@@ -206,10 +206,8 @@ void generator::generate(
for (const auto &b : c.parents()) { for (const auto &b : c.parents()) {
std::stringstream relstr; std::stringstream relstr;
try { try {
relstr << m_model.to_alias(ns_relative(uns, b.name())) relstr << m_model.to_alias(uns.relative(b.name())) << " <|-- "
<< " <|-- " << m_model.to_alias(uns.relative(c.full_name())) << '\n';
<< m_model.to_alias(ns_relative(uns, c.full_name()))
<< '\n';
all_relations_str << relstr.str(); all_relations_str << relstr.str();
} }
catch (error::uml_alias_missing &e) { catch (error::uml_alias_missing &e) {
@@ -253,13 +251,13 @@ void generator::generate(
destination = r.destination(); destination = r.destination();
relstr << m_model.to_alias( relstr << m_model.to_alias(
ns_relative(m_config.using_namespace(), e.name())) m_config.using_namespace().relative(e.name()))
<< " " << " "
<< clanguml::common::generators::plantuml::to_plantuml( << clanguml::common::generators::plantuml::to_plantuml(
r.type(), r.style()) r.type(), r.style())
<< " " << " "
<< m_model.to_alias( << m_model.to_alias(
ns_relative(m_config.using_namespace(), destination)); m_config.using_namespace().relative(destination));
if (!r.label().empty()) if (!r.label().empty())
relstr << " : " << r.label(); relstr << " : " << r.label();

View File

@@ -24,8 +24,8 @@
namespace clanguml::class_diagram::model { namespace clanguml::class_diagram::model {
class_::class_(const std::vector<std::string> &using_namespaces) class_::class_(const common::model::namespace_ &using_namespace)
: element{using_namespaces} : element{using_namespace}
{ {
} }
@@ -112,10 +112,12 @@ std::string class_::full_name_no_ns() const
std::string class_::full_name(bool relative) const std::string class_::full_name(bool relative) const
{ {
using namespace clanguml::util; using namespace clanguml::util;
using clanguml::common::model::namespace_;
std::ostringstream ostr; std::ostringstream ostr;
if (relative && starts_with(get_namespace(), using_namespace())) // if (relative && starts_with(get_namespace(), using_namespace()))
ostr << ns_relative(using_namespace(), name_and_ns()); if (relative)
ostr << namespace_{name()}.relative_to(using_namespace()).to_string();
else else
ostr << name_and_ns(); ostr << name_and_ns();
@@ -126,6 +128,8 @@ std::string class_::full_name(bool relative) const
std::ostringstream &class_::render_template_params( std::ostringstream &class_::render_template_params(
std::ostringstream &ostr) const std::ostringstream &ostr) const
{ {
using clanguml::common::model::namespace_;
if (!templates_.empty()) { if (!templates_.empty()) {
std::vector<std::string> tnames; std::vector<std::string> tnames;
std::transform(templates_.cbegin(), templates_.cend(), std::transform(templates_.cbegin(), templates_.cend(),
@@ -133,12 +137,14 @@ std::ostringstream &class_::render_template_params(
std::vector<std::string> res; std::vector<std::string> res;
if (!tmplt.type().empty()) if (!tmplt.type().empty())
res.push_back( res.push_back(namespace_{tmplt.type()}
util::ns_relative(using_namespace(), tmplt.type())); .relative_to(using_namespace())
.to_string());
if (!tmplt.name().empty()) if (!tmplt.name().empty())
res.push_back( res.push_back(namespace_{tmplt.name()}
util::ns_relative(using_namespace(), tmplt.name())); .relative_to(using_namespace())
.to_string());
if (!tmplt.default_value().empty()) { if (!tmplt.default_value().empty()) {
res.push_back("="); res.push_back("=");

View File

@@ -34,7 +34,7 @@ namespace clanguml::class_diagram::model {
class class_ : public common::model::element, class class_ : public common::model::element,
public common::model::stylable_element { public common::model::stylable_element {
public: public:
class_(const std::vector<std::string> &using_namespaces); class_(const common::model::namespace_ &using_namespace);
class_(const class_ &) = delete; class_(const class_ &) = delete;
class_(class_ &&) noexcept = delete; class_(class_ &&) noexcept = delete;

View File

@@ -82,7 +82,7 @@ void diagram::add_class(std::unique_ptr<class_> &&c)
auto ns = c->get_relative_namespace(); auto ns = c->get_relative_namespace();
auto name = c->name(); auto name = c->name();
add_element(ns, std::move(c)); add_element(ns, std::move(c));
ns.push_back(name); ns |= name;
const auto ccc = get_element<class_>(ns); const auto ccc = get_element<class_>(ns);
assert(ccc.value().name() == name); assert(ccc.value().name() == name);
} }

View File

@@ -24,8 +24,8 @@
namespace clanguml::class_diagram::model { namespace clanguml::class_diagram::model {
enum_::enum_(const std::vector<std::string> &using_namespaces) enum_::enum_(const common::model::namespace_ &using_namespace)
: element{using_namespaces} : element{using_namespace}
{ {
} }
@@ -37,10 +37,11 @@ bool operator==(const enum_ &l, const enum_ &r)
std::string enum_::full_name(bool relative) const std::string enum_::full_name(bool relative) const
{ {
using namespace clanguml::util; using namespace clanguml::util;
using clanguml::common::model::namespace_;
std::ostringstream ostr; std::ostringstream ostr;
if (relative) if (relative)
ostr << ns_relative(using_namespace(), name()); ostr << namespace_{name()}.relative_to(using_namespace()).to_string();
else else
ostr << name(); ostr << name();

View File

@@ -27,7 +27,7 @@ namespace clanguml::class_diagram::model {
class enum_ : public common::model::element, class enum_ : public common::model::element,
public common::model::stylable_element { public common::model::stylable_element {
public: public:
enum_(const std::vector<std::string> &using_namespaces); enum_(const common::model::namespace_ &using_namespaces);
enum_(const enum_ &) = delete; enum_(const enum_ &) = delete;
enum_(enum_ &&) = default; enum_(enum_ &&) = default;

View File

@@ -38,14 +38,16 @@ void method_parameter::set_default_value(const std::string &value)
std::string method_parameter::default_value() const { return default_value_; } std::string method_parameter::default_value() const { return default_value_; }
std::string method_parameter::to_string( std::string method_parameter::to_string(
const std::vector<std::string> &using_namespaces) const const common::model::namespace_ &using_namespace) const
{ {
using namespace clanguml::util; using namespace clanguml::util;
auto t = ns_relative(using_namespaces, type()); auto type_ns = common::model::namespace_{type()}
.relative_to(using_namespace)
.to_string();
if (default_value().empty()) if (default_value().empty())
return fmt::format("{} {}", t, name()); return fmt::format("{} {}", type_ns, name());
return fmt::format("{} {} = {}", t, name(), default_value()); return fmt::format("{} {} = {}", type_ns, name(), default_value());
} }
} }

View File

@@ -18,6 +18,7 @@
#pragma once #pragma once
#include "common/model/decorated_element.h" #include "common/model/decorated_element.h"
#include "common/model/namespace.h"
#include <string> #include <string>
#include <vector> #include <vector>
@@ -36,7 +37,7 @@ public:
std::string default_value() const; std::string default_value() const;
std::string to_string( std::string to_string(
const std::vector<std::string> &using_namespaces) const; const common::model::namespace_ &using_namespaces) const;
private: private:
std::string type_; std::string type_;

View File

@@ -154,14 +154,14 @@ translation_unit_context::get_type_alias_template(
void translation_unit_context::push_namespace(const std::string &ns) void translation_unit_context::push_namespace(const std::string &ns)
{ {
namespace_.push_back(ns); ns_ |= ns;
} }
void translation_unit_context::pop_namespace() { namespace_.pop_back(); } void translation_unit_context::pop_namespace() { ns_.pop_back(); }
const std::vector<std::string> &translation_unit_context::get_namespace() const const common::model::namespace_ &translation_unit_context::get_namespace() const
{ {
return namespace_; return ns_;
} }
const cppast::cpp_entity_index &translation_unit_context::entity_index() const const cppast::cpp_entity_index &translation_unit_context::entity_index() const

View File

@@ -66,7 +66,7 @@ public:
void pop_namespace(); void pop_namespace();
const std::vector<std::string> &get_namespace() const; const common::model::namespace_ &get_namespace() const;
const cppast::cpp_entity_index &entity_index() const; const cppast::cpp_entity_index &entity_index() const;
@@ -80,7 +80,7 @@ public:
private: private:
// Current visitor namespace // Current visitor namespace
std::vector<std::string> namespace_; common::model::namespace_ ns_;
// Reference to the cppast entity index // Reference to the cppast entity index
cppast::cpp_entity_index &entity_index_; cppast::cpp_entity_index &entity_index_;

View File

@@ -200,7 +200,7 @@ void translation_unit_visitor::process_type_alias_template(
cx::util::full_name(ctx.get_namespace(), at), cx::util::full_name(ctx.get_namespace(), at),
type_safe::ref(at.type_alias().underlying_type())); type_safe::ref(at.type_alias().underlying_type()));
if (ctx.config().should_include(tinst->get_namespace(), tinst->name())) if (ctx.config().should_include(tinst->get_namespace() | tinst->name()))
ctx.diagram().add_class(std::move(tinst)); ctx.diagram().add_class(std::move(tinst));
} }
} }
@@ -222,15 +222,14 @@ void translation_unit_visitor::process_type_alias(
void translation_unit_visitor::process_namespace( void translation_unit_visitor::process_namespace(
const cppast::cpp_entity &e, const cppast::cpp_namespace &ns_declaration) const cppast::cpp_entity &e, const cppast::cpp_namespace &ns_declaration)
{ {
std::vector<std::string> package_parent = ctx.get_namespace(); auto package_parent = ctx.get_namespace();
auto package_path = package_parent; auto package_path = package_parent | e.name();
package_path.push_back(e.name());
auto usn = util::split(ctx.config().using_namespace()[0], "::"); auto usn = ctx.config().using_namespace();
if (ctx.config().should_include_package(util::join(package_path, "::"))) { if (ctx.config().should_include_package(package_path)) {
auto p = std::make_unique<common::model::package>(usn); auto p = std::make_unique<common::model::package>(usn);
util::remove_prefix(package_path, usn); package_path = package_path.relative_to(usn);
p->set_name(e.name()); p->set_name(e.name());
p->set_namespace(package_parent); p->set_namespace(package_parent);
@@ -267,8 +266,7 @@ void translation_unit_visitor::process_enum_declaration(
return; return;
} }
auto e_ptr = std::make_unique<enum_>( auto e_ptr = std::make_unique<enum_>(ctx.config().using_namespace());
util::split(ctx.config().using_namespace()[0], "::"));
auto &e = *e_ptr; auto &e = *e_ptr;
e.set_name(enm.name()); e.set_name(enm.name());
e.set_namespace(ctx.get_namespace()); e.set_namespace(ctx.get_namespace());
@@ -312,8 +310,7 @@ void translation_unit_visitor::process_class_declaration(
const cppast::cpp_class &cls, const cppast::cpp_class &cls,
type_safe::optional_ref<const cppast::cpp_template_specialization> tspec) type_safe::optional_ref<const cppast::cpp_template_specialization> tspec)
{ {
auto c_ptr = std::make_unique<class_>( auto c_ptr = std::make_unique<class_>(ctx.config().using_namespace());
util::split(ctx.config().using_namespace()[0], "::"));
auto &c = *c_ptr; auto &c = *c_ptr;
c.is_struct(cls.class_kind() == cppast::cpp_class_kind::struct_t); c.is_struct(cls.class_kind() == cppast::cpp_class_kind::struct_t);
// c.set_name(cx::util::full_name(ctx.get_namespace(), cls)); // c.set_name(cx::util::full_name(ctx.get_namespace(), cls));
@@ -1275,8 +1272,7 @@ bool translation_unit_visitor::find_relationships_in_template_instantiation(
const auto [ns, base_name] = cx::util::split_ns(fn); const auto [ns, base_name] = cx::util::split_ns(fn);
auto ns_and_name = ns; auto ns_and_name = ns | base_name;
ns_and_name.push_back(base_name);
auto full_name = fmt::format("{}", fmt::join(ns_and_name, "::")); auto full_name = fmt::format("{}", fmt::join(ns_and_name, "::"));
@@ -1403,8 +1399,7 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
std::optional<clanguml::class_diagram::model::class_ *> parent) std::optional<clanguml::class_diagram::model::class_ *> parent)
{ {
// Create class_ instance to hold the template instantiation // Create class_ instance to hold the template instantiation
auto tinst_ptr = std::make_unique<class_>( auto tinst_ptr = std::make_unique<class_>(ctx.config().using_namespace());
util::split(ctx.config().using_namespace()[0], "::"));
auto &tinst = *tinst_ptr; auto &tinst = *tinst_ptr;
std::string full_template_name; std::string full_template_name;
@@ -1430,7 +1425,7 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
// Extract namespace from base template name // Extract namespace from base template name
const auto [ns, name] = cx::util::split_ns(tinst_full_name); const auto [ns, name] = cx::util::split_ns(tinst_full_name);
tinst.set_name(name); tinst.set_name(name);
if (ns.empty()) if (ns.is_empty())
tinst.set_namespace(ctx.get_namespace()); tinst.set_namespace(ctx.get_namespace());
else else
tinst.set_namespace(ns); tinst.set_namespace(ns);

View File

@@ -83,11 +83,10 @@ void generator<C, D>::generate_config_layout_hints(std::ostream &ostr) const
for (const auto &hint : hints) { for (const auto &hint : hints) {
std::stringstream hint_str; std::stringstream hint_str;
try { try {
hint_str << m_model.to_alias(ns_relative(uns, entity)) hint_str << m_model.to_alias(uns.relative(entity))
<< " -[hidden]" << " -[hidden]"
<< clanguml::config::to_string(hint.hint) << "- " << clanguml::config::to_string(hint.hint) << "- "
<< m_model.to_alias(ns_relative(uns, hint.entity)) << m_model.to_alias(uns.relative(hint.entity)) << '\n';
<< '\n';
ostr << hint_str.str(); ostr << hint_str.str();
} }
catch (clanguml::error::uml_alias_missing &e) { catch (clanguml::error::uml_alias_missing &e) {
@@ -103,12 +102,14 @@ template <typename C, typename D>
void generator<C, D>::generate_plantuml_directives( void generator<C, D>::generate_plantuml_directives(
std::ostream &ostr, const std::vector<std::string> &directives) const std::ostream &ostr, const std::vector<std::string> &directives) const
{ {
using common::model::namespace_;
for (const auto &b : directives) { for (const auto &b : directives) {
std::string note{b}; std::string note{b};
std::tuple<std::string, size_t, size_t> alias_match; std::tuple<std::string, size_t, size_t> alias_match;
while (util::find_element_alias(note, alias_match)) { while (util::find_element_alias(note, alias_match)) {
auto alias = m_model.to_alias(util::ns_relative( auto alias = m_model.to_alias(
m_config.using_namespace(), std::get<0>(alias_match))); m_config.using_namespace().relative(std::get<0>(alias_match)));
note.replace( note.replace(
std::get<1>(alias_match), std::get<2>(alias_match), alias); std::get<1>(alias_match), std::get<2>(alias_match), alias);
} }

View File

@@ -26,12 +26,10 @@ namespace clanguml::common::model {
std::atomic_uint64_t element::m_nextId = 1; std::atomic_uint64_t element::m_nextId = 1;
element::element(const std::vector<std::string> &using_namespaces) element::element(const namespace_ &using_namespace)
: using_namespace_{using_namespaces} : using_namespace_{using_namespace}
, m_id{m_nextId++} , m_id{m_nextId++}
{ {
for (const auto &n : using_namespace_)
assert(!util::contains(n, "::"));
} }
std::string element::alias() const { return fmt::format("C_{:010}", m_id); } std::string element::alias() const { return fmt::format("C_{:010}", m_id); }
@@ -59,18 +57,12 @@ void element::add_relationship(relationship &&cr)
relationships_.emplace_back(std::move(cr)); relationships_.emplace_back(std::move(cr));
} }
void element::set_using_namespaces(const std::vector<std::string> &un) void element::set_using_namespaces(const namespace_ &un)
{ {
for (const auto &n : un)
assert(!util::contains(n, "::"));
using_namespace_ = un; using_namespace_ = un;
} }
const std::vector<std::string> &element::using_namespace() const const namespace_ &element::using_namespace() const { return ns_; }
{
return using_namespace_;
}
std::vector<relationship> &element::relationships() { return relationships_; } std::vector<relationship> &element::relationships() { return relationships_; }
@@ -88,9 +80,8 @@ bool operator==(const element &l, const element &r)
std::ostream &operator<<(std::ostream &out, const element &rhs) std::ostream &operator<<(std::ostream &out, const element &rhs)
{ {
out << "(" << rhs.name() << ", ns=[" out << "(" << rhs.name() << ", ns=[" << rhs.get_namespace().to_string()
<< util::join(rhs.get_namespace(), "::") << "], full_name=[" << "], full_name=[" << rhs.full_name(true) << "])";
<< rhs.full_name(true) << "])";
return out; return out;
} }

View File

@@ -18,6 +18,7 @@
#pragma once #pragma once
#include "decorated_element.h" #include "decorated_element.h"
#include "namespace.h"
#include "relationship.h" #include "relationship.h"
#include "util/util.h" #include "util/util.h"
@@ -30,7 +31,7 @@ namespace clanguml::common::model {
class element : public decorated_element { class element : public decorated_element {
public: public:
element(const std::vector<std::string> &using_namespaces); element(const namespace_ &using_namespace);
virtual ~element() = default; virtual ~element() = default;
@@ -42,27 +43,24 @@ public:
std::string name_and_ns() const std::string name_and_ns() const
{ {
auto ns = namespace_; auto ns = ns_ | name();
ns.push_back(name()); return ns.to_string();
return util::join(ns, "::");
} }
void set_namespace(const std::vector<std::string> &ns) { namespace_ = ns; } void set_namespace(const namespace_ &ns) { ns_ = ns; }
std::vector<std::string> get_namespace() const { return namespace_; } namespace_ get_namespace() const { return ns_; }
std::vector<std::string> get_relative_namespace() const namespace_ get_relative_namespace() const
{ {
auto relative_ns = namespace_; return ns_.relative_to(using_namespace_);
util::remove_prefix(relative_ns, using_namespace_);
return relative_ns;
} }
virtual std::string full_name(bool relative) const { return name(); } virtual std::string full_name(bool relative) const { return name(); }
void set_using_namespaces(const std::vector<std::string> &un); void set_using_namespaces(const namespace_ &un);
const std::vector<std::string> &using_namespace() const; const namespace_ &using_namespace() const;
std::vector<relationship> &relationships(); std::vector<relationship> &relationships();
@@ -81,8 +79,8 @@ protected:
private: private:
std::string name_; std::string name_;
std::vector<std::string> namespace_; namespace_ ns_;
std::vector<std::string> using_namespace_; namespace_ using_namespace_;
std::vector<relationship> relationships_; std::vector<relationship> relationships_;
static std::atomic_uint64_t m_nextId; static std::atomic_uint64_t m_nextId;

View File

@@ -0,0 +1,213 @@
/**
* src/common/model/namespace.h
*
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "namespace.h"
#include "util/util.h"
namespace clanguml::common::model {
namespace_::namespace_(std::initializer_list<std::string> ns)
{
if ((ns.size() == 1) && util::contains(*ns.begin(), "::"))
namespace_path_ = util::split(*ns.begin(), "::");
else
namespace_path_ = ns;
}
namespace_::namespace_(const std::vector<std::string> &ns)
{
if ((ns.size() == 1) && util::contains(*ns.begin(), "::"))
namespace_path_ = util::split(*ns.begin(), "::");
else
namespace_path_ = ns;
}
namespace_::namespace_(const std::string &ns)
{
namespace_path_ = util::split(ns, "::");
}
namespace_::namespace_(
container_type::const_iterator begin, container_type::const_iterator end)
{
std::copy(begin, end, std::back_inserter(namespace_path_));
}
std::string namespace_::to_string() const
{
return fmt::format("{}", fmt::join(namespace_path_, "::"));
}
size_t namespace_::size() const { return namespace_path_.size(); }
bool namespace_::is_empty() const { return namespace_path_.empty(); }
namespace_::container_type::iterator namespace_::begin()
{
return namespace_path_.begin();
}
namespace_::container_type::iterator namespace_::end()
{
return namespace_path_.end();
}
namespace_::container_type::const_iterator namespace_::cbegin() const
{
return namespace_path_.cbegin();
}
namespace_::container_type::const_iterator namespace_::cend() const
{
return namespace_path_.cend();
}
namespace_::container_type::const_iterator namespace_::begin() const
{
return namespace_path_.begin();
}
namespace_::container_type::const_iterator namespace_::end() const
{
return namespace_path_.end();
}
void namespace_::append(const std::string &ns)
{
namespace_path_.push_back(ns);
}
void namespace_::append(const namespace_ &ns)
{
for (const auto &n : ns) {
append(n);
}
}
void namespace_::pop_back() { namespace_path_.pop_back(); }
namespace_ namespace_::operator|(const namespace_ &right) const
{
namespace_ res{*this};
res.append(right);
return res;
}
void namespace_::operator|=(const namespace_ &right) { append(right); }
namespace_ namespace_::operator|(const std::string &right) const
{
namespace_ res{*this};
res.append(right);
return res;
}
void namespace_::operator|=(const std::string &right) { append(right); }
std::string &namespace_::operator[](const int index)
{
return namespace_path_[index];
}
const std::string &namespace_::operator[](const int index) const
{
return namespace_path_[index];
}
bool namespace_::starts_with(const namespace_ &right) const
{
return util::starts_with(namespace_path_, right.namespace_path_);
}
namespace_ namespace_::common_path(const namespace_ &right) const
{
namespace_ res{};
for (auto i = 0U; i < std::min(size(), right.size()); i++) {
if (namespace_path_[i] == right[i])
res |= namespace_path_[i];
else
break;
}
return res;
}
namespace_ namespace_::relative_to(const namespace_ &right) const
{
namespace_ res{*this};
if (res.starts_with(right))
util::remove_prefix(res.namespace_path_, right.namespace_path_);
return res;
}
std::string namespace_::relative(const std::string &name) const
{
/*
std::vector<std::string> namespaces_sorted{namespaces};
std::sort(namespaces_sorted.rbegin(), namespaces_sorted.rend());
auto res = name;
for (const auto &ns : namespaces_sorted) {
if (ns.empty())
continue;
if (name == ns)
return split(n, "::").back();
auto ns_prefix = ns + "::";
auto it = res.find(ns_prefix);
while (it != std::string::npos) {
res.erase(it, ns_prefix.size());
it = res.find(ns_prefix);
}
}
return res;
*/
if (is_empty())
return name;
if (name == to_string())
return name;
auto res = name;
auto ns_prefix = to_string() + "::";
auto it = res.find(ns_prefix);
while (it != std::string::npos) {
res.erase(it, ns_prefix.size());
it = res.find(ns_prefix);
}
return res;
}
bool operator==(const namespace_ &left, const namespace_ &right)
{
return left.namespace_path_ == right.namespace_path_;
}
std::string namespace_::name() const
{
assert(size() > 0);
return namespace_path_.back();
}
}

View File

@@ -0,0 +1,87 @@
/**
* src/common/model/namespace.h
*
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <string>
#include <vector>
namespace clanguml::common::model {
class namespace_ {
using container_type = std::vector<std::string>;
public:
namespace_() = default;
namespace_(const std::string &ns);
namespace_(container_type::const_iterator begin,
container_type::const_iterator end);
namespace_(const namespace_ &right) noexcept = default;
namespace_ &operator=(const namespace_ &right) noexcept = default;
namespace_(namespace_ &&right) noexcept = default;
namespace_ &operator=(namespace_ &&right) noexcept = default;
friend bool operator==(const namespace_ &left, const namespace_ &right);
namespace_(std::initializer_list<std::string> ns);
explicit namespace_(const std::vector<std::string> &ns);
std::string to_string() const;
bool is_empty() const;
size_t size() const;
namespace_ operator|(const namespace_ &right) const;
void operator|=(const namespace_ &right);
namespace_ operator|(const std::string &right) const;
void operator|=(const std::string &right);
std::string &operator[](const int index);
const std::string &operator[](const int index) const;
void append(const std::string &ns);
void append(const namespace_ &ns);
void pop_back();
bool starts_with(const namespace_ &right) const;
namespace_ common_path(const namespace_ &right) const;
namespace_ relative_to(const namespace_ &right) const;
std::string relative(const std::string &name) const;
std::string name() const;
container_type::iterator begin();
container_type::iterator end();
container_type::const_iterator begin() const;
container_type::const_iterator end() const;
container_type::const_iterator cbegin() const;
container_type::const_iterator cend() const;
private:
container_type namespace_path_;
};
}

View File

@@ -52,58 +52,59 @@ public:
} }
template <typename V = T> template <typename V = T>
void add_element(std::vector<std::string> path, std::unique_ptr<V> p) void add_element(namespace_ ns, std::unique_ptr<V> p)
{ {
assert(p); assert(p);
LOG_DBG("Adding nested element {} at path {}", p->name(), LOG_DBG(
fmt::join(path, "::")); "Adding nested element {} at path {}", p->name(), ns.to_string());
if (path.empty()) { if (ns.is_empty()) {
add_element(std::move(p)); add_element(std::move(p));
return; return;
} }
auto parent = get_element(path); auto parent = get_element(ns);
if (parent && dynamic_cast<nested_trait<T> *>(&parent.value())) if (parent && dynamic_cast<nested_trait<T> *>(&parent.value()))
dynamic_cast<nested_trait<T> &>(parent.value()) dynamic_cast<nested_trait<T> &>(parent.value())
.template add_element<V>(std::move(p)); .template add_element<V>(std::move(p));
else { else {
spdlog::error( spdlog::error("No parent element found at: {}", ns.to_string());
"No parent element found at: {}", fmt::join(path, "::")); throw std::runtime_error(
throw std::runtime_error("No parent element found"); "No parent element found for " + ns.to_string());
} }
} }
template <typename V = T> template <typename V = T> auto get_element(const namespace_ &path) const
auto get_element(std::vector<std::string> path) const
{ {
LOG_DBG("Getting nested element at path: {}", fmt::join(path, "::")); LOG_DBG("Getting nested element at path: {}", path.to_string());
if (path.empty() || !has_element(path.at(0))) { if (path.is_empty() || !has_element(path[0])) {
LOG_WARN("Nested element {} not found in element", LOG_WARN(
fmt::join(path, "::")); "Nested element {} not found in element", path.to_string());
return type_safe::optional_ref<V>{}; return type_safe::optional_ref<V>{};
} }
if (path.size() == 1) if (path.size() == 1)
return get_element<V>(path.at(0)); return get_element<V>(path[0]);
auto p = get_element<T>(path.at(0)); auto p = get_element<T>(path[0]);
if (!p) if (!p)
return type_safe::optional_ref<V>{}; return type_safe::optional_ref<V>{};
if (dynamic_cast<nested_trait<T> *>(&p.value())) if (dynamic_cast<nested_trait<T> *>(&p.value()))
return dynamic_cast<nested_trait<T> &>(p.value()).get_element<V>( return dynamic_cast<nested_trait<T> &>(p.value()).get_element<V>(
std::vector<std::string>(path.begin() + 1, path.end())); namespace_{path.begin() + 1, path.end()});
return type_safe::optional_ref<V>{}; return type_safe::optional_ref<V>{};
} }
template <typename V = T> auto get_element(const std::string &name) const template <typename V = T> auto get_element(const std::string &name) const
{ {
assert(!util::contains(name, "::"));
auto it = std::find_if(elements_.cbegin(), elements_.cend(), auto it = std::find_if(elements_.cbegin(), elements_.cend(),
[&](const auto &p) { return name == p->name(); }); [&](const auto &p) { return name == p->name(); });

View File

@@ -23,24 +23,33 @@
#include <sstream> #include <sstream>
namespace clanguml::common::model { namespace clanguml::common::model {
package::package(const std::vector<std::string> &using_namespaces) package::package(const common::model::namespace_ &using_namespace)
: element{using_namespaces} : element{using_namespace}
{ {
} }
std::string package::full_name(bool relative) const std::string package::full_name(bool relative) const
{ {
auto fn = get_namespace(); if (relative) {
auto ns = using_namespace(); auto res = get_namespace().relative_to(using_namespace()) | name();
return res.to_string();
if (relative && (fn.size() >= ns.size())) {
if (util::starts_with(fn, ns))
fn = std::vector<std::string>(fn.begin() + ns.size(), fn.end());
} }
fn.push_back(name()); return (get_namespace().relative_to(using_namespace()) | name())
.to_string();
return fmt::format("{}", fmt::join(fn, "::")); // auto fn = get_namespace();
// auto ns = using_namespace();
//
// if (relative && (fn.size() >= ns.size())) {
// if (fn.starts_with(using_namespace())
// fn = std::vector<std::string>(fn.begin() + ns.size(),
// fn.end());
// }
//
// fn.push_back(name());
//
// return fmt::format("{}", fmt::join(fn, "::"));
} }
bool package::is_deprecated() const { return is_deprecated_; } bool package::is_deprecated() const { return is_deprecated_; }

View File

@@ -35,7 +35,7 @@ class package : public element,
public stylable_element, public stylable_element,
public nested_trait<element> { public nested_trait<element> {
public: public:
package(const std::vector<std::string> &using_namespaces); package(const common::model::namespace_ &using_namespace);
package(const package &) = delete; package(const package &) = delete;
package(package &&) = default; package(package &&) = default;

View File

@@ -130,17 +130,22 @@ bool diagram::should_include_relationship(const std::string &rel)
} }
bool diagram::should_include( bool diagram::should_include(
const std::pair<std::vector<std::string>, std::string> &name) const const std::pair<common::model::namespace_, std::string> &name) const
{ {
return should_include(std::get<0>(name), std::get<1>(name)); return should_include(std::get<0>(name), std::get<1>(name));
} }
// bool diagram::should_include(
// const common::model::namespace_ &ns, const std::string &name) const
//{
// auto ns_and_name = ns | name;
// return should_include(ns_and_name.to_string());
//}
bool diagram::should_include( bool diagram::should_include(
const std::vector<std::string> &ns, const std::string &name) const const common::model::namespace_ &ns, const std::string &name) const
{ {
auto ns_and_name = ns; return should_include(ns | name);
ns_and_name.push_back(name);
return should_include(util::join(ns_and_name, "::"));
} }
bool diagram::should_include(const std::string &name_) const bool diagram::should_include(const std::string &name_) const
@@ -148,7 +153,7 @@ bool diagram::should_include(const std::string &name_) const
auto name = clanguml::util::unqualify(name_); auto name = clanguml::util::unqualify(name_);
for (const auto &ex : exclude().namespaces) { for (const auto &ex : exclude().namespaces) {
if (name.find(ex) == 0) { if (ex.starts_with(name)) {
LOG_DBG("Skipping from diagram: {}", name); LOG_DBG("Skipping from diagram: {}", name);
return false; return false;
} }
@@ -160,7 +165,7 @@ bool diagram::should_include(const std::string &name_) const
return true; return true;
for (const auto &in : include().namespaces) { for (const auto &in : include().namespaces) {
if (name.find(in) == 0) if (name.find(in.to_string()) == 0)
return true; return true;
} }
@@ -169,11 +174,22 @@ bool diagram::should_include(const std::string &name_) const
return false; return false;
} }
bool diagram::should_include(const common::model::namespace_ &path) const
{
return should_include(path.to_string());
}
bool diagram::should_include_package(
const common::model::namespace_ &path) const
{
return should_include_package(path.to_string());
}
bool diagram::should_include_package(const std::string &name) const bool diagram::should_include_package(const std::string &name) const
{ {
for (const auto &ex : exclude().namespaces) { for (const auto &ex : exclude().namespaces) {
if (name.find(ex) == 0) { if (name.find(ex.to_string()) == 0) {
LOG_DBG("Skipping from diagram: {}", name); LOG_DBG("Skipping from diagram: {}", name);
return false; return false;
} }
@@ -185,7 +201,7 @@ bool diagram::should_include_package(const std::string &name) const
return true; return true;
for (const auto &in : include().namespaces) { for (const auto &in : include().namespaces) {
if (in.find(name) == 0 || name.find(in) == 0) if (in.to_string().find(name) == 0 || name.find(in.to_string()) == 0)
return true; return true;
} }
@@ -283,6 +299,21 @@ void get_option(const Node &node, clanguml::config::option<T> &option)
option.set(node[option.name].template as<T>()); option.set(node[option.name].template as<T>());
} }
template <>
void get_option<clanguml::common::model::namespace_>(const Node &node,
clanguml::config::option<clanguml::common::model::namespace_> &option)
{
if (node[option.name]) {
if (node[option.name].Type() == NodeType::Scalar)
option.set(node[option.name].template as<std::string>());
else if (node[option.name].Type() == NodeType::Sequence)
option.set(
node[option.name].template as<std::vector<std::string>>()[0]);
else
throw std::runtime_error("Invalid using_namespace value");
}
}
template <> template <>
void get_option<method_arguments>( void get_option<method_arguments>(
const Node &node, clanguml::config::option<method_arguments> &option) const Node &node, clanguml::config::option<method_arguments> &option)
@@ -393,8 +424,12 @@ template <> struct convert<plantuml> {
template <> struct convert<filter> { template <> struct convert<filter> {
static bool decode(const Node &node, filter &rhs) static bool decode(const Node &node, filter &rhs)
{ {
if (node["namespaces"]) if (node["namespaces"]) {
rhs.namespaces = node["namespaces"].as<decltype(rhs.namespaces)>(); auto namespace_list =
node["namespaces"].as<std::vector<std::string>>();
for (const auto &ns : namespace_list)
rhs.namespaces.push_back(ns);
}
if (node["relationships"]) if (node["relationships"])
rhs.relationships = rhs.relationships =

View File

@@ -46,7 +46,7 @@ struct plantuml {
}; };
struct filter { struct filter {
std::vector<std::string> namespaces; std::vector<common::model::namespace_> namespaces;
// Valid values are: // Valid values are:
// - inheritance // - inheritance
@@ -79,7 +79,7 @@ std::string to_string(const hint_t t);
struct inheritable_diagram_options { struct inheritable_diagram_options {
option<std::vector<std::string>> glob{"glob"}; option<std::vector<std::string>> glob{"glob"};
option<std::vector<std::string>> using_namespace{"using_namespace"}; option<common::model::namespace_> using_namespace{"using_namespace"};
option<bool> include_relations_also_as_members{ option<bool> include_relations_also_as_members{
"include_relations_also_as_members", true}; "include_relations_also_as_members", true};
option<filter> include{"include"}; option<filter> include{"include"};
@@ -105,15 +105,24 @@ struct diagram : public inheritable_diagram_options {
bool should_include_package(const std::string &name) const; bool should_include_package(const std::string &name) const;
bool should_include( bool should_include_package(const common::model::namespace_ &path) const;
const std::pair<std::vector<std::string>, std::string> &name) const;
bool should_include( bool should_include(
const std::vector<std::string> &ns, const std::string &name) const; const std::pair<common::model::namespace_, std::string> &name) const;
// bool should_include(
// const std::vector<std::string> &ns, const std::string &name)
// const;
bool should_include(
const common::model::namespace_ &ns, const std::string &name) const;
bool should_include(const common::model::scope_t scope) const; bool should_include(const common::model::scope_t scope) const;
bool should_include(const std::string &name_) const; bool should_include(const std::string &name_) const;
bool should_include(const common::model::namespace_ &path) const;
private: private:
}; };

View File

@@ -28,7 +28,7 @@ template <typename T> struct option {
option(const std::string &name_, option(const std::string &name_,
option_inherit_mode im = option_inherit_mode::override) option_inherit_mode im = option_inherit_mode::override)
: name{name_} : name{name_}
, value{{}} , value{}
{ {
} }
option(const std::string &name_, const T &initial_value, option(const std::string &name_, const T &initial_value,

View File

@@ -39,7 +39,7 @@ std::string to_string(CXString &&cxs)
} }
std::string full_name( std::string full_name(
const std::vector<std::string> &current_ns, const cppast::cpp_entity &e) const common::model::namespace_ &current_ns, const cppast::cpp_entity &e)
{ {
if (e.name().empty()) if (e.name().empty())
return ""; return "";
@@ -126,12 +126,13 @@ bool is_inside_class(const cppast::cpp_entity &e)
return false; return false;
} }
std::pair<std::vector<std::string>, std::string> split_ns( std::pair<common::model::namespace_, std::string> split_ns(
const std::string &full_name) const std::string &full_name)
{ {
auto name_before_template = ::clanguml::util::split(full_name, "<")[0]; auto name_before_template = ::clanguml::util::split(full_name, "<")[0];
auto ns = ::clanguml::util::split(name_before_template, "::"); auto ns = common::model::namespace_{
auto name = ns.back(); ::clanguml::util::split(name_before_template, "::")};
auto name = ns.name();
ns.pop_back(); ns.pop_back();
return {ns, name}; return {ns, name};
} }
@@ -197,7 +198,7 @@ std::string ns(const cppast::cpp_type &t, const cppast::cpp_entity_index &idx)
} }
std::string fully_prefixed( std::string fully_prefixed(
const std::vector<std::string> &current_ns, const cppast::cpp_entity &e) const common::model::namespace_ &current_ns, const cppast::cpp_entity &e)
{ {
if (e.name().find("::") != std::string::npos) { if (e.name().find("::") != std::string::npos) {
// the name already contains namespace, but it could be not // the name already contains namespace, but it could be not

View File

@@ -17,6 +17,8 @@
*/ */
#pragma once #pragma once
#include "common/model/namespace.h"
#include <clang-c/CXCompilationDatabase.h> #include <clang-c/CXCompilationDatabase.h>
#include <clang-c/Index.h> #include <clang-c/Index.h>
#include <cppast/cpp_entity.hpp> #include <cppast/cpp_entity.hpp>
@@ -41,13 +43,13 @@ namespace util {
std::string to_string(CXString &&cxs); std::string to_string(CXString &&cxs);
std::string full_name( std::string full_name(
const std::vector<std::string> &current_ns, const cppast::cpp_entity &e); const common::model::namespace_ &current_ns, const cppast::cpp_entity &e);
std::string full_name(const cppast::cpp_type &t, std::string full_name(const cppast::cpp_type &t,
const cppast::cpp_entity_index &idx, bool inside_class); const cppast::cpp_entity_index &idx, bool inside_class);
std::string fully_prefixed( std::string fully_prefixed(
const std::vector<std::string> &current_ns, const cppast::cpp_entity &e); const common::model::namespace_ &current_ns, const cppast::cpp_entity &e);
const cppast::cpp_type &unreferenced(const cppast::cpp_type &t); const cppast::cpp_type &unreferenced(const cppast::cpp_type &t);
@@ -58,7 +60,7 @@ type_safe::optional_ref<const cppast::cpp_namespace> entity_ns(
std::string ns(const cppast::cpp_type &t, const cppast::cpp_entity_index &idx); std::string ns(const cppast::cpp_type &t, const cppast::cpp_entity_index &idx);
std::pair<std::vector<std::string>, std::string> split_ns( std::pair<common::model::namespace_, std::string> split_ns(
const std::string &full_name); const std::string &full_name);
bool is_inside_class(const cppast::cpp_entity &e); bool is_inside_class(const cppast::cpp_entity &e);

View File

@@ -39,9 +39,9 @@ void generator::generate_relationships(
for (const auto &r : p.relationships()) { for (const auto &r : p.relationships()) {
std::stringstream relstr; std::stringstream relstr;
try { try {
relstr << m_model.to_alias(ns_relative(uns, p.full_name(false))) relstr << m_model.to_alias(uns.relative(p.full_name(false)))
<< " ..> " << " ..> "
<< m_model.to_alias(ns_relative(uns, r.destination())) << m_model.to_alias(uns.relative(r.destination()))
<< '\n'; << '\n';
ostr << relstr.str(); ostr << relstr.str();
} }

View File

@@ -27,17 +27,17 @@ std::string diagram::to_alias(const std::string &full_name) const
{ {
LOG_DBG("Looking for alias for {}", full_name); LOG_DBG("Looking for alias for {}", full_name);
auto fn = util::split(full_name, "::"); auto path = common::model::namespace_{full_name};
if (fn.empty()) if (path.is_empty())
throw error::uml_alias_missing( throw error::uml_alias_missing(
fmt::format("Missing alias for '{}'", full_name)); fmt::format("Missing alias for '{}'", path.to_string()));
auto package = get_element<common::model::package>(fn); auto package = get_element<common::model::package>(path);
if (!package) if (!package)
throw error::uml_alias_missing( throw error::uml_alias_missing(
fmt::format("Missing alias for '{}'", full_name)); fmt::format("Missing alias for '{}'", path.to_string()));
return package.value().alias(); return package.value().alias();
} }

View File

@@ -153,12 +153,12 @@ translation_unit_context::get_type_alias_template(
void translation_unit_context::push_namespace(const std::string &ns) void translation_unit_context::push_namespace(const std::string &ns)
{ {
namespace_.push_back(ns); namespace_ |= ns;
} }
void translation_unit_context::pop_namespace() { namespace_.pop_back(); } void translation_unit_context::pop_namespace() { namespace_.pop_back(); }
const std::vector<std::string> &translation_unit_context::get_namespace() const const common::model::namespace_ &translation_unit_context::get_namespace() const
{ {
return namespace_; return namespace_;
} }

View File

@@ -68,7 +68,7 @@ public:
void pop_namespace(); void pop_namespace();
const std::vector<std::string> &get_namespace() const; const common::model::namespace_ &get_namespace() const;
const cppast::cpp_entity_index &entity_index() const; const cppast::cpp_entity_index &entity_index() const;
@@ -82,7 +82,7 @@ public:
private: private:
// Current visitor namespace // Current visitor namespace
std::vector<std::string> namespace_; common::model::namespace_ namespace_;
// Reference to the cppast entity index // Reference to the cppast entity index
cppast::cpp_entity_index &entity_index_; cppast::cpp_entity_index &entity_index_;

View File

@@ -18,6 +18,8 @@
#include "translation_unit_visitor.h" #include "translation_unit_visitor.h"
#include "common/model/namespace.h"
#include <cppast/cpp_alias_template.hpp> #include <cppast/cpp_alias_template.hpp>
#include <cppast/cpp_array_type.hpp> #include <cppast/cpp_array_type.hpp>
#include <cppast/cpp_class_template.hpp> #include <cppast/cpp_class_template.hpp>
@@ -89,20 +91,17 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
if (!ns_declaration.is_anonymous() && if (!ns_declaration.is_anonymous() &&
!ns_declaration.is_inline()) { !ns_declaration.is_inline()) {
std::vector<std::string> package_parent = auto package_parent = ctx.get_namespace();
ctx.get_namespace(); auto package_path = package_parent | e.name();
auto package_path = package_parent; auto usn = common::model::namespace_{
package_path.push_back(e.name()); ctx.config().using_namespace()};
auto usn = util::split( if (!usn.starts_with(package_path)) {
ctx.config().using_namespace()[0], "::");
if (!util::starts_with(usn, package_path)) {
auto p = std::make_unique<package>(usn); auto p = std::make_unique<package>(usn);
util::remove_prefix(package_path, usn); package_path = package_path.relative_to(usn);
p->set_name(e.name()); p->set_name(e.name());
p->set_namespace(package_parent); p->set_namespace(package_path);
if (ns_declaration.comment().has_value()) if (ns_declaration.comment().has_value())
p->add_decorators(decorators::parse( p->add_decorators(decorators::parse(
@@ -303,10 +302,10 @@ void translation_unit_visitor::process_class_declaration(
} }
for (const auto &dependency : relationships) { for (const auto &dependency : relationships) {
auto destination = util::split(std::get<0>(dependency), "::"); auto destination = common::model::namespace_{std::get<0>(dependency)};
if (!util::starts_with(ctx.get_namespace(), destination) && if (!ctx.get_namespace().starts_with(destination) &&
!util::starts_with(destination, ctx.get_namespace())) { !destination.starts_with(ctx.get_namespace())) {
relationship r{ relationship r{
relationship_t::kDependency, std::get<0>(dependency)}; relationship_t::kDependency, std::get<0>(dependency)};
current_package.value().add_relationship(std::move(r)); current_package.value().add_relationship(std::move(r));
@@ -330,10 +329,10 @@ void translation_unit_visitor::process_function(const cppast::cpp_function &f)
f.return_type(), relationships, relationship_t::kDependency); f.return_type(), relationships, relationship_t::kDependency);
for (const auto &dependency : relationships) { for (const auto &dependency : relationships) {
auto destination = util::split(std::get<0>(dependency), "::"); auto destination = common::model::namespace_{std::get<0>(dependency)};
if (!util::starts_with(ctx.get_namespace(), destination) && if (!ctx.get_namespace().starts_with(destination) &&
!util::starts_with(destination, ctx.get_namespace())) { !destination.starts_with(ctx.get_namespace())) {
relationship r{ relationship r{
relationship_t::kDependency, std::get<0>(dependency)}; relationship_t::kDependency, std::get<0>(dependency)};
current_package.value().add_relationship(std::move(r)); current_package.value().add_relationship(std::move(r));
@@ -350,8 +349,8 @@ bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_,
const auto fn = cx::util::full_name( const auto fn = cx::util::full_name(
resolve_alias(cppast::remove_cv(t_)), ctx.entity_index(), false); resolve_alias(cppast::remove_cv(t_)), ctx.entity_index(), false);
auto t_ns = util::split(fn, "::"); auto t_ns = common::model::namespace_{fn};
auto t_name = t_ns.back(); auto t_name = t_ns.name();
t_ns.pop_back(); t_ns.pop_back();
const auto &t_raw = resolve_alias(cppast::remove_cv(t_)); const auto &t_raw = resolve_alias(cppast::remove_cv(t_));
@@ -371,13 +370,13 @@ bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_,
const auto &t_raw_ns_final = cx::util::ns(t_raw_ns.value()) + const auto &t_raw_ns_final = cx::util::ns(t_raw_ns.value()) +
"::" + cx::util::full_name({}, t_raw_ns.value()); "::" + cx::util::full_name({}, t_raw_ns.value());
t_ns = util::split(t_raw_ns_final, "::"); t_ns = common::model::namespace_{t_raw_ns_final};
} }
} }
std::vector<std::string> possible_matches; std::vector<std::string> possible_matches;
possible_matches.push_back(util::join(t_ns, "::")); possible_matches.push_back(t_ns.to_string());
const auto fn_ns = cx::util::ns(cppast::remove_cv(t_), ctx.entity_index()); const auto fn_ns = cx::util::ns(cppast::remove_cv(t_), ctx.entity_index());

View File

@@ -44,8 +44,8 @@ generator::generator(
void generator::generate_call(const message &m, std::ostream &ostr) const void generator::generate_call(const message &m, std::ostream &ostr) const
{ {
const auto from = ns_relative(m_config.using_namespace(), m.from); const auto from = m_config.using_namespace().relative(m.from);
const auto to = ns_relative(m_config.using_namespace(), m.to); const auto to = m_config.using_namespace().relative(m.to);
ostr << '"' << from << "\" " ostr << '"' << from << "\" "
<< common::generators::plantuml::to_plantuml(message_t::kCall) << " \"" << common::generators::plantuml::to_plantuml(message_t::kCall) << " \""
@@ -57,8 +57,8 @@ void generator::generate_return(const message &m, std::ostream &ostr) const
// Add return activity only for messages between different actors and // Add return activity only for messages between different actors and
// only if the return type is different than void // only if the return type is different than void
if ((m.from != m.to) && (m.return_type != "void")) { if ((m.from != m.to) && (m.return_type != "void")) {
const auto from = ns_relative(m_config.using_namespace(), m.from); const auto from = m_config.using_namespace().relative(m.from);
const auto to = ns_relative(m_config.using_namespace(), m.to); const auto to = m_config.using_namespace().relative(m.to);
ostr << '"' << to << "\" " ostr << '"' << to << "\" "
<< common::generators::plantuml::to_plantuml(message_t::kReturn) << common::generators::plantuml::to_plantuml(message_t::kReturn)
@@ -69,7 +69,7 @@ void generator::generate_return(const message &m, std::ostream &ostr) const
void generator::generate_activity(const activity &a, std::ostream &ostr) const void generator::generate_activity(const activity &a, std::ostream &ostr) const
{ {
for (const auto &m : a.messages) { for (const auto &m : a.messages) {
const auto to = ns_relative(m_config.using_namespace(), m.to); const auto to = m_config.using_namespace().relative(m.to);
generate_call(m, ostr); generate_call(m, ostr);
ostr << "activate " << '"' << to << '"' << std::endl; ostr << "activate " << '"' << to << '"' << std::endl;
if (m_model.sequences.find(m.to_usr) != m_model.sequences.end()) if (m_model.sequences.find(m.to_usr) != m_model.sequences.end())

View File

@@ -18,6 +18,7 @@
#include "translation_unit_visitor.h" #include "translation_unit_visitor.h"
#include "common/model/namespace.h"
#include "translation_unit_context.h" #include "translation_unit_context.h"
#include <cppast/cpp_function.hpp> #include <cppast/cpp_function.hpp>
@@ -81,7 +82,7 @@ void translation_unit_visitor::process_activities(const cppast::cpp_function &e)
m.from = cx::util::ns(caller) + "::" + caller.name(); m.from = cx::util::ns(caller) + "::" + caller.name();
if (!ctx.config().should_include( if (!ctx.config().should_include(
util::split(cx::util::ns(caller), "::"), caller.name())) common::model::namespace_{cx::util::ns(caller)}, caller.name()))
continue; continue;
if (caller.kind() == cpp_entity_kind::function_t) if (caller.kind() == cpp_entity_kind::function_t)
@@ -98,7 +99,7 @@ void translation_unit_visitor::process_activities(const cppast::cpp_function &e)
m.to += "()"; m.to += "()";
if (!ctx.config().should_include( if (!ctx.config().should_include(
util::split(cx::util::ns(callee), "::"), callee.name())) common::model::namespace_{cx::util::ns(callee)}, callee.name()))
continue; continue;
m.to_usr = type_safe::get(function_call.get_callee_method_id()); m.to_usr = type_safe::get(function_call.get_callee_method_id());

View File

@@ -68,6 +68,7 @@ std::string join(const std::vector<std::string> &toks, std::string delimiter)
return fmt::format("{}", fmt::join(toks, delimiter)); return fmt::format("{}", fmt::join(toks, delimiter));
} }
/*
std::string ns_relative( std::string ns_relative(
const std::vector<std::string> &namespaces, const std::string &n) const std::vector<std::string> &namespaces, const std::string &n)
{ {
@@ -93,6 +94,7 @@ std::string ns_relative(
} }
return res; return res;
} }
*/
std::string unqualify(const std::string &s) std::string unqualify(const std::string &s)
{ {

View File

@@ -83,8 +83,8 @@ std::string join(const std::vector<std::string> &toks, std::string delimiter);
* *
* @return Identifier relative to one of the matching namespaces. * @return Identifier relative to one of the matching namespaces.
*/ */
std::string ns_relative( // std::string ns_relative(
const std::vector<std::string> &namespaces, const std::string &n); // const std::vector<std::string> &namespaces, const std::string &n);
/** /**
* @brief Remove any qualifiers (e.g. const) from type. * @brief Remove any qualifiers (e.g. const) from type.

View File

@@ -26,7 +26,8 @@ TEST_CASE("t00002", "[test-case][class]")
REQUIRE(diagram->include().namespaces.size() == 1); REQUIRE(diagram->include().namespaces.size() == 1);
REQUIRE_THAT(diagram->include().namespaces, REQUIRE_THAT(diagram->include().namespaces,
VectorContains(std::string{"clanguml::t00002"})); VectorContains(
clanguml::common::model::namespace_{"clanguml::t00002"}));
REQUIRE(diagram->exclude().namespaces.size() == 0); REQUIRE(diagram->exclude().namespaces.size() == 0);

View File

@@ -25,8 +25,6 @@ TEST_CASE("t00003", "[test-case][class]")
REQUIRE(diagram->name == "t00003_class"); REQUIRE(diagram->name == "t00003_class");
REQUIRE(diagram->include().namespaces.size() == 1); REQUIRE(diagram->include().namespaces.size() == 1);
REQUIRE_THAT(diagram->include().namespaces,
VectorContains(std::string{"clanguml::t00003"}));
REQUIRE(diagram->exclude().namespaces.size() == 0); REQUIRE(diagram->exclude().namespaces.size() == 0);

View File

@@ -25,9 +25,6 @@ TEST_CASE("t00004", "[test-case][class]")
REQUIRE(diagram->name == "t00004_class"); REQUIRE(diagram->name == "t00004_class");
REQUIRE(diagram->include().namespaces.size() == 1); REQUIRE(diagram->include().namespaces.size() == 1);
REQUIRE_THAT(diagram->include().namespaces,
VectorContains(std::string{"clanguml::t00004"}));
REQUIRE(diagram->exclude().namespaces.size() == 0); REQUIRE(diagram->exclude().namespaces.size() == 0);
REQUIRE(diagram->should_include("clanguml::t00004::A")); REQUIRE(diagram->should_include("clanguml::t00004::A"));

View File

@@ -53,7 +53,7 @@ TEST_CASE("Test config inherited", "[unit-test]")
CHECK(cus.type() == clanguml::config::diagram_type::class_diagram); CHECK(cus.type() == clanguml::config::diagram_type::class_diagram);
CHECK(cus.glob().size() == 1); CHECK(cus.glob().size() == 1);
CHECK(cus.glob()[0] == "src/main.cc"); CHECK(cus.glob()[0] == "src/main.cc");
CHECK(clanguml::util::contains(cus.using_namespace(), "clanguml::ns1")); CHECK(cus.using_namespace().starts_with({"clanguml::ns1"}));
CHECK(cus.include_relations_also_as_members()); CHECK(cus.include_relations_also_as_members());
CHECK(def.generate_packages() == false); CHECK(def.generate_packages() == false);
} }
@@ -76,7 +76,7 @@ TEST_CASE("Test config includes", "[unit-test]")
CHECK(cus.type() == clanguml::config::diagram_type::class_diagram); CHECK(cus.type() == clanguml::config::diagram_type::class_diagram);
CHECK(cus.glob().size() == 1); CHECK(cus.glob().size() == 1);
CHECK(cus.glob()[0] == "src/main.cc"); CHECK(cus.glob()[0] == "src/main.cc");
CHECK(clanguml::util::contains(cus.using_namespace(), "clanguml::ns1")); CHECK(cus.using_namespace().starts_with({"clanguml::ns1"}));
CHECK(cus.include_relations_also_as_members()); CHECK(cus.include_relations_also_as_members());
CHECK(cus.generate_method_arguments() == CHECK(cus.generate_method_arguments() ==
clanguml::config::method_arguments::none); clanguml::config::method_arguments::none);

View File

@@ -6,8 +6,7 @@ diagrams:
glob: glob:
- src/**/*.cc - src/**/*.cc
- src/**/*.h - src/**/*.h
using_namespace: using_namespace: clanguml
- clanguml
generate_method_arguments: full generate_method_arguments: full
generate_packages: true generate_packages: true
include: include:

72
tests/test_model.cc Normal file
View File

@@ -0,0 +1,72 @@
/**
* tests/test_model.cc
*
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define CATCH_CONFIG_MAIN
#include "catch.h"
#include "common/model/namespace.h"
TEST_CASE("Test namespace_", "[unit-test]")
{
using clanguml::common::model::namespace_;
namespace_ ns1{};
CHECK(ns1.is_empty());
namespace_ ns2{"aaa", "bbb", "ccc"};
CHECK(ns2.size() == 3);
CHECK(ns2[0] == "aaa");
CHECK(ns2[1] == "bbb");
CHECK(ns2[2] == "ccc");
namespace_ ns3 = ns1 | "aaa" | "bbb" | "ccc";
CHECK(ns3.size() == 3);
CHECK(ns3[0] == "aaa");
CHECK(ns3[1] == "bbb");
CHECK(ns3[2] == "ccc");
namespace_ ns4 = namespace_{"aaa", "bbb"} | namespace_{"ccc"};
CHECK(ns4.size() == 3);
CHECK(ns4[0] == "aaa");
CHECK(ns4[1] == "bbb");
CHECK(ns4[2] == "ccc");
namespace_ ns5{"aaa::bbb::ccc"};
CHECK(ns5.size() == 3);
CHECK(ns5[0] == "aaa");
CHECK(ns5[1] == "bbb");
CHECK(ns5[2] == "ccc");
CHECK(ns4 == ns5);
namespace_ ns6a{"aaa::bbb::ccc"};
namespace_ ns6b{"aaa::bbb::ddd::eee"};
auto ns6 = ns6a.common_path(ns6b);
CHECK(ns6 == namespace_{"aaa", "bbb"});
CHECK(ns6b.starts_with({"aaa", "bbb", "ddd"}));
namespace_ ns7a{"aaa::bbb"};
namespace_ ns7b{"aaa::bbb::ccc::ddd"};
CHECK(ns7b.relative_to(ns7a) == namespace_{"ccc", "ddd"});
CHECK(ns7a.relative_to(ns7b) == namespace_{"aaa::bbb"});
namespace_ ns8{"aaa::bbb"};
const std::string name{"aaa::bbb::ccc<std::unique_ptr<aaa::bbb::ddd>>"};
CHECK(ns8.relative(name) == "ccc<std::unique_ptr<ddd>>");
}

View File

@@ -35,19 +35,19 @@ TEST_CASE("Test split", "[unit-test]")
CHECK(split("std::vector::detail::", "::") == C{"std", "vector", "detail"}); CHECK(split("std::vector::detail::", "::") == C{"std", "vector", "detail"});
} }
//
TEST_CASE("Test ns_relative", "[unit-test]") // TEST_CASE("Test ns_relative", "[unit-test]")
{ //{
using namespace clanguml::util; // using namespace clanguml::util;
//
CHECK(ns_relative({}, "std::vector") == "std::vector"); // CHECK(ns_relative({}, "std::vector") == "std::vector");
CHECK(ns_relative({"std"}, "std::vector") == "vector"); // CHECK(ns_relative({"std"}, "std::vector") == "vector");
CHECK(ns_relative({"std"}, "const std::vector&") == "const vector&"); // CHECK(ns_relative({"std"}, "const std::vector&") == "const vector&");
CHECK(ns_relative({"std", "clanguml::t0"}, // CHECK(ns_relative({"std", "clanguml::t0"},
"static const std::vector<clanguml::t0::a>&") == // "static const std::vector<clanguml::t0::a>&") ==
"static const vector<a>&"); // "static const vector<a>&");
CHECK(ns_relative({"clanguml::t0"}, "clanguml::t0") == "t0"); // CHECK(ns_relative({"clanguml::t0"}, "clanguml::t0") == "t0");
} //}
TEST_CASE("Test abbreviate", "[unit-test]") TEST_CASE("Test abbreviate", "[unit-test]")
{ {