Refactored template_builder to common namespace (#227)
This commit is contained in:
@@ -25,7 +25,7 @@
|
|||||||
namespace clanguml::class_diagram::model {
|
namespace clanguml::class_diagram::model {
|
||||||
|
|
||||||
class_::class_(const common::model::namespace_ &using_namespace)
|
class_::class_(const common::model::namespace_ &using_namespace)
|
||||||
: element{using_namespace}
|
: template_element{using_namespace}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,10 +33,6 @@ bool class_::is_struct() const { return is_struct_; }
|
|||||||
|
|
||||||
void class_::is_struct(bool is_struct) { is_struct_ = is_struct; }
|
void class_::is_struct(bool is_struct) { is_struct_ = is_struct; }
|
||||||
|
|
||||||
bool class_::is_template() const { return is_template_; }
|
|
||||||
|
|
||||||
void class_::is_template(bool is_template) { is_template_ = is_template; }
|
|
||||||
|
|
||||||
bool class_::is_union() const { return is_union_; }
|
bool class_::is_union() const { return is_union_; }
|
||||||
|
|
||||||
void class_::is_union(bool is_union) { is_union_ = is_union; }
|
void class_::is_union(bool is_union) { is_union_ = is_union; }
|
||||||
@@ -115,27 +111,6 @@ bool class_::is_abstract() const
|
|||||||
[](const auto &method) { return method.is_pure_virtual(); });
|
[](const auto &method) { return method.is_pure_virtual(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
int class_::calculate_template_specialization_match(const class_ &other) const
|
|
||||||
{
|
|
||||||
int res{0};
|
|
||||||
|
|
||||||
if (name_and_ns() != other.name_and_ns()) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return template_trait::calculate_template_specialization_match(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
void class_::template_specialization_found(bool found)
|
|
||||||
{
|
|
||||||
template_specialization_found_ = found;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool class_::template_specialization_found() const
|
|
||||||
{
|
|
||||||
return template_specialization_found_;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::string> class_::doxygen_link() const
|
std::optional<std::string> class_::doxygen_link() const
|
||||||
{
|
{
|
||||||
const auto *type = is_struct() ? "struct" : "class";
|
const auto *type = is_struct() ? "struct" : "class";
|
||||||
|
|||||||
@@ -20,9 +20,9 @@
|
|||||||
#include "class_member.h"
|
#include "class_member.h"
|
||||||
#include "class_method.h"
|
#include "class_method.h"
|
||||||
#include "class_parent.h"
|
#include "class_parent.h"
|
||||||
#include "common/model/element.h"
|
|
||||||
#include "common/model/enums.h"
|
#include "common/model/enums.h"
|
||||||
#include "common/model/stylable_element.h"
|
#include "common/model/stylable_element.h"
|
||||||
|
#include "common/model/template_element.h"
|
||||||
#include "common/model/template_parameter.h"
|
#include "common/model/template_parameter.h"
|
||||||
#include "common/model/template_trait.h"
|
#include "common/model/template_trait.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
@@ -35,9 +35,8 @@ namespace clanguml::class_diagram::model {
|
|||||||
/**
|
/**
|
||||||
* @brief Diagram element representing a class or class template.
|
* @brief Diagram element representing a class or class template.
|
||||||
*/
|
*/
|
||||||
class class_ : public common::model::element,
|
class class_ : public common::model::template_element,
|
||||||
public common::model::stylable_element,
|
public common::model::stylable_element {
|
||||||
public template_trait {
|
|
||||||
public:
|
public:
|
||||||
class_(const common::model::namespace_ &using_namespace);
|
class_(const common::model::namespace_ &using_namespace);
|
||||||
|
|
||||||
@@ -69,20 +68,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void is_struct(bool is_struct);
|
void is_struct(bool is_struct);
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the class is a template.
|
|
||||||
*
|
|
||||||
* @return True, if the class is a template.
|
|
||||||
*/
|
|
||||||
bool is_template() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set, whether the class is a template.
|
|
||||||
*
|
|
||||||
* @param is_struct True, if the class is a template.
|
|
||||||
*/
|
|
||||||
void is_template(bool is_template);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the class is a union.
|
* Whether or not the class is a union.
|
||||||
*
|
*
|
||||||
@@ -171,31 +156,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool is_abstract() const;
|
bool is_abstract() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Calculate template specialization match with other class.
|
|
||||||
*
|
|
||||||
* This method is a wrapper over
|
|
||||||
* @ref template_trait::calculate_template_specialization_match()
|
|
||||||
*
|
|
||||||
* @param other
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
int calculate_template_specialization_match(const class_ &other) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether, a template specialization has already been found for this class.
|
|
||||||
* @return True, if a template specialization has already been found.
|
|
||||||
*/
|
|
||||||
bool template_specialization_found() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set, whether a template specialization has already been found for this
|
|
||||||
* class.
|
|
||||||
*
|
|
||||||
* @param found True, if a template specialization has already been found.
|
|
||||||
*/
|
|
||||||
void template_specialization_found(bool found);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Generate Doxygen style HTML link for the class.
|
* @brief Generate Doxygen style HTML link for the class.
|
||||||
*
|
*
|
||||||
@@ -208,15 +168,12 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool is_struct_{false};
|
bool is_struct_{false};
|
||||||
bool is_template_{false};
|
|
||||||
bool is_union_{false};
|
bool is_union_{false};
|
||||||
std::vector<class_member> members_;
|
std::vector<class_member> members_;
|
||||||
std::vector<class_method> methods_;
|
std::vector<class_method> methods_;
|
||||||
std::vector<class_parent> bases_;
|
std::vector<class_parent> bases_;
|
||||||
std::string base_template_full_name_;
|
std::string base_template_full_name_;
|
||||||
std::string full_name_;
|
std::string full_name_;
|
||||||
|
|
||||||
bool template_specialization_found_{false};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace clanguml::class_diagram::model
|
} // namespace clanguml::class_diagram::model
|
||||||
|
|||||||
@@ -32,7 +32,26 @@ translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
|
|||||||
: common::visitor::translation_unit_visitor{sm, config}
|
: common::visitor::translation_unit_visitor{sm, config}
|
||||||
, diagram_{diagram}
|
, diagram_{diagram}
|
||||||
, config_{config}
|
, config_{config}
|
||||||
, template_builder_{*this}
|
, template_builder_{diagram_, config_, *this,
|
||||||
|
[uns = config_.using_namespace()](const clang::NamedDecl *decl) {
|
||||||
|
auto cls = std::make_unique<class_>(uns);
|
||||||
|
cls->is_struct(common::is_struct(decl));
|
||||||
|
return cls;
|
||||||
|
},
|
||||||
|
[this](common::model::template_element &template_instantiation_base,
|
||||||
|
const std::string &full_name, common::id_t templated_decl_id) {
|
||||||
|
find_instantiation_relationships(
|
||||||
|
template_instantiation_base, full_name, templated_decl_id);
|
||||||
|
},
|
||||||
|
[](clanguml::common::model::template_element &tinst,
|
||||||
|
clanguml::common::id_t id, const std::string &full_name) {
|
||||||
|
model::class_parent cp;
|
||||||
|
cp.set_access(common::model::access_t::kPublic);
|
||||||
|
cp.set_name(full_name);
|
||||||
|
cp.set_id(id);
|
||||||
|
|
||||||
|
dynamic_cast<class_ &>(tinst).add_parent(std::move(cp));
|
||||||
|
}}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +273,9 @@ bool translation_unit_visitor::VisitTypeAliasTemplateDecl(
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
auto template_specialization_ptr =
|
auto template_specialization_ptr =
|
||||||
tbuilder().build(cls, *template_type_specialization_ptr);
|
std::make_unique<class_>(config().using_namespace());
|
||||||
|
tbuilder().build(
|
||||||
|
*template_specialization_ptr, cls, *template_type_specialization_ptr);
|
||||||
|
|
||||||
if (!template_specialization_ptr)
|
if (!template_specialization_ptr)
|
||||||
return true;
|
return true;
|
||||||
@@ -1060,7 +1081,9 @@ void translation_unit_visitor::process_class_bases(
|
|||||||
else if (const auto *tsp =
|
else if (const auto *tsp =
|
||||||
base.getType()->getAs<clang::TemplateSpecializationType>();
|
base.getType()->getAs<clang::TemplateSpecializationType>();
|
||||||
tsp != nullptr) {
|
tsp != nullptr) {
|
||||||
auto template_specialization_ptr = tbuilder().build(cls, *tsp, {});
|
auto template_specialization_ptr =
|
||||||
|
std::make_unique<class_>(config().using_namespace());
|
||||||
|
tbuilder().build(*template_specialization_ptr, cls, *tsp, {});
|
||||||
if (template_specialization_ptr) {
|
if (template_specialization_ptr) {
|
||||||
cp.set_id(template_specialization_ptr->id());
|
cp.set_id(template_specialization_ptr->id());
|
||||||
}
|
}
|
||||||
@@ -1261,7 +1284,7 @@ void translation_unit_visitor::process_method(
|
|||||||
auto method_return_type =
|
auto method_return_type =
|
||||||
common::to_string(mf.getReturnType(), mf.getASTContext());
|
common::to_string(mf.getReturnType(), mf.getASTContext());
|
||||||
|
|
||||||
ensure_lambda_type_is_relative(method_return_type);
|
common::ensure_lambda_type_is_relative(config(), method_return_type);
|
||||||
|
|
||||||
auto method_name = mf.getNameAsString();
|
auto method_name = mf.getNameAsString();
|
||||||
if (mf.isTemplated()) {
|
if (mf.isTemplated()) {
|
||||||
@@ -1304,7 +1327,9 @@ void translation_unit_visitor::process_method(
|
|||||||
->getAs<clang::TemplateSpecializationType>();
|
->getAs<clang::TemplateSpecializationType>();
|
||||||
|
|
||||||
if (unaliased_type != nullptr) {
|
if (unaliased_type != nullptr) {
|
||||||
auto template_specialization_ptr = tbuilder().build(
|
auto template_specialization_ptr =
|
||||||
|
std::make_unique<class_>(config().using_namespace());
|
||||||
|
tbuilder().build(*template_specialization_ptr,
|
||||||
unaliased_type->getTemplateName().getAsTemplateDecl(),
|
unaliased_type->getTemplateName().getAsTemplateDecl(),
|
||||||
*unaliased_type, &c);
|
*unaliased_type, &c);
|
||||||
|
|
||||||
@@ -1652,7 +1677,7 @@ void translation_unit_visitor::process_function_parameter(
|
|||||||
auto parameter_type = common::to_string(p.getType(), p.getASTContext());
|
auto parameter_type = common::to_string(p.getType(), p.getASTContext());
|
||||||
|
|
||||||
// Is there no better way to determine that 'type' is a lambda?
|
// Is there no better way to determine that 'type' is a lambda?
|
||||||
ensure_lambda_type_is_relative(parameter_type);
|
common::ensure_lambda_type_is_relative(config(), parameter_type);
|
||||||
|
|
||||||
parameter.set_type(parameter_type);
|
parameter.set_type(parameter_type);
|
||||||
|
|
||||||
@@ -1678,7 +1703,9 @@ void translation_unit_visitor::process_function_parameter(
|
|||||||
.getUnqualifiedType()
|
.getUnqualifiedType()
|
||||||
->getAs<clang::TemplateSpecializationType>();
|
->getAs<clang::TemplateSpecializationType>();
|
||||||
templ != nullptr) {
|
templ != nullptr) {
|
||||||
auto template_specialization_ptr = tbuilder().build(
|
auto template_specialization_ptr =
|
||||||
|
std::make_unique<class_>(config().using_namespace());
|
||||||
|
tbuilder().build(*template_specialization_ptr,
|
||||||
templ->getTemplateName().getAsTemplateDecl(), *templ, &c);
|
templ->getTemplateName().getAsTemplateDecl(), *templ, &c);
|
||||||
|
|
||||||
if (diagram().should_include(
|
if (diagram().should_include(
|
||||||
@@ -1711,40 +1738,6 @@ void translation_unit_visitor::process_function_parameter(
|
|||||||
method.add_parameter(std::move(parameter));
|
method.add_parameter(std::move(parameter));
|
||||||
}
|
}
|
||||||
|
|
||||||
void translation_unit_visitor::ensure_lambda_type_is_relative(
|
|
||||||
std::string ¶meter_type) const
|
|
||||||
{
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
auto root_name =
|
|
||||||
fmt::format("{}", std::filesystem::current_path().root_name().string());
|
|
||||||
#else
|
|
||||||
auto root_name = std::string{"/"};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::string lambda_prefix{fmt::format("(lambda at {}", root_name)};
|
|
||||||
|
|
||||||
while (parameter_type.find(lambda_prefix) != std::string::npos) {
|
|
||||||
auto lambda_begin = parameter_type.find(lambda_prefix);
|
|
||||||
auto lambda_prefix_size = lambda_prefix.size();
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
// Skip the `\` or `/` after drive letter and semicolon
|
|
||||||
lambda_prefix_size++;
|
|
||||||
#endif
|
|
||||||
auto absolute_lambda_path_end =
|
|
||||||
parameter_type.find(':', lambda_begin + lambda_prefix_size);
|
|
||||||
auto absolute_lambda_path = parameter_type.substr(
|
|
||||||
lambda_begin + lambda_prefix_size - 1,
|
|
||||||
absolute_lambda_path_end - (lambda_begin + lambda_prefix_size - 1));
|
|
||||||
|
|
||||||
auto relative_lambda_path = util::path_to_url(
|
|
||||||
config().make_path_relative(absolute_lambda_path).string());
|
|
||||||
|
|
||||||
parameter_type = fmt::format("{}(lambda at {}{}",
|
|
||||||
parameter_type.substr(0, lambda_begin), relative_lambda_path,
|
|
||||||
parameter_type.substr(absolute_lambda_path_end));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void translation_unit_visitor::add_relationships(class_ &c,
|
void translation_unit_visitor::add_relationships(class_ &c,
|
||||||
const class_member &field, const found_relationships_t &relationships,
|
const class_member &field, const found_relationships_t &relationships,
|
||||||
bool break_on_first_aggregation)
|
bool break_on_first_aggregation)
|
||||||
@@ -1816,7 +1809,8 @@ std::unique_ptr<class_>
|
|||||||
translation_unit_visitor::process_template_specialization(
|
translation_unit_visitor::process_template_specialization(
|
||||||
clang::ClassTemplateSpecializationDecl *cls)
|
clang::ClassTemplateSpecializationDecl *cls)
|
||||||
{
|
{
|
||||||
auto c_ptr = tbuilder().build_from_class_template_specialization(*cls);
|
auto c_ptr = std::make_unique<class_>(config().using_namespace());
|
||||||
|
tbuilder().build_from_class_template_specialization(*c_ptr, *cls);
|
||||||
|
|
||||||
auto &template_instantiation = *c_ptr;
|
auto &template_instantiation = *c_ptr;
|
||||||
template_instantiation.is_template(true);
|
template_instantiation.is_template(true);
|
||||||
@@ -1876,7 +1870,7 @@ void translation_unit_visitor::process_field(
|
|||||||
auto field_type_str =
|
auto field_type_str =
|
||||||
common::to_string(field_type, field_declaration.getASTContext(), false);
|
common::to_string(field_type, field_declaration.getASTContext(), false);
|
||||||
|
|
||||||
ensure_lambda_type_is_relative(field_type_str);
|
common::ensure_lambda_type_is_relative(config(), field_type_str);
|
||||||
|
|
||||||
class_member field{
|
class_member field{
|
||||||
common::access_specifier_to_access_t(field_declaration.getAccess()),
|
common::access_specifier_to_access_t(field_declaration.getAccess()),
|
||||||
@@ -1938,7 +1932,9 @@ void translation_unit_visitor::process_field(
|
|||||||
if (template_field_type != nullptr &&
|
if (template_field_type != nullptr &&
|
||||||
!field_type_is_template_template_parameter) {
|
!field_type_is_template_template_parameter) {
|
||||||
// Build the template instantiation for the field type
|
// Build the template instantiation for the field type
|
||||||
auto template_specialization_ptr = tbuilder().build(
|
auto template_specialization_ptr =
|
||||||
|
std::make_unique<class_>(config().using_namespace());
|
||||||
|
tbuilder().build(*template_specialization_ptr,
|
||||||
field_type->getAs<clang::TemplateSpecializationType>()
|
field_type->getAs<clang::TemplateSpecializationType>()
|
||||||
->getTemplateName()
|
->getTemplateName()
|
||||||
.getAsTemplateDecl(),
|
.getAsTemplateDecl(),
|
||||||
@@ -2136,6 +2132,12 @@ bool translation_unit_visitor::has_processed_template_class(
|
|||||||
return util::contains(processed_template_qualified_names_, qualified_name);
|
return util::contains(processed_template_qualified_names_, qualified_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void translation_unit_visitor::add_diagram_element(
|
||||||
|
std::unique_ptr<common::model::template_element> element)
|
||||||
|
{
|
||||||
|
add_class(util::unique_pointer_cast<class_>(std::move(element)));
|
||||||
|
}
|
||||||
|
|
||||||
void translation_unit_visitor::add_class(std::unique_ptr<class_> &&c)
|
void translation_unit_visitor::add_class(std::unique_ptr<class_> &&c)
|
||||||
{
|
{
|
||||||
if ((config().generate_packages() &&
|
if ((config().generate_packages() &&
|
||||||
@@ -2220,4 +2222,67 @@ void translation_unit_visitor::add_concept(std::unique_ptr<concept_> &&c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void translation_unit_visitor::find_instantiation_relationships(
|
||||||
|
common::model::template_element &template_instantiation_base,
|
||||||
|
const std::string &full_name, common::id_t templated_decl_id)
|
||||||
|
{
|
||||||
|
class_diagram::model::class_ &template_instantiation =
|
||||||
|
dynamic_cast<class_diagram::model::class_ &>(
|
||||||
|
template_instantiation_base);
|
||||||
|
|
||||||
|
// First try to find the best match for this template in partially
|
||||||
|
// specialized templates
|
||||||
|
std::string destination{};
|
||||||
|
std::string best_match_full_name{};
|
||||||
|
auto full_template_name = template_instantiation.full_name(false);
|
||||||
|
int best_match{};
|
||||||
|
common::id_t best_match_id{0};
|
||||||
|
|
||||||
|
for (const auto templ : diagram().classes()) {
|
||||||
|
if (templ.get() == template_instantiation)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto c_full_name = templ.get().full_name(false);
|
||||||
|
auto match =
|
||||||
|
template_instantiation.calculate_template_specialization_match(
|
||||||
|
templ.get());
|
||||||
|
|
||||||
|
if (match > best_match) {
|
||||||
|
best_match = match;
|
||||||
|
best_match_full_name = c_full_name;
|
||||||
|
best_match_id = templ.get().id();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto templated_decl_global_id =
|
||||||
|
id_mapper().get_global_id(templated_decl_id).value_or(0);
|
||||||
|
|
||||||
|
if (best_match_id > 0) {
|
||||||
|
destination = best_match_full_name;
|
||||||
|
template_instantiation.add_relationship(
|
||||||
|
{common::model::relationship_t::kInstantiation, best_match_id});
|
||||||
|
template_instantiation.template_specialization_found(true);
|
||||||
|
}
|
||||||
|
// If we can't find optimal match for parent template specialization,
|
||||||
|
// just use whatever clang suggests
|
||||||
|
else if (diagram().has_element(templated_decl_global_id)) {
|
||||||
|
template_instantiation.add_relationship(
|
||||||
|
{common::model::relationship_t::kInstantiation,
|
||||||
|
templated_decl_global_id});
|
||||||
|
template_instantiation.template_specialization_found(true);
|
||||||
|
}
|
||||||
|
else if (diagram().should_include(common::model::namespace_{full_name})) {
|
||||||
|
LOG_DBG("Skipping instantiation relationship from {} to {}",
|
||||||
|
template_instantiation.full_name(false), templated_decl_global_id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG_DBG("== Cannot determine global id for specialization template {} "
|
||||||
|
"- delaying until the translation unit is complete ",
|
||||||
|
templated_decl_global_id);
|
||||||
|
|
||||||
|
template_instantiation.add_relationship(
|
||||||
|
{common::model::relationship_t::kInstantiation, templated_decl_id});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace clanguml::class_diagram::visitor
|
} // namespace clanguml::class_diagram::visitor
|
||||||
|
|||||||
@@ -20,13 +20,11 @@
|
|||||||
#include "class_diagram/model/class.h"
|
#include "class_diagram/model/class.h"
|
||||||
#include "class_diagram/model/concept.h"
|
#include "class_diagram/model/concept.h"
|
||||||
#include "class_diagram/model/diagram.h"
|
#include "class_diagram/model/diagram.h"
|
||||||
#include "class_diagram/visitor/template_builder.h"
|
|
||||||
#include "common/model/enums.h"
|
#include "common/model/enums.h"
|
||||||
#include "common/model/template_trait.h"
|
#include "common/model/template_trait.h"
|
||||||
#include "common/visitor/ast_id_mapper.h"
|
#include "common/visitor/template_builder.h"
|
||||||
#include "common/visitor/translation_unit_visitor.h"
|
#include "common/visitor/translation_unit_visitor.h"
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
#include "template_builder.h"
|
|
||||||
|
|
||||||
#include <clang/AST/RecursiveASTVisitor.h>
|
#include <clang/AST/RecursiveASTVisitor.h>
|
||||||
#include <clang/Basic/SourceManager.h>
|
#include <clang/Basic/SourceManager.h>
|
||||||
@@ -53,6 +51,8 @@ using clanguml::common::model::relationship;
|
|||||||
using clanguml::common::model::relationship_t;
|
using clanguml::common::model::relationship_t;
|
||||||
using clanguml::common::model::template_parameter;
|
using clanguml::common::model::template_parameter;
|
||||||
using clanguml::common::model::template_trait;
|
using clanguml::common::model::template_trait;
|
||||||
|
using clanguml::common::visitor::found_relationships_t;
|
||||||
|
using clanguml::common::visitor::template_builder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Class diagram translation unit visitor
|
* @brief Class diagram translation unit visitor
|
||||||
@@ -136,13 +136,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void finalize();
|
void finalize();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get reference to Clang AST to clang-uml id mapper
|
|
||||||
*
|
|
||||||
* @return Reference to Clang AST to clang-uml id mapper
|
|
||||||
*/
|
|
||||||
common::visitor::ast_id_mapper &id_mapper() const { return id_mapper_; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Add class (or template class) to the diagram.
|
* @brief Add class (or template class) to the diagram.
|
||||||
*
|
*
|
||||||
@@ -164,8 +157,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void add_concept(std::unique_ptr<concept_> &&c);
|
void add_concept(std::unique_ptr<concept_> &&c);
|
||||||
|
|
||||||
void ensure_lambda_type_is_relative(std::string ¶meter_type) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* @brief Check if the diagram should include a declaration.
|
* @brief Check if the diagram should include a declaration.
|
||||||
@@ -460,6 +451,13 @@ private:
|
|||||||
*/
|
*/
|
||||||
bool has_processed_template_class(const std::string &qualified_name) const;
|
bool has_processed_template_class(const std::string &qualified_name) const;
|
||||||
|
|
||||||
|
void add_diagram_element(
|
||||||
|
std::unique_ptr<common::model::template_element> element) override;
|
||||||
|
|
||||||
|
void find_instantiation_relationships(
|
||||||
|
common::model::template_element &template_instantiation_base,
|
||||||
|
const std::string &full_name, common::id_t templated_decl_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get template builder reference
|
* @brief Get template builder reference
|
||||||
*
|
*
|
||||||
@@ -473,8 +471,6 @@ private:
|
|||||||
// Reference to class diagram config
|
// Reference to class diagram config
|
||||||
const clanguml::config::class_diagram &config_;
|
const clanguml::config::class_diagram &config_;
|
||||||
|
|
||||||
mutable common::visitor::ast_id_mapper id_mapper_;
|
|
||||||
|
|
||||||
template_builder template_builder_;
|
template_builder template_builder_;
|
||||||
|
|
||||||
std::map<common::id_t,
|
std::map<common::id_t,
|
||||||
|
|||||||
@@ -334,6 +334,40 @@ extract_template_parameter_index(const std::string &type_parameter)
|
|||||||
return {std::stoi(toks.at(0)), std::stoi(toks.at(1)), std::move(qualifier)};
|
return {std::stoi(toks.at(0)), std::stoi(toks.at(1)), std::move(qualifier)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ensure_lambda_type_is_relative(
|
||||||
|
const config::diagram &config, std::string ¶meter_type)
|
||||||
|
{
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
auto root_name =
|
||||||
|
fmt::format("{}", std::filesystem::current_path().root_name().string());
|
||||||
|
#else
|
||||||
|
auto root_name = std::string{"/"};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string lambda_prefix{fmt::format("(lambda at {}", root_name)};
|
||||||
|
|
||||||
|
while (parameter_type.find(lambda_prefix) != std::string::npos) {
|
||||||
|
auto lambda_begin = parameter_type.find(lambda_prefix);
|
||||||
|
auto lambda_prefix_size = lambda_prefix.size();
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
// Skip the `\` or `/` after drive letter and semicolon
|
||||||
|
lambda_prefix_size++;
|
||||||
|
#endif
|
||||||
|
auto absolute_lambda_path_end =
|
||||||
|
parameter_type.find(':', lambda_begin + lambda_prefix_size);
|
||||||
|
auto absolute_lambda_path = parameter_type.substr(
|
||||||
|
lambda_begin + lambda_prefix_size - 1,
|
||||||
|
absolute_lambda_path_end - (lambda_begin + lambda_prefix_size - 1));
|
||||||
|
|
||||||
|
auto relative_lambda_path = util::path_to_url(
|
||||||
|
config.make_path_relative(absolute_lambda_path).string());
|
||||||
|
|
||||||
|
parameter_type = fmt::format("{}(lambda at {}{}",
|
||||||
|
parameter_type.substr(0, lambda_begin), relative_lambda_path,
|
||||||
|
parameter_type.substr(absolute_lambda_path_end));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool is_subexpr_of(const clang::Stmt *parent_stmt, const clang::Stmt *sub_stmt)
|
bool is_subexpr_of(const clang::Stmt *parent_stmt, const clang::Stmt *sub_stmt)
|
||||||
{
|
{
|
||||||
if (parent_stmt == nullptr || sub_stmt == nullptr)
|
if (parent_stmt == nullptr || sub_stmt == nullptr)
|
||||||
@@ -893,4 +927,23 @@ bool is_coroutine(const clang::FunctionDecl &decl)
|
|||||||
return clang::isa_and_nonnull<clang::CoroutineBodyStmt>(body);
|
return clang::isa_and_nonnull<clang::CoroutineBodyStmt>(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_struct(const clang::NamedDecl *decl)
|
||||||
|
{
|
||||||
|
if (decl == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (const clang::CXXRecordDecl *record =
|
||||||
|
clang::dyn_cast<clang::CXXRecordDecl>(decl);
|
||||||
|
record) {
|
||||||
|
return record->isStruct();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const clang::TagDecl *tag = clang::dyn_cast<clang::TagDecl>(decl);
|
||||||
|
tag) {
|
||||||
|
return tag->isStruct();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace clanguml::common
|
} // namespace clanguml::common
|
||||||
|
|||||||
@@ -17,9 +17,11 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
// #include "class_diagram/model/diagram.h"
|
||||||
#include "common/model/enums.h"
|
#include "common/model/enums.h"
|
||||||
#include "common/model/namespace.h"
|
#include "common/model/namespace.h"
|
||||||
#include "common/model/template_parameter.h"
|
#include "common/model/template_parameter.h"
|
||||||
|
#include "config/config.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
|
|
||||||
@@ -153,6 +155,9 @@ std::string get_source_text(
|
|||||||
std::tuple<unsigned int, unsigned int, std::string>
|
std::tuple<unsigned int, unsigned int, std::string>
|
||||||
extract_template_parameter_index(const std::string &type_parameter);
|
extract_template_parameter_index(const std::string &type_parameter);
|
||||||
|
|
||||||
|
void ensure_lambda_type_is_relative(
|
||||||
|
const config::diagram &config, std::string ¶meter_type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check if an expression is contained in another expression
|
* @brief Check if an expression is contained in another expression
|
||||||
*
|
*
|
||||||
@@ -303,4 +308,12 @@ clang::RawComment *get_expression_raw_comment(const clang::SourceManager &sm,
|
|||||||
*/
|
*/
|
||||||
bool is_coroutine(const clang::FunctionDecl &decl);
|
bool is_coroutine(const clang::FunctionDecl &decl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if named declaration is a C++ struct.
|
||||||
|
*
|
||||||
|
* @param decl Declaration to check
|
||||||
|
* @return True, if declaration represents a struct.
|
||||||
|
*/
|
||||||
|
bool is_struct(const clang::NamedDecl *decl);
|
||||||
|
|
||||||
} // namespace clanguml::common
|
} // namespace clanguml::common
|
||||||
|
|||||||
52
src/common/model/template_element.cc
Normal file
52
src/common/model/template_element.cc
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* @file src/common/model/template_element.cc
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2024 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 "template_element.h"
|
||||||
|
|
||||||
|
namespace clanguml::common::model {
|
||||||
|
|
||||||
|
bool template_element::is_template() const { return is_template_; }
|
||||||
|
|
||||||
|
void template_element::is_template(bool is_template)
|
||||||
|
{
|
||||||
|
is_template_ = is_template;
|
||||||
|
}
|
||||||
|
|
||||||
|
int template_element::calculate_template_specialization_match(
|
||||||
|
const template_element &other) const
|
||||||
|
{
|
||||||
|
int res{0};
|
||||||
|
|
||||||
|
if (name_and_ns() != other.name_and_ns()) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return template_trait::calculate_template_specialization_match(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
void template_element::template_specialization_found(bool found)
|
||||||
|
{
|
||||||
|
template_specialization_found_ = found;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool template_element::template_specialization_found() const
|
||||||
|
{
|
||||||
|
return template_specialization_found_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace clanguml::common::model
|
||||||
79
src/common/model/template_element.h
Normal file
79
src/common/model/template_element.h
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* @file src/common/model/template_element.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2024 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.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "element.h"
|
||||||
|
#include "template_trait.h"
|
||||||
|
|
||||||
|
namespace clanguml::common::model {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Base class for any element qualified by namespace.
|
||||||
|
*/
|
||||||
|
class template_element : public element, public template_trait {
|
||||||
|
public:
|
||||||
|
using element::element;
|
||||||
|
|
||||||
|
virtual ~template_element() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the class is a template.
|
||||||
|
*
|
||||||
|
* @return True, if the class is a template.
|
||||||
|
*/
|
||||||
|
bool is_template() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set, whether the class is a template.
|
||||||
|
*
|
||||||
|
* @param is_struct True, if the class is a template.
|
||||||
|
*/
|
||||||
|
void is_template(bool is_template);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculate template specialization match with other class.
|
||||||
|
*
|
||||||
|
* This method is a wrapper over
|
||||||
|
* @ref template_trait::calculate_template_specialization_match()
|
||||||
|
*
|
||||||
|
* @param other
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
int calculate_template_specialization_match(
|
||||||
|
const template_element &other) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether, a template specialization has already been found for this class.
|
||||||
|
* @return True, if a template specialization has already been found.
|
||||||
|
*/
|
||||||
|
bool template_specialization_found() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set, whether a template specialization has already been found for this
|
||||||
|
* class.
|
||||||
|
*
|
||||||
|
* @param found True, if a template specialization has already been found.
|
||||||
|
*/
|
||||||
|
void template_specialization_found(bool found);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool template_specialization_found_{false};
|
||||||
|
bool is_template_{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -21,24 +21,29 @@
|
|||||||
#include "translation_unit_visitor.h"
|
#include "translation_unit_visitor.h"
|
||||||
#include <clang/Lex/Lexer.h>
|
#include <clang/Lex/Lexer.h>
|
||||||
|
|
||||||
namespace clanguml::class_diagram::visitor {
|
namespace clanguml::common::visitor {
|
||||||
|
|
||||||
template_builder::template_builder(
|
template_builder::template_builder(clanguml::common::model::diagram &diagram_,
|
||||||
clanguml::class_diagram::visitor::translation_unit_visitor &visitor)
|
const clanguml::config::diagram &config_,
|
||||||
: diagram_{visitor.diagram()}
|
clanguml::common::visitor::translation_unit_visitor &visitor,
|
||||||
, config_{visitor.config()}
|
element_factory_t element_factory,
|
||||||
|
find_instantiation_relationships_t find_instantiation_relationships,
|
||||||
|
on_argument_base_found_t on_argument_base_found)
|
||||||
|
: diagram_{diagram_}
|
||||||
|
, config_{config_}
|
||||||
, id_mapper_{visitor.id_mapper()}
|
, id_mapper_{visitor.id_mapper()}
|
||||||
, source_manager_{visitor.source_manager()}
|
, source_manager_{visitor.source_manager()}
|
||||||
, visitor_{visitor}
|
, visitor_{visitor}
|
||||||
|
, element_factory_{std::move(element_factory)}
|
||||||
|
, find_instantiation_relationships_{std::move(
|
||||||
|
find_instantiation_relationships)}
|
||||||
|
, on_argument_base_found_{std::move(on_argument_base_found)}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
class_diagram::model::diagram &template_builder::diagram() { return diagram_; }
|
common::model::diagram &template_builder::diagram() { return diagram_; }
|
||||||
|
|
||||||
const config::class_diagram &template_builder::config() const
|
const config::diagram &template_builder::config() const { return config_; }
|
||||||
{
|
|
||||||
return config_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const namespace_ &template_builder::using_namespace() const
|
const namespace_ &template_builder::using_namespace() const
|
||||||
{
|
{
|
||||||
@@ -70,9 +75,11 @@ bool template_builder::simplify_system_template(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<class_> template_builder::build(const clang::NamedDecl *cls,
|
void template_builder::build(
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
|
const clang::NamedDecl *cls,
|
||||||
const clang::TemplateSpecializationType &template_type_decl,
|
const clang::TemplateSpecializationType &template_type_decl,
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> parent)
|
std::optional<clanguml::common::model::template_element *> parent)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// Here we'll hold the template base class params to replace with the
|
// Here we'll hold the template base class params to replace with the
|
||||||
@@ -94,13 +101,6 @@ std::unique_ptr<class_> template_builder::build(const clang::NamedDecl *cls,
|
|||||||
|
|
||||||
const auto &template_type = *template_type_ptr;
|
const auto &template_type = *template_type_ptr;
|
||||||
|
|
||||||
//
|
|
||||||
// Create class_ instance to hold the template instantiation
|
|
||||||
//
|
|
||||||
auto template_instantiation_ptr =
|
|
||||||
std::make_unique<class_>(using_namespace());
|
|
||||||
|
|
||||||
auto &template_instantiation = *template_instantiation_ptr;
|
|
||||||
template_instantiation.is_template(true);
|
template_instantiation.is_template(true);
|
||||||
|
|
||||||
std::string full_template_specialization_name = common::to_string(
|
std::string full_template_specialization_name = common::to_string(
|
||||||
@@ -210,78 +210,21 @@ std::unique_ptr<class_> template_builder::build(const clang::NamedDecl *cls,
|
|||||||
template_type.template_arguments(), template_instantiation,
|
template_type.template_arguments(), template_instantiation,
|
||||||
template_decl);
|
template_decl);
|
||||||
|
|
||||||
// First try to find the best match for this template in partially
|
find_instantiation_relationships(template_instantiation,
|
||||||
// specialized templates
|
template_type.getTemplateName().getAsTemplateDecl()->getID(),
|
||||||
std::string destination{};
|
full_template_specialization_name);
|
||||||
std::string best_match_full_name{};
|
|
||||||
auto full_template_name = template_instantiation.full_name(false);
|
|
||||||
int best_match{};
|
|
||||||
common::id_t best_match_id{0};
|
|
||||||
|
|
||||||
for (const auto templ : diagram().classes()) {
|
|
||||||
if (templ.get() == template_instantiation)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto c_full_name = templ.get().full_name(false);
|
|
||||||
auto match =
|
|
||||||
template_instantiation.calculate_template_specialization_match(
|
|
||||||
templ.get());
|
|
||||||
|
|
||||||
if (match > best_match) {
|
|
||||||
best_match = match;
|
|
||||||
best_match_full_name = c_full_name;
|
|
||||||
best_match_id = templ.get().id();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto templated_decl_id =
|
|
||||||
template_type.getTemplateName().getAsTemplateDecl()->getID();
|
|
||||||
auto templated_decl_global_id =
|
|
||||||
id_mapper().get_global_id(templated_decl_id).value_or(0);
|
|
||||||
|
|
||||||
if (best_match_id > 0) {
|
|
||||||
destination = best_match_full_name;
|
|
||||||
template_instantiation.add_relationship(
|
|
||||||
{relationship_t::kInstantiation, best_match_id});
|
|
||||||
template_instantiation.template_specialization_found(true);
|
|
||||||
}
|
|
||||||
// If we can't find optimal match for parent template specialization,
|
|
||||||
// just use whatever clang suggests
|
|
||||||
else if (diagram().has_element(templated_decl_global_id)) {
|
|
||||||
template_instantiation.add_relationship(
|
|
||||||
{relationship_t::kInstantiation, templated_decl_global_id});
|
|
||||||
template_instantiation.template_specialization_found(true);
|
|
||||||
}
|
|
||||||
else if (diagram().should_include(
|
|
||||||
namespace_{full_template_specialization_name})) {
|
|
||||||
LOG_DBG("Skipping instantiation relationship from {} to {}",
|
|
||||||
template_instantiation_ptr->full_name(false), templated_decl_id);
|
|
||||||
}
|
|
||||||
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(
|
template_instantiation.set_id(
|
||||||
common::to_id(template_instantiation_ptr->full_name(false)));
|
common::to_id(template_instantiation.full_name(false)));
|
||||||
|
|
||||||
visitor_.set_source_location(*cls, template_instantiation);
|
visitor_.set_source_location(*cls, template_instantiation);
|
||||||
|
|
||||||
return template_instantiation_ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<class_>
|
void template_builder::build_from_class_template_specialization(
|
||||||
template_builder::build_from_class_template_specialization(
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
const clang::ClassTemplateSpecializationDecl &template_specialization,
|
const clang::ClassTemplateSpecializationDecl &template_specialization,
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> parent)
|
std::optional<clanguml::common::model::template_element *> parent)
|
||||||
{
|
{
|
||||||
auto template_instantiation_ptr =
|
|
||||||
std::make_unique<class_>(config_.using_namespace());
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Here we'll hold the template base params to replace with the
|
// Here we'll hold the template base params to replace with the
|
||||||
// instantiated values
|
// instantiated values
|
||||||
@@ -290,9 +233,6 @@ template_builder::build_from_class_template_specialization(
|
|||||||
/*is variadic */ bool>>
|
/*is variadic */ bool>>
|
||||||
template_base_params{};
|
template_base_params{};
|
||||||
|
|
||||||
auto &template_instantiation = *template_instantiation_ptr;
|
|
||||||
template_instantiation.is_struct(template_specialization.isStruct());
|
|
||||||
|
|
||||||
const clang::ClassTemplateDecl *template_decl =
|
const clang::ClassTemplateDecl *template_decl =
|
||||||
template_specialization.getSpecializedTemplate();
|
template_specialization.getSpecializedTemplate();
|
||||||
|
|
||||||
@@ -312,63 +252,29 @@ template_builder::build_from_class_template_specialization(
|
|||||||
template_instantiation.set_id(
|
template_instantiation.set_id(
|
||||||
common::to_id(template_instantiation.full_name(false)));
|
common::to_id(template_instantiation.full_name(false)));
|
||||||
|
|
||||||
// First try to find the best match for this template in partially
|
find_instantiation_relationships(template_instantiation,
|
||||||
// specialized templates
|
template_specialization.getID(), qualified_name);
|
||||||
std::string destination{};
|
|
||||||
std::string best_match_full_name{};
|
|
||||||
auto full_template_name = template_instantiation.full_name(false);
|
|
||||||
int best_match{};
|
|
||||||
common::id_t best_match_id{0};
|
|
||||||
|
|
||||||
for (const auto templ : diagram().classes()) {
|
|
||||||
if (templ.get() == template_instantiation)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto c_full_name = templ.get().full_name(false);
|
|
||||||
auto match =
|
|
||||||
template_instantiation.calculate_template_specialization_match(
|
|
||||||
templ.get());
|
|
||||||
|
|
||||||
if (match > best_match) {
|
|
||||||
best_match = match;
|
|
||||||
best_match_full_name = c_full_name;
|
|
||||||
best_match_id = templ.get().id();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto templated_decl_id = template_specialization.getID();
|
|
||||||
auto templated_decl_local_id =
|
|
||||||
id_mapper().get_global_id(templated_decl_id).value_or(0);
|
|
||||||
|
|
||||||
if (best_match_id > 0) {
|
|
||||||
destination = best_match_full_name;
|
|
||||||
template_instantiation.add_relationship(
|
|
||||||
{relationship_t::kInstantiation, best_match_id});
|
|
||||||
template_instantiation.template_specialization_found(true);
|
|
||||||
}
|
|
||||||
else if (diagram().has_element(templated_decl_local_id)) {
|
|
||||||
// If we can't find optimal match for parent template specialization,
|
|
||||||
// just use whatever clang suggests
|
|
||||||
template_instantiation.add_relationship(
|
|
||||||
{relationship_t::kInstantiation, templated_decl_local_id});
|
|
||||||
template_instantiation.template_specialization_found(true);
|
|
||||||
}
|
|
||||||
else if (diagram().should_include(namespace_{qualified_name})) {
|
|
||||||
LOG_DBG("Skipping instantiation relationship from {} to {}",
|
|
||||||
template_instantiation_ptr->full_name(false), templated_decl_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
visitor_.set_source_location(*template_decl, template_instantiation);
|
visitor_.set_source_location(*template_decl, template_instantiation);
|
||||||
|
}
|
||||||
|
|
||||||
return template_instantiation_ptr;
|
void template_builder::find_instantiation_relationships(
|
||||||
|
common::model::template_element &template_instantiation, common::id_t id,
|
||||||
|
const std::string &qualified_name) const
|
||||||
|
{
|
||||||
|
if (find_instantiation_relationships_) {
|
||||||
|
find_instantiation_relationships_(
|
||||||
|
template_instantiation, qualified_name, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void template_builder::process_template_arguments(
|
void template_builder::process_template_arguments(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls,
|
const clang::NamedDecl *cls,
|
||||||
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
|
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
|
||||||
const clang::ArrayRef<clang::TemplateArgument> &template_args,
|
const clang::ArrayRef<clang::TemplateArgument> &template_args,
|
||||||
class_ &template_instantiation, const clang::TemplateDecl *template_decl)
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
|
const clang::TemplateDecl *template_decl)
|
||||||
{
|
{
|
||||||
auto arg_index{0};
|
auto arg_index{0};
|
||||||
|
|
||||||
@@ -445,8 +351,9 @@ void template_builder::process_template_arguments(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void template_builder::argument_process_dispatch(
|
void template_builder::argument_process_dispatch(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls, class_ &template_instantiation,
|
const clang::NamedDecl *cls,
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
const clang::TemplateDecl *template_decl,
|
const clang::TemplateDecl *template_decl,
|
||||||
const clang::TemplateArgument &arg, size_t argument_index,
|
const clang::TemplateArgument &arg, size_t argument_index,
|
||||||
std::vector<template_parameter> &argument)
|
std::vector<template_parameter> &argument)
|
||||||
@@ -529,9 +436,11 @@ clang::QualType template_builder::consume_context(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template_parameter template_builder::process_type_argument(
|
template_parameter template_builder::process_type_argument(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
||||||
clang::QualType type, class_ &template_instantiation, size_t argument_index)
|
clang::QualType type,
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
|
size_t argument_index)
|
||||||
{
|
{
|
||||||
std::optional<template_parameter> argument;
|
std::optional<template_parameter> argument;
|
||||||
|
|
||||||
@@ -739,8 +648,9 @@ template_parameter template_builder::process_expression_argument(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<template_parameter> template_builder::process_pack_argument(
|
std::vector<template_parameter> template_builder::process_pack_argument(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls, class_ &template_instantiation,
|
const clang::NamedDecl *cls,
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
const clang::TemplateDecl *base_template_decl,
|
const clang::TemplateDecl *base_template_decl,
|
||||||
const clang::TemplateArgument &arg, size_t argument_index,
|
const clang::TemplateArgument &arg, size_t argument_index,
|
||||||
std::vector<template_parameter> & /*argument*/)
|
std::vector<template_parameter> & /*argument*/)
|
||||||
@@ -760,9 +670,10 @@ std::vector<template_parameter> template_builder::process_pack_argument(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<template_parameter> template_builder::try_as_member_pointer(
|
std::optional<template_parameter> template_builder::try_as_member_pointer(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
||||||
clang::QualType &type, class_ &template_instantiation,
|
clang::QualType &type,
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
size_t argument_index)
|
size_t argument_index)
|
||||||
{
|
{
|
||||||
const auto *mp_type =
|
const auto *mp_type =
|
||||||
@@ -835,9 +746,10 @@ std::optional<template_parameter> template_builder::try_as_member_pointer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<template_parameter> template_builder::try_as_array(
|
std::optional<template_parameter> template_builder::try_as_array(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
||||||
clang::QualType &type, class_ &template_instantiation,
|
clang::QualType &type,
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
size_t argument_index)
|
size_t argument_index)
|
||||||
{
|
{
|
||||||
const auto *array_type = common::dereference(type)->getAsArrayTypeUnsafe();
|
const auto *array_type = common::dereference(type)->getAsArrayTypeUnsafe();
|
||||||
@@ -877,9 +789,10 @@ std::optional<template_parameter> template_builder::try_as_array(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<template_parameter> template_builder::try_as_function_prototype(
|
std::optional<template_parameter> template_builder::try_as_function_prototype(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
||||||
clang::QualType &type, class_ &template_instantiation,
|
clang::QualType &type,
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
size_t argument_index)
|
size_t argument_index)
|
||||||
{
|
{
|
||||||
const auto *function_type = type->getAs<clang::FunctionProtoType>();
|
const auto *function_type = type->getAs<clang::FunctionProtoType>();
|
||||||
@@ -926,10 +839,11 @@ std::optional<template_parameter> template_builder::try_as_function_prototype(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<template_parameter> template_builder::try_as_decl_type(
|
std::optional<template_parameter> template_builder::try_as_decl_type(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> & /*parent*/,
|
std::optional<clanguml::common::model::template_element *> & /*parent*/,
|
||||||
const clang::NamedDecl * /*cls*/,
|
const clang::NamedDecl * /*cls*/,
|
||||||
const clang::TemplateDecl * /*template_decl*/, clang::QualType &type,
|
const clang::TemplateDecl * /*template_decl*/, clang::QualType &type,
|
||||||
class_ & /*template_instantiation*/, size_t /*argument_index*/)
|
clanguml::common::model::template_element & /*template_instantiation*/,
|
||||||
|
size_t /*argument_index*/)
|
||||||
{
|
{
|
||||||
const auto *decl_type =
|
const auto *decl_type =
|
||||||
common::dereference(type)->getAs<clang::DecltypeType>();
|
common::dereference(type)->getAs<clang::DecltypeType>();
|
||||||
@@ -944,10 +858,11 @@ std::optional<template_parameter> template_builder::try_as_decl_type(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<template_parameter> template_builder::try_as_typedef_type(
|
std::optional<template_parameter> template_builder::try_as_typedef_type(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl * /*cls*/,
|
const clang::NamedDecl * /*cls*/,
|
||||||
const clang::TemplateDecl * /*template_decl*/, clang::QualType &type,
|
const clang::TemplateDecl * /*template_decl*/, clang::QualType &type,
|
||||||
class_ & /*template_instantiation*/, size_t /*argument_index*/)
|
clanguml::common::model::template_element & /*template_instantiation*/,
|
||||||
|
size_t /*argument_index*/)
|
||||||
{
|
{
|
||||||
const auto *typedef_type =
|
const auto *typedef_type =
|
||||||
common::dereference(type)->getAs<clang::TypedefType>();
|
common::dereference(type)->getAs<clang::TypedefType>();
|
||||||
@@ -978,9 +893,10 @@ std::optional<template_parameter> template_builder::try_as_typedef_type(
|
|||||||
|
|
||||||
std::optional<template_parameter>
|
std::optional<template_parameter>
|
||||||
template_builder::try_as_template_specialization_type(
|
template_builder::try_as_template_specialization_type(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
||||||
clang::QualType &type, class_ &template_instantiation,
|
clang::QualType &type,
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
size_t argument_index)
|
size_t argument_index)
|
||||||
{
|
{
|
||||||
const auto *nested_template_type =
|
const auto *nested_template_type =
|
||||||
@@ -1019,7 +935,11 @@ template_builder::try_as_template_specialization_type(
|
|||||||
|
|
||||||
argument.set_type(nested_type_name);
|
argument.set_type(nested_type_name);
|
||||||
|
|
||||||
auto nested_template_instantiation = build(cls, *nested_template_type,
|
auto nested_template_instantiation =
|
||||||
|
element_factory_(nested_template_type->getTemplateName()
|
||||||
|
.getAsTemplateDecl()
|
||||||
|
->getTemplatedDecl());
|
||||||
|
build(*nested_template_instantiation, cls, *nested_template_type,
|
||||||
diagram().should_include(
|
diagram().should_include(
|
||||||
namespace_{template_decl->getQualifiedNameAsString()})
|
namespace_{template_decl->getQualifiedNameAsString()})
|
||||||
? std::make_optional(&template_instantiation)
|
? std::make_optional(&template_instantiation)
|
||||||
@@ -1064,7 +984,7 @@ template_builder::try_as_template_specialization_type(
|
|||||||
if (diagram().should_include(
|
if (diagram().should_include(
|
||||||
namespace_{nested_template_instantiation_full_name})) {
|
namespace_{nested_template_instantiation_full_name})) {
|
||||||
visitor_.set_source_location(*cls, *nested_template_instantiation);
|
visitor_.set_source_location(*cls, *nested_template_instantiation);
|
||||||
visitor_.add_class(std::move(nested_template_instantiation));
|
visitor_.add_diagram_element(std::move(nested_template_instantiation));
|
||||||
}
|
}
|
||||||
|
|
||||||
return argument;
|
return argument;
|
||||||
@@ -1108,7 +1028,7 @@ std::optional<template_parameter> template_builder::try_as_template_parm_type(
|
|||||||
|
|
||||||
argument.is_variadic(is_variadic);
|
argument.is_variadic(is_variadic);
|
||||||
|
|
||||||
visitor_.ensure_lambda_type_is_relative(type_parameter_name);
|
common::ensure_lambda_type_is_relative(config(), type_parameter_name);
|
||||||
|
|
||||||
return argument;
|
return argument;
|
||||||
}
|
}
|
||||||
@@ -1127,16 +1047,17 @@ std::optional<template_parameter> template_builder::try_as_lambda(
|
|||||||
auto argument = template_parameter::make_argument("");
|
auto argument = template_parameter::make_argument("");
|
||||||
type = consume_context(type, argument);
|
type = consume_context(type, argument);
|
||||||
|
|
||||||
visitor_.ensure_lambda_type_is_relative(type_name);
|
common::ensure_lambda_type_is_relative(config(), type_name);
|
||||||
argument.set_type(type_name);
|
argument.set_type(type_name);
|
||||||
|
|
||||||
return argument;
|
return argument;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<template_parameter> template_builder::try_as_record_type(
|
std::optional<template_parameter> template_builder::try_as_record_type(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl * /*cls*/, const clang::TemplateDecl *template_decl,
|
const clang::NamedDecl * /*cls*/, const clang::TemplateDecl *template_decl,
|
||||||
clang::QualType &type, class_ &template_instantiation,
|
clang::QualType &type,
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
size_t /*argument_index*/)
|
size_t /*argument_index*/)
|
||||||
{
|
{
|
||||||
const auto *record_type =
|
const auto *record_type =
|
||||||
@@ -1162,8 +1083,10 @@ std::optional<template_parameter> template_builder::try_as_record_type(
|
|||||||
record_type->getAsRecordDecl());
|
record_type->getAsRecordDecl());
|
||||||
|
|
||||||
if (class_template_specialization != nullptr) {
|
if (class_template_specialization != nullptr) {
|
||||||
auto tag_argument = build_from_class_template_specialization(
|
auto tag_argument = element_factory_(class_template_specialization);
|
||||||
*class_template_specialization);
|
|
||||||
|
build_from_class_template_specialization(
|
||||||
|
*tag_argument, *class_template_specialization);
|
||||||
|
|
||||||
if (tag_argument) {
|
if (tag_argument) {
|
||||||
argument.set_type(tag_argument->name_and_ns());
|
argument.set_type(tag_argument->name_and_ns());
|
||||||
@@ -1179,7 +1102,7 @@ std::optional<template_parameter> template_builder::try_as_record_type(
|
|||||||
parent.value()->add_relationship(
|
parent.value()->add_relationship(
|
||||||
{relationship_t::kDependency, tag_argument->id()});
|
{relationship_t::kDependency, tag_argument->id()});
|
||||||
visitor_.set_source_location(*template_decl, *tag_argument);
|
visitor_.set_source_location(*template_decl, *tag_argument);
|
||||||
visitor_.add_class(std::move(tag_argument));
|
visitor_.add_diagram_element(std::move(tag_argument));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1198,9 +1121,10 @@ std::optional<template_parameter> template_builder::try_as_record_type(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<template_parameter> template_builder::try_as_enum_type(
|
std::optional<template_parameter> template_builder::try_as_enum_type(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> & /*parent*/,
|
std::optional<clanguml::common::model::template_element *> & /*parent*/,
|
||||||
const clang::NamedDecl * /*cls*/, const clang::TemplateDecl *template_decl,
|
const clang::NamedDecl * /*cls*/, const clang::TemplateDecl *template_decl,
|
||||||
clang::QualType &type, class_ &template_instantiation)
|
clang::QualType &type,
|
||||||
|
clanguml::common::model::template_element &template_instantiation)
|
||||||
{
|
{
|
||||||
const auto *enum_type = type->getAs<clang::EnumType>();
|
const auto *enum_type = type->getAs<clang::EnumType>();
|
||||||
if (enum_type == nullptr)
|
if (enum_type == nullptr)
|
||||||
@@ -1226,7 +1150,7 @@ std::optional<template_parameter> template_builder::try_as_enum_type(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<template_parameter> template_builder::try_as_builtin_type(
|
std::optional<template_parameter> template_builder::try_as_builtin_type(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> & /*parent*/,
|
std::optional<clanguml::common::model::template_element *> & /*parent*/,
|
||||||
clang::QualType &type, const clang::TemplateDecl *template_decl)
|
clang::QualType &type, const clang::TemplateDecl *template_decl)
|
||||||
{
|
{
|
||||||
const auto *builtin_type = type->getAs<clang::BuiltinType>();
|
const auto *builtin_type = type->getAs<clang::BuiltinType>();
|
||||||
@@ -1244,16 +1168,19 @@ std::optional<template_parameter> template_builder::try_as_builtin_type(
|
|||||||
return argument;
|
return argument;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool template_builder::add_base_classes(class_ &tinst,
|
bool template_builder::add_base_classes(
|
||||||
|
clanguml::common::model::template_element &tinst,
|
||||||
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
|
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
|
||||||
int arg_index, bool variadic_params, const template_parameter &ct)
|
int arg_index, bool variadic_params, const template_parameter &ct)
|
||||||
{
|
{
|
||||||
bool add_template_argument_as_base_class = false;
|
bool add_template_argument_as_base_class = false;
|
||||||
|
|
||||||
auto [arg_name, index, is_variadic] = template_base_params.front();
|
if (variadic_params) {
|
||||||
if (variadic_params)
|
|
||||||
add_template_argument_as_base_class = true;
|
add_template_argument_as_base_class = true;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
|
auto [arg_name, index, is_variadic] = template_base_params.front();
|
||||||
|
|
||||||
variadic_params = is_variadic;
|
variadic_params = is_variadic;
|
||||||
if ((arg_index == index) || (is_variadic && arg_index >= index)) {
|
if ((arg_index == index) || (is_variadic && arg_index >= index)) {
|
||||||
add_template_argument_as_base_class = true;
|
add_template_argument_as_base_class = true;
|
||||||
@@ -1268,13 +1195,9 @@ bool template_builder::add_base_classes(class_ &tinst,
|
|||||||
if (add_template_argument_as_base_class && maybe_id) {
|
if (add_template_argument_as_base_class && maybe_id) {
|
||||||
LOG_DBG("Adding template argument as base class '{}'",
|
LOG_DBG("Adding template argument as base class '{}'",
|
||||||
ct.to_string({}, false));
|
ct.to_string({}, false));
|
||||||
|
if (on_argument_base_found_)
|
||||||
model::class_parent cp;
|
on_argument_base_found_(
|
||||||
cp.set_access(common::model::access_t::kPublic);
|
tinst, maybe_id.value(), ct.to_string({}, false));
|
||||||
cp.set_name(ct.to_string({}, false));
|
|
||||||
cp.set_id(maybe_id.value());
|
|
||||||
|
|
||||||
tinst.add_parent(std::move(cp));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return variadic_params;
|
return variadic_params;
|
||||||
@@ -17,15 +17,15 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "class_diagram/model/class.h"
|
#include "common/model/diagram.h"
|
||||||
#include "class_diagram/model/concept.h"
|
#include "common/model/template_element.h"
|
||||||
#include "class_diagram/model/diagram.h"
|
|
||||||
#include "common/visitor/ast_id_mapper.h"
|
#include "common/visitor/ast_id_mapper.h"
|
||||||
|
#include "common/visitor/translation_unit_visitor.h"
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
|
|
||||||
namespace clanguml::class_diagram::visitor {
|
namespace clanguml::common::visitor {
|
||||||
|
|
||||||
using class_diagram::model::class_;
|
// using class_diagram::model::class_;
|
||||||
using common::model::namespace_;
|
using common::model::namespace_;
|
||||||
using common::model::relationship_t;
|
using common::model::relationship_t;
|
||||||
using common::model::template_parameter;
|
using common::model::template_parameter;
|
||||||
@@ -40,27 +40,42 @@ class translation_unit_visitor;
|
|||||||
*/
|
*/
|
||||||
class template_builder {
|
class template_builder {
|
||||||
public:
|
public:
|
||||||
|
using element_factory_t =
|
||||||
|
std::function<std::unique_ptr<common::model::template_element>(
|
||||||
|
const clang::NamedDecl *)>;
|
||||||
|
|
||||||
|
using find_instantiation_relationships_t = std::function<void(
|
||||||
|
common::model::template_element &, const std::string &, common::id_t)>;
|
||||||
|
|
||||||
|
using on_argument_base_found_t =
|
||||||
|
std::function<void(clanguml::common::model::template_element &,
|
||||||
|
clanguml::common::id_t, const std::string &)>;
|
||||||
/**
|
/**
|
||||||
* @brief Constructor.
|
* @brief Constructor.
|
||||||
*
|
*
|
||||||
* @param visitor Reference to class diagram translation_unit_visitor
|
* @param visitor Reference to class diagram translation_unit_visitor
|
||||||
*/
|
*/
|
||||||
template_builder(
|
template_builder(clanguml::common::model::diagram &diagram_,
|
||||||
clanguml::class_diagram::visitor::translation_unit_visitor &visitor);
|
const clanguml::config::diagram &config_,
|
||||||
|
clanguml::common::visitor::translation_unit_visitor &visitor,
|
||||||
|
element_factory_t element_factory,
|
||||||
|
find_instantiation_relationships_t find_instantiation_relationships =
|
||||||
|
{},
|
||||||
|
on_argument_base_found_t on_argument_base_found = {});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get reference to the current diagram model
|
* @brief Get reference to the current diagram model
|
||||||
*
|
*
|
||||||
* @return Reference to the current diagram model
|
* @return Reference to the current diagram model
|
||||||
*/
|
*/
|
||||||
class_diagram::model::diagram &diagram();
|
common::model::diagram &diagram();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get reference to the current diagram configuration
|
* @brief Get reference to the current diagram configuration
|
||||||
*
|
*
|
||||||
* @return Reference to the current diagram configuration
|
* @return Reference to the current diagram configuration
|
||||||
*/
|
*/
|
||||||
const config::class_diagram &config() const;
|
const config::diagram &config() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get diagram relative namespace
|
* @brief Get diagram relative namespace
|
||||||
@@ -94,10 +109,11 @@ public:
|
|||||||
* @param parent Optional class in which this template is contained
|
* @param parent Optional class in which this template is contained
|
||||||
* @return Created template class model
|
* @return Created template class model
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<clanguml::class_diagram::model::class_> build(
|
void build(
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
const clang::NamedDecl *cls,
|
const clang::NamedDecl *cls,
|
||||||
const clang::TemplateSpecializationType &template_type_decl,
|
const clang::TemplateSpecializationType &template_type_decl,
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> parent = {});
|
std::optional<clanguml::common::model::template_element *> parent = {});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Build template class from class template specialization decl
|
* @brief Build template class from class template specialization decl
|
||||||
@@ -106,10 +122,10 @@ public:
|
|||||||
* @param parent Optional class in which this template is contained
|
* @param parent Optional class in which this template is contained
|
||||||
* @return Created template class model
|
* @return Created template class model
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<clanguml::class_diagram::model::class_>
|
void build_from_class_template_specialization(
|
||||||
build_from_class_template_specialization(
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
const clang::ClassTemplateSpecializationDecl &template_specialization,
|
const clang::ClassTemplateSpecializationDecl &template_specialization,
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> parent = {});
|
std::optional<clanguml::common::model::template_element *> parent = {});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Add base classes to the template class, if any.
|
* @brief Add base classes to the template class, if any.
|
||||||
@@ -125,7 +141,7 @@ public:
|
|||||||
* @param ct Template parameter model
|
* @param ct Template parameter model
|
||||||
* @return True, if any base classes were added
|
* @return True, if any base classes were added
|
||||||
*/
|
*/
|
||||||
bool add_base_classes(clanguml::class_diagram::model::class_ &tinst,
|
bool add_base_classes(clanguml::common::model::template_element &tinst,
|
||||||
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
|
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
|
||||||
int arg_index, bool variadic_params,
|
int arg_index, bool variadic_params,
|
||||||
const clanguml::common::model::template_parameter &ct);
|
const clanguml::common::model::template_parameter &ct);
|
||||||
@@ -141,11 +157,11 @@ public:
|
|||||||
* @param template_decl Base template declaration
|
* @param template_decl Base template declaration
|
||||||
*/
|
*/
|
||||||
void process_template_arguments(
|
void process_template_arguments(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls,
|
const clang::NamedDecl *cls,
|
||||||
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
|
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
|
||||||
const clang::ArrayRef<clang::TemplateArgument> &template_args,
|
const clang::ArrayRef<clang::TemplateArgument> &template_args,
|
||||||
model::class_ &template_instantiation,
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
const clang::TemplateDecl *template_decl);
|
const clang::TemplateDecl *template_decl);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -161,8 +177,9 @@ public:
|
|||||||
* variadic parameters)
|
* variadic parameters)
|
||||||
*/
|
*/
|
||||||
void argument_process_dispatch(
|
void argument_process_dispatch(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls, class_ &template_instantiation,
|
const clang::NamedDecl *cls,
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
const clang::TemplateDecl *template_decl,
|
const clang::TemplateDecl *template_decl,
|
||||||
const clang::TemplateArgument &arg, size_t argument_index,
|
const clang::TemplateArgument &arg, size_t argument_index,
|
||||||
std::vector<template_parameter> &argument);
|
std::vector<template_parameter> &argument);
|
||||||
@@ -226,8 +243,9 @@ public:
|
|||||||
* @return Return template argument model
|
* @return Return template argument model
|
||||||
*/
|
*/
|
||||||
std::vector<template_parameter> process_pack_argument(
|
std::vector<template_parameter> process_pack_argument(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls, class_ &template_instantiation,
|
const clang::NamedDecl *cls,
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
const clang::TemplateDecl *base_template_decl,
|
const clang::TemplateDecl *base_template_decl,
|
||||||
const clang::TemplateArgument &arg, size_t argument_index,
|
const clang::TemplateArgument &arg, size_t argument_index,
|
||||||
std::vector<template_parameter> &argument);
|
std::vector<template_parameter> &argument);
|
||||||
@@ -241,10 +259,11 @@ public:
|
|||||||
* @return Return template argument model
|
* @return Return template argument model
|
||||||
*/
|
*/
|
||||||
template_parameter process_type_argument(
|
template_parameter process_type_argument(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls,
|
const clang::NamedDecl *cls,
|
||||||
const clang::TemplateDecl *base_template_decl, clang::QualType type,
|
const clang::TemplateDecl *base_template_decl, clang::QualType type,
|
||||||
model::class_ &template_instantiation, size_t argument_index);
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
|
size_t argument_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Process `clang::TemplateArgument::Template`
|
* @brief Process `clang::TemplateArgument::Template`
|
||||||
@@ -282,9 +301,10 @@ public:
|
|||||||
* @return Function template argument if succeeds, or std::nullopt
|
* @return Function template argument if succeeds, or std::nullopt
|
||||||
*/
|
*/
|
||||||
std::optional<template_parameter> try_as_function_prototype(
|
std::optional<template_parameter> try_as_function_prototype(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
||||||
clang::QualType &type, class_ &template_instantiation,
|
clang::QualType &type,
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
size_t argument_index);
|
size_t argument_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -299,9 +319,10 @@ public:
|
|||||||
* @return Array template argument if succeeds, or std::nullopt
|
* @return Array template argument if succeeds, or std::nullopt
|
||||||
*/
|
*/
|
||||||
std::optional<template_parameter> try_as_array(
|
std::optional<template_parameter> try_as_array(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
||||||
clang::QualType &type, class_ &template_instantiation,
|
clang::QualType &type,
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
size_t argument_index);
|
size_t argument_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -317,9 +338,10 @@ public:
|
|||||||
* or std::nullopt
|
* or std::nullopt
|
||||||
*/
|
*/
|
||||||
std::optional<template_parameter> try_as_template_specialization_type(
|
std::optional<template_parameter> try_as_template_specialization_type(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
||||||
clang::QualType &type, class_ &template_instantiation,
|
clang::QualType &type,
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
size_t argument_index);
|
size_t argument_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -357,9 +379,10 @@ public:
|
|||||||
* @return Record type template argument if succeeds, or std::nullopt
|
* @return Record type template argument if succeeds, or std::nullopt
|
||||||
*/
|
*/
|
||||||
std::optional<template_parameter> try_as_record_type(
|
std::optional<template_parameter> try_as_record_type(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
||||||
clang::QualType &type, class_ &template_instantiation,
|
clang::QualType &type,
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
size_t argument_index);
|
size_t argument_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -373,9 +396,10 @@ public:
|
|||||||
* @return Enum type template argument if succeeds, or std::nullopt
|
* @return Enum type template argument if succeeds, or std::nullopt
|
||||||
*/
|
*/
|
||||||
std::optional<template_parameter> try_as_enum_type(
|
std::optional<template_parameter> try_as_enum_type(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
||||||
clang::QualType &type, class_ &template_instantiation);
|
clang::QualType &type,
|
||||||
|
clanguml::common::model::template_element &template_instantiation);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Try to process template type argument as builtin type
|
* @brief Try to process template type argument as builtin type
|
||||||
@@ -386,7 +410,7 @@ public:
|
|||||||
* @return Builtin type template argument if succeeds, or std::nullopt
|
* @return Builtin type template argument if succeeds, or std::nullopt
|
||||||
*/
|
*/
|
||||||
std::optional<template_parameter> try_as_builtin_type(
|
std::optional<template_parameter> try_as_builtin_type(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
clang::QualType &type, const clang::TemplateDecl *template_decl);
|
clang::QualType &type, const clang::TemplateDecl *template_decl);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -402,9 +426,10 @@ public:
|
|||||||
* or std::nullopt
|
* or std::nullopt
|
||||||
*/
|
*/
|
||||||
std::optional<template_parameter> try_as_member_pointer(
|
std::optional<template_parameter> try_as_member_pointer(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
||||||
clang::QualType &type, class_ &template_instantiation,
|
clang::QualType &type,
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
size_t argument_index);
|
size_t argument_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -419,9 +444,10 @@ public:
|
|||||||
* @return `decltype()` type template argument if succeeds, or std::nullopt
|
* @return `decltype()` type template argument if succeeds, or std::nullopt
|
||||||
*/
|
*/
|
||||||
std::optional<template_parameter> try_as_decl_type(
|
std::optional<template_parameter> try_as_decl_type(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
||||||
clang::QualType &type, class_ &template_instantiation,
|
clang::QualType &type,
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
size_t argument_index);
|
size_t argument_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -436,9 +462,10 @@ public:
|
|||||||
* @return Typedef type template argument if succeeds, or std::nullopt
|
* @return Typedef type template argument if succeeds, or std::nullopt
|
||||||
*/
|
*/
|
||||||
std::optional<template_parameter> try_as_typedef_type(
|
std::optional<template_parameter> try_as_typedef_type(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::common::model::template_element *> &parent,
|
||||||
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
||||||
clang::QualType &type, class_ &template_instantiation,
|
clang::QualType &type,
|
||||||
|
clanguml::common::model::template_element &template_instantiation,
|
||||||
size_t argument_index);
|
size_t argument_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -471,8 +498,11 @@ public:
|
|||||||
* @return True, if any relationships were found
|
* @return True, if any relationships were found
|
||||||
*/
|
*/
|
||||||
bool find_relationships_in_unexposed_template_params(
|
bool find_relationships_in_unexposed_template_params(
|
||||||
const template_parameter &ct,
|
const template_parameter &ct, found_relationships_t &relationships);
|
||||||
class_diagram::visitor::found_relationships_t &relationships);
|
|
||||||
|
void find_instantiation_relationships(
|
||||||
|
common::model::template_element &template_instantiation,
|
||||||
|
common::id_t id, const std::string &qualified_name) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get reference to Clang AST to clang-uml id mapper
|
* @brief Get reference to Clang AST to clang-uml id mapper
|
||||||
@@ -490,16 +520,24 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// Reference to the output diagram model
|
// Reference to the output diagram model
|
||||||
clanguml::class_diagram::model::diagram &diagram_;
|
clanguml::common::model::diagram &diagram_;
|
||||||
|
|
||||||
// Reference to class diagram config
|
// Reference to diagram config
|
||||||
const clanguml::config::class_diagram &config_;
|
const clanguml::config::diagram &config_;
|
||||||
|
|
||||||
common::visitor::ast_id_mapper &id_mapper_;
|
common::visitor::ast_id_mapper &id_mapper_;
|
||||||
|
|
||||||
clang::SourceManager &source_manager_;
|
clang::SourceManager &source_manager_;
|
||||||
|
|
||||||
clanguml::class_diagram::visitor::translation_unit_visitor &visitor_;
|
clanguml::common::visitor::translation_unit_visitor &visitor_;
|
||||||
|
|
||||||
|
element_factory_t element_factory_;
|
||||||
|
|
||||||
|
find_instantiation_relationships_t find_instantiation_relationships_;
|
||||||
|
|
||||||
|
// Callback to call when a template instantiation has arguments which are
|
||||||
|
// base classes, i.e. when template class inherits from template params
|
||||||
|
on_argument_base_found_t on_argument_base_found_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace clanguml::class_diagram::visitor
|
} // namespace clanguml::class_diagram::visitor
|
||||||
@@ -18,8 +18,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "comment/comment_visitor.h"
|
#include "comment/comment_visitor.h"
|
||||||
#include "common/model/element.h"
|
|
||||||
#include "common/model/source_location.h"
|
#include "common/model/source_location.h"
|
||||||
|
#include "common/model/template_element.h"
|
||||||
|
#include "common/visitor/ast_id_mapper.h"
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
|
|
||||||
#include <clang/AST/Comment.h>
|
#include <clang/AST/Comment.h>
|
||||||
@@ -65,6 +66,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
const std::filesystem::path &tu_path() const;
|
const std::filesystem::path &tu_path() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get reference to Clang AST to clang-uml id mapper
|
||||||
|
*
|
||||||
|
* @return Reference to Clang AST to clang-uml id mapper
|
||||||
|
*/
|
||||||
|
common::visitor::ast_id_mapper &id_mapper() const { return id_mapper_; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get clang::SourceManager
|
* @brief Get clang::SourceManager
|
||||||
* @return Reference to @ref clang::SourceManager used by this translation
|
* @return Reference to @ref clang::SourceManager used by this translation
|
||||||
@@ -105,6 +113,11 @@ public:
|
|||||||
void set_owning_module(
|
void set_owning_module(
|
||||||
const clang::Decl &decl, clanguml::common::model::element &element);
|
const clang::Decl &decl, clanguml::common::model::element &element);
|
||||||
|
|
||||||
|
virtual void add_diagram_element(
|
||||||
|
std::unique_ptr<common::model::template_element> element)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief Process comment directives in comment attached to a declaration
|
* @brief Process comment directives in comment attached to a declaration
|
||||||
@@ -136,5 +149,7 @@ private:
|
|||||||
std::filesystem::path translation_unit_path_;
|
std::filesystem::path translation_unit_path_;
|
||||||
|
|
||||||
std::set<const clang::RawComment *> processed_comments_;
|
std::set<const clang::RawComment *> processed_comments_;
|
||||||
|
|
||||||
|
mutable common::visitor::ast_id_mapper id_mapper_;
|
||||||
};
|
};
|
||||||
} // namespace clanguml::common::visitor
|
} // namespace clanguml::common::visitor
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
return common::optional_ref<T>(
|
return common::optional_ref<T>(
|
||||||
static_cast<T *>(participants_.at(id).get()));
|
dynamic_cast<T *>(participants_.at(id).get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/model/element.h"
|
#include "common/model/element.h"
|
||||||
|
#include "common/model/template_element.h"
|
||||||
#include "common/model/template_parameter.h"
|
#include "common/model/template_parameter.h"
|
||||||
#include "common/model/template_trait.h"
|
#include "common/model/template_trait.h"
|
||||||
|
|
||||||
@@ -31,9 +32,9 @@ using clanguml::common::model::template_trait;
|
|||||||
/**
|
/**
|
||||||
* @brief Base class for various types of sequence diagram participants
|
* @brief Base class for various types of sequence diagram participants
|
||||||
*/
|
*/
|
||||||
struct participant : public common::model::element,
|
struct participant : public common::model::template_element,
|
||||||
public common::model::stylable_element {
|
public common::model::stylable_element {
|
||||||
using common::model::element::element;
|
using common::model::template_element::template_element;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enum representing stereotype of a participant
|
* @brief Enum representing stereotype of a participant
|
||||||
@@ -74,7 +75,7 @@ struct participant : public common::model::element,
|
|||||||
/**
|
/**
|
||||||
* @brief Sequence diagram participant representing a class.
|
* @brief Sequence diagram participant representing a class.
|
||||||
*/
|
*/
|
||||||
struct class_ : public participant, public template_trait {
|
struct class_ : public participant {
|
||||||
public:
|
public:
|
||||||
class_(const common::model::namespace_ &using_namespace);
|
class_(const common::model::namespace_ &using_namespace);
|
||||||
|
|
||||||
@@ -477,7 +478,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* @brief Participant model representing a function template.
|
* @brief Participant model representing a function template.
|
||||||
*/
|
*/
|
||||||
struct function_template : public function, public template_trait {
|
struct function_template : public function {
|
||||||
function_template(const common::model::namespace_ &using_namespace);
|
function_template(const common::model::namespace_ &using_namespace);
|
||||||
|
|
||||||
function_template(const function_template &) = delete;
|
function_template(const function_template &) = delete;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "common/clang_utils.h"
|
#include "common/clang_utils.h"
|
||||||
#include "common/model/namespace.h"
|
#include "common/model/namespace.h"
|
||||||
|
#include "sequence_diagram/model/participant.h"
|
||||||
|
|
||||||
namespace clanguml::sequence_diagram::visitor {
|
namespace clanguml::sequence_diagram::visitor {
|
||||||
|
|
||||||
|
|||||||
@@ -160,6 +160,17 @@ std::string get_git_toplevel_dir();
|
|||||||
*/
|
*/
|
||||||
std::string get_os_name();
|
std::string get_os_name();
|
||||||
|
|
||||||
|
template <typename T, typename S>
|
||||||
|
std::unique_ptr<T> unique_pointer_cast(std::unique_ptr<S> &&p) noexcept
|
||||||
|
{
|
||||||
|
if (T *const converted = dynamic_cast<T *>(p.get())) {
|
||||||
|
p.release();
|
||||||
|
return std::unique_ptr<T>{converted};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Split a string using delimiter
|
* @brief Split a string using delimiter
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ namespace clanguml::t00044 {
|
|||||||
|
|
||||||
template <typename T> class sink;
|
template <typename T> class sink;
|
||||||
|
|
||||||
template <typename T, typename A> class signal_handler;
|
template <typename T, typename A> struct signal_handler;
|
||||||
|
|
||||||
template <typename Ret, typename... Args, typename A>
|
template <typename Ret, typename... Args, typename A>
|
||||||
class sink<signal_handler<Ret(Args...), A>> {
|
class sink<signal_handler<Ret(Args...), A>> {
|
||||||
@@ -22,7 +22,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename Ret, typename... Args, typename A>
|
template <typename Ret, typename... Args, typename A>
|
||||||
class signal_handler<Ret(Args...), A> { };
|
struct signal_handler<Ret(Args...), A> { };
|
||||||
|
|
||||||
template <typename Ret, typename... Args, typename A>
|
template <typename Ret, typename... Args, typename A>
|
||||||
sink(signal_handler<Ret(Args...), A> &)
|
sink(signal_handler<Ret(Args...), A> &)
|
||||||
|
|||||||
@@ -74,9 +74,10 @@ TEST_CASE("t00044", "[test-case][class]")
|
|||||||
REQUIRE(IsClassTemplate(j, "sink<T>"));
|
REQUIRE(IsClassTemplate(j, "sink<T>"));
|
||||||
REQUIRE(IsClassTemplate(j, "signal_handler<T,A>"));
|
REQUIRE(IsClassTemplate(j, "signal_handler<T,A>"));
|
||||||
REQUIRE(IsClassTemplate(j, "signal_handler<Ret(Args...),A>"));
|
REQUIRE(IsClassTemplate(j, "signal_handler<Ret(Args...),A>"));
|
||||||
|
REQUIRE(IsStruct(j, "signal_handler<Ret(Args...),A>"));
|
||||||
REQUIRE(IsClassTemplate(j, "signal_handler<void(int),bool>"));
|
REQUIRE(IsClassTemplate(j, "signal_handler<void(int),bool>"));
|
||||||
REQUIRE(IsClassTemplate(j, "sink<signal_handler<Ret(Args...),A>>"));
|
REQUIRE(IsClassTemplate(j, "sink<signal_handler<Ret(Args...),A>>"));
|
||||||
REQUIRE(IsClass(j, "R"));
|
REQUIRE(IsStruct(j, "R"));
|
||||||
|
|
||||||
save_json(config.output_directory(), diagram->name + ".json", j);
|
save_json(config.output_directory(), diagram->name + ".json", j);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1273,6 +1273,12 @@ bool IsClass(const nlohmann::json &j, const std::string &name)
|
|||||||
return e && e->at("type") == "class";
|
return e && e->at("type") == "class";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsStruct(const nlohmann::json &j, const std::string &name)
|
||||||
|
{
|
||||||
|
auto e = get_element(j, expand_name(j, name));
|
||||||
|
return e && e->at("type") == "class" && e->at("is_struct");
|
||||||
|
}
|
||||||
|
|
||||||
bool InPublicModule(const nlohmann::json &j, const std::string &element,
|
bool InPublicModule(const nlohmann::json &j, const std::string &element,
|
||||||
const std::string &module)
|
const std::string &module)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user