// Copyright (C) 2017 Jonathan Müller // This file is subject to the license terms in the LICENSE file // found in the top-level directory of this distribution. #include #include "test_parser.hpp" using namespace cppast; TEST_CASE("cpp_variable") { auto code = R"( // basic int a; unsigned long long b = 42; float c = 3.f + 0.14f; // with storage class specifiers extern int d; // actually declaration static int e; thread_local int f; thread_local static int g; // constexpr constexpr int h = 12; // inline definition struct foo {} i; const struct bar {} j = bar(); struct baz {} k{}; static struct {} l; )"; cpp_entity_index idx; auto check_variable = [&](const cpp_variable& var, const cpp_type& type, type_safe::optional_ref default_value, int storage_class, bool is_constexpr, bool is_declaration) { if (is_declaration) { REQUIRE(var.is_declaration()); REQUIRE(!var.is_definition()); } else { REQUIRE(var.is_definition()); REQUIRE(!var.is_declaration()); } REQUIRE(equal_types(idx, var.type(), type)); if (var.default_value()) { REQUIRE(default_value); REQUIRE(equal_expressions(var.default_value().value(), default_value.value())); } else REQUIRE(!default_value); REQUIRE(var.storage_class() == storage_class); REQUIRE(var.is_constexpr() == is_constexpr); }; auto file = parse(idx, "cpp_variable.cpp", code); auto int_type = cpp_builtin_type::build("int"); auto count = test_visit(*file, [&](const cpp_variable& var) { if (var.name() == "a") check_variable(var, *int_type, nullptr, cpp_storage_class_none, false, false); else if (var.name() == "b") check_variable(var, *cpp_builtin_type::build("unsigned long long"), // unexposed due to implicit cast, I think type_safe::ref( *cpp_unexposed_expression::build(cpp_builtin_type::build("int"), "42")), cpp_storage_class_none, false, false); else if (var.name() == "c") check_variable(var, *cpp_builtin_type::build("float"), type_safe::ref( *cpp_unexposed_expression::build(cpp_builtin_type::build("float"), "3.f+0.14f")), cpp_storage_class_none, false, false); else if (var.name() == "d") check_variable(var, *int_type, nullptr, cpp_storage_class_extern, false, true); else if (var.name() == "e") check_variable(var, *int_type, nullptr, cpp_storage_class_static, false, false); else if (var.name() == "f") check_variable(var, *int_type, nullptr, cpp_storage_class_thread_local, false, false); else if (var.name() == "g") check_variable(var, *int_type, nullptr, cpp_storage_class_static | cpp_storage_class_thread_local, false, false); else if (var.name() == "h") check_variable(var, *cpp_cv_qualified_type::build(cpp_builtin_type::build("int"), cpp_cv_const), type_safe::ref( *cpp_literal_expression::build(cpp_builtin_type::build("int"), "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); 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")), cpp_cv_const), type_safe::ref( *cpp_unexposed_expression::build(cpp_user_defined_type::build( cpp_type_ref(cpp_entity_id(""), "bar")), "bar()")), cpp_storage_class_none, false, false); else if (var.name() == "k") check_variable(var, *cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "baz")), type_safe::ref( *cpp_unexposed_expression::build(cpp_user_defined_type::build( cpp_type_ref(cpp_entity_id(""), "baz")), "{}")), cpp_storage_class_none, false, 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); else REQUIRE(false); }); REQUIRE(count == 12u); } TEST_CASE("static cpp_variable") { auto code = R"( struct test { static int a; static const int b; static thread_local int c; }; )"; auto file = parse({}, "static_cpp_variable.cpp", code); auto count = test_visit(*file, [&](const cpp_variable& var) { REQUIRE(var.is_declaration()); REQUIRE(!var.is_definition()); REQUIRE(!var.default_value()); REQUIRE(!var.is_constexpr()); REQUIRE(is_static(var.storage_class())); if (var.name() == "a") REQUIRE(equal_types({}, var.type(), *cpp_builtin_type::build("int"))); else if (var.name() == "b") REQUIRE(equal_types({}, var.type(), *cpp_cv_qualified_type::build(cpp_builtin_type::build("int"), cpp_cv_const))); else if (var.name() == "c") { REQUIRE(equal_types({}, var.type(), *cpp_builtin_type::build("int"))); REQUIRE(is_thread_local(var.storage_class())); } else REQUIRE(false); }); REQUIRE(count == 3u); }