Added template insantiation relation
This commit is contained in:
@@ -19,6 +19,9 @@
|
||||
|
||||
#include "cx/type.h"
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
namespace clanguml {
|
||||
namespace cx {
|
||||
|
||||
@@ -214,6 +217,11 @@ public:
|
||||
return clang_Cursor_getTemplateArgumentValue(m_cursor, i);
|
||||
}
|
||||
|
||||
cursor specialized_cursor_template() const
|
||||
{
|
||||
return clang_getSpecializedCursorTemplate(m_cursor);
|
||||
}
|
||||
|
||||
std::string usr() const { return to_string(clang_getCursorUSR(m_cursor)); }
|
||||
|
||||
const CXCursor &get() const { return m_cursor; }
|
||||
|
||||
42
src/cx/type.cc
Normal file
42
src/cx/type.cc
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* src/cx/type.cc
|
||||
*
|
||||
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "type.h"
|
||||
#include "cursor.h"
|
||||
|
||||
namespace clanguml {
|
||||
namespace cx {
|
||||
|
||||
cursor type::type_declaration() const
|
||||
{
|
||||
return {clang_getTypeDeclaration(m_type)};
|
||||
}
|
||||
|
||||
std::string type::instantiation_template() const
|
||||
{
|
||||
assert(is_template_instantiation());
|
||||
|
||||
auto s = spelling();
|
||||
auto it = s.find('<');
|
||||
auto template_base_name = s.substr(0, it);
|
||||
|
||||
auto cur = type_declaration();
|
||||
|
||||
return cur.fully_qualified();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,8 @@ namespace cx {
|
||||
|
||||
using util::to_string;
|
||||
|
||||
class cursor;
|
||||
|
||||
class type {
|
||||
public:
|
||||
type(CXType &&t)
|
||||
@@ -50,6 +52,8 @@ public:
|
||||
|
||||
type canonical() const { return {clang_getCanonicalType(m_type)}; }
|
||||
|
||||
bool is_unexposed() const { return kind() == CXType_Unexposed; }
|
||||
|
||||
bool is_const_qualified() const
|
||||
{
|
||||
return clang_isConstQualifiedType(m_type);
|
||||
@@ -72,12 +76,7 @@ public:
|
||||
|
||||
type pointee_type() const { return {clang_getPointeeType(m_type)}; }
|
||||
|
||||
/*
|
||||
*cursor type_declaration() const
|
||||
*{
|
||||
* return {clang_getTypeDeclaration(m_type)};
|
||||
*}
|
||||
*/
|
||||
cursor type_declaration() const;
|
||||
|
||||
/*
|
||||
*std::string type_kind_spelling() const
|
||||
@@ -151,7 +150,7 @@ public:
|
||||
bool is_relationship() const
|
||||
{
|
||||
return is_pointer() || is_record() || is_reference() || !is_pod() ||
|
||||
is_array() ||
|
||||
is_array() || is_template() ||
|
||||
(spelling().find("std::array") ==
|
||||
0 /* There must be a better way... */);
|
||||
}
|
||||
@@ -204,6 +203,15 @@ public:
|
||||
return clang_Type_getCXXRefQualifier(m_type);
|
||||
}
|
||||
|
||||
bool is_template_instantiation() const
|
||||
{
|
||||
auto s = spelling();
|
||||
auto it = s.find('<');
|
||||
return it != std::string::npos;
|
||||
}
|
||||
|
||||
std::string instantiation_template() const;
|
||||
|
||||
/**
|
||||
* @brief Remove all qualifiers from field declaration.
|
||||
*
|
||||
|
||||
@@ -88,6 +88,8 @@ public:
|
||||
return "+--";
|
||||
case relationship_t::kAssociation:
|
||||
return "-->";
|
||||
case relationship_t::kInstantiation:
|
||||
return "..|>";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
@@ -159,11 +161,22 @@ public:
|
||||
}
|
||||
|
||||
for (const auto &r : c.relationships) {
|
||||
std::string destination;
|
||||
if (r.type == relationship_t::kInstantiation) {
|
||||
destination = m_model.usr_to_name(
|
||||
m_config.using_namespace, r.destination);
|
||||
}
|
||||
else {
|
||||
destination = r.destination;
|
||||
}
|
||||
|
||||
ostr << m_model.to_alias(m_config.using_namespace,
|
||||
ns_relative(m_config.using_namespace, c.name))
|
||||
ns_relative(m_config.using_namespace,
|
||||
c.full_name(m_config.using_namespace)))
|
||||
<< " " << to_string(r.type) << " "
|
||||
<< m_model.to_alias(m_config.using_namespace,
|
||||
ns_relative(m_config.using_namespace, r.destination));
|
||||
ns_relative(m_config.using_namespace, destination));
|
||||
|
||||
if (!r.label.empty())
|
||||
ostr << " : " << r.label;
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@ enum class relationship_t {
|
||||
kAggregation,
|
||||
kContainment,
|
||||
kOwnership,
|
||||
kAssociation
|
||||
kAssociation,
|
||||
kInstantiation
|
||||
};
|
||||
|
||||
class element {
|
||||
@@ -112,14 +113,17 @@ struct class_template {
|
||||
|
||||
class class_ : public element {
|
||||
public:
|
||||
std::string usr;
|
||||
bool is_struct{false};
|
||||
bool is_template{false};
|
||||
bool is_template_instantiation{false};
|
||||
std::vector<class_member> members;
|
||||
std::vector<class_method> methods;
|
||||
std::vector<class_parent> bases;
|
||||
std::vector<std::string> inner_classes;
|
||||
std::vector<class_relationship> relationships;
|
||||
std::vector<class_template> templates;
|
||||
std::string base_template_usr;
|
||||
|
||||
std::string full_name(
|
||||
const std::vector<std::string> &using_namespaces) const
|
||||
@@ -186,6 +190,17 @@ struct diagram {
|
||||
|
||||
return full_name;
|
||||
}
|
||||
|
||||
std::string usr_to_name(const std::vector<std::string> &using_namespaces,
|
||||
const std::string &usr) const
|
||||
{
|
||||
for (const auto &c : classes) {
|
||||
if (c.usr == usr)
|
||||
return c.full_name(using_namespaces);
|
||||
}
|
||||
|
||||
throw std::runtime_error("Cannot resolve USR: " + usr);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,13 +56,15 @@ struct tu_context {
|
||||
};
|
||||
|
||||
template <typename T> struct element_visitor_context {
|
||||
element_visitor_context(T &e)
|
||||
element_visitor_context(diagram &d_, T &e)
|
||||
: element(e)
|
||||
, d{d_}
|
||||
{
|
||||
}
|
||||
tu_context *ctx;
|
||||
|
||||
T &element;
|
||||
diagram &d;
|
||||
};
|
||||
|
||||
enum CXChildVisitResult visit_if_cursor_valid(
|
||||
@@ -238,7 +240,8 @@ static enum CXChildVisitResult class_visitor(
|
||||
spdlog::info("Class {} has {} template arguments.", c.name,
|
||||
cursor.template_argument_count());
|
||||
|
||||
auto class_ctx = element_visitor_context<class_>(c);
|
||||
auto class_ctx =
|
||||
element_visitor_context<class_>(ctx->ctx->d, c);
|
||||
class_ctx.ctx = ctx->ctx;
|
||||
|
||||
clang_visitChildren(cursor.get(), class_visitor, &class_ctx);
|
||||
@@ -266,7 +269,7 @@ static enum CXChildVisitResult class_visitor(
|
||||
e.name = cursor.fully_qualified();
|
||||
e.namespace_ = ctx->ctx->namespace_;
|
||||
|
||||
auto enum_ctx = element_visitor_context<enum_>(e);
|
||||
auto enum_ctx = element_visitor_context<enum_>(ctx->ctx->d, e);
|
||||
enum_ctx.ctx = ctx->ctx;
|
||||
|
||||
clang_visitChildren(cursor.get(), enum_visitor, &enum_ctx);
|
||||
@@ -367,6 +370,43 @@ static enum CXChildVisitResult class_visitor(
|
||||
spdlog::info("Adding member {} {}::{} {}", m.type,
|
||||
ctx->element.name, cursor.spelling(), t);
|
||||
|
||||
if (t.is_unexposed()) {
|
||||
if (t.is_template_instantiation() &&
|
||||
t.type_declaration()
|
||||
.specialized_cursor_template()
|
||||
.kind() != CXCursor_InvalidFile) {
|
||||
spdlog::info(
|
||||
"Found template instantiation: {} ..|> {}",
|
||||
t.type_declaration(),
|
||||
t.type_declaration()
|
||||
.specialized_cursor_template());
|
||||
class_ tinst;
|
||||
tinst.name = t.type_declaration().spelling();
|
||||
tinst.is_template_instantiation = true;
|
||||
tinst.usr = t.type_declaration().usr();
|
||||
for (int i = 0; i < t.template_arguments_count();
|
||||
i++) {
|
||||
class_template ct;
|
||||
ct.type =
|
||||
t.template_argument_type(i).spelling();
|
||||
tinst.templates.emplace_back(std::move(ct));
|
||||
}
|
||||
tinst.base_template_usr =
|
||||
t.type_declaration()
|
||||
.specialized_cursor_template()
|
||||
.usr();
|
||||
|
||||
class_relationship r;
|
||||
r.destination = tinst.base_template_usr;
|
||||
r.type = relationship_t::kInstantiation;
|
||||
r.label = "";
|
||||
|
||||
tinst.relationships.emplace_back(std::move(r));
|
||||
|
||||
ctx->d.classes.emplace_back(std::move(tinst));
|
||||
}
|
||||
}
|
||||
|
||||
relationship_t relationship_type = relationship_t::kNone;
|
||||
|
||||
auto name = t.canonical().unqualified();
|
||||
@@ -407,9 +447,13 @@ static enum CXChildVisitResult class_visitor(
|
||||
|
||||
ctx->element.members.emplace_back(std::move(m));
|
||||
});
|
||||
ret = CXChildVisit_Continue;
|
||||
ret = CXChildVisit_Recurse;
|
||||
break;
|
||||
}
|
||||
case CXCursor_ClassTemplatePartialSpecialization: {
|
||||
spdlog::info("Found template specialization: {}", cursor);
|
||||
ret = CXChildVisit_Continue;
|
||||
} break;
|
||||
case CXCursor_CXXBaseSpecifier: {
|
||||
if (!config.should_include(cursor.referenced().fully_qualified())) {
|
||||
ret = CXChildVisit_Continue;
|
||||
@@ -493,11 +537,12 @@ static enum CXChildVisitResult translation_unit_visitor(
|
||||
|
||||
visit_if_cursor_valid(cursor, [ctx, is_struct](cx::cursor cursor) {
|
||||
class_ c{};
|
||||
c.usr = cursor.usr();
|
||||
c.is_struct = is_struct;
|
||||
c.name = cursor.fully_qualified();
|
||||
c.namespace_ = ctx->namespace_;
|
||||
|
||||
auto class_ctx = element_visitor_context<class_>(c);
|
||||
auto class_ctx = element_visitor_context<class_>(ctx->d, c);
|
||||
class_ctx.ctx = ctx;
|
||||
|
||||
clang_visitChildren(cursor.get(), class_visitor, &class_ctx);
|
||||
@@ -520,7 +565,7 @@ static enum CXChildVisitResult translation_unit_visitor(
|
||||
e.name = cursor.fully_qualified();
|
||||
e.namespace_ = ctx->namespace_;
|
||||
|
||||
auto enum_ctx = element_visitor_context<enum_>(e);
|
||||
auto enum_ctx = element_visitor_context<enum_>(ctx->d, e);
|
||||
enum_ctx.ctx = ctx;
|
||||
|
||||
clang_visitChildren(cursor.get(), enum_visitor, &enum_ctx);
|
||||
|
||||
Reference in New Issue
Block a user