// Copyright (C) 2017 Jonathan Müller // This file is subject to the license terms in the LICENSE file // found in the top-level directory of this distribution. #ifndef CPPAST_CPP_MEMBER_FUNCTION_HPP_INCLUDED #define CPPAST_CPP_MEMBER_FUNCTION_HPP_INCLUDED #include #include namespace cppast { /// The `virtual`-ness of a member function. /// /// This is a [ts::flag_set]() `enum`. /// \notes It does not specify whether a member function is `virtual` or not, /// only the kind of `virtual`. /// \notes As surprising as it may be, any of these can be used in combination, /// i.e. you can have a `final` non-overriding function or an overriding pure `virtual` function. enum class cpp_virtual_flags { pure, //< Set if the function is pure. override, //< Set if the function overrides a base class function. final, //< Set if the function is marked `final`. }; } // namespace cppast /// \exclude namespace type_safe { template <> struct flag_set_traits : std::true_type { static constexpr std::size_t size() noexcept { return 3u; } }; } // namespace type_safe namespace cppast { /// The `virtual` information of a member function. /// /// This is an optional of the combination of the [cppast::cpp_virtual_flags](). /// If the optional has a value, the member function is `virtual`, /// and the [ts::flag_set]() describes additional information. using cpp_virtual = type_safe::optional>; /// \returns Whether or not a member function is `virtual`. inline bool is_virtual(const cpp_virtual& virt) noexcept { return virt.has_value(); } /// \returns Whether or not a member function is pure. inline bool is_pure(const cpp_virtual& virt) noexcept { return static_cast(virt.value_or(cpp_virtual_flags::final) & cpp_virtual_flags::pure); } /// \returns Whether or not a member function overrides another one. inline bool is_overriding(const cpp_virtual& virt) noexcept { return static_cast(virt.value_or(cpp_virtual_flags::pure) & cpp_virtual_flags::override); } /// \returns Whether or not a member function is `final`. inline bool is_final(const cpp_virtual& virt) noexcept { return static_cast(virt.value_or(cpp_virtual_flags::pure) & cpp_virtual_flags::final); } /// Base classes for all regular member function. /// /// The two derived classes are [cppast::cpp_member_function]() and [cppast::cpp_conversion_op](). class cpp_member_function_base : public cpp_function_base { public: /// \returns The return type of the member function. const cpp_type& return_type() const noexcept { return *return_type_; } /// \returns Whether or not it is `virtual`. bool is_virtual() const noexcept { return virtual_info().has_value(); } /// \returns The `virtual`-ness of the member function. const cpp_virtual& virtual_info() const noexcept { return virtual_; } /// \returns The cv-qualifier on the member function. cpp_cv cv_qualifier() const noexcept { return cv_; } /// \returns The ref-qualifier on the member function. cpp_reference ref_qualifier() const noexcept { return ref_; } /// \returns Whether or not the member function is `constexpr`. bool is_constexpr() const noexcept { return constexpr_; } protected: /// Builder class for member functions. template class basic_member_builder : public basic_builder { public: /// \effects Sets the name and return type. basic_member_builder(std::string name, std::unique_ptr return_type) { this->function = std::unique_ptr(new T(std::move(name), std::move(return_type))); } /// \effects Sets the cv- and ref-qualifier. void cv_ref_qualifier(cpp_cv cv, cpp_reference ref) noexcept { auto& base = static_cast(*this->function); base.cv_ = cv; base.ref_ = ref; } /// \effects Sets the `virtual`-ness of the function. void virtual_info(type_safe::flag_set virt) noexcept { static_cast(*this->function).virtual_ = virt; } /// \effects Marks the function as `constexpr`. void is_constexpr() noexcept { static_cast(*this->function).constexpr_ = true; } protected: basic_member_builder() noexcept = default; }; /// \effects Sets name and return type, as well as the rest to defaults. cpp_member_function_base(std::string name, std::unique_ptr return_type) : cpp_function_base(std::move(name)), return_type_(std::move(return_type)), cv_(cpp_cv_none), ref_(cpp_ref_none), constexpr_(false) { } private: std::unique_ptr return_type_; cpp_virtual virtual_; cpp_cv cv_; cpp_reference ref_; bool constexpr_; }; /// A [cppast::cpp_entity]() modelling a member function. class cpp_member_function final : public cpp_member_function_base { public: static cpp_entity_kind kind() noexcept; /// Builder for [cppast::cpp_member_function](). class builder : public cpp_member_function_base::basic_member_builder { public: using cpp_member_function_base::basic_member_builder:: basic_member_builder; }; private: using cpp_member_function_base::cpp_member_function_base; cpp_entity_kind do_get_entity_kind() const noexcept override; friend basic_member_builder; }; /// A [cppast::cpp_entity]() modelling a C++ conversion operator. class cpp_conversion_op final : public cpp_member_function_base { public: static cpp_entity_kind kind() noexcept; /// Builder for [cppast::cpp_conversion_op](). class builder : public basic_member_builder { public: using basic_member_builder::basic_member_builder; /// \effects Marks the conversion operator `explicit`. void is_explicit() noexcept { function->explicit_ = true; } private: using basic_member_builder::is_variadic; using basic_member_builder::add_parameter; }; /// \returns Whether or not the conversion is `explicit`. bool is_explicit() const noexcept { return explicit_; } private: cpp_conversion_op(std::string name, std::unique_ptr return_t) : cpp_member_function_base(std::move(name), std::move(return_t)), explicit_(false) { } cpp_entity_kind do_get_entity_kind() const noexcept override; bool explicit_; friend basic_member_builder; }; /// A [cppast::cpp_entity]() modelling a C++ constructor. class cpp_constructor final : public cpp_function_base { public: static cpp_entity_kind kind() noexcept; /// Builder for [cppast::cpp_constructor](). class builder : public basic_builder { public: using basic_builder::basic_builder; /// \effects Marks the constructor `explicit`. void is_explicit() noexcept { function->explicit_ = true; } /// \effects Marks the constructor `constexpr`. void is_constexpr() noexcept { function->constexpr_ = true; } }; /// \returns Whether or not the constructor is `explicit`. bool is_explicit() const noexcept { return explicit_; } /// \returns Whether or not the constructor is `constexpr`. bool is_constexpr() const noexcept { return constexpr_; } private: cpp_constructor(std::string name) : cpp_function_base(std::move(name)), explicit_(false), constexpr_(false) { } cpp_entity_kind do_get_entity_kind() const noexcept override; bool explicit_; bool constexpr_; friend basic_builder; }; /// A [cppast::cpp_entity]() modelling a C++ destructor. class cpp_destructor final : public cpp_function_base { public: static cpp_entity_kind kind() noexcept; /// Builds a [cppast::cpp_destructor](). class builder : public basic_builder { public: using basic_builder::basic_builder; /// \effects Sets the `virtual`-ness of the destructor. void virtual_info(cpp_virtual virt) noexcept { function->virtual_ = virt; } private: using basic_builder::add_parameter; using basic_builder::is_variadic; }; /// \returns Whether or not it is `virtual`. bool is_virtual() const noexcept { return virtual_info().has_value(); } /// \returns The `virtual`-ness of the constructor. cpp_virtual virtual_info() const noexcept { return virtual_; } private: cpp_destructor(std::string name) : cpp_function_base(std::move(name)) { } cpp_entity_kind do_get_entity_kind() const noexcept override; cpp_virtual virtual_; friend basic_builder; }; } // namespace cppast #endif // CPPAST_CPP_MEMBER_FUNCTION_HPP_INCLUDED