Parse cpp_function_template_specialization
This commit is contained in:
parent
eeb48f1df5
commit
bf7c85a9dd
19 changed files with 567 additions and 257 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue