diff --git a/include/cppast/code_generator.hpp b/include/cppast/code_generator.hpp index de4fdfa..39f24b7 100644 --- a/include/cppast/code_generator.hpp +++ b/include/cppast/code_generator.hpp @@ -157,6 +157,7 @@ namespace cppast /// Flags that control the generation. enum generation_flags { + custom, //< A custom output is written. exclude, //< Exclude the entire entity. exclude_return, //< Exclude the return type of a function entity. exclude_target, //< Exclude the underlying entity of an alias (e.g. typedef). @@ -193,12 +194,10 @@ namespace cppast output& operator=(const output&) = delete; - /// \returns Whether or not the `on_XXX` function returned something other than `exclude`. - /// \notes If this returns `false`, - /// the other functions have no effects. + /// \returns Whether or not the `on_XXX` function returned something other than `exclude` or `custom`. explicit operator bool() const noexcept { - return !options_.is_set(exclude); + return !options_.is_set(exclude) && !options_.is_set(custom); } /// \returns The generation options. @@ -234,19 +233,15 @@ namespace cppast /// \effects Call `do_indent()` followed by `do_write_newline()` (if `print_newline` is `true`). void indent(bool print_newline = true) const noexcept { - if (*this) - { - gen_->do_indent(); - if (print_newline) - gen_->do_write_newline(); - } + gen_->do_indent(); + if (print_newline) + gen_->do_write_newline(); } /// \effects Calls `do_unindent()`. void unindent() const noexcept { - if (*this) - gen_->do_unindent(); + gen_->do_unindent(); } /// \effects Calls `func(*this)`. @@ -259,16 +254,14 @@ namespace cppast /// \effects Calls `do_write_keyword()`. const output& operator<<(const keyword& k) const { - if (*this) - gen_->do_write_keyword(k.str()); + gen_->do_write_keyword(k.str()); return *this; } /// \effects Calls `do_write_identifier()`. const output& operator<<(const identifier& ident) const { - if (*this) - gen_->do_write_identifier(ident.str()); + gen_->do_write_identifier(ident.str()); return *this; } @@ -276,88 +269,77 @@ namespace cppast template const output& operator<<(const basic_cpp_entity_ref& ref) const { - if (*this) - gen_->do_write_reference(ref.id(), ref.name()); + gen_->do_write_reference(ref.id(), ref.name()); return *this; } /// \effects Calls `do_write_punctuation()`. const output& operator<<(const punctuation& punct) const { - if (*this) - gen_->do_write_punctuation(punct.str()); + gen_->do_write_punctuation(punct.str()); return *this; } /// \effects Calls `do_write_str_literal`. const output& operator<<(const string_literal& lit) const { - if (*this) - gen_->do_write_str_literal(lit.str()); + gen_->do_write_str_literal(lit.str()); return *this; } /// \effects Calls `do_write_int_literal()`. const output& operator<<(const int_literal& lit) const { - if (*this) - gen_->do_write_int_literal(lit.str()); + gen_->do_write_int_literal(lit.str()); return *this; } /// \effects Calls `do_write_float_literal()`. const output& operator<<(const float_literal& lit) const { - if (*this) - gen_->do_write_float_literal(lit.str()); + gen_->do_write_float_literal(lit.str()); return *this; } /// \effects Calls `do_write_preprocessor()`. const output& operator<<(const preprocessor_token& tok) const { - if (*this) - gen_->do_write_preprocessor(tok.str()); + gen_->do_write_preprocessor(tok.str()); return *this; } /// \effects Calls `do_write_comment()`. const output& operator<<(const comment& c) const { - if (*this) - gen_->do_write_comment(c.str()); + gen_->do_write_comment(c.str()); return *this; } /// \effects Calls `do_write_token_seq()`. const output& operator<<(const token_seq& seq) const { - if (*this) - gen_->do_write_token_seq(seq.str()); + gen_->do_write_token_seq(seq.str()); return *this; } /// \effects Calls `do_write_excluded()`. const output& excluded(const cpp_entity& e) const { - if (*this) - gen_->do_write_excluded(e); + gen_->do_write_excluded(e); return *this; } /// \effects Calls `do_write_newline()`. const output& operator<<(newl_t) const { - if (*this) - gen_->do_write_newline(); + gen_->do_write_newline(); return *this; } /// \effects Calls `do_write_whitespace()`. const output& operator<<(whitespace_t) const { - if (*this) - gen_->do_write_whitespace(); + gen_->do_write_whitespace(); return *this; } @@ -376,6 +358,12 @@ namespace cppast return main_entity_.value(); } + /// \effects Generates the code for the specified entity. + /// It can be used to generate additional entities while generating another one. + /// \returns Whether or not any code was generated. + /// \notes This does not affect the main entity, but otherwise behaves just like [cppast::generate_code()](). + bool generate_code(const cpp_entity& entity); + private: /// \returns The formatting options that should be used. /// The base class version has no flags set. diff --git a/src/code_generator.cpp b/src/code_generator.cpp index 8f54149..eb88d96 100644 --- a/src/code_generator.cpp +++ b/src/code_generator.cpp @@ -66,9 +66,13 @@ namespace auto need_sep = false; for (auto& child : cont) { - if (need_sep) - output << s; - need_sep = generate_code_impl(*output.generator(), child, cur_access); + auto is_excluded = output.options(child, cur_access).is_set(code_generator::exclude); + if (!is_excluded) + { + if (need_sep) + output << s; + need_sep = generate_code_impl(*output.generator(), child, cur_access); + } } return need_sep; } @@ -636,15 +640,15 @@ namespace case cpp_cv_none: break; case cpp_cv_const: - output << keyword("const"); + output << operator_ws << keyword("const"); need_ws = true; break; case cpp_cv_volatile: - output << keyword("volatile"); + output << operator_ws << keyword("volatile"); need_ws = true; break; case cpp_cv_const_volatile: - output << keyword("const") << whitespace << keyword("volatile"); + output << operator_ws << keyword("const") << whitespace << keyword("volatile"); need_ws = true; break; } @@ -654,11 +658,11 @@ namespace case cpp_ref_none: break; case cpp_ref_lvalue: - output << operator_ws << punctuation("&") << operator_ws; + output << operator_ws << punctuation("&"); need_ws = false; break; case cpp_ref_rvalue: - output << operator_ws << punctuation("&&") << operator_ws; + output << operator_ws << punctuation("&&"); need_ws = false; break; } @@ -905,23 +909,25 @@ namespace if (!hide_if_empty) output << keyword("template") << operator_ws << punctuation("<") << bracket_ws; - auto need_sep = false; - auto first = hide_if_empty; + auto need_sep = false; + auto need_header = hide_if_empty; for (auto& param : templ.parameters()) { - if (first - && !output.options(*templ.parameters().begin(), cpp_public) - .is_set(code_generator::exclude)) + auto is_excluded = output.options(param, cpp_public).is_set(code_generator::exclude); + if (!is_excluded) { - first = false; - output << keyword("template") << operator_ws << punctuation("<") << bracket_ws; + if (need_header) + { + need_header = false; + output << keyword("template") << operator_ws << punctuation("<") << bracket_ws; + } + else if (need_sep) + output << comma; + need_sep = generate_code_impl(*output.generator(), param, cpp_public); } - else if (need_sep) - output << comma; - need_sep = generate_code_impl(*output.generator(), param, cpp_public); } - if (!hide_if_empty || need_sep) + if (!need_header) output << bracket_ws << punctuation(">") << newl; } @@ -1097,6 +1103,11 @@ namespace } } +bool code_generator::generate_code(const cpp_entity& entity) +{ + return generate_code_impl(*this, entity, cpp_public); +} + bool cppast::generate_code(code_generator& generator, const cpp_entity& e) { generator.main_entity_ = type_safe::ref(e); diff --git a/src/libclang/type_parser.cpp b/src/libclang/type_parser.cpp index a6a3e9f..32ae2ec 100644 --- a/src/libclang/type_parser.cpp +++ b/src/libclang/type_parser.cpp @@ -438,6 +438,8 @@ namespace if (spelling.empty() || spelling.back() != '>') return nullptr; spelling.pop_back(); + while (!spelling.empty() && spelling.back() == ' ') + spelling.pop_back(); builder.add_unexposed_arguments(ptr); return builder.finish();