Refactored template_builder to common namespace (#227)
This commit is contained in:
@@ -25,7 +25,7 @@
|
||||
namespace clanguml::class_diagram::model {
|
||||
|
||||
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; }
|
||||
|
||||
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_; }
|
||||
|
||||
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(); });
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
const auto *type = is_struct() ? "struct" : "class";
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
#include "class_member.h"
|
||||
#include "class_method.h"
|
||||
#include "class_parent.h"
|
||||
#include "common/model/element.h"
|
||||
#include "common/model/enums.h"
|
||||
#include "common/model/stylable_element.h"
|
||||
#include "common/model/template_element.h"
|
||||
#include "common/model/template_parameter.h"
|
||||
#include "common/model/template_trait.h"
|
||||
#include "common/types.h"
|
||||
@@ -35,9 +35,8 @@ namespace clanguml::class_diagram::model {
|
||||
/**
|
||||
* @brief Diagram element representing a class or class template.
|
||||
*/
|
||||
class class_ : public common::model::element,
|
||||
public common::model::stylable_element,
|
||||
public template_trait {
|
||||
class class_ : public common::model::template_element,
|
||||
public common::model::stylable_element {
|
||||
public:
|
||||
class_(const common::model::namespace_ &using_namespace);
|
||||
|
||||
@@ -69,20 +68,6 @@ public:
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@@ -171,31 +156,6 @@ public:
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@@ -208,15 +168,12 @@ public:
|
||||
|
||||
private:
|
||||
bool is_struct_{false};
|
||||
bool is_template_{false};
|
||||
bool is_union_{false};
|
||||
std::vector<class_member> members_;
|
||||
std::vector<class_method> methods_;
|
||||
std::vector<class_parent> bases_;
|
||||
std::string base_template_full_name_;
|
||||
std::string full_name_;
|
||||
|
||||
bool template_specialization_found_{false};
|
||||
};
|
||||
|
||||
} // namespace clanguml::class_diagram::model
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -32,7 +32,26 @@ translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
|
||||
: common::visitor::translation_unit_visitor{sm, config}
|
||||
, diagram_{diagram}
|
||||
, 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;
|
||||
|
||||
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)
|
||||
return true;
|
||||
@@ -1060,7 +1081,9 @@ void translation_unit_visitor::process_class_bases(
|
||||
else if (const auto *tsp =
|
||||
base.getType()->getAs<clang::TemplateSpecializationType>();
|
||||
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) {
|
||||
cp.set_id(template_specialization_ptr->id());
|
||||
}
|
||||
@@ -1261,7 +1284,7 @@ void translation_unit_visitor::process_method(
|
||||
auto method_return_type =
|
||||
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();
|
||||
if (mf.isTemplated()) {
|
||||
@@ -1304,7 +1327,9 @@ void translation_unit_visitor::process_method(
|
||||
->getAs<clang::TemplateSpecializationType>();
|
||||
|
||||
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, &c);
|
||||
|
||||
@@ -1652,7 +1677,7 @@ void translation_unit_visitor::process_function_parameter(
|
||||
auto parameter_type = common::to_string(p.getType(), p.getASTContext());
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -1678,7 +1703,9 @@ void translation_unit_visitor::process_function_parameter(
|
||||
.getUnqualifiedType()
|
||||
->getAs<clang::TemplateSpecializationType>();
|
||||
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);
|
||||
|
||||
if (diagram().should_include(
|
||||
@@ -1711,40 +1738,6 @@ void translation_unit_visitor::process_function_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,
|
||||
const class_member &field, const found_relationships_t &relationships,
|
||||
bool break_on_first_aggregation)
|
||||
@@ -1816,7 +1809,8 @@ std::unique_ptr<class_>
|
||||
translation_unit_visitor::process_template_specialization(
|
||||
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;
|
||||
template_instantiation.is_template(true);
|
||||
@@ -1876,7 +1870,7 @@ void translation_unit_visitor::process_field(
|
||||
auto field_type_str =
|
||||
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{
|
||||
common::access_specifier_to_access_t(field_declaration.getAccess()),
|
||||
@@ -1938,7 +1932,9 @@ void translation_unit_visitor::process_field(
|
||||
if (template_field_type != nullptr &&
|
||||
!field_type_is_template_template_parameter) {
|
||||
// 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>()
|
||||
->getTemplateName()
|
||||
.getAsTemplateDecl(),
|
||||
@@ -2136,6 +2132,12 @@ bool translation_unit_visitor::has_processed_template_class(
|
||||
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)
|
||||
{
|
||||
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
|
||||
|
||||
@@ -20,13 +20,11 @@
|
||||
#include "class_diagram/model/class.h"
|
||||
#include "class_diagram/model/concept.h"
|
||||
#include "class_diagram/model/diagram.h"
|
||||
#include "class_diagram/visitor/template_builder.h"
|
||||
#include "common/model/enums.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 "config/config.h"
|
||||
#include "template_builder.h"
|
||||
|
||||
#include <clang/AST/RecursiveASTVisitor.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::template_parameter;
|
||||
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
|
||||
@@ -136,13 +136,6 @@ public:
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@@ -164,8 +157,6 @@ public:
|
||||
*/
|
||||
void add_concept(std::unique_ptr<concept_> &&c);
|
||||
|
||||
void ensure_lambda_type_is_relative(std::string ¶meter_type) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @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;
|
||||
|
||||
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
|
||||
*
|
||||
@@ -473,8 +471,6 @@ private:
|
||||
// Reference to class diagram config
|
||||
const clanguml::config::class_diagram &config_;
|
||||
|
||||
mutable common::visitor::ast_id_mapper id_mapper_;
|
||||
|
||||
template_builder template_builder_;
|
||||
|
||||
std::map<common::id_t,
|
||||
|
||||
Reference in New Issue
Block a user