Added constrained template parameter names in requires relationship
This commit is contained in:
@@ -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>>";
|
||||||
|
|
||||||
|
|||||||
@@ -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 =
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -147,4 +147,16 @@ std::vector<common::model::template_parameter> parse_unexposed_template_params(
|
|||||||
const std::string ¶ms,
|
const std::string ¶ms,
|
||||||
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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user