Fixed handling of nested and anonymous classes

This commit is contained in:
Bartek Kryza
2022-09-04 18:12:54 +02:00
parent 4d4eb02e57
commit d887353c24
11 changed files with 102 additions and 20 deletions

View File

@@ -39,6 +39,35 @@ std::optional<clanguml::common::model::namespace_> get_enclosing_namespace(
common::get_qualified_name(*namespace_declaration)};
}
std::string get_tag_name(const clang::TagDecl &declaration)
{
auto base_name = declaration.getNameAsString();
if (base_name.empty()) {
base_name =
fmt::format("(anonymous_{})", std::to_string(declaration.getID()));
}
if (declaration.getParent() && declaration.getParent()->isRecord()) {
// If the record is nested within another record (e.g. class or struct)
// we have to maintain a containment namespace in order to ensure
// unique names within the diagram
std::deque<std::string> record_parent_names;
record_parent_names.push_front(base_name);
auto *cls_parent{declaration.getParent()};
while (cls_parent->isRecord()) {
auto parent_name =
static_cast<const clang::RecordDecl *>(cls_parent)
->getNameAsString();
record_parent_names.push_front(parent_name);
cls_parent = cls_parent->getParent();
}
return fmt::format("{}", fmt::join(record_parent_names, "##"));
}
return base_name;
}
std::string to_string(const clang::QualType &type, const clang::ASTContext &ctx,
bool try_canonical)
{
@@ -66,6 +95,14 @@ std::string to_string(const clang::QualType &type, const clang::ASTContext &ctx,
}
}
// If for any reason clang reports the type as empty string, make sure
// it has some default name
if (result.empty())
result = "(anonymous)";
else if (util::contains(result, "unnamed struct")) {
result = common::get_tag_name(*type->getAsTagDecl());
}
// Remove trailing spaces after commas in template arguments
clanguml::util::replace_all(result, ", ", ",");

View File

@@ -22,6 +22,7 @@
#include <clang/AST/RecursiveASTVisitor.h>
#include <deque>
#include <filesystem>
#include <string>
@@ -30,12 +31,23 @@ class NamespaceDecl;
}
namespace clanguml::common {
std::string get_tag_name(const clang::TagDecl &declaration);
template <typename T> std::string get_qualified_name(const T &declaration)
{
auto qualified_name = declaration.getQualifiedNameAsString();
util::replace_all(qualified_name, "(anonymous namespace)", "");
util::replace_all(qualified_name, "::::", "::");
if constexpr (std::is_base_of_v<clang::TagDecl, T>) {
auto base_name = get_tag_name(declaration);
model::namespace_ ns{qualified_name};
ns.pop_back();
ns = ns | base_name;
return ns.to_string();
}
return qualified_name;
}

View File

@@ -28,6 +28,7 @@ std::atomic_uint64_t diagram_element::m_nextId = 1;
diagram_element::diagram_element()
: id_{0}
, nested_{false}
, complete_{false}
{
}
@@ -84,6 +85,10 @@ inja::json diagram_element::context() const
return ctx;
}
bool diagram_element::is_nested() const { return nested_; }
void diagram_element::nested(bool nested) { nested_ = nested; }
bool diagram_element::complete() const { return complete_; }
void diagram_element::complete(bool completed) { complete_ = completed; }

View File

@@ -65,6 +65,10 @@ public:
virtual inja::json context() const;
bool is_nested() const;
void nested(bool nested);
bool complete() const;
void complete(bool completed);
@@ -73,7 +77,7 @@ private:
id_t id_;
std::string name_;
std::vector<relationship> relationships_;
bool nested_;
bool complete_;
static std::atomic_uint64_t m_nextId;