Add get_class() function to resolve base class types

This commit is contained in:
Jonathan Müller 2017-12-14 19:07:47 +01:00
commit 2c7b06dea9
2 changed files with 91 additions and 0 deletions

View file

@ -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<const cpp_entity> 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<const cpp_class> get_class(const cpp_entity_index& index,
const cpp_base_class& base);
} // namespace cppast
#endif // CPPAST_CPP_CLASS_HPP_INCLUDED

View file

@ -6,6 +6,8 @@
#include <cppast/cpp_entity_index.hpp>
#include <cppast/cpp_entity_kind.hpp>
#include <cppast/cpp_alias_template.hpp>
#include <cppast/cpp_class_template.hpp>
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<const cpp_user_defined_type&>(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<const cpp_template_instantiation_type&>(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("<null id>"), "");
}
type_safe::optional_ref<const cpp_entity> 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<const cpp_class_template&>(*entity).class_());
else if (entity->kind() == cpp_class_template_specialization::kind())
return type_safe::ref(
static_cast<const cpp_class_template_specialization&>(*entity).class_());
else
return entity;
}
type_safe::optional_ref<const cpp_class> 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<const cppast::cpp_alias_template&>(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<const cppast::cpp_type_alias&>(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<const cpp_class&>(entity.value()));
}
}
}
type_safe::optional_ref<const cpp_class> 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<const cpp_entity> 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()));
}