Add and parse cpp_static_assert

This commit is contained in:
Jonathan Müller 2017-04-11 20:21:25 +02:00
commit 4db09778b5
14 changed files with 200 additions and 6 deletions

View file

@ -57,6 +57,8 @@ namespace cppast
class_template_t,
class_template_specialization_t,
static_assert_t,
unexposed_t,
count,

View 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

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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
View 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();
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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,

View file

@ -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);

View file

@ -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});

View file

@ -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)

View 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);
}