Continued refactor of template building code to template_builder

This commit is contained in:
Bartek Kryza
2024-02-11 19:33:03 +01:00
parent 251857e9c4
commit 7f25fa58f5
16 changed files with 1738 additions and 2369 deletions

View File

@@ -29,32 +29,19 @@ namespace clanguml::class_diagram::visitor {
translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
clanguml::class_diagram::model::diagram &diagram,
const clanguml::config::class_diagram &config)
: common::visitor::translation_unit_visitor{sm, config}
, diagram_{diagram}
, config_{config}
, 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));
}}
: visitor_specialization_t{sm, diagram, config}
, template_builder_{diagram, config, *this}
{
}
std::unique_ptr<class_> translation_unit_visitor::create_element(
const clang::NamedDecl *decl) const
{
auto cls = std::make_unique<class_>(config().using_namespace());
cls->is_struct(common::is_struct(decl));
return cls;
}
bool translation_unit_visitor::VisitNamespaceDecl(clang::NamespaceDecl *ns)
{
assert(ns != nullptr);
@@ -126,7 +113,7 @@ bool translation_unit_visitor::VisitEnumDecl(clang::EnumDecl *enm)
enm->getQualifiedNameAsString(),
enm->getLocation().printToString(source_manager()));
auto e_ptr = std::make_unique<enum_>(config_.using_namespace());
auto e_ptr = std::make_unique<enum_>(config().using_namespace());
auto &e = *e_ptr;
std::string qualified_name = common::get_qualified_name(*enm);
@@ -274,7 +261,7 @@ bool translation_unit_visitor::VisitTypeAliasTemplateDecl(
auto template_specialization_ptr =
std::make_unique<class_>(config().using_namespace());
tbuilder().build(
tbuilder().build_from_template_specialization_type(
*template_specialization_ptr, cls, *template_type_specialization_ptr);
if (diagram().should_include(*template_specialization_ptr)) {
@@ -309,11 +296,10 @@ bool translation_unit_visitor::VisitClassTemplateDecl(
add_processed_template_class(cls->getQualifiedNameAsString());
tbuilder().build_from_template_declaration(*c_ptr, *cls, *c_ptr);
// Override the id with the template id, for now we don't care about the
// underlying templated class id
process_template_parameters(*cls, *c_ptr, *c_ptr);
const auto cls_full_name = c_ptr->full_name(false);
const auto id = common::to_id(cls_full_name);
@@ -420,7 +406,7 @@ bool translation_unit_visitor::TraverseConceptDecl(clang::ConceptDecl *cpt)
id_mapper().add(cpt->getID(), concept_id);
process_template_parameters(*cpt, *concept_model);
tbuilder().build_from_template_declaration(*concept_model, *cpt);
constexpr auto kMaxConstraintCount = 24U;
llvm::SmallVector<const clang::Expr *, kMaxConstraintCount> constraints{};
@@ -774,7 +760,7 @@ translation_unit_visitor::create_concept_declaration(clang::ConceptDecl *cpt)
return {};
auto concept_ptr{
std::make_unique<model::concept_>(config_.using_namespace())};
std::make_unique<model::concept_>(config().using_namespace())};
auto &concept_model = *concept_ptr;
auto ns = common::get_template_namespace(*cpt);
@@ -803,7 +789,7 @@ std::unique_ptr<class_> translation_unit_visitor::create_record_declaration(
if (!should_include(rec))
return {};
auto record_ptr{std::make_unique<class_>(config_.using_namespace())};
auto record_ptr{std::make_unique<class_>(config().using_namespace())};
auto &record = *record_ptr;
process_record_parent(rec, record, namespace_{});
@@ -849,7 +835,7 @@ std::unique_ptr<class_> translation_unit_visitor::create_class_declaration(
if (!should_include(cls))
return {};
auto c_ptr{std::make_unique<class_>(config_.using_namespace())};
auto c_ptr{std::make_unique<class_>(config().using_namespace())};
auto &c = *c_ptr;
auto ns{common::get_tag_namespace(*cls)};
@@ -909,11 +895,11 @@ void translation_unit_visitor::process_record_parent(
}
}
if (id_opt && diagram_.find<class_>(*id_opt)) {
if (id_opt && diagram().find<class_>(*id_opt)) {
// Here we have 2 options, either:
// - the parent is a regular C++ class/struct
// - the parent is a class template declaration/specialization
auto parent_class = diagram_.find<class_>(*id_opt);
auto parent_class = diagram().find<class_>(*id_opt);
c.set_namespace(parent_ns);
const auto cls_name = cls->getNameAsString();
@@ -963,102 +949,6 @@ void translation_unit_visitor::process_class_declaration(
c.complete(true);
}
bool translation_unit_visitor::process_template_parameters(
const clang::TemplateDecl &template_declaration,
common::model::template_trait &c,
common::optional_ref<common::model::element> templated_element)
{
LOG_DBG("Processing {} template parameters...",
common::get_qualified_name(template_declaration));
if (template_declaration.getTemplateParameters() == nullptr)
return false;
for (const auto *parameter :
*template_declaration.getTemplateParameters()) {
if (clang::dyn_cast_or_null<clang::TemplateTypeParmDecl>(parameter) !=
nullptr) {
const auto *template_type_parameter =
clang::dyn_cast_or_null<clang::TemplateTypeParmDecl>(parameter);
std::optional<std::string> default_arg;
if (template_type_parameter->hasDefaultArgument()) {
default_arg =
template_type_parameter->getDefaultArgument().getAsString();
}
auto parameter_name = template_type_parameter->getNameAsString();
if (parameter_name.empty())
parameter_name = "typename";
auto ct = template_parameter::make_template_type(parameter_name,
default_arg, template_type_parameter->isParameterPack());
if (template_type_parameter->getTypeConstraint() != nullptr) {
util::if_not_null(template_type_parameter->getTypeConstraint()
->getNamedConcept(),
[this, &ct, &templated_element](
const clang::ConceptDecl *named_concept) mutable {
ct.set_concept_constraint(
named_concept->getQualifiedNameAsString());
if (templated_element &&
should_include(named_concept)) {
templated_element.value().add_relationship(
{relationship_t::kConstraint,
id_mapper()
.get_global_id(named_concept->getID())
.value(),
access_t::kNone, ct.name().value()});
}
});
}
c.add_template(std::move(ct));
}
else if (clang::dyn_cast_or_null<clang::NonTypeTemplateParmDecl>(
parameter) != nullptr) {
const auto *template_nontype_parameter =
clang::dyn_cast_or_null<clang::NonTypeTemplateParmDecl>(
parameter);
std::optional<std::string> default_arg;
if (template_nontype_parameter->hasDefaultArgument())
default_arg = common::to_string(
template_nontype_parameter->getDefaultArgument());
auto ct = template_parameter::make_non_type_template(
template_nontype_parameter->getType().getAsString(),
template_nontype_parameter->getNameAsString(), default_arg,
template_nontype_parameter->isParameterPack());
c.add_template(std::move(ct));
}
else if (clang::dyn_cast_or_null<clang::TemplateTemplateParmDecl>(
parameter) != nullptr) {
const auto *template_template_parameter =
clang::dyn_cast_or_null<clang::TemplateTemplateParmDecl>(
parameter);
std::optional<std::string> default_arg;
if (template_template_parameter->hasDefaultArgument()) {
default_arg = common::to_string(
template_template_parameter->getDefaultArgument()
.getArgument());
}
auto ct = template_parameter::make_template_template_type(
template_template_parameter->getNameAsString(), default_arg,
template_template_parameter->isParameterPack());
c.add_template(std::move(ct));
}
else {
// pass
}
}
return false;
}
void translation_unit_visitor::process_class_bases(
const clang::CXXRecordDecl *cls, class_ &c)
{
@@ -1074,7 +964,8 @@ void translation_unit_visitor::process_class_bases(
tsp != nullptr) {
auto template_specialization_ptr =
std::make_unique<class_>(config().using_namespace());
tbuilder().build(*template_specialization_ptr, cls, *tsp, {});
tbuilder().build_from_template_specialization_type(
*template_specialization_ptr, cls, *tsp, {});
cp.set_id(template_specialization_ptr->id());
cp.set_name(template_specialization_ptr->full_name(false));
@@ -1330,7 +1221,8 @@ void translation_unit_visitor::process_method(
if (unaliased_type != nullptr) {
auto template_specialization_ptr =
std::make_unique<class_>(config().using_namespace());
tbuilder().build(*template_specialization_ptr,
tbuilder().build_from_template_specialization_type(
*template_specialization_ptr,
unaliased_type->getTemplateName().getAsTemplateDecl(),
*unaliased_type, &c);
@@ -1476,14 +1368,13 @@ void translation_unit_visitor::process_template_method(
// Is there a better way to do this?
method_name = method_name.substr(0, method_name.find('<'));
}
util::if_not_null(
clang::dyn_cast<clang::CXXMethodDecl>(mf.getTemplatedDecl()),
[&](const auto *decl) {
process_method_properties(*decl, c, method_name, method);
});
process_template_parameters(mf, method);
tbuilder().build_from_template_declaration(method, mf);
process_comment(mf, method);
@@ -1705,7 +1596,8 @@ void translation_unit_visitor::process_function_parameter(
templ != nullptr) {
auto template_specialization_ptr =
std::make_unique<class_>(config().using_namespace());
tbuilder().build(*template_specialization_ptr,
tbuilder().build_from_template_specialization_type(
*template_specialization_ptr,
templ->getTemplateName().getAsTemplateDecl(), *templ, &c);
if (diagram().should_include(*template_specialization_ptr)) {
@@ -1933,7 +1825,8 @@ void translation_unit_visitor::process_field(
// Build the template instantiation for the field type
auto template_specialization_ptr =
std::make_unique<class_>(config().using_namespace());
tbuilder().build(*template_specialization_ptr,
tbuilder().build_from_template_specialization_type(
*template_specialization_ptr,
field_type->getAs<clang::TemplateSpecializationType>()
->getTemplateName()
.getAsTemplateDecl(),
@@ -2100,25 +1993,6 @@ void translation_unit_visitor::extract_constrained_template_param_name(
}
}
bool translation_unit_visitor::should_include(const clang::NamedDecl *decl)
{
if (decl == nullptr)
return false;
if (source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
return false;
auto should_include_namespace =
diagram().should_include(namespace_{decl->getQualifiedNameAsString()});
const auto decl_file = decl->getLocation().printToString(source_manager());
const auto should_include_decl_file =
diagram().should_include(common::model::source_file{decl_file});
return should_include_namespace && should_include_decl_file;
}
void translation_unit_visitor::add_processed_template_class(
std::string qualified_name)
{

View File

@@ -54,6 +54,10 @@ using clanguml::common::model::template_trait;
using clanguml::common::visitor::found_relationships_t;
using clanguml::common::visitor::template_builder;
using visitor_specialization_t =
common::visitor::translation_unit_visitor<clanguml::config::class_diagram,
clanguml::class_diagram::model::diagram>;
/**
* @brief Class diagram translation unit visitor
*
@@ -62,8 +66,13 @@ using clanguml::common::visitor::template_builder;
*/
class translation_unit_visitor
: public clang::RecursiveASTVisitor<translation_unit_visitor>,
public common::visitor::translation_unit_visitor {
public visitor_specialization_t {
public:
using visitor_specialization_t::config_t;
using visitor_specialization_t::diagram_t;
using template_builder_t = template_builder<translation_unit_visitor>;
/**
* @brief Constructor.
*
@@ -102,30 +111,6 @@ public:
virtual bool TraverseConceptDecl(clang::ConceptDecl *cpt);
/** @} */
/**
* @brief Get diagram model reference
*
* @return Reference to diagram model created by the visitor
*/
clanguml::class_diagram::model::diagram &diagram() { return diagram_; }
/**
* @brief Get diagram model reference
*
* @return Reference to diagram model created by the visitor
*/
const clanguml::class_diagram::model::diagram &diagram() const
{
return diagram_;
}
/**
* @brief Get diagram config instance
*
* @return Reference to config instance
*/
const clanguml::config::class_diagram &config() const { return config_; }
/**
* @brief Finalize diagram model
*
@@ -157,15 +142,16 @@ public:
*/
void add_concept(std::unique_ptr<concept_> &&c);
private:
/**
* @brief Check if the diagram should include a declaration.
*
* @param decl Clang declaration.
* @return True, if the entity should be included in the diagram.
*/
bool should_include(const clang::NamedDecl *decl);
void add_diagram_element(
std::unique_ptr<common::model::template_element> element) override;
std::unique_ptr<class_> create_element(const clang::NamedDecl *decl) const;
void find_instantiation_relationships(
common::model::template_element &template_instantiation_base,
const std::string &full_name, common::id_t templated_decl_id);
private:
/**
* @brief Create class element model from class declaration
*
@@ -244,20 +230,6 @@ private:
void process_template_specialization_children(
const clang::ClassTemplateSpecializationDecl *cls, class_ &c);
/**
* @brief Process template parameters
*
* @param template_declaration Template declaration
* @param t `template_trait` instance to which the parameters should be
* added
* @param templated_element Optional templated diagram element (e.g. class_)
* @return Ignored
*/
bool process_template_parameters(
const clang::TemplateDecl &template_declaration,
clanguml::common::model::template_trait &t,
common::optional_ref<common::model::element> templated_element = {});
/**
* @brief Process class method
*
@@ -451,27 +423,14 @@ 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
*
* @return Reference to 'template_builder' instance
*/
template_builder &tbuilder() { return template_builder_; }
template_builder_t &tbuilder() { return template_builder_; }
// Reference to the output diagram model
clanguml::class_diagram::model::diagram &diagram_;
// Reference to class diagram config
const clanguml::config::class_diagram &config_;
template_builder template_builder_;
template_builder_t template_builder_;
std::map<common::id_t,
std::unique_ptr<clanguml::class_diagram::model::class_>>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -16,174 +16,6 @@
* limitations under the License.
*/
#include "translation_unit_visitor.h"
#include "comment/clang_visitor.h"
#include "comment/plain_visitor.h"
#include "common/clang_utils.h"
#include <clang/AST/Expr.h>
#include <clang/Basic/Module.h>
namespace clanguml::common::visitor {
translation_unit_visitor::translation_unit_visitor(
clang::SourceManager &sm, const clanguml::config::diagram &config)
: source_manager_{sm}
, relative_to_path_{config.root_directory()}
{
if (config.comment_parser() == config::comment_parser_t::plain) {
comment_visitor_ =
std::make_unique<comment::plain_visitor>(source_manager_);
}
else if (config.comment_parser() == config::comment_parser_t::clang) {
comment_visitor_ =
std::make_unique<comment::clang_visitor>(source_manager_);
}
}
void translation_unit_visitor::set_tu_path(
const std::string &translation_unit_path)
{
translation_unit_path_ = relative(
std::filesystem::path{translation_unit_path}, relative_to_path_);
translation_unit_path_.make_preferred();
}
const std::filesystem::path &translation_unit_visitor::tu_path() const
{
return translation_unit_path_;
}
clang::SourceManager &translation_unit_visitor::source_manager() const
{
return source_manager_;
}
void translation_unit_visitor::process_comment(
const clang::NamedDecl &decl, clanguml::common::model::decorated_element &e)
{
assert(comment_visitor_.get() != nullptr);
comment_visitor_->visit(decl, e);
const auto *comment =
decl.getASTContext().getRawCommentForDeclNoCache(&decl);
process_comment(comment, decl.getASTContext().getDiagnostics(), e);
}
void translation_unit_visitor::process_comment(const clang::RawComment *comment,
clang::DiagnosticsEngine &de, clanguml::common::model::decorated_element &e)
{
if (comment != nullptr) {
auto [it, inserted] = processed_comments_.emplace(comment);
if (!inserted)
return;
// Process clang-uml decorators in the comments
// TODO: Refactor to use standard block comments processable by clang
// comments
e.add_decorators(
decorators::parse(comment->getFormattedText(source_manager_, de)));
}
}
void translation_unit_visitor::set_source_location(
const clang::Decl &decl, clanguml::common::model::source_location &element)
{
set_source_location(decl.getLocation(), element);
}
void translation_unit_visitor::set_source_location(
const clang::Expr &expr, clanguml::common::model::source_location &element)
{
set_source_location(expr.getBeginLoc(), element);
}
void translation_unit_visitor::set_source_location(
const clang::Stmt &stmt, clanguml::common::model::source_location &element)
{
set_source_location(stmt.getBeginLoc(), element);
}
void translation_unit_visitor::set_source_location(
const clang::SourceLocation &location,
clanguml::common::model::source_location &element)
{
namespace fs = std::filesystem;
std::string file;
unsigned line{};
unsigned column{};
if (location.isValid()) {
file = source_manager_.getFilename(location).str();
line = source_manager_.getSpellingLineNumber(location);
column = source_manager_.getSpellingColumnNumber(location);
if (file.empty()) {
// Why do I have to do this?
parse_source_location(
location.printToString(source_manager()), file, line, column);
}
}
else {
auto success = parse_source_location(
location.printToString(source_manager()), file, line, column);
if (!success) {
LOG_DBG("Failed to extract source location for element from {}",
location.printToString(source_manager_));
return;
}
}
// ensure the path is absolute
fs::path file_path{file};
if (!file_path.is_absolute()) {
file_path = fs::absolute(file_path);
}
file_path = fs::weakly_canonical(file_path);
file = file_path.string();
element.set_file(file);
if (util::is_relative_to(file_path, relative_to_path_)) {
element.set_file_relative(util::path_to_url(
fs::relative(element.file(), relative_to_path_).string()));
}
else {
element.set_file_relative("");
}
element.set_translation_unit(tu_path().string());
element.set_line(line);
element.set_column(column);
element.set_location_id(location.getHashValue());
}
void translation_unit_visitor::set_owning_module(
const clang::Decl &decl, clanguml::common::model::element &element)
{
if (const clang::Module *module = decl.getOwningModule();
module != nullptr) {
std::string module_name = module->Name;
bool is_private{false};
#if LLVM_VERSION_MAJOR < 15
is_private =
module->Kind == clang::Module::ModuleKind::PrivateModuleFragment;
#else
is_private = module->isPrivateModule();
#endif
if (is_private) {
// Clang just maps private modules names to "<private>"
module_name = module->getTopLevelModule()->Name;
}
element.set_module(module_name);
element.set_module_private(is_private);
}
}
} // namespace clanguml::common::visitor

View File

@@ -17,14 +17,21 @@
*/
#pragma once
#include "comment/clang_visitor.h"
#include "comment/comment_visitor.h"
#include "comment/plain_visitor.h"
#include "common/clang_utils.h"
#include "common/model/namespace.h"
#include "common/model/source_file.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 <clang/AST/Comment.h>
#include <clang/AST/Expr.h>
#include <clang/AST/RawCommentList.h>
#include <clang/Basic/Module.h>
#include <clang/Basic/SourceManager.h>
#include <deque>
@@ -44,8 +51,11 @@ using found_relationships_t = std::vector<
* This class provides common interface for diagram translation unit
* visitors.
*/
class translation_unit_visitor {
template <typename ConfigT, typename DiagramT> class translation_unit_visitor {
public:
using config_t = ConfigT;
using diagram_t = DiagramT;
/**
* @brief Constructor
*
@@ -54,17 +64,39 @@ public:
* instance
*/
explicit translation_unit_visitor(
clang::SourceManager &sm, const clanguml::config::diagram &config);
clang::SourceManager &sm, DiagramT &diagram, const ConfigT &config)
: diagram_{diagram}
, config_{config}
, source_manager_{sm}
, relative_to_path_{config.root_directory()}
{
if (config.comment_parser() == config::comment_parser_t::plain) {
comment_visitor_ =
std::make_unique<comment::plain_visitor>(source_manager_);
}
else if (config.comment_parser() == config::comment_parser_t::clang) {
comment_visitor_ =
std::make_unique<comment::clang_visitor>(source_manager_);
}
}
virtual ~translation_unit_visitor() = default;
void set_tu_path(const std::string &translation_unit_path);
void set_tu_path(const std::string &translation_unit_path)
{
translation_unit_path_ = relative(
std::filesystem::path{translation_unit_path}, relative_to_path_);
translation_unit_path_.make_preferred();
}
/**
* @brief Return relative path to current translation unit
* @return Current translation unit path
*/
const std::filesystem::path &tu_path() const;
const std::filesystem::path &tu_path() const
{
return translation_unit_path_;
}
/**
* @brief Get reference to Clang AST to clang-uml id mapper
@@ -78,7 +110,7 @@ public:
* @return Reference to @ref clang::SourceManager used by this translation
* unit visitor
*/
clang::SourceManager &source_manager() const;
clang::SourceManager &source_manager() const { return source_manager_; }
/**
* @brief Set source location in diagram element
@@ -87,7 +119,10 @@ public:
* @param element Reference to element to be updated
*/
void set_source_location(const clang::Decl &decl,
clanguml::common::model::source_location &element);
clanguml::common::model::source_location &element)
{
set_source_location(decl.getLocation(), element);
}
/**
* @brief Set source location in diagram element
@@ -96,10 +131,25 @@ public:
* @param element Reference to element to be updated
*/
void set_source_location(const clang::Expr &expr,
clanguml::common::model::source_location &element);
clanguml::common::model::source_location &element)
{
set_source_location(expr.getBeginLoc(), element);
}
void set_source_location(const clang::Stmt &stmt,
clanguml::common::model::source_location &element);
clanguml::common::model::source_location &element)
{
set_source_location(stmt.getBeginLoc(), element);
}
void set_qualified_name(
const clang::NamedDecl &decl, clanguml::common::model::element &element)
{
common::model::namespace_ ns{decl.getQualifiedNameAsString()};
element.set_name(ns.name());
ns.pop_back();
element.set_namespace(ns);
}
/**
* @brief Set source location in diagram element
@@ -108,17 +158,88 @@ public:
* @param element Reference to element to be updated
*/
void set_source_location(const clang::SourceLocation &location,
clanguml::common::model::source_location &element);
clanguml::common::model::source_location &element)
{
namespace fs = std::filesystem;
std::string file;
unsigned line{};
unsigned column{};
if (location.isValid()) {
file = source_manager_.getFilename(location).str();
line = source_manager_.getSpellingLineNumber(location);
column = source_manager_.getSpellingColumnNumber(location);
if (file.empty()) {
// Why do I have to do this?
parse_source_location(location.printToString(source_manager()),
file, line, column);
}
}
else {
auto success = parse_source_location(
location.printToString(source_manager()), file, line, column);
if (!success) {
LOG_DBG("Failed to extract source location for element from {}",
location.printToString(source_manager_));
return;
}
}
// ensure the path is absolute
fs::path file_path{file};
if (!file_path.is_absolute()) {
file_path = fs::absolute(file_path);
}
file_path = fs::weakly_canonical(file_path);
file = file_path.string();
element.set_file(file);
if (util::is_relative_to(file_path, relative_to_path_)) {
element.set_file_relative(util::path_to_url(
fs::relative(element.file(), relative_to_path_).string()));
}
else {
element.set_file_relative("");
}
element.set_translation_unit(tu_path().string());
element.set_line(line);
element.set_column(column);
element.set_location_id(location.getHashValue());
}
void set_owning_module(
const clang::Decl &decl, clanguml::common::model::element &element);
const clang::Decl &decl, clanguml::common::model::element &element)
{
if (const clang::Module *module = decl.getOwningModule();
module != nullptr) {
std::string module_name = module->Name;
bool is_private{false};
#if LLVM_VERSION_MAJOR < 15
is_private = module->Kind ==
clang::Module::ModuleKind::PrivateModuleFragment;
#else
is_private = module->isPrivateModule();
#endif
if (is_private) {
// Clang just maps private modules names to "<private>"
module_name = module->getTopLevelModule()->Name;
}
element.set_module(module_name);
element.set_module_private(is_private);
}
}
virtual void add_diagram_element(
std::unique_ptr<common::model::template_element> element)
{
}
protected:
/**
* @brief Process comment directives in comment attached to a declaration
*
@@ -126,7 +247,17 @@ protected:
* @param element Reference to element to be updated
*/
void process_comment(const clang::NamedDecl &decl,
clanguml::common::model::decorated_element &e);
clanguml::common::model::decorated_element &e)
{
assert(comment_visitor_.get() != nullptr);
comment_visitor_->visit(decl, e);
const auto *comment =
decl.getASTContext().getRawCommentForDeclNoCache(&decl);
process_comment(comment, decl.getASTContext().getDiagnostics(), e);
}
/**
* @brief Process comment directives in raw comment
@@ -137,9 +268,77 @@ protected:
*/
void process_comment(const clang::RawComment *comment,
clang::DiagnosticsEngine &de,
clanguml::common::model::decorated_element &e);
clanguml::common::model::decorated_element &e)
{
if (comment != nullptr) {
auto [it, inserted] = processed_comments_.emplace(comment);
if (!inserted)
return;
// Process clang-uml decorators in the comments
// TODO: Refactor to use standard block comments processable by
// clang comments
e.add_decorators(decorators::parse(
comment->getFormattedText(source_manager_, de)));
}
}
/**
* @brief Check if the diagram should include a declaration.
*
* @param decl Clang declaration.
* @return True, if the entity should be included in the diagram.
*/
bool should_include(const clang::NamedDecl *decl)
{
if (decl == nullptr)
return false;
if (source_manager().isInSystemHeader(
decl->getSourceRange().getBegin()))
return false;
auto should_include_namespace = diagram().should_include(
common::model::namespace_{decl->getQualifiedNameAsString()});
const auto decl_file =
decl->getLocation().printToString(source_manager());
const auto should_include_decl_file =
diagram().should_include(common::model::source_file{decl_file});
return should_include_namespace && should_include_decl_file;
}
/**
* @brief Get diagram model reference
*
* @return Reference to diagram model created by the visitor
*/
DiagramT &diagram() { return diagram_; }
/**
* @brief Get diagram model reference
*
* @return Reference to diagram model created by the visitor
*/
const DiagramT &diagram() const { return diagram_; }
/**
* @brief Get diagram config instance
*
* @return Reference to config instance
*/
const ConfigT &config() const { return config_; }
private:
// Reference to the output diagram model
DiagramT &diagram_;
// Reference to class diagram config
const ConfigT &config_;
clang::SourceManager &source_manager_;
std::unique_ptr<comment::comment_visitor> comment_visitor_;

View File

@@ -37,9 +37,7 @@ translation_unit_visitor::include_visitor::include_visitor(
clang::SourceManager &sm,
clanguml::include_diagram::model::diagram &diagram,
const clanguml::config::include_diagram &config)
: common::visitor::translation_unit_visitor{sm, config}
, diagram_{diagram}
, config_{config}
: visitor_specialization_t{sm, diagram, config}
{
}
@@ -112,18 +110,6 @@ void translation_unit_visitor::include_visitor::InclusionDirective(
}
}
clanguml::include_diagram::model::diagram &
translation_unit_visitor::include_visitor::diagram()
{
return diagram_;
}
const clanguml::config::include_diagram &
translation_unit_visitor::include_visitor::config() const
{
return config_;
}
void translation_unit_visitor::include_visitor::process_internal_header(
const std::filesystem::path &include_path, bool is_system,
const common::id_t current_file_id)

View File

@@ -35,6 +35,10 @@
namespace clanguml::include_diagram::visitor {
using visitor_specialization_t =
common::visitor::translation_unit_visitor<clanguml::config::include_diagram,
clanguml::include_diagram::model::diagram>;
/**
* @brief Include diagram translation unit visitor wrapper
*
@@ -53,7 +57,7 @@ public:
* include_visitor type from translation_unit_visitor type
*/
class include_visitor : public clang::PPCallbacks,
public common::visitor::translation_unit_visitor {
public visitor_specialization_t {
public:
/**
* @brief Constructor.
@@ -123,27 +127,6 @@ public:
*/
std::optional<common::id_t> process_source_file(
const std::filesystem::path &file);
/**
* @brief Get reference to the include diagram model
*
* @return Reference to the include diagram model
*/
clanguml::include_diagram::model::diagram &diagram();
/**
* @brief Get reference to the diagram configuration
*
* @return Reference to the diagram configuration
*/
const clanguml::config::include_diagram &config() const;
private:
// Reference to the output diagram model
clanguml::include_diagram::model::diagram &diagram_;
// Reference to class diagram config
const clanguml::config::include_diagram &config_;
};
/**

View File

@@ -37,9 +37,7 @@ using clanguml::common::model::relationship_t;
translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
clanguml::package_diagram::model::diagram &diagram,
const clanguml::config::package_diagram &config)
: common::visitor::translation_unit_visitor{sm, config}
, diagram_{diagram}
, config_{config}
: visitor_specialization_t{sm, diagram, config}
{
}
@@ -676,17 +674,6 @@ bool translation_unit_visitor::find_relationships(const clang::QualType &type,
return result;
}
clanguml::package_diagram::model::diagram &translation_unit_visitor::diagram()
{
return diagram_;
}
const clanguml::config::package_diagram &
translation_unit_visitor::config() const
{
return config_;
}
void translation_unit_visitor::finalize() { }
std::vector<common::id_t> translation_unit_visitor::get_parent_package_ids(

View File

@@ -36,6 +36,10 @@ namespace clanguml::package_diagram::visitor {
using found_relationships_t = std::vector<
std::pair<clanguml::common::id_t, common::model::relationship_t>>;
using visitor_specialization_t =
common::visitor::translation_unit_visitor<clanguml::config::package_diagram,
clanguml::package_diagram::model::diagram>;
/**
* @brief Package diagram translation unit visitor
*
@@ -44,7 +48,7 @@ using found_relationships_t = std::vector<
*/
class translation_unit_visitor
: public clang::RecursiveASTVisitor<translation_unit_visitor>,
public common::visitor::translation_unit_visitor {
public visitor_specialization_t {
public:
/**
* @brief Constructor.
@@ -76,20 +80,6 @@ public:
virtual bool VisitFunctionDecl(clang::FunctionDecl *function_declaration);
/** @} */
/**
* @brief Get diagram model reference
*
* @return Reference to diagram model created by the visitor
*/
clanguml::package_diagram::model::diagram &diagram();
/**
* @brief Get diagram model reference
*
* @return Reference to diagram model created by the visitor
*/
const clanguml::config::package_diagram &config() const;
/**
* @brief Finalize diagram model
*/
@@ -214,11 +204,5 @@ private:
clang::Decl *cls, found_relationships_t &relationships);
std::vector<common::id_t> get_parent_package_ids(common::id_t id);
// Reference to the output diagram model
clanguml::package_diagram::model::diagram &diagram_;
// Reference to class diagram config
const clanguml::config::package_diagram &config_;
};
} // namespace clanguml::package_diagram::visitor

File diff suppressed because it is too large Load Diff

View File

@@ -36,6 +36,10 @@ using common::model::template_parameter;
std::string to_string(const clang::FunctionTemplateDecl *decl);
using visitor_specialization_t = common::visitor::translation_unit_visitor<
clanguml::config::sequence_diagram,
clanguml::sequence_diagram::model::diagram>;
/**
* @brief Sequence diagram translation unit visitor
*
@@ -44,8 +48,14 @@ std::string to_string(const clang::FunctionTemplateDecl *decl);
*/
class translation_unit_visitor
: public clang::RecursiveASTVisitor<translation_unit_visitor>,
public common::visitor::translation_unit_visitor {
public visitor_specialization_t {
public:
using visitor_specialization_t::config_t;
using visitor_specialization_t::diagram_t;
using template_builder_t =
common::visitor::template_builder<translation_unit_visitor>;
/**
* @brief Constructor.
*
@@ -124,27 +134,6 @@ public:
bool TraverseConditionalOperator(clang::ConditionalOperator *stmt);
/** @} */
/**
* @brief Get diagram model reference
*
* @return Reference to diagram model created by the visitor
*/
clanguml::sequence_diagram::model::diagram &diagram();
/**
* @brief Get diagram model reference
*
* @return Reference to diagram model created by the visitor
*/
const clanguml::sequence_diagram::model::diagram &diagram() const;
/**
* @brief Get diagram config instance
*
* @return Reference to config instance
*/
const clanguml::config::sequence_diagram &config() const;
/**
* @brief Get current call expression context reference
*
@@ -255,6 +244,9 @@ public:
*/
void finalize();
std::unique_ptr<sequence_diagram::model::class_> create_element(
const clang::NamedDecl *decl) const;
private:
/**
* @brief Check if the diagram should include a declaration.
@@ -312,21 +304,12 @@ private:
*/
bool should_include(const clang::ClassTemplateDecl *decl) const;
/**
* @todo #227 Refactor this group of methods to @ref template_builder
*
* @{
*/
std::unique_ptr<clanguml::sequence_diagram::model::class_>
create_class_model(clang::CXXRecordDecl *cls);
std::unique_ptr<clanguml::sequence_diagram::model::method>
create_method_model(clang::CXXMethodDecl *cls);
bool process_template_parameters(
const clang::TemplateDecl &template_declaration,
common::model::template_trait &c);
std::unique_ptr<model::function_template>
build_function_template_instantiation(const clang::FunctionDecl &pDecl);
@@ -336,63 +319,10 @@ private:
std::unique_ptr<model::function_template> build_function_template(
const clang::FunctionTemplateDecl &declaration);
void build_template_instantiation_process_template_arguments(
model::template_trait *parent,
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
const clang::ArrayRef<clang::TemplateArgument> &template_args,
model::template_trait &template_instantiation,
const std::string &full_template_specialization_name,
const clang::TemplateDecl *template_decl);
common::model::template_parameter
build_template_instantiation_process_template_argument(
const clang::TemplateArgument &arg) const;
common::model::template_parameter
build_template_instantiation_process_integral_argument(
const clang::TemplateArgument &arg) const;
common::model::template_parameter
build_template_instantiation_process_expression_argument(
const clang::TemplateArgument &arg) const;
void build_template_instantiation_process_tag_argument(
model::template_trait &template_instantiation,
const std::string &full_template_specialization_name,
const clang::TemplateDecl *template_decl,
const clang::TemplateArgument &arg,
common::model::template_parameter &argument) const;
common::model::template_parameter
build_template_instantiation_process_type_argument(
model::template_trait *parent,
const std::string &full_template_specialization_name,
const clang::TemplateDecl *template_decl,
const clang::TemplateArgument &arg,
model::template_trait &template_instantiation);
std::unique_ptr<model::class_> process_template_specialization(
std::unique_ptr<model::class_> process_class_template_specialization(
clang::ClassTemplateSpecializationDecl *cls);
void process_template_specialization_argument(
const clang::ClassTemplateSpecializationDecl *cls,
model::class_ &template_instantiation,
const clang::TemplateArgument &arg, size_t argument_index,
bool in_parameter_pack = false);
void process_unexposed_template_specialization_parameters(
const std::string &type_name, common::model::template_parameter &tp,
model::class_ &c) const;
std::unique_ptr<model::class_> build_template_instantiation(
const clang::TemplateSpecializationType &template_type_decl,
model::class_ *parent);
bool simplify_system_template(common::model::template_parameter &ct,
const std::string &full_name) const;
std::string simplify_system_template(const std::string &full_name) const;
/** }@ */
/**
* @brief Assuming `cls` is a lambda, create it's full name.
@@ -516,13 +446,7 @@ private:
*
* @return Reference to 'template_builder' instance
*/
common::visitor::template_builder &tbuilder() { return template_builder_; }
// Reference to the output diagram model
clanguml::sequence_diagram::model::diagram &diagram_;
// Reference to class diagram config
const clanguml::config::sequence_diagram &config_;
template_builder_t &tbuilder() { return template_builder_; }
call_expression_context call_expression_context_;
@@ -558,6 +482,6 @@ private:
mutable std::set<std::pair<int64_t, const clang::RawComment *>>
processed_comments_;
common::visitor::template_builder template_builder_;
template_builder_t template_builder_;
};
} // namespace clanguml::sequence_diagram::visitor