Added handling of template instantiation relationships
This commit is contained in:
@@ -166,6 +166,10 @@ public:
|
||||
destination = m_model.usr_to_name(
|
||||
m_config.using_namespace, r.destination);
|
||||
}
|
||||
else if (r.destination.find("#") != std::string::npos) {
|
||||
destination = m_model.usr_to_name(
|
||||
m_config.using_namespace, r.destination);
|
||||
}
|
||||
else {
|
||||
destination = r.destination;
|
||||
}
|
||||
|
||||
@@ -354,12 +354,14 @@ static enum CXChildVisitResult class_visitor(
|
||||
case CXCursor_FieldDecl: {
|
||||
visit_if_cursor_valid(
|
||||
cursor, [ctx, &config, is_vardecl](cx::cursor cursor) {
|
||||
bool added_relation_to_instantiation{false};
|
||||
auto t = cursor.type();
|
||||
auto tr = t.referenced();
|
||||
class_member m;
|
||||
m.name = cursor.spelling();
|
||||
if (t.is_template())
|
||||
if (tr.is_template())
|
||||
m.type = t.unqualified();
|
||||
else if (t.is_template_parameter())
|
||||
else if (tr.is_template_parameter())
|
||||
m.type = t.spelling();
|
||||
else
|
||||
m.type = t.canonical().unqualified();
|
||||
@@ -367,32 +369,32 @@ static enum CXChildVisitResult class_visitor(
|
||||
cursor.cxxaccess_specifier());
|
||||
m.is_static = cursor.is_static();
|
||||
|
||||
spdlog::info("Adding member {} {}::{} {}", m.type,
|
||||
ctx->element.name, cursor.spelling(), t);
|
||||
spdlog::info("Adding member {} {}::{} {}, {}", m.type,
|
||||
ctx->element.name, cursor.spelling(), t, tr);
|
||||
|
||||
if (t.is_unexposed()) {
|
||||
if (t.is_template_instantiation() &&
|
||||
t.type_declaration()
|
||||
if (tr.is_unexposed()) {
|
||||
if (tr.is_template_instantiation() &&
|
||||
tr.type_declaration()
|
||||
.specialized_cursor_template()
|
||||
.kind() != CXCursor_InvalidFile) {
|
||||
spdlog::info(
|
||||
"Found template instantiation: {} ..|> {}",
|
||||
t.type_declaration(),
|
||||
t.type_declaration()
|
||||
tr.type_declaration(),
|
||||
tr.type_declaration()
|
||||
.specialized_cursor_template());
|
||||
class_ tinst;
|
||||
tinst.name = t.type_declaration().spelling();
|
||||
tinst.name = tr.type_declaration().spelling();
|
||||
tinst.is_template_instantiation = true;
|
||||
tinst.usr = t.type_declaration().usr();
|
||||
for (int i = 0; i < t.template_arguments_count();
|
||||
tinst.usr = tr.type_declaration().usr();
|
||||
for (int i = 0; i < tr.template_arguments_count();
|
||||
i++) {
|
||||
class_template ct;
|
||||
ct.type =
|
||||
t.template_argument_type(i).spelling();
|
||||
tr.template_argument_type(i).spelling();
|
||||
tinst.templates.emplace_back(std::move(ct));
|
||||
}
|
||||
tinst.base_template_usr =
|
||||
t.type_declaration()
|
||||
tr.type_declaration()
|
||||
.specialized_cursor_template()
|
||||
.usr();
|
||||
|
||||
@@ -401,20 +403,31 @@ static enum CXChildVisitResult class_visitor(
|
||||
r.type = relationship_t::kInstantiation;
|
||||
r.label = "";
|
||||
|
||||
class_relationship a;
|
||||
a.destination = tinst.usr;
|
||||
if (t.is_pointer() || t.is_reference())
|
||||
a.type = relationship_t::kAssociation;
|
||||
else
|
||||
a.type = relationship_t::kComposition;
|
||||
a.label = m.name;
|
||||
|
||||
ctx->element.relationships.emplace_back(
|
||||
std::move(a));
|
||||
tinst.relationships.emplace_back(std::move(r));
|
||||
|
||||
ctx->d.classes.emplace_back(std::move(tinst));
|
||||
added_relation_to_instantiation = true;
|
||||
}
|
||||
}
|
||||
if (!added_relation_to_instantiation) {
|
||||
|
||||
relationship_t relationship_type = relationship_t::kNone;
|
||||
relationship_t relationship_type =
|
||||
relationship_t::kNone;
|
||||
|
||||
auto name = t.canonical().unqualified();
|
||||
auto destination = name;
|
||||
|
||||
// Parse the field declaration to determine the relationship
|
||||
// type
|
||||
// Skip:
|
||||
// Parse the field declaration to determine the
|
||||
// relationship type Skip:
|
||||
// - POD
|
||||
// - function variables
|
||||
spdlog::info(
|
||||
@@ -422,7 +435,8 @@ static enum CXChildVisitResult class_visitor(
|
||||
t.canonical().unqualified());
|
||||
|
||||
if (t.is_relationship() &&
|
||||
(config.should_include(t.canonical().unqualified()) ||
|
||||
(config.should_include(
|
||||
t.canonical().unqualified()) ||
|
||||
t.is_template() || t.is_array())) {
|
||||
std::vector<std::pair<cx::type, relationship_t>>
|
||||
relationships{};
|
||||
@@ -430,24 +444,27 @@ static enum CXChildVisitResult class_visitor(
|
||||
|
||||
for (const auto &[type, relationship_type] :
|
||||
relationships) {
|
||||
if (relationship_type != relationship_t::kNone) {
|
||||
if (relationship_type !=
|
||||
relationship_t::kNone) {
|
||||
class_relationship r;
|
||||
r.destination =
|
||||
type.referenced().canonical().unqualified();
|
||||
r.destination = type.referenced()
|
||||
.canonical()
|
||||
.unqualified();
|
||||
r.type = relationship_type;
|
||||
r.label = m.name;
|
||||
ctx->element.relationships.emplace_back(
|
||||
std::move(r));
|
||||
|
||||
spdlog::info(
|
||||
"Added relationship to: {}", r.destination);
|
||||
spdlog::info("Added relationship to: {}",
|
||||
r.destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx->element.members.emplace_back(std::move(m));
|
||||
});
|
||||
ret = CXChildVisit_Recurse;
|
||||
ret = CXChildVisit_Continue;
|
||||
break;
|
||||
}
|
||||
case CXCursor_ClassTemplatePartialSpecialization: {
|
||||
|
||||
@@ -64,11 +64,14 @@ TEST_CASE("Test t00006", "[unit-test]")
|
||||
REQUIRE_THAT(puml, IsClass(_A("NN")));
|
||||
REQUIRE_THAT(puml, IsClass(_A("NNN")));
|
||||
|
||||
REQUIRE_THAT(puml,
|
||||
IsInstantiation(_A("custom_container<T>"), _A("custom_container<E>")));
|
||||
|
||||
REQUIRE_THAT(puml, IsComposition(_A("R"), _A("A"), "a"));
|
||||
REQUIRE_THAT(puml, IsAssociation(_A("R"), _A("B"), "b"));
|
||||
REQUIRE_THAT(puml, IsComposition(_A("R"), _A("C"), "c"));
|
||||
REQUIRE_THAT(puml, IsAssociation(_A("R"), _A("D"), "d"));
|
||||
REQUIRE_THAT(puml, IsComposition(_A("R"), _A("E"), "e"));
|
||||
REQUIRE_THAT(puml, IsComposition(_A("R"), _A("custom_container<E>"), "e"));
|
||||
REQUIRE_THAT(puml, IsComposition(_A("R"), _A("F"), "f"));
|
||||
REQUIRE_THAT(puml, IsAssociation(_A("R"), _A("G"), "g"));
|
||||
REQUIRE_THAT(puml, IsComposition(_A("R"), _A("H"), "h"));
|
||||
|
||||
@@ -1,31 +1,6 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/*
|
||||
@startuml
|
||||
|
||||
class "A<T>" as C_0000000046
|
||||
class C_0000000046 {
|
||||
+T value
|
||||
}
|
||||
|
||||
class "A<int>" as ABC
|
||||
class "A<std::string>" as ABCD
|
||||
|
||||
class "B" as C_0000000047
|
||||
class C_0000000047 {
|
||||
+A<int> aint
|
||||
+A<std::string> astring
|
||||
}
|
||||
|
||||
C_0000000046 <|.. ABC
|
||||
C_0000000046 <|.. ABCD
|
||||
|
||||
ABC <-- C_0000000047 : aint
|
||||
ABCD <-- C_0000000047 : astring
|
||||
|
||||
@enduml
|
||||
*/
|
||||
namespace clanguml {
|
||||
namespace t00009 {
|
||||
|
||||
@@ -37,7 +12,8 @@ public:
|
||||
class B {
|
||||
public:
|
||||
A<int> aint;
|
||||
A<std::string> astring;
|
||||
A<std::string> *astring;
|
||||
A<std::vector<std::string>> &avector;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,18 +47,20 @@ TEST_CASE("Test t00009", "[unit-test]")
|
||||
REQUIRE_THAT(puml, IsClassTemplate("A", "T"));
|
||||
REQUIRE_THAT(puml, IsClass(_A("B")));
|
||||
|
||||
/*
|
||||
REQUIRE_THAT(puml, IsField(Public("T value")));
|
||||
REQUIRE_THAT(puml, IsField(Public("T * pointer")));
|
||||
REQUIRE_THAT(puml, IsField(Public("T & reference")));
|
||||
REQUIRE_THAT(puml, IsField(Public("std::vector<P> values")));
|
||||
REQUIRE_THAT(puml, IsField(Public("std::array<int, N> ints")));
|
||||
REQUIRE_THAT(puml, IsField(Public("bool (*)(int, int) comparator")));
|
||||
REQUIRE_THAT(puml, IsField(Public("A<int> aint")));
|
||||
REQUIRE_THAT(puml, IsField(Public("A<std::string> * astring")));
|
||||
REQUIRE_THAT(
|
||||
puml, IsField(Public("A<std::vector<std::string>> & avector")));
|
||||
|
||||
REQUIRE_THAT(puml, IsClassTemplate("B", "T, C<>"));
|
||||
REQUIRE_THAT(puml, IsInstantiation(_A("A<T>"), _A("A<int>")));
|
||||
REQUIRE_THAT(puml, IsInstantiation(_A("A<T>"), _A("A<std::string>")));
|
||||
|
||||
REQUIRE_THAT(puml, IsComposition(_A("B"), _A("A<int>"), "aint"));
|
||||
REQUIRE_THAT(puml, IsAssociation(_A("B"), _A("A<std::string>"), "astring"));
|
||||
REQUIRE_THAT(puml,
|
||||
IsAssociation(_A("B"), _A("A<std::vector<std::string>>"), "avector"));
|
||||
|
||||
REQUIRE_THAT(puml, IsField(Public("C<T> template_template")));
|
||||
*/
|
||||
save_puml(
|
||||
"./" + config.output_directory + "/" + diagram->name + ".puml", puml);
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ using clanguml::test::matchers::IsComposition;
|
||||
using clanguml::test::matchers::IsEnum;
|
||||
using clanguml::test::matchers::IsField;
|
||||
using clanguml::test::matchers::IsInnerClass;
|
||||
using clanguml::test::matchers::IsInstantiation;
|
||||
using clanguml::test::matchers::Private;
|
||||
using clanguml::test::matchers::Protected;
|
||||
using clanguml::test::matchers::Public;
|
||||
|
||||
@@ -286,6 +286,13 @@ ContainsMatcher IsAggregation(std::string const &from, std::string const &to,
|
||||
fmt::format("{} o-- {} : {}", from, to, label), caseSensitivity));
|
||||
}
|
||||
|
||||
ContainsMatcher IsInstantiation(std::string const &from, std::string const &to,
|
||||
CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
|
||||
{
|
||||
return ContainsMatcher(
|
||||
CasedString(fmt::format("{} ..|> {}", to, from), caseSensitivity));
|
||||
}
|
||||
|
||||
ContainsMatcher IsMethod(std::string const &name,
|
||||
CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user