Add exclude_return and exclude_target code generation options
This commit is contained in:
parent
2be20f60a2
commit
c86e950847
5 changed files with 151 additions and 29 deletions
|
|
@ -8,6 +8,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include <type_safe/index.hpp>
|
#include <type_safe/index.hpp>
|
||||||
|
#include <type_safe/flag_set.hpp>
|
||||||
|
|
||||||
#include <cppast/cpp_entity.hpp>
|
#include <cppast/cpp_entity.hpp>
|
||||||
#include <cppast/cpp_entity_ref.hpp>
|
#include <cppast/cpp_entity_ref.hpp>
|
||||||
|
|
@ -129,14 +130,19 @@ namespace cppast
|
||||||
code_generator& operator=(const code_generator&) = delete;
|
code_generator& operator=(const code_generator&) = delete;
|
||||||
virtual ~code_generator() noexcept = default;
|
virtual ~code_generator() noexcept = default;
|
||||||
|
|
||||||
/// Options that control the synopsis.
|
/// Flags that control the synopsis.
|
||||||
enum synopsis_options
|
enum synopsis_flags
|
||||||
{
|
{
|
||||||
exclude, //< Exclude the entire entity.
|
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).
|
||||||
declaration, //< Only write declaration.
|
declaration, //< Only write declaration.
|
||||||
definition, //< Also write definition.
|
_flag_set_size, //< \exclude
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Options that control the synopsis.
|
||||||
|
using synopsis_options = type_safe::flag_set<synopsis_flags>;
|
||||||
|
|
||||||
/// Sentinel type used to output a given entity.
|
/// Sentinel type used to output a given entity.
|
||||||
class output
|
class output
|
||||||
{
|
{
|
||||||
|
|
@ -177,10 +183,16 @@ namespace cppast
|
||||||
return options_ != exclude;
|
return options_ != exclude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \returns The synopsis options.
|
||||||
|
synopsis_options options() const noexcept
|
||||||
|
{
|
||||||
|
return options_;
|
||||||
|
}
|
||||||
|
|
||||||
/// \returns Whether or not the definition should be generated as well.
|
/// \returns Whether or not the definition should be generated as well.
|
||||||
bool generate_definition() const noexcept
|
bool generate_definition() const noexcept
|
||||||
{
|
{
|
||||||
return options_ == definition;
|
return !(options_ & declaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \returns A reference to the generator.
|
/// \returns A reference to the generator.
|
||||||
|
|
@ -280,6 +292,14 @@ namespace cppast
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \effects Calls `do_write_excluded()`.
|
||||||
|
const output& excluded(const cpp_entity& e) const
|
||||||
|
{
|
||||||
|
if (*this)
|
||||||
|
gen_->do_write_excluded(e);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/// \effects Calls `do_write_newline()`.
|
/// \effects Calls `do_write_newline()`.
|
||||||
const output& operator<<(newl_t) const
|
const output& operator<<(newl_t) const
|
||||||
{
|
{
|
||||||
|
|
@ -309,11 +329,11 @@ namespace cppast
|
||||||
/// \effects Will be invoked before code of a container entity is generated.
|
/// \effects Will be invoked before code of a container entity is generated.
|
||||||
/// The base class version has no effect.
|
/// The base class version has no effect.
|
||||||
/// \returns The synopsis options for that entity,
|
/// \returns The synopsis options for that entity,
|
||||||
/// the base class version always returns `definition`.
|
/// the base class version always returns no special options.
|
||||||
virtual synopsis_options on_container_begin(const cpp_entity& e)
|
virtual synopsis_options on_container_begin(const cpp_entity& e)
|
||||||
{
|
{
|
||||||
(void)e;
|
(void)e;
|
||||||
return definition;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \effects Will be invoked after all code of a container entity has been generated.
|
/// \effects Will be invoked after all code of a container entity has been generated.
|
||||||
|
|
@ -326,11 +346,11 @@ namespace cppast
|
||||||
/// \effects Will be invoked before code of a non-container entity is generated.
|
/// \effects Will be invoked before code of a non-container entity is generated.
|
||||||
/// The base class version has no effect.
|
/// The base class version has no effect.
|
||||||
/// \returns The synopsis options for that entity,
|
/// \returns The synopsis options for that entity,
|
||||||
/// the base class version always returns `definition`.
|
/// the base class version always returns no special options.
|
||||||
virtual synopsis_options on_leaf(const cpp_entity& e)
|
virtual synopsis_options on_leaf(const cpp_entity& e)
|
||||||
{
|
{
|
||||||
(void)e;
|
(void)e;
|
||||||
return definition;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \effects Will be invoked when the indentation level should be increased by one.
|
/// \effects Will be invoked when the indentation level should be increased by one.
|
||||||
|
|
@ -390,6 +410,14 @@ namespace cppast
|
||||||
do_write_token_seq(punct);
|
do_write_token_seq(punct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \effects Writes a string for an excluded target or return type for the given entity.
|
||||||
|
/// The base class version writes the identifier `excluded`.
|
||||||
|
virtual void do_write_excluded(const cpp_entity& e)
|
||||||
|
{
|
||||||
|
(void)e;
|
||||||
|
do_write_identifier("excluded");
|
||||||
|
}
|
||||||
|
|
||||||
/// \effects Writes a newline.
|
/// \effects Writes a newline.
|
||||||
/// It is guaranteed that this is the only way a newline will be printed.
|
/// It is guaranteed that this is the only way a newline will be printed.
|
||||||
/// The base class forwards to `do_write_token_seq()`.
|
/// The base class forwards to `do_write_token_seq()`.
|
||||||
|
|
|
||||||
|
|
@ -146,8 +146,15 @@ namespace
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(alias), false);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(alias), false);
|
||||||
if (output)
|
if (output)
|
||||||
|
{
|
||||||
output << keyword("namespace") << whitespace << identifier(alias.name())
|
output << keyword("namespace") << whitespace << identifier(alias.name())
|
||||||
<< punctuation("=") << alias.target() << punctuation(";") << newl;
|
<< punctuation("=");
|
||||||
|
if (output.options() & code_generator::exclude_target)
|
||||||
|
output.excluded(alias);
|
||||||
|
else
|
||||||
|
output << alias.target();
|
||||||
|
output << punctuation(";") << newl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_using_directive(code_generator& generator, const cpp_using_directive& directive)
|
void generate_using_directive(code_generator& generator, const cpp_using_directive& directive)
|
||||||
|
|
@ -175,6 +182,9 @@ namespace
|
||||||
{
|
{
|
||||||
output << keyword("using") << whitespace << identifier(alias.name())
|
output << keyword("using") << whitespace << identifier(alias.name())
|
||||||
<< punctuation("=");
|
<< punctuation("=");
|
||||||
|
if (output.options() & code_generator::exclude_target)
|
||||||
|
output.excluded(alias);
|
||||||
|
else
|
||||||
detail::write_type(output, alias.underlying_type(), "");
|
detail::write_type(output, alias.underlying_type(), "");
|
||||||
output << punctuation(";") << newl;
|
output << punctuation(";") << newl;
|
||||||
}
|
}
|
||||||
|
|
@ -485,7 +495,9 @@ namespace
|
||||||
output << keyword("friend") << whitespace;
|
output << keyword("friend") << whitespace;
|
||||||
write_storage_class(output, func.storage_class(), func.is_constexpr());
|
write_storage_class(output, func.storage_class(), func.is_constexpr());
|
||||||
|
|
||||||
if (detail::is_complex_type(func.return_type()))
|
if (output.options() & code_generator::exclude_return)
|
||||||
|
output.excluded(func) << whitespace;
|
||||||
|
else if (detail::is_complex_type(func.return_type()))
|
||||||
output << keyword("auto") << whitespace;
|
output << keyword("auto") << whitespace;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -504,7 +516,8 @@ namespace
|
||||||
write_function_parameters(output, func);
|
write_function_parameters(output, func);
|
||||||
write_noexcept(output, func, false);
|
write_noexcept(output, func, false);
|
||||||
|
|
||||||
if (detail::is_complex_type(func.return_type()))
|
if (!(output.options() & code_generator::exclude_return)
|
||||||
|
&& detail::is_complex_type(func.return_type()))
|
||||||
{
|
{
|
||||||
output << punctuation("->");
|
output << punctuation("->");
|
||||||
detail::write_type(output, func.return_type(), "");
|
detail::write_type(output, func.return_type(), "");
|
||||||
|
|
@ -579,7 +592,9 @@ namespace
|
||||||
else
|
else
|
||||||
write_prefix_virtual(output, func.virtual_info());
|
write_prefix_virtual(output, func.virtual_info());
|
||||||
|
|
||||||
if (detail::is_complex_type(func.return_type()))
|
if (output.options() & code_generator::exclude_return)
|
||||||
|
output.excluded(func) << whitespace;
|
||||||
|
else if (detail::is_complex_type(func.return_type()))
|
||||||
output << keyword("auto") << whitespace;
|
output << keyword("auto") << whitespace;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -599,7 +614,8 @@ namespace
|
||||||
auto need_ws = write_cv_ref(output, func);
|
auto need_ws = write_cv_ref(output, func);
|
||||||
write_noexcept(output, func, need_ws);
|
write_noexcept(output, func, need_ws);
|
||||||
|
|
||||||
if (detail::is_complex_type(func.return_type()))
|
if (!(output.options() & code_generator::exclude_return)
|
||||||
|
&& detail::is_complex_type(func.return_type()))
|
||||||
{
|
{
|
||||||
output << punctuation("->");
|
output << punctuation("->");
|
||||||
detail::write_type(output, func.return_type(), "");
|
detail::write_type(output, func.return_type(), "");
|
||||||
|
|
@ -628,7 +644,11 @@ namespace
|
||||||
|
|
||||||
auto pos = op.name().find("operator");
|
auto pos = op.name().find("operator");
|
||||||
output << identifier(op.name().substr(0u, pos)) << keyword("operator") << whitespace;
|
output << identifier(op.name().substr(0u, pos)) << keyword("operator") << whitespace;
|
||||||
|
if (output.options() & code_generator::exclude_return)
|
||||||
|
output.excluded(op);
|
||||||
|
else
|
||||||
detail::write_type(output, op.return_type(), "");
|
detail::write_type(output, op.return_type(), "");
|
||||||
|
|
||||||
output << punctuation("(") << punctuation(")");
|
output << punctuation("(") << punctuation(")");
|
||||||
auto need_ws = write_cv_ref(output, op);
|
auto need_ws = write_cv_ref(output, op);
|
||||||
write_noexcept(output, op, need_ws);
|
write_noexcept(output, op, need_ws);
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,12 @@
|
||||||
|
|
||||||
#include "test_parser.hpp"
|
#include "test_parser.hpp"
|
||||||
|
|
||||||
|
using namespace cppast;
|
||||||
|
|
||||||
TEST_CASE("code_generator")
|
TEST_CASE("code_generator")
|
||||||
{
|
{
|
||||||
|
SECTION("basic")
|
||||||
|
{
|
||||||
// no need to check much here, as each entity check separately
|
// no need to check much here, as each entity check separately
|
||||||
// only write some file with equivalent code and synopsis
|
// only write some file with equivalent code and synopsis
|
||||||
auto code = R"(using type=int;
|
auto code = R"(using type=int;
|
||||||
|
|
@ -36,4 +40,58 @@ extern void(* ptr)(int(*)(int))=&func;
|
||||||
|
|
||||||
auto file = parse({}, "code_generator.cpp", code);
|
auto file = parse({}, "code_generator.cpp", code);
|
||||||
REQUIRE(get_code(*file) == code);
|
REQUIRE(get_code(*file) == code);
|
||||||
|
}
|
||||||
|
SECTION("exclude target")
|
||||||
|
{
|
||||||
|
auto code = R"(
|
||||||
|
namespace a {}
|
||||||
|
|
||||||
|
namespace b = a;
|
||||||
|
|
||||||
|
using c = int*;
|
||||||
|
typedef int d;
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto synopsis = R"(namespace a{
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace b=excluded;
|
||||||
|
|
||||||
|
using c=excluded;
|
||||||
|
|
||||||
|
using d=excluded;
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto file = parse({}, "code_generator_exclude_target.cpp", code);
|
||||||
|
REQUIRE(get_code(*file, code_generator::exclude_target) == synopsis);
|
||||||
|
}
|
||||||
|
SECTION("exclude return")
|
||||||
|
{
|
||||||
|
auto code = R"(
|
||||||
|
void a();
|
||||||
|
template <typename T>
|
||||||
|
auto b() -> int*;
|
||||||
|
|
||||||
|
struct foo
|
||||||
|
{
|
||||||
|
int c() const&;
|
||||||
|
operator const int ();
|
||||||
|
};
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto synopsis = R"(excluded a();
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
excluded b();
|
||||||
|
|
||||||
|
struct foo{
|
||||||
|
excluded c()const&;
|
||||||
|
|
||||||
|
operator excluded();
|
||||||
|
};
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto file = parse({}, "code_generator_exclude_return.cpp", code);
|
||||||
|
REQUIRE(get_code(*file, code_generator::exclude_return) == synopsis);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,12 +45,26 @@ inline std::unique_ptr<cppast::cpp_file> parse(const cppast::cpp_entity_index& i
|
||||||
class test_generator : public cppast::code_generator
|
class test_generator : public cppast::code_generator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
test_generator(synopsis_options options) : options_(std::move(options))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
const std::string& str() const noexcept
|
const std::string& str() const noexcept
|
||||||
{
|
{
|
||||||
return str_;
|
return str_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
synopsis_options on_container_begin(const cppast::cpp_entity&) override
|
||||||
|
{
|
||||||
|
return options_;
|
||||||
|
}
|
||||||
|
|
||||||
|
synopsis_options on_leaf(const cppast::cpp_entity&) override
|
||||||
|
{
|
||||||
|
return options_;
|
||||||
|
}
|
||||||
|
|
||||||
void do_indent() override
|
void do_indent() override
|
||||||
{
|
{
|
||||||
++indent_;
|
++indent_;
|
||||||
|
|
@ -79,13 +93,15 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string str_;
|
std::string str_;
|
||||||
|
synopsis_options options_;
|
||||||
unsigned indent_ = 0;
|
unsigned indent_ = 0;
|
||||||
bool was_newline_ = false;
|
bool was_newline_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::string get_code(const cppast::cpp_entity& e)
|
inline std::string get_code(const cppast::cpp_entity& e,
|
||||||
|
cppast::code_generator::synopsis_options options = {})
|
||||||
{
|
{
|
||||||
test_generator generator;
|
test_generator generator(options);
|
||||||
cppast::generate_code(generator, e);
|
cppast::generate_code(generator, e);
|
||||||
auto str = generator.str();
|
auto str = generator.str();
|
||||||
if (!str.empty() && str.back() == '\n')
|
if (!str.empty() && str.back() == '\n')
|
||||||
|
|
|
||||||
|
|
@ -82,14 +82,14 @@ void print_entity(std::ostream& out, const cppast::cpp_entity& e)
|
||||||
synopsis_options on_container_begin(const cppast::cpp_entity&) override
|
synopsis_options on_container_begin(const cppast::cpp_entity&) override
|
||||||
{
|
{
|
||||||
// generate declaration only
|
// generate declaration only
|
||||||
return synopsis_options::declaration;
|
return code_generator::declaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
// called before code generation of a leaf entity
|
// called before code generation of a leaf entity
|
||||||
synopsis_options on_leaf(const cppast::cpp_entity&) override
|
synopsis_options on_leaf(const cppast::cpp_entity&) override
|
||||||
{
|
{
|
||||||
// generate declaration only
|
// generate declaration only
|
||||||
return synopsis_options::declaration;
|
return code_generator::declaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
// no need to handle indentation, as only a single line is used
|
// no need to handle indentation, as only a single line is used
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue