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 <type_safe/index.hpp>
|
||||
#include <type_safe/flag_set.hpp>
|
||||
|
||||
#include <cppast/cpp_entity.hpp>
|
||||
#include <cppast/cpp_entity_ref.hpp>
|
||||
|
|
@ -129,14 +130,19 @@ namespace cppast
|
|||
code_generator& operator=(const code_generator&) = delete;
|
||||
virtual ~code_generator() noexcept = default;
|
||||
|
||||
/// Options that control the synopsis.
|
||||
enum synopsis_options
|
||||
/// Flags that control the synopsis.
|
||||
enum synopsis_flags
|
||||
{
|
||||
exclude, //< Exclude the entire entity.
|
||||
declaration, //< Only write declaration.
|
||||
definition, //< Also write definition.
|
||||
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.
|
||||
_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.
|
||||
class output
|
||||
{
|
||||
|
|
@ -177,10 +183,16 @@ namespace cppast
|
|||
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.
|
||||
bool generate_definition() const noexcept
|
||||
{
|
||||
return options_ == definition;
|
||||
return !(options_ & declaration);
|
||||
}
|
||||
|
||||
/// \returns A reference to the generator.
|
||||
|
|
@ -280,6 +292,14 @@ namespace cppast
|
|||
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()`.
|
||||
const output& operator<<(newl_t) const
|
||||
{
|
||||
|
|
@ -309,11 +329,11 @@ namespace cppast
|
|||
/// \effects Will be invoked before code of a container entity is generated.
|
||||
/// The base class version has no effect.
|
||||
/// \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)
|
||||
{
|
||||
(void)e;
|
||||
return definition;
|
||||
return {};
|
||||
}
|
||||
|
||||
/// \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.
|
||||
/// The base class version has no effect.
|
||||
/// \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)
|
||||
{
|
||||
(void)e;
|
||||
return definition;
|
||||
return {};
|
||||
}
|
||||
|
||||
/// \effects Will be invoked when the indentation level should be increased by one.
|
||||
|
|
@ -390,6 +410,14 @@ namespace cppast
|
|||
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.
|
||||
/// It is guaranteed that this is the only way a newline will be printed.
|
||||
/// 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);
|
||||
if (output)
|
||||
{
|
||||
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)
|
||||
|
|
@ -175,7 +182,10 @@ namespace
|
|||
{
|
||||
output << keyword("using") << whitespace << identifier(alias.name())
|
||||
<< punctuation("=");
|
||||
detail::write_type(output, alias.underlying_type(), "");
|
||||
if (output.options() & code_generator::exclude_target)
|
||||
output.excluded(alias);
|
||||
else
|
||||
detail::write_type(output, alias.underlying_type(), "");
|
||||
output << punctuation(";") << newl;
|
||||
}
|
||||
}
|
||||
|
|
@ -485,7 +495,9 @@ namespace
|
|||
output << keyword("friend") << whitespace;
|
||||
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;
|
||||
else
|
||||
{
|
||||
|
|
@ -504,7 +516,8 @@ namespace
|
|||
write_function_parameters(output, func);
|
||||
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("->");
|
||||
detail::write_type(output, func.return_type(), "");
|
||||
|
|
@ -579,7 +592,9 @@ namespace
|
|||
else
|
||||
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;
|
||||
else
|
||||
{
|
||||
|
|
@ -599,7 +614,8 @@ namespace
|
|||
auto need_ws = write_cv_ref(output, func);
|
||||
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("->");
|
||||
detail::write_type(output, func.return_type(), "");
|
||||
|
|
@ -628,7 +644,11 @@ namespace
|
|||
|
||||
auto pos = op.name().find("operator");
|
||||
output << identifier(op.name().substr(0u, pos)) << keyword("operator") << whitespace;
|
||||
detail::write_type(output, op.return_type(), "");
|
||||
if (output.options() & code_generator::exclude_return)
|
||||
output.excluded(op);
|
||||
else
|
||||
detail::write_type(output, op.return_type(), "");
|
||||
|
||||
output << punctuation("(") << punctuation(")");
|
||||
auto need_ws = write_cv_ref(output, op);
|
||||
write_noexcept(output, op, need_ws);
|
||||
|
|
|
|||
|
|
@ -6,11 +6,15 @@
|
|||
|
||||
#include "test_parser.hpp"
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
TEST_CASE("code_generator")
|
||||
{
|
||||
// no need to check much here, as each entity check separately
|
||||
// only write some file with equivalent code and synopsis
|
||||
auto code = R"(using type=int;
|
||||
SECTION("basic")
|
||||
{
|
||||
// no need to check much here, as each entity check separately
|
||||
// only write some file with equivalent code and synopsis
|
||||
auto code = R"(using type=int;
|
||||
|
||||
struct foo{
|
||||
int a;
|
||||
|
|
@ -34,6 +38,60 @@ void func(int(*)(int));
|
|||
extern void(* ptr)(int(*)(int))=&func;
|
||||
)";
|
||||
|
||||
auto file = parse({}, "code_generator.cpp", code);
|
||||
REQUIRE(get_code(*file) == code);
|
||||
auto file = parse({}, "code_generator.cpp", 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
|
||||
{
|
||||
public:
|
||||
test_generator(synopsis_options options) : options_(std::move(options))
|
||||
{
|
||||
}
|
||||
|
||||
const std::string& str() const noexcept
|
||||
{
|
||||
return str_;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
++indent_;
|
||||
|
|
@ -78,14 +92,16 @@ private:
|
|||
was_newline_ = true;
|
||||
}
|
||||
|
||||
std::string str_;
|
||||
unsigned indent_ = 0;
|
||||
bool was_newline_ = false;
|
||||
std::string str_;
|
||||
synopsis_options options_;
|
||||
unsigned indent_ = 0;
|
||||
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);
|
||||
auto str = generator.str();
|
||||
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
|
||||
{
|
||||
// generate declaration only
|
||||
return synopsis_options::declaration;
|
||||
return code_generator::declaration;
|
||||
}
|
||||
|
||||
// called before code generation of a leaf entity
|
||||
synopsis_options on_leaf(const cppast::cpp_entity&) override
|
||||
{
|
||||
// generate declaration only
|
||||
return synopsis_options::declaration;
|
||||
return code_generator::declaration;
|
||||
}
|
||||
|
||||
// no need to handle indentation, as only a single line is used
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue