Parse cpp_function_template_specialization

This commit is contained in:
Jonathan Müller 2017-03-27 10:07:13 +02:00
commit bf7c85a9dd
19 changed files with 567 additions and 257 deletions

View file

@ -69,7 +69,7 @@ using h = g<T, a>;
cpp_template_instantiation_type::builder builder(
cpp_template_ref(cpp_entity_id(""), "a"));
builder.add_argument(cpp_unexposed_type::build("void"));
builder.add_unexposed_arguments("void");
REQUIRE(equal_types(idx, alias.type_alias().underlying_type(), *builder.finish()));
}
else if (alias.name() == "e")
@ -79,8 +79,7 @@ using h = g<T, a>;
cpp_template_instantiation_type::builder builder(
cpp_template_ref(cpp_entity_id(""), "b"));
builder.add_argument(
cpp_unexposed_expression::build(cpp_builtin_type::build("int"), "I"));
builder.add_unexposed_arguments("I");
REQUIRE(equal_types(idx, alias.type_alias().underlying_type(),
*cpp_cv_qualified_type::build(builder.finish(), cpp_cv_const)));
}
@ -91,9 +90,7 @@ using h = g<T, a>;
cpp_template_instantiation_type::builder builder(
cpp_template_ref(cpp_entity_id(""), "b"));
builder.add_argument(cpp_unexposed_expression::build(cpp_builtin_type::build("int"),
"I < a<int>{(0 , 1)}"));
builder.add_argument(cpp_unexposed_type::build("int"));
builder.add_unexposed_arguments("I < a<int>{(0 , 1)}, int");
REQUIRE(equal_types(idx, alias.type_alias().underlying_type(), *builder.finish()));
}
else if (alias.name() == "g")
@ -104,7 +101,7 @@ using h = g<T, a>;
cpp_template_instantiation_type::builder builder(
cpp_template_ref(cpp_entity_id(""), "Templ"));
builder.add_argument(cpp_unexposed_type::build("T"));
builder.add_unexposed_arguments("T");
REQUIRE(equal_types(idx, alias.type_alias().underlying_type(), *builder.finish()));
}
else if (alias.name() == "h")
@ -113,8 +110,7 @@ using h = g<T, a>;
cpp_template_instantiation_type::builder builder(
cpp_template_ref(cpp_entity_id(""), "g"));
builder.add_argument(cpp_unexposed_type::build("T"));
builder.add_argument(cpp_template_ref(cpp_entity_id("magic-allow-empty"), "a"));
builder.add_unexposed_arguments("T, a");
REQUIRE(equal_types(idx, alias.type_alias().underlying_type(), *builder.finish()));
}
else

View file

@ -29,8 +29,14 @@ constexpr void i();
static constexpr void j();
// body
void k() = delete;
void l()
namespace ns
{
void k() = delete;
void l();
}
void ns::l()
{
// might confuse parser
auto b = noexcept(g());
@ -174,7 +180,7 @@ void l()
REQUIRE(func.storage_class() == cpp_storage_class_static);
}
}
else if (func.name() == "k" || func.name() == "l")
else if (func.name() == "k" || func.name() == "l" || func.name() == "ns::l")
{
REQUIRE(equal_types(idx, func.return_type(), *cpp_builtin_type::build("void")));
REQUIRE(count_children(func) == 0u);
@ -186,12 +192,14 @@ void l()
if (func.name() == "k")
check_body(func, cpp_function_deleted);
else if (func.name() == "l")
check_body(func, cpp_function_declaration);
else if (func.name() == "ns::l")
check_body(func, cpp_function_definition);
}
else
REQUIRE(false);
});
REQUIRE(count == 12u);
REQUIRE(count == 13u);
}
TEST_CASE("static cpp_function")
@ -206,6 +214,8 @@ struct foo
static constexpr char c() = delete;
};
void foo::a() {}
)";
cpp_entity_index idx;
@ -215,12 +225,16 @@ struct foo
REQUIRE(count_children(func) == 0u);
REQUIRE(func.storage_class() == cpp_storage_class_static);
if (func.name() == "a")
if (func.name() == "a" || func.name() == "foo::a")
{
REQUIRE(equal_types(idx, func.return_type(), *cpp_builtin_type::build("void")));
REQUIRE(!func.noexcept_condition());
REQUIRE(!func.is_constexpr());
REQUIRE(func.body_kind() == cpp_function_declaration);
if (func.name() == "a")
REQUIRE(func.body_kind() == cpp_function_declaration);
else
REQUIRE(func.body_kind() == cpp_function_definition);
}
else if (func.name() == "b")
{
@ -243,7 +257,7 @@ struct foo
else
REQUIRE(false);
});
REQUIRE(count == 3u);
REQUIRE(count == 4u);
}
// TODO: friend functions (clang 4.0 required)

View file

@ -14,12 +14,12 @@ TEST_CASE("cpp_function_template")
{
// only check templated related stuff
auto code = R"(
template <typename T>
T a(const T& t);
template <int I>
using type = int;
template <typename T>
T a(const T& t);
struct d
{
template <int I, typename T>
@ -34,6 +34,21 @@ struct d
template <typename T>
d(const T&);
};
template <>
int a(const int& t);
template <>
type<0> d::b<0, int>(int);
template <>
auto d::c() -> int;
template <>
d::operator int() const;
template <>
d::d(const int&);
)";
cpp_entity_index idx;
@ -75,8 +90,7 @@ struct d
cpp_template_instantiation_type::builder builder(
cpp_template_ref(cpp_entity_id(""), "type"));
builder.add_argument(
cpp_unexposed_expression::build(cpp_builtin_type::build("int"), "I"));
builder.add_unexposed_arguments("I");
REQUIRE(equal_types(idx, func.return_type(), *builder.finish()));
auto type_parameter = cpp_template_type_parameter_ref(cpp_entity_id(""), "T");
@ -91,6 +105,7 @@ struct d
}
else if (tfunc.name() == "c")
{
check_parent(tfunc, "d", "d::c");
check_template_parameters(tfunc, {{cpp_entity_kind::template_type_parameter_t, "T"}});
REQUIRE(tfunc.function().kind() == cpp_entity_kind::member_function_t);
@ -103,6 +118,7 @@ struct d
}
else if (tfunc.name() == "operator T")
{
check_parent(tfunc, "d", "d::operator T");
check_template_parameters(tfunc, {{cpp_entity_kind::template_type_parameter_t, "T"}});
REQUIRE(tfunc.function().kind() == cpp_entity_kind::conversion_op_t);
@ -115,6 +131,7 @@ struct d
}
else if (tfunc.name() == "d")
{
check_parent(tfunc, "d", "d::d");
check_template_parameters(tfunc, {{cpp_entity_kind::template_type_parameter_t, "T"}});
REQUIRE(tfunc.function().kind() == cpp_entity_kind::constructor_t);
@ -139,4 +156,105 @@ struct d
REQUIRE(false);
});
REQUIRE(count == 5u);
count = test_visit<cpp_function_template_specialization>(
*file, [&](const cpp_function_template_specialization& tfunc) {
REQUIRE(tfunc.is_full_specialization());
REQUIRE(!tfunc.arguments_exposed());
auto templ = tfunc.primary_template();
if (tfunc.name() == "d::operator int")
REQUIRE(equal_ref(idx, templ, cpp_template_ref(cpp_entity_id(""), tfunc.name()),
"d::operator T"));
else
REQUIRE(equal_ref(idx, templ, cpp_template_ref(cpp_entity_id(""), tfunc.name())));
if (tfunc.name() == "a")
{
REQUIRE(tfunc.unexposed_arguments() == "");
REQUIRE(tfunc.function().kind() == cpp_entity_kind::function_t);
auto& func = static_cast<const cpp_function&>(tfunc.function());
REQUIRE(equal_types(idx, func.return_type(), *cpp_builtin_type::build("int")));
auto count = 0u;
for (auto& param : func)
{
++count;
REQUIRE(
equal_types(idx, param.type(),
*cpp_reference_type::
build(cpp_cv_qualified_type::build(cpp_builtin_type::build(
"int"),
cpp_cv_const),
cpp_ref_lvalue)));
}
REQUIRE(count == 1u);
}
else if (tfunc.name() == "d::b")
{
REQUIRE(tfunc.unexposed_arguments() == "0,int");
REQUIRE(tfunc.function().kind() == cpp_entity_kind::function_t);
auto& func = static_cast<const cpp_function&>(tfunc.function());
cpp_template_instantiation_type::builder builder(
cpp_template_ref(cpp_entity_id(""), "type"));
builder.add_unexposed_arguments("0");
REQUIRE(equal_types(idx, func.return_type(), *builder.finish()));
auto count = 0u;
for (auto& param : func)
{
++count;
REQUIRE(equal_types(idx, param.type(), *cpp_builtin_type::build("int")));
}
REQUIRE(count == 1u);
}
else if (tfunc.name() == "d::c")
{
REQUIRE(tfunc.unexposed_arguments() == "");
REQUIRE(tfunc.function().kind() == cpp_entity_kind::member_function_t);
auto& func = static_cast<const cpp_member_function&>(tfunc.function());
REQUIRE(func.cv_qualifier() == cpp_cv_none);
REQUIRE(equal_types(idx, func.return_type(), *cpp_builtin_type::build("int")));
}
else if (tfunc.name() == "d::operator int")
{
REQUIRE(tfunc.unexposed_arguments() == "");
REQUIRE(tfunc.function().kind() == cpp_entity_kind::conversion_op_t);
auto& func = static_cast<const cpp_conversion_op&>(tfunc.function());
REQUIRE(func.cv_qualifier() == cpp_cv_const);
REQUIRE(equal_types(idx, func.return_type(), *cpp_builtin_type::build("int")));
}
else if (tfunc.name() == "d::d")
{
REQUIRE(tfunc.unexposed_arguments() == "");
REQUIRE(tfunc.function().kind() == cpp_entity_kind::constructor_t);
auto& func = static_cast<const cpp_constructor&>(tfunc.function());
auto count = 0u;
for (auto& param : func)
{
++count;
REQUIRE(
equal_types(idx, param.type(),
*cpp_reference_type::
build(cpp_cv_qualified_type::build(cpp_builtin_type::build(
"int"),
cpp_cv_const),
cpp_ref_lvalue)));
}
REQUIRE(count == 1u);
}
else
REQUIRE(false);
});
REQUIRE(count == 5u);
}

View file

@ -160,7 +160,7 @@ struct foo
if (!op.is_explicit() && !op.is_constexpr())
{
REQUIRE(op.name() == "operator int &");
REQUIRE(op.name() == "operator int&");
REQUIRE(equal_types(idx, op.return_type(),
*cpp_reference_type::build(cpp_builtin_type::build("int"),
cpp_ref_lvalue)));

View file

@ -13,23 +13,6 @@
using namespace cppast;
template <typename T, class Predicate>
bool equal_ref(const cpp_entity_index& idx, const basic_cpp_entity_ref<T, Predicate>& parsed,
const basic_cpp_entity_ref<T, Predicate>& synthesized)
{
if (parsed.name() != synthesized.name())
return false;
else if (parsed.is_overloaded() != synthesized.is_overloaded())
return false;
else if (parsed.is_overloaded())
return false;
auto entities = parsed.get(idx);
if (entities.size() != 1u)
return synthesized.id()[0u] == cpp_entity_id("magic-allow-empty");
return entities[0u]->name().empty() || full_name(*entities[0u]) == parsed.name();
}
bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_type& synthesized)
{
if (parsed.kind() != synthesized.kind())
@ -153,6 +136,10 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_
if (!equal_ref(idx, inst_parsed.primary_template(), inst_synthesized.primary_template()))
return false;
else if (inst_parsed.arguments_exposed() != inst_synthesized.arguments_exposed())
return false;
else if (!inst_parsed.arguments_exposed())
return inst_parsed.unexposed_arguments() == inst_synthesized.unexposed_arguments();
auto iter_a = inst_parsed.arguments().begin();
auto iter_b = inst_synthesized.arguments().begin();

View file

@ -100,6 +100,26 @@ inline bool equal_expressions(const cppast::cpp_expression& parsed,
return false;
}
template <typename T, class Predicate>
bool equal_ref(const cppast::cpp_entity_index& idx,
const cppast::basic_cpp_entity_ref<T, Predicate>& parsed,
const cppast::basic_cpp_entity_ref<T, Predicate>& synthesized,
const char* full_name_override = nullptr)
{
if (parsed.name() != synthesized.name())
return false;
else if (parsed.is_overloaded() != synthesized.is_overloaded())
return false;
else if (parsed.is_overloaded())
return false;
auto entities = parsed.get(idx);
if (entities.size() != 1u)
return false;
return entities[0u]->name().empty()
|| full_name(*entities[0u]) == (full_name_override ? full_name_override : parsed.name());
}
template <typename T>
void check_template_parameters(
const T& templ, std::initializer_list<std::pair<cppast::cpp_entity_kind, const char*>> params)