Added constrained template parameter names in requires relationship

This commit is contained in:
Bartek Kryza
2023-02-25 19:35:18 +01:00
parent 274a698713
commit 1fc0bf3f80
7 changed files with 139 additions and 43 deletions

View File

@@ -107,10 +107,10 @@ void generator::generate_alias(const concept_ &c, std::ostream &ostr) const
print_debug(c, ostr); print_debug(c, ostr);
if (m_config.generate_packages()) if (m_config.generate_packages())
ostr << "annotation" ostr << "class"
<< " \"" << c.name(); << " \"" << c.name();
else else
ostr << "annotation" ostr << "class"
<< " \"" << render_name(c.full_name()); << " \"" << render_name(c.full_name());
ostr << "\" as " << c.alias() << '\n'; ostr << "\" as " << c.alias() << '\n';
@@ -300,7 +300,7 @@ void generator::generate(const concept_ &c, std::ostream &ostr) const
{ {
namespace plantuml_common = clanguml::common::generators::plantuml; namespace plantuml_common = clanguml::common::generators::plantuml;
std::string class_type{"annotation"}; std::string class_type{"class"};
ostr << class_type << " " << c.alias() << " <<concept>>"; ostr << class_type << " " << c.alias() << " <<concept>>";

View File

@@ -415,8 +415,6 @@ bool translation_unit_visitor::TraverseConceptDecl(clang::ConceptDecl *cpt)
// process 'requires (...)' declaration // process 'requires (...)' declaration
for (const auto *decl : constraint->getBody()->decls()) { for (const auto *decl : constraint->getBody()->decls()) {
// decl->dump();
if (const auto *parm_var_decl = if (const auto *parm_var_decl =
clang::dyn_cast<clang::ParmVarDecl>(decl); clang::dyn_cast<clang::ParmVarDecl>(decl);
parm_var_decl) { parm_var_decl) {
@@ -491,38 +489,92 @@ void translation_unit_visitor::find_relationships_in_constraint_expression(
if (expr == nullptr) if (expr == nullptr)
return; return;
if (const auto *concept_specialization = common::if_dyn_cast<clang::ConceptSpecializationExpr>(
clang::dyn_cast<clang::ConceptSpecializationExpr>(expr); expr, [&](const auto *cs) {
concept_specialization) { process_concept_specialization_relationships(c, cs);
if (concept_specialization->getNamedConcept() && });
diagram().should_include(concept_specialization->getNamedConcept()
->getQualifiedNameAsString())) {
auto target_id = get_ast_local_id(
concept_specialization->getNamedConcept()->getID())
.value();
for (const auto ta : common::if_dyn_cast<clang::RequiresExpr>(expr, [&](const auto *re) {
concept_specialization->getTemplateArguments()) {
if (ta.getKind() == clang::TemplateArgument::Template)
ta.getAsTemplateOrTemplatePattern().dump();
}
c.add_relationship({relationship_t::kDependency, target_id});
}
}
else if (const auto *constraint =
clang::dyn_cast<clang::RequiresExpr>(expr);
constraint) {
// TODO // TODO
} });
else if (const auto *binop = clang::dyn_cast<clang::BinaryOperator>(expr);
binop) { common::if_dyn_cast<clang::BinaryOperator>(expr, [&](const auto *op) {
find_relationships_in_constraint_expression(c, binop->getLHS()); find_relationships_in_constraint_expression(c, op->getLHS());
find_relationships_in_constraint_expression(c, binop->getRHS()); find_relationships_in_constraint_expression(c, op->getRHS());
} });
else if (const auto *unop = clang::dyn_cast<clang::UnaryOperator>(expr);
unop) { common::if_dyn_cast<clang::UnaryOperator>(expr, [&](const auto *op) {
find_relationships_in_constraint_expression(c, unop->getSubExpr()); find_relationships_in_constraint_expression(c, op->getSubExpr());
});
}
void translation_unit_visitor::process_concept_specialization_relationships(
common::model::element &c,
const clang::ConceptSpecializationExpr *concept_specialization)
{
const auto *cpt = concept_specialization->getNamedConcept();
if (cpt && diagram().should_include(cpt->getQualifiedNameAsString())) {
auto target_id = get_ast_local_id(cpt->getID()).value();
std::vector<std::string> constrained_template_params;
size_t argument_index{};
for (const auto ta : concept_specialization->getTemplateArguments()) {
if (ta.getKind() == clang::TemplateArgument::Type) {
auto type_name =
common::to_string(ta.getAsType(), cpt->getASTContext());
if (const auto *nested_template_type =
ta.getAsType()->getAs<clang::TemplateTypeParmType>();
nested_template_type != nullptr) {
auto declaration_text = common::get_source_text_raw(
concept_specialization->getSourceRange(),
source_manager());
if (!declaration_text.empty()) {
// Handle typename constraint in requires clause
if (type_name.find("type-parameter-") == 0) {
declaration_text = declaration_text.substr(
declaration_text.find(cpt->getNameAsString()) +
cpt->getNameAsString().size() + 1);
auto template_params =
common::parse_unexposed_template_params(
declaration_text,
[](const auto &t) { return t; });
if (template_params.size() > argument_index)
type_name =
template_params[argument_index].to_string(
config().using_namespace(), false);
else {
LOG_DBG("Failed to find type specialization "
"for argument "
"{} at index {} in declaration "
"\n===\n{}\n===\n",
type_name, argument_index,
declaration_text);
}
}
constrained_template_params.push_back(type_name);
}
}
}
else {
auto type_name =
common::to_string(ta.getAsType(), cpt->getASTContext());
LOG_DBG(
"=== Unsupported concept type parameter: {}", type_name);
}
argument_index++;
}
if (!constrained_template_params.empty())
c.add_relationship(
{relationship_t::kDependency, target_id, access_t::kNone,
fmt::format(
"{}", fmt::join(constrained_template_params, ","))});
} }
} }
@@ -817,9 +869,19 @@ bool translation_unit_visitor::process_template_parameters(
util::apply_if_not_null( util::apply_if_not_null(
template_type_parameter->getTypeConstraint() template_type_parameter->getTypeConstraint()
->getNamedConcept(), ->getNamedConcept(),
[&ct](const clang::ConceptDecl *named_concept) mutable { [this, &ct, &templated_element](
const clang::ConceptDecl *named_concept) mutable {
ct.set_concept_constraint( ct.set_concept_constraint(
named_concept->getQualifiedNameAsString()); named_concept->getQualifiedNameAsString());
if (templated_element &&
diagram().should_include(
named_concept->getQualifiedNameAsString())) {
templated_element.value().add_relationship(
{relationship_t::kDependency,
get_ast_local_id(named_concept->getID())
.value(),
access_t::kNone, ct.name()});
}
}); });
} }
@@ -867,7 +929,7 @@ void translation_unit_visitor::process_template_record_containment(
{ {
assert(record.getParent()->isRecord()); assert(record.getParent()->isRecord());
const auto *parent = record.getParent(); //->getOuterLexicalRecordContext(); const auto *parent = record.getParent();
if (parent != nullptr) { if (parent != nullptr) {
if (const auto *record_decl = if (const auto *record_decl =

View File

@@ -293,5 +293,7 @@ private:
std::tuple<std::string /* field name */, common::model::relationship_t, std::tuple<std::string /* field name */, common::model::relationship_t,
common::model::access_t>> common::model::access_t>>
anonymous_struct_relationships_; anonymous_struct_relationships_;
void process_concept_specialization_relationships(common::model::element &c,
const clang::ConceptSpecializationExpr *concept_specialization);
}; };
} // namespace clanguml::class_diagram::visitor } // namespace clanguml::class_diagram::visitor

View File

@@ -147,4 +147,16 @@ std::vector<common::model::template_parameter> parse_unexposed_template_params(
const std::string &params, const std::string &params,
const std::function<std::string(const std::string &)> &ns_resolve, const std::function<std::string(const std::string &)> &ns_resolve,
int depth = 0); int depth = 0);
template <typename T, typename P, typename F>
void if_dyn_cast(P pointer, F &&func)
{
if (pointer == nullptr)
return;
if (const auto *dyn_cast_value = clang::dyn_cast<T>(pointer);
dyn_cast_value) {
std::forward<F>(func)(dyn_cast_value);
}
}
} // namespace clanguml::common } // namespace clanguml::common

View File

@@ -23,7 +23,7 @@ namespace clanguml::common::model {
enum class diagram_t { kClass, kSequence, kPackage, kInclude }; enum class diagram_t { kClass, kSequence, kPackage, kInclude };
enum class access_t { kPublic, kProtected, kPrivate }; enum class access_t { kPublic, kProtected, kPrivate, kNone };
enum class relationship_t { enum class relationship_t {
kNone, kNone,

View File

@@ -18,7 +18,7 @@ endif(MSVC)
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_20 SUPPORTS_CXX_STD_20) list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_20 SUPPORTS_CXX_STD_20)
if(SUPPORTS_CXX_STD_20 EQUAL -1 if(SUPPORTS_CXX_STD_20 EQUAL -1
OR ${LLVM_PACKAGE_VERSION} VERSION_LESS "15.0") OR ${LLVM_PACKAGE_VERSION} VERSION_LESS "14.0")
set(ENABLE_CXX_STD_20_TEST_CASES 0) set(ENABLE_CXX_STD_20_TEST_CASES 0)
foreach(CXX20_TC ${TEST_CASES_REQUIRING_CXX20}) foreach(CXX20_TC ${TEST_CASES_REQUIRING_CXX20})
list(FILTER TEST_CASE_SOURCES list(FILTER TEST_CASE_SOURCES

View File

@@ -4,10 +4,10 @@ namespace clanguml {
namespace t00056 { namespace t00056 {
template <typename T, typename L> template <typename T, typename L>
concept greater_than = sizeof(T) > sizeof(L); concept greater_than_simple = sizeof(T) > sizeof(L);
template <typename T, typename P> template <typename T, typename P>
concept greater_than_requires = requires(T l, P r) concept greater_than_with_requires = requires(T l, P r)
{ {
sizeof(l) > sizeof(r); sizeof(l) > sizeof(r);
}; };
@@ -60,8 +60,8 @@ struct B {
T b; T b;
}; };
// Anonymous concept requirement // Anonymous concept requirement (TODO)
template <typename T> template <convertible_to_string T>
requires requires(T t) requires requires(T t)
{ {
--t; --t;
@@ -71,5 +71,25 @@ struct C {
T c; T c;
}; };
template <iterable T1, typename T2, iterable T3, typename T4, typename T5>
requires max_four_bytes<T2> && max_four_bytes<T5>
struct D {
};
template <typename T1, typename T2, typename T3>
requires greater_than_with_requires<T1, T3>
struct E {
T1 e1;
T2 e2;
T3 e3;
};
template <typename T1, typename T2, typename T3>
requires greater_than_simple<T1, T3>
struct F {
T1 f1;
T2 f2;
T3 f3;
};
} }
} }