Pass current access specifier to visitors

This commit is contained in:
Jonathan Müller 2017-07-19 13:00:40 +02:00
commit 0d549ce3d1
9 changed files with 295 additions and 193 deletions

View file

@ -15,6 +15,8 @@
namespace cppast namespace cppast
{ {
enum cpp_access_specifier_kind : int;
/// A simple string view implementation, like [std::string_view](). /// A simple string view implementation, like [std::string_view]().
/// ///
/// It "views" - stores a pointer to - some kind of string. /// It "views" - stores a pointer to - some kind of string.
@ -174,8 +176,9 @@ namespace cppast
public: public:
/// \effects Creates it giving the generator and the entity. /// \effects Creates it giving the generator and the entity.
explicit output(type_safe::object_ref<code_generator> gen, explicit output(type_safe::object_ref<code_generator> gen,
type_safe::object_ref<const cpp_entity> e) type_safe::object_ref<const cpp_entity> e,
: gen_(gen), e_(e), options_(gen->do_get_options(*e)) cppast::cpp_access_specifier_kind access)
: gen_(gen), e_(e), options_(gen->do_get_options(*e, access))
{ {
gen_->on_begin(*e_); gen_->on_begin(*e_);
} }
@ -205,9 +208,9 @@ namespace cppast
} }
/// \returns The generation options for the given entity. /// \returns The generation options for the given entity.
generation_options options(const cpp_entity& e) const generation_options options(const cpp_entity& e, cpp_access_specifier_kind access) const
{ {
return gen_->do_get_options(e); return gen_->do_get_options(e, access);
} }
/// \returns The formatting. /// \returns The formatting.
@ -367,11 +370,14 @@ namespace cppast
return {}; return {};
} }
/// \returns The generation options for that entity. /// \returns The generation options for that entity with the given access specifier.
/// If an entity is not part of a class the access specifier is alwasy [cppast::cpp_public]().
/// The base class version always returns no special options. /// The base class version always returns no special options.
virtual generation_options do_get_options(const cpp_entity& e) virtual generation_options do_get_options(const cpp_entity& e,
cppast::cpp_access_specifier_kind access)
{ {
(void)e; (void)e;
(void)access;
return {}; return {};
} }

View file

@ -24,7 +24,7 @@ namespace cppast
const char* to_string(cpp_class_kind kind) noexcept; const char* to_string(cpp_class_kind kind) noexcept;
/// The C++ access specifiers. /// The C++ access specifiers.
enum cpp_access_specifier_kind enum cpp_access_specifier_kind : int
{ {
cpp_public, cpp_public,
cpp_protected, cpp_protected,

View file

@ -5,6 +5,7 @@
#ifndef CPPAST_VISITOR_HPP_INCLUDED #ifndef CPPAST_VISITOR_HPP_INCLUDED
#define CPPAST_VISITOR_HPP_INCLUDED #define CPPAST_VISITOR_HPP_INCLUDED
#include <cppast/cpp_class.hpp>
#include <cppast/cpp_entity.hpp> #include <cppast/cpp_entity.hpp>
#include <cppast/cpp_entity_kind.hpp> #include <cppast/cpp_entity_kind.hpp>
@ -24,6 +25,9 @@ namespace cppast
container_entity_exit, //< Callback called for a container entity after the children. container_entity_exit, //< Callback called for a container entity after the children.
/// If callback returns `false`, visit operation will be aborted. /// If callback returns `false`, visit operation will be aborted.
} event; } event;
cpp_access_specifier_kind access; //< The current access specifier.
bool bool
last_child; //< True when the current entity is the last child of the visited parent entity. last_child; //< True when the current entity is the last child of the visited parent entity.
/// \notes It will always be `false` for the initial entity. /// \notes It will always be `false` for the initial entity.
@ -42,7 +46,8 @@ namespace cppast
return func(e, info); return func(e, info);
} }
bool visit(const cpp_entity& e, visitor_callback_t cb, void* functor, bool last_child); bool visit(const cpp_entity& e, visitor_callback_t cb, void* functor,
cpp_access_specifier_kind cur_access, bool last_child);
} // namespace detail } // namespace detail
/// Visits a [cppast::cpp_entity](). /// Visits a [cppast::cpp_entity]().
@ -54,7 +59,7 @@ namespace cppast
template <typename Func> template <typename Func>
void visit(const cpp_entity& e, Func f) void visit(const cpp_entity& e, Func f)
{ {
detail::visit(e, &detail::visitor_callback<Func>, &f, false); detail::visit(e, &detail::visitor_callback<Func>, &f, cpp_public, false);
} }
/// Visits a [cppast::cpp_entity](). /// Visits a [cppast::cpp_entity]().

View file

@ -56,25 +56,30 @@ namespace
output << whitespace; output << whitespace;
} }
bool generate_code_impl(code_generator& generator, const cpp_entity& e,
cpp_access_specifier_kind cur_access);
template <class Container, typename Sep> template <class Container, typename Sep>
bool write_container(code_generator::output& output, const Container& cont, Sep s) bool write_container(code_generator::output& output, const Container& cont, Sep s,
cpp_access_specifier_kind cur_access)
{ {
auto need_sep = false; auto need_sep = false;
for (auto& child : cont) for (auto& child : cont)
{ {
if (need_sep) if (need_sep)
output << s; output << s;
need_sep = generate_code(*output.generator(), child); need_sep = generate_code_impl(*output.generator(), child, cur_access);
} }
return need_sep; return need_sep;
} }
bool generate_file(code_generator& generator, const cpp_file& f) bool generate_file(code_generator& generator, const cpp_file& f,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(f)); code_generator::output output(type_safe::ref(generator), type_safe::ref(f), cur_access);
if (output) if (output)
{ {
auto need_sep = write_container(output, f, newl); auto need_sep = write_container(output, f, newl, cur_access);
if (!need_sep) if (!need_sep)
// file empty, write newl // file empty, write newl
output << newl; output << newl;
@ -82,9 +87,10 @@ namespace
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_macro_definition(code_generator& generator, const cpp_macro_definition& def) bool generate_macro_definition(code_generator& generator, const cpp_macro_definition& def,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(def)); code_generator::output output(type_safe::ref(generator), type_safe::ref(def), cur_access);
if (output) if (output)
{ {
output << preprocessor_token("#define") << whitespace << identifier(def.name()); output << preprocessor_token("#define") << whitespace << identifier(def.name());
@ -100,9 +106,11 @@ namespace
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_include_directive(code_generator& generator, const cpp_include_directive& include) bool generate_include_directive(code_generator& generator, const cpp_include_directive& include,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(include)); code_generator::output output(type_safe::ref(generator), type_safe::ref(include),
cur_access);
if (output) if (output)
{ {
output << preprocessor_token("#include") << whitespace; output << preprocessor_token("#include") << whitespace;
@ -120,9 +128,11 @@ namespace
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_language_linkage(code_generator& generator, const cpp_language_linkage& linkage) bool generate_language_linkage(code_generator& generator, const cpp_language_linkage& linkage,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(linkage)); code_generator::output output(type_safe::ref(generator), type_safe::ref(linkage),
cur_access);
if (output) if (output)
{ {
output << keyword("extern") << whitespace << string_literal(linkage.name()); output << keyword("extern") << whitespace << string_literal(linkage.name());
@ -131,7 +141,7 @@ namespace
output << opening_brace; output << opening_brace;
output.indent(); output.indent();
write_container(output, linkage, newl); write_container(output, linkage, newl, cur_access);
output.unindent(); output.unindent();
output << punctuation("}") << newl; output << punctuation("}") << newl;
@ -139,15 +149,16 @@ namespace
else else
{ {
output << whitespace; output << whitespace;
generate_code(generator, *linkage.begin()); generate_code_impl(generator, *linkage.begin(), cur_access);
} }
} }
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_namespace(code_generator& generator, const cpp_namespace& ns) bool generate_namespace(code_generator& generator, const cpp_namespace& ns,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(ns)); code_generator::output output(type_safe::ref(generator), type_safe::ref(ns), cur_access);
if (output) if (output)
{ {
if (ns.is_inline()) if (ns.is_inline())
@ -156,7 +167,7 @@ namespace
output << opening_brace; output << opening_brace;
output.indent(); output.indent();
write_container(output, ns, newl); write_container(output, ns, newl, cur_access);
output.unindent(); output.unindent();
output << punctuation("}") << newl; output << punctuation("}") << newl;
@ -164,9 +175,10 @@ namespace
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_namespace_alias(code_generator& generator, const cpp_namespace_alias& alias) bool generate_namespace_alias(code_generator& generator, const cpp_namespace_alias& alias,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(alias)); code_generator::output output(type_safe::ref(generator), type_safe::ref(alias), cur_access);
if (output) if (output)
{ {
output << keyword("namespace") << whitespace << identifier(alias.name()) << operator_ws output << keyword("namespace") << whitespace << identifier(alias.name()) << operator_ws
@ -180,9 +192,11 @@ namespace
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_using_directive(code_generator& generator, const cpp_using_directive& directive) bool generate_using_directive(code_generator& generator, const cpp_using_directive& directive,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(directive)); code_generator::output output(type_safe::ref(generator), type_safe::ref(directive),
cur_access);
if (output) if (output)
output << keyword("using") << whitespace << keyword("namespace") << whitespace output << keyword("using") << whitespace << keyword("namespace") << whitespace
<< directive.target() << punctuation(";") << newl; << directive.target() << punctuation(";") << newl;
@ -190,18 +204,21 @@ namespace
} }
bool generate_using_declaration(code_generator& generator, bool generate_using_declaration(code_generator& generator,
const cpp_using_declaration& declaration) const cpp_using_declaration& declaration,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(declaration)); code_generator::output output(type_safe::ref(generator), type_safe::ref(declaration),
cur_access);
if (output) if (output)
output << keyword("using") << whitespace << declaration.target() << punctuation(";") output << keyword("using") << whitespace << declaration.target() << punctuation(";")
<< newl; << newl;
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_type_alias(code_generator& generator, const cpp_type_alias& alias) bool generate_type_alias(code_generator& generator, const cpp_type_alias& alias,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(alias)); code_generator::output output(type_safe::ref(generator), type_safe::ref(alias), cur_access);
if (output) if (output)
{ {
output << keyword("using") << whitespace << identifier(alias.name()) << operator_ws output << keyword("using") << whitespace << identifier(alias.name()) << operator_ws
@ -215,9 +232,10 @@ namespace
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_enum_value(code_generator& generator, const cpp_enum_value& value) bool generate_enum_value(code_generator& generator, const cpp_enum_value& value,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(value)); code_generator::output output(type_safe::ref(generator), type_safe::ref(value), cur_access);
if (output) if (output)
{ {
output << identifier(value.name()); output << identifier(value.name());
@ -233,9 +251,10 @@ namespace
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_enum(code_generator& generator, const cpp_enum& e) bool generate_enum(code_generator& generator, const cpp_enum& e,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(e)); code_generator::output output(type_safe::ref(generator), type_safe::ref(e), cur_access);
if (output) if (output)
{ {
output << keyword("enum"); output << keyword("enum");
@ -253,9 +272,11 @@ namespace
output << opening_brace; output << opening_brace;
output.indent(); output.indent();
auto need_sep = write_container(output, e, [](const code_generator::output& out) { auto need_sep = write_container(output, e,
out << punctuation(",") << newl; [](const code_generator::output& out) {
}); out << punctuation(",") << newl;
},
cur_access);
if (need_sep) if (need_sep)
output << newl; output << newl;
@ -275,21 +296,25 @@ namespace
output.indent(); output.indent();
} }
bool generate_access_specifier(code_generator& generator, const cpp_access_specifier& access) bool generate_access_specifier(code_generator& generator, const cpp_access_specifier& access,
cpp_access_specifier_kind)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(access)); code_generator::output output(type_safe::ref(generator), type_safe::ref(access),
access.access_specifier());
if (output) if (output)
write_access_specifier(output, access.access_specifier()); write_access_specifier(output, access.access_specifier());
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_base_class(code_generator& generator, const cpp_base_class& base) bool generate_base_class(code_generator& generator, const cpp_base_class& base,
cpp_access_specifier_kind)
{ {
DEBUG_ASSERT(base.parent() && base.parent().value().kind() == cpp_entity_kind::class_t, DEBUG_ASSERT(base.parent() && base.parent().value().kind() == cpp_entity_kind::class_t,
detail::assert_handler{}); detail::assert_handler{});
auto parent_kind = static_cast<const cpp_class&>(base.parent().value()).class_kind(); auto parent_kind = static_cast<const cpp_class&>(base.parent().value()).class_kind();
code_generator::output output(type_safe::ref(generator), type_safe::ref(base)); code_generator::output output(type_safe::ref(generator), type_safe::ref(base),
base.access_specifier());
if (output) if (output)
{ {
if (base.is_virtual()) if (base.is_virtual())
@ -324,21 +349,23 @@ namespace
auto first = true; auto first = true;
for (auto& base : c.bases()) for (auto& base : c.bases())
{ {
if (first && !output.options(base).is_set(code_generator::exclude)) auto opt = output.options(base, base.access_specifier());
if (first && !opt.is_set(code_generator::exclude))
{ {
first = false; first = false;
output << newl << punctuation(":") << operator_ws; output << newl << punctuation(":") << operator_ws;
} }
else if (need_sep) else if (need_sep)
output << comma; output << comma;
need_sep = generate_base_class(generator, base); need_sep = generate_base_class(generator, base, cpp_public);
} }
} }
bool generate_class(code_generator& generator, const cpp_class& c, bool generate_class(code_generator& generator, const cpp_class& c,
cpp_access_specifier_kind cur_access,
type_safe::optional_ref<const cpp_template_specialization> spec = nullptr) type_safe::optional_ref<const cpp_template_specialization> spec = nullptr)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(c)); code_generator::output output(type_safe::ref(generator), type_safe::ref(c), cur_access);
if (output) if (output)
{ {
if (is_friended(c)) if (is_friended(c))
@ -376,7 +403,7 @@ namespace
auto& access = static_cast<const cpp_access_specifier&>(member); auto& access = static_cast<const cpp_access_specifier&>(member);
last_access = access.access_specifier(); last_access = access.access_specifier();
} }
else if (output.options(member).is_set(code_generator::exclude)) else if (output.options(member, last_access).is_set(code_generator::exclude))
continue; continue;
else else
{ {
@ -387,7 +414,7 @@ namespace
write_access_specifier(output, last_access); write_access_specifier(output, last_access);
last_written_access = last_access; last_written_access = last_access;
} }
need_sep = generate_code(generator, member); need_sep = generate_code_impl(generator, member, last_access);
} }
} }
@ -424,9 +451,10 @@ namespace
output << keyword("constexpr") << whitespace; output << keyword("constexpr") << whitespace;
} }
bool generate_variable(code_generator& generator, const cpp_variable& var) bool generate_variable(code_generator& generator, const cpp_variable& var,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(var)); code_generator::output output(type_safe::ref(generator), type_safe::ref(var), cur_access);
if (output) if (output)
{ {
write_storage_class(output, var.storage_class(), var.is_constexpr()); write_storage_class(output, var.storage_class(), var.is_constexpr());
@ -437,9 +465,10 @@ namespace
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_member_variable(code_generator& generator, const cpp_member_variable& var) bool generate_member_variable(code_generator& generator, const cpp_member_variable& var,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(var)); code_generator::output output(type_safe::ref(generator), type_safe::ref(var), cur_access);
if (output) if (output)
{ {
if (var.is_mutable()) if (var.is_mutable())
@ -450,9 +479,10 @@ namespace
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_bitfield(code_generator& generator, const cpp_bitfield& var) bool generate_bitfield(code_generator& generator, const cpp_bitfield& var,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(var)); code_generator::output output(type_safe::ref(generator), type_safe::ref(var), cur_access);
if (output) if (output)
{ {
if (var.is_mutable()) if (var.is_mutable())
@ -465,9 +495,10 @@ namespace
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_function_parameter(code_generator& generator, const cpp_function_parameter& param) bool generate_function_parameter(code_generator& generator, const cpp_function_parameter& param,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(param)); code_generator::output output(type_safe::ref(generator), type_safe::ref(param), cur_access);
if (output) if (output)
write_variable_base(output, param, param.name()); write_variable_base(output, param, param.name());
return static_cast<bool>(output); return static_cast<bool>(output);
@ -476,7 +507,7 @@ namespace
void write_function_parameters(code_generator::output& output, const cpp_function_base& base) void write_function_parameters(code_generator::output& output, const cpp_function_base& base)
{ {
output << punctuation("(") << bracket_ws; output << punctuation("(") << bracket_ws;
auto need_sep = write_container(output, base.parameters(), comma); auto need_sep = write_container(output, base.parameters(), comma, cpp_public);
if (base.is_variadic()) if (base.is_variadic())
{ {
if (need_sep) if (need_sep)
@ -536,10 +567,10 @@ namespace
} }
bool generate_function( bool generate_function(
code_generator& generator, const cpp_function& func, code_generator& generator, const cpp_function& func, cpp_access_specifier_kind cur_access,
type_safe::optional_ref<const cpp_template_specialization> spec = nullptr) type_safe::optional_ref<const cpp_template_specialization> spec = nullptr)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(func)); code_generator::output output(type_safe::ref(generator), type_safe::ref(func), cur_access);
if (output) if (output)
{ {
if (is_friended(func)) if (is_friended(func))
@ -637,9 +668,10 @@ namespace
bool generate_member_function( bool generate_member_function(
code_generator& generator, const cpp_member_function& func, code_generator& generator, const cpp_member_function& func,
cpp_access_specifier_kind cur_access,
type_safe::optional_ref<const cpp_template_specialization> spec = nullptr) type_safe::optional_ref<const cpp_template_specialization> spec = nullptr)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(func)); code_generator::output output(type_safe::ref(generator), type_safe::ref(func), cur_access);
if (output) if (output)
{ {
if (is_friended(func)) if (is_friended(func))
@ -685,9 +717,10 @@ namespace
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_conversion_op(code_generator& generator, const cpp_conversion_op& op) bool generate_conversion_op(code_generator& generator, const cpp_conversion_op& op,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(op)); code_generator::output output(type_safe::ref(generator), type_safe::ref(op), cur_access);
if (output) if (output)
{ {
if (is_friended(op)) if (is_friended(op))
@ -719,9 +752,10 @@ namespace
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_constructor(code_generator& generator, const cpp_constructor& ctor) bool generate_constructor(code_generator& generator, const cpp_constructor& ctor,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(ctor)); code_generator::output output(type_safe::ref(generator), type_safe::ref(ctor), cur_access);
if (output) if (output)
{ {
if (is_friended(ctor)) if (is_friended(ctor))
@ -740,9 +774,10 @@ namespace
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_destructor(code_generator& generator, const cpp_destructor& dtor) bool generate_destructor(code_generator& generator, const cpp_destructor& dtor,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(dtor)); code_generator::output output(type_safe::ref(generator), type_safe::ref(dtor), cur_access);
if (output) if (output)
{ {
if (is_friended(dtor)) if (is_friended(dtor))
@ -759,21 +794,24 @@ namespace
} }
bool generate_function_base(code_generator& generator, const cpp_function_base& base, bool generate_function_base(code_generator& generator, const cpp_function_base& base,
cpp_access_specifier_kind cur_access,
const cpp_template_specialization& spec) const cpp_template_specialization& spec)
{ {
switch (base.kind()) switch (base.kind())
{ {
case cpp_entity_kind::function_t: case cpp_entity_kind::function_t:
return generate_function(generator, static_cast<const cpp_function&>(base), return generate_function(generator, static_cast<const cpp_function&>(base), cur_access,
type_safe::ref(spec)); type_safe::ref(spec));
case cpp_entity_kind::member_function_t: case cpp_entity_kind::member_function_t:
return generate_member_function(generator, return generate_member_function(generator,
static_cast<const cpp_member_function&>(base), static_cast<const cpp_member_function&>(base),
type_safe::ref(spec)); cur_access, type_safe::ref(spec));
case cpp_entity_kind::conversion_op_t: case cpp_entity_kind::conversion_op_t:
return generate_conversion_op(generator, static_cast<const cpp_conversion_op&>(base)); return generate_conversion_op(generator, static_cast<const cpp_conversion_op&>(base),
cur_access);
case cpp_entity_kind::constructor_t: case cpp_entity_kind::constructor_t:
return generate_constructor(generator, static_cast<const cpp_constructor&>(base)); return generate_constructor(generator, static_cast<const cpp_constructor&>(base),
cur_access);
default: default:
DEBUG_UNREACHABLE(detail::assert_handler{}); DEBUG_UNREACHABLE(detail::assert_handler{});
@ -782,13 +820,14 @@ namespace
return false; return false;
} }
bool generate_friend(code_generator& generator, const cpp_friend& f) bool generate_friend(code_generator& generator, const cpp_friend& f,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(f)); code_generator::output output(type_safe::ref(generator), type_safe::ref(f), cur_access);
if (output) if (output)
{ {
if (auto e = f.entity()) if (auto e = f.entity())
generate_code(generator, e.value()); generate_code_impl(generator, e.value(), cur_access);
else if (auto type = f.type()) else if (auto type = f.type())
{ {
output << keyword("friend") << whitespace; output << keyword("friend") << whitespace;
@ -802,9 +841,10 @@ namespace
} }
bool generate_template_type_parameter(code_generator& generator, bool generate_template_type_parameter(code_generator& generator,
const cpp_template_type_parameter& param) const cpp_template_type_parameter& param,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(param)); code_generator::output output(type_safe::ref(generator), type_safe::ref(param), cur_access);
if (output) if (output)
{ {
output << keyword(to_string(param.keyword())); output << keyword(to_string(param.keyword()));
@ -822,9 +862,10 @@ namespace
} }
bool generate_non_type_template_parameter(code_generator& generator, bool generate_non_type_template_parameter(code_generator& generator,
const cpp_non_type_template_parameter& param) const cpp_non_type_template_parameter& param,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(param)); code_generator::output output(type_safe::ref(generator), type_safe::ref(param), cur_access);
if (output) if (output)
{ {
detail::write_type(output, param.type(), param.name(), param.is_variadic()); detail::write_type(output, param.type(), param.name(), param.is_variadic());
@ -838,13 +879,14 @@ namespace
} }
bool generate_template_template_parameter(code_generator& generator, bool generate_template_template_parameter(code_generator& generator,
const cpp_template_template_parameter& param) const cpp_template_template_parameter& param,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(param)); code_generator::output output(type_safe::ref(generator), type_safe::ref(param), cur_access);
if (output) if (output)
{ {
output << keyword("template") << operator_ws << punctuation("<") << bracket_ws; output << keyword("template") << operator_ws << punctuation("<") << bracket_ws;
write_container(output, param.parameters(), punctuation(",")); write_container(output, param.parameters(), punctuation(","), cur_access);
output << bracket_ws << punctuation(">") << operator_ws output << bracket_ws << punctuation(">") << operator_ws
<< keyword(to_string(param.keyword())); << keyword(to_string(param.keyword()));
if (param.is_variadic()) if (param.is_variadic())
@ -868,94 +910,103 @@ namespace
for (auto& param : templ.parameters()) for (auto& param : templ.parameters())
{ {
if (first if (first
&& !output.options(*templ.parameters().begin()).is_set(code_generator::exclude)) && !output.options(*templ.parameters().begin(), cpp_public)
.is_set(code_generator::exclude))
{ {
first = false; first = false;
output << keyword("template") << operator_ws << punctuation("<") << bracket_ws; output << keyword("template") << operator_ws << punctuation("<") << bracket_ws;
} }
else if (need_sep) else if (need_sep)
output << comma; output << comma;
need_sep = generate_code(*output.generator(), param); need_sep = generate_code_impl(*output.generator(), param, cpp_public);
} }
if (!hide_if_empty || need_sep) if (!hide_if_empty || need_sep)
output << bracket_ws << punctuation(">") << newl; output << bracket_ws << punctuation(">") << newl;
} }
bool generate_alias_template(code_generator& generator, const cpp_alias_template& alias) bool generate_alias_template(code_generator& generator, const cpp_alias_template& alias,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(alias)); code_generator::output output(type_safe::ref(generator), type_safe::ref(alias), cur_access);
if (output) if (output)
{ {
write_template_parameters(output, alias, true); write_template_parameters(output, alias, true);
generate_code(generator, alias.type_alias()); generate_code_impl(generator, alias.type_alias(), cur_access);
} }
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_variable_template(code_generator& generator, const cpp_variable_template& var) bool generate_variable_template(code_generator& generator, const cpp_variable_template& var,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(var)); code_generator::output output(type_safe::ref(generator), type_safe::ref(var), cur_access);
if (output) if (output)
{ {
write_template_parameters(output, var, true); write_template_parameters(output, var, true);
generate_code(generator, var.variable()); generate_code_impl(generator, var.variable(), cur_access);
} }
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_function_template(code_generator& generator, const cpp_function_template& func) bool generate_function_template(code_generator& generator, const cpp_function_template& func,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(func)); code_generator::output output(type_safe::ref(generator), type_safe::ref(func), cur_access);
if (output) if (output)
{ {
write_template_parameters(output, func, true); write_template_parameters(output, func, true);
generate_code(generator, func.function()); generate_code_impl(generator, func.function(), cur_access);
} }
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_function_template_specialization(code_generator& generator, bool generate_function_template_specialization(code_generator& generator,
const cpp_function_template_specialization& func) const cpp_function_template_specialization& func,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(func)); code_generator::output output(type_safe::ref(generator), type_safe::ref(func), cur_access);
if (output) if (output)
{ {
DEBUG_ASSERT(func.is_full_specialization(), detail::assert_handler{}); DEBUG_ASSERT(func.is_full_specialization(), detail::assert_handler{});
if (!is_friended(func)) if (!is_friended(func))
// don't write template parameters in friend // don't write template parameters in friend
write_template_parameters(output, func, false); write_template_parameters(output, func, false);
generate_function_base(generator, func.function(), func); generate_function_base(generator, func.function(), cur_access, func);
} }
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_class_template(code_generator& generator, const cpp_class_template& templ) bool generate_class_template(code_generator& generator, const cpp_class_template& templ,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(templ)); code_generator::output output(type_safe::ref(generator), type_safe::ref(templ), cur_access);
if (output) if (output)
{ {
write_template_parameters(output, templ, true); write_template_parameters(output, templ, true);
generate_class(generator, templ.class_()); generate_class(generator, templ.class_(), cur_access);
} }
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_class_template_specialization(code_generator& generator, bool generate_class_template_specialization(code_generator& generator,
const cpp_class_template_specialization& templ) const cpp_class_template_specialization& templ,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(templ)); code_generator::output output(type_safe::ref(generator), type_safe::ref(templ), cur_access);
if (output) if (output)
{ {
write_template_parameters(output, templ, false); write_template_parameters(output, templ, false);
generate_class(generator, templ.class_(), type_safe::ref(templ)); generate_class(generator, templ.class_(), cur_access, type_safe::ref(templ));
} }
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_static_assert(code_generator& generator, const cpp_static_assert& assert) bool generate_static_assert(code_generator& generator, const cpp_static_assert& assert,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(assert)); code_generator::output output(type_safe::ref(generator), type_safe::ref(assert),
cur_access);
if (output) if (output)
{ {
output << keyword("static_assert") << punctuation("(") << bracket_ws; output << keyword("static_assert") << punctuation("(") << bracket_ws;
@ -966,80 +1017,89 @@ namespace
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_unexposed(code_generator& generator, const cpp_unexposed_entity& entity) bool generate_unexposed(code_generator& generator, const cpp_unexposed_entity& entity,
cpp_access_specifier_kind cur_access)
{ {
code_generator::output output(type_safe::ref(generator), type_safe::ref(entity)); code_generator::output output(type_safe::ref(generator), type_safe::ref(entity),
cur_access);
if (output) if (output)
output << token_seq(entity.spelling()); output << token_seq(entity.spelling());
return static_cast<bool>(output); return static_cast<bool>(output);
} }
bool generate_code_impl(code_generator& generator, const cpp_entity& e,
cpp_access_specifier_kind cur_access)
{
switch (e.kind())
{
#define CPPAST_DETAIL_HANDLE(Name) \
case cpp_entity_kind::Name##_t: \
return generate_##Name(generator, static_cast<const cpp_##Name&>(e), cur_access);
CPPAST_DETAIL_HANDLE(file)
CPPAST_DETAIL_HANDLE(macro_definition)
CPPAST_DETAIL_HANDLE(include_directive)
CPPAST_DETAIL_HANDLE(language_linkage)
CPPAST_DETAIL_HANDLE(namespace)
CPPAST_DETAIL_HANDLE(namespace_alias)
CPPAST_DETAIL_HANDLE(using_directive)
CPPAST_DETAIL_HANDLE(using_declaration)
CPPAST_DETAIL_HANDLE(type_alias)
CPPAST_DETAIL_HANDLE(enum)
CPPAST_DETAIL_HANDLE(enum_value)
CPPAST_DETAIL_HANDLE(class)
CPPAST_DETAIL_HANDLE(access_specifier)
CPPAST_DETAIL_HANDLE(base_class)
CPPAST_DETAIL_HANDLE(variable)
CPPAST_DETAIL_HANDLE(member_variable)
CPPAST_DETAIL_HANDLE(bitfield)
CPPAST_DETAIL_HANDLE(function_parameter)
CPPAST_DETAIL_HANDLE(function)
CPPAST_DETAIL_HANDLE(member_function)
CPPAST_DETAIL_HANDLE(conversion_op)
CPPAST_DETAIL_HANDLE(constructor)
CPPAST_DETAIL_HANDLE(destructor)
CPPAST_DETAIL_HANDLE(friend)
CPPAST_DETAIL_HANDLE(template_type_parameter)
CPPAST_DETAIL_HANDLE(non_type_template_parameter)
CPPAST_DETAIL_HANDLE(template_template_parameter)
CPPAST_DETAIL_HANDLE(alias_template)
CPPAST_DETAIL_HANDLE(variable_template)
CPPAST_DETAIL_HANDLE(function_template)
CPPAST_DETAIL_HANDLE(function_template_specialization)
CPPAST_DETAIL_HANDLE(class_template)
CPPAST_DETAIL_HANDLE(class_template_specialization)
CPPAST_DETAIL_HANDLE(static_assert)
case cpp_entity_kind::unexposed_t:
return generate_unexposed(generator, static_cast<const cpp_unexposed_entity&>(e),
cur_access);
#undef CPPAST_DETAIL_HANDLE
case cpp_entity_kind::count:
DEBUG_UNREACHABLE(detail::assert_handler{});
break;
}
return false;
}
} }
bool cppast::generate_code(code_generator& generator, const cpp_entity& e) bool cppast::generate_code(code_generator& generator, const cpp_entity& e)
{ {
switch (e.kind()) return generate_code_impl(generator, e, cpp_public);
{
#define CPPAST_DETAIL_HANDLE(Name) \
case cpp_entity_kind::Name##_t: \
return generate_##Name(generator, static_cast<const cpp_##Name&>(e));
CPPAST_DETAIL_HANDLE(file)
CPPAST_DETAIL_HANDLE(macro_definition)
CPPAST_DETAIL_HANDLE(include_directive)
CPPAST_DETAIL_HANDLE(language_linkage)
CPPAST_DETAIL_HANDLE(namespace)
CPPAST_DETAIL_HANDLE(namespace_alias)
CPPAST_DETAIL_HANDLE(using_directive)
CPPAST_DETAIL_HANDLE(using_declaration)
CPPAST_DETAIL_HANDLE(type_alias)
CPPAST_DETAIL_HANDLE(enum)
CPPAST_DETAIL_HANDLE(enum_value)
CPPAST_DETAIL_HANDLE(class)
CPPAST_DETAIL_HANDLE(access_specifier)
CPPAST_DETAIL_HANDLE(base_class)
CPPAST_DETAIL_HANDLE(variable)
CPPAST_DETAIL_HANDLE(member_variable)
CPPAST_DETAIL_HANDLE(bitfield)
CPPAST_DETAIL_HANDLE(function_parameter)
CPPAST_DETAIL_HANDLE(function)
CPPAST_DETAIL_HANDLE(member_function)
CPPAST_DETAIL_HANDLE(conversion_op)
CPPAST_DETAIL_HANDLE(constructor)
CPPAST_DETAIL_HANDLE(destructor)
CPPAST_DETAIL_HANDLE(friend)
CPPAST_DETAIL_HANDLE(template_type_parameter)
CPPAST_DETAIL_HANDLE(non_type_template_parameter)
CPPAST_DETAIL_HANDLE(template_template_parameter)
CPPAST_DETAIL_HANDLE(alias_template)
CPPAST_DETAIL_HANDLE(variable_template)
CPPAST_DETAIL_HANDLE(function_template)
CPPAST_DETAIL_HANDLE(function_template_specialization)
CPPAST_DETAIL_HANDLE(class_template)
CPPAST_DETAIL_HANDLE(class_template_specialization)
CPPAST_DETAIL_HANDLE(static_assert)
case cpp_entity_kind::unexposed_t:
return generate_unexposed(generator, static_cast<const cpp_unexposed_entity&>(e));
#undef CPPAST_DETAIL_HANDLE
case cpp_entity_kind::count:
DEBUG_UNREACHABLE(detail::assert_handler{});
break;
}
return false;
} }
void detail::write_template_arguments( void detail::write_template_arguments(

View file

@ -5,6 +5,7 @@
#include <cppast/cpp_type.hpp> #include <cppast/cpp_type.hpp>
#include <cppast/cpp_array_type.hpp> #include <cppast/cpp_array_type.hpp>
#include <cppast/cpp_class.hpp>
#include <cppast/cpp_decltype_type.hpp> #include <cppast/cpp_decltype_type.hpp>
#include <cppast/cpp_entity.hpp> #include <cppast/cpp_entity.hpp>
#include <cppast/cpp_entity_kind.hpp> #include <cppast/cpp_entity_kind.hpp>
@ -576,7 +577,8 @@ std::string detail::to_string(const cpp_type& type)
// just a dummy type for the output // just a dummy type for the output
static auto dummy_entity = cpp_type_alias::build("foo", cpp_builtin_type::build(cpp_int)); static auto dummy_entity = cpp_type_alias::build("foo", cpp_builtin_type::build(cpp_int));
to_string_generator::output output(type_safe::ref(generator), type_safe::ref(*dummy_entity)); to_string_generator::output output(type_safe::ref(generator), type_safe::ref(*dummy_entity),
cpp_public);
write_type(output, type, ""); write_type(output, type, "");
return generator.get(); return generator.get();
} }

View file

@ -5,8 +5,6 @@
#include <cppast/visitor.hpp> #include <cppast/visitor.hpp>
#include <cppast/cpp_alias_template.hpp> #include <cppast/cpp_alias_template.hpp>
#include <cppast/cpp_entity.hpp>
#include <cppast/cpp_entity_kind.hpp>
#include <cppast/cpp_class.hpp> #include <cppast/cpp_class.hpp>
#include <cppast/cpp_class_template.hpp> #include <cppast/cpp_class_template.hpp>
#include <cppast/cpp_enum.hpp> #include <cppast/cpp_enum.hpp>
@ -20,56 +18,78 @@ using namespace cppast;
namespace namespace
{ {
cpp_access_specifier_kind get_initial_access(const cpp_entity& e)
{
if (e.kind() == cpp_class::kind())
return static_cast<const cpp_class&>(e).class_kind() == cpp_class_kind::class_t ?
cpp_private :
cpp_public;
return cpp_public;
}
void update_access(cpp_access_specifier_kind& child_access, const cpp_entity& child)
{
if (child.kind() == cpp_access_specifier::kind())
child_access = static_cast<const cpp_access_specifier&>(child).access_specifier();
}
template <typename T> template <typename T>
bool handle_container(const cpp_entity& e, detail::visitor_callback_t cb, void* functor, bool handle_container(const cpp_entity& e, detail::visitor_callback_t cb, void* functor,
bool last_child) cpp_access_specifier_kind cur_access, bool last_child)
{ {
auto& container = static_cast<const T&>(e); auto& container = static_cast<const T&>(e);
auto handle_children = auto handle_children =
cb(functor, container, {visitor_info::container_entity_enter, last_child}); cb(functor, container, {visitor_info::container_entity_enter, cur_access, last_child});
if (handle_children) if (handle_children)
{ {
auto child_access = get_initial_access(e);
for (auto iter = container.begin(); iter != container.end();) for (auto iter = container.begin(); iter != container.end();)
{ {
auto& cur = *iter; auto& cur = *iter;
++iter; ++iter;
if (!detail::visit(cur, cb, functor, iter == container.end()))
update_access(child_access, cur);
if (!detail::visit(cur, cb, functor, child_access, iter == container.end()))
return false; return false;
} }
} }
return cb(functor, container, {visitor_info::container_entity_exit, last_child}); return cb(functor, container,
{visitor_info::container_entity_exit, cur_access, last_child});
} }
} }
bool detail::visit(const cpp_entity& e, detail::visitor_callback_t cb, void* functor, bool detail::visit(const cpp_entity& e, detail::visitor_callback_t cb, void* functor,
bool last_child) cpp_access_specifier_kind cur_access, bool last_child)
{ {
switch (e.kind()) switch (e.kind())
{ {
case cpp_entity_kind::file_t: case cpp_entity_kind::file_t:
return handle_container<cpp_file>(e, cb, functor, last_child); return handle_container<cpp_file>(e, cb, functor, cur_access, last_child);
case cpp_entity_kind::language_linkage_t: case cpp_entity_kind::language_linkage_t:
return handle_container<cpp_language_linkage>(e, cb, functor, last_child); return handle_container<cpp_language_linkage>(e, cb, functor, cur_access, last_child);
case cpp_entity_kind::namespace_t: case cpp_entity_kind::namespace_t:
return handle_container<cpp_namespace>(e, cb, functor, last_child); return handle_container<cpp_namespace>(e, cb, functor, cur_access, last_child);
case cpp_entity_kind::enum_t: case cpp_entity_kind::enum_t:
return handle_container<cpp_enum>(e, cb, functor, last_child); return handle_container<cpp_enum>(e, cb, functor, cur_access, last_child);
case cpp_entity_kind::class_t: case cpp_entity_kind::class_t:
return handle_container<cpp_class>(e, cb, functor, last_child); return handle_container<cpp_class>(e, cb, functor, cur_access, last_child);
case cpp_entity_kind::alias_template_t: case cpp_entity_kind::alias_template_t:
return handle_container<cpp_alias_template>(e, cb, functor, last_child); return handle_container<cpp_alias_template>(e, cb, functor, cur_access, last_child);
case cpp_entity_kind::variable_template_t: case cpp_entity_kind::variable_template_t:
return handle_container<cpp_variable_template>(e, cb, functor, last_child); return handle_container<cpp_variable_template>(e, cb, functor, cur_access, last_child);
case cpp_entity_kind::function_template_t: case cpp_entity_kind::function_template_t:
return handle_container<cpp_function_template>(e, cb, functor, last_child); return handle_container<cpp_function_template>(e, cb, functor, cur_access, last_child);
case cpp_entity_kind::function_template_specialization_t: case cpp_entity_kind::function_template_specialization_t:
return handle_container<cpp_function_template_specialization>(e, cb, functor, last_child); return handle_container<cpp_function_template_specialization>(e, cb, functor, cur_access,
last_child);
case cpp_entity_kind::class_template_t: case cpp_entity_kind::class_template_t:
return handle_container<cpp_class_template>(e, cb, functor, last_child); return handle_container<cpp_class_template>(e, cb, functor, cur_access, last_child);
case cpp_entity_kind::class_template_specialization_t: case cpp_entity_kind::class_template_specialization_t:
return handle_container<cpp_class_template_specialization>(e, cb, functor, last_child); return handle_container<cpp_class_template_specialization>(e, cb, functor, cur_access,
last_child);
case cpp_entity_kind::macro_definition_t: case cpp_entity_kind::macro_definition_t:
case cpp_entity_kind::include_directive_t: case cpp_entity_kind::include_directive_t:
@ -95,7 +115,7 @@ bool detail::visit(const cpp_entity& e, detail::visitor_callback_t cb, void* fun
case cpp_entity_kind::template_template_parameter_t: case cpp_entity_kind::template_template_parameter_t:
case cpp_entity_kind::static_assert_t: case cpp_entity_kind::static_assert_t:
case cpp_entity_kind::unexposed_t: case cpp_entity_kind::unexposed_t:
return cb(functor, e, {visitor_info::leaf_entity, last_child}); return cb(functor, e, {visitor_info::leaf_entity, cur_access, last_child});
case cpp_entity_kind::count: case cpp_entity_kind::count:
break; break;

View file

@ -153,9 +153,13 @@ struct foo{
using test_generator::test_generator; using test_generator::test_generator;
private: private:
generation_options do_get_options(const cpp_entity& e) override generation_options do_get_options(const cpp_entity& e,
cpp_access_specifier_kind cur_access) override
{ {
if (e.name().front() == 'e') if (cur_access == cpp_protected)
// exclude all protected
return code_generator::exclude;
else if (e.name().front() == 'e')
// exclude all entities starting with `e` // exclude all entities starting with `e`
// add declaration flag to detect check for equality // add declaration flag to detect check for equality
return code_generator::exclude | code_generator::declaration; return code_generator::exclude | code_generator::declaration;
@ -181,7 +185,7 @@ struct e_t {};
struct bar : e_t, base {}; struct bar : e_t, base {};
class foo : e_t class foo : e_t, protected base
{ {
int a; int a;
@ -191,6 +195,9 @@ public:
private: private:
int b; int b;
protected:
int p1;
public: public:
int c; int c;
int e2; int e2;

View file

@ -59,7 +59,8 @@ public:
} }
private: private:
generation_options do_get_options(const cppast::cpp_entity&) override generation_options do_get_options(const cppast::cpp_entity&,
cppast::cpp_access_specifier_kind) override
{ {
return options_; return options_;
} }

View file

@ -79,7 +79,8 @@ void print_entity(std::ostream& out, const cppast::cpp_entity& e)
private: private:
// called to retrieve the generation options of an entity // called to retrieve the generation options of an entity
generation_options do_get_options(const cppast::cpp_entity&) override generation_options do_get_options(const cppast::cpp_entity&,
cppast::cpp_access_specifier_kind) override
{ {
// generate declaration only // generate declaration only
return code_generator::declaration; return code_generator::declaration;