Implemented tests for concept test case 00056
This commit is contained in:
@@ -512,8 +512,14 @@ void translation_unit_visitor::process_concept_specialization_relationships(
|
|||||||
common::model::element &c,
|
common::model::element &c,
|
||||||
const clang::ConceptSpecializationExpr *concept_specialization)
|
const clang::ConceptSpecializationExpr *concept_specialization)
|
||||||
{
|
{
|
||||||
const auto *cpt = concept_specialization->getNamedConcept();
|
if (const auto *cpt = concept_specialization->getNamedConcept();
|
||||||
if (cpt && diagram().should_include(cpt->getQualifiedNameAsString())) {
|
should_include(cpt)) {
|
||||||
|
|
||||||
|
const auto cpt_name = cpt->getNameAsString();
|
||||||
|
|
||||||
|
if (!get_ast_local_id(cpt->getID()))
|
||||||
|
return;
|
||||||
|
|
||||||
auto target_id = get_ast_local_id(cpt->getID()).value();
|
auto target_id = get_ast_local_id(cpt->getID()).value();
|
||||||
|
|
||||||
std::vector<std::string> constrained_template_params;
|
std::vector<std::string> constrained_template_params;
|
||||||
@@ -524,43 +530,9 @@ void translation_unit_visitor::process_concept_specialization_relationships(
|
|||||||
if (ta.getKind() == clang::TemplateArgument::Type) {
|
if (ta.getKind() == clang::TemplateArgument::Type) {
|
||||||
auto type_name =
|
auto type_name =
|
||||||
common::to_string(ta.getAsType(), cpt->getASTContext());
|
common::to_string(ta.getAsType(), cpt->getASTContext());
|
||||||
|
extract_constrained_template_param_name(concept_specialization,
|
||||||
if (const auto *nested_template_type =
|
cpt, constrained_template_params, argument_index,
|
||||||
ta.getAsType()->getAs<clang::TemplateTypeParmType>();
|
type_name);
|
||||||
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 {
|
else {
|
||||||
auto type_name =
|
auto type_name =
|
||||||
@@ -572,7 +544,7 @@ void translation_unit_visitor::process_concept_specialization_relationships(
|
|||||||
}
|
}
|
||||||
if (!constrained_template_params.empty())
|
if (!constrained_template_params.empty())
|
||||||
c.add_relationship(
|
c.add_relationship(
|
||||||
{relationship_t::kDependency, target_id, access_t::kNone,
|
{relationship_t::kConstraint, target_id, access_t::kNone,
|
||||||
fmt::format(
|
fmt::format(
|
||||||
"{}", fmt::join(constrained_template_params, ","))});
|
"{}", fmt::join(constrained_template_params, ","))});
|
||||||
}
|
}
|
||||||
@@ -877,7 +849,7 @@ bool translation_unit_visitor::process_template_parameters(
|
|||||||
diagram().should_include(
|
diagram().should_include(
|
||||||
named_concept->getQualifiedNameAsString())) {
|
named_concept->getQualifiedNameAsString())) {
|
||||||
templated_element.value().add_relationship(
|
templated_element.value().add_relationship(
|
||||||
{relationship_t::kDependency,
|
{relationship_t::kConstraint,
|
||||||
get_ast_local_id(named_concept->getID())
|
get_ast_local_id(named_concept->getID())
|
||||||
.value(),
|
.value(),
|
||||||
access_t::kNone, ct.name()});
|
access_t::kNone, ct.name()});
|
||||||
@@ -1301,7 +1273,6 @@ void translation_unit_visitor::
|
|||||||
deduced_auto_decl->getQualifiedNameAsString();
|
deduced_auto_decl->getQualifiedNameAsString();
|
||||||
|
|
||||||
if (diagram().should_include(template_field_decl_name)) {
|
if (diagram().should_include(template_field_decl_name)) {
|
||||||
|
|
||||||
relationship r{relationship_t::kDependency,
|
relationship r{relationship_t::kDependency,
|
||||||
template_specialization_model.get().id()};
|
template_specialization_model.get().id()};
|
||||||
|
|
||||||
@@ -2715,4 +2686,38 @@ translation_unit_visitor::get_ast_local_id(int64_t local_id) const
|
|||||||
|
|
||||||
return local_ast_id_map_.at(local_id);
|
return local_ast_id_map_.at(local_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void translation_unit_visitor::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
|
||||||
|
{
|
||||||
|
const auto full_declaration_text = common::get_source_text_raw(
|
||||||
|
concept_specialization->getSourceRange(), source_manager());
|
||||||
|
|
||||||
|
if (!full_declaration_text.empty()) {
|
||||||
|
// Handle typename constraint in requires clause
|
||||||
|
if (type_name.find("type-parameter-") == 0) {
|
||||||
|
const auto concept_declaration_text = full_declaration_text.substr(
|
||||||
|
full_declaration_text.find(cpt->getNameAsString()) +
|
||||||
|
cpt->getNameAsString().size() + 1);
|
||||||
|
|
||||||
|
auto template_params = common::parse_unexposed_template_params(
|
||||||
|
concept_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);
|
||||||
|
}
|
||||||
|
constrained_template_params.push_back(type_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool translation_unit_visitor::should_include(const clang::NamedDecl *decl)
|
||||||
|
{
|
||||||
|
return decl != nullptr &&
|
||||||
|
diagram().should_include(decl->getQualifiedNameAsString());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace clanguml::class_diagram::visitor
|
} // namespace clanguml::class_diagram::visitor
|
||||||
|
|||||||
@@ -111,6 +111,8 @@ public:
|
|||||||
void finalize();
|
void finalize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool should_include(const clang::NamedDecl *decl);
|
||||||
|
|
||||||
std::unique_ptr<clanguml::class_diagram::model::class_>
|
std::unique_ptr<clanguml::class_diagram::model::class_>
|
||||||
create_class_declaration(clang::CXXRecordDecl *cls);
|
create_class_declaration(clang::CXXRecordDecl *cls);
|
||||||
|
|
||||||
@@ -268,6 +270,15 @@ private:
|
|||||||
bool simplify_system_template(common::model::template_parameter &ct,
|
bool simplify_system_template(common::model::template_parameter &ct,
|
||||||
const std::string &full_name) const;
|
const std::string &full_name) const;
|
||||||
|
|
||||||
|
void process_concept_specialization_relationships(common::model::element &c,
|
||||||
|
const clang::ConceptSpecializationExpr *concept_specialization);
|
||||||
|
|
||||||
|
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
|
/// Store the mapping from local clang entity id (obtained using
|
||||||
/// getID()) method to clang-uml global id
|
/// getID()) method to clang-uml global id
|
||||||
void set_ast_local_id(
|
void set_ast_local_id(
|
||||||
@@ -293,7 +304,5 @@ 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
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ std::string to_plantuml(relationship_t r, const std::string &style)
|
|||||||
return style.empty() ? "<.." : fmt::format("<.[{}].", style);
|
return style.empty() ? "<.." : fmt::format("<.[{}].", style);
|
||||||
case relationship_t::kDependency:
|
case relationship_t::kDependency:
|
||||||
return style.empty() ? "..>" : fmt::format(".[{}].>", style);
|
return style.empty() ? "..>" : fmt::format(".[{}].>", style);
|
||||||
|
case relationship_t::kConstraint:
|
||||||
|
return style.empty() ? "..>" : fmt::format(".[{}].>", style);
|
||||||
case relationship_t::kAlias:
|
case relationship_t::kAlias:
|
||||||
return style.empty() ? ".." : fmt::format(".[{}].", style);
|
return style.empty() ? ".." : fmt::format(".[{}].", style);
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ std::string to_string(relationship_t r)
|
|||||||
return "dependency";
|
return "dependency";
|
||||||
case relationship_t::kAlias:
|
case relationship_t::kAlias:
|
||||||
return "alias";
|
return "alias";
|
||||||
|
case relationship_t::kConstraint:
|
||||||
|
return "constraint";
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
return "";
|
return "";
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ enum class relationship_t {
|
|||||||
kInstantiation,
|
kInstantiation,
|
||||||
kFriendship,
|
kFriendship,
|
||||||
kAlias,
|
kAlias,
|
||||||
kDependency
|
kDependency,
|
||||||
|
kConstraint
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Types of sequence diagram activity elements
|
/// Types of sequence diagram activity elements
|
||||||
|
|||||||
@@ -35,32 +35,59 @@ TEST_CASE("t00056", "[test-case][class]")
|
|||||||
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
||||||
|
|
||||||
// Check if all classes exist
|
// Check if all classes exist
|
||||||
// REQUIRE_THAT(puml, IsClass(_A("A")));
|
REQUIRE_THAT(puml, IsConcept(_A("greater_than_simple<T,L>")));
|
||||||
|
REQUIRE_THAT(puml, IsConcept(_A("greater_than_with_requires<T,P>")));
|
||||||
|
REQUIRE_THAT(puml, IsConcept(_A("max_four_bytes<T>")));
|
||||||
|
REQUIRE_THAT(puml, IsConcept(_A("iterable<T>")));
|
||||||
|
REQUIRE_THAT(puml, IsConcept(_A("has_value_type<T>")));
|
||||||
|
REQUIRE_THAT(puml, IsConcept(_A("convertible_to_string<T>")));
|
||||||
|
REQUIRE_THAT(puml, IsConcept(_A("iterable_with_value_type<T>")));
|
||||||
|
REQUIRE_THAT(puml, IsConcept(_A("iterable_or_small_value_type<T>")));
|
||||||
|
|
||||||
// Check if class templates exist
|
// Check if class templates exist
|
||||||
// REQUIRE_THAT(puml, IsClassTemplate("A", "T,P,CMP,int N"));
|
REQUIRE_THAT(puml, IsClassTemplate("A", "max_four_bytes T"));
|
||||||
|
REQUIRE_THAT(puml, IsClassTemplate("B", "T"));
|
||||||
// Check if all enums exist
|
REQUIRE_THAT(puml, IsClassTemplate("C", "convertible_to_string T"));
|
||||||
// REQUIRE_THAT(puml, IsEnum(_A("Lights")));
|
REQUIRE_THAT(
|
||||||
|
puml, IsClassTemplate("D", "iterable T1,T2,iterable T3,T4,T5"));
|
||||||
// Check if all inner classes exist
|
REQUIRE_THAT(puml, IsClassTemplate("E", "T1,T2,T3"));
|
||||||
// REQUIRE_THAT(puml, IsInnerClass(_A("A"), _A("AA")));
|
REQUIRE_THAT(puml, IsClassTemplate("F", "T1,T2,T3"));
|
||||||
|
|
||||||
// Check if all inheritance relationships exist
|
|
||||||
// REQUIRE_THAT(puml, IsBaseClass(_A("Base"), _A("Child")));
|
|
||||||
|
|
||||||
// Check if all methods exist
|
|
||||||
// REQUIRE_THAT(puml, (IsMethod<Public, Const>("foo")));
|
|
||||||
|
|
||||||
// Check if all fields exist
|
|
||||||
// REQUIRE_THAT(puml, (IsField<Private>("private_member", "int")));
|
|
||||||
|
|
||||||
// Check if all relationships exist
|
// Check if all relationships exist
|
||||||
// REQUIRE_THAT(puml, IsAssociation(_A("D"), _A("A"), "-as"));
|
REQUIRE_THAT(puml,
|
||||||
// REQUIRE_THAT(puml, IsDependency(_A("R"), _A("B")));
|
IsConstraint(_A("A<max_four_bytes T>"), _A("max_four_bytes<T>"), "T"));
|
||||||
// REQUIRE_THAT(puml, IsAggregation(_A("R"), _A("D")));
|
|
||||||
// REQUIRE_THAT(puml, IsComposition(_A("R"), _A("D")));
|
REQUIRE_THAT(puml,
|
||||||
// REQUIRE_THAT(puml, IsInstantiation(_A("ABCD::F<T>"), _A("F<int>")));
|
IsConstraint(_A("D<iterable T1,T2,iterable T3,T4,T5>"),
|
||||||
|
_A("max_four_bytes<T>"), "T2"));
|
||||||
|
REQUIRE_THAT(puml,
|
||||||
|
IsConstraint(_A("D<iterable T1,T2,iterable T3,T4,T5>"),
|
||||||
|
_A("max_four_bytes<T>"), "T5"));
|
||||||
|
REQUIRE_THAT(puml,
|
||||||
|
IsConstraint(_A("D<iterable T1,T2,iterable T3,T4,T5>"),
|
||||||
|
_A("iterable<T>"), "T1"));
|
||||||
|
REQUIRE_THAT(puml,
|
||||||
|
IsConstraint(_A("D<iterable T1,T2,iterable T3,T4,T5>"),
|
||||||
|
_A("iterable<T>"), "T3"));
|
||||||
|
|
||||||
|
REQUIRE_THAT(puml,
|
||||||
|
IsConstraint(
|
||||||
|
_A("iterable_with_value_type<T>"), _A("has_value_type<T>"), "T"));
|
||||||
|
|
||||||
|
REQUIRE_THAT(puml,
|
||||||
|
IsConstraint(_A("iterable_or_small_value_type<T>"),
|
||||||
|
_A("max_four_bytes<T>"), "T"));
|
||||||
|
REQUIRE_THAT(puml,
|
||||||
|
IsConstraint(_A("iterable_or_small_value_type<T>"),
|
||||||
|
_A("iterable_with_value_type<T>"), "T"));
|
||||||
|
|
||||||
|
REQUIRE_THAT(puml,
|
||||||
|
IsConstraint(
|
||||||
|
_A("E<T1,T2,T3>"), _A("greater_than_with_requires<T,P>"), "T1,T3"));
|
||||||
|
|
||||||
|
REQUIRE_THAT(puml,
|
||||||
|
IsConstraint(
|
||||||
|
_A("F<T1,T2,T3>"), _A("greater_than_simple<T,L>"), "T1,T3"));
|
||||||
|
|
||||||
save_puml(config.output_directory() + "/" + diagram->name + ".puml", puml);
|
save_puml(config.output_directory() + "/" + diagram->name + ".puml", puml);
|
||||||
}
|
}
|
||||||
@@ -281,6 +281,13 @@ ContainsMatcher IsClassTemplate(std::string const &str,
|
|||||||
fmt::format("class \"{}<{}>\"", str, tmplt), caseSensitivity));
|
fmt::format("class \"{}<{}>\"", str, tmplt), caseSensitivity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContainsMatcher IsConcept(std::string const &str,
|
||||||
|
CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
|
||||||
|
{
|
||||||
|
return ContainsMatcher(
|
||||||
|
CasedString("class " + str + " <<concept>>", caseSensitivity));
|
||||||
|
}
|
||||||
|
|
||||||
ContainsMatcher IsEnum(std::string const &str,
|
ContainsMatcher IsEnum(std::string const &str,
|
||||||
CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
|
CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
|
||||||
{
|
{
|
||||||
@@ -426,6 +433,18 @@ ContainsMatcher IsDependency(std::string const &from, std::string const &to,
|
|||||||
CasedString(fmt::format("{} ..> {}", from, to), caseSensitivity));
|
CasedString(fmt::format("{} ..> {}", from, to), caseSensitivity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContainsMatcher IsConstraint(std::string const &from, std::string const &to,
|
||||||
|
std::string const &label = {},
|
||||||
|
CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
|
||||||
|
{
|
||||||
|
if (label.empty())
|
||||||
|
return ContainsMatcher(
|
||||||
|
CasedString(fmt::format("{} ..> {}", from, to), caseSensitivity));
|
||||||
|
else
|
||||||
|
return ContainsMatcher(CasedString(
|
||||||
|
fmt::format("{} ..> {} : {}", from, to, label), caseSensitivity));
|
||||||
|
}
|
||||||
|
|
||||||
ContainsMatcher IsLayoutHint(std::string const &from, std::string const &hint,
|
ContainsMatcher IsLayoutHint(std::string const &from, std::string const &hint,
|
||||||
std::string const &to,
|
std::string const &to,
|
||||||
CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
|
CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
|
||||||
|
|||||||
Reference in New Issue
Block a user