This commit is contained in:
Bartek Kryza
2022-07-18 23:41:37 +02:00
parent 88a87edc42
commit 8a7e89cb63
32 changed files with 491 additions and 648 deletions

View File

@@ -23,9 +23,9 @@
#include "util/util.h"
//#include <cppast/libclang_parser.hpp>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Tooling/CompilationDatabase.h>
#include <clang/Tooling/Tooling.h>
#include <clang/Frontend/CompilerInstance.h>
#include <glob/glob.hpp>
#include <inja/inja.hpp>
@@ -146,23 +146,28 @@ void generator<C, D>::generate_config_layout_hints(std::ostream &ostr) const
{
using namespace clanguml::util;
const auto &uns = m_config.using_namespace();
// const auto &uns = m_config.using_namespace();
// Generate layout hints
for (const auto &[entity, hints] : m_config.layout()) {
for (const auto &[entity_name, hints] : m_config.layout()) {
for (const auto &hint : hints) {
std::stringstream hint_str;
try {
hint_str << m_model.to_alias(uns.relative(entity))
<< " -[hidden]"
auto element_opt = m_model.get(
m_config.using_namespace().relative(entity_name));
auto hint_element_opt = m_model.get(
m_config.using_namespace().relative(hint.entity));
if (!element_opt || !hint_element_opt)
continue;
hint_str << element_opt.value().get().alias() << " -[hidden]"
<< clanguml::config::to_string(hint.hint) << "- "
<< m_model.to_alias(uns.relative(hint.entity)) << '\n';
<< hint_element_opt.value().get().alias() << '\n';
ostr << hint_str.str();
}
catch (clanguml::error::uml_alias_missing &e) {
LOG_DBG("=== Skipping layout hint from {} to {} due "
"to: {}",
entity, hint.entity, e.what());
entity_name, hint.entity, e.what());
}
}
}
@@ -181,10 +186,17 @@ void generator<C, D>::generate_plantuml_directives(
// Now search for alias @A() directives in the text
std::tuple<std::string, size_t, size_t> alias_match;
while (util::find_element_alias(directive, alias_match)) {
auto alias = m_model.to_alias(
m_config.using_namespace().relative(std::get<0>(alias_match)));
directive.replace(
std::get<1>(alias_match), std::get<2>(alias_match), alias);
const auto full_name =
m_config.using_namespace() | std::get<0>(alias_match);
auto element_opt = m_model.get(full_name.to_string());
if (element_opt)
directive.replace(std::get<1>(alias_match),
std::get<2>(alias_match),
element_opt.value().get().alias());
else
directive.replace(std::get<1>(alias_match),
std::get<2>(alias_match), "UNKNOWN_ALIAS");
}
ostr << directive << '\n';
}
@@ -242,8 +254,8 @@ public:
virtual void HandleTranslationUnit(clang::ASTContext &ast_context)
{
// const auto* tud = ast_context.getTranslationUnitDecl();
//// tud->dump();
// const auto* tud = ast_context.getTranslationUnitDecl();
//// tud->dump();
visitor_.TraverseDecl(ast_context.getTranslationUnitDecl());
}
};
@@ -402,9 +414,11 @@ template <typename C, typename D> void generator<C, D>::init_env()
// is equivalent to the old syntax:
// "note left of @A(ClassA): This is a note"
m_env.add_callback("alias", 1, [this](inja::Arguments &args) {
auto alias_match = args[0]->get<std::string>();
return m_model.to_alias(
m_config.using_namespace().relative(alias_match));
auto alias_match =
m_config.using_namespace() | args[0]->get<std::string>();
auto element_opt = m_model.get(alias_match.to_string());
return element_opt.value().get().alias();
});
m_env.add_callback("comment", 1, [this](inja::Arguments &args) {
@@ -419,7 +433,7 @@ template <typename C, typename D> void generator<C, D>::init_env()
}
if (element.has_value()) {
auto comment = element.value().comment();
auto comment = element.value().get().comment();
if (comment.has_value())
res = comment.value();

View File

@@ -22,8 +22,6 @@
#include "namespace.h"
#include "source_file.h"
#include <type_safe/optional_ref.hpp>
#include <memory>
#include <string>
@@ -40,8 +38,9 @@ public:
virtual diagram_t type() const = 0;
virtual type_safe::optional_ref<const diagram_element> get(
const std::string &full_name) const = 0;
virtual std::optional<
std::reference_wrapper<const clanguml::common::model::diagram_element>>
get(const std::string &full_name) const = 0;
diagram(const diagram &) = delete;
diagram(diagram &&);
@@ -63,8 +62,12 @@ public:
bool should_include(const relationship r) const;
bool should_include(const relationship_t r) const;
bool should_include(const access_t s) const;
virtual bool has_element(const diagram_element::id_t id) const
{
return false;
}
bool should_include(const namespace_ &ns, const std::string &name) const;
virtual bool should_include(const namespace_ &ns, const std::string &name) const;
private:
std::string name_;

View File

@@ -27,26 +27,25 @@ namespace clanguml::common::model {
std::atomic_uint64_t diagram_element::m_nextId = 1;
diagram_element::diagram_element()
: m_id{m_nextId++}
: id_{0}
{
}
diagram_element::id_t diagram_element::id() const { return id_; }
void diagram_element::set_id(diagram_element::id_t id) { id_ = id; }
std::string diagram_element::alias() const
{
return fmt::format("C_{:010}", m_id);
assert(id_ >= 0);
return fmt::format("C_{:022}", 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))) {
(cr.destination() == id())) {
LOG_DBG("Skipping self instantiation relationship for {}",
cr.destination());
return;
@@ -86,7 +85,8 @@ inja::json diagram_element::context() const
bool operator==(const diagram_element &l, const diagram_element &r)
{
return l.full_name(false) == r.full_name(false);
return l.id() == r.id();
//return l.full_name(false) == r.full_name(false);
}
std::ostream &operator<<(std::ostream &out, const diagram_element &rhs)

View File

@@ -32,10 +32,16 @@ namespace clanguml::common::model {
class diagram_element : public decorated_element {
public:
using id_t = int64_t;
diagram_element();
virtual ~diagram_element() = default;
id_t id() const;
void set_id(id_t id);
std::string alias() const;
void set_name(const std::string &name) { name_ = name; }
@@ -59,10 +65,8 @@ public:
virtual inja::json context() const;
protected:
const uint64_t m_id{0};
private:
id_t id_;
std::string name_;
std::vector<relationship> relationships_;

View File

@@ -28,59 +28,59 @@ namespace clanguml::common::model {
namespace detail {
template <>
const std::vector<type_safe::object_ref<const class_diagram::model::class_>> &
view(const class_diagram::model::diagram &d)
const clanguml::common::reference_vector<class_diagram::model::class_> &view(
const class_diagram::model::diagram &d)
{
return d.classes();
}
template <>
const std::vector<type_safe::object_ref<const class_diagram::model::enum_>> &
view(const class_diagram::model::diagram &d)
const clanguml::common::reference_vector<class_diagram::model::enum_> &view(
const class_diagram::model::diagram &d)
{
return d.enums();
}
template <>
const std::vector<type_safe::object_ref<const common::model::package>> &view(
const clanguml::common::reference_vector<common::model::package> &view(
const package_diagram::model::diagram &d)
{
return d.packages();
}
template <>
const std::vector<type_safe::object_ref<const common::model::source_file>> &
view(const include_diagram::model::diagram &d)
const clanguml::common::reference_vector<common::model::source_file> &view(
const include_diagram::model::diagram &d)
{
return d.files();
}
template <>
const type_safe::optional_ref<const class_diagram::model::class_> get(
const clanguml::common::optional_ref<class_diagram::model::class_> get(
const class_diagram::model::diagram &d, const std::string &full_name)
{
return d.get_class(full_name);
}
template <>
const type_safe::optional_ref<const common::model::package> get(
const clanguml::common::optional_ref<const common::model::package> get(
const package_diagram::model::diagram &d, const std::string &full_name)
{
return d.get_package(full_name);
}
template <>
const type_safe::optional_ref<const common::model::source_file> get(
const clanguml::common::optional_ref<const common::model::source_file> get(
const include_diagram::model::diagram &d, const std::string &full_name)
{
return d.get_file(full_name);
}
template <>
std::string destination_comparator<common::model::source_file>(
clanguml::common::id_t destination_comparator<common::model::source_file>(
const common::model::source_file &f)
{
return f.alias();
return f.id();
}
} // namespace detail
@@ -221,9 +221,7 @@ tvl::value_t subclass_filter::match(const diagram &d, const element &e) const
const auto &cd = dynamic_cast<const class_diagram::model::diagram &>(d);
// First get all parents of element e
std::unordered_set<
type_safe::object_ref<const class_diagram::model::class_, false>>
parents;
clanguml::common::reference_set<class_diagram::model::class_> parents;
const auto &fn = e.full_name(false);
auto class_ref = cd.get_class(fn);
@@ -296,26 +294,25 @@ tvl::value_t context_filter::match(const diagram &d, const element &e) const
if (context_root.has_value()) {
// This is a direct match to the context root
if (context_root.value().full_name(false) == e.full_name(false))
if (context_root.value().get().id() == e.id())
return true;
// Return a positive match if the element e is in a direct
// relationship with any of the context_root's
for (const relationship &rel :
context_root.value().relationships()) {
if (rel.destination() == e.full_name(false))
context_root.value().get().relationships()) {
if (rel.destination() == e.id())
return true;
}
for (const relationship &rel : e.relationships()) {
if (rel.destination() ==
context_root.value().full_name(false))
if (rel.destination() == context_root.value().get().id())
return true;
}
// Return a positive match if the context_root is a parent
// of the element
for (const class_diagram::model::class_parent &p :
context_root.value().parents()) {
context_root.value().get().parents()) {
if (p.name() == e.full_name(false))
return true;
}
@@ -324,7 +321,8 @@ tvl::value_t context_filter::match(const diagram &d, const element &e) const
for (const class_diagram::model::class_parent &p :
static_cast<const class_diagram::model::class_ &>(e)
.parents()) {
if (p.name() == context_root.value().full_name(false))
if (p.name() ==
context_root.value().get().full_name(false))
return true;
}
}

View File

@@ -37,21 +37,20 @@ enum filter_t { kInclusive, kExclusive };
namespace detail {
template <typename ElementT, typename DiagramT>
const std::vector<type_safe::object_ref<const ElementT>> &view(
const DiagramT &d);
const clanguml::common::reference_vector<ElementT> &view(const DiagramT &d);
template <typename ElementT, typename DiagramT>
const type_safe::optional_ref<const ElementT> get(
const clanguml::common::optional_ref<ElementT> get(
const DiagramT &d, const std::string &full_name);
template <typename ElementT>
std::string destination_comparator(const ElementT &e)
template <typename ElementT> int64_t destination_comparator(const ElementT &e)
{
return e.full_name(false);
return e.id();
}
template <>
std::string destination_comparator(const common::model::source_file &f);
clanguml::common::id_t destination_comparator(
const common::model::source_file &f);
} // namespace detail
class filter_visitor {
@@ -177,7 +176,7 @@ struct edge_traversal_filter : public filter_visitor {
// Now check if the e element is contained in the calculated set
return std::any_of(matching_elements_.begin(), matching_elements_.end(),
[&e](const auto &te) {
return te->full_name(false) == e.full_name(false);
return te.get().full_name(false) == e.full_name(false);
});
}
@@ -192,12 +191,12 @@ private:
// Check if any of its relationships of type relationship_
// points to an element already in the matching_elements_
// set
for (const auto &rel : from_el->relationships()) {
for (const auto &rel : from_el.get().relationships()) {
// Consider only if connected by one of specified relationships
if (util::contains(relationships, rel.type())) {
for (const auto &to_el : to) {
if (rel.destination() ==
detail::destination_comparator(*to_el)) {
detail::destination_comparator(to_el.get())) {
const auto &to_add = forward_ ? to_el : from_el;
if (matching_elements_.insert(to_add).second)
added_new_element = true;
@@ -220,9 +219,9 @@ private:
cd, element.get().path().to_string());
while (parent.has_value()) {
parents.emplace(type_safe::ref(parent.value()));
parents.emplace(std::ref(parent.value()));
parent = detail::get<ElementT, DiagramT>(
cd, parent.value().path().to_string());
cd, parent.value().get().path().to_string());
}
});
@@ -272,8 +271,7 @@ private:
std::vector<std::string> roots_;
relationship_t relationship_;
mutable bool initialized_{false};
mutable std::unordered_set<type_safe::object_ref<const ElementT, false>>
matching_elements_;
mutable clanguml::common::reference_set<ElementT> matching_elements_;
bool forward_;
};

View File

@@ -29,10 +29,6 @@ element::element(const namespace_ &using_namespace)
{
}
element::id_t element::id() const { return id_; }
void element::set_id(element::id_t id) { id_ = id; }
void element::set_using_namespaces(const namespace_ &un)
{
using_namespace_ = un;

View File

@@ -34,16 +34,12 @@ namespace clanguml::common::model {
class element : public diagram_element, public source_location {
public:
using id_t = int64_t;
element(const namespace_ &using_namespace);
virtual ~element() = default;
id_t id() const;
void set_id(id_t id);
std::string name_and_ns() const
{
auto ns = ns_ | name();
@@ -77,7 +73,6 @@ public:
inja::json context() const override;
private:
id_t id_;
namespace_ ns_;
namespace_ using_namespace_;
};

View File

@@ -20,6 +20,7 @@
#include "common/model/element.h"
#include "common/model/nested_trait.h"
#include "common/model/stylable_element.h"
#include "common/types.h"
#include "util/util.h"
#include <spdlog/spdlog.h>
@@ -57,14 +58,14 @@ private:
namespace std {
template <>
struct hash<type_safe::object_ref<const clanguml::common::model::package>> {
struct hash<std::reference_wrapper<const clanguml::common::model::package>> {
std::size_t operator()(
const type_safe::object_ref<const clanguml::common::model::package>
const std::reference_wrapper<const clanguml::common::model::package>
&key) const
{
using clanguml::common::model::package;
using clanguml::common::id_t;
return std::hash<std::string>{}(key.get().full_name(false));
return std::hash<id_t>{}(key.get().id());
}
};
}
}

View File

@@ -20,7 +20,7 @@
namespace clanguml::common::model {
relationship::relationship(relationship_t type, const std::string &destination,
relationship::relationship(relationship_t type, int64_t destination,
access_t access, const std::string &label,
const std::string &multiplicity_source,
const std::string &multiplicity_destination)
@@ -37,12 +37,15 @@ void relationship::set_type(relationship_t type) noexcept { type_ = type; }
relationship_t relationship::type() const noexcept { return type_; }
void relationship::set_destination(const std::string &destination)
void relationship::set_destination(int64_t destination)
{
destination_ = destination;
}
std::string relationship::destination() const { return destination_; }
clanguml::common::id_t relationship::destination() const
{
return destination_;
}
void relationship::set_multiplicity_source(
const std::string &multiplicity_source)

View File

@@ -19,6 +19,7 @@
#include "common/model/decorated_element.h"
#include "common/model/stylable_element.h"
#include "common/types.h"
#include <string>
@@ -27,7 +28,7 @@ namespace clanguml::common::model {
class relationship : public common::model::decorated_element,
public common::model::stylable_element {
public:
relationship(relationship_t type, const std::string &destination,
relationship(relationship_t type, int64_t destination,
access_t access = access_t::kPublic, const std::string &label = "",
const std::string &multiplicity_source = "",
const std::string &multiplicity_destination = "");
@@ -37,8 +38,8 @@ public:
void set_type(relationship_t type) noexcept;
relationship_t type() const noexcept;
void set_destination(const std::string &destination);
std::string destination() const;
void set_destination(int64_t destination);
clanguml::common::id_t destination() const;
void set_multiplicity_source(const std::string &multiplicity_source);
std::string multiplicity_source() const;
@@ -57,7 +58,7 @@ public:
private:
relationship_t type_;
std::string destination_;
int64_t destination_;
std::string multiplicity_source_;
std::string multiplicity_destination_;
std::string label_;

View File

@@ -22,6 +22,7 @@
#include "common/model/path.h"
#include "common/model/source_location.h"
#include "common/model/stylable_element.h"
#include "common/types.h"
#include "util/util.h"
#include <spdlog/spdlog.h>
@@ -129,15 +130,19 @@ template <> struct hash<clanguml::common::model::filesystem_path> {
}
};
}
namespace std {
template <>
struct hash<type_safe::object_ref<const clanguml::common::model::source_file>> {
struct hash<
std::reference_wrapper<const clanguml::common::model::source_file>> {
std::size_t operator()(
const type_safe::object_ref<const clanguml::common::model::source_file>
const std::reference_wrapper<const clanguml::common::model::source_file>
&key) const
{
using clanguml::common::model::source_file;
using clanguml::common::id_t;
return std::hash<std::string>{}(key.get().full_name(false));
return std::hash<id_t>{}(key.get().id());
}
};
}
}

38
src/common/types.h Normal file
View File

@@ -0,0 +1,38 @@
/**
* src/class_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 <cstdint>
#include <optional>
#include <unordered_set>
#include <vector>
namespace clanguml::common {
using id_t = int64_t;
template <typename T>
using optional_ref = std::optional<std::reference_wrapper<const T>>;
template <typename T>
using reference_vector = std::vector<std::reference_wrapper<const T>>;
template <typename T>
using reference_set = std::unordered_set<std::reference_wrapper<const T>>;
} // namespace clang::common