Initial refactor of namespace handling
This commit is contained in:
@@ -118,7 +118,7 @@ void generator::generate(
|
||||
if (m.is_defaulted())
|
||||
ostr << " = default";
|
||||
|
||||
ostr << " : " << ns_relative(uns, type);
|
||||
ostr << " : " << uns.relative(type);
|
||||
|
||||
ostr << '\n';
|
||||
}
|
||||
@@ -154,9 +154,9 @@ void generator::generate(
|
||||
if (!r.multiplicity_destination().empty())
|
||||
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 << " "
|
||||
<< m_model.to_alias(ns_relative(uns, destination));
|
||||
<< m_model.to_alias(uns.relative(destination));
|
||||
|
||||
if (!r.label().empty()) {
|
||||
relstr << " : " << plantuml_common::to_plantuml(r.scope())
|
||||
@@ -197,7 +197,7 @@ void generator::generate(
|
||||
ostr << "{static} ";
|
||||
|
||||
ostr << plantuml_common::to_plantuml(m.scope()) << m.name() << " : "
|
||||
<< ns_relative(uns, m.type()) << '\n';
|
||||
<< uns.relative(m.type()) << '\n';
|
||||
}
|
||||
|
||||
ostr << "}" << '\n';
|
||||
@@ -206,10 +206,8 @@ void generator::generate(
|
||||
for (const auto &b : c.parents()) {
|
||||
std::stringstream relstr;
|
||||
try {
|
||||
relstr << m_model.to_alias(ns_relative(uns, b.name()))
|
||||
<< " <|-- "
|
||||
<< m_model.to_alias(ns_relative(uns, c.full_name()))
|
||||
<< '\n';
|
||||
relstr << m_model.to_alias(uns.relative(b.name())) << " <|-- "
|
||||
<< m_model.to_alias(uns.relative(c.full_name())) << '\n';
|
||||
all_relations_str << relstr.str();
|
||||
}
|
||||
catch (error::uml_alias_missing &e) {
|
||||
@@ -253,13 +251,13 @@ void generator::generate(
|
||||
destination = r.destination();
|
||||
|
||||
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(
|
||||
r.type(), r.style())
|
||||
<< " "
|
||||
<< m_model.to_alias(
|
||||
ns_relative(m_config.using_namespace(), destination));
|
||||
m_config.using_namespace().relative(destination));
|
||||
|
||||
if (!r.label().empty())
|
||||
relstr << " : " << r.label();
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
|
||||
namespace clanguml::class_diagram::model {
|
||||
|
||||
class_::class_(const std::vector<std::string> &using_namespaces)
|
||||
: element{using_namespaces}
|
||||
class_::class_(const common::model::namespace_ &using_namespace)
|
||||
: element{using_namespace}
|
||||
{
|
||||
}
|
||||
|
||||
@@ -112,10 +112,12 @@ std::string class_::full_name_no_ns() const
|
||||
std::string class_::full_name(bool relative) const
|
||||
{
|
||||
using namespace clanguml::util;
|
||||
using clanguml::common::model::namespace_;
|
||||
|
||||
std::ostringstream ostr;
|
||||
if (relative && starts_with(get_namespace(), using_namespace()))
|
||||
ostr << ns_relative(using_namespace(), name_and_ns());
|
||||
// if (relative && starts_with(get_namespace(), using_namespace()))
|
||||
if (relative)
|
||||
ostr << namespace_{name()}.relative_to(using_namespace()).to_string();
|
||||
else
|
||||
ostr << name_and_ns();
|
||||
|
||||
@@ -126,6 +128,8 @@ std::string class_::full_name(bool relative) const
|
||||
std::ostringstream &class_::render_template_params(
|
||||
std::ostringstream &ostr) const
|
||||
{
|
||||
using clanguml::common::model::namespace_;
|
||||
|
||||
if (!templates_.empty()) {
|
||||
std::vector<std::string> tnames;
|
||||
std::transform(templates_.cbegin(), templates_.cend(),
|
||||
@@ -133,12 +137,14 @@ std::ostringstream &class_::render_template_params(
|
||||
std::vector<std::string> res;
|
||||
|
||||
if (!tmplt.type().empty())
|
||||
res.push_back(
|
||||
util::ns_relative(using_namespace(), tmplt.type()));
|
||||
res.push_back(namespace_{tmplt.type()}
|
||||
.relative_to(using_namespace())
|
||||
.to_string());
|
||||
|
||||
if (!tmplt.name().empty())
|
||||
res.push_back(
|
||||
util::ns_relative(using_namespace(), tmplt.name()));
|
||||
res.push_back(namespace_{tmplt.name()}
|
||||
.relative_to(using_namespace())
|
||||
.to_string());
|
||||
|
||||
if (!tmplt.default_value().empty()) {
|
||||
res.push_back("=");
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace clanguml::class_diagram::model {
|
||||
class class_ : public common::model::element,
|
||||
public common::model::stylable_element {
|
||||
public:
|
||||
class_(const std::vector<std::string> &using_namespaces);
|
||||
class_(const common::model::namespace_ &using_namespace);
|
||||
|
||||
class_(const class_ &) = delete;
|
||||
class_(class_ &&) noexcept = delete;
|
||||
|
||||
@@ -82,7 +82,7 @@ void diagram::add_class(std::unique_ptr<class_> &&c)
|
||||
auto ns = c->get_relative_namespace();
|
||||
auto name = c->name();
|
||||
add_element(ns, std::move(c));
|
||||
ns.push_back(name);
|
||||
ns |= name;
|
||||
const auto ccc = get_element<class_>(ns);
|
||||
assert(ccc.value().name() == name);
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
|
||||
namespace clanguml::class_diagram::model {
|
||||
|
||||
enum_::enum_(const std::vector<std::string> &using_namespaces)
|
||||
: element{using_namespaces}
|
||||
enum_::enum_(const common::model::namespace_ &using_namespace)
|
||||
: element{using_namespace}
|
||||
{
|
||||
}
|
||||
|
||||
@@ -37,10 +37,11 @@ bool operator==(const enum_ &l, const enum_ &r)
|
||||
std::string enum_::full_name(bool relative) const
|
||||
{
|
||||
using namespace clanguml::util;
|
||||
using clanguml::common::model::namespace_;
|
||||
|
||||
std::ostringstream ostr;
|
||||
if (relative)
|
||||
ostr << ns_relative(using_namespace(), name());
|
||||
ostr << namespace_{name()}.relative_to(using_namespace()).to_string();
|
||||
else
|
||||
ostr << name();
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace clanguml::class_diagram::model {
|
||||
class enum_ : public common::model::element,
|
||||
public common::model::stylable_element {
|
||||
public:
|
||||
enum_(const std::vector<std::string> &using_namespaces);
|
||||
enum_(const common::model::namespace_ &using_namespaces);
|
||||
|
||||
enum_(const enum_ &) = delete;
|
||||
enum_(enum_ &&) = default;
|
||||
|
||||
@@ -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::to_string(
|
||||
const std::vector<std::string> &using_namespaces) const
|
||||
const common::model::namespace_ &using_namespace) const
|
||||
{
|
||||
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())
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/model/decorated_element.h"
|
||||
#include "common/model/namespace.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -36,7 +37,7 @@ public:
|
||||
std::string default_value() const;
|
||||
|
||||
std::string to_string(
|
||||
const std::vector<std::string> &using_namespaces) const;
|
||||
const common::model::namespace_ &using_namespaces) const;
|
||||
|
||||
private:
|
||||
std::string type_;
|
||||
|
||||
@@ -154,14 +154,14 @@ translation_unit_context::get_type_alias_template(
|
||||
|
||||
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
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
|
||||
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;
|
||||
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
|
||||
private:
|
||||
// Current visitor namespace
|
||||
std::vector<std::string> namespace_;
|
||||
common::model::namespace_ ns_;
|
||||
|
||||
// Reference to the cppast entity index
|
||||
cppast::cpp_entity_index &entity_index_;
|
||||
|
||||
@@ -200,7 +200,7 @@ void translation_unit_visitor::process_type_alias_template(
|
||||
cx::util::full_name(ctx.get_namespace(), at),
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -222,15 +222,14 @@ void translation_unit_visitor::process_type_alias(
|
||||
void translation_unit_visitor::process_namespace(
|
||||
const cppast::cpp_entity &e, const cppast::cpp_namespace &ns_declaration)
|
||||
{
|
||||
std::vector<std::string> package_parent = ctx.get_namespace();
|
||||
auto package_path = package_parent;
|
||||
package_path.push_back(e.name());
|
||||
auto package_parent = ctx.get_namespace();
|
||||
auto package_path = package_parent | 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);
|
||||
util::remove_prefix(package_path, usn);
|
||||
package_path = package_path.relative_to(usn);
|
||||
|
||||
p->set_name(e.name());
|
||||
p->set_namespace(package_parent);
|
||||
@@ -267,8 +266,7 @@ void translation_unit_visitor::process_enum_declaration(
|
||||
return;
|
||||
}
|
||||
|
||||
auto e_ptr = std::make_unique<enum_>(
|
||||
util::split(ctx.config().using_namespace()[0], "::"));
|
||||
auto e_ptr = std::make_unique<enum_>(ctx.config().using_namespace());
|
||||
auto &e = *e_ptr;
|
||||
e.set_name(enm.name());
|
||||
e.set_namespace(ctx.get_namespace());
|
||||
@@ -312,8 +310,7 @@ void translation_unit_visitor::process_class_declaration(
|
||||
const cppast::cpp_class &cls,
|
||||
type_safe::optional_ref<const cppast::cpp_template_specialization> tspec)
|
||||
{
|
||||
auto c_ptr = std::make_unique<class_>(
|
||||
util::split(ctx.config().using_namespace()[0], "::"));
|
||||
auto c_ptr = std::make_unique<class_>(ctx.config().using_namespace());
|
||||
auto &c = *c_ptr;
|
||||
c.is_struct(cls.class_kind() == cppast::cpp_class_kind::struct_t);
|
||||
// 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);
|
||||
|
||||
auto ns_and_name = ns;
|
||||
ns_and_name.push_back(base_name);
|
||||
auto ns_and_name = ns | base_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)
|
||||
{
|
||||
// Create class_ instance to hold the template instantiation
|
||||
auto tinst_ptr = std::make_unique<class_>(
|
||||
util::split(ctx.config().using_namespace()[0], "::"));
|
||||
auto tinst_ptr = std::make_unique<class_>(ctx.config().using_namespace());
|
||||
auto &tinst = *tinst_ptr;
|
||||
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
|
||||
const auto [ns, name] = cx::util::split_ns(tinst_full_name);
|
||||
tinst.set_name(name);
|
||||
if (ns.empty())
|
||||
if (ns.is_empty())
|
||||
tinst.set_namespace(ctx.get_namespace());
|
||||
else
|
||||
tinst.set_namespace(ns);
|
||||
|
||||
@@ -83,11 +83,10 @@ void generator<C, D>::generate_config_layout_hints(std::ostream &ostr) const
|
||||
for (const auto &hint : hints) {
|
||||
std::stringstream hint_str;
|
||||
try {
|
||||
hint_str << m_model.to_alias(ns_relative(uns, entity))
|
||||
hint_str << m_model.to_alias(uns.relative(entity))
|
||||
<< " -[hidden]"
|
||||
<< clanguml::config::to_string(hint.hint) << "- "
|
||||
<< m_model.to_alias(ns_relative(uns, hint.entity))
|
||||
<< '\n';
|
||||
<< m_model.to_alias(uns.relative(hint.entity)) << '\n';
|
||||
ostr << hint_str.str();
|
||||
}
|
||||
catch (clanguml::error::uml_alias_missing &e) {
|
||||
@@ -103,12 +102,14 @@ template <typename C, typename D>
|
||||
void generator<C, D>::generate_plantuml_directives(
|
||||
std::ostream &ostr, const std::vector<std::string> &directives) const
|
||||
{
|
||||
using common::model::namespace_;
|
||||
|
||||
for (const auto &b : directives) {
|
||||
std::string note{b};
|
||||
std::tuple<std::string, size_t, size_t> alias_match;
|
||||
while (util::find_element_alias(note, alias_match)) {
|
||||
auto alias = m_model.to_alias(util::ns_relative(
|
||||
m_config.using_namespace(), std::get<0>(alias_match)));
|
||||
auto alias = m_model.to_alias(
|
||||
m_config.using_namespace().relative(std::get<0>(alias_match)));
|
||||
note.replace(
|
||||
std::get<1>(alias_match), std::get<2>(alias_match), alias);
|
||||
}
|
||||
|
||||
@@ -26,12 +26,10 @@ namespace clanguml::common::model {
|
||||
|
||||
std::atomic_uint64_t element::m_nextId = 1;
|
||||
|
||||
element::element(const std::vector<std::string> &using_namespaces)
|
||||
: using_namespace_{using_namespaces}
|
||||
element::element(const namespace_ &using_namespace)
|
||||
: using_namespace_{using_namespace}
|
||||
, 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); }
|
||||
@@ -59,18 +57,12 @@ void element::add_relationship(relationship &&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;
|
||||
}
|
||||
|
||||
const std::vector<std::string> &element::using_namespace() const
|
||||
{
|
||||
return using_namespace_;
|
||||
}
|
||||
const namespace_ &element::using_namespace() const { return ns_; }
|
||||
|
||||
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)
|
||||
{
|
||||
out << "(" << rhs.name() << ", ns=["
|
||||
<< util::join(rhs.get_namespace(), "::") << "], full_name=["
|
||||
<< rhs.full_name(true) << "])";
|
||||
out << "(" << rhs.name() << ", ns=[" << rhs.get_namespace().to_string()
|
||||
<< "], full_name=[" << rhs.full_name(true) << "])";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "decorated_element.h"
|
||||
#include "namespace.h"
|
||||
#include "relationship.h"
|
||||
#include "util/util.h"
|
||||
|
||||
@@ -30,7 +31,7 @@ namespace clanguml::common::model {
|
||||
|
||||
class element : public decorated_element {
|
||||
public:
|
||||
element(const std::vector<std::string> &using_namespaces);
|
||||
element(const namespace_ &using_namespace);
|
||||
|
||||
virtual ~element() = default;
|
||||
|
||||
@@ -42,27 +43,24 @@ public:
|
||||
|
||||
std::string name_and_ns() const
|
||||
{
|
||||
auto ns = namespace_;
|
||||
ns.push_back(name());
|
||||
return util::join(ns, "::");
|
||||
auto ns = ns_ | name();
|
||||
return ns.to_string();
|
||||
}
|
||||
|
||||
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_;
|
||||
util::remove_prefix(relative_ns, using_namespace_);
|
||||
return relative_ns;
|
||||
return ns_.relative_to(using_namespace_);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
@@ -81,8 +79,8 @@ protected:
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::vector<std::string> namespace_;
|
||||
std::vector<std::string> using_namespace_;
|
||||
namespace_ ns_;
|
||||
namespace_ using_namespace_;
|
||||
std::vector<relationship> relationships_;
|
||||
|
||||
static std::atomic_uint64_t m_nextId;
|
||||
|
||||
213
src/common/model/namespace.cc
Normal file
213
src/common/model/namespace.cc
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
87
src/common/model/namespace.h
Normal file
87
src/common/model/namespace.h
Normal 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_;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -52,58 +52,59 @@ public:
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
LOG_DBG("Adding nested element {} at path {}", p->name(),
|
||||
fmt::join(path, "::"));
|
||||
LOG_DBG(
|
||||
"Adding nested element {} at path {}", p->name(), ns.to_string());
|
||||
|
||||
if (path.empty()) {
|
||||
if (ns.is_empty()) {
|
||||
add_element(std::move(p));
|
||||
return;
|
||||
}
|
||||
|
||||
auto parent = get_element(path);
|
||||
auto parent = get_element(ns);
|
||||
|
||||
if (parent && dynamic_cast<nested_trait<T> *>(&parent.value()))
|
||||
dynamic_cast<nested_trait<T> &>(parent.value())
|
||||
.template add_element<V>(std::move(p));
|
||||
else {
|
||||
spdlog::error(
|
||||
"No parent element found at: {}", fmt::join(path, "::"));
|
||||
throw std::runtime_error("No parent element found");
|
||||
spdlog::error("No parent element found at: {}", ns.to_string());
|
||||
throw std::runtime_error(
|
||||
"No parent element found for " + ns.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename V = T>
|
||||
auto get_element(std::vector<std::string> path) const
|
||||
template <typename V = T> auto get_element(const namespace_ &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))) {
|
||||
LOG_WARN("Nested element {} not found in element",
|
||||
fmt::join(path, "::"));
|
||||
if (path.is_empty() || !has_element(path[0])) {
|
||||
LOG_WARN(
|
||||
"Nested element {} not found in element", path.to_string());
|
||||
return type_safe::optional_ref<V>{};
|
||||
}
|
||||
|
||||
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)
|
||||
return type_safe::optional_ref<V>{};
|
||||
|
||||
if (dynamic_cast<nested_trait<T> *>(&p.value()))
|
||||
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>{};
|
||||
}
|
||||
|
||||
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(),
|
||||
[&](const auto &p) { return name == p->name(); });
|
||||
|
||||
|
||||
@@ -23,24 +23,33 @@
|
||||
#include <sstream>
|
||||
|
||||
namespace clanguml::common::model {
|
||||
package::package(const std::vector<std::string> &using_namespaces)
|
||||
: element{using_namespaces}
|
||||
package::package(const common::model::namespace_ &using_namespace)
|
||||
: element{using_namespace}
|
||||
{
|
||||
}
|
||||
|
||||
std::string package::full_name(bool relative) const
|
||||
{
|
||||
auto fn = get_namespace();
|
||||
auto ns = using_namespace();
|
||||
|
||||
if (relative && (fn.size() >= ns.size())) {
|
||||
if (util::starts_with(fn, ns))
|
||||
fn = std::vector<std::string>(fn.begin() + ns.size(), fn.end());
|
||||
if (relative) {
|
||||
auto res = get_namespace().relative_to(using_namespace()) | name();
|
||||
return res.to_string();
|
||||
}
|
||||
|
||||
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_; }
|
||||
|
||||
@@ -35,7 +35,7 @@ class package : public element,
|
||||
public stylable_element,
|
||||
public nested_trait<element> {
|
||||
public:
|
||||
package(const std::vector<std::string> &using_namespaces);
|
||||
package(const common::model::namespace_ &using_namespace);
|
||||
|
||||
package(const package &) = delete;
|
||||
package(package &&) = default;
|
||||
|
||||
@@ -130,17 +130,22 @@ bool diagram::should_include_relationship(const std::string &rel)
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
// 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(
|
||||
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;
|
||||
ns_and_name.push_back(name);
|
||||
return should_include(util::join(ns_and_name, "::"));
|
||||
return should_include(ns | name);
|
||||
}
|
||||
|
||||
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_);
|
||||
|
||||
for (const auto &ex : exclude().namespaces) {
|
||||
if (name.find(ex) == 0) {
|
||||
if (ex.starts_with(name)) {
|
||||
LOG_DBG("Skipping from diagram: {}", name);
|
||||
return false;
|
||||
}
|
||||
@@ -160,7 +165,7 @@ bool diagram::should_include(const std::string &name_) const
|
||||
return true;
|
||||
|
||||
for (const auto &in : include().namespaces) {
|
||||
if (name.find(in) == 0)
|
||||
if (name.find(in.to_string()) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -169,11 +174,22 @@ bool diagram::should_include(const std::string &name_) const
|
||||
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
|
||||
{
|
||||
|
||||
for (const auto &ex : exclude().namespaces) {
|
||||
if (name.find(ex) == 0) {
|
||||
if (name.find(ex.to_string()) == 0) {
|
||||
LOG_DBG("Skipping from diagram: {}", name);
|
||||
return false;
|
||||
}
|
||||
@@ -185,7 +201,7 @@ bool diagram::should_include_package(const std::string &name) const
|
||||
return true;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -283,6 +299,21 @@ void get_option(const Node &node, clanguml::config::option<T> &option)
|
||||
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 <>
|
||||
void get_option<method_arguments>(
|
||||
const Node &node, clanguml::config::option<method_arguments> &option)
|
||||
@@ -393,8 +424,12 @@ template <> struct convert<plantuml> {
|
||||
template <> struct convert<filter> {
|
||||
static bool decode(const Node &node, filter &rhs)
|
||||
{
|
||||
if (node["namespaces"])
|
||||
rhs.namespaces = node["namespaces"].as<decltype(rhs.namespaces)>();
|
||||
if (node["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"])
|
||||
rhs.relationships =
|
||||
|
||||
@@ -46,7 +46,7 @@ struct plantuml {
|
||||
};
|
||||
|
||||
struct filter {
|
||||
std::vector<std::string> namespaces;
|
||||
std::vector<common::model::namespace_> namespaces;
|
||||
|
||||
// Valid values are:
|
||||
// - inheritance
|
||||
@@ -79,7 +79,7 @@ std::string to_string(const hint_t t);
|
||||
|
||||
struct inheritable_diagram_options {
|
||||
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{
|
||||
"include_relations_also_as_members", true};
|
||||
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(
|
||||
const std::pair<std::vector<std::string>, std::string> &name) const;
|
||||
bool should_include_package(const common::model::namespace_ &path) const;
|
||||
|
||||
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 std::string &name_) const;
|
||||
|
||||
bool should_include(const common::model::namespace_ &path) const;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ template <typename T> struct option {
|
||||
option(const std::string &name_,
|
||||
option_inherit_mode im = option_inherit_mode::override)
|
||||
: name{name_}
|
||||
, value{{}}
|
||||
, value{}
|
||||
{
|
||||
}
|
||||
option(const std::string &name_, const T &initial_value,
|
||||
|
||||
@@ -39,7 +39,7 @@ std::string to_string(CXString &&cxs)
|
||||
}
|
||||
|
||||
std::string full_name(
|
||||
const std::vector<std::string> ¤t_ns, const cppast::cpp_entity &e)
|
||||
const common::model::namespace_ ¤t_ns, const cppast::cpp_entity &e)
|
||||
{
|
||||
if (e.name().empty())
|
||||
return "";
|
||||
@@ -126,12 +126,13 @@ bool is_inside_class(const cppast::cpp_entity &e)
|
||||
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)
|
||||
{
|
||||
auto name_before_template = ::clanguml::util::split(full_name, "<")[0];
|
||||
auto ns = ::clanguml::util::split(name_before_template, "::");
|
||||
auto name = ns.back();
|
||||
auto ns = common::model::namespace_{
|
||||
::clanguml::util::split(name_before_template, "::")};
|
||||
auto name = ns.name();
|
||||
ns.pop_back();
|
||||
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(
|
||||
const std::vector<std::string> ¤t_ns, const cppast::cpp_entity &e)
|
||||
const common::model::namespace_ ¤t_ns, const cppast::cpp_entity &e)
|
||||
{
|
||||
if (e.name().find("::") != std::string::npos) {
|
||||
// the name already contains namespace, but it could be not
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "common/model/namespace.h"
|
||||
|
||||
#include <clang-c/CXCompilationDatabase.h>
|
||||
#include <clang-c/Index.h>
|
||||
#include <cppast/cpp_entity.hpp>
|
||||
@@ -41,13 +43,13 @@ namespace util {
|
||||
std::string to_string(CXString &&cxs);
|
||||
|
||||
std::string full_name(
|
||||
const std::vector<std::string> ¤t_ns, const cppast::cpp_entity &e);
|
||||
const common::model::namespace_ ¤t_ns, const cppast::cpp_entity &e);
|
||||
|
||||
std::string full_name(const cppast::cpp_type &t,
|
||||
const cppast::cpp_entity_index &idx, bool inside_class);
|
||||
|
||||
std::string fully_prefixed(
|
||||
const std::vector<std::string> ¤t_ns, const cppast::cpp_entity &e);
|
||||
const common::model::namespace_ ¤t_ns, const cppast::cpp_entity &e);
|
||||
|
||||
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::pair<std::vector<std::string>, std::string> split_ns(
|
||||
std::pair<common::model::namespace_, std::string> split_ns(
|
||||
const std::string &full_name);
|
||||
|
||||
bool is_inside_class(const cppast::cpp_entity &e);
|
||||
|
||||
@@ -39,9 +39,9 @@ void generator::generate_relationships(
|
||||
for (const auto &r : p.relationships()) {
|
||||
std::stringstream relstr;
|
||||
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';
|
||||
ostr << relstr.str();
|
||||
}
|
||||
|
||||
@@ -27,17 +27,17 @@ std::string diagram::to_alias(const std::string &full_name) const
|
||||
{
|
||||
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(
|
||||
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)
|
||||
throw error::uml_alias_missing(
|
||||
fmt::format("Missing alias for '{}'", full_name));
|
||||
fmt::format("Missing alias for '{}'", path.to_string()));
|
||||
|
||||
return package.value().alias();
|
||||
}
|
||||
|
||||
@@ -153,12 +153,12 @@ translation_unit_context::get_type_alias_template(
|
||||
|
||||
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(); }
|
||||
|
||||
const std::vector<std::string> &translation_unit_context::get_namespace() const
|
||||
const common::model::namespace_ &translation_unit_context::get_namespace() const
|
||||
{
|
||||
return namespace_;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
|
||||
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;
|
||||
|
||||
@@ -82,7 +82,7 @@ public:
|
||||
|
||||
private:
|
||||
// Current visitor namespace
|
||||
std::vector<std::string> namespace_;
|
||||
common::model::namespace_ namespace_;
|
||||
|
||||
// Reference to the cppast entity index
|
||||
cppast::cpp_entity_index &entity_index_;
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "translation_unit_visitor.h"
|
||||
|
||||
#include "common/model/namespace.h"
|
||||
|
||||
#include <cppast/cpp_alias_template.hpp>
|
||||
#include <cppast/cpp_array_type.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() &&
|
||||
!ns_declaration.is_inline()) {
|
||||
|
||||
std::vector<std::string> package_parent =
|
||||
ctx.get_namespace();
|
||||
auto package_path = package_parent;
|
||||
package_path.push_back(e.name());
|
||||
auto package_parent = ctx.get_namespace();
|
||||
auto package_path = package_parent | e.name();
|
||||
auto usn = common::model::namespace_{
|
||||
ctx.config().using_namespace()};
|
||||
|
||||
auto usn = util::split(
|
||||
ctx.config().using_namespace()[0], "::");
|
||||
|
||||
if (!util::starts_with(usn, package_path)) {
|
||||
if (!usn.starts_with(package_path)) {
|
||||
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_namespace(package_parent);
|
||||
p->set_namespace(package_path);
|
||||
|
||||
if (ns_declaration.comment().has_value())
|
||||
p->add_decorators(decorators::parse(
|
||||
@@ -303,10 +302,10 @@ void translation_unit_visitor::process_class_declaration(
|
||||
}
|
||||
|
||||
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) &&
|
||||
!util::starts_with(destination, ctx.get_namespace())) {
|
||||
if (!ctx.get_namespace().starts_with(destination) &&
|
||||
!destination.starts_with(ctx.get_namespace())) {
|
||||
relationship r{
|
||||
relationship_t::kDependency, std::get<0>(dependency)};
|
||||
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);
|
||||
|
||||
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) &&
|
||||
!util::starts_with(destination, ctx.get_namespace())) {
|
||||
if (!ctx.get_namespace().starts_with(destination) &&
|
||||
!destination.starts_with(ctx.get_namespace())) {
|
||||
relationship r{
|
||||
relationship_t::kDependency, std::get<0>(dependency)};
|
||||
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(
|
||||
resolve_alias(cppast::remove_cv(t_)), ctx.entity_index(), false);
|
||||
auto t_ns = util::split(fn, "::");
|
||||
auto t_name = t_ns.back();
|
||||
auto t_ns = common::model::namespace_{fn};
|
||||
auto t_name = t_ns.name();
|
||||
t_ns.pop_back();
|
||||
|
||||
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()) +
|
||||
"::" + 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;
|
||||
|
||||
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());
|
||||
|
||||
|
||||
@@ -44,8 +44,8 @@ generator::generator(
|
||||
|
||||
void generator::generate_call(const message &m, std::ostream &ostr) const
|
||||
{
|
||||
const auto from = ns_relative(m_config.using_namespace(), m.from);
|
||||
const auto to = ns_relative(m_config.using_namespace(), m.to);
|
||||
const auto from = m_config.using_namespace().relative(m.from);
|
||||
const auto to = m_config.using_namespace().relative(m.to);
|
||||
|
||||
ostr << '"' << from << "\" "
|
||||
<< 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
|
||||
// only if the return type is different than void
|
||||
if ((m.from != m.to) && (m.return_type != "void")) {
|
||||
const auto from = ns_relative(m_config.using_namespace(), m.from);
|
||||
const auto to = ns_relative(m_config.using_namespace(), m.to);
|
||||
const auto from = m_config.using_namespace().relative(m.from);
|
||||
const auto to = m_config.using_namespace().relative(m.to);
|
||||
|
||||
ostr << '"' << to << "\" "
|
||||
<< 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
|
||||
{
|
||||
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);
|
||||
ostr << "activate " << '"' << to << '"' << std::endl;
|
||||
if (m_model.sequences.find(m.to_usr) != m_model.sequences.end())
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "translation_unit_visitor.h"
|
||||
|
||||
#include "common/model/namespace.h"
|
||||
#include "translation_unit_context.h"
|
||||
|
||||
#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();
|
||||
|
||||
if (!ctx.config().should_include(
|
||||
util::split(cx::util::ns(caller), "::"), caller.name()))
|
||||
common::model::namespace_{cx::util::ns(caller)}, caller.name()))
|
||||
continue;
|
||||
|
||||
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 += "()";
|
||||
|
||||
if (!ctx.config().should_include(
|
||||
util::split(cx::util::ns(callee), "::"), callee.name()))
|
||||
common::model::namespace_{cx::util::ns(callee)}, callee.name()))
|
||||
continue;
|
||||
|
||||
m.to_usr = type_safe::get(function_call.get_callee_method_id());
|
||||
|
||||
@@ -68,6 +68,7 @@ std::string join(const std::vector<std::string> &toks, std::string delimiter)
|
||||
return fmt::format("{}", fmt::join(toks, delimiter));
|
||||
}
|
||||
|
||||
/*
|
||||
std::string ns_relative(
|
||||
const std::vector<std::string> &namespaces, const std::string &n)
|
||||
{
|
||||
@@ -93,6 +94,7 @@ std::string ns_relative(
|
||||
}
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
|
||||
std::string unqualify(const std::string &s)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
std::string ns_relative(
|
||||
const std::vector<std::string> &namespaces, const std::string &n);
|
||||
// std::string ns_relative(
|
||||
// const std::vector<std::string> &namespaces, const std::string &n);
|
||||
|
||||
/**
|
||||
* @brief Remove any qualifiers (e.g. const) from type.
|
||||
|
||||
@@ -26,7 +26,8 @@ TEST_CASE("t00002", "[test-case][class]")
|
||||
|
||||
REQUIRE(diagram->include().namespaces.size() == 1);
|
||||
REQUIRE_THAT(diagram->include().namespaces,
|
||||
VectorContains(std::string{"clanguml::t00002"}));
|
||||
VectorContains(
|
||||
clanguml::common::model::namespace_{"clanguml::t00002"}));
|
||||
|
||||
REQUIRE(diagram->exclude().namespaces.size() == 0);
|
||||
|
||||
|
||||
@@ -25,8 +25,6 @@ TEST_CASE("t00003", "[test-case][class]")
|
||||
REQUIRE(diagram->name == "t00003_class");
|
||||
|
||||
REQUIRE(diagram->include().namespaces.size() == 1);
|
||||
REQUIRE_THAT(diagram->include().namespaces,
|
||||
VectorContains(std::string{"clanguml::t00003"}));
|
||||
|
||||
REQUIRE(diagram->exclude().namespaces.size() == 0);
|
||||
|
||||
|
||||
@@ -25,9 +25,6 @@ TEST_CASE("t00004", "[test-case][class]")
|
||||
REQUIRE(diagram->name == "t00004_class");
|
||||
|
||||
REQUIRE(diagram->include().namespaces.size() == 1);
|
||||
REQUIRE_THAT(diagram->include().namespaces,
|
||||
VectorContains(std::string{"clanguml::t00004"}));
|
||||
|
||||
REQUIRE(diagram->exclude().namespaces.size() == 0);
|
||||
|
||||
REQUIRE(diagram->should_include("clanguml::t00004::A"));
|
||||
|
||||
@@ -53,7 +53,7 @@ TEST_CASE("Test config inherited", "[unit-test]")
|
||||
CHECK(cus.type() == clanguml::config::diagram_type::class_diagram);
|
||||
CHECK(cus.glob().size() == 1);
|
||||
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(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.glob().size() == 1);
|
||||
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.generate_method_arguments() ==
|
||||
clanguml::config::method_arguments::none);
|
||||
|
||||
@@ -6,8 +6,7 @@ diagrams:
|
||||
glob:
|
||||
- src/**/*.cc
|
||||
- src/**/*.h
|
||||
using_namespace:
|
||||
- clanguml
|
||||
using_namespace: clanguml
|
||||
generate_method_arguments: full
|
||||
generate_packages: true
|
||||
include:
|
||||
|
||||
72
tests/test_model.cc
Normal file
72
tests/test_model.cc
Normal 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>>");
|
||||
}
|
||||
@@ -35,19 +35,19 @@ TEST_CASE("Test split", "[unit-test]")
|
||||
|
||||
CHECK(split("std::vector::detail::", "::") == C{"std", "vector", "detail"});
|
||||
}
|
||||
|
||||
TEST_CASE("Test ns_relative", "[unit-test]")
|
||||
{
|
||||
using namespace clanguml::util;
|
||||
|
||||
CHECK(ns_relative({}, "std::vector") == "std::vector");
|
||||
CHECK(ns_relative({"std"}, "std::vector") == "vector");
|
||||
CHECK(ns_relative({"std"}, "const std::vector&") == "const vector&");
|
||||
CHECK(ns_relative({"std", "clanguml::t0"},
|
||||
"static const std::vector<clanguml::t0::a>&") ==
|
||||
"static const vector<a>&");
|
||||
CHECK(ns_relative({"clanguml::t0"}, "clanguml::t0") == "t0");
|
||||
}
|
||||
//
|
||||
// TEST_CASE("Test ns_relative", "[unit-test]")
|
||||
//{
|
||||
// using namespace clanguml::util;
|
||||
//
|
||||
// CHECK(ns_relative({}, "std::vector") == "std::vector");
|
||||
// CHECK(ns_relative({"std"}, "std::vector") == "vector");
|
||||
// CHECK(ns_relative({"std"}, "const std::vector&") == "const vector&");
|
||||
// CHECK(ns_relative({"std", "clanguml::t0"},
|
||||
// "static const std::vector<clanguml::t0::a>&") ==
|
||||
// "static const vector<a>&");
|
||||
// CHECK(ns_relative({"clanguml::t0"}, "clanguml::t0") == "t0");
|
||||
//}
|
||||
|
||||
TEST_CASE("Test abbreviate", "[unit-test]")
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user