Implement attribute parsing
This commit is contained in:
parent
151e0b1a81
commit
ccb2aaa189
15 changed files with 512 additions and 86 deletions
|
|
@ -11,6 +11,7 @@ endif()
|
|||
set(tests
|
||||
code_generator.cpp
|
||||
cpp_alias_template.cpp
|
||||
cpp_attribute.cpp
|
||||
cpp_class.cpp
|
||||
cpp_class_template.cpp
|
||||
cpp_enum.cpp
|
||||
|
|
|
|||
198
test/cpp_attribute.cpp
Normal file
198
test/cpp_attribute.cpp
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
// 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/cpp_attribute.hpp>
|
||||
|
||||
#include <cppast/cpp_function.hpp>
|
||||
|
||||
#include "test_parser.hpp"
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
TEST_CASE("cpp_attribute")
|
||||
{
|
||||
auto code = R"(
|
||||
// multiple attributes
|
||||
[[attribute1]] void [[attribute2]] a();
|
||||
[[attribute1, attribute2]] void b();
|
||||
|
||||
// variadic attributes - not actually supported by clang
|
||||
//[[variadic...]] void c();
|
||||
|
||||
// scoped attributes
|
||||
[[ns::attribute]] void d();
|
||||
|
||||
// argument attributes
|
||||
[[attribute(arg1, arg2, +(){}, 42, "Hello!")]] void e();
|
||||
|
||||
// all of the above
|
||||
[[ns::attribute(+, -, 0 4), other_attribute]] void f();
|
||||
|
||||
// known attributes
|
||||
[[deprecated]] void g();
|
||||
[[maybe_unused]] void h();
|
||||
[[nodiscard]] int i();
|
||||
[[noreturn]] void j();
|
||||
)";
|
||||
|
||||
auto file = parse({}, "cpp_attribute.cpp", code);
|
||||
|
||||
auto check_attribute = [](const cpp_attribute& attr, const char* name,
|
||||
type_safe::optional<std::string> scope, bool variadic,
|
||||
const char* args = "",
|
||||
cpp_attribute_kind kind = cpp_attribute_kind::unknown) {
|
||||
REQUIRE(attr.kind() == kind);
|
||||
REQUIRE(attr.name() == name);
|
||||
REQUIRE(attr.scope() == scope);
|
||||
REQUIRE(attr.is_variadic() == variadic);
|
||||
|
||||
if (attr.arguments())
|
||||
REQUIRE(attr.arguments().value().as_string() == args);
|
||||
else
|
||||
REQUIRE(*args == '\0');
|
||||
};
|
||||
|
||||
auto count =
|
||||
test_visit<cpp_function>(*file,
|
||||
[&](const cpp_entity& e) {
|
||||
auto& attributes = e.attributes();
|
||||
REQUIRE(attributes.size() >= 1u);
|
||||
auto& attr = attributes.front();
|
||||
|
||||
if (e.name() == "a" || e.name() == "b")
|
||||
{
|
||||
REQUIRE(attributes.size() == 2u);
|
||||
check_attribute(attr, "attribute1", type_safe::nullopt,
|
||||
false);
|
||||
check_attribute(attributes[1u], "attribute2",
|
||||
type_safe::nullopt, false);
|
||||
}
|
||||
else if (e.name() == "c")
|
||||
check_attribute(attr, "variadic", type_safe::nullopt,
|
||||
true);
|
||||
else if (e.name() == "d")
|
||||
check_attribute(attr, "attribute", "ns", false);
|
||||
else if (e.name() == "e")
|
||||
check_attribute(attr, "attribute", type_safe::nullopt,
|
||||
false, R"(arg1,arg2,+(){},42,"Hello!")");
|
||||
else if (e.name() == "f")
|
||||
{
|
||||
REQUIRE(attributes.size() == 2u);
|
||||
check_attribute(attr, "attribute", "ns", false, "+,-,0 4");
|
||||
check_attribute(attributes[1u], "other_attribute",
|
||||
type_safe::nullopt, false);
|
||||
}
|
||||
else if (e.name() == "g")
|
||||
check_attribute(attr, "deprecated", type_safe::nullopt,
|
||||
false, "", cpp_attribute_kind::deprecated);
|
||||
else if (e.name() == "h")
|
||||
check_attribute(attr, "maybe_unused", type_safe::nullopt,
|
||||
false, "",
|
||||
cpp_attribute_kind::maybe_unused);
|
||||
else if (e.name() == "i")
|
||||
check_attribute(attr, "nodiscard", type_safe::nullopt,
|
||||
false, "", cpp_attribute_kind::nodiscard);
|
||||
else if (e.name() == "j")
|
||||
check_attribute(attr, "noreturn", type_safe::nullopt,
|
||||
false, "", cpp_attribute_kind::noreturn);
|
||||
},
|
||||
false);
|
||||
REQUIRE(count == 9);
|
||||
}
|
||||
|
||||
TEST_CASE("cpp_attribute matching")
|
||||
{
|
||||
auto code = R"(
|
||||
// classes
|
||||
struct [[a]] a {};
|
||||
class [[b]] b {};
|
||||
|
||||
template <typename T>
|
||||
class [[c]] c {};
|
||||
template <typename T>
|
||||
class [[c]] c<T*> {};
|
||||
template <>
|
||||
class [[c]] c<int> {};
|
||||
|
||||
// enums
|
||||
enum [[e]] e {};
|
||||
enum class [[f]] f
|
||||
{
|
||||
a [[a]],
|
||||
b [[b]] = 42,
|
||||
};
|
||||
|
||||
// functions
|
||||
[[g]] void g();
|
||||
void [[h]] h();
|
||||
void i [[i]] ();
|
||||
void j() [[j]];
|
||||
auto k() -> int [[k]];
|
||||
|
||||
struct [[member_functions]] member_functions
|
||||
{
|
||||
void a() [[a]];
|
||||
void b() const && [[b]];
|
||||
virtual void c() [[c]] final;
|
||||
virtual void d() [[d]] = 0;
|
||||
|
||||
[[member_functions]] member_functions();
|
||||
member_functions(const member_functions&) [[member_functions]];
|
||||
};
|
||||
|
||||
// variables
|
||||
[[l]] const int l = 42;
|
||||
static void* [[m]] m;
|
||||
|
||||
void [[function_params]] function_params
|
||||
([[a]] int a, int [[b]] b, int c [[c]] = 42);
|
||||
|
||||
struct [[members]] members
|
||||
{
|
||||
int [[a]] a;
|
||||
int [[b]] b : 2;
|
||||
};
|
||||
|
||||
struct [[bases]] bases
|
||||
: [[a]] public a,
|
||||
[[members]] members
|
||||
{};
|
||||
|
||||
// namespace
|
||||
namespace [[n]] n {}
|
||||
|
||||
// type aliases
|
||||
using o [[o]] = int;
|
||||
|
||||
template <typename T>
|
||||
using p [[p]] = T;
|
||||
)";
|
||||
|
||||
auto file = parse({}, "cpp_attribute__matching.cpp", code);
|
||||
|
||||
auto count = 0u;
|
||||
auto check = [&](const cppast::cpp_entity& e) {
|
||||
INFO(e.name());
|
||||
REQUIRE(e.attributes().size() == 1u);
|
||||
REQUIRE(e.attributes().begin()->name() == e.name());
|
||||
++count;
|
||||
};
|
||||
|
||||
visit(*file, [&](const cppast::cpp_entity& e, const cppast::visitor_info& info) {
|
||||
if (info.event != cppast::visitor_info::container_entity_exit
|
||||
&& e.kind() != cppast::cpp_file::kind() && !is_friended(e) && !is_templated(e))
|
||||
{
|
||||
check(e);
|
||||
if (e.kind() == cppast::cpp_function::kind())
|
||||
for (auto& param : static_cast<const cppast::cpp_function&>(e).parameters())
|
||||
check(param);
|
||||
else if (e.kind() == cppast::cpp_class::kind())
|
||||
for (auto& base : static_cast<const cppast::cpp_class&>(e).bases())
|
||||
check(base);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
REQUIRE(count == 36u);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue