Extended nested class test case with nested template instantiations

This commit is contained in:
Bartek Kryza
2022-09-13 01:18:05 +02:00
parent 56e1010142
commit 001b093175
4 changed files with 86 additions and 26 deletions

View File

@@ -161,12 +161,14 @@ bool translation_unit_visitor::VisitEnumDecl(clang::EnumDecl *enm)
// If not, check if the parent template declaration is in the model
if (!id_opt) {
local_id = static_cast<const clang::RecordDecl *>(parent)
->getDescribedTemplate()
->getID();
if (static_cast<const clang::RecordDecl *>(parent)
->getDescribedTemplate())
->getDescribedTemplate()) {
local_id = static_cast<const clang::RecordDecl *>(parent)
->getDescribedTemplate()
->getID();
id_opt = get_ast_local_id(local_id);
}
}
assert(id_opt);
@@ -358,13 +360,24 @@ bool translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *cls)
cls->getQualifiedNameAsString(),
cls->getLocation().printToString(source_manager_));
if (!cls->getParent()->isRecord())
// Templated records are handled by VisitClassTemplateDecl()
// unless they are nested in template classes
if (cls->isTemplated() || cls->isTemplateDecl() ||
(clang::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(
cls) != nullptr))
LOG_DBG(
"== getQualifiedNameAsString() = {}", cls->getQualifiedNameAsString());
LOG_DBG("== getID() = {}", cls->getID());
LOG_DBG("== isTemplateDecl() = {}", cls->isTemplateDecl());
LOG_DBG("== isTemplated() = {}", cls->isTemplated());
LOG_DBG("== getParent()->isRecord()() = {}", cls->getParent()->isRecord());
if (cls->getParent()->isRecord()) {
LOG_DBG("== getParent()->getQualifiedNameAsString() = {}",
clang::dyn_cast<clang::RecordDecl>(cls->getParent())
->getQualifiedNameAsString());
}
if (cls->isTemplated() && cls->getDescribedTemplate()) {
// If the described templated of this class is already in the model
// skip it:
if (get_ast_local_id(cls->getDescribedTemplate()->getID()))
return true;
}
// TODO: Add support for classes defined in function/method bodies
if (cls->isLocalClass())
@@ -1331,7 +1344,8 @@ void translation_unit_visitor::process_template_specialization_argument(
}
}
else {
LOG_ERROR("Unsupported template argument kind {}", arg.getKind());
LOG_ERROR("Unsupported template argument kind {} [{}]", arg.getKind(),
cls->getLocation().printToString(source_manager_));
}
}
@@ -1462,8 +1476,8 @@ std::unique_ptr<class_> translation_unit_visitor::
{relationship_t::kInstantiation, templated_decl_local_id});
}
else if (diagram().should_include(qualified_name)) {
LOG_DBG("Skipping instantiation relationship from {}",
template_instantiation_ptr->full_name(false));
LOG_DBG("Skipping instantiation relationship from {} to {}",
template_instantiation_ptr->full_name(false), templated_decl_id);
}
return template_instantiation_ptr;
@@ -1502,15 +1516,28 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
template_type.desugar(),
template_type.getTemplateName().getAsTemplateDecl()->getASTContext());
const auto *template_decl{
template_type.getTemplateName().getAsTemplateDecl()};
auto *template_decl{template_type.getTemplateName().getAsTemplateDecl()};
auto qualified_name = template_decl->getQualifiedNameAsString();
namespace_ ns{qualified_name};
ns.pop_back();
template_instantiation.set_name(template_decl->getNameAsString());
template_instantiation.set_namespace(ns);
auto *class_template_decl{
clang::dyn_cast<clang::ClassTemplateDecl>(template_decl)};
if (parent.has_value() && class_template_decl &&
class_template_decl->getTemplatedDecl() &&
class_template_decl->getTemplatedDecl()->getParent() &&
class_template_decl->getTemplatedDecl()->getParent()->isRecord()) {
template_instantiation.set_name(parent.value()->full_name_no_ns() +
"##" + template_decl->getNameAsString());
template_instantiation.set_namespace(parent.value()->get_namespace());
}
else {
namespace_ ns{qualified_name};
ns.pop_back();
template_instantiation.set_name(template_decl->getNameAsString());
template_instantiation.set_namespace(ns);
}
// TODO: Refactor handling of base parameters to a separate method
@@ -1618,9 +1645,13 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
template_instantiation.add_relationship(
{relationship_t::kInstantiation, templated_decl_local_id});
}
else if (diagram().should_include(qualified_name)) {
LOG_DBG("Skipping instantiation relationship from {}",
template_instantiation_ptr->full_name(false));
else {
LOG_DBG("== Cannot determine global id for specialization template {} "
"- delaying until the translation unit is complete ",
templated_decl_id);
template_instantiation.add_relationship(
{relationship_t::kInstantiation, templated_decl_id});
}
template_instantiation.set_id(
@@ -1994,10 +2025,6 @@ void translation_unit_visitor::process_field(
// Process the type which is template instantiation of some sort
if (template_field_type != nullptr &&
!field_type_is_template_template_parameter) {
const auto template_field_decl_name =
template_field_type->getTemplateName()
.getAsTemplateDecl()
->getQualifiedNameAsString();
// Build the template instantiation for the field type
auto template_specialization_ptr = build_template_instantiation(
@@ -2107,9 +2134,29 @@ void translation_unit_visitor::add_incomplete_forward_declarations()
forward_declarations_.clear();
}
void translation_unit_visitor::resolve_local_to_global_ids()
{
// TODO: Refactor to a map with relationships attached to references
// to elements
for (auto &cls : diagram().classes()) {
for (auto &rel : cls.get().relationships()) {
if (rel.type() == relationship_t::kInstantiation) {
const auto maybe_local_id = rel.destination();
if (get_ast_local_id(maybe_local_id)) {
LOG_DBG("= Resolved instantiation destination from local "
"id {} to global id {}",
maybe_local_id, *get_ast_local_id(maybe_local_id));
rel.set_destination(*get_ast_local_id(maybe_local_id));
}
}
}
}
}
void translation_unit_visitor::finalize()
{
add_incomplete_forward_declarations();
resolve_local_to_global_ids();
}
bool translation_unit_visitor::simplify_system_template(

View File

@@ -215,6 +215,8 @@ private:
void add_incomplete_forward_declarations();
void resolve_local_to_global_ids();
bool simplify_system_template(
model::template_parameter &ct, const std::string &full_name);

View File

@@ -32,6 +32,12 @@ public:
enum class CCC { CCC_1, CCC_2 };
};
template <typename V> class B {
V b;
};
B<int> b_int;
enum class CC { CC_1, CC_2 };
};

View File

@@ -58,6 +58,11 @@ TEST_CASE("t00004", "[test-case][class]")
REQUIRE_THAT(puml, IsInnerClass(_A("C<T>"), _A("C<T>::CC")));
REQUIRE_THAT(puml, IsInnerClass(_A("C<T>::AA"), _A("C<T>::AA::CCC")));
REQUIRE_THAT(puml, IsInnerClass(_A("C<T>"), _A("C<T>::B<V>")));
REQUIRE_THAT(puml, IsAggregation(_A("C<T>"), _A("C<T>::B<int>"), "+b_int"));
REQUIRE_THAT(puml, !IsInnerClass(_A("C<T>"), _A("C<T>::B")));
REQUIRE_THAT(puml, IsInstantiation(_A("C<T>::B<V>"), _A("C<T>::B<int>")));
REQUIRE_THAT(puml, IsClass(_A("detail::D")));
REQUIRE_THAT(puml, IsClass(_A("detail::D::DD")));
REQUIRE_THAT(puml, IsEnum(_A("detail::D::AA")));