Update Doxygen docs for class_diagram namespace

This commit is contained in:
Bartek Kryza
2023-06-24 17:23:43 +02:00
parent 627a9fe1a8
commit 935d25c8f4
20 changed files with 1358 additions and 86 deletions

View File

@@ -56,36 +56,110 @@ using clanguml::common::model::relationship_t;
using namespace clanguml::util;
/**
* @brief Class diagram JSON generator
*/
class generator : public common_generator<diagram_config, diagram_model> {
public:
generator(diagram_config &config, diagram_model &model);
/**
* @brief Main generator method.
*
* This method is called first and coordinates the entire diagram
* generation.
*
* @param ostr Output stream.
*/
void generate(std::ostream &ostr) const override;
/**
* Render class element into a JSON node.
*
* @param c class diagram element
* @param parent JSON node
*/
void generate(const class_ &c, nlohmann::json &parent) const;
/**
* Render enum element into a JSON node.
*
* @param c enum diagram element
* @param parent JSON node
*/
void generate(const enum_ &c, nlohmann::json &parent) const;
/**
* Render concept element into a JSON node.
*
* @param c concept diagram element
* @param parent JSON node
*/
void generate(const concept_ &c, nlohmann::json &parent) const;
/**
* Render package element into a JSON node.
*
* @param p package diagram element
* @param parent JSON node
*/
void generate(const package &p, nlohmann::json &parent) const;
/**
* @brief In a nested diagram, generate the top level elements.
*
* This method iterates over the top level elements. In case the diagram
* is nested (i.e. includes packages), for each package it recursively
* call generation of elements contained in each package.
*
* @param parent JSON node
*/
void generate_top_level_elements(nlohmann::json &parent) const;
/**
* @brief Generate all relationships in the diagram.
*
* @param parent JSON node
*/
void generate_relationships(nlohmann::json &parent) const;
/**
* @brief Generate all relationships originating at a class element.
*
* @param c Class diagram element
* @param parent JSON node
*/
void generate_relationships(const class_ &c, nlohmann::json &parent) const;
/**
* @brief Generate all relationships originating at an enum element.
*
* @param c Enum diagram element
* @param parent JSON node
*/
void generate_relationships(const enum_ &c, nlohmann::json &parent) const;
/**
* @brief Generate all relationships originating at a concept element.
*
* @param c Concept diagram element
* @param parent JSON node
*/
void generate_relationships(
const concept_ &c, nlohmann::json &parent) const;
/**
* @brief Generate all relationships in a package.
*
* If the diagram is nested, it recursively calls relationship generation
* for all subelements.
*
* @param p Package diagram element
* @param parent JSON node
*/
void generate_relationships(const package &p, nlohmann::json &parent) const;
private:
std::string render_name(std::string name) const;
mutable nlohmann::json json_;
};

View File

@@ -59,60 +59,208 @@ using clanguml::common::model::relationship_t;
using namespace clanguml::util;
/**
* @brief Class diagram PlantUML generator
*/
class generator : public common_generator<diagram_config, diagram_model> {
using method_groups_t = std::map<std::string, std::vector<class_method>>;
public:
generator(diagram_config &config, diagram_model &model);
/**
* @brief Main generator method.
*
* This method is called first and coordinates the entire diagram
* generation.
*
* @param ostr Output stream.
*/
void generate(std::ostream &ostr) const override;
/**
* @brief In a nested diagram, generate the top level elements.
*
* This method iterates over the top level elements. In case the diagram
* is nested (i.e. includes packages), for each package it recursively
* call generation of elements contained in each package.
*
* @param parent JSON node
*/
void generate_top_level_elements(std::ostream &ostr) const;
/**
* @brief Generate a hyperlink for a class element.
*
* @param ostr Output stream
* @param e Class element (e.g. a method)
*/
void generate_link(std::ostream &ostr, const class_element &e) const;
/**
* @brief Generate PlantUML alias for a class element.
*
* @param c Class element
* @param ostr Output stream
*/
void generate_alias(const class_ &c, std::ostream &ostr) const;
/**
* @brief Generate PlantUML alias for a enum element.
*
* @param e Enum element
* @param ostr Output stream
*/
void generate_alias(const enum_ &e, std::ostream &ostr) const;
/**
* @brief Generate PlantUML alias for a concept element.
*
* @param c Concept element
* @param ostr Output stream
*/
void generate_alias(const concept_ &c, std::ostream &ostr) const;
/**
* @brief Render class element to PlantUML
*
* @param c Class element
* @param ostr Output stream
*/
void generate(const class_ &c, std::ostream &ostr) const;
/**
* @brief Render class methods to PlantUML
*
* @param methods List of class methods
* @param ostr Output stream
*/
void generate_methods(
const std::vector<class_method> &methods, std::ostream &ostr) const;
/**
* @brief Render class methods to PlantUML in groups
*
* @param methods Methods grouped by method type
* @param ostr Output stream
*/
void generate_methods(
const method_groups_t &methods, std::ostream &ostr) const;
/**
* @brief Render class method to PlantUML
*
* @param m Class method
* @param ostr Output stream
*/
void generate_method(const class_method &m, std::ostream &ostr) const;
/**
* @brief Render class member to PlantUML
*
* @param m Class member
* @param ostr Output stream
*/
void generate_member(const class_member &m, std::ostream &ostr) const;
void generate_top_level_elements(std::ostream &ostr) const;
/**
* @brief Render all relationships in the diagram to PlantUML
*
* @param ostr Output stream
*/
void generate_relationships(std::ostream &ostr) const;
/**
* @brief Render all relationships originating from class element.
*
* @param c Class element
* @param ostr Output stream
*/
void generate_relationships(const class_ &c, std::ostream &ostr) const;
/**
* @brief Render a specific relationship to PlantUML.
*
* @param r Relationship model
* @param rendered_relations Set of already rendered relationships, to
* ensure that there are no duplicate
* relationships
*/
void generate_relationship(
const relationship &r, std::set<std::string> &rendered_relations) const;
/**
* @brief Render enum element to PlantUML
*
* @param e Enum element
* @param ostr Output stream
*/
void generate(const enum_ &e, std::ostream &ostr) const;
/**
* @brief Render all relationships originating from enum element.
*
* @param c Enum element
* @param ostr Output stream
*/
void generate_relationships(const enum_ &c, std::ostream &ostr) const;
/**
* @brief Render concept element to PlantUML
*
* @param c Concept element
* @param ostr Output stream
*/
void generate(const concept_ &c, std::ostream &ostr) const;
/**
* @brief Render all relationships originating from concept element.
*
* @param c Concept element
* @param ostr Output stream
*/
void generate_relationships(const concept_ &c, std::ostream &ostr) const;
/**
* @brief Render package element to PlantUML
*
* @param p Package element
* @param ostr Output stream
*/
void generate(const package &p, std::ostream &ostr) const;
/**
* @brief Render all relationships originating from package element.
*
* @param p Package element
* @param ostr Output stream
*/
void generate_relationships(const package &p, std::ostream &ostr) const;
/**
* @brief Generate any notes attached specifically to some class element.
*
* @param ostream Output stream
* @param member Class element (member or method)
* @param alias PlantUML class alias
*/
void generate_member_notes(std::ostream &ostream,
const class_element &member, const std::string &basicString) const;
const class_element &member, const std::string &alias) const;
/**
* @brief Generate elements grouped together in `together` groups.
*
* @param ostr Output stream
*/
void generate_groups(std::ostream &ostr) const;
void generate(std::ostream &ostr) const override;
/**
* @brief Group class methods based on method type.
*
* @param methods List of class methods.
*
* @return Map of method groups.
*/
method_groups_t group_methods(
const std::vector<class_method> &methods) const;

View File

@@ -26,6 +26,9 @@
namespace clanguml::class_diagram::model {
/**
* @brief Base class for class elements (e.g. member or method).
*/
class class_element : public common::model::decorated_element,
public common::model::source_location {
public:
@@ -34,13 +37,46 @@ public:
~class_element() override = default;
/**
* @brief Get elements access scope.
*
* @return Elements access scope.
*/
common::model::access_t access() const;
/**
* @brief Get elements name.
*
* @return Elements name.
*/
std::string name() const;
/**
* @brief Set elements name.
*
* @param name Elements name.
*/
void set_name(const std::string &name);
/**
* @brief Get elements type as string.
*
* @return Elements type as string.
*/
std::string type() const;
/**
* @brief Set elements type as string.
*
* @param type Elements type as string.
*/
void set_type(const std::string &type);
/**
* @brief Get elements inja context in JSON.
*
* @return Context in JSON
*/
virtual inja::json context() const;
private:

View File

@@ -23,18 +23,38 @@
namespace clanguml::class_diagram::model {
/**
* @brief Class member model.
*/
class class_member : public class_element {
public:
/**
* @brief Constructor.
*
* @param access Members access scope (e.g. public)
* @param name Members name.
* @param type Members type as string.
*/
class_member(common::model::access_t access, const std::string &name,
const std::string &type);
~class_member() override = default;
/**
* @brief Whether the member is static.
*
* @return True, if the member is static.
*/
bool is_static() const;
/**
* @brief Set members static status.
*
* @param is_static True, if the member is static.
*/
void is_static(bool is_static);
private:
bool is_relationship_{false};
bool is_static_{false};
};

View File

@@ -29,56 +29,225 @@ namespace clanguml::class_diagram::model {
using clanguml::common::model::template_trait;
/**
* @brief Class method model.
*/
class class_method : public class_element, public template_trait {
public:
/**
* @brief Constructor.
*
* @param access Methods access scope (e.g. public)
* @param name Methods name.
* @param type Methods return type as string.
*/
class_method(common::model::access_t access, const std::string &name,
const std::string &type);
~class_method() override = default;
/**
* @brief Whether the method is pure virtual.
*
* @return True, if the method is pure virtual
*/
bool is_pure_virtual() const;
void is_pure_virtual(bool is_pure_virtual);
/**
* @brief Whether the method is virtual.
*
* @return True, if the method is virtual
*/
bool is_virtual() const;
/**
* @brief Set whether the method is virtual.
*
* @param is_virtual True, if the method is virtual
*/
void is_virtual(bool is_virtual);
/**
* @brief Whether the method is const.
*
* @return True, if the method is const
*/
bool is_const() const;
/**
* @brief Set whether the method is const.
*
* @param is_const True, if the method is const
*/
void is_const(bool is_const);
/**
* @brief Whether the method is defaulted.
*
* @return True, if the method is defaulted
*/
bool is_defaulted() const;
/**
* @brief Set whether the method is defaulted.
*
* @param is_defaulted True, if the method is defaulted
*/
void is_defaulted(bool is_defaulted);
/**
* @brief Whether the method is deleted.
*
* @return True, if the method is deleted
*/
bool is_deleted() const;
/**
* @brief Set whether the method is deleted.
*
* @param is_deleted True, if the method is deleted
*/
void is_deleted(bool is_deleted);
/**
* @brief Whether the method is static.
*
* @return True, if the method is static
*/
bool is_static() const;
/**
* @brief Set whether the method is static.
*
* @param is_static True, if the method is static
*/
void is_static(bool is_static);
/**
* @brief Whether the method is constexpr.
*
* @return True, if the method is constexpr
*/
bool is_constexpr() const;
/**
* @brief Set whether the method is constexpr.
*
* @param is_constexpr True, if the method is constexpr
*/
void is_constexpr(bool is_constexpr);
/**
* @brief Whether the method is consteval.
*
* @return True, if the method is consteval
*/
bool is_consteval() const;
/**
* @brief Set whether the method is consteval.
*
* @param is_consteval True, if the method is consteval
*/
void is_consteval(bool is_consteval);
/**
* @brief Whether the method is noexcept.
*
* @return True, if the method is noexcept
*/
bool is_noexcept() const;
/**
* @brief Set whether the method is noexcept.
*
* @param is_noexcept True, if the method is noexcept
*/
void is_noexcept(bool is_noexcept);
/**
* @brief Whether the method is a constructor.
*
* @return True, if the method is a constructor
*/
bool is_constructor() const;
/**
* @brief Set whether the method is a constructor.
*
* @param is_constructor True, if the method is a constructor
*/
void is_constructor(bool is_constructor);
/**
* @brief Whether the method is a destructor.
*
* @return True, if the method is a destructor
*/
bool is_destructor() const;
/**
* @brief Set whether the method is a destructor.
*
* @param is_destructor True, if the method is a destructor
*/
void is_destructor(bool is_destructor);
/**
* @brief Whether the method is move assignment.
*
* @return True, if the method is move assignment
*/
bool is_move_assignment() const;
/**
* @brief Set whether the method is a move assignment.
*
* @param is_move_assignment True, if the method is a move assignment
*/
void is_move_assignment(bool is_move_assignment);
/**
* @brief Whether the method is copy assignment.
*
* @return True, if the method is copy assignment
*/
bool is_copy_assignment() const;
/**
* @brief Set whether the method is a copy assignment.
*
* @param is_copy_assignment True, if the method is a copy assignment
*/
void is_copy_assignment(bool is_copy_assignment);
/**
* @brief Whether the method is an operator.
*
* @return True, if the method is an operator
*/
bool is_operator() const;
/**
* @brief Set whether the method is an operator.
*
* @param is_copy_assignment True, if the method is an operator
*/
void is_operator(bool is_operator);
/**
* @brief Get the method parameters.
*
* @return List of methods parameters
*/
const std::vector<method_parameter> &parameters() const;
/**
* @brief Add methods parameter.
*
* @param parameter Method parameter.
*/
void add_parameter(method_parameter &&parameter);
private:

View File

@@ -24,6 +24,10 @@ void class_parent::set_name(const std::string &name) { name_ = name; }
std::string class_parent::name() const { return name_; }
void class_parent::set_id(clanguml::common::id_t id) { id_ = id; }
clanguml::common::id_t class_parent::id() const noexcept { return id_; }
void class_parent::is_virtual(bool is_virtual) { is_virtual_ = is_virtual; }
bool class_parent::is_virtual() const { return is_virtual_; }

View File

@@ -25,25 +25,75 @@
namespace clanguml::class_diagram::model {
/**
* @brief Class parent relationship model.
*
* @todo Consider refactoring this class to a regular relationship.
*/
class class_parent {
public:
class_parent() = default;
class_parent(const std::string &name)
{
set_name(name);
set_id(common::to_id(name));
}
/**
* @brief Set the fully qualified name of class parent.
*
* @param name Fully qualified name of the parent class.
*/
void set_name(const std::string &name);
/**
* @brief Get the fully qualified name of class parent.
*
* @return Fully qualified name of the parent class.
*/
std::string name() const;
clanguml::common::id_t id() const noexcept { return id_; }
void set_id(clanguml::common::id_t id) { id_ = id; }
/**
* @brief Set the id of class parent.
*
* @param id Id of the parent class.
*/
void set_id(clanguml::common::id_t id);
/**
* @brief Get the id of class parent.
*
* @return Id of the parent class.
*/
clanguml::common::id_t id() const noexcept;
/**
* @brief Set whether the parent is virtual.
*
* @param is_virtual True if the parent is virtual
*/
void is_virtual(bool is_virtual);
/**
* @brief Get whether the parent is virtual.
*
* @return True, if the parent is virtual
*/
bool is_virtual() const;
/**
* @brief Set the parents access scope
*
* @param access Parents access scope
*/
void set_access(common::model::access_t access);
/**
* @brief Get parents access scope.
*
* @return Parents access scope.
*/
common::model::access_t access() const;
private:

View File

@@ -29,11 +29,9 @@
namespace clanguml::class_diagram::model {
struct requires_expression {
common::model::template_parameter parameter;
std::vector<std::string> requirements;
};
/**
* @brief Model of C++ concept.
*/
class concept_ : public common::model::element,
public common::model::stylable_element,
public common::model::template_trait {
@@ -45,6 +43,11 @@ public:
concept_ &operator=(const concept_ &) = delete;
concept_ &operator=(concept_ &&) = delete;
/**
* @brief Get the elements type name.
*
* @return 'concept'
*/
std::string type_name() const override { return "concept"; }
friend bool operator==(const concept_ &l, const concept_ &r);
@@ -53,12 +56,35 @@ public:
std::string full_name_no_ns() const override;
/**
* @brief Add concept parameter
*
* Concept class for convenience uses the same method parameter model
* as regular methods and functions.
*
* @param mp Concept parameter
*/
void add_parameter(const method_parameter &mp);
/**
* @brief Get concepts requires expression parameters
*
* @return List of concept requires expression parameters
*/
const std::vector<method_parameter> &requires_parameters() const;
/**
* @brief Add a concept statement
*
* @param stmt Concept statement
*/
void add_statement(std::string stmt);
/**
* @brief Get the concepts requires statements
*
* @return List of concepts requires statements
*/
const std::vector<std::string> &requires_statements() const;
private:

View File

@@ -45,6 +45,9 @@ using nested_trait_ns =
clanguml::common::model::nested_trait<clanguml::common::model::element,
clanguml::common::model::namespace_>;
/**
* @brief Class representing a class diagram.
*/
class diagram : public common::model::diagram,
public element_view<class_>,
public element_view<enum_>,
@@ -58,36 +61,132 @@ public:
diagram &operator=(const diagram &) = delete;
diagram &operator=(diagram &&) = default;
/**
* @brief Get the diagram model type - in this case class.
*
* @return Type of class diagram.
*/
diagram_t type() const override;
/**
* Inherit the should_include methods from the common diagram model.
*/
using common::model::diagram::should_include;
/**
* @brief Whether a class_member should be included in the diagram.
*
* @param m Class member
* @return True, if class member should be included in the diagram.
*/
bool should_include(const class_member &m) const;
/**
* @brief Whether a class_method should be included in the diagram.
*
* @param m Class method
* @return True, if class method should be included in the diagram.
*/
bool should_include(const class_method &m) const;
/**
* @brief Search for element in the diagram by fully qualified name.
*
* @param full_name Fully qualified element name.
* @return Optional reference to a diagram element.
*/
opt_ref<diagram_element> get(const std::string &full_name) const override;
/**
* @brief Search for element in the diagram by id.
*
* @param id Element id.
* @return Optional reference to a diagram element.
*/
opt_ref<diagram_element> get(diagram_element::id_t id) const override;
/**
* @brief Get list of references to classes in the diagram model.
*
* @return List of references to classes in the diagram model.
*/
const common::reference_vector<class_> &classes() const;
/**
* @brief Get list of references to enums in the diagram model.
*
* @return List of references to enums in the diagram model.
*/
const common::reference_vector<enum_> &enums() const;
/**
* @brief Get list of references to concepts in the diagram model.
*
* @return List of references to concepts in the diagram model.
*/
const common::reference_vector<concept_> &concepts() const;
/**
* @brief Check, if diagram contains a specific element.
*
* @tparam ElementT Type of diagram element (e.g. class_)
* @param e Element to check
* @return True, if element already exists in the diagram
*/
template <typename ElementT> bool contains(const ElementT &e);
/**
* @brief Find an element in the diagram by name.
*
* This method allows for typed search, where the type of searched for
* element is determined from template specialization.
*
* @tparam ElementT Type of element (e.g. class_)
* @param name Fully qualified name of the element
* @return Optional reference to a diagram element
*/
template <typename ElementT>
opt_ref<ElementT> find(const std::string &name) const;
/**
* @brief Find elements in the diagram by regex pattern.
*
* This method allows for typed search, where the type of searched for
* element is determined from template specialization.
*
* @tparam ElementT Type of element (e.g. class_)
* @param name String or regex pattern
* @return List of optional references to matched elements.
*/
template <typename ElementT>
std::vector<opt_ref<ElementT>> find(
const clanguml::common::string_or_regex &pattern) const;
/**
* @brief Find an element in the diagram by id.
*
* This method allows for typed search, where the type of searched for
* element is determined from template specialization.
*
* @tparam ElementT Type of element (e.g. class_)
* @param id Id of the element
* @return Optional reference to a diagram element
*/
template <typename ElementT>
opt_ref<ElementT> find(diagram_element::id_t id) const;
/**
* @brief Add element to the diagram at a specified nested path.
*
* Adds an element to a diagram, at a specific package (if any exist).
* The package is specified by the `parent_path`, which can be either
* a namespace or a directory path.
*
* @tparam ElementT Type of diagram element.
* @param parent_path Path to the parent package of the new diagram element.
* @param e Diagram element to be added.
* @return True, if the element was added to the diagram.
*/
template <typename ElementT>
bool add(const path &parent_path, std::unique_ptr<ElementT> &&e)
{
@@ -98,14 +197,41 @@ public:
return add_with_filesystem_path(parent_path, std::move(e));
}
/**
* @brief Convert element id to PlantUML alias.
*
* @todo This method does not belong here - refactor to PlantUML specific
* code.
*
* @param id Id of the diagram element.
* @return PlantUML alias.
*/
std::string to_alias(diagram_element::id_t id) const;
/**
* @brief Given an initial set of classes, add all their parents to the
* argument.
* @param parents In and out parameter with the parent classes.
*/
void get_parents(clanguml::common::reference_set<class_> &parents) const;
friend void print_diagram_tree(const diagram &d, int level);
/**
* @brief Check if diagram contains element by id.
*
* @todo Remove in favour of 'contains'
*
* @param id Id of the element.
* @return True, if diagram contains an element with a specific id.
*/
bool has_element(diagram_element::id_t id) const override;
/**
* @brief Return the elements JSON context for inja templates.
*
* @return JSON node with elements context.
*/
inja::json context() const override;
private:

View File

@@ -24,6 +24,9 @@
namespace clanguml::class_diagram::model {
/*
* @brief Diagram element representing an enum.
*/
class enum_ : public common::model::element,
public common::model::stylable_element {
public:
@@ -36,15 +39,29 @@ public:
std::string type_name() const override { return "enum"; }
// TODO: Do we need this?
friend bool operator==(const enum_ &l, const enum_ &r);
std::string full_name(bool relative = true) const override;
/**
* @brief Get the enums constants.
*
* @return Enums constants names list.
*/
std::vector<std::string> &constants();
/**
* @brief Get the enums constants.
*
* @return Enums constants names list.
*/
const std::vector<std::string> &constants() const;
/**
* @brief Get Doxygen link to documentation page for this element.
*
* @return Doxygen link for this element.
*/
std::optional<std::string> doxygen_link() const override;
private:

View File

@@ -25,23 +25,73 @@
namespace clanguml::class_diagram::model {
/**
* @brief Model of a method parameter.
*/
class method_parameter : public common::model::decorated_element {
public:
method_parameter() = default;
/**
* @brief Constructor.
*
* @param type Type of the method parameter as string.
* @param name Name of the method parameter.
* @param default_value Default value of the parameter or empty.
*/
method_parameter(
std::string type, std::string name, std::string default_value = {});
~method_parameter() override = default;
/**
* @brief Set parameters type.
*
* @param type Parameters type as string.
*/
void set_type(const std::string &type);
/**
* @brief Get parameters type.
*
* @return Parameters type as string.
*/
std::string type() const;
/**
* @brief Set parameters name.
*
* @param type Parameters name.
*/
void set_name(const std::string &name);
/**
* @brief Get parameters name.
*
* @return Parameters name.
*/
std::string name() const;
/**
* @brief Set parameters default value.
*
* @param type Parameters default value as string.
*/
void set_default_value(const std::string &value);
/**
* @brief Get parameters name.
*
* @return Parameters name.
*/
std::string default_value() const;
/**
* @brief Render the method parameter to a string.
*
* @param using_namespaces If provided, make all namespaces relative to it.
* @return String representation of the parameter.
*/
std::string to_string(
const common::model::namespace_ &using_namespaces) const;

View File

@@ -235,7 +235,7 @@ std::unique_ptr<class_> template_builder::build(const clang::NamedDecl *cls,
auto templated_decl_id =
template_type.getTemplateName().getAsTemplateDecl()->getID();
auto templated_decl_local_id =
auto templated_decl_global_id =
id_mapper().get_global_id(templated_decl_id).value_or(0);
if (best_match_id > 0) {
@@ -246,12 +246,13 @@ std::unique_ptr<class_> template_builder::build(const clang::NamedDecl *cls,
}
// If we can't find optimal match for parent template specialization,
// just use whatever clang suggests
else if (diagram().has_element(templated_decl_local_id)) {
else if (diagram().has_element(templated_decl_global_id)) {
template_instantiation.add_relationship(
{relationship_t::kInstantiation, templated_decl_local_id});
{relationship_t::kInstantiation, templated_decl_global_id});
template_instantiation.template_specialization_found(true);
}
else if (diagram().should_include(full_template_specialization_name)) {
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);
}
@@ -351,7 +352,7 @@ template_builder::build_from_class_template_specialization(
{relationship_t::kInstantiation, templated_decl_local_id});
template_instantiation.template_specialization_found(true);
}
else if (diagram().should_include(qualified_name)) {
else if (diagram().should_include(namespace_{qualified_name})) {
LOG_DBG("Skipping instantiation relationship from {} to {}",
template_instantiation_ptr->full_name(false), templated_decl_id);
}
@@ -380,7 +381,7 @@ void template_builder::process_template_arguments(
// default values, and add them when they are specifically
// overridden
if (!diagram().should_include(
template_decl->getQualifiedNameAsString())) {
namespace_{template_decl->getQualifiedNameAsString()})) {
const auto *maybe_type_parm_decl =
clang::dyn_cast<clang::TemplateTypeParmDecl>(
template_decl->getTemplateParameters()->getParam(
@@ -1012,7 +1013,8 @@ template_builder::try_as_template_specialization_type(
argument.set_type(nested_type_name);
auto nested_template_instantiation = build(cls, *nested_template_type,
diagram().should_include(template_decl->getQualifiedNameAsString())
diagram().should_include(
namespace_{template_decl->getQualifiedNameAsString()})
? std::make_optional(&template_instantiation)
: parent);
@@ -1031,9 +1033,10 @@ template_builder::try_as_template_specialization_type(
nested_template_instantiation->full_name(false);
if (nested_template_instantiation &&
diagram().should_include(nested_template_instantiation_full_name)) {
diagram().should_include(
namespace_{nested_template_instantiation_full_name})) {
if (diagram().should_include(
template_decl->getQualifiedNameAsString())) {
namespace_{template_decl->getQualifiedNameAsString()})) {
template_instantiation.add_relationship(
{relationship_t::kDependency,
nested_template_instantiation->id()});
@@ -1045,7 +1048,8 @@ template_builder::try_as_template_specialization_type(
}
}
if (diagram().should_include(nested_template_instantiation_full_name)) {
if (diagram().should_include(
namespace_{nested_template_instantiation_full_name})) {
visitor_.set_source_location(
*template_decl, *nested_template_instantiation);
visitor_.add_class(std::move(nested_template_instantiation));
@@ -1155,7 +1159,7 @@ std::optional<template_parameter> template_builder::try_as_record_type(
template_instantiation.add_relationship(std::move(r));
}
if (diagram().should_include(tag_argument->full_name(false))) {
if (diagram().should_include(tag_argument->get_namespace())) {
if (parent.has_value())
parent.value()->add_relationship(
{relationship_t::kDependency, tag_argument->id()});
@@ -1166,7 +1170,7 @@ std::optional<template_parameter> template_builder::try_as_record_type(
}
else if (const auto *record_type_decl = record_type->getAsRecordDecl();
record_type_decl != nullptr) {
if (diagram().should_include(type_name)) {
if (diagram().should_include(namespace_{type_name})) {
// Add dependency relationship to the parent
// template
template_instantiation.add_relationship(

View File

@@ -36,35 +36,111 @@ using found_relationships_t =
class translation_unit_visitor;
/**
* @brief Class responsible for building all kinds of templates from Clang AST.
*/
class template_builder {
public:
/**
* @brief Constructor.
*
* @param visitor Reference to class diagram translation_unit_visitor
*/
template_builder(
clanguml::class_diagram::visitor::translation_unit_visitor &visitor);
/**
* @brief Get reference to the current diagram model
*
* @return Reference to the current diagram model
*/
class_diagram::model::diagram &diagram();
/**
* @brief Get reference to the current diagram configuration
*
* @return Reference to the current diagram configuration
*/
const config::class_diagram &config() const;
/**
* @brief Get diagram relative namespace
*
* @return Diagram relative namespace
*/
const namespace_ &using_namespace() const;
/**
* @brief Simplify system templates
*
* This method tries to simplify all fully qualified template names
* in the `full_name` using substitutions from the configuration file
* ().
*
* Typical example is replace every `std::basic_string<char>` with
* `std::string`.
*
* @param ct Template parameter
* @param full_name Full template name
* @return
*/
bool simplify_system_template(
template_parameter &ct, const std::string &full_name) const;
/**
* @brief Basic template class build method
*
* @param cls Clang template declaration
* @param template_type_decl Template specialization type
* @param parent Optional class in which this template is contained
* @return Created template class model
*/
std::unique_ptr<clanguml::class_diagram::model::class_> build(
const clang::NamedDecl *cls,
const clang::TemplateSpecializationType &template_type_decl,
std::optional<clanguml::class_diagram::model::class_ *> parent = {});
/**
* @brief Build template class from class template specialization decl
*
* @param template_specialization Class template specialization declaration
* @param parent Optional class in which this template is contained
* @return Created template class model
*/
std::unique_ptr<clanguml::class_diagram::model::class_>
build_from_class_template_specialization(
const clang::ClassTemplateSpecializationDecl &template_specialization,
std::optional<clanguml::class_diagram::model::class_ *> parent = {});
/**
* @brief Add base classes to the template class, if any.
*
* This method adds base classes to a template declaration or
* specialization, including inferring whether variadic template
* parameter bases.
*
* @param tinst Class template model
* @param template_base_params List of base class template parameters
* @param arg_index Index of the template argument used for base class
* @param variadic_params Whether the parameter is variadic
* @param ct Template parameter model
* @return True, if any base classes were added
*/
bool add_base_classes(clanguml::class_diagram::model::class_ &tinst,
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
int arg_index, bool variadic_params,
const clanguml::common::model::template_parameter &ct);
/**
* @brief Process template class parameters and arguments
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_base_params List of base class template parameters
* @param template_args List of template arguments
* @param template_instantiation Template class model to add template args
* @param template_decl Base template declaration
*/
void process_template_arguments(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls,
@@ -73,6 +149,18 @@ public:
model::class_ &template_instantiation,
const clang::TemplateDecl *template_decl);
/**
* @brief Process template arguments based on their type
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_instantiation Template class model to add template args
* @param template_decl Base template declaration
* @param arg Template argument
* @param argument_index Argument index
* @param argument Output list of arguments (can be more than one for
* variadic parameters)
*/
void argument_process_dispatch(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, class_ &template_instantiation,
@@ -80,18 +168,64 @@ public:
const clang::TemplateArgument &arg, size_t argument_index,
std::vector<template_parameter> &argument);
/**
* @brief Process `clang::TemplateArgument::Expression`
*
* @note The template argument is a pack expansion of a template name that
* was provided for a template template parameter.
*
* @param arg Template argument
* @return Return template argument model
*/
template_parameter process_expression_argument(
const clang::TemplateArgument &arg);
/**
* @brief Process `clang::TemplateArgument::Integral`
*
* @note The template argument is an integral value stored in an
* llvm::APSInt that was provided for an integral non-type template
* parameter.
*
* @param arg Template argument
* @return Return template argument model
*/
template_parameter process_integral_argument(
const clang::TemplateArgument &arg);
/**
* @brief Process `clang::TemplateArgument::NullPtr`
*
* @note The template argument is a null pointer or null pointer to member
* that was provided for a non-type template parameter.
*
* @param arg Template argument
* @return Return template argument model
*/
template_parameter process_nullptr_argument(
const clang::TemplateArgument &arg);
/**
* @brief Process `clang::TemplateArgument::Null`
*
* @note Represents an empty template argument, e.g., one that has not
* been deduced.
*
* @param arg Template argument
* @return Return template argument model
*/
template_parameter process_null_argument(
const clang::TemplateArgument &arg);
/**
* @brief Process `clang::TemplateArgument::Pack`
*
* @note The template argument is actually a parameter pack. Arguments are
* stored in the Args struct.
*
* @param arg Template argument
* @return Return template argument model
*/
std::vector<template_parameter> process_pack_argument(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, class_ &template_instantiation,
@@ -99,85 +233,260 @@ public:
const clang::TemplateArgument &arg, size_t argument_index,
std::vector<template_parameter> &argument);
/**
* @brief Process `clang::TemplateArgument::Type`
*
* @note The template argument is a type.
*
* @param arg Template argument
* @return Return template argument model
*/
template_parameter process_type_argument(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls,
const clang::TemplateDecl *base_template_decl, clang::QualType type,
model::class_ &template_instantiation, size_t argument_index);
/**
* @brief Process `clang::TemplateArgument::Template`
*
* @note The template argument is a template name that was provided for a
* template template parameter.
*
* @param arg Template argument
* @return Return template argument model
*/
common::model::template_parameter process_template_argument(
const clang::TemplateArgument &arg);
/**
* @brief Process `clang::TemplateArgument::TemplateExpansion`
*
* @note The template argument is a pack expansion of a template name that
* was provided for a template template parameter.
*
* @param arg Template argument
* @return Return template argument model
*/
common::model::template_parameter process_template_expansion(
const clang::TemplateArgument &arg);
/**
* @brief Try to process template type argument as function template
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @param template_instantiation Template class model
* @param argument_index Argument index
* @return Function template argument if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_function_prototype(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index);
/**
* @brief Try to process template type argument as array
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @param template_instantiation Template class model
* @param argument_index Argument index
* @return Array template argument if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_array(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index);
/**
* @brief Try to process template type argument as specialization type
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @param template_instantiation Template class model
* @param argument_index Argument index
* @return Template specialization template argument if succeeds,
* or std::nullopt
*/
std::optional<template_parameter> try_as_template_specialization_type(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index);
/**
* @brief Try to process template type argument as template parameter
*
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @return Template parameter if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_template_parm_type(
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type);
/**
* @brief Try to process template type argument as lambda
*
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @return Lambda template argument if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_lambda(const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl, clang::QualType &type);
/**
* @brief Try to process template type argument as record type
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @param template_instantiation Template class model
* @param argument_index Argument index
* @return Record type template argument if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_record_type(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index);
/**
* @brief Try to process template type argument as enum type
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @param template_instantiation Template class model
* @return Enum type template argument if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_enum_type(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation);
/**
* @brief Try to process template type argument as builtin type
*
* @param parent Optional class in which this template is contained
* @param type Template type
* @param template_decl Base template declaration
* @return Builtin type template argument if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_builtin_type(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
clang::QualType &type, const clang::TemplateDecl *template_decl);
/**
* @brief Try to process template type argument as member pointer type
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @param template_instantiation Template class model
* @param argument_index Argument index
* @return Member pointer type template argument if succeeds,
* or std::nullopt
*/
std::optional<template_parameter> try_as_member_pointer(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index);
/**
* @brief Try to process template type argument as `decltype()` type
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @param template_instantiation Template class model
* @param argument_index Argument index
* @return `decltype()` type template argument if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_decl_type(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index);
/**
* @brief Try to process template type argument as typedef/using type
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @param template_instantiation Template class model
* @param argument_index Argument index
* @return Typedef type template argument if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_typedef_type(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index);
/**
* @brief Remove types context (e.g. const or reference qualifiers)
*
* This method removes all const and reference/pointer qualifiers from
* `type`, adds them to the template parameter model `tp` and returns
* a type without context.
*
* @param type Type to remove context from
* @param tp Template model to add context to
* @return Type without context
*/
clang::QualType consume_context(
clang::QualType type, template_parameter &tp) const;
/**
* @brief Try to find additional relationships in unexposed parameters
*
* Sometimes, Clang will report a template parameter as unexposed, which
* means all we get a is a string representation of the type, sometimes
* with template parameter names replaced with `type-parameter-X-Y`
* string.
*
* This method tries to find any type names, which might be relevant for
* the diagram relationships.
*
* @param ct Template argument model
* @param relationships List of discovered relationships
* @return True, if any relationships were found
*/
bool find_relationships_in_unexposed_template_params(
const template_parameter &ct,
class_diagram::visitor::found_relationships_t &relationships);
/**
* @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();
/**
* @brief Get reference to the current source manager
*
* @return Reference to the current source manager
*/
clang::SourceManager &source_manager() const;
private:

View File

@@ -100,7 +100,7 @@ bool translation_unit_visitor::VisitEnumDecl(clang::EnumDecl *enm)
if (enm->getNameAsString().empty())
return true;
if (!diagram().should_include(enm->getQualifiedNameAsString()))
if (!should_include(enm))
return true;
LOG_DBG("= Visiting enum declaration {} at {}",
@@ -169,7 +169,6 @@ bool translation_unit_visitor::VisitEnumDecl(clang::EnumDecl *enm)
e.constants().push_back(ev->getNameAsString());
}
if (diagram().should_include(qualified_name))
add_enum(std::move(e_ptr));
return true;
@@ -178,10 +177,7 @@ bool translation_unit_visitor::VisitEnumDecl(clang::EnumDecl *enm)
bool translation_unit_visitor::VisitClassTemplateSpecializationDecl(
clang::ClassTemplateSpecializationDecl *cls)
{
if (source_manager().isInSystemHeader(cls->getSourceRange().getBegin()))
return true;
if (!diagram().should_include(cls->getQualifiedNameAsString()))
if (!should_include(cls))
return true;
LOG_DBG("= Visiting template specialization declaration {} at {} "
@@ -241,10 +237,7 @@ bool translation_unit_visitor::VisitClassTemplateSpecializationDecl(
bool translation_unit_visitor::VisitTypeAliasTemplateDecl(
clang::TypeAliasTemplateDecl *cls)
{
if (source_manager().isInSystemHeader(cls->getSourceRange().getBegin()))
return true;
if (!diagram().should_include(cls->getQualifiedNameAsString()))
if (!should_include(cls))
return true;
LOG_DBG("= Visiting template type alias declaration {} at {}",
@@ -280,10 +273,7 @@ bool translation_unit_visitor::VisitTypeAliasTemplateDecl(
bool translation_unit_visitor::VisitClassTemplateDecl(
clang::ClassTemplateDecl *cls)
{
if (source_manager().isInSystemHeader(cls->getSourceRange().getBegin()))
return true;
if (!diagram().should_include(cls->getQualifiedNameAsString()))
if (!should_include(cls))
return true;
LOG_DBG("= Visiting class template declaration {} at {}",
@@ -339,16 +329,12 @@ bool translation_unit_visitor::VisitClassTemplateDecl(
bool translation_unit_visitor::VisitRecordDecl(clang::RecordDecl *rec)
{
// Skip system headers
if (source_manager().isInSystemHeader(rec->getSourceRange().getBegin()))
return true;
if (clang::dyn_cast_or_null<clang::CXXRecordDecl>(rec) != nullptr)
// This is handled by VisitCXXRecordDecl()
return true;
// It seems we are in a C (not C++) translation unit
if (!diagram().should_include(rec->getQualifiedNameAsString()))
if (!should_include(rec))
return true;
LOG_DBG("= Visiting record declaration {} at {}",
@@ -396,11 +382,7 @@ bool translation_unit_visitor::VisitRecordDecl(clang::RecordDecl *rec)
bool translation_unit_visitor::TraverseConceptDecl(clang::ConceptDecl *cpt)
{
// Skip system headers
if (source_manager().isInSystemHeader(cpt->getSourceRange().getBegin()))
return true;
if (!diagram().should_include(cpt->getQualifiedNameAsString()))
if (!should_include(cpt))
return true;
LOG_DBG("= Visiting concept (isType: {}) declaration {} at {}",
@@ -1314,7 +1296,7 @@ void translation_unit_visitor::process_method(
*unaliased_type, &c);
if (diagram().should_include(
template_specialization_ptr->full_name(false))) {
template_specialization_ptr->get_namespace())) {
relationships.emplace_back(template_specialization_ptr->id(),
relationship_t::kDependency);
@@ -1686,7 +1668,7 @@ void translation_unit_visitor::process_function_parameter(
templ->getTemplateName().getAsTemplateDecl(), *templ, &c);
if (diagram().should_include(
template_specialization_ptr->full_name(false))) {
template_specialization_ptr->get_namespace())) {
relationships.emplace_back(template_specialization_ptr->id(),
relationship_t::kDependency);
@@ -1956,7 +1938,7 @@ void translation_unit_visitor::process_field(
// it's a std::vector<>, it's nested types might be added
bool add_template_instantiation_to_diagram{false};
if (diagram().should_include(
template_specialization.full_name(false))) {
template_specialization.get_namespace())) {
found_relationships_t::value_type r{
template_specialization.id(), relationship_hint};
@@ -2034,7 +2016,7 @@ void translation_unit_visitor::process_field(
void translation_unit_visitor::add_incomplete_forward_declarations()
{
for (auto &[id, c] : forward_declarations_) {
if (diagram().should_include(c->full_name(false))) {
if (diagram().should_include(c->get_namespace())) {
add_class(std::move(c));
}
}
@@ -2107,8 +2089,21 @@ void translation_unit_visitor::extract_constrained_template_param_name(
bool translation_unit_visitor::should_include(const clang::NamedDecl *decl)
{
return decl != nullptr &&
diagram().should_include(decl->getQualifiedNameAsString());
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(

View File

@@ -64,10 +64,21 @@ class translation_unit_visitor
: public clang::RecursiveASTVisitor<translation_unit_visitor>,
public common::visitor::translation_unit_visitor {
public:
/**
* @brief Constructor.
*
* @param sm Current source manager reference
* @param diagram Diagram model
* @param config Diagram configuration
*/
explicit translation_unit_visitor(clang::SourceManager &sm,
clanguml::class_diagram::model::diagram &diagram,
const clanguml::config::class_diagram &config);
/**
* \defgroup Implementation of ResursiveASTVisitor methods
* @{
*/
bool shouldVisitTemplateInstantiations() const { return false; }
bool shouldVisitImplicitCode() const { return false; }
@@ -89,6 +100,7 @@ public:
virtual bool VisitTypeAliasTemplateDecl(clang::TypeAliasTemplateDecl *cls);
virtual bool TraverseConceptDecl(clang::ConceptDecl *cpt);
/** @} */
/**
* @brief Get diagram model reference
@@ -97,6 +109,11 @@ public:
*/
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_;
@@ -119,112 +136,335 @@ 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.
*
* @param c Class model
*/
void add_class(std::unique_ptr<class_> &&c);
/**
* @brief Add enum to the diagram.
*
* @param e Enum model
*/
void add_enum(std::unique_ptr<enum_> &&e);
/**
* @brief Add concept to the diagram.
*
* @param c Concept model
*/
void add_concept(std::unique_ptr<concept_> &&c);
void ensure_lambda_type_is_relative(std::string &parameter_type) const;
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);
/**
* @brief Create class element model from class declaration
*
* @param cls Class declaration
* @return Class diagram element model
*/
std::unique_ptr<clanguml::class_diagram::model::class_>
create_class_declaration(clang::CXXRecordDecl *cls);
/**
* @brief Create class element model from record (e.g. struct) declaration
*
* @param rec Record declaration
* @return Class diagram element model
*/
std::unique_ptr<clanguml::class_diagram::model::class_>
create_record_declaration(clang::RecordDecl *rec);
/**
* @brief Create concept element model from concept declaration
* @param cpt Concept declaration
* @return Concept diagram element model
*/
std::unique_ptr<clanguml::class_diagram::model::concept_>
create_concept_declaration(clang::ConceptDecl *cpt);
/**
* @brief Process class declaration
*
* @param cls Class declaration
* @param c Class diagram element return from `create_class_declaration`
*/
void process_class_declaration(const clang::CXXRecordDecl &cls,
clanguml::class_diagram::model::class_ &c);
/**
* @brief Process class declaration bases (parents), if any
*
* @param cls Class declaration
* @param c Class diagram element model
*/
void process_class_bases(const clang::CXXRecordDecl *cls,
clanguml::class_diagram::model::class_ &c);
/**
* @brief Process class children elements (members and methods)
*
* @param cls Class declaration
* @param c Class diagram element model
*/
void process_class_children(const clang::CXXRecordDecl *cls,
clanguml::class_diagram::model::class_ &c);
/**
* @brief Process class or record data members
* @param cls Class declaration
* @param c Class diagram element model
*/
void process_record_members(const clang::RecordDecl *cls, class_ &c);
/**
* @brief Process class template specialization/instantiation
*
* @param cls Class template specialization declaration
* @return Class diagram element model
*/
std::unique_ptr<clanguml::class_diagram::model::class_>
process_template_specialization(
clang::ClassTemplateSpecializationDecl *cls);
/**
* @brief Process template specialiaztion children (members and methods)
* @param cls Class template specialization declaration
* @param c Class diagram element model
*/
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
*
* @param mf Method declaration
* @param c Class diagram element model
*/
void process_method(const clang::CXXMethodDecl &mf,
clanguml::class_diagram::model::class_ &c);
/**
* @brief Process class method properties
* @param mf Method declaration
* @param c Class diagram element model
* @param method_name Method name
* @param method Method model
*/
void process_method_properties(const clang::CXXMethodDecl &mf,
const class_ &c, const std::string &method_name,
class_method &method) const;
/**
* @brief Process class template method
*
* @param mf Method declaration
* @param c Class diagram element model
*/
void process_template_method(const clang::FunctionTemplateDecl &mf,
clanguml::class_diagram::model::class_ &c);
/**
* @brief Process class static data member
*
* @param field_declaration Static data member declaration
* @param c Class diagram element model
*/
void process_static_field(const clang::VarDecl &field_declaration,
clanguml::class_diagram::model::class_ &c);
/**
* @brief Process class data member
*
* @param field_declaration Data member declaration
* @param c Class diagram element model
*/
void process_field(const clang::FieldDecl &field_declaration,
clanguml::class_diagram::model::class_ &c);
/**
* @brief Process function/method parameter
*
* @param param Parameter declaration
* @param method Class method model
* @param c Class diagram element model
* @param template_parameter_names Ignored
*/
void process_function_parameter(const clang::ParmVarDecl &param,
clanguml::class_diagram::model::class_method &method,
clanguml::class_diagram::model::class_ &c,
const std::set<std::string> &template_parameter_names = {});
/**
* @brief Process class friend
*
* @param f Friend declaration
* @param c Class diagram element model
*/
void process_friend(
const clang::FriendDecl &f, clanguml::class_diagram::model::class_ &c);
/**
* @brief Find relationships in a specific type
*
* @param type Type to search for relationships
* @param relationship_hint Default relationship type to infer from this
* type
* @return True, if any relationships were found
*/
bool find_relationships(const clang::QualType &type,
found_relationships_t & /*relationships*/,
clanguml::common::model::relationship_t relationship_hint);
/**
* @brief Add relationships from relationship list to a class model
*
* This method takes a list of relationships whose originating element
* is class `c` and adds them to it, ignoring any duplicates and skipping
* relationships that should be excluded from the diagram.
*
* @param c Class diagram element model
* @param field Class member model
* @param relationships List of found relationships
* @param break_on_first_aggregation Stop adding relatinoships, after first
* aggregation is found
*/
void add_relationships(clanguml::class_diagram::model::class_ &c,
const clanguml::class_diagram::model::class_member &field,
const found_relationships_t &relationships,
bool break_on_first_aggregation = false);
/**
* @brief Process record parent element (e.g. for nested classes)
*
* This method handles nested classes or structs.
*
* @param cls Record declaration
* @param c Class diagram element model
* @param ns Package in the diagram to which the class `c` should belong
*/
void process_record_parent(
clang::RecordDecl *cls, class_ &c, const namespace_ &ns);
/**
* @brief Find relationships in function parameter
*
* @param c Class diagram element model
* @param atsp `auto` type
*/
void process_function_parameter_find_relationships_in_autotype(
model::class_ &c, const clang::AutoType *atsp);
/**
* @brief Find relationships in concept constraint expression
*
* @param c Diagram element model (concept)
* @param expr Concept constraint expression
*/
void find_relationships_in_constraint_expression(
clanguml::common::model::element &c, const clang::Expr *expr);
/**
* @brief Register incomplete forward declaration to be updated later
*/
void add_incomplete_forward_declarations();
/**
* @brief Replace any AST local ids in diagram elements with global ones
*
* Not all elements global ids can be set in relationships during
* traversal of the AST. In such cases, a local id (obtained from `getID()`)
* and at after the traversal is complete, the id is replaced with the
* global diagram id.
*/
void resolve_local_to_global_ids();
/**
* @brief Process concept constraint requirements
*
* @param cpt Concept declaration
* @param expr Requires expression
* @param concept_model Concept diagram element model
*/
void process_constraint_requirements(const clang::ConceptDecl *cpt,
const clang::Expr *expr, model::concept_ &concept_model) const;
/**
* @brief Find concept specializations relationships
*
* @param c Concept element model
* @param concept_specialization Concept specialization expression
*/
void process_concept_specialization_relationships(common::model::element &c,
const clang::ConceptSpecializationExpr *concept_specialization);
/**
* @brief Extract template contraint parameter name from raw source code
*
* @param concept_specialization Concept specialization expression
* @param cpt Concept declaration
* @param constrained_template_params Found constraint template param names
* @param argument_index Argument index
* @param type_name Type parameter name - used if extraction fails
*/
void extract_constrained_template_param_name(
const clang::ConceptSpecializationExpr *concept_specialization,
const clang::ConceptDecl *cpt,
std::vector<std::string> &constrained_template_params,
size_t argument_index, std::string &type_name) const;
/// Store the mapping from local clang entity id (obtained using
/// getID()) method to clang-uml global id
void set_ast_local_id(
int64_t local_id, common::model::diagram_element::id_t global_id);
/**
* @brief Register already processed template class name
*
* @param qualified_name Fully qualified template class name
*/
void add_processed_template_class(std::string qualified_name);
/**
* @brief Check if template class has already been processed
*
* @param qualified_name Fully qualified template class name
* @return True, if template class has already been processed
*/
bool has_processed_template_class(const std::string &qualified_name) const;
/**
* @brief Get template builder reference
*
* @return Reference to 'template_builder' instance
*/
template_builder &tbuilder() { return template_builder_; }
// Reference to the output diagram model
@@ -246,13 +486,13 @@ private:
common::model::access_t>>
anonymous_struct_relationships_;
// When visiting CXX records we need to know if they have already been
// process in VisitClassTemplateDecl or VisitClassTemplateSpecializationDecl
// If yes, then we need to skip it
// TODO: There must be a better way to do this...
/**
* When visiting CXX records we need to know if they have already been
* process in VisitClassTemplateDecl or
* VisitClassTemplateSpecializationDecl. If yes, then we need to skip it
*
* @todo There must be a better way to do this...
*/
std::set<std::string> processed_template_qualified_names_;
void process_method_properties(const clang::CXXMethodDecl &mf,
const class_ &c, const std::string &method_name,
class_method &method) const;
};
} // namespace clanguml::class_diagram::visitor

View File

@@ -137,6 +137,8 @@ public:
bool should_include(relationship r) const;
bool should_include(relationship_t r) const;
bool should_include(access_t s) const;
// Disallow std::string overload
bool should_include(const std::string &s) const = delete;
virtual bool has_element(const diagram_element::id_t /*id*/) const
{

View File

@@ -553,8 +553,9 @@ bool translation_unit_visitor::find_relationships(const clang::QualType &type,
clang::cast<clang::NamespaceDecl>(namespace_context);
if (namespace_declaration != nullptr &&
diagram().should_include(common::get_qualified_name(
*namespace_declaration))) {
diagram().should_include(
namespace_{common::get_qualified_name(
*namespace_declaration)})) {
const auto target_id = get_package_id(cxxrecord_decl);
relationships.emplace_back(
target_id, relationship_hint);
@@ -563,8 +564,9 @@ bool translation_unit_visitor::find_relationships(const clang::QualType &type,
}
}
else {
if (diagram().should_include(common::get_qualified_name(
*type->getAsCXXRecordDecl()))) {
if (diagram().should_include(
namespace_{common::get_qualified_name(
*type->getAsCXXRecordDecl())})) {
const auto target_id =
get_package_id(type->getAsCXXRecordDecl());
relationships.emplace_back(target_id, relationship_hint);
@@ -578,7 +580,7 @@ bool translation_unit_visitor::find_relationships(const clang::QualType &type,
// need to consider namespaces here
if (config().package_type() == config::package_type_t::kDirectory) {
if (diagram().should_include(
common::get_qualified_name(*record_decl))) {
namespace_{common::get_qualified_name(*record_decl)})) {
const auto target_id = get_package_id(record_decl);
relationships.emplace_back(target_id, relationship_hint);
result = true;

View File

@@ -1222,18 +1222,15 @@ translation_unit_visitor::create_class_model(clang::CXXRecordDecl *cls)
config().using_namespace())};
auto &c = *c_ptr;
// TODO: refactor to method get_qualified_name()
auto qualified_name =
cls->getQualifiedNameAsString(); // common::get_qualified_name(*cls);
auto qualified_name = cls->getQualifiedNameAsString();
if (!cls->isLambda())
if (!diagram().should_include(qualified_name))
if (!should_include(cls))
return {};
auto ns = common::get_tag_namespace(*cls);
if (cls->isLambda() &&
!diagram().should_include(ns.to_string() + "::lambda"))
if (cls->isLambda() && !diagram().should_include(ns | "lambda"))
return {};
const auto *parent = cls->getParent();
@@ -2202,7 +2199,8 @@ bool translation_unit_visitor::should_include(const clang::TagDecl *decl) const
const auto decl_file = decl->getLocation().printToString(source_manager());
return diagram().should_include(decl->getQualifiedNameAsString()) &&
return diagram().should_include(
namespace_{decl->getQualifiedNameAsString()}) &&
diagram().should_include(common::model::source_file{decl_file});
}
@@ -2255,7 +2253,8 @@ bool translation_unit_visitor::should_include(
{
const auto decl_file = decl->getLocation().printToString(source_manager());
return diagram().should_include(decl->getQualifiedNameAsString()) &&
return diagram().should_include(
namespace_{decl->getQualifiedNameAsString()}) &&
diagram().should_include(common::model::source_file{decl_file});
}
@@ -2273,7 +2272,8 @@ bool translation_unit_visitor::should_include(
const auto decl_file = decl->getLocation().printToString(source_manager());
return diagram().should_include(decl->getQualifiedNameAsString()) &&
return diagram().should_include(
namespace_{decl->getQualifiedNameAsString()}) &&
diagram().should_include(common::model::source_file{decl_file});
}
} // namespace clanguml::sequence_diagram::visitor

View File

@@ -30,6 +30,7 @@
namespace clanguml::sequence_diagram::visitor {
using common::model::namespace_;
using common::model::template_parameter;
std::string to_string(const clang::FunctionTemplateDecl *decl);

View File

@@ -31,7 +31,6 @@ TEST_CASE("t00003", "[test-case][class]")
auto model = generate_class_diagram(*db, diagram);
REQUIRE(model->name() == "t00003_class");
REQUIRE(model->should_include(std::string("clanguml::t00003::A")));
{
auto puml = generate_class_puml(diagram, *model);