diff --git a/include/cppast/cpp_class.hpp b/include/cppast/cpp_class.hpp index a7a1194..c4642fd 100644 --- a/include/cppast/cpp_class.hpp +++ b/include/cppast/cpp_class.hpp @@ -235,6 +235,16 @@ namespace cppast cpp_class_kind kind_; bool final_; }; + + /// \returns The type the base class refers to. + /// It is either a class or some form of typedef. + type_safe::optional_ref get_class_or_typedef(const cpp_entity_index& index, + const cpp_base_class& base); + + /// \returns The type the base class refers to. + /// Typedefs are unwrapped. + type_safe::optional_ref get_class(const cpp_entity_index& index, + const cpp_base_class& base); } // namespace cppast #endif // CPPAST_CPP_CLASS_HPP_INCLUDED diff --git a/src/cpp_class.cpp b/src/cpp_class.cpp index 84a801d..14cad8b 100644 --- a/src/cpp_class.cpp +++ b/src/cpp_class.cpp @@ -6,6 +6,8 @@ #include #include +#include +#include using namespace cppast; @@ -98,3 +100,82 @@ cpp_entity_kind cpp_class::do_get_entity_kind() const noexcept { return kind(); } + +namespace +{ + cpp_entity_ref get_type_ref(const cpp_type& type) + { + if (type.kind() == cpp_type_kind::user_defined_t) + { + auto& ref = static_cast(type).entity(); + return cpp_entity_ref(ref.id()[0u], ref.name()); + } + else if (type.kind() == cpp_type_kind::template_instantiation_t) + { + auto& ref = + static_cast(type).primary_template(); + return cpp_entity_ref(ref.id()[0u], ref.name()); + } + + DEBUG_ASSERT(type.kind() == cpp_type_kind::template_parameter_t + || type.kind() == cpp_type_kind::decltype_t + || type.kind() == cpp_type_kind::decltype_auto_t + || type.kind() == cpp_type_kind::unexposed_t, + detail::assert_handler{}); + return cpp_entity_ref(cpp_entity_id(""), ""); + } + + type_safe::optional_ref get_entity_impl(const cpp_entity_index& index, + const cpp_entity_ref& ref) + { + auto result = ref.get(index); + if (result.empty()) + return nullptr; + DEBUG_ASSERT(result.size() == 1u, detail::assert_handler{}); + + auto entity = result.front(); + if (entity->kind() == cpp_class_template::kind()) + return type_safe::ref(static_cast(*entity).class_()); + else if (entity->kind() == cpp_class_template_specialization::kind()) + return type_safe::ref( + static_cast(*entity).class_()); + else + return entity; + } + + type_safe::optional_ref get_class_impl(const cpp_entity_index& index, + const cpp_entity_ref& ref) + { + auto entity = get_entity_impl(index, ref); + if (!entity) + return nullptr; + + if (entity.value().kind() == cpp_alias_template::kind()) + { + auto& alias = static_cast(entity.value()); + return get_class_impl(index, get_type_ref(alias.type_alias().underlying_type())); + } + else if (entity.value().kind() == cpp_type_alias::kind()) + { + auto& alias = static_cast(entity.value()); + return get_class_impl(index, get_type_ref(alias.underlying_type())); + } + else + { + DEBUG_ASSERT(entity.value().kind() == cpp_class::kind(), detail::assert_handler{}); + return type_safe::ref(static_cast(entity.value())); + } + } +} + +type_safe::optional_ref cppast::get_class(const cpp_entity_index& index, + const cpp_base_class& base) +{ + return get_class_impl(index, get_type_ref(base.type())); +} + +type_safe::optional_ref cppast::get_class_or_typedef( + const cpp_entity_index& index, const cpp_base_class& base) +{ + return get_entity_impl(index, get_type_ref(base.type())); +}