Add and parse cpp_static_assert
This commit is contained in:
parent
d125869df5
commit
4db09778b5
14 changed files with 200 additions and 6 deletions
|
|
@ -57,6 +57,8 @@ namespace cppast
|
|||
class_template_t,
|
||||
class_template_specialization_t,
|
||||
|
||||
static_assert_t,
|
||||
|
||||
unexposed_t,
|
||||
|
||||
count,
|
||||
|
|
|
|||
52
include/cppast/cpp_static_assert.hpp
Normal file
52
include/cppast/cpp_static_assert.hpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// 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.
|
||||
|
||||
#ifndef CPPAST_CPP_STATIC_ASSERT_HPP_INCLUDED
|
||||
#define CPPAST_CPP_STATIC_ASSERT_HPP_INCLUDED
|
||||
|
||||
#include <cppast/cpp_entity.hpp>
|
||||
#include <cppast/cpp_expression.hpp>
|
||||
|
||||
namespace cppast
|
||||
{
|
||||
class cpp_static_assert : public cpp_entity
|
||||
{
|
||||
public:
|
||||
static cpp_entity_kind kind() noexcept;
|
||||
|
||||
/// \returns A newly created `static_assert()` entity.
|
||||
/// \notes It will not be registered as nothing can refer to it.
|
||||
static std::unique_ptr<cpp_static_assert> build(std::unique_ptr<cpp_expression> expr,
|
||||
std::string msg)
|
||||
{
|
||||
return std::unique_ptr<cpp_static_assert>(
|
||||
new cpp_static_assert(std::move(expr), std::move(msg)));
|
||||
}
|
||||
|
||||
/// \returns A reference to the [cppast::cpp_expression]() that is being asserted.
|
||||
const cpp_expression& expression() const noexcept
|
||||
{
|
||||
return *expr_;
|
||||
}
|
||||
|
||||
/// \returns A reference to the message of the assertion.
|
||||
const std::string& message() const noexcept
|
||||
{
|
||||
return msg_;
|
||||
}
|
||||
|
||||
private:
|
||||
cpp_static_assert(std::unique_ptr<cpp_expression> expr, std::string msg)
|
||||
: cpp_entity(""), expr_(std::move(expr)), msg_(std::move(msg))
|
||||
{
|
||||
}
|
||||
|
||||
cpp_entity_kind do_get_entity_kind() const noexcept override;
|
||||
|
||||
std::unique_ptr<cpp_expression> expr_;
|
||||
std::string msg_;
|
||||
};
|
||||
} // namespace cppast
|
||||
|
||||
#endif // CPPAST_CPP_STATIC_ASSERT_HPP_INCLUDED
|
||||
|
|
@ -32,6 +32,7 @@ set(header
|
|||
../include/cppast/cpp_member_variable.hpp
|
||||
../include/cppast/cpp_namespace.hpp
|
||||
../include/cppast/cpp_preprocessor.hpp
|
||||
../include/cppast/cpp_static_assert.hpp
|
||||
../include/cppast/cpp_storage_class_specifiers.hpp
|
||||
../include/cppast/cpp_template.hpp
|
||||
../include/cppast/cpp_template_parameter.hpp
|
||||
|
|
@ -64,6 +65,7 @@ set(source
|
|||
cpp_member_variable.cpp
|
||||
cpp_namespace.cpp
|
||||
cpp_preprocessor.cpp
|
||||
cpp_static_assert.cpp
|
||||
cpp_template_parameter.cpp
|
||||
cpp_type.cpp
|
||||
cpp_type_alias.cpp
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <cppast/cpp_member_variable.hpp>
|
||||
#include <cppast/cpp_namespace.hpp>
|
||||
#include <cppast/cpp_preprocessor.hpp>
|
||||
#include <cppast/cpp_static_assert.hpp>
|
||||
#include <cppast/cpp_template_parameter.hpp>
|
||||
#include <cppast/cpp_type_alias.hpp>
|
||||
#include <cppast/cpp_variable.hpp>
|
||||
|
|
@ -843,6 +844,18 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
void generate_static_assert(code_generator& generator, const cpp_static_assert& assert)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(assert), false);
|
||||
if (output)
|
||||
{
|
||||
output << keyword("static_assert") << punctuation("(");
|
||||
detail::write_expression(output, assert.expression());
|
||||
output << punctuation(",") << string_literal('"' + assert.message() + '"');
|
||||
output << punctuation(");") << newl;
|
||||
}
|
||||
}
|
||||
|
||||
void generate_unexposed(code_generator& generator, const cpp_unexposed_entity& entity)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(entity), false);
|
||||
|
|
@ -904,6 +917,8 @@ void cppast::generate_code(code_generator& generator, const cpp_entity& e)
|
|||
CPPAST_DETAIL_HANDLE(class_template)
|
||||
CPPAST_DETAIL_HANDLE(class_template_specialization)
|
||||
|
||||
CPPAST_DETAIL_HANDLE(static_assert)
|
||||
|
||||
case cpp_entity_kind::unexposed_t:
|
||||
generate_unexposed(generator, static_cast<const cpp_unexposed_entity&>(e));
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -88,6 +88,9 @@ const char* cppast::to_string(cpp_entity_kind kind) noexcept
|
|||
case cpp_entity_kind::class_template_specialization_t:
|
||||
return "class template specialization";
|
||||
|
||||
case cpp_entity_kind::static_assert_t:
|
||||
return "static_assert";
|
||||
|
||||
case cpp_entity_kind::unexposed_t:
|
||||
return "unexposed entity";
|
||||
|
||||
|
|
@ -137,6 +140,7 @@ bool cppast::is_function(cpp_entity_kind kind) noexcept
|
|||
case cpp_entity_kind::function_template_specialization_t:
|
||||
case cpp_entity_kind::class_template_t:
|
||||
case cpp_entity_kind::class_template_specialization_t:
|
||||
case cpp_entity_kind::static_assert_t:
|
||||
case cpp_entity_kind::unexposed_t:
|
||||
case cpp_entity_kind::count:
|
||||
break;
|
||||
|
|
@ -184,6 +188,7 @@ bool cppast::is_parameter(cpp_entity_kind kind) noexcept
|
|||
case cpp_entity_kind::function_template_specialization_t:
|
||||
case cpp_entity_kind::class_template_t:
|
||||
case cpp_entity_kind::class_template_specialization_t:
|
||||
case cpp_entity_kind::static_assert_t:
|
||||
case cpp_entity_kind::unexposed_t:
|
||||
case cpp_entity_kind::count:
|
||||
break;
|
||||
|
|
@ -230,6 +235,7 @@ bool cppast::is_template(cpp_entity_kind kind) noexcept
|
|||
case cpp_entity_kind::template_type_parameter_t:
|
||||
case cpp_entity_kind::non_type_template_parameter_t:
|
||||
case cpp_entity_kind::template_template_parameter_t:
|
||||
case cpp_entity_kind::static_assert_t:
|
||||
case cpp_entity_kind::unexposed_t:
|
||||
case cpp_entity_kind::count:
|
||||
break;
|
||||
|
|
@ -277,6 +283,7 @@ bool cppast::is_template_specialization(cpp_entity_kind kind) noexcept
|
|||
case cpp_entity_kind::variable_template_t:
|
||||
case cpp_entity_kind::function_template_t:
|
||||
case cpp_entity_kind::class_template_t:
|
||||
case cpp_entity_kind::static_assert_t:
|
||||
case cpp_entity_kind::unexposed_t:
|
||||
case cpp_entity_kind::count:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ namespace
|
|||
case cpp_entity_kind::function_template_specialization_t:
|
||||
case cpp_entity_kind::class_template_t:
|
||||
case cpp_entity_kind::class_template_specialization_t:
|
||||
case cpp_entity_kind::static_assert_t:
|
||||
case cpp_entity_kind::unexposed_t:
|
||||
return nullptr;
|
||||
|
||||
|
|
|
|||
19
src/cpp_static_assert.cpp
Normal file
19
src/cpp_static_assert.cpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// 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_static_assert.hpp>
|
||||
|
||||
#include <cppast/cpp_entity_kind.hpp>
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
cppast::cpp_entity_kind cpp_static_assert::kind() noexcept
|
||||
{
|
||||
return cpp_entity_kind::static_assert_t;
|
||||
}
|
||||
|
||||
cppast::cpp_entity_kind cpp_static_assert::do_get_entity_kind() const noexcept
|
||||
{
|
||||
return kind();
|
||||
}
|
||||
|
|
@ -113,6 +113,7 @@ bool detail::cpp_type_ref_predicate::operator()(const cpp_entity& e)
|
|||
case cpp_entity_kind::function_template_specialization_t:
|
||||
case cpp_entity_kind::class_template_t:
|
||||
case cpp_entity_kind::class_template_specialization_t:
|
||||
case cpp_entity_kind::static_assert_t:
|
||||
case cpp_entity_kind::unexposed_t:
|
||||
case cpp_entity_kind::count:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@
|
|||
#include "parse_functions.hpp"
|
||||
|
||||
#include <cppast/cpp_storage_class_specifiers.hpp>
|
||||
#include <cppast/cpp_static_assert.hpp>
|
||||
|
||||
#include "libclang_visitor.hpp"
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
|
|
@ -153,6 +156,9 @@ std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& co
|
|||
case CXCursor_ClassTemplatePartialSpecialization:
|
||||
return parse_cpp_class_template_specialization(context, cur);
|
||||
|
||||
case CXCursor_StaticAssert:
|
||||
return parse_cpp_static_assert(context, cur);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -178,3 +184,39 @@ catch (parse_error& ex)
|
|||
context.logger->log("libclang parser", ex.get_diagnostic());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_cpp_static_assert(const detail::parse_context& context,
|
||||
const CXCursor& cur)
|
||||
{
|
||||
DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_StaticAssert, detail::assert_handler{});
|
||||
|
||||
std::unique_ptr<cpp_expression> expr;
|
||||
std::string msg;
|
||||
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||
if (!expr)
|
||||
{
|
||||
DEBUG_ASSERT(clang_isExpression(clang_getCursorKind(child)),
|
||||
detail::parse_error_handler{}, cur,
|
||||
"unexpected child cursor of static assert");
|
||||
expr = detail::parse_expression(context, child);
|
||||
}
|
||||
else if (msg.empty())
|
||||
{
|
||||
DEBUG_ASSERT(clang_getCursorKind(child) == CXCursor_StringLiteral,
|
||||
detail::parse_error_handler{}, cur,
|
||||
"unexpected child cursor of static assert");
|
||||
msg = detail::get_cursor_name(child).c_str();
|
||||
DEBUG_ASSERT(msg.front() == '"' && msg.back() == '"', detail::parse_error_handler{},
|
||||
cur, "unexpected name format");
|
||||
msg.pop_back();
|
||||
msg.erase(msg.begin());
|
||||
}
|
||||
else
|
||||
DEBUG_UNREACHABLE(detail::parse_error_handler{}, cur,
|
||||
"unexpected child cursor of static assert");
|
||||
});
|
||||
|
||||
auto result = cpp_static_assert::build(std::move(expr), std::move(msg));
|
||||
context.comments.match(*result, cur);
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,6 +156,9 @@ namespace cppast
|
|||
std::unique_ptr<cpp_entity> parse_cpp_class_template_specialization(
|
||||
const parse_context& context, const CXCursor& cur);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_static_assert(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
|
||||
// parent_cur: used when parsing templates or friends
|
||||
std::unique_ptr<cpp_entity> parse_entity(
|
||||
const parse_context& context, const CXCursor& cur,
|
||||
|
|
|
|||
|
|
@ -183,13 +183,14 @@ namespace
|
|||
while (!token_after_is(tu, file, cur, end, ";"))
|
||||
end = get_next_location(tu, file, end);
|
||||
}
|
||||
else if (clang_isExpression(kind)
|
||||
#if CINDEX_VERSION_MINOR < 37
|
||||
|| kind == CXCursor_CXXBaseSpecifier || kind == CXCursor_TemplateTypeParameter
|
||||
#endif
|
||||
|| kind == CXCursor_FieldDecl || kind == CXCursor_ParmDecl
|
||||
else if (kind == CXCursor_FieldDecl || kind == CXCursor_ParmDecl
|
||||
|| kind == CXCursor_NonTypeTemplateParameter
|
||||
|| kind == CXCursor_TemplateTemplateParameter)
|
||||
|| kind == CXCursor_TemplateTemplateParameter
|
||||
#if CINDEX_VERSION_MINOR < 37
|
||||
|| clang_isExpression(kind) || kind == CXCursor_CXXBaseSpecifier
|
||||
|| kind == CXCursor_TemplateTypeParameter
|
||||
#endif
|
||||
)
|
||||
// need to shrink range by one
|
||||
end = get_next_location(tu, file, end, -1);
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ bool detail::visit(const cpp_entity& e, detail::visitor_callback_t cb, void* fun
|
|||
case cpp_entity_kind::template_type_parameter_t:
|
||||
case cpp_entity_kind::non_type_template_parameter_t:
|
||||
case cpp_entity_kind::template_template_parameter_t:
|
||||
case cpp_entity_kind::static_assert_t:
|
||||
case cpp_entity_kind::unexposed_t:
|
||||
return cb(functor, e, {visitor_info::leaf_entity, last_child});
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ set(tests
|
|||
cpp_member_variable.cpp
|
||||
cpp_namespace.cpp
|
||||
cpp_preprocessor.cpp
|
||||
cpp_static_assert.cpp
|
||||
cpp_template_parameter.cpp
|
||||
cpp_type_alias.cpp
|
||||
cpp_variable.cpp)
|
||||
|
|
|
|||
47
test/cpp_static_assert.cpp
Normal file
47
test/cpp_static_assert.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// 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_static_assert.hpp>
|
||||
|
||||
#include "test_parser.hpp"
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
TEST_CASE("cpp_static_assert")
|
||||
{
|
||||
auto code = R"(
|
||||
/// static_assert(true,"");
|
||||
static_assert(true, "");
|
||||
/// static_assert(true||false,"a");
|
||||
static_assert(true || false, "a");
|
||||
|
||||
template <bool B>
|
||||
struct foo
|
||||
{
|
||||
/// static_assert(!B,"b");
|
||||
static_assert(!B, "b");
|
||||
};
|
||||
)";
|
||||
|
||||
cpp_entity_index idx;
|
||||
auto file = parse(idx, "cpp_static_assert.cpp", code);
|
||||
auto count = test_visit<cpp_static_assert>(*file, [&](const cpp_static_assert& assert) {
|
||||
auto bool_t = cpp_builtin_type::build(cpp_builtin_type_kind::cpp_bool);
|
||||
|
||||
REQUIRE(assert.name().empty());
|
||||
if (assert.message() == "")
|
||||
REQUIRE(equal_expressions(assert.expression(),
|
||||
*cpp_literal_expression::build(std::move(bool_t), "true")));
|
||||
else if (assert.message() == "a")
|
||||
REQUIRE(equal_expressions(assert.expression(),
|
||||
*cpp_unexposed_expression::build(std::move(bool_t),
|
||||
"true||false")));
|
||||
else if (assert.message() == "b")
|
||||
REQUIRE(equal_expressions(assert.expression(),
|
||||
*cpp_unexposed_expression::build(std::move(bool_t), "!B")));
|
||||
else
|
||||
REQUIRE(false);
|
||||
});
|
||||
REQUIRE(count == 3u);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue