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);
|
||||
|
||||
if (m_config.generate_packages())
|
||||
ostr << "annotation"
|
||||
ostr << "class"
|
||||
<< " \"" << c.name();
|
||||
else
|
||||
ostr << "annotation"
|
||||
ostr << "class"
|
||||
<< " \"" << render_name(c.full_name());
|
||||
|
||||
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;
|
||||
|
||||
std::string class_type{"annotation"};
|
||||
std::string class_type{"class"};
|
||||
|
||||
ostr << class_type << " " << c.alias() << " <<concept>>";
|
||||
|
||||
|
||||
@@ -415,8 +415,6 @@ bool translation_unit_visitor::TraverseConceptDecl(clang::ConceptDecl *cpt)
|
||||
|
||||
// process 'requires (...)' declaration
|
||||
for (const auto *decl : constraint->getBody()->decls()) {
|
||||
// decl->dump();
|
||||
|
||||
if (const auto *parm_var_decl =
|
||||
clang::dyn_cast<clang::ParmVarDecl>(decl);
|
||||
parm_var_decl) {
|
||||
@@ -491,38 +489,92 @@ void translation_unit_visitor::find_relationships_in_constraint_expression(
|
||||
if (expr == nullptr)
|
||||
return;
|
||||
|
||||
if (const auto *concept_specialization =
|
||||
clang::dyn_cast<clang::ConceptSpecializationExpr>(expr);
|
||||
concept_specialization) {
|
||||
if (concept_specialization->getNamedConcept() &&
|
||||
diagram().should_include(concept_specialization->getNamedConcept()
|
||||
->getQualifiedNameAsString())) {
|
||||
auto target_id = get_ast_local_id(
|
||||
concept_specialization->getNamedConcept()->getID())
|
||||
.value();
|
||||
common::if_dyn_cast<clang::ConceptSpecializationExpr>(
|
||||
expr, [&](const auto *cs) {
|
||||
process_concept_specialization_relationships(c, cs);
|
||||
});
|
||||
|
||||
for (const auto ta :
|
||||
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) {
|
||||
common::if_dyn_cast<clang::RequiresExpr>(expr, [&](const auto *re) {
|
||||
// TODO
|
||||
});
|
||||
|
||||
common::if_dyn_cast<clang::BinaryOperator>(expr, [&](const auto *op) {
|
||||
find_relationships_in_constraint_expression(c, op->getLHS());
|
||||
find_relationships_in_constraint_expression(c, op->getRHS());
|
||||
});
|
||||
|
||||
common::if_dyn_cast<clang::UnaryOperator>(expr, [&](const auto *op) {
|
||||
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);
|
||||
}
|
||||
else if (const auto *binop = clang::dyn_cast<clang::BinaryOperator>(expr);
|
||||
binop) {
|
||||
find_relationships_in_constraint_expression(c, binop->getLHS());
|
||||
find_relationships_in_constraint_expression(c, binop->getRHS());
|
||||
}
|
||||
else if (const auto *unop = clang::dyn_cast<clang::UnaryOperator>(expr);
|
||||
unop) {
|
||||
find_relationships_in_constraint_expression(c, unop->getSubExpr());
|
||||
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(
|
||||
template_type_parameter->getTypeConstraint()
|
||||
->getNamedConcept(),
|
||||
[&ct](const clang::ConceptDecl *named_concept) mutable {
|
||||
[this, &ct, &templated_element](
|
||||
const clang::ConceptDecl *named_concept) mutable {
|
||||
ct.set_concept_constraint(
|
||||
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());
|
||||
|
||||
const auto *parent = record.getParent(); //->getOuterLexicalRecordContext();
|
||||
const auto *parent = record.getParent();
|
||||
|
||||
if (parent != nullptr) {
|
||||
if (const auto *record_decl =
|
||||
|
||||
@@ -293,5 +293,7 @@ private:
|
||||
std::tuple<std::string /* field name */, common::model::relationship_t,
|
||||
common::model::access_t>>
|
||||
anonymous_struct_relationships_;
|
||||
void process_concept_specialization_relationships(common::model::element &c,
|
||||
const clang::ConceptSpecializationExpr *concept_specialization);
|
||||
};
|
||||
} // 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::function<std::string(const std::string &)> &ns_resolve,
|
||||
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
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace clanguml::common::model {
|
||||
|
||||
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 {
|
||||
kNone,
|
||||
|
||||
@@ -18,7 +18,7 @@ endif(MSVC)
|
||||
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_20 SUPPORTS_CXX_STD_20)
|
||||
|
||||
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)
|
||||
foreach(CXX20_TC ${TEST_CASES_REQUIRING_CXX20})
|
||||
list(FILTER TEST_CASE_SOURCES
|
||||
|
||||
@@ -4,10 +4,10 @@ namespace clanguml {
|
||||
namespace t00056 {
|
||||
|
||||
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>
|
||||
concept greater_than_requires = requires(T l, P r)
|
||||
concept greater_than_with_requires = requires(T l, P r)
|
||||
{
|
||||
sizeof(l) > sizeof(r);
|
||||
};
|
||||
@@ -60,8 +60,8 @@ struct B {
|
||||
T b;
|
||||
};
|
||||
|
||||
// Anonymous concept requirement
|
||||
template <typename T>
|
||||
// Anonymous concept requirement (TODO)
|
||||
template <convertible_to_string T>
|
||||
requires requires(T t)
|
||||
{
|
||||
--t;
|
||||
@@ -71,5 +71,25 @@ struct 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