Fixed package diagram generation

This commit is contained in:
Bartek Kryza
2022-07-31 16:14:36 +02:00
parent 79942e06d7
commit 7274809561
26 changed files with 600 additions and 78 deletions

View File

@@ -25,13 +25,13 @@
namespace clanguml::class_diagram::model {
const std::vector<std::reference_wrapper<const class_>> &
const std::vector<std::reference_wrapper<class_>> &
diagram::classes() const
{
return classes_;
}
const std::vector<std::reference_wrapper<const enum_>> &diagram::enums() const
const std::vector<std::reference_wrapper<enum_>> &diagram::enums() const
{
return enums_;
}
@@ -41,14 +41,11 @@ common::model::diagram_t diagram::type() const
return common::model::diagram_t::kClass;
}
std::optional<
std::reference_wrapper<const clanguml::common::model::diagram_element>>
std::optional<std::reference_wrapper<clanguml::common::model::diagram_element>>
diagram::get(const std::string &full_name) const
{
// type_safe::optional_ref<const clanguml::common::model::diagram_element>
// res;
std::optional<
std::reference_wrapper<const clanguml::common::model::diagram_element>>
std::reference_wrapper<clanguml::common::model::diagram_element>>
res;
res = get_class(full_name);
@@ -61,6 +58,23 @@ diagram::get(const std::string &full_name) const
return res;
}
std::optional<std::reference_wrapper<clanguml::common::model::diagram_element>>
diagram::get(const clanguml::common::model::diagram_element::id_t id) const
{
std::optional<
std::reference_wrapper<clanguml::common::model::diagram_element>>
res;
res = get_class(id);
if (res.has_value())
return res;
res = get_enum(id);
return res;
}
bool diagram::has_class(const class_ &c) const
{
return std::any_of(classes_.cbegin(), classes_.cend(),
@@ -73,7 +87,7 @@ bool diagram::has_enum(const enum_ &e) const
[&e](const auto &ee) { return ee.get().full_name() == e.full_name(); });
}
std::optional<std::reference_wrapper<const class_>> diagram::get_class(
std::optional<std::reference_wrapper<class_>> diagram::get_class(
const std::string &name) const
{
for (const auto &c : classes_) {
@@ -87,7 +101,7 @@ std::optional<std::reference_wrapper<const class_>> diagram::get_class(
return {};
}
std::optional<std::reference_wrapper<const class_>> diagram::get_class(
std::optional<std::reference_wrapper<class_>> diagram::get_class(
clanguml::common::model::diagram_element::id_t id) const
{
for (const auto &c : classes_) {
@@ -99,7 +113,7 @@ std::optional<std::reference_wrapper<const class_>> diagram::get_class(
return {};
}
std::optional<std::reference_wrapper<const enum_>> diagram::get_enum(
std::optional<std::reference_wrapper<enum_>> diagram::get_enum(
const std::string &name) const
{
for (const auto &e : enums_) {
@@ -111,6 +125,18 @@ std::optional<std::reference_wrapper<const enum_>> diagram::get_enum(
return {};
}
std::optional<std::reference_wrapper<enum_>> diagram::get_enum(
clanguml::common::model::diagram_element::id_t id) const
{
for (const auto &e : enums_) {
if (e.get().id() == id) {
return {e};
}
}
return {};
}
void diagram::add_type_alias(std::unique_ptr<type_alias> &&ta)
{
LOG_DBG(
@@ -149,7 +175,7 @@ bool diagram::add_class(std::unique_ptr<class_> &&c)
auto name = base_name;
auto name_with_ns = c->name_and_ns();
auto name_and_ns = ns | name;
const auto &cc = *c;
auto &cc = *c;
auto cc_ref = std::ref(cc);

View File

@@ -46,26 +46,33 @@ public:
common::model::diagram_t type() const override;
std::optional<
std::reference_wrapper<const clanguml::common::model::diagram_element>>
std::reference_wrapper<clanguml::common::model::diagram_element>>
get(const std::string &full_name) const override;
const std::vector<std::reference_wrapper<const class_>> &classes() const;
std::optional<
std::reference_wrapper<clanguml::common::model::diagram_element>>
get(const clanguml::common::model::diagram_element::id_t id) const override;
const std::vector<std::reference_wrapper<const enum_>> &enums() const;
const std::vector<std::reference_wrapper<class_>> &classes() const;
const std::vector<std::reference_wrapper<enum_>> &enums() const;
bool has_class(const class_ &c) const;
bool has_enum(const enum_ &e) const;
std::optional<std::reference_wrapper<const class_>> get_class(
std::optional<std::reference_wrapper<class_>> get_class(
const std::string &name) const;
std::optional<std::reference_wrapper<const class_>> get_class(
std::optional<std::reference_wrapper<class_>> get_class(
clanguml::common::model::diagram_element::id_t id) const;
std::optional<std::reference_wrapper<const enum_>> get_enum(
std::optional<std::reference_wrapper<enum_>> get_enum(
const std::string &name) const;
std::optional<std::reference_wrapper<enum_>> get_enum(
clanguml::common::model::diagram_element::id_t id) const;
void add_type_alias(std::unique_ptr<type_alias> &&ta);
bool add_class(std::unique_ptr<class_> &&c);
@@ -85,11 +92,10 @@ public:
const clanguml::common::model::diagram_element::id_t id) const override;
private:
std::vector<std::reference_wrapper<const class_>> classes_;
std::vector<std::reference_wrapper<const enum_>> enums_;
std::vector<std::reference_wrapper<class_>> classes_;
std::vector<std::reference_wrapper<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_;
};
}

View File

@@ -783,8 +783,7 @@ bool translation_unit_visitor::find_relationships(const clang::QualType &type,
found_relationships_t &relationships,
clanguml::common::model::relationship_t relationship_hint)
{
bool result = false;
// std::string type_name =
bool result{false};
if (type->isPointerType()) {
relationship_hint = relationship_t::kAssociation;

View File

@@ -58,13 +58,10 @@ public:
virtual bool VisitTypeAliasTemplateDecl(clang::TypeAliasTemplateDecl *cls);
// virtual bool VisitVarDecl(clang::VarDecl *variable_declaration);
clanguml::class_diagram::model::diagram &diagram() { return diagram_; }
const clanguml::config::class_diagram &config() const { return config_; }
// void operator()();
void finalize();
private:

View File

@@ -34,14 +34,19 @@ class relationship;
class diagram {
public:
diagram();
virtual ~diagram();
virtual diagram_t type() const = 0;
virtual std::optional<
std::reference_wrapper<const clanguml::common::model::diagram_element>>
std::reference_wrapper<clanguml::common::model::diagram_element>>
get(const std::string &full_name) const = 0;
virtual std::optional<
std::reference_wrapper<clanguml::common::model::diagram_element>>
get(const diagram_element::id_t id) const = 0;
diagram(const diagram &) = delete;
diagram(diagram &&);
diagram &operator=(const diagram &) = delete;
@@ -62,6 +67,7 @@ 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;

View File

@@ -63,14 +63,14 @@ const clanguml::common::optional_ref<class_diagram::model::class_> get(
}
template <>
const clanguml::common::optional_ref<const common::model::package> get(
const clanguml::common::optional_ref<common::model::package> get(
const package_diagram::model::diagram &d, const std::string &full_name)
{
return d.get_package(full_name);
}
template <>
const clanguml::common::optional_ref<const common::model::source_file> get(
const clanguml::common::optional_ref<common::model::source_file> get(
const include_diagram::model::diagram &d, const std::string &full_name)
{
return d.get_file(full_name);

View File

@@ -27,10 +27,10 @@ namespace clanguml::common {
using id_t = int64_t;
template <typename T>
using optional_ref = std::optional<std::reference_wrapper<const T>>;
using optional_ref = std::optional<std::reference_wrapper<T>>;
template <typename T>
using reference_vector = std::vector<std::reference_wrapper<const T>>;
using reference_vector = std::vector<std::reference_wrapper<T>>;
template <typename T>
using reference_set = std::unordered_set<std::reference_wrapper<const T>>;

View File

@@ -34,6 +34,12 @@ common::optional_ref<common::model::diagram_element> diagram::get(
return get_file(full_name);
}
common::optional_ref<common::model::diagram_element> diagram::get(
const common::model::diagram_element::id_t /*id*/) const
{
return {};
}
void diagram::add_file(std::unique_ptr<common::model::source_file> &&f)
{
LOG_DBG("Adding source file: {}, {}", f->name(), f->full_name(true));
@@ -94,7 +100,7 @@ std::string diagram::to_alias(const std::string &full_name) const
return source_file.value().alias();
}
const common::reference_vector<const common::model::source_file> &
const common::reference_vector<common::model::source_file> &
diagram::files() const
{
return files_;

View File

@@ -44,6 +44,9 @@ public:
common::optional_ref<common::model::diagram_element> get(
const std::string &full_name) const override;
common::optional_ref<common::model::diagram_element> get(
const common::model::diagram_element::id_t id) const override;
void add_file(std::unique_ptr<common::model::source_file> &&f);
common::optional_ref<common::model::source_file> get_file(
@@ -51,11 +54,11 @@ public:
std::string to_alias(const std::string &full_name) const;
const common::reference_vector<const common::model::source_file> &
const common::reference_vector<common::model::source_file> &
files() const;
private:
common::reference_vector<const common::model::source_file> files_;
common::reference_vector<common::model::source_file> files_;
};
}

View File

@@ -41,7 +41,7 @@ void generator::generate_relationships(
try {
relstr << p.alias()
<< " ..> "
//<< m_model.get_ to_alias(uns.relative(r.destination()))
<< m_model.to_alias(r.destination())
<< '\n';
ostr << relstr.str();
}

View File

@@ -28,8 +28,7 @@ common::model::diagram_t diagram::type() const
return common::model::diagram_t::kPackage;
}
const std::vector<
std::reference_wrapper<const clanguml::common::model::package>> &
const std::vector<std::reference_wrapper<clanguml::common::model::package>> &
diagram::packages() const
{
return packages_;
@@ -46,7 +45,7 @@ void diagram::add_package(std::unique_ptr<common::model::package> &&p)
add_element(ns, std::move(p));
}
std::optional<std::reference_wrapper<const common::model::package>>
std::optional<std::reference_wrapper<common::model::package>>
diagram::get_package(const std::string &name) const
{
for (const auto &p : packages_) {
@@ -59,30 +58,42 @@ diagram::get_package(const std::string &name) const
return {};
}
std::optional<
std::reference_wrapper<const clanguml::common::model::diagram_element>>
std::optional<std::reference_wrapper<common::model::package>>
diagram::get_package(
const clanguml::common::model::diagram_element::id_t id) const
{
for (const auto &p : packages_) {
if (p.get().id() == id) {
return {p};
}
}
return {};
}
std::optional<std::reference_wrapper<clanguml::common::model::diagram_element>>
diagram::get(const std::string &full_name) const
{
return get_package(full_name);
}
std::string diagram::to_alias(const std::string &full_name) const
std::optional<std::reference_wrapper<clanguml::common::model::diagram_element>>
diagram::get(const clanguml::common::model::diagram_element::id_t id) const
{
LOG_DBG("Looking for alias for {}", full_name);
return get_package(id);
}
auto path = common::model::namespace_{full_name};
std::string diagram::to_alias(
const clanguml::common::model::diagram_element::id_t id) const
{
LOG_DBG("Looking for alias for {}", id);
if (path.is_empty())
throw error::uml_alias_missing(
fmt::format("Missing alias for '{}'", path.to_string()));
for (const auto &p : packages_) {
if (p.get().id() == id)
return p.get().alias();
}
auto package = get_element<common::model::package>(path);
if (!package)
throw error::uml_alias_missing(
fmt::format("Missing alias for '{}'", path.to_string()));
return package.value().alias();
return {};
}
}

View File

@@ -39,24 +39,30 @@ public:
common::model::diagram_t type() const override;
const std::vector<
std::reference_wrapper<const clanguml::common::model::package>> &
packages() const;
const std::vector<std::reference_wrapper<clanguml::common::model::package>>
&packages() const;
std::optional<
std::reference_wrapper<const clanguml::common::model::diagram_element>>
std::reference_wrapper<clanguml::common::model::diagram_element>>
get(const std::string &full_name) const override;
std::optional<
std::reference_wrapper<clanguml::common::model::diagram_element>>
get(const clanguml::common::model::diagram_element::id_t id) const override;
void add_package(std::unique_ptr<common::model::package> &&p);
std::optional<
std::reference_wrapper<const clanguml::common::model::package>>
std::optional<std::reference_wrapper<clanguml::common::model::package>>
get_package(const std::string &name) const;
std::string to_alias(const std::string &full_name) const;
std::optional<std::reference_wrapper<common::model::package>> get_package(
const clanguml::common::model::diagram_element::id_t id) const;
std::string to_alias(
const clanguml::common::model::diagram_element::id_t) const;
private:
std::vector<std::reference_wrapper<const clanguml::common::model::package>>
std::vector<std::reference_wrapper<clanguml::common::model::package>>
packages_;
};
}

View File

@@ -29,11 +29,21 @@ namespace clanguml::package_diagram::visitor {
using clanguml::class_diagram::model::type_alias;
using clanguml::common::model::access_t;
using clanguml::common::model::namespace_;
using clanguml::common::model::package;
using clanguml::common::model::relationship;
using clanguml::common::model::relationship_t;
using clanguml::package_diagram::model::diagram;
int64_t to_id(const clang::NamespaceDecl *ns)
{
auto qualified_name = ns->getQualifiedNameAsString();
util::replace_all(qualified_name, "(anonymous namespace)", "");
util::replace_all(qualified_name, "::::", "::");
return std::hash<std::string>{}(qualified_name) >> 3;
}
translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
clanguml::package_diagram::model::diagram &diagram,
const clanguml::config::package_diagram &config)
@@ -43,4 +53,362 @@ translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
{
}
bool translation_unit_visitor::VisitNamespaceDecl(clang::NamespaceDecl *ns)
{
if (ns->isAnonymousNamespace() || ns->isInline())
return true;
auto qualified_name = ns->getQualifiedNameAsString();
util::replace_all(qualified_name, "(anonymous namespace)", "");
util::replace_all(qualified_name, "::::", "::");
LOG_DBG("Visiting namespace declaration: {}", qualified_name);
auto package_path = namespace_{qualified_name};
auto package_parent = package_path;
std::string name;
if (!package_path.is_empty())
name = package_path.name();
if (!package_parent.is_empty())
package_parent.pop_back();
const auto usn = config().using_namespace();
auto p = std::make_unique<common::model::package>(usn);
package_path = package_path.relative_to(usn);
p->set_name(name);
p->set_namespace(package_parent);
p->set_id(to_id(ns));
assert(p->id() > 0);
if (diagram().should_include(*p) && !diagram().get(p->id())) {
process_comment(*ns, *p);
set_source_location(*ns, *p);
p->set_style(p->style_spec());
for (const auto *attr : ns->attrs()) {
if (attr->getKind() == clang::attr::Kind::Deprecated) {
p->set_deprecated(true);
break;
}
}
if (!p->skip()) {
diagram().add_package(std::move(p));
}
}
return true;
}
bool translation_unit_visitor::VisitFunctionDecl(
clang::FunctionDecl *function_declaration)
{
assert(function_declaration != nullptr);
// Skip system headers
if (source_manager_.isInSystemHeader(
function_declaration->getSourceRange().getBegin()))
return true;
found_relationships_t relationships;
find_relationships(function_declaration->getReturnType(), relationships);
for (const auto *param : function_declaration->parameters()) {
if (param != nullptr)
find_relationships(param->getType(), relationships);
}
add_relationships(function_declaration, relationships);
return true;
}
bool translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *cls)
{
assert(cls != nullptr);
// Skip system headers
if (source_manager_.isInSystemHeader(cls->getSourceRange().getBegin()))
return true;
// Templated records are handled by VisitClassTemplateDecl()
if (cls->isTemplated() || cls->isTemplateDecl() ||
(clang::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(cls) !=
nullptr))
return true;
found_relationships_t relationships;
process_class_declaration(*cls, relationships);
add_relationships(cls, relationships);
return true;
}
void translation_unit_visitor::add_relationships(
clang::DeclContext *cls, found_relationships_t &relationships)
{
int64_t current_package_id{0};
const auto *namespace_context = cls->getEnclosingNamespaceContext();
if (namespace_context != nullptr && namespace_context->isNamespace()) {
current_package_id =
to_id(llvm::cast<clang::NamespaceDecl>(namespace_context));
}
assert(current_package_id != 0);
auto current_package = diagram().get(current_package_id);
if (current_package) {
for (const auto &dependency : relationships) {
const auto destination_id = std::get<0>(dependency);
relationship r{relationship_t::kDependency, destination_id};
if (destination_id != current_package_id)
current_package.value().get().add_relationship(std::move(r));
}
}
}
void translation_unit_visitor::process_class_declaration(
const clang::CXXRecordDecl &cls, found_relationships_t &relationships)
{
// Look for dependency relationships in class children (fields, methods)
process_class_children(cls, relationships);
// Look for dependency relationships in class bases
process_class_bases(cls, relationships);
}
void translation_unit_visitor::process_class_children(
const clang::CXXRecordDecl &cls, found_relationships_t &relationships)
{
// Iterate over class methods (both regular and static)
for (const auto *method : cls.methods()) {
if (method != nullptr) {
process_method(*method, relationships);
}
}
// Iterate over class template methods
for (auto const *decl_iterator :
clang::dyn_cast_or_null<clang::DeclContext>(&cls)->decls()) {
auto const *method_template =
llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(decl_iterator);
if (method_template == nullptr)
continue;
process_template_method(*method_template, relationships);
}
// Iterate over regular class fields
for (const auto *field : cls.fields()) {
if (field != nullptr)
process_field(*field, relationships);
}
// Static fields have to be processed by iterating over variable
// declarations
for (const auto *decl : cls.decls()) {
if (decl->getKind() == clang::Decl::Var) {
const clang::VarDecl *variable_declaration{
dynamic_cast<const clang::VarDecl *>(decl)};
if (variable_declaration &&
variable_declaration->isStaticDataMember()) {
process_static_field(*variable_declaration, relationships);
}
}
}
if (cls.isCompleteDefinition())
for (const auto *friend_declaration : cls.friends()) {
if (friend_declaration != nullptr)
process_friend(*friend_declaration, relationships);
}
}
void translation_unit_visitor::process_class_bases(
const clang::CXXRecordDecl &cls, found_relationships_t &relationships)
{
for (auto &base : cls.bases()) {
find_relationships(base.getType(), relationships);
}
}
void translation_unit_visitor::process_method(
const clang::CXXMethodDecl &method, found_relationships_t &relationships)
{
find_relationships(method.getReturnType(), relationships);
for (const auto *param : method.parameters()) {
if (param != nullptr)
find_relationships(param->getType(), relationships);
}
}
void translation_unit_visitor::process_template_method(
const clang::FunctionTemplateDecl &method,
found_relationships_t &relationships)
{
// TODO: For now skip implicitly default methods
// in the future, add config option to choose
if (method.getTemplatedDecl()->isDefaulted() &&
!method.getTemplatedDecl()->isExplicitlyDefaulted())
return;
find_relationships(
method.getTemplatedDecl()->getReturnType(), relationships);
for (const auto *param : method.getTemplatedDecl()->parameters()) {
if (param != nullptr) {
find_relationships(param->getType(), relationships);
}
}
}
void translation_unit_visitor::process_field(
const clang::FieldDecl &field_declaration,
found_relationships_t &relationships)
{
find_relationships(field_declaration.getType(), relationships,
relationship_t::kDependency);
}
void translation_unit_visitor::process_static_field(
const clang::VarDecl &field_declaration,
found_relationships_t &relationships)
{
find_relationships(field_declaration.getType(), relationships,
relationship_t::kDependency);
}
void translation_unit_visitor::process_friend(
const clang::FriendDecl &friend_declaration,
found_relationships_t &relationships)
{
if (const auto *friend_type_declaration =
friend_declaration.getFriendDecl()) {
if (friend_type_declaration->isTemplateDecl()) {
// TODO
}
}
else if (const auto *friend_type = friend_declaration.getFriendType()) {
find_relationships(friend_type->getType(), relationships);
}
}
bool translation_unit_visitor::find_relationships(const clang::QualType &type,
found_relationships_t &relationships, relationship_t relationship_hint)
{
bool result{false};
if (type->isVoidType() || type->isVoidPointerType()) {
// pass
}
else if (type->isPointerType()) {
relationship_hint = relationship_t::kAssociation;
find_relationships(
type->getPointeeType(), relationships, relationship_hint);
}
else if (type->isRValueReferenceType()) {
relationship_hint = relationship_t::kAggregation;
find_relationships(
type.getNonReferenceType(), relationships, relationship_hint);
}
else if (type->isLValueReferenceType()) {
relationship_hint = relationship_t::kAssociation;
find_relationships(
type.getNonReferenceType(), relationships, relationship_hint);
}
else if (type->isArrayType()) {
find_relationships(type->getAsArrayTypeUnsafe()->getElementType(),
relationships, relationship_t::kAggregation);
}
else if (type->isEnumeralType()) {
relationships.emplace_back(
type->getAs<clang::EnumType>()->getDecl()->getID(),
relationship_hint);
}
else if (auto *template_specialization_type =
type->getAs<clang::TemplateSpecializationType>()) {
if (template_specialization_type != nullptr) {
if (template_specialization_type->isTypeAlias())
template_specialization_type =
template_specialization_type->getAliasedType()
->getAs<clang::TemplateSpecializationType>();
}
if (template_specialization_type != nullptr) {
for (const auto &template_argument :
*template_specialization_type) {
const auto template_argument_kind = template_argument.getKind();
if (template_argument_kind ==
clang::TemplateArgument::ArgKind::Integral) {
// pass
}
else if (template_argument_kind ==
clang::TemplateArgument::ArgKind::Null) {
// pass
}
else if (template_argument_kind ==
clang::TemplateArgument::ArgKind::Expression) {
// pass
}
else if (template_argument.getKind() ==
clang::TemplateArgument::ArgKind::NullPtr) {
// pass
}
else if (template_argument_kind ==
clang::TemplateArgument::ArgKind::Template) {
// pass
}
else if (template_argument_kind ==
clang::TemplateArgument::ArgKind::TemplateExpansion) {
// pass
}
else if (template_argument.getAsType()
->getAs<clang::FunctionProtoType>()) {
for (const auto &param_type :
template_argument.getAsType()
->getAs<clang::FunctionProtoType>()
->param_types()) {
result = find_relationships(param_type, relationships,
relationship_t::kDependency);
}
}
else if (template_argument_kind ==
clang::TemplateArgument::ArgKind::Type) {
result = find_relationships(template_argument.getAsType(),
relationships, relationship_hint);
}
}
}
}
else if (type->isRecordType()) {
const auto *namespace_context =
type->getAsCXXRecordDecl()->getEnclosingNamespaceContext();
if (namespace_context != nullptr && namespace_context->isNamespace()) {
const auto *namespace_declaration =
clang::cast<clang::NamespaceDecl>(namespace_context);
if (diagram().should_include(
namespace_declaration->getQualifiedNameAsString())) {
const auto target_id =
to_id(clang::cast<clang::NamespaceDecl>(namespace_context));
relationships.emplace_back(target_id, relationship_hint);
result = true;
}
}
}
return result;
}
}

View File

@@ -33,6 +33,10 @@
namespace clanguml::package_diagram::visitor {
using found_relationships_t =
std::vector<std::pair<clanguml::common::model::diagram_element::id_t,
common::model::relationship_t>>;
class translation_unit_visitor
: public clang::RecursiveASTVisitor<translation_unit_visitor> {
public:
@@ -40,9 +44,75 @@ public:
clanguml::package_diagram::model::diagram &diagram,
const clanguml::config::package_diagram &config);
virtual bool VisitNamespaceDecl(clang::NamespaceDecl *ns);
virtual bool VisitCXXRecordDecl(clang::CXXRecordDecl *cls);
virtual bool VisitFunctionDecl(clang::FunctionDecl *function_declaration);
clanguml::package_diagram::model::diagram &diagram() { return diagram_; }
const clanguml::config::package_diagram &config() const { return config_; }
void finalize() { }
private:
void process_class_declaration(
const clang::CXXRecordDecl &cls, found_relationships_t &relationships);
void process_class_children(
const clang::CXXRecordDecl &cls, found_relationships_t &relationships);
void process_class_bases(
const clang::CXXRecordDecl &cls, found_relationships_t &relationships);
void process_method(const clang::CXXMethodDecl &method,
found_relationships_t &relationships);
void process_template_method(const clang::FunctionTemplateDecl &method,
found_relationships_t &relationships);
void process_field(const clang::FieldDecl &field_declaration,
found_relationships_t &relationships);
void process_static_field(const clang::VarDecl &field_declaration,
found_relationships_t &relationships);
void process_friend(const clang::FriendDecl &friend_declaration,
found_relationships_t &relationships);
bool find_relationships(const clang::QualType &type,
found_relationships_t &relationships,
common::model::relationship_t relationship_hint =
common::model::relationship_t::kDependency);
void add_relationships(clang::DeclContext *cls, found_relationships_t &relationships);
template <typename ClangDecl>
void process_comment(
const ClangDecl &decl, clanguml::common::model::decorated_element &e)
{
const auto *comment =
decl.getASTContext().getRawCommentForDeclNoCache(&decl);
if (comment != nullptr) {
e.set_comment(comment->getFormattedText(
source_manager_, decl.getASTContext().getDiagnostics()));
e.add_decorators(decorators::parse(e.comment().value()));
}
}
void set_source_location(const clang::Decl &decl,
clanguml::common::model::source_location &element)
{
if (decl.getLocation().isValid()) {
element.set_file(
source_manager_.getFilename(decl.getLocation()).str());
element.set_line(
source_manager_.getSpellingLineNumber(decl.getLocation()));
}
}
clang::SourceManager &source_manager_;
// Reference to the output diagram model

View File

@@ -34,6 +34,12 @@ common::optional_ref<common::model::diagram_element> diagram::get(
return {};
}
common::optional_ref<common::model::diagram_element> diagram::get(
const common::model::diagram_element::id_t /*id*/) const
{
return {};
}
std::string diagram::to_alias(const std::string &full_name) const
{
return full_name;

View File

@@ -40,6 +40,9 @@ public:
common::optional_ref<common::model::diagram_element> get(
const std::string &full_name) const override;
common::optional_ref<common::model::diagram_element> get(
const common::model::diagram_element::id_t id) const override;
std::string to_alias(const std::string &full_name) const;
bool started{false};

View File

@@ -24,7 +24,7 @@ TEST_CASE("t30001", "[test-case][package]")
REQUIRE(diagram->name == "t30001_package");
auto model = generate_package_diagram(db, diagram);
auto model = generate_package_diagram(*db, diagram);
REQUIRE(model->name() == "t30001_package");

View File

@@ -66,6 +66,14 @@ namespace A15 {
struct CO {
};
}
namespace A16 {
struct CP {
};
}
namespace A17 {
struct CR {
};
}
}
namespace B::BB::BBB {
class CBA : public A::AA::A6::CF {
@@ -75,11 +83,14 @@ public:
std::shared_ptr<A::AA::A3::CC> cc_;
std::map<std::string, std::unique_ptr<A::AA::A4::CD>> *cd_;
std::array<A::AA::A15::CO, 5> co_;
static A::AA::A16::CP* cp_;
CBA() = default;
CBA(A::AA::A14::CN *cn) { }
friend A::AA::A17::CR;
template <typename... Item> CBA(std::tuple<Item...> &items) { }
void ce(const std::vector<A::AA::A5::CE> /*ce_*/) { }
@@ -87,7 +98,7 @@ public:
std::shared_ptr<A::AA::A7::CG> cg() { return {}; }
template <typename T>
void ch(std::map<T, std::shared_ptr<A::AA::A8::CH>> & /*ch_*/)
void ch(std::map<T, std::shared_ptr<A::AA::A8::CH>> & ch_)
{
}

View File

@@ -24,7 +24,7 @@ TEST_CASE("t30002", "[test-case][package]")
REQUIRE(diagram->name == "t30002_package");
auto model = generate_package_diagram(db, diagram);
auto model = generate_package_diagram(*db, diagram);
REQUIRE(model->name() == "t30002_package");
@@ -48,6 +48,8 @@ TEST_CASE("t30002", "[test-case][package]")
REQUIRE_THAT(puml, IsPackage("A13"));
REQUIRE_THAT(puml, IsPackage("A14"));
REQUIRE_THAT(puml, IsPackage("A15"));
REQUIRE_THAT(puml, IsPackage("A16"));
REQUIRE_THAT(puml, IsPackage("A17"));
REQUIRE_THAT(puml, IsDependency(_A("BBB"), _A("A1")));
REQUIRE_THAT(puml, IsDependency(_A("BBB"), _A("A2")));
@@ -64,6 +66,8 @@ TEST_CASE("t30002", "[test-case][package]")
REQUIRE_THAT(puml, IsDependency(_A("BBB"), _A("A13")));
REQUIRE_THAT(puml, IsDependency(_A("BBB"), _A("A14")));
REQUIRE_THAT(puml, IsDependency(_A("BBB"), _A("A15")));
REQUIRE_THAT(puml, IsDependency(_A("BBB"), _A("A16")));
REQUIRE_THAT(puml, IsDependency(_A("BBB"), _A("A17")));
save_puml(
"./" + config.output_directory() + "/" + diagram->name + ".puml", puml);

View File

@@ -24,7 +24,7 @@ TEST_CASE("t30003", "[test-case][package]")
REQUIRE(diagram->name == "t30003_package");
auto model = generate_package_diagram(db, diagram);
auto model = generate_package_diagram(*db, diagram);
REQUIRE(model->name() == "t30003_package");

View File

@@ -24,7 +24,7 @@ TEST_CASE("t30004", "[test-case][package]")
REQUIRE(diagram->name == "t30004_package");
auto model = generate_package_diagram(db, diagram);
auto model = generate_package_diagram(*db, diagram);
REQUIRE(model->name() == "t30004_package");

View File

@@ -24,7 +24,7 @@ TEST_CASE("t30005", "[test-case][package]")
REQUIRE(diagram->name == "t30005_package");
auto model = generate_package_diagram(db, diagram);
auto model = generate_package_diagram(*db, diagram);
REQUIRE(model->name() == "t30005_package");

View File

@@ -24,7 +24,7 @@ TEST_CASE("t30006", "[test-case][package]")
REQUIRE(diagram->name == "t30006_package");
auto model = generate_package_diagram(db, diagram);
auto model = generate_package_diagram(*db, diagram);
REQUIRE(model->name() == "t30006_package");

View File

@@ -24,7 +24,7 @@ TEST_CASE("t30007", "[test-case][package]")
REQUIRE(diagram->name == "t30007_package");
auto model = generate_package_diagram(db, diagram);
auto model = generate_package_diagram(*db, diagram);
REQUIRE(model->name() == "t30007_package");

View File

@@ -24,7 +24,7 @@ TEST_CASE("t30008", "[test-case][package]")
REQUIRE(diagram->name == "t30008_package");
auto model = generate_package_diagram(db, diagram);
auto model = generate_package_diagram(*db, diagram);
REQUIRE(model->name() == "t30008_package");

View File

@@ -245,14 +245,14 @@ using namespace clanguml::test::matchers;
////
//// Package diagram tests
////
//#include "t30001/test_case.h"
//#include "t30002/test_case.h"
//#include "t30003/test_case.h"
//#include "t30004/test_case.h"
//#include "t30005/test_case.h"
//#include "t30006/test_case.h"
//#include "t30007/test_case.h"
//#include "t30008/test_case.h"
#include "t30001/test_case.h"
#include "t30002/test_case.h"
#include "t30003/test_case.h"
#include "t30004/test_case.h"
#include "t30005/test_case.h"
#include "t30006/test_case.h"
#include "t30007/test_case.h"
#include "t30008/test_case.h"
//
////
//// Include diagram tests