WIP
This commit is contained in:
@@ -246,7 +246,7 @@ void generator::generate_relationships(
|
||||
{
|
||||
namespace plantuml_common = clanguml::common::generators::plantuml;
|
||||
|
||||
const auto &uns = m_config.using_namespace();
|
||||
// const auto &uns = m_config.using_namespace();
|
||||
|
||||
//
|
||||
// Process relationships
|
||||
@@ -264,14 +264,14 @@ void generator::generate_relationships(
|
||||
plantuml_common::to_plantuml(r.type(), r.style()));
|
||||
|
||||
std::stringstream relstr;
|
||||
std::string destination;
|
||||
clanguml::common::id_t destination;
|
||||
try {
|
||||
destination = r.destination();
|
||||
|
||||
// TODO: Refactor destination to a namespace qualified entity
|
||||
// name
|
||||
if (util::starts_with(destination, std::string{"::"}))
|
||||
destination = destination.substr(2, destination.size());
|
||||
// if (util::starts_with(destination, std::string{"::"}))
|
||||
// destination = destination.substr(2, destination.size());
|
||||
|
||||
LOG_DBG("=== Destination is: {}", destination);
|
||||
|
||||
@@ -284,8 +284,7 @@ void generator::generate_relationships(
|
||||
if (!r.multiplicity_destination().empty())
|
||||
puml_relation += " \"" + r.multiplicity_destination() + "\"";
|
||||
|
||||
auto target_alias = m_model.to_alias(
|
||||
m_config.using_namespace().relative(destination));
|
||||
auto target_alias = m_model.to_alias(destination);
|
||||
|
||||
if (m_generated_aliases.find(target_alias) ==
|
||||
m_generated_aliases.end())
|
||||
@@ -321,7 +320,7 @@ void generator::generate_relationships(
|
||||
for (const auto &b : c.parents()) {
|
||||
std::stringstream relstr;
|
||||
try {
|
||||
auto target_alias = m_model.to_alias(uns.relative(b.name()));
|
||||
auto target_alias = m_model.to_alias(b.id());
|
||||
|
||||
if (m_generated_aliases.find(target_alias) ==
|
||||
m_generated_aliases.end())
|
||||
@@ -369,13 +368,12 @@ void generator::generate_relationships(const enum_ &e, std::ostream &ostr) const
|
||||
if (!m_model.should_include(r.type()))
|
||||
continue;
|
||||
|
||||
std::string destination;
|
||||
clanguml::common::id_t destination;
|
||||
std::stringstream relstr;
|
||||
try {
|
||||
destination = r.destination();
|
||||
|
||||
auto target_alias = m_model.to_alias(
|
||||
m_config.using_namespace().relative(destination));
|
||||
auto target_alias = m_model.to_alias(destination);
|
||||
|
||||
if (m_generated_aliases.find(target_alias) ==
|
||||
m_generated_aliases.end())
|
||||
|
||||
@@ -23,11 +23,10 @@
|
||||
#include "common/model/element.h"
|
||||
#include "common/model/enums.h"
|
||||
#include "common/model/stylable_element.h"
|
||||
#include "common/types.h"
|
||||
#include "template_parameter.h"
|
||||
#include "type_alias.h"
|
||||
|
||||
#include <type_safe/reference.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -108,14 +107,14 @@ private:
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<
|
||||
type_safe::object_ref<const clanguml::class_diagram::model::class_>> {
|
||||
std::size_t operator()(const type_safe::object_ref<
|
||||
struct hash<std::reference_wrapper<
|
||||
const clanguml::class_diagram::model::class_>> {
|
||||
std::size_t operator()(const std::reference_wrapper<
|
||||
const clanguml::class_diagram::model::class_> &key) const
|
||||
{
|
||||
using clanguml::class_diagram::model::class_;
|
||||
using clanguml::common::id_t;
|
||||
|
||||
return std::hash<std::string>{}(key.get().full_name(false));
|
||||
return std::hash<id_t>{}(key.get().id());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/model/enums.h"
|
||||
#include "common/types.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -28,6 +29,11 @@ public:
|
||||
void set_name(const std::string &name);
|
||||
std::string name() const;
|
||||
|
||||
clanguml::common::id_t id() const noexcept { return id_; }
|
||||
void set_id(clanguml::common::id_t id) { id_ = id; }
|
||||
|
||||
void set_id(id_t id);
|
||||
|
||||
void is_virtual(bool is_virtual);
|
||||
bool is_virtual() const;
|
||||
|
||||
@@ -35,6 +41,7 @@ public:
|
||||
common::model::access_t access() const;
|
||||
|
||||
private:
|
||||
clanguml::common::id_t id_;
|
||||
std::string name_;
|
||||
bool is_virtual_{false};
|
||||
common::model::access_t access_;
|
||||
|
||||
@@ -25,12 +25,13 @@
|
||||
|
||||
namespace clanguml::class_diagram::model {
|
||||
|
||||
const std::vector<type_safe::object_ref<const class_>> &diagram::classes() const
|
||||
const std::vector<std::reference_wrapper<const class_>> &
|
||||
diagram::classes() const
|
||||
{
|
||||
return classes_;
|
||||
}
|
||||
|
||||
const std::vector<type_safe::object_ref<const enum_>> &diagram::enums() const
|
||||
const std::vector<std::reference_wrapper<const enum_>> &diagram::enums() const
|
||||
{
|
||||
return enums_;
|
||||
}
|
||||
@@ -40,10 +41,15 @@ common::model::diagram_t diagram::type() const
|
||||
return common::model::diagram_t::kClass;
|
||||
}
|
||||
|
||||
type_safe::optional_ref<const clanguml::common::model::diagram_element>
|
||||
std::optional<
|
||||
std::reference_wrapper<const clanguml::common::model::diagram_element>>
|
||||
diagram::get(const std::string &full_name) const
|
||||
{
|
||||
type_safe::optional_ref<const clanguml::common::model::diagram_element> res;
|
||||
// type_safe::optional_ref<const clanguml::common::model::diagram_element>
|
||||
// res;
|
||||
std::optional<
|
||||
std::reference_wrapper<const clanguml::common::model::diagram_element>>
|
||||
res;
|
||||
|
||||
res = get_class(full_name);
|
||||
|
||||
@@ -67,7 +73,7 @@ bool diagram::has_enum(const enum_ &e) const
|
||||
[&e](const auto &ee) { return ee.get().full_name() == e.full_name(); });
|
||||
}
|
||||
|
||||
type_safe::optional_ref<const class_> diagram::get_class(
|
||||
std::optional<std::reference_wrapper<const class_>> diagram::get_class(
|
||||
const std::string &name) const
|
||||
{
|
||||
for (const auto &c : classes_) {
|
||||
@@ -76,10 +82,10 @@ type_safe::optional_ref<const class_> diagram::get_class(
|
||||
}
|
||||
}
|
||||
|
||||
return type_safe::nullopt;
|
||||
return {};
|
||||
}
|
||||
|
||||
type_safe::optional_ref<const enum_> diagram::get_enum(
|
||||
std::optional<std::reference_wrapper<const enum_>> diagram::get_enum(
|
||||
const std::string &name) const
|
||||
{
|
||||
for (const auto &e : enums_) {
|
||||
@@ -88,7 +94,7 @@ type_safe::optional_ref<const enum_> diagram::get_enum(
|
||||
}
|
||||
}
|
||||
|
||||
return type_safe::nullopt;
|
||||
return {};
|
||||
}
|
||||
|
||||
void diagram::add_type_alias(std::unique_ptr<type_alias> &&ta)
|
||||
@@ -131,7 +137,7 @@ bool diagram::add_class(std::unique_ptr<class_> &&c)
|
||||
auto name_and_ns = ns | name;
|
||||
const auto &cc = *c;
|
||||
|
||||
auto cc_ref = type_safe::ref(cc);
|
||||
auto cc_ref = std::ref(cc);
|
||||
|
||||
if (!has_class(cc)) {
|
||||
if (add_element(ns, std::move(c)))
|
||||
@@ -159,7 +165,7 @@ bool diagram::add_enum(std::unique_ptr<enum_> &&e)
|
||||
|
||||
assert(!util::contains(e->name(), "::"));
|
||||
|
||||
auto e_ref = type_safe::ref(*e);
|
||||
auto e_ref = std::ref(*e);
|
||||
auto ns = e->get_relative_namespace();
|
||||
|
||||
if (!has_enum(*e)) {
|
||||
@@ -175,9 +181,9 @@ bool diagram::add_enum(std::unique_ptr<enum_> &&e)
|
||||
}
|
||||
|
||||
void diagram::get_parents(
|
||||
std::unordered_set<type_safe::object_ref<const class_>> &parents) const
|
||||
clanguml::common::reference_set<class_> &parents) const
|
||||
{
|
||||
bool found_new = false;
|
||||
bool found_new{false};
|
||||
for (const auto &parent : parents) {
|
||||
for (const auto &pp : parent.get().parents()) {
|
||||
const auto p = get_class(pp.name());
|
||||
@@ -194,25 +200,39 @@ void diagram::get_parents(
|
||||
}
|
||||
}
|
||||
|
||||
std::string diagram::to_alias(const std::string &full_name) const
|
||||
bool diagram::has_element(
|
||||
clanguml::common::model::diagram_element::id_t id) const
|
||||
{
|
||||
LOG_DBG("Looking for alias for {}", full_name);
|
||||
for (const auto &c : classes_) {
|
||||
if (c.get().id() == id)
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto &c : enums_) {
|
||||
if (c.get().id() == id)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string diagram::to_alias(
|
||||
clanguml::common::model::diagram_element::id_t id) const
|
||||
{
|
||||
LOG_DBG("Looking for alias for {}", id);
|
||||
|
||||
for (const auto &c : classes_) {
|
||||
const auto &cc = c.get();
|
||||
if (cc.full_name() == full_name) {
|
||||
return c->alias();
|
||||
if (c.get().id() == id) {
|
||||
return c.get().alias();
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &e : enums_) {
|
||||
if (e.get().full_name() == full_name) {
|
||||
return e->alias();
|
||||
}
|
||||
if (e.get().id() == id)
|
||||
return e.get().alias();
|
||||
}
|
||||
|
||||
throw error::uml_alias_missing(
|
||||
fmt::format("Missing alias for {}", full_name));
|
||||
throw error::uml_alias_missing(fmt::format("Missing alias for {}", id));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "common/model/diagram.h"
|
||||
#include "common/model/nested_trait.h"
|
||||
#include "common/model/package.h"
|
||||
#include "common/types.h"
|
||||
#include "enum.h"
|
||||
#include "type_alias.h"
|
||||
|
||||
@@ -44,21 +45,22 @@ public:
|
||||
|
||||
common::model::diagram_t type() const override;
|
||||
|
||||
type_safe::optional_ref<const clanguml::common::model::diagram_element> get(
|
||||
const std::string &full_name) const override;
|
||||
std::optional<
|
||||
std::reference_wrapper<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;
|
||||
const std::vector<std::reference_wrapper<const class_>> &classes() const;
|
||||
|
||||
const std::vector<type_safe::object_ref<const enum_>> &enums() const;
|
||||
const std::vector<std::reference_wrapper<const enum_>> &enums() const;
|
||||
|
||||
bool has_class(const class_ &c) const;
|
||||
|
||||
bool has_enum(const enum_ &e) const;
|
||||
|
||||
type_safe::optional_ref<const class_> get_class(
|
||||
std::optional<std::reference_wrapper<const class_>> get_class(
|
||||
const std::string &name) const;
|
||||
|
||||
type_safe::optional_ref<const enum_> get_enum(
|
||||
std::optional<std::reference_wrapper<const enum_>> get_enum(
|
||||
const std::string &name) const;
|
||||
|
||||
void add_type_alias(std::unique_ptr<type_alias> &&ta);
|
||||
@@ -69,16 +71,22 @@ public:
|
||||
|
||||
bool add_package(std::unique_ptr<common::model::package> &&p);
|
||||
|
||||
std::string to_alias(const std::string &full_name) const;
|
||||
std::string to_alias(
|
||||
clanguml::common::model::diagram_element::id_t id) const;
|
||||
|
||||
void get_parents(
|
||||
std::unordered_set<type_safe::object_ref<const class_>> &parents) const;
|
||||
void get_parents(clanguml::common::reference_set<class_> &parents) const;
|
||||
|
||||
friend void print_diagram_tree(const diagram &d, const int level);
|
||||
|
||||
bool has_element(
|
||||
const clanguml::common::model::diagram_element::id_t id) const override;
|
||||
|
||||
private:
|
||||
std::vector<type_safe::object_ref<const class_, false>> classes_;
|
||||
std::vector<type_safe::object_ref<const enum_, false>> enums_;
|
||||
std::vector<std::reference_wrapper<const class_>> classes_;
|
||||
std::vector<std::reference_wrapper<const enum_>> enums_;
|
||||
|
||||
// std::vector<type_safe::object_ref<const class_, false>> classes_;
|
||||
// std::vector<type_safe::object_ref<const enum_, false>> enums_;
|
||||
std::map<std::string, std::unique_ptr<type_alias>> type_aliases_;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,23 +17,8 @@
|
||||
*/
|
||||
|
||||
#include "translation_unit_visitor.h"
|
||||
|
||||
//#include "cppast/cpp_function_type.hpp"
|
||||
#include "cx/util.h"
|
||||
|
||||
//#include <cppast/cpp_alias_template.hpp>
|
||||
//#include <cppast/cpp_array_type.hpp>
|
||||
//#include <cppast/cpp_class_template.hpp>
|
||||
//#include <cppast/cpp_entity_kind.hpp>
|
||||
//#include <cppast/cpp_enum.hpp>
|
||||
//#include <cppast/cpp_friend.hpp>
|
||||
//#include <cppast/cpp_function_type.hpp>
|
||||
//#include <cppast/cpp_member_function.hpp>
|
||||
//#include <cppast/cpp_member_variable.hpp>
|
||||
//#include <cppast/cpp_namespace.hpp>
|
||||
//#include <cppast/cpp_template.hpp>
|
||||
//#include <cppast/cpp_type_alias.hpp>
|
||||
//#include <cppast/cpp_variable.hpp>
|
||||
#include <clang/Basic/FileManager.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
@@ -78,9 +63,11 @@ access_t access_specifier_to_access_t(clang::AccessSpecifier access_specifier)
|
||||
std::optional<clanguml::common::model::namespace_> get_enclosing_namespace(
|
||||
const clang::DeclContext *decl)
|
||||
{
|
||||
if (!decl->getEnclosingNamespaceContext()->isNamespace())
|
||||
return {};
|
||||
|
||||
const auto *namespace_declaration =
|
||||
static_cast<const clang::NamespaceDecl *>(
|
||||
decl->getEnclosingNamespaceContext());
|
||||
clang::cast<clang::NamespaceDecl>(decl->getEnclosingNamespaceContext());
|
||||
|
||||
if (namespace_declaration == nullptr) {
|
||||
return {};
|
||||
@@ -92,8 +79,22 @@ std::optional<clanguml::common::model::namespace_> get_enclosing_namespace(
|
||||
|
||||
std::string to_string(const clang::QualType &type, const clang::ASTContext &ctx)
|
||||
{
|
||||
clang::PrintingPolicy print_policy(ctx.getLangOpts());
|
||||
return type.getAsString(print_policy);
|
||||
const clang::PrintingPolicy print_policy(ctx.getLangOpts());
|
||||
|
||||
auto result{type.getAsString(print_policy)};
|
||||
|
||||
if (result.find('<') != std::string::npos) {
|
||||
auto canonical_type_name =
|
||||
type.getCanonicalType().getAsString(print_policy);
|
||||
|
||||
auto canonical_qualified_name =
|
||||
canonical_type_name.substr(0, canonical_type_name.find('<'));
|
||||
auto result_template_arguments = result.substr(result.find('<'));
|
||||
|
||||
result = canonical_qualified_name + result_template_arguments;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
|
||||
@@ -115,6 +116,7 @@ bool translation_unit_visitor::VisitEnumDecl(clang::EnumDecl *enm)
|
||||
ns.pop_back();
|
||||
e.set_name(enm->getNameAsString());
|
||||
e.set_namespace(ns);
|
||||
e.set_id(enm->getID());
|
||||
|
||||
process_comment(*enm, e);
|
||||
set_source_location(*enm, e);
|
||||
@@ -129,7 +131,7 @@ bool translation_unit_visitor::VisitEnumDecl(clang::EnumDecl *enm)
|
||||
}
|
||||
|
||||
if (enm->getParent()->isRecord()) {
|
||||
// process_record_containment(*enm, e);
|
||||
process_record_containment(*enm, e);
|
||||
}
|
||||
|
||||
auto namespace_declaration = detail::get_enclosing_namespace(enm);
|
||||
@@ -143,15 +145,56 @@ bool translation_unit_visitor::VisitEnumDecl(clang::EnumDecl *enm)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool translation_unit_visitor::VisitClassTemplateDecl(
|
||||
clang::ClassTemplateDecl *cls)
|
||||
{
|
||||
if (source_manager_.isInSystemHeader(cls->getSourceRange().getBegin()))
|
||||
return true;
|
||||
|
||||
auto c_ptr = process_class_declaration(cls->getTemplatedDecl());
|
||||
|
||||
c_ptr->set_id(cls->getID());
|
||||
|
||||
if (!c_ptr)
|
||||
return true;
|
||||
|
||||
process_template_parameters(*cls, *c_ptr);
|
||||
|
||||
if (diagram_.should_include(*c_ptr)) {
|
||||
diagram_.add_class(std::move(c_ptr));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *cls)
|
||||
{
|
||||
if (source_manager_.isInSystemHeader(cls->getSourceRange().getBegin()))
|
||||
return true;
|
||||
|
||||
// Check if the class was already processed within VisitClassTemplateDecl()
|
||||
if (diagram_.has_element(cls->getID()))
|
||||
return true;
|
||||
|
||||
// TODO: Add support for classes defined in function/method bodies
|
||||
if (cls->isLocalClass())
|
||||
return true;
|
||||
|
||||
auto c_ptr = process_class_declaration(cls);
|
||||
|
||||
if (!c_ptr)
|
||||
return true;
|
||||
|
||||
if (diagram_.should_include(*c_ptr)) {
|
||||
diagram_.add_class(std::move(c_ptr));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<class_> translation_unit_visitor::process_class_declaration(
|
||||
clang::CXXRecordDecl *cls)
|
||||
{
|
||||
auto c_ptr = std::make_unique<class_>(config_.using_namespace());
|
||||
auto &c = *c_ptr;
|
||||
|
||||
@@ -161,12 +204,13 @@ bool translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *cls)
|
||||
ns.pop_back();
|
||||
c.set_name(cls->getNameAsString());
|
||||
c.set_namespace(ns);
|
||||
c.set_id(cls->getID());
|
||||
|
||||
process_comment(*cls, c);
|
||||
set_source_location(*cls, c);
|
||||
|
||||
if (c.skip())
|
||||
return true;
|
||||
return {};
|
||||
|
||||
c.set_style(c.style_spec());
|
||||
|
||||
@@ -176,22 +220,82 @@ bool translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *cls)
|
||||
// Process class bases
|
||||
process_class_bases(cls, c);
|
||||
|
||||
// Process class template arguments
|
||||
// if (cls->isTemplateDecl()) {
|
||||
// bool skip = process_template_parameters(cls, c, tspec);
|
||||
// if (skip)
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (cls->getParent()->isRecord()) {
|
||||
process_record_containment(*cls, c);
|
||||
}
|
||||
|
||||
if (diagram_.should_include(c)) {
|
||||
diagram_.add_class(std::move(c_ptr));
|
||||
return c_ptr;
|
||||
}
|
||||
|
||||
bool translation_unit_visitor::process_template_parameters(
|
||||
const clang::ClassTemplateDecl &template_declaration, class_ &c)
|
||||
{
|
||||
LOG_DBG("Processing class {} template parameters...",
|
||||
template_declaration.getQualifiedNameAsString());
|
||||
|
||||
if (template_declaration.getTemplateParameters() == nullptr)
|
||||
return false;
|
||||
|
||||
for (const auto *parameter :
|
||||
*template_declaration.getTemplateParameters()) {
|
||||
if (clang::dyn_cast_or_null<clang::TemplateTypeParmDecl>(parameter)) {
|
||||
const auto *template_type_parameter =
|
||||
clang::dyn_cast_or_null<clang::TemplateTypeParmDecl>(parameter);
|
||||
template_parameter ct;
|
||||
ct.set_type("");
|
||||
ct.is_template_parameter(true);
|
||||
ct.set_name(template_type_parameter->getNameAsString());
|
||||
ct.set_default_value("");
|
||||
ct.is_variadic(template_type_parameter->isParameterPack());
|
||||
|
||||
c.add_template(std::move(ct));
|
||||
}
|
||||
else if (clang::dyn_cast_or_null<clang::NonTypeTemplateParmDecl>(
|
||||
parameter)) {
|
||||
const auto *template_nontype_parameter =
|
||||
clang::dyn_cast_or_null<clang::NonTypeTemplateParmDecl>(
|
||||
parameter);
|
||||
template_parameter ct;
|
||||
ct.set_type("");
|
||||
ct.is_template_parameter(false);
|
||||
ct.set_name(template_nontype_parameter->getNameAsString());
|
||||
ct.set_default_value("");
|
||||
ct.is_variadic(template_nontype_parameter->isParameterPack());
|
||||
|
||||
c.add_template(std::move(ct));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
/*
|
||||
auto scope = cppast::cpp_scope_name(type_safe::ref(cls));
|
||||
// Even if this is a template the scope.is_templated() returns
|
||||
// false when the template parameter list is empty
|
||||
if (scope.is_templated()) {
|
||||
process_scope_template_parameters(c, scope);
|
||||
}
|
||||
else {
|
||||
LOG_DBG("Class {} is templated but it's scope {} is not - "
|
||||
"probably this is a specialization",
|
||||
cls.name(), scope.name());
|
||||
|
||||
// Add specialization arguments
|
||||
if (tspec) {
|
||||
if (!tspec.value().arguments_exposed()) {
|
||||
process_unexposed_template_specialization_parameters(tspec, c);
|
||||
}
|
||||
else {
|
||||
process_exposed_template_specialization_parameters(tspec, c);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG_DBG("Skipping template class declaration which has only "
|
||||
"unexposed arguments but no tspec provided");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void translation_unit_visitor::process_record_containment(
|
||||
@@ -210,9 +314,10 @@ void translation_unit_visitor::process_record_containment(
|
||||
element.set_namespace(namespace_declaration.value());
|
||||
}
|
||||
|
||||
static_cast<const clang::RecordDecl *>(record.getParent())->getID();
|
||||
const auto id =
|
||||
static_cast<const clang::RecordDecl *>(record.getParent())->getID();
|
||||
|
||||
element.add_relationship({relationship_t::kContainment, parent_name});
|
||||
element.add_relationship({relationship_t::kContainment, id});
|
||||
}
|
||||
|
||||
void translation_unit_visitor::process_class_bases(
|
||||
@@ -224,6 +329,8 @@ void translation_unit_visitor::process_class_bases(
|
||||
to_string(base.getType(), cls->getASTContext())};
|
||||
|
||||
cp.set_name(name_and_ns.to_string());
|
||||
cp.set_id(
|
||||
base.getType()->getAs<clang::RecordType>()->getDecl()->getID());
|
||||
cp.is_virtual(base.isVirtual());
|
||||
|
||||
cp.set_access(
|
||||
@@ -304,6 +411,9 @@ bool translation_unit_visitor::find_relationships(const clang::QualType &type,
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
std::string type_name = type.getAsString();
|
||||
(void)type_name;
|
||||
|
||||
if (type->isPointerType()) {
|
||||
relationship_hint = relationship_t::kAssociation;
|
||||
find_relationships(
|
||||
@@ -412,13 +522,9 @@ void translation_unit_visitor::add_relationships(class_ &c,
|
||||
std::optional<std::string> label)
|
||||
{
|
||||
for (const auto &[target, relationship_type] : relationships) {
|
||||
if (target.empty())
|
||||
continue;
|
||||
|
||||
auto [target_ns, target_name] = cx::util::split_ns(target);
|
||||
if (diagram().should_include(target_ns, target_name) &&
|
||||
(relationship_type != relationship_t::kNone) &&
|
||||
(target != c.name_and_ns())) {
|
||||
if (diagram().has_element(target) &&
|
||||
(relationship_type != relationship_t::kNone) /*&&
|
||||
(target != c.name_and_ns())*/) {
|
||||
relationship r{relationship_type, target};
|
||||
if (label)
|
||||
r.set_label(label.value());
|
||||
@@ -453,9 +559,8 @@ void translation_unit_visitor::process_static_field(
|
||||
return;
|
||||
|
||||
if (!field.skip_relationship()) {
|
||||
std::vector<
|
||||
std::pair<std::string, clanguml::common::model::relationship_t>>
|
||||
relationships;
|
||||
found_relationships_t relationships;
|
||||
|
||||
// find relationship for the type
|
||||
find_relationships(field_declaration.getType(), relationships,
|
||||
relationship_t::kAssociation);
|
||||
@@ -468,6 +573,50 @@ void translation_unit_visitor::process_static_field(
|
||||
c.add_member(std::move(field));
|
||||
}
|
||||
|
||||
std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
|
||||
const clang::TemplateSpecializationType &template_type,
|
||||
std::optional<clanguml::class_diagram::model::class_ *> parent)
|
||||
{
|
||||
//
|
||||
// Create class_ instance to hold the template instantiation
|
||||
//
|
||||
auto template_instantiation_ptr =
|
||||
std::make_unique<class_>(config_.using_namespace());
|
||||
auto &template_instantiation = *template_instantiation_ptr;
|
||||
std::string full_template_specialization_name =
|
||||
to_string(template_type.desugar(),
|
||||
template_type.getAsCXXRecordDecl()->getASTContext());
|
||||
|
||||
const auto *template_record{
|
||||
template_type.getTemplateName().getAsTemplateDecl()};
|
||||
std::string qualified_name = template_record->getQualifiedNameAsString();
|
||||
namespace_ ns{qualified_name};
|
||||
ns.pop_back();
|
||||
template_instantiation.set_name(template_record->getNameAsString());
|
||||
template_instantiation.set_namespace(ns);
|
||||
template_instantiation.set_id(template_record->getID() +
|
||||
std::hash<std::string>{}(full_template_specialization_name));
|
||||
|
||||
for (const auto &arg : template_type) {
|
||||
auto argument_kind = arg.getKind();
|
||||
if (argument_kind == clang::TemplateArgument::ArgKind::Type) {
|
||||
const auto *argument_record_decl =
|
||||
arg.getAsType()->getAsRecordDecl();
|
||||
template_parameter argument;
|
||||
argument.is_template_parameter(false);
|
||||
argument.set_name(to_string(
|
||||
arg.getAsType(), argument_record_decl->getASTContext()));
|
||||
|
||||
template_instantiation.add_template(std::move(argument));
|
||||
|
||||
template_instantiation.add_relationship(
|
||||
{relationship_t::kInstantiation, template_record->getID()});
|
||||
}
|
||||
}
|
||||
|
||||
return template_instantiation_ptr;
|
||||
}
|
||||
|
||||
void translation_unit_visitor::process_field(
|
||||
const clang::FieldDecl &field_declaration, class_ &c)
|
||||
{
|
||||
@@ -481,6 +630,10 @@ void translation_unit_visitor::process_field(
|
||||
detail::access_specifier_to_access_t(field_declaration.getAccess()),
|
||||
field_declaration.getNameAsString(), type_name};
|
||||
|
||||
if (field.name() == "e") {
|
||||
LOG_DBG("EEEEEEEEE");
|
||||
}
|
||||
|
||||
process_comment(field_declaration, field);
|
||||
set_source_location(field_declaration, field);
|
||||
|
||||
@@ -488,9 +641,7 @@ void translation_unit_visitor::process_field(
|
||||
return;
|
||||
|
||||
if (!field.skip_relationship()) {
|
||||
std::vector<
|
||||
std::pair<std::string, clanguml::common::model::relationship_t>>
|
||||
relationships;
|
||||
found_relationships_t relationships;
|
||||
// find relationship for the type
|
||||
find_relationships(field_declaration.getType(), relationships,
|
||||
relationship_t::kAggregation);
|
||||
@@ -500,6 +651,17 @@ void translation_unit_visitor::process_field(
|
||||
field_declaration.getNameAsString());
|
||||
}
|
||||
|
||||
if (field_type->getAs<clang::TemplateSpecializationType>() &&
|
||||
diagram().should_include(type_name)) {
|
||||
|
||||
auto template_specialization_ptr = build_template_instantiation(
|
||||
*field_type->getAs<clang::TemplateSpecializationType>());
|
||||
|
||||
diagram().add_class(std::move(template_specialization_ptr));
|
||||
|
||||
LOG_DBG("ADDED TEMPLATE SPECIALIZATION TO DIAGRAM");
|
||||
}
|
||||
|
||||
/*
|
||||
if (field_type->getAsCXXRecordDecl()) {
|
||||
|
||||
|
||||
@@ -17,28 +17,14 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "class_diagram/model/class.h"
|
||||
#include "class_diagram/model/diagram.h"
|
||||
//#include "class_diagram/visitor/translation_unit_context.h"
|
||||
#include "common/model/enums.h"
|
||||
#include "config/config.h"
|
||||
|
||||
//#include <clang-c/CXCompilationDatabase.h>
|
||||
//#include <clang-c/Index.h>
|
||||
//#include <cppast/cpp_friend.hpp>
|
||||
//#include <cppast/cpp_function_template.hpp>
|
||||
//#include <cppast/cpp_member_function.hpp>
|
||||
//#include <cppast/cpp_member_variable.hpp>
|
||||
//#include <cppast/cpp_template.hpp>
|
||||
//#include <cppast/cpp_template_parameter.hpp>
|
||||
//#include <cppast/cpp_type.hpp>
|
||||
//#include <cppast/visitor.hpp>
|
||||
#include <clang/AST/RecursiveASTVisitor.h>
|
||||
#include <clang/Basic/SourceManager.h>
|
||||
#include <class_diagram/model/class.h>
|
||||
#include <common/model/enums.h>
|
||||
#include <type_safe/reference.hpp>
|
||||
//#include <cppast/cpp_alias_template.hpp>
|
||||
//#include <cppast/cpp_type_alias.hpp>
|
||||
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
@@ -48,7 +34,7 @@
|
||||
namespace clanguml::class_diagram::visitor {
|
||||
|
||||
using found_relationships_t =
|
||||
std::vector<std::pair<clanguml::common::model::element::id_t,
|
||||
std::vector<std::pair<clanguml::common::model::diagram_element::id_t,
|
||||
common::model::relationship_t>>;
|
||||
|
||||
class translation_unit_visitor
|
||||
@@ -62,17 +48,27 @@ public:
|
||||
|
||||
virtual bool VisitEnumDecl(clang::EnumDecl *e);
|
||||
|
||||
virtual bool VisitClassTemplateDecl(
|
||||
clang::ClassTemplateDecl *class_template_declaration);
|
||||
|
||||
// virtual bool VisitVarDecl(clang::VarDecl *variable_declaration);
|
||||
clanguml::class_diagram::model::diagram &diagram() { return diagram_; }
|
||||
// void operator()();
|
||||
|
||||
private:
|
||||
std::unique_ptr<clanguml::class_diagram::model::class_>
|
||||
process_class_declaration(clang::CXXRecordDecl *cls);
|
||||
|
||||
void process_class_bases(const clang::CXXRecordDecl *cls,
|
||||
clanguml::class_diagram::model::class_ &c) const;
|
||||
|
||||
void process_class_children(const clang::CXXRecordDecl *cls,
|
||||
clanguml::class_diagram::model::class_ &c);
|
||||
|
||||
bool process_template_parameters(
|
||||
const clang::ClassTemplateDecl &template_declaration,
|
||||
clanguml::class_diagram::model::class_ &c);
|
||||
|
||||
void process_record_containment(const clang::TagDecl &record,
|
||||
clanguml::common::model::element &c) const;
|
||||
|
||||
@@ -90,7 +86,8 @@ private:
|
||||
clanguml::class_diagram::model::class_ &c,
|
||||
const std::set<std::string> &template_parameter_names = {});
|
||||
|
||||
bool find_relationships(const clang::QualType &type, &,
|
||||
bool find_relationships(const clang::QualType &type,
|
||||
found_relationships_t &,
|
||||
clanguml::common::model::relationship_t relationship_hint);
|
||||
|
||||
void add_relationships(clanguml::class_diagram::model::class_ &c,
|
||||
@@ -101,6 +98,10 @@ private:
|
||||
void set_source_location(const clang::Decl &decl,
|
||||
clanguml::common::model::source_location &element);
|
||||
|
||||
std::unique_ptr<clanguml::class_diagram::model::class_>
|
||||
build_template_instantiation(const clang::TemplateSpecializationType& template_type,
|
||||
std::optional<clanguml::class_diagram::model::class_ *> parent = {});
|
||||
|
||||
template <typename ClangDecl>
|
||||
void process_comment(
|
||||
const ClangDecl &decl, clanguml::common::model::decorated_element &e)
|
||||
|
||||
Reference in New Issue
Block a user