Implement code generation
This commit is contained in:
parent
c44e0b512e
commit
d18070a799
29 changed files with 2522 additions and 280 deletions
39
test/code_generator.cpp
Normal file
39
test/code_generator.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (C) 2017 Jonathan Müller <jonathanmueller.dev@gmail.com>
|
||||
// This file is subject to the license terms in the LICENSE file
|
||||
// found in the top-level directory of this distribution.
|
||||
|
||||
#include <cppast/code_generator.hpp>
|
||||
|
||||
#include "test_parser.hpp"
|
||||
|
||||
TEST_CASE("code_generator")
|
||||
{
|
||||
// no need to check much here, as each entity check separately
|
||||
// only write some file with equivalent code and synopsis
|
||||
auto code = R"(using type=int;
|
||||
|
||||
struct foo{
|
||||
int a;
|
||||
|
||||
auto func(int)->int(*)[];
|
||||
|
||||
private:
|
||||
int const b=42;
|
||||
};
|
||||
|
||||
int(*(foo::* mptr)(int))[];
|
||||
|
||||
enum class bar
|
||||
:int{
|
||||
a,
|
||||
b=42
|
||||
};
|
||||
|
||||
void func(int(*)(int));
|
||||
|
||||
extern void(* ptr)(int(*)(int))=&func;
|
||||
)";
|
||||
|
||||
auto file = parse({}, "code_generator.cpp", code);
|
||||
REQUIRE(get_code(*file) == code);
|
||||
}
|
||||
|
|
@ -12,27 +12,43 @@ TEST_CASE("cpp_alias_template")
|
|||
{
|
||||
// no need to check advanced types here nor template parameters
|
||||
auto code = R"(
|
||||
/// template<typename T>
|
||||
/// using a=int;
|
||||
template <typename T>
|
||||
using a = int;
|
||||
|
||||
/// template<int I,typename T=void>
|
||||
/// using b=T;
|
||||
template <int I, typename T = void>
|
||||
using b = T;
|
||||
|
||||
/// template<typename T>
|
||||
/// using c=T const*;
|
||||
template <typename T>
|
||||
using c = const T*;
|
||||
|
||||
/// template<typename T>
|
||||
/// using d=a<void>;
|
||||
template <typename T>
|
||||
using d = a<void>;
|
||||
|
||||
/// template<int I>
|
||||
/// using e=b<I> const;
|
||||
template <int I>
|
||||
using e = const b<I>;
|
||||
|
||||
/// template<int I>
|
||||
/// using f=b<I < a<int>{(0 , 1)}, int>;
|
||||
template <int I>
|
||||
using f = b<I < a<int>{(0,1)}, int>;
|
||||
|
||||
/// template<typename T,template<typename>class Templ>
|
||||
/// using g=Templ<T>;
|
||||
template <typename T, template <typename> class Templ>
|
||||
using g = Templ<T>;
|
||||
|
||||
/// template<typename T>
|
||||
/// using h=g<T, a>;
|
||||
template <typename T>
|
||||
using h = g<T, a>;
|
||||
)";
|
||||
|
|
|
|||
|
|
@ -12,16 +12,40 @@ TEST_CASE("cpp_class")
|
|||
{
|
||||
auto code = R"(
|
||||
// forward declarations
|
||||
/// struct a;
|
||||
struct a;
|
||||
/// class b;
|
||||
class b;
|
||||
/// struct unresolved;
|
||||
struct unresolved;
|
||||
|
||||
// basic
|
||||
/// struct a{
|
||||
/// };
|
||||
struct a {};
|
||||
/// class b final{
|
||||
/// };
|
||||
class b final {};
|
||||
/// union c{
|
||||
/// };
|
||||
union c {};
|
||||
|
||||
// members
|
||||
/// struct d{
|
||||
/// enum m1{
|
||||
/// };
|
||||
///
|
||||
/// enum m2{
|
||||
/// };
|
||||
///
|
||||
/// private:
|
||||
/// enum m3{
|
||||
/// };
|
||||
///
|
||||
/// protected:
|
||||
/// enum m4{
|
||||
/// };
|
||||
/// };
|
||||
struct d
|
||||
{
|
||||
enum m1 {};
|
||||
|
|
@ -38,20 +62,31 @@ protected:
|
|||
};
|
||||
|
||||
// bases
|
||||
/// class e
|
||||
/// :a,d{
|
||||
/// };
|
||||
class e
|
||||
: a, private d {};
|
||||
|
||||
namespace ns
|
||||
{
|
||||
/// struct base{
|
||||
/// };
|
||||
struct base {};
|
||||
}
|
||||
|
||||
/// struct f
|
||||
/// :ns::base,virtual protected e{
|
||||
/// };
|
||||
struct f
|
||||
: public ns::base, virtual protected e
|
||||
{};
|
||||
|
||||
using namespace ns;
|
||||
|
||||
/// struct g
|
||||
/// :base{
|
||||
/// };
|
||||
struct g
|
||||
: base {};
|
||||
)";
|
||||
|
|
|
|||
|
|
@ -16,20 +16,45 @@ TEST_CASE("cpp_class_template")
|
|||
{
|
||||
auto code = R"(
|
||||
// check everything not related to members first
|
||||
/// template<typename T>
|
||||
/// class a{
|
||||
/// };
|
||||
template <typename T>
|
||||
class a {};
|
||||
|
||||
/// template<int I,typename T>
|
||||
/// struct b{
|
||||
/// };
|
||||
template <int I, typename T>
|
||||
struct b {};
|
||||
|
||||
/// template<template<typename>class T>
|
||||
/// union c;
|
||||
template <template <typename> class T>
|
||||
union c;
|
||||
|
||||
// bases
|
||||
/// template<typename T>
|
||||
/// struct d
|
||||
/// :T,a<T>,T::type,a<T>::type{
|
||||
/// };
|
||||
template <typename T>
|
||||
struct d : T, a<T>, T::type, a<T>::type {};
|
||||
|
||||
// members
|
||||
/// template<typename T>
|
||||
/// struct e{
|
||||
/// T var_a;
|
||||
///
|
||||
/// a<T> var_b;
|
||||
///
|
||||
/// typename T::type var_c;
|
||||
///
|
||||
/// typename a<T>::type var_d;
|
||||
///
|
||||
/// template<typename U>
|
||||
/// T func(U);
|
||||
/// };
|
||||
template <typename T>
|
||||
struct e
|
||||
{
|
||||
|
|
@ -43,16 +68,28 @@ struct e
|
|||
};
|
||||
|
||||
// full specialization
|
||||
/// template<>
|
||||
/// class a<int>{
|
||||
/// };
|
||||
template <>
|
||||
class a<int> {};
|
||||
|
||||
/// template<>
|
||||
/// struct b<0,int>{
|
||||
/// };
|
||||
template <>
|
||||
struct b<0, int> {};
|
||||
|
||||
// partial specialization
|
||||
/// template<typename T>
|
||||
/// class a<T*>{
|
||||
/// };
|
||||
template <typename T>
|
||||
class a<T*> {};
|
||||
|
||||
/// template<typename T>
|
||||
/// struct b<0,T>{
|
||||
/// };
|
||||
template <typename T>
|
||||
struct b<0, T> {};
|
||||
)";
|
||||
|
|
|
|||
|
|
@ -11,6 +11,12 @@ using namespace cppast;
|
|||
TEST_CASE("cpp_enum")
|
||||
{
|
||||
auto code = R"(
|
||||
/// enum a{
|
||||
/// a_a,
|
||||
/// a_b=42,
|
||||
/// a_c,
|
||||
/// a_d=a_a+2
|
||||
/// };
|
||||
enum a
|
||||
{
|
||||
a_a,
|
||||
|
|
@ -19,8 +25,15 @@ enum a
|
|||
a_d = a_a + 2,
|
||||
};
|
||||
|
||||
/// enum class b;
|
||||
enum class b; // forward declaration
|
||||
|
||||
/// enum class b
|
||||
/// :int{
|
||||
/// b_a,
|
||||
/// b_b=42,
|
||||
/// b_c
|
||||
/// };
|
||||
enum class b : int
|
||||
{
|
||||
b_a,
|
||||
|
|
@ -28,6 +41,8 @@ enum class b : int
|
|||
b_c
|
||||
};
|
||||
|
||||
/// enum c
|
||||
/// :int;
|
||||
enum c : int;
|
||||
)";
|
||||
|
||||
|
|
@ -54,7 +69,7 @@ enum c : int;
|
|||
++no_vals;
|
||||
REQUIRE(val.value());
|
||||
auto& expr = val.value().value();
|
||||
REQUIRE(expr.kind() == cpp_expression_kind::unexposed);
|
||||
REQUIRE(expr.kind() == cpp_expression_kind::unexposed_t);
|
||||
REQUIRE(static_cast<const cpp_unexposed_expression&>(expr).expression()
|
||||
== "42");
|
||||
REQUIRE(equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_uint)));
|
||||
|
|
@ -65,7 +80,7 @@ enum c : int;
|
|||
REQUIRE(val.value());
|
||||
auto& expr = val.value().value();
|
||||
// this is unexposed for some reason
|
||||
REQUIRE(expr.kind() == cpp_expression_kind::unexposed);
|
||||
REQUIRE(expr.kind() == cpp_expression_kind::unexposed_t);
|
||||
REQUIRE(static_cast<const cpp_unexposed_expression&>(expr).expression()
|
||||
== "a_a+2");
|
||||
REQUIRE(equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_uint)));
|
||||
|
|
@ -99,7 +114,7 @@ enum c : int;
|
|||
++no_vals;
|
||||
REQUIRE(val.value());
|
||||
auto& expr = val.value().value();
|
||||
REQUIRE(expr.kind() == cpp_expression_kind::literal);
|
||||
REQUIRE(expr.kind() == cpp_expression_kind::literal_t);
|
||||
REQUIRE(static_cast<const cpp_literal_expression&>(expr).value() == "42");
|
||||
REQUIRE(equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_int)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,29 +15,42 @@ TEST_CASE("cpp_function")
|
|||
{
|
||||
auto code = R"(
|
||||
// parameters and return type are only tested here
|
||||
/// void a();
|
||||
void a();
|
||||
/// int b(int a,float* b=nullptr);
|
||||
int b(int a, float* b = nullptr);
|
||||
/// auto c(decltype(42) a,...)->int(&)[10];
|
||||
int (&c(decltype(42) a, ...))[10];
|
||||
|
||||
// noexcept conditions
|
||||
/// void d()noexcept;
|
||||
void d() noexcept;
|
||||
/// void e()noexcept(false);
|
||||
void e() noexcept(false);
|
||||
/// void f()noexcept(noexcept(d()));
|
||||
void f() noexcept(noexcept(d()));
|
||||
|
||||
// storage class + constexpr
|
||||
/// extern void g();
|
||||
extern void g();
|
||||
/// static void h();
|
||||
static void h();
|
||||
/// constexpr void i();
|
||||
constexpr void i();
|
||||
/// static constexpr void j();
|
||||
static constexpr void j();
|
||||
|
||||
// body
|
||||
namespace ns
|
||||
{
|
||||
/// void k()=delete;
|
||||
void k() = delete;
|
||||
|
||||
/// void l();
|
||||
void l();
|
||||
}
|
||||
|
||||
/// void ns::l();
|
||||
void ns::l()
|
||||
{
|
||||
// might confuse parser
|
||||
|
|
@ -215,13 +228,17 @@ TEST_CASE("static cpp_function")
|
|||
// no need to test anything special
|
||||
struct foo
|
||||
{
|
||||
/// static void a();
|
||||
static void a();
|
||||
|
||||
/// static int b()noexcept;
|
||||
static int b() noexcept { return 0; }
|
||||
|
||||
/// static constexpr char c()=delete;
|
||||
static constexpr char c() = delete;
|
||||
};
|
||||
|
||||
/// static void foo::a();
|
||||
void foo::a() {}
|
||||
)";
|
||||
|
||||
|
|
|
|||
|
|
@ -17,36 +17,56 @@ TEST_CASE("cpp_function_template")
|
|||
template <int I>
|
||||
using type = int;
|
||||
|
||||
/// template<typename T>
|
||||
/// T a(T const& t);
|
||||
template <typename T>
|
||||
T a(const T& t);
|
||||
|
||||
struct d
|
||||
{
|
||||
/// template<int I,typename T>
|
||||
/// static type<I> b(T);
|
||||
template <int I, typename T>
|
||||
static type<I> b(T);
|
||||
|
||||
/// template<typename T=const int>
|
||||
/// T c();
|
||||
template <typename T = const int>
|
||||
auto c() -> T;
|
||||
|
||||
/// template<typename T>
|
||||
/// operator T()const;
|
||||
template <typename T>
|
||||
operator T() const;
|
||||
|
||||
/// template<typename T>
|
||||
/// d(T const&);
|
||||
template <typename T>
|
||||
d(const T&);
|
||||
};
|
||||
|
||||
/// template<>
|
||||
/// int a(int const& t);
|
||||
template <>
|
||||
int a(const int& t);
|
||||
|
||||
/// template<>
|
||||
/// static type<0> d::b<0,int>(int);
|
||||
template <>
|
||||
type<0> d::b<0, int>(int);
|
||||
|
||||
/// template<>
|
||||
/// int d::c();
|
||||
template <>
|
||||
auto d::c() -> int;
|
||||
|
||||
/// template<>
|
||||
/// d::operator int()const;
|
||||
template <>
|
||||
d::operator int() const;
|
||||
|
||||
/// template<>
|
||||
/// d::d(int const&);
|
||||
template <>
|
||||
d::d(const int&);
|
||||
)";
|
||||
|
|
|
|||
|
|
@ -13,10 +13,22 @@ using namespace cppast;
|
|||
TEST_CASE("cpp_language_linkage")
|
||||
{
|
||||
auto code = R"(
|
||||
/// extern "C" enum a{
|
||||
/// };
|
||||
extern "C" enum a {};
|
||||
|
||||
enum b {};
|
||||
|
||||
/// extern "C++"{
|
||||
/// enum c{
|
||||
/// };
|
||||
///
|
||||
/// enum d{
|
||||
/// };
|
||||
///
|
||||
/// enum e{
|
||||
/// };
|
||||
/// }
|
||||
extern "C++" // yup
|
||||
{
|
||||
enum c {};
|
||||
|
|
@ -41,21 +53,23 @@ enum f {};
|
|||
REQUIRE(count == 2u);
|
||||
|
||||
// check enums for their correct parent
|
||||
count = test_visit<cpp_enum>(*file, [&](const cpp_enum& e) {
|
||||
if (e.name() == "a")
|
||||
check_parent(e, "\"C\"", "a");
|
||||
else if (e.name() == "b")
|
||||
check_parent(e, "cpp_language_linkage.cpp", "b");
|
||||
else if (e.name() == "c")
|
||||
check_parent(e, "\"C++\"", "c");
|
||||
else if (e.name() == "d")
|
||||
check_parent(e, "\"C++\"", "d");
|
||||
else if (e.name() == "e")
|
||||
check_parent(e, "\"C++\"", "e");
|
||||
else if (e.name() == "f")
|
||||
check_parent(e, "cpp_language_linkage.cpp", "f");
|
||||
else
|
||||
REQUIRE(false);
|
||||
});
|
||||
count = test_visit<cpp_enum>(*file,
|
||||
[&](const cpp_enum& e) {
|
||||
if (e.name() == "a")
|
||||
check_parent(e, "\"C\"", "a");
|
||||
else if (e.name() == "b")
|
||||
check_parent(e, "cpp_language_linkage.cpp", "b");
|
||||
else if (e.name() == "c")
|
||||
check_parent(e, "\"C++\"", "c");
|
||||
else if (e.name() == "d")
|
||||
check_parent(e, "\"C++\"", "d");
|
||||
else if (e.name() == "e")
|
||||
check_parent(e, "\"C++\"", "e");
|
||||
else if (e.name() == "f")
|
||||
check_parent(e, "cpp_language_linkage.cpp", "f");
|
||||
else
|
||||
REQUIRE(false);
|
||||
},
|
||||
false); // don't check code generation here
|
||||
REQUIRE(count == 6u);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,24 +14,36 @@ TEST_CASE("cpp_member_function")
|
|||
// no need to test parameters/return types
|
||||
struct foo
|
||||
{
|
||||
/// void a();
|
||||
void a();
|
||||
/// void b()noexcept;
|
||||
void b() noexcept;
|
||||
|
||||
/// void c()const;
|
||||
void c() const;
|
||||
auto d() const volatile -> void;
|
||||
/// void d()const volatile noexcept;
|
||||
auto d() const volatile noexcept -> void;
|
||||
/// void e()&;
|
||||
void e() &;
|
||||
/// void f()const volatile&&;
|
||||
void f() const volatile &&;
|
||||
|
||||
/// virtual void g();
|
||||
virtual void g();
|
||||
/// virtual void h()=0;
|
||||
virtual void h() = 0;
|
||||
|
||||
/// void i();
|
||||
void i() {}
|
||||
/// void j()=delete;
|
||||
void j() = delete;
|
||||
};
|
||||
|
||||
struct bar : foo
|
||||
{
|
||||
/// virtual void g() override;
|
||||
void g();
|
||||
/// virtual void h() override final;
|
||||
virtual auto h() -> void override final;
|
||||
};
|
||||
)";
|
||||
|
|
@ -43,7 +55,7 @@ struct bar : foo
|
|||
REQUIRE(!func.is_variadic());
|
||||
REQUIRE(!func.is_constexpr());
|
||||
REQUIRE(equal_types(idx, func.return_type(), *cpp_builtin_type::build(cpp_void)));
|
||||
if (func.name() != "b")
|
||||
if (func.name() != "b" && func.name() != "d")
|
||||
REQUIRE(!func.noexcept_condition());
|
||||
if (func.name() != "g" && func.name() != "h")
|
||||
REQUIRE(!func.virtual_info());
|
||||
|
|
@ -142,8 +154,11 @@ namespace ns
|
|||
// most of it only need to be check in member function
|
||||
struct foo
|
||||
{
|
||||
/// operator int&();
|
||||
operator int&();
|
||||
/// explicit operator bool()const;
|
||||
explicit operator bool() const;
|
||||
/// constexpr operator ns::type();
|
||||
constexpr operator ns::type();
|
||||
};
|
||||
)";
|
||||
|
|
@ -192,8 +207,11 @@ TEST_CASE("cpp_constructor")
|
|||
// only test constructor specific stuff
|
||||
struct foo
|
||||
{
|
||||
/// foo()noexcept=default;
|
||||
foo() noexcept = default;
|
||||
/// explicit foo(int);
|
||||
explicit foo(int);
|
||||
/// constexpr foo(int,char)=delete;
|
||||
constexpr foo(int, char) = delete;
|
||||
};
|
||||
)";
|
||||
|
|
@ -240,21 +258,25 @@ TEST_CASE("cpp_destructor")
|
|||
auto code = R"(
|
||||
struct a
|
||||
{
|
||||
/// ~a();
|
||||
~a();
|
||||
};
|
||||
|
||||
struct b
|
||||
{
|
||||
/// ~b()noexcept(false);
|
||||
~b() noexcept(false) {}
|
||||
};
|
||||
|
||||
struct c
|
||||
{
|
||||
/// virtual ~c()=default;
|
||||
virtual ~c() = default;
|
||||
};
|
||||
|
||||
struct d : c
|
||||
{
|
||||
/// virtual ~d() override final;
|
||||
~d() final;
|
||||
};
|
||||
)";
|
||||
|
|
|
|||
|
|
@ -13,8 +13,11 @@ TEST_CASE("cpp_member_variable")
|
|||
auto code = R"(
|
||||
struct foo
|
||||
{
|
||||
/// int a;
|
||||
int a;
|
||||
/// float b=3.14f;
|
||||
float b = 3.14f;
|
||||
/// mutable char c;
|
||||
mutable char c;
|
||||
};
|
||||
)";
|
||||
|
|
@ -59,10 +62,15 @@ TEST_CASE("cpp_bitfield")
|
|||
auto code = R"(
|
||||
struct foo
|
||||
{
|
||||
/// char a:3;
|
||||
char a : 3;
|
||||
/// mutable char b:2;
|
||||
mutable char b : 2;
|
||||
/// char:0;
|
||||
char : 0;
|
||||
/// char c:3;
|
||||
char c : 3;
|
||||
/// char:4;
|
||||
char : 4;
|
||||
};
|
||||
)";
|
||||
|
|
|
|||
|
|
@ -11,12 +11,22 @@ using namespace cppast;
|
|||
TEST_CASE("cpp_namespace")
|
||||
{
|
||||
auto code = R"(
|
||||
/// namespace a{
|
||||
/// }
|
||||
namespace a {}
|
||||
|
||||
/// inline namespace b{
|
||||
/// }
|
||||
inline namespace b {}
|
||||
|
||||
/// namespace c{
|
||||
/// namespace d{
|
||||
/// }
|
||||
/// }
|
||||
namespace c
|
||||
{
|
||||
/// namespace d{
|
||||
/// }
|
||||
namespace d {}
|
||||
}
|
||||
)";
|
||||
|
|
@ -57,18 +67,24 @@ TEST_CASE("cpp_namespace_alias")
|
|||
namespace outer {}
|
||||
namespace ns {}
|
||||
|
||||
/// namespace a=outer;
|
||||
namespace a = outer;
|
||||
/// namespace b=ns;
|
||||
namespace b = ns;
|
||||
|
||||
namespace outer
|
||||
{
|
||||
namespace ns {}
|
||||
|
||||
/// namespace c=ns;
|
||||
namespace c = ns;
|
||||
/// namespace d=::outer;
|
||||
namespace d = ::outer;
|
||||
}
|
||||
|
||||
/// namespace e=outer::ns;
|
||||
namespace e = outer::ns;
|
||||
/// namespace f=outer::c;
|
||||
namespace f = outer::c;
|
||||
)";
|
||||
|
||||
|
|
@ -117,17 +133,22 @@ TEST_CASE("cpp_using_directive")
|
|||
namespace ns1 {}
|
||||
namespace ns2 {}
|
||||
|
||||
/// using namespace ns1;
|
||||
using namespace ns1;
|
||||
/// using namespace ns2;
|
||||
using namespace ns2;
|
||||
|
||||
namespace outer
|
||||
{
|
||||
namespace ns {}
|
||||
|
||||
/// using namespace ns;
|
||||
using namespace ns;
|
||||
/// using namespace ::ns1;
|
||||
using namespace ::ns1;
|
||||
}
|
||||
|
||||
/// using namespace outer::ns;
|
||||
using namespace outer::ns;
|
||||
)";
|
||||
|
||||
|
|
@ -180,7 +201,9 @@ namespace ns2
|
|||
enum b {};
|
||||
}
|
||||
|
||||
/// using ns1::a;
|
||||
using ns1::a;
|
||||
/// using ns2::b;
|
||||
using ns2::b;
|
||||
|
||||
namespace outer
|
||||
|
|
@ -190,10 +213,13 @@ namespace outer
|
|||
enum c {};
|
||||
}
|
||||
|
||||
/// using ns::c;
|
||||
using ns::c;
|
||||
}
|
||||
|
||||
/// using outer::ns::c;
|
||||
using outer::ns::c;
|
||||
/// using outer::c;
|
||||
using outer::c;
|
||||
|
||||
namespace ns1
|
||||
|
|
@ -202,6 +228,7 @@ namespace ns1
|
|||
void d(float);
|
||||
}
|
||||
|
||||
/// using ns1::d;
|
||||
using ns1::d;
|
||||
)";
|
||||
|
||||
|
|
|
|||
|
|
@ -13,15 +13,21 @@ TEST_CASE("cpp_macro_definition")
|
|||
auto code = R"(
|
||||
#include <iostream>
|
||||
#define G
|
||||
/// #define A
|
||||
#define A
|
||||
/// #define B hello
|
||||
#define B hello
|
||||
namespace ns {}
|
||||
/// #define C(x,y) x##_name
|
||||
#define C(x, y) x##_name
|
||||
/// #define D(...) __VA_ARGS__
|
||||
#define D(...) __VA_ARGS__
|
||||
/// #define E() barbaz
|
||||
#define E() bar\
|
||||
baz
|
||||
namespace ns2
|
||||
{
|
||||
/// #define F () bar
|
||||
#define F () bar
|
||||
#undef G
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,60 +35,82 @@ using e = void;
|
|||
|
||||
cpp_entity_index idx;
|
||||
auto file = parse(idx, "cpp_template_type_parameter.cpp", code);
|
||||
auto count = test_visit<cpp_alias_template>(*file, [&](const cpp_alias_template& alias) {
|
||||
REQUIRE(equal_types(idx, alias.type_alias().underlying_type(),
|
||||
*cpp_builtin_type::build(cpp_void)));
|
||||
auto count =
|
||||
test_visit<cpp_alias_template>(*file,
|
||||
[&](const cpp_alias_template& alias) {
|
||||
REQUIRE(equal_types(idx,
|
||||
alias.type_alias().underlying_type(),
|
||||
*cpp_builtin_type::build(cpp_void)));
|
||||
|
||||
for (auto& p : alias.parameters())
|
||||
{
|
||||
REQUIRE(p.kind() == cpp_entity_kind::template_type_parameter_t);
|
||||
for (auto& p : alias.parameters())
|
||||
{
|
||||
REQUIRE(
|
||||
p.kind()
|
||||
== cpp_entity_kind::template_type_parameter_t);
|
||||
|
||||
auto& param = static_cast<const cpp_template_type_parameter&>(p);
|
||||
if (param.name() == "A")
|
||||
{
|
||||
REQUIRE(alias.name() == "a");
|
||||
REQUIRE(param.keyword() == cpp_template_keyword::keyword_typename);
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(!param.default_type());
|
||||
}
|
||||
else if (param.name() == "B")
|
||||
{
|
||||
REQUIRE(alias.name() == "b");
|
||||
REQUIRE(param.keyword() == cpp_template_keyword::keyword_class);
|
||||
REQUIRE(param.is_variadic());
|
||||
REQUIRE(!param.default_type());
|
||||
}
|
||||
else if (param.name() == "")
|
||||
{
|
||||
REQUIRE(alias.name() == "c");
|
||||
REQUIRE(param.keyword() == cpp_template_keyword::keyword_typename);
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(param.default_type().has_value());
|
||||
REQUIRE(equal_types(idx, param.default_type().value(),
|
||||
*cpp_unexposed_type::build("const int*")));
|
||||
}
|
||||
else if (param.name() == "D")
|
||||
{
|
||||
REQUIRE(alias.name() == "d");
|
||||
REQUIRE(param.keyword() == cpp_template_keyword::keyword_class);
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(param.default_type().has_value());
|
||||
REQUIRE(equal_types(idx, param.default_type().value(),
|
||||
*cpp_unexposed_type::build("decltype(1+3)")));
|
||||
}
|
||||
else if (param.name() == "E")
|
||||
{
|
||||
REQUIRE(alias.name() == "e");
|
||||
REQUIRE(param.keyword() == cpp_template_keyword::keyword_typename);
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(param.default_type().has_value());
|
||||
REQUIRE(equal_types(idx, param.default_type().value(),
|
||||
*cpp_unexposed_type::build("a<void>")));
|
||||
}
|
||||
else
|
||||
REQUIRE(false);
|
||||
}
|
||||
});
|
||||
auto& param =
|
||||
static_cast<const cpp_template_type_parameter&>(
|
||||
p);
|
||||
if (param.name() == "A")
|
||||
{
|
||||
REQUIRE(alias.name() == "a");
|
||||
REQUIRE(
|
||||
param.keyword()
|
||||
== cpp_template_keyword::keyword_typename);
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(!param.default_type());
|
||||
}
|
||||
else if (param.name() == "B")
|
||||
{
|
||||
REQUIRE(alias.name() == "b");
|
||||
REQUIRE(param.keyword()
|
||||
== cpp_template_keyword::keyword_class);
|
||||
REQUIRE(param.is_variadic());
|
||||
REQUIRE(!param.default_type());
|
||||
}
|
||||
else if (param.name() == "")
|
||||
{
|
||||
REQUIRE(alias.name() == "c");
|
||||
REQUIRE(
|
||||
param.keyword()
|
||||
== cpp_template_keyword::keyword_typename);
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(param.default_type().has_value());
|
||||
REQUIRE(equal_types(idx,
|
||||
param.default_type().value(),
|
||||
*cpp_unexposed_type::build(
|
||||
"const int*")));
|
||||
}
|
||||
else if (param.name() == "D")
|
||||
{
|
||||
REQUIRE(alias.name() == "d");
|
||||
REQUIRE(param.keyword()
|
||||
== cpp_template_keyword::keyword_class);
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(param.default_type().has_value());
|
||||
REQUIRE(equal_types(idx,
|
||||
param.default_type().value(),
|
||||
*cpp_unexposed_type::build(
|
||||
"decltype(1+3)")));
|
||||
}
|
||||
else if (param.name() == "E")
|
||||
{
|
||||
REQUIRE(alias.name() == "e");
|
||||
REQUIRE(
|
||||
param.keyword()
|
||||
== cpp_template_keyword::keyword_typename);
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(param.default_type().has_value());
|
||||
REQUIRE(equal_types(idx,
|
||||
param.default_type().value(),
|
||||
*cpp_unexposed_type::build(
|
||||
"a<void>")));
|
||||
}
|
||||
else
|
||||
REQUIRE(false);
|
||||
}
|
||||
},
|
||||
false); // can't check synopsis with comments
|
||||
REQUIRE(count == 5u);
|
||||
}
|
||||
|
||||
|
|
@ -109,57 +131,62 @@ using d = void;
|
|||
)";
|
||||
|
||||
cpp_entity_index idx;
|
||||
auto file = parse(idx, "cpp_non_type_template_parameter.cpp", code);
|
||||
auto count = test_visit<cpp_alias_template>(*file, [&](const cpp_alias_template& alias) {
|
||||
REQUIRE(equal_types(idx, alias.type_alias().underlying_type(),
|
||||
*cpp_builtin_type::build(cpp_void)));
|
||||
auto file = parse(idx, "cpp_non_type_template_parameter.cpp", code);
|
||||
auto count = test_visit<cpp_alias_template>(
|
||||
*file,
|
||||
[&](const cpp_alias_template& alias) {
|
||||
REQUIRE(equal_types(idx, alias.type_alias().underlying_type(),
|
||||
*cpp_builtin_type::build(cpp_void)));
|
||||
|
||||
for (auto& p : alias.parameters())
|
||||
{
|
||||
REQUIRE(p.kind() == cpp_entity_kind::non_type_template_parameter_t);
|
||||
for (auto& p : alias.parameters())
|
||||
{
|
||||
REQUIRE(p.kind() == cpp_entity_kind::non_type_template_parameter_t);
|
||||
|
||||
auto& param = static_cast<const cpp_non_type_template_parameter&>(p);
|
||||
if (param.name() == "A")
|
||||
{
|
||||
REQUIRE(alias.name() == "a");
|
||||
REQUIRE(equal_types(idx, param.type(), *cpp_builtin_type::build(cpp_int)));
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(!param.default_value());
|
||||
}
|
||||
else if (param.name() == "")
|
||||
{
|
||||
REQUIRE(alias.name() == "b");
|
||||
REQUIRE(equal_types(idx, param.type(),
|
||||
*cpp_pointer_type::build(cpp_builtin_type::build(cpp_char))));
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(param.default_value());
|
||||
REQUIRE(equal_expressions(param.default_value().value(),
|
||||
auto& param = static_cast<const cpp_non_type_template_parameter&>(p);
|
||||
if (param.name() == "A")
|
||||
{
|
||||
REQUIRE(alias.name() == "a");
|
||||
REQUIRE(equal_types(idx, param.type(), *cpp_builtin_type::build(cpp_int)));
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(!param.default_value());
|
||||
}
|
||||
else if (param.name() == "")
|
||||
{
|
||||
REQUIRE(alias.name() == "b");
|
||||
REQUIRE(equal_types(idx, param.type(), *cpp_pointer_type::build(
|
||||
cpp_builtin_type::build(cpp_char))));
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(param.default_value());
|
||||
REQUIRE(
|
||||
equal_expressions(param.default_value().value(),
|
||||
*cpp_literal_expression::build(cpp_builtin_type::build(
|
||||
cpp_nullptr),
|
||||
"nullptr")));
|
||||
}
|
||||
else if (param.name() == "C")
|
||||
{
|
||||
REQUIRE(alias.name() == "c");
|
||||
REQUIRE(equal_types(idx, param.type(), *cpp_builtin_type::build(cpp_int)));
|
||||
REQUIRE(param.is_variadic());
|
||||
REQUIRE(!param.default_value());
|
||||
}
|
||||
else if (param.name() == "D")
|
||||
{
|
||||
REQUIRE(alias.name() == "d");
|
||||
}
|
||||
else if (param.name() == "C")
|
||||
{
|
||||
REQUIRE(alias.name() == "c");
|
||||
REQUIRE(equal_types(idx, param.type(), *cpp_builtin_type::build(cpp_int)));
|
||||
REQUIRE(param.is_variadic());
|
||||
REQUIRE(!param.default_value());
|
||||
}
|
||||
else if (param.name() == "D")
|
||||
{
|
||||
REQUIRE(alias.name() == "d");
|
||||
|
||||
cpp_function_type::builder builder(cpp_builtin_type::build(cpp_void));
|
||||
builder.is_variadic();
|
||||
REQUIRE(equal_types(idx, param.type(), *cpp_pointer_type::build(builder.finish())));
|
||||
cpp_function_type::builder builder(cpp_builtin_type::build(cpp_void));
|
||||
builder.is_variadic();
|
||||
REQUIRE(
|
||||
equal_types(idx, param.type(), *cpp_pointer_type::build(builder.finish())));
|
||||
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(!param.default_value());
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(!param.default_value());
|
||||
}
|
||||
else
|
||||
REQUIRE(false);
|
||||
}
|
||||
else
|
||||
REQUIRE(false);
|
||||
}
|
||||
});
|
||||
},
|
||||
false); // can't check synopsis with comments
|
||||
REQUIRE(count == 4u);
|
||||
}
|
||||
|
||||
|
|
@ -187,105 +214,108 @@ using d = void;
|
|||
)";
|
||||
|
||||
cpp_entity_index idx;
|
||||
auto file = parse(idx, "cpp_template_template_parameter.cpp", code);
|
||||
auto count = test_visit<cpp_alias_template>(*file, [&](const cpp_alias_template& alias) {
|
||||
REQUIRE(equal_types(idx, alias.type_alias().underlying_type(),
|
||||
*cpp_builtin_type::build(cpp_void)));
|
||||
if (alias.name() == "def")
|
||||
return;
|
||||
auto file = parse(idx, "cpp_template_template_parameter.cpp", code);
|
||||
auto count = test_visit<cpp_alias_template>(
|
||||
*file,
|
||||
[&](const cpp_alias_template& alias) {
|
||||
REQUIRE(equal_types(idx, alias.type_alias().underlying_type(),
|
||||
*cpp_builtin_type::build(cpp_void)));
|
||||
if (alias.name() == "def")
|
||||
return;
|
||||
|
||||
for (auto& p : alias.parameters())
|
||||
{
|
||||
REQUIRE(p.kind() == cpp_entity_kind::template_template_parameter_t);
|
||||
|
||||
auto& param = static_cast<const cpp_template_template_parameter&>(p);
|
||||
REQUIRE(param.keyword() == cpp_template_keyword::keyword_class);
|
||||
if (param.name() == "A")
|
||||
for (auto& p : alias.parameters())
|
||||
{
|
||||
REQUIRE(alias.name() == "a");
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(!param.default_template());
|
||||
REQUIRE(p.kind() == cpp_entity_kind::template_template_parameter_t);
|
||||
|
||||
auto no = 0u;
|
||||
for (auto& p_param : param)
|
||||
auto& param = static_cast<const cpp_template_template_parameter&>(p);
|
||||
REQUIRE(param.keyword() == cpp_template_keyword::keyword_class);
|
||||
if (param.name() == "A")
|
||||
{
|
||||
++no;
|
||||
REQUIRE(p_param.name() == "T");
|
||||
REQUIRE(p_param.kind() == cpp_entity_kind::template_type_parameter_t);
|
||||
}
|
||||
REQUIRE(no == 1u);
|
||||
}
|
||||
else if (param.name() == "B")
|
||||
{
|
||||
REQUIRE(alias.name() == "b");
|
||||
REQUIRE(param.is_variadic());
|
||||
REQUIRE(!param.default_template());
|
||||
REQUIRE(alias.name() == "a");
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(!param.default_template());
|
||||
|
||||
auto cur = param.begin();
|
||||
REQUIRE(cur != param.end());
|
||||
REQUIRE(cur->name().empty());
|
||||
REQUIRE(cur->kind() == cpp_entity_kind::non_type_template_parameter_t);
|
||||
|
||||
++cur;
|
||||
REQUIRE(cur != param.end());
|
||||
REQUIRE(cur->name().empty());
|
||||
REQUIRE(cur->kind() == cpp_entity_kind::template_type_parameter_t);
|
||||
|
||||
++cur;
|
||||
REQUIRE(cur == param.end());
|
||||
}
|
||||
else if (param.name() == "C")
|
||||
{
|
||||
REQUIRE(alias.name() == "c");
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(param.default_template());
|
||||
|
||||
auto def = param.default_template().value();
|
||||
REQUIRE(def.name() == "ns::def");
|
||||
auto entities = def.get(idx);
|
||||
REQUIRE(entities.size() == 1u);
|
||||
REQUIRE(entities[0]->name() == "def");
|
||||
|
||||
auto no = 0u;
|
||||
for (auto& p_param : param)
|
||||
{
|
||||
++no;
|
||||
REQUIRE(p_param.name() == "");
|
||||
REQUIRE(p_param.kind() == cpp_entity_kind::non_type_template_parameter_t);
|
||||
}
|
||||
REQUIRE(no == 1u);
|
||||
}
|
||||
else if (param.name() == "D")
|
||||
{
|
||||
REQUIRE(alias.name() == "d");
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(param.default_template());
|
||||
|
||||
auto def = param.default_template().value();
|
||||
REQUIRE(def.name() == "a");
|
||||
auto entities = def.get(idx);
|
||||
REQUIRE(entities.size() == 1u);
|
||||
REQUIRE(entities[0]->name() == "a");
|
||||
|
||||
auto no = 0u;
|
||||
for (auto& p_param : param)
|
||||
{
|
||||
++no;
|
||||
REQUIRE(p_param.name() == "");
|
||||
REQUIRE(p_param.kind() == cpp_entity_kind::template_template_parameter_t);
|
||||
for (auto& p_p_param :
|
||||
static_cast<const cpp_template_template_parameter&>(p_param))
|
||||
auto no = 0u;
|
||||
for (auto& p_param : param)
|
||||
{
|
||||
++no;
|
||||
REQUIRE(p_p_param.name() == "");
|
||||
REQUIRE(p_p_param.kind() == cpp_entity_kind::template_type_parameter_t);
|
||||
REQUIRE(p_param.name() == "T");
|
||||
REQUIRE(p_param.kind() == cpp_entity_kind::template_type_parameter_t);
|
||||
}
|
||||
REQUIRE(no == 1u);
|
||||
}
|
||||
REQUIRE(no == 2u);
|
||||
else if (param.name() == "B")
|
||||
{
|
||||
REQUIRE(alias.name() == "b");
|
||||
REQUIRE(param.is_variadic());
|
||||
REQUIRE(!param.default_template());
|
||||
|
||||
auto cur = param.begin();
|
||||
REQUIRE(cur != param.end());
|
||||
REQUIRE(cur->name().empty());
|
||||
REQUIRE(cur->kind() == cpp_entity_kind::non_type_template_parameter_t);
|
||||
|
||||
++cur;
|
||||
REQUIRE(cur != param.end());
|
||||
REQUIRE(cur->name().empty());
|
||||
REQUIRE(cur->kind() == cpp_entity_kind::template_type_parameter_t);
|
||||
|
||||
++cur;
|
||||
REQUIRE(cur == param.end());
|
||||
}
|
||||
else if (param.name() == "C")
|
||||
{
|
||||
REQUIRE(alias.name() == "c");
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(param.default_template());
|
||||
|
||||
auto def = param.default_template().value();
|
||||
REQUIRE(def.name() == "ns::def");
|
||||
auto entities = def.get(idx);
|
||||
REQUIRE(entities.size() == 1u);
|
||||
REQUIRE(entities[0]->name() == "def");
|
||||
|
||||
auto no = 0u;
|
||||
for (auto& p_param : param)
|
||||
{
|
||||
++no;
|
||||
REQUIRE(p_param.name() == "");
|
||||
REQUIRE(p_param.kind() == cpp_entity_kind::non_type_template_parameter_t);
|
||||
}
|
||||
REQUIRE(no == 1u);
|
||||
}
|
||||
else if (param.name() == "D")
|
||||
{
|
||||
REQUIRE(alias.name() == "d");
|
||||
REQUIRE(!param.is_variadic());
|
||||
REQUIRE(param.default_template());
|
||||
|
||||
auto def = param.default_template().value();
|
||||
REQUIRE(def.name() == "a");
|
||||
auto entities = def.get(idx);
|
||||
REQUIRE(entities.size() == 1u);
|
||||
REQUIRE(entities[0]->name() == "a");
|
||||
|
||||
auto no = 0u;
|
||||
for (auto& p_param : param)
|
||||
{
|
||||
++no;
|
||||
REQUIRE(p_param.name() == "");
|
||||
REQUIRE(p_param.kind() == cpp_entity_kind::template_template_parameter_t);
|
||||
for (auto& p_p_param :
|
||||
static_cast<const cpp_template_template_parameter&>(p_param))
|
||||
{
|
||||
++no;
|
||||
REQUIRE(p_p_param.name() == "");
|
||||
REQUIRE(p_p_param.kind() == cpp_entity_kind::template_type_parameter_t);
|
||||
}
|
||||
}
|
||||
REQUIRE(no == 2u);
|
||||
}
|
||||
else
|
||||
REQUIRE(false);
|
||||
}
|
||||
else
|
||||
REQUIRE(false);
|
||||
}
|
||||
});
|
||||
},
|
||||
false); // can't check synopsis with comments
|
||||
REQUIRE(count == 5u);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,26 +21,26 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_
|
|||
|
||||
switch (parsed.kind())
|
||||
{
|
||||
case cpp_type_kind::builtin:
|
||||
case cpp_type_kind::builtin_t:
|
||||
return static_cast<const cpp_builtin_type&>(parsed).builtin_type_kind()
|
||||
== static_cast<const cpp_builtin_type&>(synthesized).builtin_type_kind();
|
||||
|
||||
case cpp_type_kind::user_defined:
|
||||
case cpp_type_kind::user_defined_t:
|
||||
{
|
||||
auto& user_parsed = static_cast<const cpp_user_defined_type&>(parsed);
|
||||
auto& user_synthesized = static_cast<const cpp_user_defined_type&>(synthesized);
|
||||
return equal_ref(idx, user_parsed.entity(), user_synthesized.entity());
|
||||
}
|
||||
|
||||
case cpp_type_kind::auto_:
|
||||
case cpp_type_kind::auto_t:
|
||||
return true;
|
||||
case cpp_type_kind::decltype_:
|
||||
case cpp_type_kind::decltype_t:
|
||||
return equal_expressions(static_cast<const cpp_decltype_type&>(parsed).expression(),
|
||||
static_cast<const cpp_decltype_type&>(synthesized).expression());
|
||||
case cpp_type_kind::decltype_auto:
|
||||
case cpp_type_kind::decltype_auto_t:
|
||||
return true;
|
||||
|
||||
case cpp_type_kind::cv_qualified:
|
||||
case cpp_type_kind::cv_qualified_t:
|
||||
{
|
||||
auto& cv_a = static_cast<const cpp_cv_qualified_type&>(parsed);
|
||||
auto& cv_b = static_cast<const cpp_cv_qualified_type&>(synthesized);
|
||||
|
|
@ -48,10 +48,10 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_
|
|||
&& equal_types(idx, cv_a.type(), cv_b.type());
|
||||
}
|
||||
|
||||
case cpp_type_kind::pointer:
|
||||
case cpp_type_kind::pointer_t:
|
||||
return equal_types(idx, static_cast<const cpp_pointer_type&>(parsed).pointee(),
|
||||
static_cast<const cpp_pointer_type&>(synthesized).pointee());
|
||||
case cpp_type_kind::reference:
|
||||
case cpp_type_kind::reference_t:
|
||||
{
|
||||
auto& ref_a = static_cast<const cpp_reference_type&>(parsed);
|
||||
auto& ref_b = static_cast<const cpp_reference_type&>(synthesized);
|
||||
|
|
@ -59,7 +59,7 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_
|
|||
&& equal_types(idx, ref_a.referee(), ref_b.referee());
|
||||
}
|
||||
|
||||
case cpp_type_kind::array:
|
||||
case cpp_type_kind::array_t:
|
||||
{
|
||||
auto& array_a = static_cast<const cpp_array_type&>(parsed);
|
||||
auto& array_b = static_cast<const cpp_array_type&>(synthesized);
|
||||
|
|
@ -77,7 +77,7 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_
|
|||
return equal_expressions(size_a, size_b);
|
||||
}
|
||||
|
||||
case cpp_type_kind::function:
|
||||
case cpp_type_kind::function_t:
|
||||
{
|
||||
auto& func_a = static_cast<const cpp_function_type&>(parsed);
|
||||
auto& func_b = static_cast<const cpp_function_type&>(synthesized);
|
||||
|
|
@ -98,7 +98,7 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_
|
|||
}
|
||||
return iter_a == func_a.parameter_types().end() && iter_b == func_b.parameter_types().end();
|
||||
}
|
||||
case cpp_type_kind::member_function:
|
||||
case cpp_type_kind::member_function_t:
|
||||
{
|
||||
auto& func_a = static_cast<const cpp_member_function_type&>(parsed);
|
||||
auto& func_b = static_cast<const cpp_member_function_type&>(synthesized);
|
||||
|
|
@ -121,7 +121,7 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_
|
|||
}
|
||||
return iter_a == func_a.parameter_types().end() && iter_b == func_b.parameter_types().end();
|
||||
}
|
||||
case cpp_type_kind::member_object:
|
||||
case cpp_type_kind::member_object_t:
|
||||
{
|
||||
auto& obj_a = static_cast<const cpp_member_object_type&>(parsed);
|
||||
auto& obj_b = static_cast<const cpp_member_object_type&>(synthesized);
|
||||
|
|
@ -131,14 +131,14 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_
|
|||
return equal_types(idx, obj_a.object_type(), obj_b.object_type());
|
||||
}
|
||||
|
||||
case cpp_type_kind::template_parameter:
|
||||
case cpp_type_kind::template_parameter_t:
|
||||
{
|
||||
auto& entity_parsed = static_cast<const cpp_template_parameter_type&>(parsed).entity();
|
||||
auto& entity_synthesized =
|
||||
static_cast<const cpp_template_parameter_type&>(synthesized).entity();
|
||||
return equal_ref(idx, entity_parsed, entity_synthesized);
|
||||
}
|
||||
case cpp_type_kind::template_instantiation:
|
||||
case cpp_type_kind::template_instantiation_t:
|
||||
{
|
||||
auto& inst_parsed = static_cast<const cpp_template_instantiation_type&>(parsed);
|
||||
auto& inst_synthesized = static_cast<const cpp_template_instantiation_type&>(synthesized);
|
||||
|
|
@ -179,10 +179,10 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_
|
|||
&& iter_b == inst_synthesized.arguments().end();
|
||||
}
|
||||
// TODO: implement equality when those can be parsed
|
||||
case cpp_type_kind::dependent:
|
||||
case cpp_type_kind::dependent_t:
|
||||
break;
|
||||
|
||||
case cpp_type_kind::unexposed:
|
||||
case cpp_type_kind::unexposed_t:
|
||||
return static_cast<const cpp_unexposed_type&>(parsed).name()
|
||||
== static_cast<const cpp_unexposed_type&>(synthesized).name();
|
||||
}
|
||||
|
|
@ -194,45 +194,66 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_
|
|||
// other test cases don't need that anymore
|
||||
TEST_CASE("cpp_type_alias")
|
||||
{
|
||||
const char* code = nullptr;
|
||||
const char* code = nullptr;
|
||||
auto check_code = false;
|
||||
SECTION("using")
|
||||
{
|
||||
code = R"(
|
||||
check_code = true;
|
||||
code = R"(
|
||||
// basic
|
||||
/// using a=int;
|
||||
using a = int;
|
||||
/// using b=long double const volatile;
|
||||
using b = const long double volatile;
|
||||
|
||||
// pointers
|
||||
/// using c=int*;
|
||||
using c = int*;
|
||||
/// using d=unsigned int const*;
|
||||
using d = const unsigned int*;
|
||||
/// using e=unsigned int const* volatile;
|
||||
using e = unsigned const * volatile;
|
||||
|
||||
// references
|
||||
/// using f=int&;
|
||||
using f = int&;
|
||||
/// using g=int const&&;
|
||||
using g = const int&&;
|
||||
|
||||
// user-defined types
|
||||
/// using h=c;
|
||||
using h = c;
|
||||
/// using i=d const;
|
||||
using i = const d;
|
||||
/// using j=e*;
|
||||
using j = e*;
|
||||
|
||||
// arrays
|
||||
/// using k=int[42];
|
||||
using k = int[42];
|
||||
/// using l=float*[];
|
||||
using l = float*[];
|
||||
/// using m=char[42];
|
||||
using m = char[3 * 2 + 4 ? 42 : 43];
|
||||
|
||||
// function pointers
|
||||
/// using n=void(*)(int);
|
||||
using n = void(*)(int);
|
||||
/// using o=char*(&)(int const&,...);
|
||||
using o = char*(&)(const int&,...);
|
||||
/// using p=n(*)(int,o);
|
||||
using p = n(*)(int, o);
|
||||
|
||||
struct foo {};
|
||||
|
||||
// member function pointers
|
||||
/// using q=void(foo::*)(int);
|
||||
using q = void(foo::*)(int);
|
||||
/// using r=void(foo::*)(int,...)const&;
|
||||
using r = void(foo::*)(int,...) const &;
|
||||
|
||||
// member data pointers
|
||||
/// using s=int(foo::*);
|
||||
using s = int(foo::*);
|
||||
|
||||
// user-defined types inline definition
|
||||
|
|
@ -241,12 +262,14 @@ using u = const struct u_ {}*;
|
|||
using v = struct {};
|
||||
|
||||
// decltype
|
||||
/// using w=decltype(0);
|
||||
using w = decltype(0);
|
||||
)";
|
||||
}
|
||||
SECTION("typedef")
|
||||
{
|
||||
code = R"(
|
||||
check_code = false; // will always generate using
|
||||
code = R"(
|
||||
// basic
|
||||
typedef int a;
|
||||
typedef const long double volatile b;
|
||||
|
|
@ -455,6 +478,8 @@ typedef decltype(0) w;
|
|||
{
|
||||
auto type = cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "t_"));
|
||||
REQUIRE(equal_types(idx, alias.underlying_type(), *type));
|
||||
return false; // inhibit comment check for next three entities
|
||||
// as they can't be documented (will always apply to the inline type)
|
||||
}
|
||||
else if (alias.name() == "u")
|
||||
{
|
||||
|
|
@ -462,11 +487,13 @@ typedef decltype(0) w;
|
|||
add_cv(cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "u_")),
|
||||
cpp_cv_const));
|
||||
REQUIRE(equal_types(idx, alias.underlying_type(), *type));
|
||||
return false;
|
||||
}
|
||||
else if (alias.name() == "v")
|
||||
{
|
||||
auto type = cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "v"));
|
||||
REQUIRE(equal_types(idx, alias.underlying_type(), *type));
|
||||
return false;
|
||||
}
|
||||
else if (alias.name() == "w")
|
||||
{
|
||||
|
|
@ -476,6 +503,8 @@ typedef decltype(0) w;
|
|||
}
|
||||
else
|
||||
REQUIRE(false);
|
||||
|
||||
return check_code;
|
||||
});
|
||||
REQUIRE(count == 23u);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,17 +14,25 @@ TEST_CASE("cpp_variable")
|
|||
{
|
||||
auto code = R"(
|
||||
// basic
|
||||
/// int a;
|
||||
int a;
|
||||
/// unsigned long long b=42;
|
||||
unsigned long long b = 42;
|
||||
/// float c=3.f+0.14f;
|
||||
float c = 3.f + 0.14f;
|
||||
|
||||
// with storage class specifiers
|
||||
/// extern int d;
|
||||
extern int d; // actually declaration
|
||||
/// static int e;
|
||||
static int e;
|
||||
/// thread_local int f;
|
||||
thread_local int f;
|
||||
/// static thread_local int g;
|
||||
thread_local static int g;
|
||||
|
||||
// constexpr
|
||||
/// constexpr int const h=12;
|
||||
constexpr int h = 12;
|
||||
|
||||
// inline definition
|
||||
|
|
@ -34,11 +42,15 @@ struct baz {} k{};
|
|||
static struct {} l;
|
||||
|
||||
// auto
|
||||
/// auto m=128;
|
||||
auto m = 128;
|
||||
/// auto const& n=m;
|
||||
const auto& n = m;
|
||||
|
||||
// decltype
|
||||
/// decltype(0) o;
|
||||
decltype(0) o;
|
||||
/// decltype(o) const& p=o;
|
||||
const decltype(o)& p = o;
|
||||
)";
|
||||
|
||||
|
|
@ -106,10 +118,14 @@ const decltype(o)& p = o;
|
|||
"12")),
|
||||
cpp_storage_class_none, true, false);
|
||||
else if (var.name() == "i")
|
||||
{
|
||||
check_variable(var,
|
||||
*cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "foo")),
|
||||
nullptr, cpp_storage_class_none, false, false);
|
||||
return false; // can't check code here
|
||||
}
|
||||
else if (var.name() == "j")
|
||||
{
|
||||
check_variable(var, *cpp_cv_qualified_type::build(cpp_user_defined_type::build(
|
||||
cpp_type_ref(cpp_entity_id(""),
|
||||
"bar")),
|
||||
|
|
@ -120,7 +136,10 @@ const decltype(o)& p = o;
|
|||
"bar")),
|
||||
"bar()")),
|
||||
cpp_storage_class_none, false, false);
|
||||
return false;
|
||||
}
|
||||
else if (var.name() == "k")
|
||||
{
|
||||
check_variable(var,
|
||||
*cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "baz")),
|
||||
type_safe::ref(
|
||||
|
|
@ -129,9 +148,14 @@ const decltype(o)& p = o;
|
|||
"baz")),
|
||||
"{}")),
|
||||
cpp_storage_class_none, false, false);
|
||||
return false;
|
||||
}
|
||||
else if (var.name() == "l")
|
||||
{
|
||||
check_variable(var, *cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "")),
|
||||
nullptr, cpp_storage_class_static, false, false);
|
||||
return false;
|
||||
}
|
||||
else if (var.name() == "m")
|
||||
check_variable(var, *cpp_auto_type::build(),
|
||||
type_safe::ref(
|
||||
|
|
@ -167,6 +191,8 @@ const decltype(o)& p = o;
|
|||
cpp_storage_class_none, false, false);
|
||||
else
|
||||
REQUIRE(false);
|
||||
|
||||
return true;
|
||||
});
|
||||
REQUIRE(count == 16u);
|
||||
}
|
||||
|
|
@ -176,8 +202,11 @@ TEST_CASE("static cpp_variable")
|
|||
auto code = R"(
|
||||
struct test
|
||||
{
|
||||
/// static int a;
|
||||
static int a;
|
||||
/// static int const b;
|
||||
static const int b;
|
||||
/// static thread_local int c;
|
||||
static thread_local int c;
|
||||
};
|
||||
)";
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <cppast/code_generator.hpp>
|
||||
#include <cppast/cpp_entity_kind.hpp>
|
||||
#include <cppast/cpp_expression.hpp>
|
||||
#include <cppast/cpp_type.hpp>
|
||||
|
|
@ -39,8 +40,72 @@ inline std::unique_ptr<cppast::cpp_file> parse(const cppast::cpp_entity_index& i
|
|||
return result;
|
||||
}
|
||||
|
||||
class test_generator : public cppast::code_generator
|
||||
{
|
||||
public:
|
||||
const std::string& str() const noexcept
|
||||
{
|
||||
return str_;
|
||||
}
|
||||
|
||||
private:
|
||||
void do_indent() override
|
||||
{
|
||||
++indent_;
|
||||
}
|
||||
|
||||
void do_unindent() override
|
||||
{
|
||||
if (indent_)
|
||||
--indent_;
|
||||
}
|
||||
|
||||
void do_write_token_seq(cppast::string_view tokens)
|
||||
{
|
||||
if (was_newline_)
|
||||
{
|
||||
str_ += std::string(indent_ * 2u, ' ');
|
||||
was_newline_ = false;
|
||||
}
|
||||
str_ += tokens.c_str();
|
||||
}
|
||||
|
||||
void do_write_newline() override
|
||||
{
|
||||
str_ += "\n";
|
||||
was_newline_ = true;
|
||||
}
|
||||
|
||||
std::string str_;
|
||||
unsigned indent_ = 0;
|
||||
bool was_newline_ = false;
|
||||
};
|
||||
|
||||
inline std::string get_code(const cppast::cpp_entity& e)
|
||||
{
|
||||
test_generator generator;
|
||||
cppast::generate_code(generator, e);
|
||||
auto str = generator.str();
|
||||
if (!str.empty() && str.back() == '\n')
|
||||
str.pop_back();
|
||||
return str;
|
||||
}
|
||||
|
||||
template <typename Func, typename T>
|
||||
auto visit_callback(bool, Func f, const T& t) -> decltype(f(t) == true)
|
||||
{
|
||||
return f(t);
|
||||
}
|
||||
|
||||
template <typename Func, typename T>
|
||||
bool visit_callback(int check, Func f, const T& t)
|
||||
{
|
||||
f(t);
|
||||
return check == 1;
|
||||
}
|
||||
|
||||
template <typename T, typename Func>
|
||||
unsigned test_visit(const cppast::cpp_file& file, Func f)
|
||||
unsigned test_visit(const cppast::cpp_file& file, Func f, bool check_code = true)
|
||||
{
|
||||
auto count = 0u;
|
||||
cppast::visit(file, [&](const cppast::cpp_entity& e, cppast::visitor_info info) {
|
||||
|
|
@ -49,9 +114,16 @@ unsigned test_visit(const cppast::cpp_file& file, Func f)
|
|||
|
||||
if (e.kind() == T::kind())
|
||||
{
|
||||
auto& obj = static_cast<const T&>(e);
|
||||
f(obj);
|
||||
auto& obj = static_cast<const T&>(e);
|
||||
auto check_cur = visit_callback(check_code, f, obj);
|
||||
++count;
|
||||
|
||||
if (check_cur)
|
||||
{
|
||||
INFO(e.name());
|
||||
REQUIRE(e.comment());
|
||||
REQUIRE(e.comment().value() == get_code(e));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -88,11 +160,11 @@ inline bool equal_expressions(const cppast::cpp_expression& parsed,
|
|||
return false;
|
||||
switch (parsed.kind())
|
||||
{
|
||||
case cpp_expression_kind::unexposed:
|
||||
case cpp_expression_kind::unexposed_t:
|
||||
return static_cast<const cpp_unexposed_expression&>(parsed).expression()
|
||||
== static_cast<const cpp_unexposed_expression&>(synthesized).expression();
|
||||
|
||||
case cpp_expression_kind::literal:
|
||||
case cpp_expression_kind::literal_t:
|
||||
return static_cast<const cpp_literal_expression&>(parsed).value()
|
||||
== static_cast<const cpp_literal_expression&>(synthesized).value();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue