diff --git a/include/cppast/cpp_entity_kind.hpp b/include/cppast/cpp_entity_kind.hpp index e0e88a6..0e4ecfb 100644 --- a/include/cppast/cpp_entity_kind.hpp +++ b/include/cppast/cpp_entity_kind.hpp @@ -28,6 +28,9 @@ namespace cppast variable_t, + function_parameter_t, + function_t, + count, }; diff --git a/include/cppast/cpp_function.hpp b/include/cppast/cpp_function.hpp new file mode 100644 index 0000000..afb6a9f --- /dev/null +++ b/include/cppast/cpp_function.hpp @@ -0,0 +1,215 @@ +// 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_FUNCTION_HPP_INCLUDED +#define CPPAST_CPP_FUNCTION_HPP_INCLUDED + +#include +#include +#include + +namespace cppast +{ + /// A [cppast::cpp_entity]() modelling a function parameter. + class cpp_function_parameter final : public cpp_variable_base + { + public: + /// \returns A newly created and registered function parameter. + static std::unique_ptr build( + const cpp_entity_index& idx, cpp_entity_id id, std::string name, + std::unique_ptr type, std::unique_ptr def = nullptr); + + private: + cpp_function_parameter(std::string name, std::unique_ptr type, + std::unique_ptr def) + : cpp_variable_base(std::move(name), std::move(type), std::move(def)) + { + } + + cpp_entity_kind do_get_entity_kind() const noexcept override; + }; + + /// The kinds of function bodies of a [cppast::cpp_function_base](). + enum cpp_function_body_kind + { + cpp_function_declaration, //< Just a declaration. + cpp_function_definition, //< Regular definition. + cpp_function_defaulted, //< Defaulted definition. + cpp_function_deleted, //< Deleted definition. + }; + + /// Base class for all entities that are functions. + /// + /// It contains arguments and common flags. + class cpp_function_base : public cpp_entity, + public cpp_entity_container + { + public: + /// \returns The [cppast::cpp_function_body_kind](). + cpp_function_body_kind body_kind() const noexcept + { + return body_; + } + + /// \returns A [ts::optional_ref]() to the [cppast::cpp_expression]() that is the given `noexcept` condition. + /// \notes If this returns `nullptr`, the function has the implicit noexcept value (i.e. none, unless it is a destructor). + /// \notes There is no way to distinguish between `noexcept` and `noexcept(true)`. + type_safe::optional_ref noexcept_condition() const noexcept + { + return type_safe::opt_cref(noexcept_expr_.get()); + } + + /// \returns Whether the function has an ellipsis. + bool is_variadic() const noexcept + { + return variadic_; + } + + protected: + /// Builder class for functions. + /// + /// Inherit from it to provide additional setter. + template + class basic_builder + { + public: + /// \effects Sets the name. + basic_builder(std::string name) : function(new T(name)) + { + } + + /// \effects Adds a parameter. + void add_parameter(std::unique_ptr parameter) + { + static_cast(*function).add_child(std::move(parameter)); + } + + /// \effects Marks the function as variadic. + void is_variadic() + { + static_cast(*function).variadic_ = true; + } + + /// \effects Sets the noexcept condition expression. + void noexcept_condition(std::unique_ptr cond) + { + static_cast(*function).noexcept_expr_ = std::move(cond); + } + + /// \effects Sets the [cppast::cpp_function_body_kind](). + void body_kind(cpp_function_body_kind kind) + { + static_cast(*function).body_ = kind; + } + + /// \effects Registers the function. + /// \returns The finished function. + std::unique_ptr finish(const cpp_entity_index& idx, cpp_entity_id id) + { + idx.register_entity(std::move(id), type_safe::cref(*function)); + return std::move(function); + } + + protected: + basic_builder() = default; + ~basic_builder() noexcept = default; + + std::unique_ptr function; + }; + + cpp_function_base(std::string name) + : cpp_entity(std::move(name)), body_(cpp_function_declaration), variadic_(false) + { + } + + private: + std::unique_ptr noexcept_expr_; + cpp_function_body_kind body_; + bool variadic_; + }; + + /// A [cppast::cpp_entity]() modelling a C++ function. + /// \notes This is not a member function, + /// use [cppast::cpp_member_function]() for that. + /// It can be a `static` function of a class, + /// or a `friend`, however. + class cpp_function final : public cpp_function_base + { + public: + /// Builds a [cppast::cpp_function](). + class builder : public cpp_function_base::basic_builder + { + public: + /// \effects Sets the name and return type. + builder(std::string name, std::unique_ptr return_type) + { + function = std::unique_ptr( + new cpp_function(std::move(name), std::move(return_type))); + } + + /// \effects Sets the storage class. + void storage_class(cpp_storage_specifiers storage) + { + function->storage_ = storage; + } + + /// \effects Marks the function as `constexpr`. + void is_constexpr() + { + function->constexpr_ = true; + } + + /// \effects Marks the function as `friend`. + void is_friend() + { + function->friend_ = true; + } + }; + + /// \returns A reference to the return [cppast::cpp_type](). + const cpp_type& return_type() const noexcept + { + return *return_type_; + } + + /// \returns The [cppast::cpp_storage_specifiers]() of the function. + /// \notes If it is `cpp_storage_class_static` and inside a [cppast::cpp_class](), + /// it is a `static` class function. + cpp_storage_specifiers storage_class() const noexcept + { + return storage_; + } + + /// \returns Whether the function is marked `constexpr`. + bool is_constexpr() const noexcept + { + return constexpr_; + } + + /// \returns Whether the function is a `friend` function of the parent [cppast::cpp_class](). + bool is_friend() const noexcept + { + return friend_; + } + + private: + cpp_entity_kind do_get_entity_kind() const noexcept override; + + cpp_function(std::string name, std::unique_ptr ret) + : cpp_function_base(std::move(name)), + return_type_(std::move(ret)), + storage_(cpp_storage_class_none), + friend_(false), + constexpr_(false) + { + } + + std::unique_ptr return_type_; + cpp_storage_specifiers storage_; + bool friend_; + bool constexpr_; + }; +} // namespace cppast + +#endif // CPPAST_CPP_FUNCTION_HPP_INCLUDED diff --git a/include/cppast/cpp_function_types.hpp b/include/cppast/cpp_function_types.hpp index 00ab89a..656c67e 100644 --- a/include/cppast/cpp_function_types.hpp +++ b/include/cppast/cpp_function_types.hpp @@ -25,14 +25,14 @@ namespace cppast { } - /// \effects Adds an argument type. - void add_argument(std::unique_ptr arg) + /// \effects Adds an parameter type. + void add_parameter(std::unique_ptr arg) { - func_->arguments_.push_back(*func_, std::move(arg)); + func_->parameters_.push_back(*func_, std::move(arg)); } /// \effects Adds an ellipsis, marking it as variadic. - void variadic() + void is_variadic() { func_->variadic_ = true; } @@ -53,10 +53,10 @@ namespace cppast return *return_type_; } - /// \returns An iteratable object iterating over the argument types. - detail::iteratable_intrusive_list argument_types() const noexcept + /// \returns An iteratable object iterating over the parameter types. + detail::iteratable_intrusive_list parameter_types() const noexcept { - return type_safe::ref(arguments_); + return type_safe::ref(parameters_); } /// \returns Whether or not the function is variadic (C-style ellipsis). @@ -77,7 +77,7 @@ namespace cppast } std::unique_ptr return_type_; - detail::intrusive_list arguments_; + detail::intrusive_list parameters_; bool variadic_; }; @@ -99,14 +99,14 @@ namespace cppast { } - /// \effects Adds an argument type. - void add_argument(std::unique_ptr arg) + /// \effects Adds a parameter type. + void add_parameter(std::unique_ptr arg) { - func_->arguments_.push_back(*func_, std::move(arg)); + func_->parameters_.push_back(*func_, std::move(arg)); } /// \effects Adds an ellipsis, marking it as variadic. - void variadic() + void is_variadic() { func_->variadic_ = true; } @@ -133,10 +133,10 @@ namespace cppast return *object_type_; } - /// \returns An iteratable object iterating over the argument types. - detail::iteratable_intrusive_list argument_types() const noexcept + /// \returns An iteratable object iterating over the parameter types. + detail::iteratable_intrusive_list parameter_types() const noexcept { - return type_safe::ref(arguments_); + return type_safe::ref(parameters_); } /// \returns Whether or not the function is variadic (C-style ellipsis). @@ -158,7 +158,7 @@ namespace cppast } std::unique_ptr class_type_, object_type_; - detail::intrusive_list arguments_; + detail::intrusive_list parameters_; bool variadic_; }; diff --git a/include/cppast/cpp_storage_specifiers.hpp b/include/cppast/cpp_storage_specifiers.hpp new file mode 100644 index 0000000..fee9171 --- /dev/null +++ b/include/cppast/cpp_storage_specifiers.hpp @@ -0,0 +1,40 @@ +// 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_STORAGE_SPECIFIERS_HPP_INCLUDED +#define CPPAST_CPP_STORAGE_SPECIFIERS_HPP_INCLUDED + +namespace cppast +{ + /// C++ storage class specifiers. + enum cpp_storage_specifiers + { + cpp_storage_class_none = 0, + + cpp_storage_class_static = 1, + cpp_storage_class_extern = 2, + + cpp_storage_class_thread_local = 4, + }; + + /// \returns Whether the [cppast::cpp_storage_specifiers]() contain `thread_local`. + inline bool is_thread_local(cpp_storage_specifiers spec) noexcept + { + return (spec & cpp_storage_class_thread_local) != 0; + } + + /// \returns Whether the [cppast::cpp_storage_specifiers]() contain `static`. + inline bool is_static(cpp_storage_specifiers spec) noexcept + { + return (spec & cpp_storage_class_static) != 0; + } + + /// \returns Whether the [cppast::cpp_storage_specifiers]() contain `extern`. + inline bool is_extern(cpp_storage_specifiers spec) noexcept + { + return (spec & cpp_storage_class_extern) != 0; + } +} // namespace cppast + +#endif // CPPAST_CPP_STORAGE_SPECIFIERS_HPP_INCLUDED diff --git a/include/cppast/cpp_type.hpp b/include/cppast/cpp_type.hpp index 6540d68..c54edd0 100644 --- a/include/cppast/cpp_type.hpp +++ b/include/cppast/cpp_type.hpp @@ -103,7 +103,7 @@ namespace cppast { public: /// \returns A newly created builtin type. - std::unique_ptr build(std::string name) + static std::unique_ptr build(std::string name) { return std::unique_ptr(new cpp_builtin_type(std::move(name))); } @@ -146,7 +146,7 @@ namespace cppast { public: /// \returns A newly created user-defined type. - std::unique_ptr build(cpp_type_ref entity) + static std::unique_ptr build(cpp_type_ref entity) { return std::unique_ptr( new cpp_user_defined_type(std::move(entity))); diff --git a/include/cppast/cpp_variable.hpp b/include/cppast/cpp_variable.hpp index 2e75bc5..6e3663d 100644 --- a/include/cppast/cpp_variable.hpp +++ b/include/cppast/cpp_variable.hpp @@ -5,23 +5,11 @@ #ifndef CPPAST_CPP_VARIABLE_HPP_INCLUDED #define CPPAST_CPP_VARIABLE_HPP_INCLUDED +#include #include namespace cppast { - /// Storage class and other specifiers for a [cppast::cpp_variable](). - enum cpp_variable_specifiers - { - cpp_var_none = 0, - - cpp_var_static = 1, - cpp_var_extern = 2, - - cpp_var_thread_local = 4, - - cpp_var_constexpr = 8, - }; - /// A [cppast::cpp_entity]() modelling a C++ variable. /// \notes This is not a member variable, /// use [cppast::cpp_member_variable]() for that. @@ -33,24 +21,34 @@ namespace cppast static std::unique_ptr build(const cpp_entity_index& idx, cpp_entity_id id, std::string name, std::unique_ptr type, std::unique_ptr def, - cpp_variable_specifiers spec); + cpp_storage_specifiers spec, bool is_constexpr); - /// \returns The [cppast::cpp_variable_specifiers]() on that variable. - cpp_variable_specifiers specifiers() const noexcept + /// \returns The [cppast::cpp_storage_specifiers]() on that variable. + cpp_storage_specifiers storage_class() const noexcept { - return specifiers_; + return storage_; + } + + /// \returns Whether the variable is marked `constexpr`. + bool is_constexpr() const noexcept + { + return is_constexpr_; } private: cpp_variable(std::string name, std::unique_ptr type, - std::unique_ptr def, cpp_variable_specifiers spec) - : cpp_variable_base(std::move(name), std::move(type), std::move(def)), specifiers_(spec) + std::unique_ptr def, cpp_storage_specifiers spec, + bool is_constexpr) + : cpp_variable_base(std::move(name), std::move(type), std::move(def)), + storage_(spec), + is_constexpr_(is_constexpr) { } cpp_entity_kind do_get_entity_kind() const noexcept override; - cpp_variable_specifiers specifiers_; + cpp_storage_specifiers storage_; + bool is_constexpr_; }; } // namespace cppast diff --git a/src/cpp_entity_kind.cpp b/src/cpp_entity_kind.cpp index 75bedb7..4d26f61 100644 --- a/src/cpp_entity_kind.cpp +++ b/src/cpp_entity_kind.cpp @@ -36,6 +36,11 @@ const char* cppast::to_string(cpp_entity_kind kind) noexcept case cpp_entity_kind::variable_t: return "variable"; + case cpp_entity_kind::function_parameter_t: + return "function parameter"; + case cpp_entity_kind::function_t: + return "function"; + case cpp_entity_kind::count: break; } @@ -59,6 +64,8 @@ bool cppast::is_type(cpp_entity_kind kind) noexcept case cpp_entity_kind::using_declaration_t: case cpp_entity_kind::enum_value_t: case cpp_entity_kind::variable_t: + case cpp_entity_kind::function_parameter_t: + case cpp_entity_kind::function_t: case cpp_entity_kind::count: break; } diff --git a/src/cpp_function.cpp b/src/cpp_function.cpp new file mode 100644 index 0000000..54e4f5c --- /dev/null +++ b/src/cpp_function.cpp @@ -0,0 +1,29 @@ +// 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. + +#include + +#include + +using namespace cppast; + +std::unique_ptr cpp_function_parameter::build( + const cpp_entity_index& idx, cpp_entity_id id, std::string name, std::unique_ptr type, + std::unique_ptr def) +{ + auto result = std::unique_ptr( + new cpp_function_parameter(std::move(name), std::move(type), std::move(def))); + idx.register_entity(std::move(id), type_safe::cref(*result)); + return result; +} + +cpp_entity_kind cpp_function_parameter::do_get_entity_kind() const noexcept +{ + return cpp_entity_kind::function_parameter_t; +} + +cpp_entity_kind cpp_function::do_get_entity_kind() const noexcept +{ + return cpp_entity_kind::function_t; +} diff --git a/src/cpp_type.cpp b/src/cpp_type.cpp index 93407df..0ddf58b 100644 --- a/src/cpp_type.cpp +++ b/src/cpp_type.cpp @@ -69,7 +69,7 @@ bool cppast::is_valid(const cpp_type& type) noexcept if (!can_compose(func.return_type()) || !is_valid(func.return_type())) return false; - for (auto& arg : func.argument_types()) + for (auto& arg : func.parameter_types()) if (!can_compose(arg) || !is_valid(arg)) return false; @@ -84,7 +84,7 @@ bool cppast::is_valid(const cpp_type& type) noexcept else if (!can_compose(func.return_type()) || !is_valid(func.return_type())) return false; - for (auto& arg : func.argument_types()) + for (auto& arg : func.parameter_types()) if (!can_compose(arg) || !is_valid(arg)) return false; diff --git a/src/cpp_variable.cpp b/src/cpp_variable.cpp index bdec5fb..c084362 100644 --- a/src/cpp_variable.cpp +++ b/src/cpp_variable.cpp @@ -11,10 +11,10 @@ using namespace cppast; std::unique_ptr cpp_variable::build(const cpp_entity_index& idx, cpp_entity_id id, std::string name, std::unique_ptr type, std::unique_ptr def, - cpp_variable_specifiers spec) + cpp_storage_specifiers spec, bool is_constexpr) { auto result = std::unique_ptr( - new cpp_variable(std::move(name), std::move(type), std::move(def), spec)); + new cpp_variable(std::move(name), std::move(type), std::move(def), spec, is_constexpr)); idx.register_entity(std::move(id), type_safe::cref(*result)); return result; } diff --git a/src/visitor.cpp b/src/visitor.cpp index 9f65191..951ae18 100644 --- a/src/visitor.cpp +++ b/src/visitor.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,8 @@ bool detail::visit(const cpp_entity& e, detail::visitor_callback_t cb, void* fun return handle_container(e, cb, functor); case cpp_entity_kind::enum_t: return handle_container(e, cb, functor); + case cpp_entity_kind::function_t: + return handle_container(e, cb, functor); case cpp_entity_kind::namespace_alias_t: case cpp_entity_kind::using_directive_t: @@ -51,6 +54,7 @@ bool detail::visit(const cpp_entity& e, detail::visitor_callback_t cb, void* fun case cpp_entity_kind::type_alias_t: case cpp_entity_kind::enum_value_t: case cpp_entity_kind::variable_t: + case cpp_entity_kind::function_parameter_t: return cb(functor, e, visitor_info::leaf_entity); case cpp_entity_kind::count: