Ported template instantiation handling to cppast

This commit is contained in:
Bartek Kryza
2021-03-28 22:21:41 +02:00
parent 1daf611329
commit b61143a5b2
12 changed files with 642 additions and 622 deletions

View File

@@ -44,7 +44,7 @@ std::string full_name(const cppast::cpp_entity &e);
std::string fully_prefixed(const cppast::cpp_entity &e); std::string fully_prefixed(const cppast::cpp_entity &e);
const cppast::cpp_type& unreferenced(const cppast::cpp_type &t); const cppast::cpp_type &unreferenced(const cppast::cpp_type &t);
} // namespace util } // namespace util
} // namespace cx } // namespace cx

View File

@@ -67,37 +67,37 @@ public:
std::string to_string(scope_t scope) const std::string to_string(scope_t scope) const
{ {
switch (scope) { switch (scope) {
case scope_t::kPublic: case scope_t::kPublic:
return "+"; return "+";
case scope_t::kProtected: case scope_t::kProtected:
return "#"; return "#";
case scope_t::kPrivate: case scope_t::kPrivate:
return "-"; return "-";
default: default:
return ""; return "";
} }
} }
std::string to_string(relationship_t r) const std::string to_string(relationship_t r) const
{ {
switch (r) { switch (r) {
case relationship_t::kOwnership: case relationship_t::kOwnership:
case relationship_t::kComposition: case relationship_t::kComposition:
return "*--"; return "*--";
case relationship_t::kAggregation: case relationship_t::kAggregation:
return "o--"; return "o--";
case relationship_t::kContainment: case relationship_t::kContainment:
return "--+"; return "--+";
case relationship_t::kAssociation: case relationship_t::kAssociation:
return "-->"; return "-->";
case relationship_t::kInstantiation: case relationship_t::kInstantiation:
return "..|>"; return "..|>";
case relationship_t::kFriendship: case relationship_t::kFriendship:
return "<.."; return "<..";
case relationship_t::kDependency: case relationship_t::kDependency:
return "..>"; return "..>";
default: default:
return ""; return "";
} }
} }

View File

@@ -54,12 +54,12 @@ public:
std::string to_string(message_t r) const std::string to_string(message_t r) const
{ {
switch (r) { switch (r) {
case message_t::kCall: case message_t::kCall:
return "->"; return "->";
case message_t::kReturn: case message_t::kReturn:
return "<--"; return "<--";
default: default:
return ""; return "";
} }
} }

View File

@@ -26,32 +26,30 @@ std::atomic_uint64_t element::m_nextId = 1;
std::string to_string(relationship_t r) std::string to_string(relationship_t r)
{ {
switch (r) { switch (r) {
case relationship_t::kNone: case relationship_t::kNone:
return "none"; return "none";
case relationship_t::kExtension: case relationship_t::kExtension:
return "extension"; return "extension";
case relationship_t::kComposition: case relationship_t::kComposition:
return "composition"; return "composition";
case relationship_t::kAggregation: case relationship_t::kAggregation:
return "aggregation"; return "aggregation";
case relationship_t::kContainment: case relationship_t::kContainment:
return "containment"; return "containment";
case relationship_t::kOwnership: case relationship_t::kOwnership:
return "ownership"; return "ownership";
case relationship_t::kAssociation: case relationship_t::kAssociation:
return "association"; return "association";
case relationship_t::kInstantiation: case relationship_t::kInstantiation:
return "instantiation"; return "instantiation";
case relationship_t::kFriendship: case relationship_t::kFriendship:
return "frendship"; return "frendship";
case relationship_t::kDependency: case relationship_t::kDependency:
return "dependency"; return "dependency";
default: default:
return "invalid"; return "invalid";
} }
} }
} }
} }
} }

View File

@@ -77,8 +77,8 @@ void tu_visitor::operator()(const cppast::cpp_entity &file)
} }
if (e.kind() == cppast::cpp_entity_kind::class_t) { if (e.kind() == cppast::cpp_entity_kind::class_t) {
spdlog::debug("'{}' - {}", cx::util::full_name(e), spdlog::debug("========== Visiting '{}' - {}",
cppast::to_string(e.kind())); cx::util::full_name(e), cppast::to_string(e.kind()));
auto &cls = static_cast<const cppast::cpp_class &>(e); auto &cls = static_cast<const cppast::cpp_class &>(e);
@@ -86,8 +86,8 @@ void tu_visitor::operator()(const cppast::cpp_entity &file)
process_class_declaration(cls); process_class_declaration(cls);
} }
else if (e.kind() == cppast::cpp_entity_kind::enum_t) { else if (e.kind() == cppast::cpp_entity_kind::enum_t) {
spdlog::debug("'{}' - {}", cx::util::full_name(e), spdlog::debug("========== Visiting '{}' - {}",
cppast::to_string(e.kind())); cx::util::full_name(e), cppast::to_string(e.kind()));
auto &enm = static_cast<const cppast::cpp_enum &>(e); auto &enm = static_cast<const cppast::cpp_enum &>(e);
@@ -146,6 +146,7 @@ void tu_visitor::process_class_declaration(const cppast::cpp_class &cls)
} }
else if (child.kind() == cppast::cpp_entity_kind::member_variable_t) { else if (child.kind() == cppast::cpp_entity_kind::member_variable_t) {
auto &mv = static_cast<const cppast::cpp_member_variable &>(child); auto &mv = static_cast<const cppast::cpp_member_variable &>(child);
spdlog::debug("Found member variable {}", mv.name());
process_field(mv, c, last_access_specifier); process_field(mv, c, last_access_specifier);
} }
else if (child.kind() == cppast::cpp_entity_kind::variable_t) { else if (child.kind() == cppast::cpp_entity_kind::variable_t) {
@@ -168,11 +169,10 @@ void tu_visitor::process_class_declaration(const cppast::cpp_class &cls)
auto &mc = static_cast<const cppast::cpp_destructor &>(child); auto &mc = static_cast<const cppast::cpp_destructor &>(child);
process_destructor(mc, c, last_access_specifier); process_destructor(mc, c, last_access_specifier);
} }
else if (child.kind() == cppast::cpp_entity_kind::friend_t) { else if (child.kind() == cppast::cpp_entity_kind::friend_t) {
auto &fr = static_cast<const cppast::cpp_friend &>(child); auto &fr = static_cast<const cppast::cpp_friend &>(child);
spdlog::debug("Found friend declaration: {}, {}", spdlog::debug("Found friend declaration: {}, {}", child.name(),
child.name(),
child.scope_name() ? child.scope_name().value().name() child.scope_name() ? child.scope_name().value().name()
: "<no-scope>"); : "<no-scope>");
@@ -187,8 +187,8 @@ void tu_visitor::process_class_declaration(const cppast::cpp_class &cls)
process_friend(fr, c); process_friend(fr, c);
} }
else { else {
spdlog::debug("Found some other class child: {} ({})", spdlog::debug("Found some other class child: {} ({})", child.name(),
child.name(), cppast::to_string(child.kind())); cppast::to_string(child.kind()));
} }
} }
@@ -217,10 +217,13 @@ void tu_visitor::process_class_declaration(const cppast::cpp_class &cls)
// Process class template arguments // Process class template arguments
if (cppast::is_templated(cls)) { if (cppast::is_templated(cls)) {
spdlog::debug("Processing class template parameters...");
auto scope = cppast::cpp_scope_name(type_safe::ref(cls)); auto scope = cppast::cpp_scope_name(type_safe::ref(cls));
for (const auto &tp : scope.template_parameters()) { for (const auto &tp : scope.template_parameters()) {
if (tp.kind() == if (tp.kind() ==
cppast::cpp_entity_kind::template_type_parameter_t) { cppast::cpp_entity_kind::template_type_parameter_t) {
spdlog::debug(
"Processing template type parameter {}", tp.name());
process_template_type_parameter( process_template_type_parameter(
static_cast<const cppast::cpp_template_type_parameter &>( static_cast<const cppast::cpp_template_type_parameter &>(
tp), tp),
@@ -228,6 +231,8 @@ void tu_visitor::process_class_declaration(const cppast::cpp_class &cls)
} }
else if (tp.kind() == else if (tp.kind() ==
cppast::cpp_entity_kind::non_type_template_parameter_t) { cppast::cpp_entity_kind::non_type_template_parameter_t) {
spdlog::debug(
"Processing template nontype parameter {}", tp.name());
process_template_nontype_parameter( process_template_nontype_parameter(
static_cast< static_cast<
const cppast::cpp_non_type_template_parameter &>(tp), const cppast::cpp_non_type_template_parameter &>(tp),
@@ -235,6 +240,8 @@ void tu_visitor::process_class_declaration(const cppast::cpp_class &cls)
} }
else if (tp.kind() == else if (tp.kind() ==
cppast::cpp_entity_kind::template_template_parameter_t) { cppast::cpp_entity_kind::template_template_parameter_t) {
spdlog::debug(
"Processing template template parameter {}", tp.name());
process_template_template_parameter( process_template_template_parameter(
static_cast< static_cast<
const cppast::cpp_template_template_parameter &>(tp), const cppast::cpp_template_template_parameter &>(tp),
@@ -281,7 +288,14 @@ void tu_visitor::process_field(const cppast::cpp_member_variable &mv, class_ &c,
m.is_static = false; m.is_static = false;
const auto &tr = cx::util::unreferenced(mv.type()); const auto &tr = cx::util::unreferenced(mv.type());
spdlog::debug(
"Processing field with unreferenced type of kind {}", tr.kind());
if (tr.kind() == cppast::cpp_type_kind::template_instantiation_t) { if (tr.kind() == cppast::cpp_type_kind::template_instantiation_t) {
spdlog::debug("Processing field with template instatiation type {}",
cppast::to_string(tr));
const auto &template_instantiation_type = const auto &template_instantiation_type =
static_cast<const cppast::cpp_template_instantiation_type &>(tr); static_cast<const cppast::cpp_template_instantiation_type &>(tr);
if (template_instantiation_type.primary_template() if (template_instantiation_type.primary_template()
@@ -325,6 +339,11 @@ void tu_visitor::process_field(const cppast::cpp_member_variable &mv, class_ &c,
} }
} }
} }
else if (tr.kind() == cppast::cpp_type_kind::unexposed_t) {
spdlog::debug(
"Processing field with unexposed type {}", cppast::to_string(tr));
// TODO
}
if (mv.type().kind() != cppast::cpp_type_kind::builtin_t) { if (mv.type().kind() != cppast::cpp_type_kind::builtin_t) {
std::vector<std::pair<std::string, relationship_t>> relationships; std::vector<std::pair<std::string, relationship_t>> relationships;
@@ -614,8 +633,9 @@ void tu_visitor::find_relationships(const cppast::cpp_type &t_,
} }
else { else {
for (const auto &arg : args) { for (const auto &arg : args) {
find_relationships( if (arg.type())
arg.type().value(), relationships, relationship_type); find_relationships(
arg.type().value(), relationships, relationship_type);
} }
} }
} }
@@ -675,6 +695,11 @@ class_ tu_visitor::build_template_instantiation(const cppast::cpp_entity &e,
ct.type = ct.type =
static_cast<const cppast::cpp_literal_expression &>(exp) static_cast<const cppast::cpp_literal_expression &>(exp)
.value(); .value();
else if (exp.kind() == cppast::cpp_expression_kind::unexposed_t)
ct.type =
static_cast<const cppast::cpp_unexposed_expression &>(exp)
.expression()
.as_string();
} }
spdlog::debug("Adding template argument '{}'", ct.type); spdlog::debug("Adding template argument '{}'", ct.type);

View File

@@ -65,100 +65,97 @@ static enum CXChildVisitResult translation_unit_visitor(
} }
switch (cursor.kind()) { switch (cursor.kind()) {
case CXCursor_FunctionTemplate: case CXCursor_FunctionTemplate:
case CXCursor_CXXMethod: case CXCursor_CXXMethod:
case CXCursor_FunctionDecl: case CXCursor_FunctionDecl:
ctx->current_method = cursor; ctx->current_method = cursor;
ret = CXChildVisit_Recurse; ret = CXChildVisit_Recurse;
break; break;
case CXCursor_CallExpr: { case CXCursor_CallExpr: {
auto referenced = cursor.referenced(); auto referenced = cursor.referenced();
auto referenced_type = referenced.type(); auto referenced_type = referenced.type();
auto referenced_cursor_name = referenced.display_name(); auto referenced_cursor_name = referenced.display_name();
auto semantic_parent = referenced.semantic_parent(); auto semantic_parent = referenced.semantic_parent();
auto sp_name = semantic_parent.fully_qualified(); auto sp_name = semantic_parent.fully_qualified();
auto lexical_parent = cursor.lexical_parent(); auto lexical_parent = cursor.lexical_parent();
auto lp_name = lexical_parent.spelling(); auto lp_name = lexical_parent.spelling();
CXFile f; CXFile f;
unsigned int line{}; unsigned int line{};
unsigned int column{}; unsigned int column{};
unsigned int offset{}; unsigned int offset{};
clang_getFileLocation( clang_getFileLocation(cursor.location(), &f, &line, &column, &offset);
cursor.location(), &f, &line, &column, &offset); std::string file{clang_getCString(clang_getFileName(f))};
std::string file{clang_getCString(clang_getFileName(f))};
auto &d = ctx->d; auto &d = ctx->d;
auto &config = ctx->config; auto &config = ctx->config;
if (referenced.kind() == CXCursor_CXXMethod) { if (referenced.kind() == CXCursor_CXXMethod) {
if (config.should_include(sp_name)) { if (config.should_include(sp_name)) {
// Get calling object // Get calling object
std::string caller{}; std::string caller{};
if (ctx->current_method.semantic_parent() if (ctx->current_method.semantic_parent()
.is_translation_unit() || .is_translation_unit() ||
ctx->current_method.semantic_parent().is_namespace()) { ctx->current_method.semantic_parent().is_namespace()) {
caller = ctx->current_method.semantic_parent() caller = ctx->current_method.semantic_parent()
.fully_qualified() + .fully_qualified() +
"::" + ctx->current_method.spelling() + "()"; "::" + ctx->current_method.spelling() + "()";
} }
else { else {
caller = ctx->current_method.semantic_parent() caller =
.fully_qualified(); ctx->current_method.semantic_parent().fully_qualified();
}
auto caller_usr = ctx->current_method.usr();
// Get called object
auto callee =
referenced.semantic_parent().fully_qualified();
auto callee_usr = referenced.semantic_parent().usr();
// Get called method
auto called_message = cursor.spelling();
// Found method call: CXCursorKind () const
spdlog::debug(
"Adding method call at line {}:{} to diagram {}"
"\n\tCURRENT_METHOD: {}\n\tFROM: '{}'\n\tTO: "
"{}\n\tMESSAGE: {}\n\tFROM_USR: {}\n\tTO_USR: "
"{}\n\tRETURN_TYPE: {}",
file, line, d.name, ctx->current_method.spelling(),
caller, callee, called_message, caller_usr, callee_usr,
referenced.type().result_type().spelling());
message m;
m.type = message_t::kCall;
m.from = caller;
m.from_usr = caller_usr;
m.line = line;
m.to = callee;
m.to_usr = referenced.usr();
m.message = called_message;
m.return_type = referenced.type().result_type().spelling();
if (d.sequences.find(caller_usr) == d.sequences.end()) {
activity a;
a.usr = caller_usr;
a.from = caller;
d.sequences.insert({caller_usr, std::move(a)});
}
d.sequences[caller_usr].messages.emplace_back(std::move(m));
} }
}
else if (referenced.kind() == CXCursor_FunctionDecl) {
// TODO
}
ret = CXChildVisit_Recurse; auto caller_usr = ctx->current_method.usr();
break; // Get called object
auto callee = referenced.semantic_parent().fully_qualified();
auto callee_usr = referenced.semantic_parent().usr();
// Get called method
auto called_message = cursor.spelling();
// Found method call: CXCursorKind () const
spdlog::debug("Adding method call at line {}:{} to diagram {}"
"\n\tCURRENT_METHOD: {}\n\tFROM: '{}'\n\tTO: "
"{}\n\tMESSAGE: {}\n\tFROM_USR: {}\n\tTO_USR: "
"{}\n\tRETURN_TYPE: {}",
file, line, d.name, ctx->current_method.spelling(), caller,
callee, called_message, caller_usr, callee_usr,
referenced.type().result_type().spelling());
message m;
m.type = message_t::kCall;
m.from = caller;
m.from_usr = caller_usr;
m.line = line;
m.to = callee;
m.to_usr = referenced.usr();
m.message = called_message;
m.return_type = referenced.type().result_type().spelling();
if (d.sequences.find(caller_usr) == d.sequences.end()) {
activity a;
a.usr = caller_usr;
a.from = caller;
d.sequences.insert({caller_usr, std::move(a)});
}
d.sequences[caller_usr].messages.emplace_back(std::move(m));
}
} }
case CXCursor_Namespace: { else if (referenced.kind() == CXCursor_FunctionDecl) {
ret = CXChildVisit_Recurse; // TODO
break;
} }
default:
ret = CXChildVisit_Recurse; ret = CXChildVisit_Recurse;
break;
}
case CXCursor_Namespace: {
ret = CXChildVisit_Recurse;
break;
}
default:
ret = CXChildVisit_Recurse;
} }
return ret; return ret;

File diff suppressed because it is too large Load Diff

View File

@@ -56,7 +56,8 @@ TEST_CASE("t00003", "[test-case][class]")
REQUIRE_THAT(puml, IsField(Public("int public_member"))); REQUIRE_THAT(puml, IsField(Public("int public_member")));
REQUIRE_THAT(puml, IsField(Protected("int protected_member"))); REQUIRE_THAT(puml, IsField(Protected("int protected_member")));
REQUIRE_THAT(puml, IsField(Private("int private_member"))); REQUIRE_THAT(puml, IsField(Private("int private_member")));
REQUIRE_THAT(puml, IsField(Static(Public("unsigned long const auto_member")))); REQUIRE_THAT(
puml, IsField(Static(Public("unsigned long const auto_member"))));
REQUIRE_THAT(puml, IsField(Private("int a"))); REQUIRE_THAT(puml, IsField(Private("int a")));
REQUIRE_THAT(puml, IsField(Private("int b"))); REQUIRE_THAT(puml, IsField(Private("int b")));

View File

@@ -48,8 +48,7 @@ TEST_CASE("t00009", "[test-case][class]")
REQUIRE_THAT(puml, IsField(Public("T value"))); REQUIRE_THAT(puml, IsField(Public("T value")));
REQUIRE_THAT(puml, IsField(Public("A<int> aint"))); REQUIRE_THAT(puml, IsField(Public("A<int> aint")));
REQUIRE_THAT(puml, IsField(Public("A<std::string>* astring"))); REQUIRE_THAT(puml, IsField(Public("A<std::string>* astring")));
REQUIRE_THAT( REQUIRE_THAT(puml, IsField(Public("A<std::vector<std::string>>& avector")));
puml, IsField(Public("A<std::vector<std::string>>& avector")));
REQUIRE_THAT(puml, IsInstantiation(_A("A<T>"), _A("A<int>"))); REQUIRE_THAT(puml, IsInstantiation(_A("A<T>"), _A("A<int>")));
REQUIRE_THAT(puml, IsInstantiation(_A("A<T>"), _A("A<std::string>"))); REQUIRE_THAT(puml, IsInstantiation(_A("A<T>"), _A("A<std::string>")));

View File

@@ -47,7 +47,7 @@ TEST_CASE("t00011", "[test-case][class]")
REQUIRE_THAT(puml, IsClass(_A("D<T>"))); REQUIRE_THAT(puml, IsClass(_A("D<T>")));
REQUIRE_THAT(puml, IsFriend(_A("A"), _A("B"))); REQUIRE_THAT(puml, IsFriend(_A("A"), _A("B")));
//REQUIRE_THAT(puml, IsFriend(_A("A"), _A("D<T>"))); // REQUIRE_THAT(puml, IsFriend(_A("A"), _A("D<T>")));
save_puml( save_puml(
"./" + config.output_directory + "/" + diagram->name + ".puml", puml); "./" + config.output_directory + "/" + diagram->name + ".puml", puml);

View File

@@ -3,6 +3,7 @@
#include <numeric> #include <numeric>
#include <string> #include <string>
#include <variant> #include <variant>
#include <vector>
namespace clanguml { namespace clanguml {
namespace t00012 { namespace t00012 {

View File

@@ -50,7 +50,7 @@ TEST_CASE("t00012", "[test-case][class]")
puml, IsInstantiation(_A("B<int Is...>"), _A("B<1, 1, 1, 1>"))); puml, IsInstantiation(_A("B<int Is...>"), _A("B<1, 1, 1, 1>")));
REQUIRE_THAT(puml, REQUIRE_THAT(puml,
IsInstantiation(_A("C<T, int Is...>"), IsInstantiation(_A("C<T, int Is...>"),
_A("C<std::map<int, " _A("C<std::map<int,"
"std::vector<std::vector<std::vector<std::string>>>>, 3, 3, " "std::vector<std::vector<std::vector<std::string>>>>, 3, 3, "
"3>"))); "3>")));