From 0c4de49234f81dcce46a75600594fdbe50cbf20a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20M=C3=BCller?= Date: Tue, 18 Jul 2017 23:08:53 +0200 Subject: [PATCH 1/3] Pass current access specifier to code generator --- include/cppast/code_generator.hpp | 22 +- include/cppast/cpp_class.hpp | 2 +- src/code_generator.cpp | 378 +++++++++++++++++------------- src/cpp_type.cpp | 4 +- test/code_generator.cpp | 13 +- 5 files changed, 251 insertions(+), 168 deletions(-) diff --git a/include/cppast/code_generator.hpp b/include/cppast/code_generator.hpp index a81f6a4..f4a4e1f 100644 --- a/include/cppast/code_generator.hpp +++ b/include/cppast/code_generator.hpp @@ -15,6 +15,8 @@ namespace cppast { + enum cpp_access_specifier_kind : int; + /// A simple string view implementation, like [std::string_view](). /// /// It "views" - stores a pointer to - some kind of string. @@ -174,8 +176,9 @@ namespace cppast public: /// \effects Creates it giving the generator and the entity. explicit output(type_safe::object_ref gen, - type_safe::object_ref e) - : gen_(gen), e_(e), options_(gen->do_get_options(*e)) + type_safe::object_ref e, + cppast::cpp_access_specifier_kind access) + : gen_(gen), e_(e), options_(gen->do_get_options(*e, access)) { gen_->on_begin(*e_); } @@ -205,9 +208,9 @@ namespace cppast } /// \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. @@ -369,12 +372,23 @@ namespace cppast /// \returns The generation options for that entity. /// The base class version always returns no special options. + /// \notes This function will not be called if the one with the access specifier is overridden. virtual generation_options do_get_options(const cpp_entity& e) { (void)e; return {}; } + /// \returns The generation options for that entity with the given access specifier. + /// If an entity is not part of a class, returns [cppast::cpp_public](). + /// The base class version forwards to the overload that doesn't take an access specifier. + virtual generation_options do_get_options(const cpp_entity& e, + cppast::cpp_access_specifier_kind access) + { + (void)access; + return do_get_options(e); + } + /// \effects Will be invoked before code of an entity is generated. /// The base class version has no effect. virtual void on_begin(const cpp_entity& e) diff --git a/include/cppast/cpp_class.hpp b/include/cppast/cpp_class.hpp index e59b1fe..e050844 100644 --- a/include/cppast/cpp_class.hpp +++ b/include/cppast/cpp_class.hpp @@ -24,7 +24,7 @@ namespace cppast const char* to_string(cpp_class_kind kind) noexcept; /// The C++ access specifiers. - enum cpp_access_specifier_kind + enum cpp_access_specifier_kind : int { cpp_public, cpp_protected, diff --git a/src/code_generator.cpp b/src/code_generator.cpp index 2f1007e..06c495a 100644 --- a/src/code_generator.cpp +++ b/src/code_generator.cpp @@ -56,25 +56,30 @@ namespace output << whitespace; } + bool generate_code_impl(code_generator& generator, const cpp_entity& e, + cpp_access_specifier_kind cur_access); + template - 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; for (auto& child : cont) { if (need_sep) output << s; - need_sep = generate_code(*output.generator(), child); + need_sep = generate_code_impl(*output.generator(), child, cur_access); } 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) { - auto need_sep = write_container(output, f, newl); + auto need_sep = write_container(output, f, newl, cur_access); if (!need_sep) // file empty, write newl output << newl; @@ -82,9 +87,10 @@ namespace return static_cast(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) { output << preprocessor_token("#define") << whitespace << identifier(def.name()); @@ -100,9 +106,11 @@ namespace return static_cast(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) { output << preprocessor_token("#include") << whitespace; @@ -120,9 +128,11 @@ namespace return static_cast(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) { output << keyword("extern") << whitespace << string_literal(linkage.name()); @@ -131,7 +141,7 @@ namespace output << opening_brace; output.indent(); - write_container(output, linkage, newl); + write_container(output, linkage, newl, cur_access); output.unindent(); output << punctuation("}") << newl; @@ -139,15 +149,16 @@ namespace else { output << whitespace; - generate_code(generator, *linkage.begin()); + generate_code_impl(generator, *linkage.begin(), cur_access); } } return static_cast(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 (ns.is_inline()) @@ -156,7 +167,7 @@ namespace output << opening_brace; output.indent(); - write_container(output, ns, newl); + write_container(output, ns, newl, cur_access); output.unindent(); output << punctuation("}") << newl; @@ -164,9 +175,10 @@ namespace return static_cast(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) { output << keyword("namespace") << whitespace << identifier(alias.name()) << operator_ws @@ -180,9 +192,11 @@ namespace return static_cast(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) output << keyword("using") << whitespace << keyword("namespace") << whitespace << directive.target() << punctuation(";") << newl; @@ -190,18 +204,21 @@ namespace } 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) output << keyword("using") << whitespace << declaration.target() << punctuation(";") << newl; return static_cast(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) { output << keyword("using") << whitespace << identifier(alias.name()) << operator_ws @@ -215,9 +232,10 @@ namespace return static_cast(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) { output << identifier(value.name()); @@ -233,9 +251,10 @@ namespace return static_cast(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) { output << keyword("enum"); @@ -253,9 +272,11 @@ namespace output << opening_brace; output.indent(); - auto need_sep = write_container(output, e, [](const code_generator::output& out) { - out << punctuation(",") << newl; - }); + auto need_sep = write_container(output, e, + [](const code_generator::output& out) { + out << punctuation(",") << newl; + }, + cur_access); if (need_sep) output << newl; @@ -275,21 +296,25 @@ namespace 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) write_access_specifier(output, access.access_specifier()); return static_cast(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, detail::assert_handler{}); auto parent_kind = static_cast(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 (base.is_virtual()) @@ -324,21 +349,23 @@ namespace auto first = true; 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; output << newl << punctuation(":") << operator_ws; } else if (need_sep) 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, + cpp_access_specifier_kind cur_access, type_safe::optional_ref 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 (is_friended(c)) @@ -376,7 +403,7 @@ namespace auto& access = static_cast(member); 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; else { @@ -387,7 +414,7 @@ namespace write_access_specifier(output, 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; } - 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) { write_storage_class(output, var.storage_class(), var.is_constexpr()); @@ -437,9 +465,10 @@ namespace return static_cast(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 (var.is_mutable()) @@ -450,9 +479,10 @@ namespace return static_cast(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 (var.is_mutable()) @@ -465,9 +495,10 @@ namespace return static_cast(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) write_variable_base(output, param, param.name()); return static_cast(output); @@ -476,7 +507,7 @@ namespace void write_function_parameters(code_generator::output& output, const cpp_function_base& base) { 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 (need_sep) @@ -536,10 +567,10 @@ namespace } 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 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 (is_friended(func)) @@ -637,9 +668,10 @@ namespace bool generate_member_function( code_generator& generator, const cpp_member_function& func, + cpp_access_specifier_kind cur_access, type_safe::optional_ref 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 (is_friended(func)) @@ -685,9 +717,10 @@ namespace return static_cast(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 (is_friended(op)) @@ -719,9 +752,10 @@ namespace return static_cast(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 (is_friended(ctor)) @@ -740,9 +774,10 @@ namespace return static_cast(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 (is_friended(dtor)) @@ -759,21 +794,24 @@ namespace } bool generate_function_base(code_generator& generator, const cpp_function_base& base, + cpp_access_specifier_kind cur_access, const cpp_template_specialization& spec) { switch (base.kind()) { case cpp_entity_kind::function_t: - return generate_function(generator, static_cast(base), + return generate_function(generator, static_cast(base), cur_access, type_safe::ref(spec)); case cpp_entity_kind::member_function_t: return generate_member_function(generator, static_cast(base), - type_safe::ref(spec)); + cur_access, type_safe::ref(spec)); case cpp_entity_kind::conversion_op_t: - return generate_conversion_op(generator, static_cast(base)); + return generate_conversion_op(generator, static_cast(base), + cur_access); case cpp_entity_kind::constructor_t: - return generate_constructor(generator, static_cast(base)); + return generate_constructor(generator, static_cast(base), + cur_access); default: DEBUG_UNREACHABLE(detail::assert_handler{}); @@ -782,13 +820,14 @@ namespace 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 (auto e = f.entity()) - generate_code(generator, e.value()); + generate_code_impl(generator, e.value(), cur_access); else if (auto type = f.type()) { output << keyword("friend") << whitespace; @@ -802,9 +841,10 @@ namespace } 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) { output << keyword(to_string(param.keyword())); @@ -822,9 +862,10 @@ namespace } 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) { detail::write_type(output, param.type(), param.name(), param.is_variadic()); @@ -838,13 +879,14 @@ namespace } 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) { 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 << keyword(to_string(param.keyword())); if (param.is_variadic()) @@ -868,94 +910,103 @@ namespace for (auto& param : templ.parameters()) { 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; output << keyword("template") << operator_ws << punctuation("<") << bracket_ws; } else if (need_sep) 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) 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) { write_template_parameters(output, alias, true); - generate_code(generator, alias.type_alias()); + generate_code_impl(generator, alias.type_alias(), cur_access); } return static_cast(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) { write_template_parameters(output, var, true); - generate_code(generator, var.variable()); + generate_code_impl(generator, var.variable(), cur_access); } return static_cast(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) { write_template_parameters(output, func, true); - generate_code(generator, func.function()); + generate_code_impl(generator, func.function(), cur_access); } return static_cast(output); } 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) { DEBUG_ASSERT(func.is_full_specialization(), detail::assert_handler{}); if (!is_friended(func)) // don't write template parameters in friend 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(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) { write_template_parameters(output, templ, true); - generate_class(generator, templ.class_()); + generate_class(generator, templ.class_(), cur_access); } return static_cast(output); } 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) { 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(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) { output << keyword("static_assert") << punctuation("(") << bracket_ws; @@ -966,80 +1017,89 @@ namespace return static_cast(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) output << token_seq(entity.spelling()); return static_cast(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(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(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) { - switch (e.kind()) - { -#define CPPAST_DETAIL_HANDLE(Name) \ - case cpp_entity_kind::Name##_t: \ - return generate_##Name(generator, static_cast(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(e)); - -#undef CPPAST_DETAIL_HANDLE - - case cpp_entity_kind::count: - DEBUG_UNREACHABLE(detail::assert_handler{}); - break; - } - - return false; + return generate_code_impl(generator, e, cpp_public); } void detail::write_template_arguments( diff --git a/src/cpp_type.cpp b/src/cpp_type.cpp index 53684af..10636f5 100644 --- a/src/cpp_type.cpp +++ b/src/cpp_type.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -576,7 +577,8 @@ std::string detail::to_string(const cpp_type& type) // just a dummy type for the output 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, ""); return generator.get(); } diff --git a/test/code_generator.cpp b/test/code_generator.cpp index 637471e..ae908ab 100644 --- a/test/code_generator.cpp +++ b/test/code_generator.cpp @@ -153,9 +153,13 @@ struct foo{ using test_generator::test_generator; 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` // add declaration flag to detect check for equality return code_generator::exclude | code_generator::declaration; @@ -181,7 +185,7 @@ struct e_t {}; struct bar : e_t, base {}; -class foo : e_t +class foo : e_t, protected base { int a; @@ -191,6 +195,9 @@ public: private: int b; +protected: + int p1; + public: int c; int e2; From bb4527ff939dc7677a5cfc04e43e5cfeaecab7bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20M=C3=BCller?= Date: Wed, 19 Jul 2017 08:29:24 +0200 Subject: [PATCH 2/3] Add access specifier to visitor_info --- include/cppast/visitor.hpp | 9 ++++-- src/visitor.cpp | 58 +++++++++++++++++++++++++------------- 2 files changed, 46 insertions(+), 21 deletions(-) diff --git a/include/cppast/visitor.hpp b/include/cppast/visitor.hpp index 6195dbc..889c194 100644 --- a/include/cppast/visitor.hpp +++ b/include/cppast/visitor.hpp @@ -5,6 +5,7 @@ #ifndef CPPAST_VISITOR_HPP_INCLUDED #define CPPAST_VISITOR_HPP_INCLUDED +#include #include #include @@ -24,6 +25,9 @@ namespace cppast container_entity_exit, //< Callback called for a container entity after the children. /// If callback returns `false`, visit operation will be aborted. } event; + + cpp_access_specifier_kind access; //< The current access specifier. + bool 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. @@ -42,7 +46,8 @@ namespace cppast 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 /// Visits a [cppast::cpp_entity](). @@ -54,7 +59,7 @@ namespace cppast template void visit(const cpp_entity& e, Func f) { - detail::visit(e, &detail::visitor_callback, &f, false); + detail::visit(e, &detail::visitor_callback, &f, cpp_public, false); } /// Visits a [cppast::cpp_entity](). diff --git a/src/visitor.cpp b/src/visitor.cpp index 78c47bf..73a2327 100644 --- a/src/visitor.cpp +++ b/src/visitor.cpp @@ -5,8 +5,6 @@ #include #include -#include -#include #include #include #include @@ -20,56 +18,78 @@ using namespace cppast; namespace { + cpp_access_specifier_kind get_initial_access(const cpp_entity& e) + { + if (e.kind() == cpp_class::kind()) + return static_cast(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(child).access_specifier(); + } + template 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(e); 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) { + auto child_access = get_initial_access(e); for (auto iter = container.begin(); iter != container.end();) { auto& cur = *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 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 last_child) + cpp_access_specifier_kind cur_access, bool last_child) { switch (e.kind()) { case cpp_entity_kind::file_t: - return handle_container(e, cb, functor, last_child); + return handle_container(e, cb, functor, cur_access, last_child); case cpp_entity_kind::language_linkage_t: - return handle_container(e, cb, functor, last_child); + return handle_container(e, cb, functor, cur_access, last_child); case cpp_entity_kind::namespace_t: - return handle_container(e, cb, functor, last_child); + return handle_container(e, cb, functor, cur_access, last_child); case cpp_entity_kind::enum_t: - return handle_container(e, cb, functor, last_child); + return handle_container(e, cb, functor, cur_access, last_child); case cpp_entity_kind::class_t: - return handle_container(e, cb, functor, last_child); + return handle_container(e, cb, functor, cur_access, last_child); case cpp_entity_kind::alias_template_t: - return handle_container(e, cb, functor, last_child); + return handle_container(e, cb, functor, cur_access, last_child); case cpp_entity_kind::variable_template_t: - return handle_container(e, cb, functor, last_child); + return handle_container(e, cb, functor, cur_access, last_child); case cpp_entity_kind::function_template_t: - return handle_container(e, cb, functor, last_child); + return handle_container(e, cb, functor, cur_access, last_child); case cpp_entity_kind::function_template_specialization_t: - return handle_container(e, cb, functor, last_child); + return handle_container(e, cb, functor, cur_access, + last_child); case cpp_entity_kind::class_template_t: - return handle_container(e, cb, functor, last_child); + return handle_container(e, cb, functor, cur_access, last_child); case cpp_entity_kind::class_template_specialization_t: - return handle_container(e, cb, functor, last_child); + return handle_container(e, cb, functor, cur_access, + last_child); case cpp_entity_kind::macro_definition_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::static_assert_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: break; From 9c8260e68532f58becfc928b2917097c84fba6e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20M=C3=BCller?= Date: Wed, 19 Jul 2017 12:49:41 +0200 Subject: [PATCH 3/3] [breaking] Change signature of do_get_options() --- include/cppast/code_generator.hpp | 16 ++++------------ test/test_parser.hpp | 3 ++- tool/main.cpp | 3 ++- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/include/cppast/code_generator.hpp b/include/cppast/code_generator.hpp index f4a4e1f..5f12e2e 100644 --- a/include/cppast/code_generator.hpp +++ b/include/cppast/code_generator.hpp @@ -370,23 +370,15 @@ namespace cppast return {}; } - /// \returns The generation options for that entity. - /// The base class version always returns no special options. - /// \notes This function will not be called if the one with the access specifier is overridden. - virtual generation_options do_get_options(const cpp_entity& e) - { - (void)e; - return {}; - } - /// \returns The generation options for that entity with the given access specifier. - /// If an entity is not part of a class, returns [cppast::cpp_public](). - /// The base class version forwards to the overload that doesn't take an 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. virtual generation_options do_get_options(const cpp_entity& e, cppast::cpp_access_specifier_kind access) { + (void)e; (void)access; - return do_get_options(e); + return {}; } /// \effects Will be invoked before code of an entity is generated. diff --git a/test/test_parser.hpp b/test/test_parser.hpp index aa4cf0d..609588a 100644 --- a/test/test_parser.hpp +++ b/test/test_parser.hpp @@ -59,7 +59,8 @@ public: } 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_; } diff --git a/tool/main.cpp b/tool/main.cpp index 2936ae2..9affd3d 100644 --- a/tool/main.cpp +++ b/tool/main.cpp @@ -79,7 +79,8 @@ void print_entity(std::ostream& out, const cppast::cpp_entity& e) private: // 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 return code_generator::declaration;