Added initial structure for include diagram generation

This commit is contained in:
Bartek Kryza
2022-04-04 23:55:12 +02:00
parent 0301173a52
commit 46e8885c41
39 changed files with 1268 additions and 356 deletions

View File

@@ -41,10 +41,10 @@ common::model::diagram_t diagram::type() const
return common::model::diagram_t::kClass;
}
type_safe::optional_ref<const clanguml::common::model::element> diagram::get(
const std::string &full_name) const
type_safe::optional_ref<const clanguml::common::model::diagram_element>
diagram::get(const std::string &full_name) const
{
type_safe::optional_ref<const clanguml::common::model::element> res;
type_safe::optional_ref<const clanguml::common::model::diagram_element> res;
res = get_class(full_name);

View File

@@ -32,7 +32,8 @@ namespace clanguml::class_diagram::model {
class diagram : public clanguml::common::model::diagram,
public clanguml::common::model::nested_trait<
clanguml::common::model::element> {
clanguml::common::model::element,
clanguml::common::model::namespace_> {
public:
diagram() = default;
@@ -43,7 +44,7 @@ public:
common::model::diagram_t type() const override;
type_safe::optional_ref<const clanguml::common::model::element> get(
type_safe::optional_ref<const clanguml::common::model::diagram_element> get(
const std::string &full_name) const override;
const std::vector<type_safe::object_ref<const class_>> classes() const;

View File

@@ -17,7 +17,9 @@
*/
#pragma once
#include "diagram_element.h"
#include "enums.h"
#include "namespace.h"
#include <type_safe/optional_ref.hpp>
@@ -27,7 +29,6 @@
namespace clanguml::common::model {
class diagram_filter;
class namespace_;
class element;
class relationship;
@@ -38,7 +39,7 @@ public:
virtual diagram_t type() const = 0;
virtual type_safe::optional_ref<const element> get(
virtual type_safe::optional_ref<const diagram_element> get(
const std::string &full_name) const = 0;
diagram(const diagram &) = delete;

View File

@@ -0,0 +1,99 @@
/**
* src/common/model/diagram_element.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.
*/
#include "diagram_element.h"
#include "util/util.h"
#include <ostream>
namespace clanguml::common::model {
std::atomic_uint64_t diagram_element::m_nextId = 1;
diagram_element::diagram_element()
: m_id{m_nextId++}
{
}
std::string diagram_element::alias() const
{
return fmt::format("C_{:010}", m_id);
}
void diagram_element::add_relationship(relationship &&cr)
{
if (cr.destination().empty()) {
LOG_DBG("Skipping relationship '{}' - {} - '{}' due empty "
"destination",
cr.destination(), to_string(cr.type()), full_name(true));
return;
}
if ((cr.type() == relationship_t::kInstantiation) &&
(cr.destination() == full_name(true))) {
LOG_DBG("Skipping self instantiation relationship for {}",
cr.destination());
return;
}
LOG_DBG("Adding relationship: '{}' - {} - '{}'", cr.destination(),
to_string(cr.type()), full_name(true));
if (!util::contains(relationships_, cr))
relationships_.emplace_back(std::move(cr));
}
std::vector<relationship> &diagram_element::relationships()
{
return relationships_;
}
const std::vector<relationship> &diagram_element::relationships() const
{
return relationships_;
}
void diagram_element::append(const decorated_element &e)
{
decorated_element::append(e);
}
inja::json diagram_element::context() const
{
inja::json ctx;
ctx["name"] = name();
ctx["alias"] = alias();
ctx["full_name"] = full_name(false);
return ctx;
}
bool operator==(const diagram_element &l, const diagram_element &r)
{
return l.full_name(false) == r.full_name(false);
}
std::ostream &operator<<(std::ostream &out, const diagram_element &rhs)
{
out << "(" << rhs.name() << ", full_name=[" << rhs.full_name(false) << "])";
return out;
}
}

View File

@@ -0,0 +1,71 @@
/**
* src/common/model/diagram_element.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 "decorated_element.h"
#include "relationship.h"
#include "util/util.h"
#include <inja/inja.hpp>
#include <atomic>
#include <exception>
#include <string>
#include <vector>
namespace clanguml::common::model {
class diagram_element : public decorated_element {
public:
diagram_element();
virtual ~diagram_element() = default;
std::string alias() const;
void set_name(const std::string &name) { name_ = name; }
std::string name() const { return name_; }
virtual std::string full_name(bool relative) const { return name(); }
std::vector<relationship> &relationships();
const std::vector<relationship> &relationships() const;
void add_relationship(relationship &&cr);
void append(const decorated_element &e);
friend bool operator==(const diagram_element &l, const diagram_element &r);
friend std::ostream &operator<<(
std::ostream &out, const diagram_element &rhs);
virtual inja::json context() const;
protected:
const uint64_t m_id{0};
private:
std::string name_;
std::vector<relationship> relationships_;
static std::atomic_uint64_t m_nextId;
};
}

View File

@@ -24,39 +24,11 @@
namespace clanguml::common::model {
std::atomic_uint64_t element::m_nextId = 1;
element::element(const namespace_ &using_namespace)
: using_namespace_{using_namespace}
, m_id{m_nextId++}
{
}
std::string element::alias() const { return fmt::format("C_{:010}", m_id); }
void element::add_relationship(relationship &&cr)
{
if (cr.destination().empty()) {
LOG_DBG("Skipping relationship '{}' - {} - '{}' due empty "
"destination",
cr.destination(), to_string(cr.type()), full_name(true));
return;
}
if ((cr.type() == relationship_t::kInstantiation) &&
(cr.destination() == full_name(true))) {
LOG_DBG("Skipping self instantiation relationship for {}",
cr.destination());
return;
}
LOG_DBG("Adding relationship: '{}' - {} - '{}'", cr.destination(),
to_string(cr.type()), full_name(true));
if (!util::contains(relationships_, cr))
relationships_.emplace_back(std::move(cr));
}
void element::set_using_namespaces(const namespace_ &un)
{
using_namespace_ = un;
@@ -64,15 +36,6 @@ void element::set_using_namespaces(const namespace_ &un)
const namespace_ &element::using_namespace() const { return using_namespace_; }
std::vector<relationship> &element::relationships() { return relationships_; }
const std::vector<relationship> &element::relationships() const
{
return relationships_;
}
void element::append(const element &e) { decorated_element::append(e); }
inja::json element::context() const
{
inja::json ctx;

View File

@@ -17,7 +17,7 @@
*/
#pragma once
#include "decorated_element.h"
#include "diagram_element.h"
#include "namespace.h"
#include "relationship.h"
#include "source_location.h"
@@ -32,18 +32,12 @@
namespace clanguml::common::model {
class element : public decorated_element, public source_location {
class element : public diagram_element, public source_location {
public:
element(const namespace_ &using_namespace);
virtual ~element() = default;
std::string alias() const;
void set_name(const std::string &name) { name_ = name; }
std::string name() const { return name_; }
std::string name_and_ns() const
{
auto ns = ns_ | name();
@@ -59,36 +53,26 @@ public:
return ns_.relative_to(using_namespace_);
}
virtual std::string full_name(bool relative) const { return name_and_ns(); }
const namespace_ &path() const { return ns_; }
std::string full_name(bool relative) const override
{
return name_and_ns();
}
void set_using_namespaces(const namespace_ &un);
const namespace_ &using_namespace() const;
std::vector<relationship> &relationships();
const std::vector<relationship> &relationships() const;
void add_relationship(relationship &&cr);
void append(const element &e);
friend bool operator==(const element &l, const element &r);
friend std::ostream &operator<<(std::ostream &out, const element &rhs);
virtual inja::json context() const;
protected:
const uint64_t m_id{0};
inja::json context() const override;
private:
std::string name_;
namespace_ ns_;
namespace_ using_namespace_;
std::vector<relationship> relationships_;
type_safe::optional<source_location> location_;
static std::atomic_uint64_t m_nextId;
// type_safe::optional<source_location> location_;
};
}

View File

@@ -35,7 +35,8 @@ enum class relationship_t {
kAssociation,
kInstantiation,
kFriendship,
kDependency
kDependency,
kInclusion
};
enum class message_t { kCall, kReturn };

View File

@@ -17,194 +17,3 @@
*/
#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(); }
type_safe::optional<namespace_> namespace_::parent() const
{
if (size() <= 1) {
return {};
}
namespace_ res{*this};
res.pop_back();
return {std::move(res)};
}
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_);
}
bool namespace_::ends_with(const namespace_ &right) const
{
return util::ends_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
{
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_;
}
bool operator<(const namespace_ &left, const namespace_ &right)
{
return std::hash<namespace_>{}(left) < std::hash<namespace_>{}(right);
}
std::string namespace_::name() const
{
assert(size() > 0);
return namespace_path_.back();
}
}

View File

@@ -17,78 +17,20 @@
*/
#pragma once
#include "path.h"
#include <string>
#include <type_safe/optional.hpp>
#include <vector>
namespace clanguml::common::model {
class namespace_ {
public:
using container_type = std::vector<std::string>;
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);
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();
type_safe::optional<namespace_> parent() const;
bool starts_with(const namespace_ &right) const;
bool ends_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_;
struct ns_path_separator {
static constexpr std::string_view value = "::";
};
using namespace_ = path<ns_path_separator>;
}
namespace std {
@@ -96,7 +38,7 @@ namespace std {
template <> struct hash<clanguml::common::model::namespace_> {
std::size_t operator()(const clanguml::common::model::namespace_ &key) const
{
using clanguml::common::model::namespace_;
using clanguml::common::model::path;
std::size_t seed = key.size();
for (const auto &ns : key) {
@@ -108,4 +50,4 @@ template <> struct hash<clanguml::common::model::namespace_> {
}
};
}
}

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/element.h
* src/common/model/nested_trait.h
*
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
*
@@ -26,7 +26,7 @@
#include <vector>
namespace clanguml::common::model {
template <typename T> class nested_trait {
template <typename T, typename Path> class nested_trait {
public:
nested_trait() = default;
@@ -52,31 +52,31 @@ public:
}
template <typename V = T>
void add_element(namespace_ ns, std::unique_ptr<V> p)
void add_element(const Path &path, std::unique_ptr<V> p)
{
assert(p);
LOG_DBG(
"Adding nested element {} at path {}", p->name(), ns.to_string());
"Adding nested element {} at path {}", p->name(), path.to_string());
if (ns.is_empty()) {
if (path.is_empty()) {
add_element(std::move(p));
return;
}
auto parent = get_element(ns);
auto parent = get_element(path);
if (parent && dynamic_cast<nested_trait<T> *>(&parent.value()))
dynamic_cast<nested_trait<T> &>(parent.value())
if (parent && dynamic_cast<nested_trait<T, Path> *>(&parent.value()))
dynamic_cast<nested_trait<T, Path> &>(parent.value())
.template add_element<V>(std::move(p));
else {
spdlog::error("No parent element found at: {}", ns.to_string());
spdlog::error("No parent element found at: {}", path.to_string());
throw std::runtime_error(
"No parent element found for " + ns.to_string());
"No parent element found for " + path.to_string());
}
}
template <typename V = T> auto get_element(const namespace_ &path) const
template <typename V = T> auto get_element(const Path &path) const
{
LOG_DBG("Getting nested element at path: {}", path.to_string());
@@ -93,9 +93,9 @@ public:
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>(
namespace_{path.begin() + 1, path.end()});
if (dynamic_cast<nested_trait<T, Path> *>(&p.value()))
return dynamic_cast<nested_trait<T, Path> &>(p.value())
.get_element<V>(Path{path.begin() + 1, path.end()});
return type_safe::optional_ref<V>{};
}
@@ -145,9 +145,10 @@ public:
std::cout << "--- Printing tree:\n";
}
for (const auto &e : d) {
if (dynamic_cast<nested_trait<T> *>(e.get())) {
if (dynamic_cast<nested_trait<T, Path> *>(e.get())) {
std::cout << std::string(level, ' ') << "[" << *e << "]\n";
dynamic_cast<nested_trait<T> *>(e.get())->print_tree(level + 1);
dynamic_cast<nested_trait<T, Path> *>(e.get())->print_tree(
level + 1);
}
else {
std::cout << std::string(level, ' ') << "- " << *e << "]\n";

View File

@@ -33,7 +33,7 @@ namespace clanguml::common::model {
class package : public element,
public stylable_element,
public nested_trait<element> {
public nested_trait<element, namespace_> {
public:
package(const common::model::namespace_ &using_namespace);

207
src/common/model/path.h Normal file
View File

@@ -0,0 +1,207 @@
/**
* src/common/model/path.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 "util/util.h"
#include <string>
#include <type_safe/optional.hpp>
#include <vector>
namespace clanguml::common::model {
template <typename Sep> class path {
public:
using container_type = std::vector<std::string>;
path() = default;
path(const std::string &ns) { path_ = util::split(ns, Sep::value); }
path(container_type::const_iterator begin,
container_type::const_iterator end)
{
std::copy(begin, end, std::back_inserter(path_));
}
path(const path &right) noexcept = default;
path &operator=(const path &right) noexcept = default;
path(path &&right) noexcept = default;
path &operator=(path &&right) noexcept = default;
path(std::initializer_list<std::string> ns)
{
if ((ns.size() == 1) && util::contains(*ns.begin(), Sep::value))
path_ = util::split(*ns.begin(), Sep::value);
else
path_ = ns;
}
explicit path(const std::vector<std::string> &ns)
{
if ((ns.size() == 1) && util::contains(*ns.begin(), Sep::value))
path_ = util::split(*ns.begin(), Sep::value);
else
path_ = ns;
}
friend bool operator==(const path<Sep> &left, const path<Sep> &right)
{
return left.path_ == right.path_;
}
friend bool operator<(const path<Sep> &left, const path<Sep> &right)
{
return std::hash<path<Sep>>{}(left) < std::hash<path<Sep>>{}(right);
}
std::string to_string() const
{
return fmt::format("{}", fmt::join(path_, Sep::value));
}
bool is_empty() const { return path_.empty(); }
size_t size() const { return path_.size(); }
path operator|(const path &right) const
{
path res{*this};
res.append(right);
return res;
}
void operator|=(const path &right) { append(right); }
path operator|(const std::string &right) const
{
path res{*this};
res.append(right);
return res;
}
void operator|=(const std::string &right) { append(right); }
std::string &operator[](const int index) { return path_[index]; }
const std::string &operator[](const int index) const
{
return path_[index];
}
void append(const std::string &ns) { path_.push_back(ns); }
void append(const path &ns)
{
for (const auto &n : ns) {
append(n);
}
}
void pop_back() { path_.pop_back(); }
type_safe::optional<path> parent() const
{
if (size() <= 1) {
return {};
}
path res{*this};
res.pop_back();
return {std::move(res)};
}
bool starts_with(const path &right) const
{
return util::starts_with(path_, right.path_);
}
bool ends_with(const path &right) const
{
return util::ends_with(path_, right.path_);
}
path common_path(const path &right) const
{
path res{};
for (auto i = 0U; i < std::min(size(), right.size()); i++) {
if (path_[i] == right[i])
res |= path_[i];
else
break;
}
return res;
}
path relative_to(const path &right) const
{
path res{*this};
if (res.starts_with(right))
util::remove_prefix(res.path_, right.path_);
return res;
}
std::string relative(const std::string &name) const
{
if (is_empty())
return name;
if (name == to_string())
return name;
auto res = name;
auto ns_prefix = to_string() + std::string{Sep::value};
auto it = res.find(ns_prefix);
while (it != std::string::npos) {
res.erase(it, ns_prefix.size());
it = res.find(ns_prefix);
}
return res;
}
std::string name() const
{
assert(size() > 0);
return path_.back();
}
path::container_type::iterator begin() { return path_.begin(); }
path::container_type::iterator end() { return path_.end(); }
path::container_type::const_iterator cbegin() const
{
return path_.cbegin();
}
path::container_type::const_iterator cend() const { return path_.cend(); }
path::container_type::const_iterator begin() const { return path_.begin(); }
path::container_type::const_iterator end() const { return path_.end(); }
private:
container_type path_;
};
}

View File

@@ -66,6 +66,8 @@ std::string to_string(const diagram_type t)
return "sequence";
case diagram_type::package_diagram:
return "package";
case diagram_type::include_diagram:
return "include";
default:
assert(false);
}
@@ -136,6 +138,11 @@ diagram_type package_diagram::type() const
return diagram_type::package_diagram;
}
diagram_type include_diagram::type() const
{
return diagram_type::include_diagram;
}
template <>
void append_value<std::vector<std::string>>(
std::vector<std::string> &l, const std::vector<std::string> &r)
@@ -159,6 +166,7 @@ using clanguml::config::filter;
using clanguml::config::generate_links_config;
using clanguml::config::git_config;
using clanguml::config::hint_t;
using clanguml::config::include_diagram;
using clanguml::config::layout_hint;
using clanguml::config::method_arguments;
using clanguml::config::package_diagram;
@@ -228,6 +236,9 @@ std::shared_ptr<clanguml::config::diagram> parse_diagram_config(const Node &d)
else if (diagram_type == "package") {
return std::make_shared<package_diagram>(d.as<package_diagram>());
}
else if (diagram_type == "include") {
return std::make_shared<include_diagram>(d.as<include_diagram>());
}
LOG_ERROR("Diagrams of type {} are not supported... ", diagram_type);
@@ -470,7 +481,7 @@ template <> struct convert<sequence_diagram> {
};
//
// class_diagram Yaml decoder
// package_diagram Yaml decoder
//
template <> struct convert<package_diagram> {
static bool decode(const Node &node, package_diagram &rhs)
@@ -484,6 +495,21 @@ template <> struct convert<package_diagram> {
}
};
//
// include_diagram Yaml decoder
//
template <> struct convert<include_diagram> {
static bool decode(const Node &node, include_diagram &rhs)
{
if (!decode_diagram(node, rhs))
return false;
get_option(node, rhs.layout);
return true;
}
};
//
// layout_hint Yaml decoder
//

View File

@@ -35,7 +35,13 @@
namespace clanguml {
namespace config {
enum class diagram_type { class_diagram, sequence_diagram, package_diagram };
enum class diagram_type {
class_diagram,
sequence_diagram,
package_diagram,
include_diagram
};
enum class method_arguments { full, abbreviated, none };
struct plantuml {
@@ -149,6 +155,14 @@ struct package_diagram : public diagram {
option<layout_hints> layout{"layout"};
};
struct include_diagram : public diagram {
virtual ~include_diagram() = default;
diagram_type type() const override;
option<layout_hints> layout{"layout"};
};
struct config : public inheritable_diagram_options {
// the glob list is additive and relative to the current
// directory

View File

@@ -0,0 +1,64 @@
/**
* src/package_diagram/generators/plantuml/package_diagram_generator.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.
*/
#include "include_diagram_generator.h"
#include "util/error.h"
namespace clanguml::include_diagram::generators::plantuml {
generator::generator(diagram_config &config, diagram_model &model)
: common_generator<diagram_config, diagram_model>{config, model}
{
}
void generator::generate_relationships(
const source_file &f, std::ostream &ostr) const
{
LOG_DBG("Generating relationships for file {}", f.full_name(true));
}
void generator::generate(const source_file &f, std::ostream &ostr) const
{
LOG_DBG("Generating source_file {}", f.name());
}
void generator::generate(std::ostream &ostr) const
{
ostr << "@startuml" << '\n';
generate_plantuml_directives(ostr, m_config.puml().before);
for (const auto &p : m_model) {
generate(dynamic_cast<source_file &>(*p), ostr);
ostr << '\n';
}
// Process package relationships
for (const auto &p : m_model) {
generate_relationships(dynamic_cast<source_file &>(*p), ostr);
ostr << '\n';
}
generate_config_layout_hints(ostr);
generate_plantuml_directives(ostr, m_config.puml().after);
ostr << "@enduml" << '\n';
}
}

View File

@@ -0,0 +1,70 @@
/**
* src/include_diagram/generators/plantuml/include_diagram_generator.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 "common/generators/plantuml/generator.h"
#include "common/model/package.h"
#include "common/model/relationship.h"
#include "config/config.h"
#include "cx/compilation_database.h"
#include "include_diagram/model/diagram.h"
#include "include_diagram/model/source_file.h"
#include "include_diagram/visitor/translation_unit_visitor.h"
#include "util/util.h"
#include <cppast/cpp_entity_index.hpp>
#include <cppast/libclang_parser.hpp>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <sstream>
namespace clanguml {
namespace include_diagram {
namespace generators {
namespace plantuml {
using diagram_config = clanguml::config::include_diagram;
using diagram_model = clanguml::include_diagram::model::diagram;
template <typename C, typename D>
using common_generator =
clanguml::common::generators::plantuml::generator<C, D>;
using clanguml::common::model::access_t;
using clanguml::common::model::package;
using clanguml::common::model::relationship_t;
using clanguml::include_diagram::model::source_file;
using namespace clanguml::util;
class generator : public common_generator<diagram_config, diagram_model> {
public:
generator(diagram_config &config, diagram_model &model);
void generate_relationships(const source_file &p, std::ostream &ostr) const;
void generate(const source_file &e, std::ostream &ostr) const;
void generate(std::ostream &ostr) const;
};
}
}
}
}

View File

@@ -0,0 +1,65 @@
/**
* src/include_diagram/model/diagram.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.
*/
#include "diagram.h"
#include "util/error.h"
#include "util/util.h"
namespace clanguml::include_diagram::model {
common::model::diagram_t diagram::type() const
{
return common::model::diagram_t::kPackage;
}
type_safe::optional_ref<const common::model::diagram_element> diagram::get(
const std::string &full_name) const
{
return get_file(full_name);
}
void diagram::add_file(std::unique_ptr<include_diagram::model::source_file> &&f)
{
LOG_DBG("Adding source file: {}, {}", f->name(), f->full_name(true));
files_.emplace_back(*f);
add_element(f->path(), std::move(f));
}
type_safe::optional_ref<const include_diagram::model::source_file>
diagram::get_file(const std::string &name) const
{
for (const auto &p : files_) {
if (p.get().full_name(false) == name) {
return {p};
}
}
return type_safe::nullopt;
}
std::string diagram::to_alias(const std::string &full_name) const
{
LOG_DBG("Looking for alias for {}", full_name);
return full_name;
}
}

View File

@@ -0,0 +1,59 @@
/**
* src/include_diagram/model/diagram.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 "common/model/diagram.h"
#include "common/model/package.h"
#include "source_file.h"
#include <type_safe/optional_ref.hpp>
#include <string>
#include <vector>
namespace clanguml::include_diagram::model {
class diagram : public clanguml::common::model::diagram,
public clanguml::common::model::nested_trait<source_file,
filesystem_path> {
public:
diagram() = default;
diagram(const diagram &) = delete;
diagram(diagram &&) = default;
diagram &operator=(const diagram &) = delete;
diagram &operator=(diagram &&) = default;
common::model::diagram_t type() const override;
type_safe::optional_ref<const common::model::diagram_element> get(
const std::string &full_name) const;
void add_file(std::unique_ptr<include_diagram::model::source_file> &&f);
type_safe::optional_ref<const include_diagram::model::source_file> get_file(
const std::string &name) const;
std::string to_alias(const std::string &full_name) const;
private:
std::vector<
type_safe::object_ref<const include_diagram::model::source_file, false>>
files_;
};
}

View File

@@ -0,0 +1,19 @@
/**
* src/include_diagram/model/source_file.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.
*/
#include "source_file.h"

View File

@@ -0,0 +1,95 @@
/**
* src/include_diagram/model/source_file.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 "common/model/diagram_element.h"
#include "common/model/nested_trait.h"
#include "common/model/path.h"
#include "common/model/stylable_element.h"
#include "util/util.h"
#include <spdlog/spdlog.h>
#include <type_safe/optional_ref.hpp>
#include <set>
#include <string>
#include <vector>
namespace clanguml::include_diagram::model {
enum class source_file_type { kDirectory, kHeader, kImplementation };
struct fs_path_sep {
static constexpr std::string_view value = "/";
};
using filesystem_path = common::model::path<fs_path_sep>;
class source_file
: public common::model::diagram_element,
public common::model::stylable_element,
public common::model::nested_trait<common::model::diagram_element,
filesystem_path> {
public:
source_file() = default;
void set_path(const filesystem_path &p) { path_ = p; }
source_file(const source_file &) = delete;
source_file(source_file &&) = default;
source_file &operator=(const source_file &) = delete;
source_file &operator=(source_file &&) = delete;
const filesystem_path &path() const { return path_; }
std::string full_name(bool relative) const override
{
return (path_ | name()).to_string();
}
void add_file(std::unique_ptr<include_diagram::model::source_file> &&f)
{
LOG_DBG("Adding source file: {}, {}", f->name(), f->full_name(true));
add_element(f->path(), std::move(f));
}
private:
filesystem_path path_;
};
}
namespace std {
template <> struct hash<clanguml::include_diagram::model::filesystem_path> {
std::size_t operator()(
const clanguml::include_diagram::model::filesystem_path &key) const
{
using clanguml::common::model::path;
std::size_t seed = key.size();
for (const auto &ns : key) {
seed ^= std::hash<std::string>{}(ns) + 0x6a3712b5 + (seed << 6) +
(seed >> 2);
}
return seed;
}
};
}

View File

@@ -0,0 +1,43 @@
/**
* src/include_diagram/model/visitor/element_visitor_context.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.
*/
#include "element_visitor_context.h"
#include "translation_unit_context.h"
namespace clanguml::include_diagram::visitor {
template <typename T>
element_visitor_context<T>::element_visitor_context(
clanguml::include_diagram::model::diagram &diagram, T &element)
: element_{element}
, diagram_{diagram}
{
}
template <typename T> T &element_visitor_context<T>::element()
{
return element_;
}
template <typename T>
clanguml::include_diagram::model::diagram &element_visitor_context<T>::diagram()
{
return diagram_;
}
}

View File

@@ -0,0 +1,42 @@
/**
* src/include_diagram/model/visitor/element_visitor_context.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 "include_diagram/model/diagram.h"
namespace clanguml::include_diagram::visitor {
class translation_unit_context;
template <typename T> class element_visitor_context {
public:
element_visitor_context(
clanguml::include_diagram::model::diagram &diagram, T &element);
T &element();
clanguml::include_diagram::model::diagram &diagram();
private:
translation_unit_context *ctx_;
T &element_;
clanguml::include_diagram::model::diagram &diagram_;
};
}

View File

@@ -0,0 +1,63 @@
/**
* src/include_diagram/visitor/translation_unit_context.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.
*/
#include "translation_unit_context.h"
#include "cx/util.h"
namespace clanguml::include_diagram::visitor {
translation_unit_context::translation_unit_context(
cppast::cpp_entity_index &idx,
clanguml::include_diagram::model::diagram &diagram,
const clanguml::config::include_diagram &config)
: entity_index_{idx}
, diagram_{diagram}
, config_{config}
{
}
const cppast::cpp_entity_index &translation_unit_context::entity_index() const
{
return entity_index_;
}
const clanguml::config::include_diagram &
translation_unit_context::config() const
{
return config_;
}
clanguml::include_diagram::model::diagram &translation_unit_context::diagram()
{
return diagram_;
}
void translation_unit_context::set_current_file(
type_safe::optional_ref<include_diagram::model::source_file> f)
{
current_file_ = f;
}
type_safe::optional_ref<include_diagram::model::source_file>
translation_unit_context::get_current_file() const
{
return current_file_;
}
}

View File

@@ -0,0 +1,62 @@
/**
* src/include_diagram/visitor/translation_unit_context.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 "common/model/package.h"
#include "config/config.h"
#include "include_diagram/model/diagram.h"
#include <cppast/cpp_entity_index.hpp>
#include <cppast/cpp_namespace.hpp>
#include <cppast/cpp_type.hpp>
#include <type_safe/reference.hpp>
namespace clanguml::include_diagram::visitor {
class translation_unit_context {
public:
translation_unit_context(cppast::cpp_entity_index &idx,
clanguml::include_diagram::model::diagram &diagram,
const clanguml::config::include_diagram &config);
const cppast::cpp_entity_index &entity_index() const;
const clanguml::config::include_diagram &config() const;
clanguml::include_diagram::model::diagram &diagram();
void set_current_file(
type_safe::optional_ref<include_diagram::model::source_file> p);
type_safe::optional_ref<include_diagram::model::source_file>
get_current_file() const;
private:
// Reference to the cppast entity index
cppast::cpp_entity_index &entity_index_;
// Reference to the output diagram model
clanguml::include_diagram::model::diagram &diagram_;
// Reference to class diagram config
const clanguml::config::include_diagram &config_;
type_safe::optional_ref<include_diagram::model::source_file> current_file_;
};
}

View File

@@ -0,0 +1,53 @@
/**
* src/include_diagram/visitor/translation_unit_visitor.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.
*/
#include "translation_unit_visitor.h"
#include <cppast/cpp_entity_kind.hpp>
#include <cppast/cpp_preprocessor.hpp>
namespace clanguml::include_diagram::visitor {
using clanguml::include_diagram::model::diagram;
translation_unit_visitor::translation_unit_visitor(
cppast::cpp_entity_index &idx,
clanguml::include_diagram::model::diagram &diagram,
const clanguml::config::include_diagram &config)
: ctx{idx, diagram, config}
{
}
void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
{
cppast::visit(file,
[&, this](const cppast::cpp_entity &e, cppast::visitor_info info) {
if (e.kind() == cppast::cpp_entity_kind::include_directive_t) {
const auto &inc =
static_cast<const cppast::cpp_include_directive &>(e);
auto file_name = std::filesystem::path(inc.full_path());
auto f = std::make_unique<model::source_file>();
f->set_path(file_name.parent_path().string());
f->set_name(file_name.filename().string());
}
});
}
}

View File

@@ -0,0 +1,51 @@
/**
* src/include_diagram/visitor/translation_unit_visitor.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 "config/config.h"
#include "cx/cursor.h"
#include "include_diagram/model/diagram.h"
#include "include_diagram/visitor/translation_unit_context.h"
#include <clang-c/CXCompilationDatabase.h>
#include <clang-c/Index.h>
#include <cppast/visitor.hpp>
#include <type_safe/reference.hpp>
#include <common/model/enums.h>
#include <common/model/package.h>
#include <functional>
#include <map>
#include <memory>
#include <string>
namespace clanguml::include_diagram::visitor {
class translation_unit_visitor {
public:
translation_unit_visitor(cppast::cpp_entity_index &idx,
clanguml::include_diagram::model::diagram &diagram,
const clanguml::config::include_diagram &config);
void operator()(const cppast::cpp_entity &file);
private:
// ctx allows to track current visitor context, e.g. current namespace
translation_unit_context ctx;
};
}

View File

@@ -51,7 +51,7 @@ type_safe::optional_ref<const common::model::package> diagram::get_package(
return type_safe::nullopt;
}
type_safe::optional_ref<const clanguml::common::model::element> diagram::get(
type_safe::optional_ref<const common::model::diagram_element> diagram::get(
const std::string &full_name) const
{
return get_package(full_name);

View File

@@ -29,7 +29,8 @@ namespace clanguml::package_diagram::model {
class diagram : public clanguml::common::model::diagram,
public clanguml::common::model::nested_trait<
clanguml::common::model::element> {
clanguml::common::model::element,
clanguml::common::model::namespace_> {
public:
diagram() = default;
@@ -40,7 +41,7 @@ public:
common::model::diagram_t type() const override;
type_safe::optional_ref<const common::model::element> get(
type_safe::optional_ref<const common::model::diagram_element> get(
const std::string &full_name) const;
void add_package(std::unique_ptr<common::model::package> &&p);

View File

@@ -28,7 +28,7 @@ common::model::diagram_t diagram::type() const
return common::model::diagram_t::kSequence;
}
type_safe::optional_ref<const clanguml::common::model::element> diagram::get(
type_safe::optional_ref<const common::model::diagram_element> diagram::get(
const std::string &full_name) const
{
return {};

View File

@@ -36,7 +36,7 @@ public:
common::model::diagram_t type() const override;
type_safe::optional_ref<const clanguml::common::model::element> get(
type_safe::optional_ref<const common::model::diagram_element> get(
const std::string &full_name) const;
std::string to_alias(const std::string &full_name) const;

View File

@@ -101,7 +101,7 @@ std::string rtrim(const std::string &s)
std::string trim(const std::string &s) { return rtrim(ltrim(s)); }
std::vector<std::string> split(std::string str, std::string delimiter)
std::vector<std::string> split(std::string str, std::string_view delimiter)
{
std::vector<std::string> result;
@@ -124,7 +124,8 @@ std::vector<std::string> split(std::string str, std::string delimiter)
return result;
}
std::string join(const std::vector<std::string> &toks, std::string delimiter)
std::string join(
const std::vector<std::string> &toks, std::string_view delimiter)
{
return fmt::format("{}", fmt::join(toks, delimiter));
}

View File

@@ -83,9 +83,10 @@ std::string get_git_toplevel_dir();
*
* @return Vector of string tokens.
*/
std::vector<std::string> split(std::string str, std::string delimiter);
std::vector<std::string> split(std::string str, std::string_view delimiter);
std::string join(const std::vector<std::string> &toks, std::string delimiter);
std::string join(
const std::vector<std::string> &toks, std::string_view delimiter);
/**
* @brief Remove any qualifiers (e.g. const) from type.

10
tests/t40001/.clang-uml Normal file
View File

@@ -0,0 +1,10 @@
compilation_database_dir: ..
output_directory: puml
diagrams:
t40001_include:
type: include
glob:
- ../../tests/t40001/t40001.cc
plantuml:
before:
- "' t40001 test include diagram"

10
tests/t40001/t40001.cc Normal file
View File

@@ -0,0 +1,10 @@
#include <string>
#include <vector>
#include "t40001_include1.h"
namespace clanguml {
namespace t40001 {
} // namespace t40001
} // namespace clanguml

View File

@@ -0,0 +1,7 @@
#pragma once
namespace clanguml::t40001 {
int foo() { return 0; }
}

40
tests/t40001/test_case.h Normal file
View File

@@ -0,0 +1,40 @@
/**
* tests/t40001/test_case.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.
*/
TEST_CASE("t40001", "[test-case][package]")
{
auto [config, db] = load_config("t40001");
auto diagram = config.diagrams["t40001_include"];
REQUIRE(diagram->name == "t40001_include");
auto model = generate_include_diagram(db, diagram);
REQUIRE(model->name() == "t40001_include");
auto puml = generate_include_puml(diagram, *model);
AliasMatcher _A(puml);
REQUIRE_THAT(puml, StartsWith("@startuml"));
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
save_puml(
"./" + config.output_directory() + "/" + diagram->name + ".puml", puml);
}

View File

@@ -103,6 +103,22 @@ generate_package_diagram(cppast::libclang_compilation_database &db,
db, diagram->name, dynamic_cast<diagram_config &>(*diagram));
}
std::unique_ptr<clanguml::include_diagram::model::diagram>
generate_include_diagram(cppast::libclang_compilation_database &db,
std::shared_ptr<clanguml::config::diagram> diagram)
{
using diagram_config = clanguml::config::include_diagram;
using diagram_model = clanguml::include_diagram::model::diagram;
using diagram_visitor =
clanguml::include_diagram::visitor::translation_unit_visitor;
inject_diagram_options(diagram);
return clanguml::common::generators::plantuml::generate<diagram_model,
diagram_config, diagram_visitor>(
db, diagram->name, dynamic_cast<diagram_config &>(*diagram));
}
std::string generate_sequence_puml(
std::shared_ptr<clanguml::config::diagram> config,
clanguml::sequence_diagram::model::diagram &model)
@@ -145,6 +161,20 @@ std::string generate_package_puml(
return ss.str();
}
std::string generate_include_puml(
std::shared_ptr<clanguml::config::diagram> config,
clanguml::include_diagram::model::diagram &model)
{
using namespace clanguml::include_diagram::generators::plantuml;
std::stringstream ss;
ss << generator(
dynamic_cast<clanguml::config::include_diagram &>(*config), model);
return ss.str();
}
void save_puml(const std::string &path, const std::string &puml)
{
std::filesystem::path p{path};
@@ -218,6 +248,11 @@ using namespace clanguml::test::matchers;
#include "t30006/test_case.h"
#include "t30007/test_case.h"
//
// Include diagram tests
//
#include "t40001/test_case.h"
//
// Other tests (e.g. configuration file)
//

View File

@@ -24,6 +24,8 @@
#include "class_diagram/visitor/translation_unit_visitor.h"
#include "config/config.h"
#include "cx/compilation_database.h"
#include "include_diagram/generators/plantuml/include_diagram_generator.h"
#include "include_diagram/visitor/translation_unit_visitor.h"
#include "package_diagram/generators/plantuml/package_diagram_generator.h"
#include "package_diagram/visitor/translation_unit_visitor.h"
#include "sequence_diagram/generators/plantuml/sequence_diagram_generator.h"