See More

// Copyright (C) 2017-2022 Jonathan Müller and cppast contributors // SPDX-License-Identifier: MIT #ifndef CPPAST_CPP_TYPE_HPP_INCLUDED #define CPPAST_CPP_TYPE_HPP_INCLUDED #include #include #include #include #include namespace cppast { /// The kinds of a [cppast::cpp_type](). enum class cpp_type_kind { builtin_t, user_defined_t, auto_t, decltype_t, decltype_auto_t, cv_qualified_t, pointer_t, reference_t, array_t, function_t, member_function_t, member_object_t, template_parameter_t, template_instantiation_t, dependent_t, unexposed_t, }; /// Base class for all C++ types. class cpp_type : detail::intrusive_list_node { public: cpp_type(const cpp_type&) = delete; cpp_type& operator=(const cpp_type&) = delete; virtual ~cpp_type() noexcept = default; /// \returns The [cppast::cpp_type_kind](). cpp_type_kind kind() const noexcept { return do_get_kind(); } /// \returns The specified user data. void* user_data() const noexcept { return user_data_.load(); } /// \effects Sets some kind of user data. /// /// User data is just some kind of pointer, there are no requirements. /// The class will do no lifetime management. /// /// User data is useful if you need to store additional data for an entity without the need to /// maintain a registry. void set_user_data(void* data) const noexcept { user_data_ = data; } protected: cpp_type() noexcept : user_data_(nullptr) {} private: /// \returns The [cppast::cpp_type_kind](). virtual cpp_type_kind do_get_kind() const noexcept = 0; void on_insert(const cpp_type&) {} mutable std::atomic user_data_; template friend struct detail::intrusive_list_access; friend detail::intrusive_list_node; }; /// An unexposed [cppast::cpp_type](). /// /// This is one where no further information besides a name is available. class cpp_unexposed_type final : public cpp_type { public: /// \returns A newly created unexposed type. static std::unique_ptr build(std::string name) { return std::unique_ptr(new cpp_unexposed_type(std::move(name))); } /// \returns The name of the type. const std::string& name() const noexcept { return name_; } private: cpp_unexposed_type(std::string name) : name_(std::move(name)) {} cpp_type_kind do_get_kind() const noexcept override { return cpp_type_kind::unexposed_t; } std::string name_; }; /// The C++ builtin types. enum cpp_builtin_type_kind : int { cpp_void, //< `void` cpp_bool, //< `bool` cpp_uchar, //< `unsigned char` cpp_ushort, //< `unsigned short` cpp_uint, //< `unsigned int` cpp_ulong, //< `unsigned long` cpp_ulonglong, //< `unsigned long long` cpp_uint128, //< `unsigned __int128` cpp_schar, //< `signed char` cpp_short, //< `short` cpp_int, //< `int` cpp_long, //< `long` cpp_longlong, //< `long long` cpp_int128, //< `__int128` cpp_float, //< `float` cpp_double, //< `double` cpp_longdouble, //< `long double` cpp_float128, //< `__float128` cpp_char, //< `char` cpp_wchar, //< `wchar_t` cpp_char16, //< `char16_t` cpp_char32, //< `char32_t` cpp_nullptr, //< `decltype(nullptr)` aka `std::nullptr_t` }; /// \returns The string representing the spelling of that type in the source code. const char* to_string(cpp_builtin_type_kind kind) noexcept; /// A builtin [cppast::cpp_type](). /// /// This is one where there is no associated [cppast::cpp_entity](). class cpp_builtin_type final : public cpp_type { public: /// \returns A newly created builtin type. static std::unique_ptr build(cpp_builtin_type_kind kind) { return std::unique_ptr(new cpp_builtin_type(kind)); } /// \returns Which builtin type it is. cpp_builtin_type_kind builtin_type_kind() const noexcept { return kind_; } private: cpp_builtin_type(cpp_builtin_type_kind kind) : kind_(kind) {} cpp_type_kind do_get_kind() const noexcept override { return cpp_type_kind::builtin_t; } cpp_builtin_type_kind kind_; }; /// \exclude namespace detail { struct cpp_type_ref_predicate { bool operator()(const cpp_entity& e); }; } // namespace detail /// Reference to a [cppast::cpp_entity]() representing a new type. using cpp_type_ref = basic_cpp_entity_ref; /// A user-defined [cppast::cpp_type](). /// /// It has an associated [cppast::cpp_entity](). class cpp_user_defined_type final : public cpp_type { public: /// \returns A newly created user-defined type. static std::unique_ptr build(cpp_type_ref entity) { return std::unique_ptr(new cpp_user_defined_type(std::move(entity))); } /// \returns A [cppast::cpp_type_ref]() to the associated [cppast::cpp_entity]() that is the /// type. const cpp_type_ref& entity() const noexcept { return entity_; } private: cpp_user_defined_type(cpp_type_ref entity) : entity_(std::move(entity)) {} cpp_type_kind do_get_kind() const noexcept override { return cpp_type_kind::user_defined_t; } cpp_type_ref entity_; }; /// A [cppast::cpp_type]() that isn't given but deduced by `auto`. class cpp_auto_type final : public cpp_type { public: /// \returns A newly created `auto` type. static std::unique_ptr build() { return std::unique_ptr(new cpp_auto_type); } private: cpp_auto_type() = default; cpp_type_kind do_get_kind() const noexcept override { return cpp_type_kind::auto_t; } }; /// A [cppast::cpp_type]() that depends on another type. class cpp_dependent_type final : public cpp_type { public: /// \returns A newly created type dependent on a [cppast::cpp_template_parameter_type](). static std::unique_ptr build( std::string name, std::unique_ptr dependee); /// \returns A newly created type dependent on a [cppast::cpp_template_instantiation_type](). static std::unique_ptr build( std::string name, std::unique_ptr dependee); /// \returns The name of the dependent type. /// \notes It does not include a scope. const std::string& name() const noexcept { return name_; } /// \returns A reference to the [cppast::cpp_type]() it depends one. /// \notes This is either [cppast::cpp_template_parameter_type]() or /// [cppast:cpp_template_instantiation_type](). const cpp_type& dependee() const noexcept { return *dependee_; } private: cpp_dependent_type(std::string name, std::unique_ptr dependee) : name_(std::move(name)), dependee_(std::move(dependee)) {} cpp_type_kind do_get_kind() const noexcept override { return cpp_type_kind::dependent_t; } std::string name_; std::unique_ptr dependee_; }; /// The kinds of C++ cv qualifiers. enum cpp_cv : int { cpp_cv_none, cpp_cv_const, cpp_cv_volatile, cpp_cv_const_volatile, }; /// \returns `true` if the qualifier contains `const`. inline bool is_const(cpp_cv cv) noexcept { return cv == cpp_cv_const || cv == cpp_cv_const_volatile; } /// \returns `true` if the qualifier contains `volatile`. inline bool is_volatile(cpp_cv cv) noexcept { return cv == cpp_cv_volatile || cv == cpp_cv_const_volatile; } /// A [cppast::cpp_cv]() qualified [cppast::cpp_type](). class cpp_cv_qualified_type final : public cpp_type { public: /// \returns A newly created qualified type. /// \requires `cv` must not be [cppast::cpp_cv::cpp_cv_none](). static std::unique_ptr build(std::unique_ptr type, cpp_cv cv) { DEBUG_ASSERT(cv != cpp_cv_none, detail::precondition_error_handler{}); return std::unique_ptr( new cpp_cv_qualified_type(std::move(type), cv)); } /// \returns A reference to the [cppast::cpp_type]() that is qualified. const cpp_type& type() const noexcept { return *type_; } /// \returns The [cppast::cpp_cv]() qualifier. cpp_cv cv_qualifier() const noexcept { return cv_; } private: cpp_cv_qualified_type(std::unique_ptr type, cpp_cv cv) : type_(std::move(type)), cv_(cv) {} cpp_type_kind do_get_kind() const noexcept override { return cpp_type_kind::cv_qualified_t; } std::unique_ptr type_; cpp_cv cv_; }; /// \returns The type without top-level const/volatile qualifiers. const cpp_type& remove_cv(const cpp_type& type) noexcept; /// \returns The type without top-level const qualifiers. const cpp_type& remove_const(const cpp_type& type) noexcept; /// \returns The type without top-level volatile qualifiers. const cpp_type& remove_volatile(const cpp_type& type) noexcept; /// A pointer to a [cppast::cpp_type](). class cpp_pointer_type final : public cpp_type { public: /// \returns A newly created pointer type. static std::unique_ptr build(std::unique_ptr pointee) { return std::unique_ptr(new cpp_pointer_type(std::move(pointee))); } /// \returns A reference to the [cppast::cpp_type]() that is the pointee. const cpp_type& pointee() const noexcept { return *pointee_; } private: cpp_pointer_type(std::unique_ptr pointee) : pointee_(std::move(pointee)) {} cpp_type_kind do_get_kind() const noexcept override { return cpp_type_kind::pointer_t; } std::unique_ptr pointee_; }; /// The kinds of C++ references. enum cpp_reference : int { cpp_ref_none, cpp_ref_lvalue, cpp_ref_rvalue, }; /// A reference to a [cppast::cpp_type](). class cpp_reference_type final : public cpp_type { public: /// \returns A newly created qualified type. /// \requires `ref` must not be [cppast::cpp_reference::cpp_ref_none](). static std::unique_ptr build(std::unique_ptr type, cpp_reference ref) { DEBUG_ASSERT(ref != cpp_ref_none, detail::precondition_error_handler{}); return std::unique_ptr(new cpp_reference_type(std::move(type), ref)); } /// \returns A reference to the [cppast::cpp_type]() that is referenced. const cpp_type& referee() const noexcept { return *referee_; } /// \returns The [cppast::cpp_reference]() type. cpp_reference reference_kind() const noexcept { return ref_; } private: cpp_reference_type(std::unique_ptr referee, cpp_reference ref) : referee_(std::move(referee)), ref_(ref) {} cpp_type_kind do_get_kind() const noexcept override { return cpp_type_kind::reference_t; } std::unique_ptr referee_; cpp_reference ref_; }; /// \returns The type as a string representation. std::string to_string(const cpp_type& type); /// \exclude namespace detail { // whether or not it requires special treatment when printing it // i.e. function pointer types are complex as the identifier has to be put inside bool is_complex_type(const cpp_type& type) noexcept; // write part of the type that comes before the variable name void write_type_prefix(code_generator::output& output, const cpp_type& type); // write part of the type that comes after the name // for non-complex types, this does nothing void write_type_suffix(code_generator::output& output, const cpp_type& type); // write prefix, variadic, name, suffix void write_type(code_generator::output& output, const cpp_type& type, std::string name, bool is_variadic = false); } // namespace detail } // namespace cppast #endif // CPPAST_CPP_TYPE_HPP_INCLUDED