Update clang-format
This commit is contained in:
parent
c755a885bf
commit
9f18b7f4d8
89 changed files with 11377 additions and 11546 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -12,32 +12,32 @@ using namespace cppast;
|
|||
|
||||
namespace
|
||||
{
|
||||
const char* get_attribute_name(cpp_attribute_kind kind) noexcept
|
||||
const char* get_attribute_name(cpp_attribute_kind kind) noexcept
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case cpp_attribute_kind::alignas_:
|
||||
return "alignas";
|
||||
case cpp_attribute_kind::carries_dependency:
|
||||
return "carries_dependency";
|
||||
case cpp_attribute_kind::deprecated:
|
||||
return "deprecated";
|
||||
case cpp_attribute_kind::fallthrough:
|
||||
return "fallthrough";
|
||||
case cpp_attribute_kind::maybe_unused:
|
||||
return "maybe_unused";
|
||||
case cpp_attribute_kind::nodiscard:
|
||||
return "nodiscard";
|
||||
case cpp_attribute_kind::noreturn:
|
||||
return "noreturn";
|
||||
case cpp_attribute_kind::alignas_:
|
||||
return "alignas";
|
||||
case cpp_attribute_kind::carries_dependency:
|
||||
return "carries_dependency";
|
||||
case cpp_attribute_kind::deprecated:
|
||||
return "deprecated";
|
||||
case cpp_attribute_kind::fallthrough:
|
||||
return "fallthrough";
|
||||
case cpp_attribute_kind::maybe_unused:
|
||||
return "maybe_unused";
|
||||
case cpp_attribute_kind::nodiscard:
|
||||
return "nodiscard";
|
||||
case cpp_attribute_kind::noreturn:
|
||||
return "noreturn";
|
||||
|
||||
case cpp_attribute_kind::unknown:
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
return "<error>";
|
||||
case cpp_attribute_kind::unknown:
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
return "<error>";
|
||||
}
|
||||
} // namespace
|
||||
|
||||
cpp_attribute::cpp_attribute(cpp_attribute_kind kind,
|
||||
type_safe::optional<cpp_token_string> arguments)
|
||||
|
|
@ -49,13 +49,13 @@ cpp_attribute::cpp_attribute(cpp_attribute_kind kind,
|
|||
type_safe::optional_ref<const cpp_attribute> cppast::has_attribute(
|
||||
const cpp_attribute_list& attributes, const std::string& name)
|
||||
{
|
||||
auto iter =
|
||||
std::find_if(attributes.begin(), attributes.end(), [&](const cpp_attribute& attribute) {
|
||||
if (attribute.scope())
|
||||
return attribute.scope().value() + "::" + attribute.name() == name;
|
||||
else
|
||||
return attribute.name() == name;
|
||||
});
|
||||
auto iter
|
||||
= std::find_if(attributes.begin(), attributes.end(), [&](const cpp_attribute& attribute) {
|
||||
if (attribute.scope())
|
||||
return attribute.scope().value() + "::" + attribute.name() == name;
|
||||
else
|
||||
return attribute.name() == name;
|
||||
});
|
||||
|
||||
if (iter == attributes.end())
|
||||
return nullptr;
|
||||
|
|
@ -66,9 +66,9 @@ type_safe::optional_ref<const cpp_attribute> cppast::has_attribute(
|
|||
type_safe::optional_ref<const cpp_attribute> cppast::has_attribute(
|
||||
const cpp_attribute_list& attributes, cpp_attribute_kind kind)
|
||||
{
|
||||
auto iter =
|
||||
std::find_if(attributes.begin(), attributes.end(),
|
||||
[&](const cpp_attribute& attribute) { return attribute.kind() == kind; });
|
||||
auto iter
|
||||
= std::find_if(attributes.begin(), attributes.end(),
|
||||
[&](const cpp_attribute& attribute) { return attribute.kind() == kind; });
|
||||
|
||||
if (iter == attributes.end())
|
||||
return nullptr;
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
|
||||
#include <cppast/cpp_class.hpp>
|
||||
|
||||
#include <cppast/cpp_entity_index.hpp>
|
||||
#include <cppast/cpp_entity_kind.hpp>
|
||||
#include <cppast/cpp_alias_template.hpp>
|
||||
#include <cppast/cpp_class_template.hpp>
|
||||
#include <cppast/cpp_entity_index.hpp>
|
||||
#include <cppast/cpp_entity_kind.hpp>
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
|
|
@ -103,70 +103,69 @@ cpp_entity_kind cpp_class::do_get_entity_kind() const noexcept
|
|||
|
||||
namespace
|
||||
{
|
||||
cpp_entity_ref get_type_ref(const cpp_type& type)
|
||||
cpp_entity_ref get_type_ref(const cpp_type& type)
|
||||
{
|
||||
if (type.kind() == cpp_type_kind::user_defined_t)
|
||||
{
|
||||
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>"), "");
|
||||
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());
|
||||
}
|
||||
|
||||
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{});
|
||||
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>"), "");
|
||||
}
|
||||
|
||||
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_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()));
|
||||
}
|
||||
|
||||
type_safe::optional_ref<const cpp_class> get_class_impl(const cpp_entity_index& index,
|
||||
const cpp_entity_ref& ref)
|
||||
else if (entity.value().kind() == cpp_type_alias::kind())
|
||||
{
|
||||
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()));
|
||||
}
|
||||
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()));
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
type_safe::optional_ref<const cpp_class> cppast::get_class(const cpp_entity_index& index,
|
||||
const cpp_base_class& base)
|
||||
|
|
|
|||
|
|
@ -4,17 +4,16 @@
|
|||
|
||||
#include <cppast/cpp_entity_index.hpp>
|
||||
|
||||
#include <cppast/detail/assert.hpp>
|
||||
#include <cppast/cpp_entity.hpp>
|
||||
#include <cppast/cpp_entity_kind.hpp>
|
||||
#include <cppast/cpp_file.hpp>
|
||||
#include <cppast/detail/assert.hpp>
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
cpp_entity_index::duplicate_definition_error::duplicate_definition_error()
|
||||
: std::logic_error("duplicate registration of entity definition")
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
void cpp_entity_index::register_definition(cpp_entity_id id,
|
||||
type_safe::object_ref<const cpp_entity> entity) const
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ std::unique_ptr<cpp_enum_value> cpp_enum_value::build(const cpp_entity_index& id
|
|||
std::string name,
|
||||
std::unique_ptr<cpp_expression> value)
|
||||
{
|
||||
auto result =
|
||||
std::unique_ptr<cpp_enum_value>(new cpp_enum_value(std::move(name), std::move(value)));
|
||||
auto result
|
||||
= std::unique_ptr<cpp_enum_value>(new cpp_enum_value(std::move(name), std::move(value)));
|
||||
idx.register_definition(std::move(id), type_safe::ref(*result));
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,77 +8,77 @@ using namespace cppast;
|
|||
|
||||
namespace
|
||||
{
|
||||
void write_literal(code_generator::output& output, const cpp_literal_expression& expr)
|
||||
void write_literal(code_generator::output& output, const cpp_literal_expression& expr)
|
||||
{
|
||||
auto type_kind = cpp_void;
|
||||
if (expr.type().kind() == cpp_type_kind::builtin_t)
|
||||
type_kind = static_cast<const cpp_builtin_type&>(expr.type()).builtin_type_kind();
|
||||
else if (expr.type().kind() == cpp_type_kind::pointer_t)
|
||||
{
|
||||
auto type_kind = cpp_void;
|
||||
if (expr.type().kind() == cpp_type_kind::builtin_t)
|
||||
type_kind = static_cast<const cpp_builtin_type&>(expr.type()).builtin_type_kind();
|
||||
else if (expr.type().kind() == cpp_type_kind::pointer_t)
|
||||
auto& pointee = static_cast<const cpp_pointer_type&>(expr.type()).pointee();
|
||||
if (pointee.kind() == cpp_type_kind::builtin_t)
|
||||
{
|
||||
auto& pointee = static_cast<const cpp_pointer_type&>(expr.type()).pointee();
|
||||
if (pointee.kind() == cpp_type_kind::builtin_t)
|
||||
{
|
||||
auto& builtin_pointee = static_cast<const cpp_builtin_type&>(pointee);
|
||||
if (builtin_pointee.builtin_type_kind() == cpp_char
|
||||
|| builtin_pointee.builtin_type_kind() == cpp_wchar
|
||||
|| builtin_pointee.builtin_type_kind() == cpp_char16
|
||||
|| builtin_pointee.builtin_type_kind() == cpp_char32)
|
||||
// pointer to char aka string
|
||||
type_kind = builtin_pointee.builtin_type_kind();
|
||||
}
|
||||
}
|
||||
|
||||
switch (type_kind)
|
||||
{
|
||||
case cpp_void:
|
||||
output << token_seq(expr.value());
|
||||
break;
|
||||
|
||||
case cpp_bool:
|
||||
output << keyword(expr.value());
|
||||
break;
|
||||
|
||||
case cpp_uchar:
|
||||
case cpp_ushort:
|
||||
case cpp_uint:
|
||||
case cpp_ulong:
|
||||
case cpp_ulonglong:
|
||||
case cpp_uint128:
|
||||
case cpp_schar:
|
||||
case cpp_short:
|
||||
case cpp_int:
|
||||
case cpp_long:
|
||||
case cpp_longlong:
|
||||
case cpp_int128:
|
||||
output << int_literal(expr.value());
|
||||
break;
|
||||
|
||||
case cpp_float:
|
||||
case cpp_double:
|
||||
case cpp_longdouble:
|
||||
case cpp_float128:
|
||||
output << float_literal(expr.value());
|
||||
break;
|
||||
|
||||
case cpp_char:
|
||||
case cpp_wchar:
|
||||
case cpp_char16:
|
||||
case cpp_char32:
|
||||
output << string_literal(expr.value());
|
||||
break;
|
||||
|
||||
case cpp_nullptr:
|
||||
output << keyword(expr.value());
|
||||
break;
|
||||
auto& builtin_pointee = static_cast<const cpp_builtin_type&>(pointee);
|
||||
if (builtin_pointee.builtin_type_kind() == cpp_char
|
||||
|| builtin_pointee.builtin_type_kind() == cpp_wchar
|
||||
|| builtin_pointee.builtin_type_kind() == cpp_char16
|
||||
|| builtin_pointee.builtin_type_kind() == cpp_char32)
|
||||
// pointer to char aka string
|
||||
type_kind = builtin_pointee.builtin_type_kind();
|
||||
}
|
||||
}
|
||||
|
||||
void write_unexposed(code_generator::output& output, const cpp_unexposed_expression& expr)
|
||||
switch (type_kind)
|
||||
{
|
||||
detail::write_token_string(output, expr.expression());
|
||||
case cpp_void:
|
||||
output << token_seq(expr.value());
|
||||
break;
|
||||
|
||||
case cpp_bool:
|
||||
output << keyword(expr.value());
|
||||
break;
|
||||
|
||||
case cpp_uchar:
|
||||
case cpp_ushort:
|
||||
case cpp_uint:
|
||||
case cpp_ulong:
|
||||
case cpp_ulonglong:
|
||||
case cpp_uint128:
|
||||
case cpp_schar:
|
||||
case cpp_short:
|
||||
case cpp_int:
|
||||
case cpp_long:
|
||||
case cpp_longlong:
|
||||
case cpp_int128:
|
||||
output << int_literal(expr.value());
|
||||
break;
|
||||
|
||||
case cpp_float:
|
||||
case cpp_double:
|
||||
case cpp_longdouble:
|
||||
case cpp_float128:
|
||||
output << float_literal(expr.value());
|
||||
break;
|
||||
|
||||
case cpp_char:
|
||||
case cpp_wchar:
|
||||
case cpp_char16:
|
||||
case cpp_char32:
|
||||
output << string_literal(expr.value());
|
||||
break;
|
||||
|
||||
case cpp_nullptr:
|
||||
output << keyword(expr.value());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void write_unexposed(code_generator::output& output, const cpp_unexposed_expression& expr)
|
||||
{
|
||||
detail::write_token_string(output, expr.expression());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void detail::write_expression(code_generator::output& output, const cpp_expression& expr)
|
||||
{
|
||||
switch (expr.kind())
|
||||
|
|
|
|||
|
|
@ -15,73 +15,73 @@ using namespace cppast;
|
|||
|
||||
namespace
|
||||
{
|
||||
type_safe::optional_ref<const cpp_forward_declarable> get_declarable(const cpp_entity& e)
|
||||
type_safe::optional_ref<const cpp_forward_declarable> get_declarable(const cpp_entity& e)
|
||||
{
|
||||
switch (e.kind())
|
||||
{
|
||||
switch (e.kind())
|
||||
{
|
||||
case cpp_entity_kind::enum_t:
|
||||
return type_safe::ref(static_cast<const cpp_enum&>(e));
|
||||
case cpp_entity_kind::class_t:
|
||||
return type_safe::ref(static_cast<const cpp_class&>(e));
|
||||
case cpp_entity_kind::variable_t:
|
||||
return type_safe::ref(static_cast<const cpp_variable&>(e));
|
||||
case cpp_entity_kind::function_t:
|
||||
case cpp_entity_kind::member_function_t:
|
||||
case cpp_entity_kind::conversion_op_t:
|
||||
case cpp_entity_kind::constructor_t:
|
||||
case cpp_entity_kind::destructor_t:
|
||||
return type_safe::ref(static_cast<const cpp_function_base&>(e));
|
||||
case cpp_entity_kind::function_template_t:
|
||||
case cpp_entity_kind::function_template_specialization_t:
|
||||
case cpp_entity_kind::class_template_t:
|
||||
case cpp_entity_kind::class_template_specialization_t:
|
||||
return get_declarable(*static_cast<const cpp_template&>(e).begin());
|
||||
case cpp_entity_kind::enum_t:
|
||||
return type_safe::ref(static_cast<const cpp_enum&>(e));
|
||||
case cpp_entity_kind::class_t:
|
||||
return type_safe::ref(static_cast<const cpp_class&>(e));
|
||||
case cpp_entity_kind::variable_t:
|
||||
return type_safe::ref(static_cast<const cpp_variable&>(e));
|
||||
case cpp_entity_kind::function_t:
|
||||
case cpp_entity_kind::member_function_t:
|
||||
case cpp_entity_kind::conversion_op_t:
|
||||
case cpp_entity_kind::constructor_t:
|
||||
case cpp_entity_kind::destructor_t:
|
||||
return type_safe::ref(static_cast<const cpp_function_base&>(e));
|
||||
case cpp_entity_kind::function_template_t:
|
||||
case cpp_entity_kind::function_template_specialization_t:
|
||||
case cpp_entity_kind::class_template_t:
|
||||
case cpp_entity_kind::class_template_specialization_t:
|
||||
return get_declarable(*static_cast<const cpp_template&>(e).begin());
|
||||
|
||||
case cpp_entity_kind::file_t:
|
||||
case cpp_entity_kind::macro_parameter_t:
|
||||
case cpp_entity_kind::macro_definition_t:
|
||||
case cpp_entity_kind::include_directive_t:
|
||||
case cpp_entity_kind::language_linkage_t:
|
||||
case cpp_entity_kind::namespace_t:
|
||||
case cpp_entity_kind::namespace_alias_t:
|
||||
case cpp_entity_kind::using_directive_t:
|
||||
case cpp_entity_kind::using_declaration_t:
|
||||
case cpp_entity_kind::type_alias_t:
|
||||
case cpp_entity_kind::enum_value_t:
|
||||
case cpp_entity_kind::access_specifier_t:
|
||||
case cpp_entity_kind::base_class_t:
|
||||
case cpp_entity_kind::member_variable_t:
|
||||
case cpp_entity_kind::bitfield_t:
|
||||
case cpp_entity_kind::function_parameter_t:
|
||||
case cpp_entity_kind::friend_t:
|
||||
case cpp_entity_kind::template_type_parameter_t:
|
||||
case cpp_entity_kind::non_type_template_parameter_t:
|
||||
case cpp_entity_kind::template_template_parameter_t:
|
||||
case cpp_entity_kind::alias_template_t:
|
||||
case cpp_entity_kind::variable_template_t:
|
||||
case cpp_entity_kind::static_assert_t:
|
||||
case cpp_entity_kind::unexposed_t:
|
||||
return nullptr;
|
||||
|
||||
case cpp_entity_kind::count:
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
case cpp_entity_kind::file_t:
|
||||
case cpp_entity_kind::macro_parameter_t:
|
||||
case cpp_entity_kind::macro_definition_t:
|
||||
case cpp_entity_kind::include_directive_t:
|
||||
case cpp_entity_kind::language_linkage_t:
|
||||
case cpp_entity_kind::namespace_t:
|
||||
case cpp_entity_kind::namespace_alias_t:
|
||||
case cpp_entity_kind::using_directive_t:
|
||||
case cpp_entity_kind::using_declaration_t:
|
||||
case cpp_entity_kind::type_alias_t:
|
||||
case cpp_entity_kind::enum_value_t:
|
||||
case cpp_entity_kind::access_specifier_t:
|
||||
case cpp_entity_kind::base_class_t:
|
||||
case cpp_entity_kind::member_variable_t:
|
||||
case cpp_entity_kind::bitfield_t:
|
||||
case cpp_entity_kind::function_parameter_t:
|
||||
case cpp_entity_kind::friend_t:
|
||||
case cpp_entity_kind::template_type_parameter_t:
|
||||
case cpp_entity_kind::non_type_template_parameter_t:
|
||||
case cpp_entity_kind::template_template_parameter_t:
|
||||
case cpp_entity_kind::alias_template_t:
|
||||
case cpp_entity_kind::variable_template_t:
|
||||
case cpp_entity_kind::static_assert_t:
|
||||
case cpp_entity_kind::unexposed_t:
|
||||
return nullptr;
|
||||
|
||||
case cpp_entity_kind::count:
|
||||
break;
|
||||
}
|
||||
|
||||
type_safe::optional_ref<const cpp_entity> get_definition_impl(const cpp_entity_index& idx,
|
||||
const cpp_entity& e)
|
||||
{
|
||||
auto declarable = get_declarable(e);
|
||||
if (!declarable || declarable.value().is_definition())
|
||||
// not declarable or is a definition
|
||||
// return reference to entity itself
|
||||
return type_safe::ref(e);
|
||||
// else lookup definition
|
||||
return idx.lookup_definition(declarable.value().definition().value());
|
||||
}
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
type_safe::optional_ref<const cpp_entity> get_definition_impl(const cpp_entity_index& idx,
|
||||
const cpp_entity& e)
|
||||
{
|
||||
auto declarable = get_declarable(e);
|
||||
if (!declarable || declarable.value().is_definition())
|
||||
// not declarable or is a definition
|
||||
// return reference to entity itself
|
||||
return type_safe::ref(e);
|
||||
// else lookup definition
|
||||
return idx.lookup_definition(declarable.value().definition().value());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool cppast::is_definition(const cpp_entity& e) noexcept
|
||||
|
|
|
|||
1014
src/cpp_token.cpp
1014
src/cpp_token.cpp
File diff suppressed because it is too large
Load diff
533
src/cpp_type.cpp
533
src/cpp_type.cpp
|
|
@ -10,8 +10,8 @@
|
|||
#include <cppast/cpp_entity.hpp>
|
||||
#include <cppast/cpp_entity_kind.hpp>
|
||||
#include <cppast/cpp_function_type.hpp>
|
||||
#include <cppast/cpp_type_alias.hpp>
|
||||
#include <cppast/cpp_template.hpp>
|
||||
#include <cppast/cpp_type_alias.hpp>
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
|
|
@ -174,36 +174,36 @@ std::unique_ptr<cpp_dependent_type> cpp_dependent_type::build(
|
|||
|
||||
namespace
|
||||
{
|
||||
// is directly a complex type
|
||||
// is_complex_type also checks for children
|
||||
bool is_direct_complex(const cpp_type& type) noexcept
|
||||
// is directly a complex type
|
||||
// is_complex_type also checks for children
|
||||
bool is_direct_complex(const cpp_type& type) noexcept
|
||||
{
|
||||
switch (type.kind())
|
||||
{
|
||||
switch (type.kind())
|
||||
{
|
||||
case cpp_type_kind::builtin_t:
|
||||
case cpp_type_kind::user_defined_t:
|
||||
case cpp_type_kind::auto_t:
|
||||
case cpp_type_kind::decltype_t:
|
||||
case cpp_type_kind::decltype_auto_t:
|
||||
case cpp_type_kind::cv_qualified_t:
|
||||
case cpp_type_kind::pointer_t:
|
||||
case cpp_type_kind::reference_t:
|
||||
case cpp_type_kind::template_parameter_t:
|
||||
case cpp_type_kind::template_instantiation_t:
|
||||
case cpp_type_kind::dependent_t:
|
||||
case cpp_type_kind::unexposed_t:
|
||||
return false;
|
||||
|
||||
case cpp_type_kind::array_t:
|
||||
case cpp_type_kind::function_t:
|
||||
case cpp_type_kind::member_function_t:
|
||||
case cpp_type_kind::member_object_t:
|
||||
return true;
|
||||
}
|
||||
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
case cpp_type_kind::builtin_t:
|
||||
case cpp_type_kind::user_defined_t:
|
||||
case cpp_type_kind::auto_t:
|
||||
case cpp_type_kind::decltype_t:
|
||||
case cpp_type_kind::decltype_auto_t:
|
||||
case cpp_type_kind::cv_qualified_t:
|
||||
case cpp_type_kind::pointer_t:
|
||||
case cpp_type_kind::reference_t:
|
||||
case cpp_type_kind::template_parameter_t:
|
||||
case cpp_type_kind::template_instantiation_t:
|
||||
case cpp_type_kind::dependent_t:
|
||||
case cpp_type_kind::unexposed_t:
|
||||
return false;
|
||||
|
||||
case cpp_type_kind::array_t:
|
||||
case cpp_type_kind::function_t:
|
||||
case cpp_type_kind::member_function_t:
|
||||
case cpp_type_kind::member_object_t:
|
||||
return true;
|
||||
}
|
||||
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
return false;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool detail::is_complex_type(const cpp_type& type) noexcept
|
||||
|
|
@ -226,281 +226,278 @@ bool detail::is_complex_type(const cpp_type& type) noexcept
|
|||
|
||||
namespace
|
||||
{
|
||||
void comma(const code_generator::output& output)
|
||||
{
|
||||
output << punctuation(",");
|
||||
if (output.formatting().is_set(formatting_flags::comma_ws))
|
||||
output << whitespace;
|
||||
}
|
||||
void comma(const code_generator::output& output)
|
||||
{
|
||||
output << punctuation(",");
|
||||
if (output.formatting().is_set(formatting_flags::comma_ws))
|
||||
output << whitespace;
|
||||
}
|
||||
|
||||
void bracket_ws(const code_generator::output& output)
|
||||
{
|
||||
if (output.formatting().is_set(formatting_flags::bracket_ws))
|
||||
output << whitespace;
|
||||
}
|
||||
void bracket_ws(const code_generator::output& output)
|
||||
{
|
||||
if (output.formatting().is_set(formatting_flags::bracket_ws))
|
||||
output << whitespace;
|
||||
}
|
||||
|
||||
void operator_ws(const code_generator::output& output)
|
||||
{
|
||||
if (output.formatting().is_set(formatting_flags::operator_ws))
|
||||
output << whitespace;
|
||||
}
|
||||
void operator_ws(const code_generator::output& output)
|
||||
{
|
||||
if (output.formatting().is_set(formatting_flags::operator_ws))
|
||||
output << whitespace;
|
||||
}
|
||||
|
||||
void write_builtin(code_generator::output& output, const cpp_builtin_type& type)
|
||||
{
|
||||
output << keyword(to_string(type.builtin_type_kind()));
|
||||
}
|
||||
void write_builtin(code_generator::output& output, const cpp_builtin_type& type)
|
||||
{
|
||||
output << keyword(to_string(type.builtin_type_kind()));
|
||||
}
|
||||
|
||||
void write_user_defined(code_generator::output& output, const cpp_user_defined_type& type)
|
||||
{
|
||||
output << type.entity();
|
||||
}
|
||||
void write_user_defined(code_generator::output& output, const cpp_user_defined_type& type)
|
||||
{
|
||||
output << type.entity();
|
||||
}
|
||||
|
||||
void write_auto(code_generator::output& output, const cpp_auto_type&)
|
||||
{
|
||||
output << keyword("auto");
|
||||
}
|
||||
void write_auto(code_generator::output& output, const cpp_auto_type&)
|
||||
{
|
||||
output << keyword("auto");
|
||||
}
|
||||
|
||||
void write_decltype(code_generator::output& output, const cpp_decltype_type& type)
|
||||
{
|
||||
output << keyword("decltype") << punctuation("(") << bracket_ws;
|
||||
detail::write_expression(output, type.expression());
|
||||
output << bracket_ws << punctuation(")");
|
||||
}
|
||||
void write_decltype(code_generator::output& output, const cpp_decltype_type& type)
|
||||
{
|
||||
output << keyword("decltype") << punctuation("(") << bracket_ws;
|
||||
detail::write_expression(output, type.expression());
|
||||
output << bracket_ws << punctuation(")");
|
||||
}
|
||||
|
||||
void write_decltype_auto(code_generator::output& output, const cpp_decltype_auto_type&)
|
||||
{
|
||||
output << keyword("decltype") << punctuation("(") << bracket_ws << keyword("auto")
|
||||
<< bracket_ws << punctuation(")");
|
||||
}
|
||||
void write_decltype_auto(code_generator::output& output, const cpp_decltype_auto_type&)
|
||||
{
|
||||
output << keyword("decltype") << punctuation("(") << bracket_ws << keyword("auto") << bracket_ws
|
||||
<< punctuation(")");
|
||||
}
|
||||
|
||||
void write_cv_qualified_prefix(code_generator::output& output,
|
||||
const cpp_cv_qualified_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.type());
|
||||
void write_cv_qualified_prefix(code_generator::output& output, const cpp_cv_qualified_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.type());
|
||||
|
||||
if (is_direct_complex(type.type()))
|
||||
output << punctuation("(") << bracket_ws;
|
||||
|
||||
if (is_const(type.cv_qualifier()))
|
||||
output << whitespace << keyword("const");
|
||||
if (is_volatile(type.cv_qualifier()))
|
||||
output << whitespace << keyword("volatile");
|
||||
}
|
||||
|
||||
void write_cv_qualified_suffix(code_generator::output& output,
|
||||
const cpp_cv_qualified_type& type)
|
||||
{
|
||||
if (is_direct_complex(type.type()))
|
||||
output << bracket_ws << punctuation(")");
|
||||
detail::write_type_suffix(output, type.type());
|
||||
}
|
||||
|
||||
bool pointer_requires_paren(const cpp_pointer_type& type)
|
||||
{
|
||||
auto kind = type.pointee().kind();
|
||||
return kind == cpp_type_kind::function_t || kind == cpp_type_kind::array_t;
|
||||
}
|
||||
|
||||
void write_pointer_prefix(code_generator::output& output, const cpp_pointer_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.pointee());
|
||||
|
||||
if (pointer_requires_paren(type))
|
||||
output << punctuation("(") << bracket_ws;
|
||||
else if (output.formatting().is_set(formatting_flags::ptr_ref_var))
|
||||
output << whitespace;
|
||||
|
||||
output << punctuation("*");
|
||||
}
|
||||
|
||||
void write_pointer_suffix(code_generator::output& output, const cpp_pointer_type& type)
|
||||
{
|
||||
if (pointer_requires_paren(type))
|
||||
output << bracket_ws << punctuation(")");
|
||||
detail::write_type_suffix(output, type.pointee());
|
||||
}
|
||||
|
||||
void write_reference_prefix(code_generator::output& output, const cpp_reference_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.referee());
|
||||
|
||||
if (is_direct_complex(type.referee()))
|
||||
output << punctuation("(") << bracket_ws;
|
||||
else if (output.formatting().is_set(formatting_flags::ptr_ref_var))
|
||||
output << whitespace;
|
||||
|
||||
if (type.reference_kind() == cpp_ref_lvalue)
|
||||
output << punctuation("&");
|
||||
else if (type.reference_kind() == cpp_ref_rvalue)
|
||||
output << punctuation("&&");
|
||||
else
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
}
|
||||
|
||||
void write_reference_suffix(code_generator::output& output, const cpp_reference_type& type)
|
||||
{
|
||||
if (is_direct_complex(type.referee()))
|
||||
output << bracket_ws << punctuation(")");
|
||||
detail::write_type_suffix(output, type.referee());
|
||||
}
|
||||
|
||||
void write_array_prefix(code_generator::output& output, const cpp_array_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.value_type());
|
||||
}
|
||||
|
||||
void write_array_suffix(code_generator::output& output, const cpp_array_type& type)
|
||||
{
|
||||
output << punctuation("[");
|
||||
if (type.size())
|
||||
{
|
||||
output << bracket_ws;
|
||||
detail::write_expression(output, type.size().value());
|
||||
output << bracket_ws;
|
||||
}
|
||||
output << punctuation("]");
|
||||
detail::write_type_suffix(output, type.value_type());
|
||||
}
|
||||
|
||||
void write_function_prefix(code_generator::output& output, const cpp_function_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.return_type());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void write_parameters(code_generator::output& output, const T& type)
|
||||
{
|
||||
if (is_direct_complex(type.type()))
|
||||
output << punctuation("(") << bracket_ws;
|
||||
|
||||
auto need_sep = false;
|
||||
for (auto& param : type.parameter_types())
|
||||
{
|
||||
if (need_sep)
|
||||
output << comma;
|
||||
else
|
||||
need_sep = true;
|
||||
detail::write_type_prefix(output, param);
|
||||
detail::write_type_suffix(output, param);
|
||||
}
|
||||
if (type.is_variadic())
|
||||
{
|
||||
if (need_sep)
|
||||
output << comma;
|
||||
output << punctuation("...");
|
||||
}
|
||||
if (is_const(type.cv_qualifier()))
|
||||
output << whitespace << keyword("const");
|
||||
if (is_volatile(type.cv_qualifier()))
|
||||
output << whitespace << keyword("volatile");
|
||||
}
|
||||
|
||||
void write_cv_qualified_suffix(code_generator::output& output, const cpp_cv_qualified_type& type)
|
||||
{
|
||||
if (is_direct_complex(type.type()))
|
||||
output << bracket_ws << punctuation(")");
|
||||
}
|
||||
detail::write_type_suffix(output, type.type());
|
||||
}
|
||||
|
||||
void write_function_suffix(code_generator::output& output, const cpp_function_type& type)
|
||||
{
|
||||
write_parameters(output, type);
|
||||
bool pointer_requires_paren(const cpp_pointer_type& type)
|
||||
{
|
||||
auto kind = type.pointee().kind();
|
||||
return kind == cpp_type_kind::function_t || kind == cpp_type_kind::array_t;
|
||||
}
|
||||
|
||||
detail::write_type_suffix(output, type.return_type());
|
||||
}
|
||||
|
||||
const cpp_type& strip_class_type(const cpp_type& type, cpp_cv* cv, cpp_reference* ref)
|
||||
{
|
||||
if (type.kind() == cpp_type_kind::cv_qualified_t)
|
||||
{
|
||||
auto& cv_qual = static_cast<const cpp_cv_qualified_type&>(type);
|
||||
if (cv)
|
||||
*cv = cv_qual.cv_qualifier();
|
||||
return strip_class_type(cv_qual.type(), cv, ref);
|
||||
}
|
||||
else if (type.kind() == cpp_type_kind::reference_t)
|
||||
{
|
||||
auto& ref_type = static_cast<const cpp_reference_type&>(type);
|
||||
if (ref)
|
||||
*ref = ref_type.reference_kind();
|
||||
return strip_class_type(ref_type.referee(), cv, ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_ASSERT(!detail::is_complex_type(type), detail::assert_handler{});
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
void write_member_function_prefix(code_generator::output& output,
|
||||
const cpp_member_function_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.return_type());
|
||||
void write_pointer_prefix(code_generator::output& output, const cpp_pointer_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.pointee());
|
||||
|
||||
if (pointer_requires_paren(type))
|
||||
output << punctuation("(") << bracket_ws;
|
||||
detail::write_type_prefix(output, strip_class_type(type.class_type(), nullptr, nullptr));
|
||||
output << punctuation("::");
|
||||
}
|
||||
else if (output.formatting().is_set(formatting_flags::ptr_ref_var))
|
||||
output << whitespace;
|
||||
|
||||
void write_member_function_suffix(code_generator::output& output,
|
||||
const cpp_member_function_type& type)
|
||||
{
|
||||
output << punctuation("*");
|
||||
}
|
||||
|
||||
void write_pointer_suffix(code_generator::output& output, const cpp_pointer_type& type)
|
||||
{
|
||||
if (pointer_requires_paren(type))
|
||||
output << bracket_ws << punctuation(")");
|
||||
write_parameters(output, type);
|
||||
detail::write_type_suffix(output, type.pointee());
|
||||
}
|
||||
|
||||
auto cv = cpp_cv_none;
|
||||
auto ref = cpp_ref_none;
|
||||
strip_class_type(type.class_type(), &cv, &ref);
|
||||
void write_reference_prefix(code_generator::output& output, const cpp_reference_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.referee());
|
||||
|
||||
if (cv == cpp_cv_const_volatile)
|
||||
output << keyword("const") << whitespace << keyword("volatile");
|
||||
else if (is_const(cv))
|
||||
output << keyword("const");
|
||||
else if (is_volatile(cv))
|
||||
output << keyword("volatile");
|
||||
|
||||
if (ref == cpp_ref_lvalue)
|
||||
output << operator_ws << punctuation("&") << operator_ws;
|
||||
else if (ref == cpp_ref_rvalue)
|
||||
output << operator_ws << punctuation("&&") << operator_ws;
|
||||
|
||||
detail::write_type_suffix(output, type.return_type());
|
||||
}
|
||||
|
||||
void write_member_object_prefix(code_generator::output& output,
|
||||
const cpp_member_object_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.object_type());
|
||||
if (is_direct_complex(type.referee()))
|
||||
output << punctuation("(") << bracket_ws;
|
||||
DEBUG_ASSERT(!detail::is_complex_type(type.class_type()), detail::assert_handler{});
|
||||
detail::write_type_prefix(output, type.class_type());
|
||||
output << punctuation("::");
|
||||
}
|
||||
else if (output.formatting().is_set(formatting_flags::ptr_ref_var))
|
||||
output << whitespace;
|
||||
|
||||
void write_member_object_suffix(code_generator::output& output, const cpp_member_object_type&)
|
||||
{
|
||||
if (type.reference_kind() == cpp_ref_lvalue)
|
||||
output << punctuation("&");
|
||||
else if (type.reference_kind() == cpp_ref_rvalue)
|
||||
output << punctuation("&&");
|
||||
else
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
}
|
||||
|
||||
void write_reference_suffix(code_generator::output& output, const cpp_reference_type& type)
|
||||
{
|
||||
if (is_direct_complex(type.referee()))
|
||||
output << bracket_ws << punctuation(")");
|
||||
}
|
||||
detail::write_type_suffix(output, type.referee());
|
||||
}
|
||||
|
||||
void write_template_parameter(code_generator::output& output,
|
||||
const cpp_template_parameter_type& type)
|
||||
void write_array_prefix(code_generator::output& output, const cpp_array_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.value_type());
|
||||
}
|
||||
|
||||
void write_array_suffix(code_generator::output& output, const cpp_array_type& type)
|
||||
{
|
||||
output << punctuation("[");
|
||||
if (type.size())
|
||||
{
|
||||
output << type.entity();
|
||||
output << bracket_ws;
|
||||
detail::write_expression(output, type.size().value());
|
||||
output << bracket_ws;
|
||||
}
|
||||
output << punctuation("]");
|
||||
detail::write_type_suffix(output, type.value_type());
|
||||
}
|
||||
|
||||
void write_template_instantiation(code_generator::output& output,
|
||||
const cpp_template_instantiation_type& type)
|
||||
void write_function_prefix(code_generator::output& output, const cpp_function_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.return_type());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void write_parameters(code_generator::output& output, const T& type)
|
||||
{
|
||||
output << punctuation("(") << bracket_ws;
|
||||
|
||||
auto need_sep = false;
|
||||
for (auto& param : type.parameter_types())
|
||||
{
|
||||
output << type.primary_template();
|
||||
if (output.was_reference_excluded())
|
||||
return;
|
||||
|
||||
if (type.arguments_exposed())
|
||||
detail::write_template_arguments(output, type.arguments());
|
||||
if (need_sep)
|
||||
output << comma;
|
||||
else
|
||||
output << punctuation("<") << bracket_ws << token_seq(type.unexposed_arguments())
|
||||
<< bracket_ws << punctuation(">");
|
||||
need_sep = true;
|
||||
detail::write_type_prefix(output, param);
|
||||
detail::write_type_suffix(output, param);
|
||||
}
|
||||
if (type.is_variadic())
|
||||
{
|
||||
if (need_sep)
|
||||
output << comma;
|
||||
output << punctuation("...");
|
||||
}
|
||||
|
||||
void write_dependent(code_generator::output& output, const cpp_dependent_type& type)
|
||||
{
|
||||
output << token_seq(type.name());
|
||||
}
|
||||
output << bracket_ws << punctuation(")");
|
||||
}
|
||||
|
||||
void write_unexposed(code_generator::output& output, const cpp_unexposed_type& type)
|
||||
void write_function_suffix(code_generator::output& output, const cpp_function_type& type)
|
||||
{
|
||||
write_parameters(output, type);
|
||||
|
||||
detail::write_type_suffix(output, type.return_type());
|
||||
}
|
||||
|
||||
const cpp_type& strip_class_type(const cpp_type& type, cpp_cv* cv, cpp_reference* ref)
|
||||
{
|
||||
if (type.kind() == cpp_type_kind::cv_qualified_t)
|
||||
{
|
||||
output << token_seq(type.name());
|
||||
auto& cv_qual = static_cast<const cpp_cv_qualified_type&>(type);
|
||||
if (cv)
|
||||
*cv = cv_qual.cv_qualifier();
|
||||
return strip_class_type(cv_qual.type(), cv, ref);
|
||||
}
|
||||
else if (type.kind() == cpp_type_kind::reference_t)
|
||||
{
|
||||
auto& ref_type = static_cast<const cpp_reference_type&>(type);
|
||||
if (ref)
|
||||
*ref = ref_type.reference_kind();
|
||||
return strip_class_type(ref_type.referee(), cv, ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_ASSERT(!detail::is_complex_type(type), detail::assert_handler{});
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
void write_member_function_prefix(code_generator::output& output,
|
||||
const cpp_member_function_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.return_type());
|
||||
|
||||
output << punctuation("(") << bracket_ws;
|
||||
detail::write_type_prefix(output, strip_class_type(type.class_type(), nullptr, nullptr));
|
||||
output << punctuation("::");
|
||||
}
|
||||
|
||||
void write_member_function_suffix(code_generator::output& output,
|
||||
const cpp_member_function_type& type)
|
||||
{
|
||||
output << bracket_ws << punctuation(")");
|
||||
write_parameters(output, type);
|
||||
|
||||
auto cv = cpp_cv_none;
|
||||
auto ref = cpp_ref_none;
|
||||
strip_class_type(type.class_type(), &cv, &ref);
|
||||
|
||||
if (cv == cpp_cv_const_volatile)
|
||||
output << keyword("const") << whitespace << keyword("volatile");
|
||||
else if (is_const(cv))
|
||||
output << keyword("const");
|
||||
else if (is_volatile(cv))
|
||||
output << keyword("volatile");
|
||||
|
||||
if (ref == cpp_ref_lvalue)
|
||||
output << operator_ws << punctuation("&") << operator_ws;
|
||||
else if (ref == cpp_ref_rvalue)
|
||||
output << operator_ws << punctuation("&&") << operator_ws;
|
||||
|
||||
detail::write_type_suffix(output, type.return_type());
|
||||
}
|
||||
|
||||
void write_member_object_prefix(code_generator::output& output, const cpp_member_object_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.object_type());
|
||||
output << punctuation("(") << bracket_ws;
|
||||
DEBUG_ASSERT(!detail::is_complex_type(type.class_type()), detail::assert_handler{});
|
||||
detail::write_type_prefix(output, type.class_type());
|
||||
output << punctuation("::");
|
||||
}
|
||||
|
||||
void write_member_object_suffix(code_generator::output& output, const cpp_member_object_type&)
|
||||
{
|
||||
output << bracket_ws << punctuation(")");
|
||||
}
|
||||
|
||||
void write_template_parameter(code_generator::output& output,
|
||||
const cpp_template_parameter_type& type)
|
||||
{
|
||||
output << type.entity();
|
||||
}
|
||||
|
||||
void write_template_instantiation(code_generator::output& output,
|
||||
const cpp_template_instantiation_type& type)
|
||||
{
|
||||
output << type.primary_template();
|
||||
if (output.was_reference_excluded())
|
||||
return;
|
||||
|
||||
if (type.arguments_exposed())
|
||||
detail::write_template_arguments(output, type.arguments());
|
||||
else
|
||||
output << punctuation("<") << bracket_ws << token_seq(type.unexposed_arguments())
|
||||
<< bracket_ws << punctuation(">");
|
||||
}
|
||||
|
||||
void write_dependent(code_generator::output& output, const cpp_dependent_type& type)
|
||||
{
|
||||
output << token_seq(type.name());
|
||||
}
|
||||
|
||||
void write_unexposed(code_generator::output& output, const cpp_unexposed_type& type)
|
||||
{
|
||||
output << token_seq(type.name());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void detail::write_type_prefix(code_generator::output& output, const cpp_type& type)
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
// This file is subject to the license terms in the LICENSE file
|
||||
// found in the top-level directory of this distribution.
|
||||
|
||||
#include <cppast/cpp_class.hpp>
|
||||
#include <clang-c/Index.h>
|
||||
#include <cppast/cpp_class.hpp>
|
||||
|
||||
#include "libclang_visitor.hpp"
|
||||
#include "parse_functions.hpp"
|
||||
|
|
@ -12,104 +12,104 @@ using namespace cppast;
|
|||
|
||||
namespace
|
||||
{
|
||||
cpp_class_kind parse_class_kind(detail::cxtoken_stream& stream)
|
||||
cpp_class_kind parse_class_kind(detail::cxtoken_stream& stream)
|
||||
{
|
||||
auto kind = clang_getTemplateCursorKind(stream.cursor());
|
||||
if (kind == CXCursor_NoDeclFound)
|
||||
kind = clang_getCursorKind(stream.cursor());
|
||||
|
||||
if (detail::skip_if(stream, "template"))
|
||||
// skip template parameters
|
||||
detail::skip_brackets(stream);
|
||||
|
||||
detail::skip_if(stream, "friend");
|
||||
|
||||
if (detail::skip_if(stream, "extern"))
|
||||
// extern template
|
||||
detail::skip(stream, "template");
|
||||
|
||||
switch (kind)
|
||||
{
|
||||
auto kind = clang_getTemplateCursorKind(stream.cursor());
|
||||
if (kind == CXCursor_NoDeclFound)
|
||||
kind = clang_getCursorKind(stream.cursor());
|
||||
|
||||
if (detail::skip_if(stream, "template"))
|
||||
// skip template parameters
|
||||
detail::skip_brackets(stream);
|
||||
|
||||
detail::skip_if(stream, "friend");
|
||||
|
||||
if (detail::skip_if(stream, "extern"))
|
||||
// extern template
|
||||
detail::skip(stream, "template");
|
||||
|
||||
switch (kind)
|
||||
{
|
||||
case CXCursor_ClassDecl:
|
||||
detail::skip(stream, "class");
|
||||
return cpp_class_kind::class_t;
|
||||
case CXCursor_StructDecl:
|
||||
detail::skip(stream, "struct");
|
||||
return cpp_class_kind::struct_t;
|
||||
case CXCursor_UnionDecl:
|
||||
detail::skip(stream, "union");
|
||||
return cpp_class_kind::union_t;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
case CXCursor_ClassDecl:
|
||||
detail::skip(stream, "class");
|
||||
return cpp_class_kind::class_t;
|
||||
case CXCursor_StructDecl:
|
||||
detail::skip(stream, "struct");
|
||||
return cpp_class_kind::struct_t;
|
||||
case CXCursor_UnionDecl:
|
||||
detail::skip(stream, "union");
|
||||
return cpp_class_kind::union_t;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
cpp_class::builder make_class_builder(const detail::parse_context& context, const CXCursor& cur)
|
||||
{
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
|
||||
auto kind = parse_class_kind(stream);
|
||||
auto attributes = detail::parse_attributes(stream);
|
||||
auto name = detail::get_cursor_name(cur);
|
||||
|
||||
auto result = cpp_class::builder(name.c_str(), kind);
|
||||
result.get().add_attribute(attributes);
|
||||
return result;
|
||||
}
|
||||
|
||||
cpp_access_specifier_kind convert_access(const CXCursor& cur)
|
||||
{
|
||||
switch (clang_getCXXAccessSpecifier(cur))
|
||||
{
|
||||
case CX_CXXInvalidAccessSpecifier:
|
||||
break;
|
||||
|
||||
case CX_CXXPublic:
|
||||
return cpp_public;
|
||||
case CX_CXXProtected:
|
||||
return cpp_protected;
|
||||
case CX_CXXPrivate:
|
||||
return cpp_private;
|
||||
}
|
||||
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
return cpp_public;
|
||||
}
|
||||
|
||||
void add_access_specifier(cpp_class::builder& builder, const CXCursor& cur)
|
||||
{
|
||||
DEBUG_ASSERT(cur.kind == CXCursor_CXXAccessSpecifier, detail::assert_handler{});
|
||||
builder.access_specifier(convert_access(cur));
|
||||
}
|
||||
|
||||
void add_base_class(cpp_class::builder& builder, const detail::parse_context& context,
|
||||
const CXCursor& cur, const CXCursor& class_cur)
|
||||
{
|
||||
DEBUG_ASSERT(cur.kind == CXCursor_CXXBaseSpecifier, detail::assert_handler{});
|
||||
auto access = convert_access(cur);
|
||||
auto is_virtual = clang_isVirtualBase(cur) != 0u;
|
||||
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
|
||||
// [<attribute>] [virtual] [<access>] <name>
|
||||
// can't use spelling to get the name
|
||||
auto attributes = detail::parse_attributes(stream);
|
||||
if (is_virtual)
|
||||
detail::skip(stream, "virtual");
|
||||
detail::skip_if(stream, to_string(access));
|
||||
|
||||
auto name = detail::to_string(stream, stream.end()).as_string();
|
||||
|
||||
auto type = detail::parse_type(context, class_cur, clang_getCursorType(cur));
|
||||
auto& base = builder.base_class(std::move(name), std::move(type), access, is_virtual);
|
||||
base.add_attribute(attributes);
|
||||
}
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
return cpp_class_kind::class_t;
|
||||
}
|
||||
|
||||
cpp_class::builder make_class_builder(const detail::parse_context& context, const CXCursor& cur)
|
||||
{
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
|
||||
auto kind = parse_class_kind(stream);
|
||||
auto attributes = detail::parse_attributes(stream);
|
||||
auto name = detail::get_cursor_name(cur);
|
||||
|
||||
auto result = cpp_class::builder(name.c_str(), kind);
|
||||
result.get().add_attribute(attributes);
|
||||
return result;
|
||||
}
|
||||
|
||||
cpp_access_specifier_kind convert_access(const CXCursor& cur)
|
||||
{
|
||||
switch (clang_getCXXAccessSpecifier(cur))
|
||||
{
|
||||
case CX_CXXInvalidAccessSpecifier:
|
||||
break;
|
||||
|
||||
case CX_CXXPublic:
|
||||
return cpp_public;
|
||||
case CX_CXXProtected:
|
||||
return cpp_protected;
|
||||
case CX_CXXPrivate:
|
||||
return cpp_private;
|
||||
}
|
||||
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
return cpp_public;
|
||||
}
|
||||
|
||||
void add_access_specifier(cpp_class::builder& builder, const CXCursor& cur)
|
||||
{
|
||||
DEBUG_ASSERT(cur.kind == CXCursor_CXXAccessSpecifier, detail::assert_handler{});
|
||||
builder.access_specifier(convert_access(cur));
|
||||
}
|
||||
|
||||
void add_base_class(cpp_class::builder& builder, const detail::parse_context& context,
|
||||
const CXCursor& cur, const CXCursor& class_cur)
|
||||
{
|
||||
DEBUG_ASSERT(cur.kind == CXCursor_CXXBaseSpecifier, detail::assert_handler{});
|
||||
auto access = convert_access(cur);
|
||||
auto is_virtual = clang_isVirtualBase(cur) != 0u;
|
||||
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
|
||||
// [<attribute>] [virtual] [<access>] <name>
|
||||
// can't use spelling to get the name
|
||||
auto attributes = detail::parse_attributes(stream);
|
||||
if (is_virtual)
|
||||
detail::skip(stream, "virtual");
|
||||
detail::skip_if(stream, to_string(access));
|
||||
|
||||
auto name = detail::to_string(stream, stream.end()).as_string();
|
||||
|
||||
auto type = detail::parse_type(context, class_cur, clang_getCursorType(cur));
|
||||
auto& base = builder.base_class(std::move(name), std::move(type), access, is_virtual);
|
||||
base.add_attribute(attributes);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_cpp_class(const detail::parse_context& context,
|
||||
const CXCursor& cur, const CXCursor& parent_cur)
|
||||
{
|
||||
|
|
@ -145,9 +145,9 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_class(const detail::parse_context&
|
|||
stream.bump();
|
||||
}
|
||||
if (!scope.empty())
|
||||
semantic_parent =
|
||||
cpp_entity_ref(detail::get_entity_id(clang_getCursorSemanticParent(cur)),
|
||||
std::move(scope));
|
||||
semantic_parent
|
||||
= cpp_entity_ref(detail::get_entity_id(clang_getCursorSemanticParent(cur)),
|
||||
std::move(scope));
|
||||
}
|
||||
|
||||
context.comments.match(builder.get(), cur);
|
||||
|
|
@ -159,12 +159,12 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_class(const detail::parse_context&
|
|||
add_base_class(builder, context, child, cur);
|
||||
else if (kind == CXCursor_CXXFinalAttr)
|
||||
builder.is_final();
|
||||
else if (
|
||||
kind == CXCursor_TemplateTypeParameter || kind == CXCursor_NonTypeTemplateParameter
|
||||
|| kind == CXCursor_TemplateTemplateParameter || kind == CXCursor_ParmDecl
|
||||
|| clang_isExpression(kind) || clang_isReference(kind)
|
||||
|| kind
|
||||
== CXCursor_UnexposedAttr) // I have no idea what this is, but happens on Windows
|
||||
else if (kind == CXCursor_TemplateTypeParameter
|
||||
|| kind == CXCursor_NonTypeTemplateParameter
|
||||
|| kind == CXCursor_TemplateTemplateParameter || kind == CXCursor_ParmDecl
|
||||
|| clang_isExpression(kind) || clang_isReference(kind)
|
||||
|| kind == CXCursor_UnexposedAttr) // I have no idea what this is, but happens
|
||||
// on Windows
|
||||
// other children due to templates and stuff
|
||||
return;
|
||||
else if (auto entity = parse_entity(context, &builder.get(), child))
|
||||
|
|
@ -173,10 +173,10 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_class(const detail::parse_context&
|
|||
}
|
||||
|
||||
if (!is_friend && clang_isCursorDefinition(cur))
|
||||
return is_templated ?
|
||||
builder.finish(std::move(semantic_parent)) :
|
||||
builder.finish(*context.idx, get_entity_id(cur), std::move(semantic_parent));
|
||||
return is_templated
|
||||
? builder.finish(std::move(semantic_parent))
|
||||
: builder.finish(*context.idx, get_entity_id(cur), std::move(semantic_parent));
|
||||
else
|
||||
return is_templated ? builder.finish_declaration(detail::get_entity_id(cur)) :
|
||||
builder.finish_declaration(*context.idx, get_entity_id(cur));
|
||||
return is_templated ? builder.finish_declaration(detail::get_entity_id(cur))
|
||||
: builder.finish_declaration(*context.idx, get_entity_id(cur));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,290 +13,282 @@ using namespace cppast;
|
|||
|
||||
detail::cxtoken::cxtoken(const CXTranslationUnit& tu_unit, const CXToken& token)
|
||||
: value_(clang_getTokenSpelling(tu_unit, token)), kind_(clang_getTokenKind(token))
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool cursor_is_function(CXCursorKind kind)
|
||||
bool cursor_is_function(CXCursorKind kind)
|
||||
{
|
||||
return kind == CXCursor_FunctionDecl || kind == CXCursor_CXXMethod
|
||||
|| kind == CXCursor_Constructor || kind == CXCursor_Destructor
|
||||
|| kind == CXCursor_ConversionFunction;
|
||||
}
|
||||
|
||||
CXSourceLocation get_next_location(const CXTranslationUnit& tu, CXFile file,
|
||||
const CXSourceLocation& loc, int inc = 1)
|
||||
{
|
||||
unsigned offset;
|
||||
clang_getSpellingLocation(loc, nullptr, nullptr, nullptr, &offset);
|
||||
if (inc >= 0)
|
||||
offset += unsigned(inc);
|
||||
else
|
||||
offset -= unsigned(-inc);
|
||||
return clang_getLocationForOffset(tu, file, offset);
|
||||
}
|
||||
|
||||
class simple_tokenizer
|
||||
{
|
||||
public:
|
||||
explicit simple_tokenizer(const CXTranslationUnit& tu, const CXSourceRange& range) : tu_(tu)
|
||||
{
|
||||
return kind == CXCursor_FunctionDecl || kind == CXCursor_CXXMethod
|
||||
|| kind == CXCursor_Constructor || kind == CXCursor_Destructor
|
||||
|| kind == CXCursor_ConversionFunction;
|
||||
clang_tokenize(tu, range, &tokens_, &no_);
|
||||
}
|
||||
|
||||
CXSourceLocation get_next_location(const CXTranslationUnit& tu, CXFile file,
|
||||
const CXSourceLocation& loc, int inc = 1)
|
||||
~simple_tokenizer()
|
||||
{
|
||||
unsigned offset;
|
||||
clang_getSpellingLocation(loc, nullptr, nullptr, nullptr, &offset);
|
||||
if (inc >= 0)
|
||||
offset += unsigned(inc);
|
||||
else
|
||||
offset -= unsigned(-inc);
|
||||
return clang_getLocationForOffset(tu, file, offset);
|
||||
clang_disposeTokens(tu_, tokens_, no_);
|
||||
}
|
||||
|
||||
class simple_tokenizer
|
||||
simple_tokenizer(const simple_tokenizer&) = delete;
|
||||
simple_tokenizer& operator=(const simple_tokenizer&) = delete;
|
||||
|
||||
unsigned size() const noexcept
|
||||
{
|
||||
public:
|
||||
explicit simple_tokenizer(const CXTranslationUnit& tu, const CXSourceRange& range) : tu_(tu)
|
||||
{
|
||||
clang_tokenize(tu, range, &tokens_, &no_);
|
||||
}
|
||||
|
||||
~simple_tokenizer()
|
||||
{
|
||||
clang_disposeTokens(tu_, tokens_, no_);
|
||||
}
|
||||
|
||||
simple_tokenizer(const simple_tokenizer&) = delete;
|
||||
simple_tokenizer& operator=(const simple_tokenizer&) = delete;
|
||||
|
||||
unsigned size() const noexcept
|
||||
{
|
||||
return no_;
|
||||
}
|
||||
|
||||
const CXToken& operator[](unsigned i) const noexcept
|
||||
{
|
||||
return tokens_[i];
|
||||
}
|
||||
|
||||
private:
|
||||
CXTranslationUnit tu_;
|
||||
CXToken* tokens_;
|
||||
unsigned no_;
|
||||
};
|
||||
|
||||
bool token_after_is(const CXTranslationUnit& tu, const CXFile& file,
|
||||
const CXSourceLocation& loc, const char* token_str, int inc)
|
||||
{
|
||||
auto loc_after = get_next_location(tu, file, loc, inc);
|
||||
if (!clang_Location_isFromMainFile(loc_after))
|
||||
return false;
|
||||
|
||||
simple_tokenizer tokenizer(tu, inc > 0 ? clang_getRange(loc, loc_after) :
|
||||
clang_getRange(loc_after, loc));
|
||||
if (tokenizer.size() == 0u)
|
||||
return false;
|
||||
|
||||
detail::cxstring spelling(clang_getTokenSpelling(tu, tokenizer[0u]));
|
||||
return spelling == token_str;
|
||||
return no_;
|
||||
}
|
||||
|
||||
// clang_getCursorExtent() is somehow broken in various ways
|
||||
// this function returns the actual CXSourceRange that covers all parts required for parsing
|
||||
// might include more tokens
|
||||
// this function is the reason you shouldn't use libclang
|
||||
CXSourceRange get_extent(const CXTranslationUnit& tu, const CXFile& file, const CXCursor& cur,
|
||||
bool& unmunch)
|
||||
const CXToken& operator[](unsigned i) const noexcept
|
||||
{
|
||||
unmunch = false;
|
||||
return tokens_[i];
|
||||
}
|
||||
|
||||
auto extent = clang_getCursorExtent(cur);
|
||||
auto begin = clang_getRangeStart(extent);
|
||||
auto end = clang_getRangeEnd(extent);
|
||||
private:
|
||||
CXTranslationUnit tu_;
|
||||
CXToken* tokens_;
|
||||
unsigned no_;
|
||||
};
|
||||
|
||||
auto kind = clang_getCursorKind(cur);
|
||||
if (cursor_is_function(kind) || cursor_is_function(clang_getTemplateCursorKind(cur))
|
||||
|| kind == CXCursor_VarDecl || kind == CXCursor_FieldDecl || kind == CXCursor_ParmDecl
|
||||
|| kind == CXCursor_NonTypeTemplateParameter)
|
||||
bool token_after_is(const CXTranslationUnit& tu, const CXFile& file, const CXSourceLocation& loc,
|
||||
const char* token_str, int inc)
|
||||
{
|
||||
auto loc_after = get_next_location(tu, file, loc, inc);
|
||||
if (!clang_Location_isFromMainFile(loc_after))
|
||||
return false;
|
||||
|
||||
simple_tokenizer tokenizer(tu, inc > 0 ? clang_getRange(loc, loc_after)
|
||||
: clang_getRange(loc_after, loc));
|
||||
if (tokenizer.size() == 0u)
|
||||
return false;
|
||||
|
||||
detail::cxstring spelling(clang_getTokenSpelling(tu, tokenizer[0u]));
|
||||
return spelling == token_str;
|
||||
}
|
||||
|
||||
// clang_getCursorExtent() is somehow broken in various ways
|
||||
// this function returns the actual CXSourceRange that covers all parts required for parsing
|
||||
// might include more tokens
|
||||
// this function is the reason you shouldn't use libclang
|
||||
CXSourceRange get_extent(const CXTranslationUnit& tu, const CXFile& file, const CXCursor& cur,
|
||||
bool& unmunch)
|
||||
{
|
||||
unmunch = false;
|
||||
|
||||
auto extent = clang_getCursorExtent(cur);
|
||||
auto begin = clang_getRangeStart(extent);
|
||||
auto end = clang_getRangeEnd(extent);
|
||||
|
||||
auto kind = clang_getCursorKind(cur);
|
||||
if (cursor_is_function(kind) || cursor_is_function(clang_getTemplateCursorKind(cur))
|
||||
|| kind == CXCursor_VarDecl || kind == CXCursor_FieldDecl || kind == CXCursor_ParmDecl
|
||||
|| kind == CXCursor_NonTypeTemplateParameter)
|
||||
{
|
||||
if (token_after_is(tu, file, begin, "]", -2) && token_after_is(tu, file, begin, "]", -3))
|
||||
{
|
||||
if (token_after_is(tu, file, begin, "]", -2)
|
||||
&& token_after_is(tu, file, begin, "]", -3))
|
||||
{
|
||||
while (!token_after_is(tu, file, begin, "[", -1)
|
||||
&& !token_after_is(tu, file, begin, "[", -2))
|
||||
begin = get_next_location(tu, file, begin, -1);
|
||||
|
||||
begin = get_next_location(tu, file, begin, -3);
|
||||
DEBUG_ASSERT(token_after_is(tu, file, begin, "[", 0)
|
||||
&& token_after_is(tu, file, get_next_location(tu, file, begin),
|
||||
"[", 0),
|
||||
detail::parse_error_handler{}, cur,
|
||||
"error in pre-function attribute parsing");
|
||||
}
|
||||
else if (token_after_is(tu, file, begin, ")", -2))
|
||||
{
|
||||
// maybe alignas specifier
|
||||
auto save_begin = begin;
|
||||
|
||||
auto paren_count = 1;
|
||||
begin = get_next_location(tu, file, begin, -1);
|
||||
for (auto last_begin = begin; paren_count != 0; last_begin = begin)
|
||||
{
|
||||
begin = get_next_location(tu, file, begin, -1);
|
||||
if (token_after_is(tu, file, begin, "(", -1))
|
||||
--paren_count;
|
||||
else if (token_after_is(tu, file, begin, ")", -1))
|
||||
++paren_count;
|
||||
|
||||
DEBUG_ASSERT(!clang_equalLocations(last_begin, begin),
|
||||
detail::parse_error_handler{}, cur,
|
||||
"infinite loop in alignas parsing");
|
||||
}
|
||||
begin = get_next_location(tu, file, begin, -(int(std::strlen("alignas")) + 1));
|
||||
|
||||
if (token_after_is(tu, file, begin, "alignas", 0))
|
||||
begin = get_next_location(tu, file, begin, -1);
|
||||
else
|
||||
begin = save_begin;
|
||||
}
|
||||
}
|
||||
|
||||
if (cursor_is_function(kind) || cursor_is_function(clang_getTemplateCursorKind(cur)))
|
||||
{
|
||||
auto is_definition = false;
|
||||
// if a function we need to remove the body
|
||||
// it does not need to be parsed
|
||||
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||
if (clang_getCursorKind(child) == CXCursor_CompoundStmt
|
||||
|| clang_getCursorKind(child) == CXCursor_CXXTryStmt
|
||||
|| clang_getCursorKind(child) == CXCursor_InitListExpr)
|
||||
{
|
||||
auto child_extent = clang_getCursorExtent(child);
|
||||
end = clang_getRangeStart(child_extent);
|
||||
is_definition = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!is_definition)
|
||||
{
|
||||
// i have no idea why this is necessary
|
||||
is_definition = token_after_is(tu, file, end, "{", 0)
|
||||
|| token_after_is(tu, file, end, "try", 0)
|
||||
|| token_after_is(tu, file, end, ":", 0);
|
||||
if (is_definition)
|
||||
// need to extend range here to include the token
|
||||
end = get_next_location(tu, file, end);
|
||||
}
|
||||
|
||||
if (!is_definition && !token_after_is(tu, file, end, ";", 0))
|
||||
{
|
||||
// we do not have a body, but it is not a declaration either
|
||||
do
|
||||
{
|
||||
end = get_next_location(tu, file, end);
|
||||
} while (!token_after_is(tu, file, end, ";", 0));
|
||||
}
|
||||
else if (kind == CXCursor_CXXMethod)
|
||||
// necessary for some reason
|
||||
while (!token_after_is(tu, file, begin, "[", -1)
|
||||
&& !token_after_is(tu, file, begin, "[", -2))
|
||||
begin = get_next_location(tu, file, begin, -1);
|
||||
else if (kind == CXCursor_Destructor && token_after_is(tu, file, end, ")", 0))
|
||||
// necessary for some other reason
|
||||
end = get_next_location(tu, file, end);
|
||||
|
||||
begin = get_next_location(tu, file, begin, -3);
|
||||
DEBUG_ASSERT(token_after_is(tu, file, begin, "[", 0)
|
||||
&& token_after_is(tu, file, get_next_location(tu, file, begin), "[",
|
||||
0),
|
||||
detail::parse_error_handler{}, cur,
|
||||
"error in pre-function attribute parsing");
|
||||
}
|
||||
else if (kind == CXCursor_TemplateTypeParameter && token_after_is(tu, file, end, "(", 0))
|
||||
else if (token_after_is(tu, file, begin, ")", -2))
|
||||
{
|
||||
// if you have decltype as default argument for a type template parameter
|
||||
// libclang doesn't include the parameters
|
||||
auto next = get_next_location(tu, file, end);
|
||||
auto prev = end;
|
||||
for (auto paren_count = 1; paren_count != 0; next = get_next_location(tu, file, next))
|
||||
// maybe alignas specifier
|
||||
auto save_begin = begin;
|
||||
|
||||
auto paren_count = 1;
|
||||
begin = get_next_location(tu, file, begin, -1);
|
||||
for (auto last_begin = begin; paren_count != 0; last_begin = begin)
|
||||
{
|
||||
if (token_after_is(tu, file, next, "(", 0))
|
||||
++paren_count;
|
||||
else if (token_after_is(tu, file, next, ")", 0))
|
||||
begin = get_next_location(tu, file, begin, -1);
|
||||
if (token_after_is(tu, file, begin, "(", -1))
|
||||
--paren_count;
|
||||
prev = next;
|
||||
else if (token_after_is(tu, file, begin, ")", -1))
|
||||
++paren_count;
|
||||
|
||||
DEBUG_ASSERT(!clang_equalLocations(last_begin, begin),
|
||||
detail::parse_error_handler{}, cur,
|
||||
"infinite loop in alignas parsing");
|
||||
}
|
||||
#if CINDEX_VERSION_MINOR < 37
|
||||
end = prev;
|
||||
#else
|
||||
end = next;
|
||||
#endif
|
||||
}
|
||||
else if (kind == CXCursor_TemplateTemplateParameter
|
||||
&& token_after_is(tu, file, end, "<", 0))
|
||||
{
|
||||
// if you have a template template parameter in a template template parameter,
|
||||
// the tokens are all messed up, only contain the `template`
|
||||
begin = get_next_location(tu, file, begin, -(int(std::strlen("alignas")) + 1));
|
||||
|
||||
// first: skip to closing angle bracket
|
||||
// luckily no need to handle expressions here
|
||||
auto next = get_next_location(tu, file, end, 2);
|
||||
for (auto angle_count = 1; angle_count != 0; next = get_next_location(tu, file, next))
|
||||
{
|
||||
if (token_after_is(tu, file, next, ">", 0))
|
||||
--angle_count;
|
||||
else if (token_after_is(tu, file, next, ">>", 0))
|
||||
angle_count -= 2;
|
||||
else if (token_after_is(tu, file, next, "<", 0))
|
||||
++angle_count;
|
||||
}
|
||||
|
||||
// second: skip until end of parameter
|
||||
// no need to handle default, so look for '>' or ','
|
||||
while (!token_after_is(tu, file, next, ">", 0)
|
||||
&& !token_after_is(tu, file, next, ",", 0))
|
||||
next = get_next_location(tu, file, next);
|
||||
// now we found the proper end of the token
|
||||
end = get_next_location(tu, file, next, -1);
|
||||
if (token_after_is(tu, file, begin, "alignas", 0))
|
||||
begin = get_next_location(tu, file, begin, -1);
|
||||
else
|
||||
begin = save_begin;
|
||||
}
|
||||
else if ((kind == CXCursor_TemplateTypeParameter
|
||||
|| kind == CXCursor_NonTypeTemplateParameter
|
||||
|| kind == CXCursor_TemplateTemplateParameter)
|
||||
&& token_after_is(tu, file, end, "...", 0))
|
||||
{
|
||||
// variadic tokens in unnamed parameter not included
|
||||
end = get_next_location(tu, file, end, 3);
|
||||
if (token_after_is(tu, file, end, ".", 0))
|
||||
// extra whitespace, so bump again
|
||||
// this should all go away once I redid the whole token thing...
|
||||
end = get_next_location(tu, file, end, 1);
|
||||
|
||||
DEBUG_ASSERT(token_after_is(tu, file, end, ">", 0)
|
||||
|| token_after_is(tu, file, end, ",", 0),
|
||||
detail::parse_error_handler{}, cur,
|
||||
"unexpected token in variadic parameter workaround");
|
||||
}
|
||||
else if ((kind == CXCursor_TemplateTypeParameter
|
||||
|| kind == CXCursor_NonTypeTemplateParameter
|
||||
|| kind == CXCursor_TemplateTemplateParameter)
|
||||
&& !token_after_is(tu, file, end, ">", 0)
|
||||
&& !token_after_is(tu, file, end, ",", 0))
|
||||
{
|
||||
DEBUG_ASSERT(token_after_is(tu, file, get_next_location(tu, file, end, -2), ">>", 0),
|
||||
detail::parse_error_handler{}, cur,
|
||||
"unexpected token in maximal munch workaround");
|
||||
unmunch = true;
|
||||
// need to shrink range anyway
|
||||
end = get_next_location(tu, file, end, -1);
|
||||
}
|
||||
else if (kind == CXCursor_EnumDecl && !token_after_is(tu, file, end, ";", 0))
|
||||
{
|
||||
while (!token_after_is(tu, file, end, ";", 0))
|
||||
end = get_next_location(tu, file, end);
|
||||
}
|
||||
else if (kind == CXCursor_EnumConstantDecl && !token_after_is(tu, file, end, ",", 0))
|
||||
{
|
||||
// need to support attributes
|
||||
// just give up and extend the range to the range of the entire enum...
|
||||
auto parent = clang_getCursorLexicalParent(cur);
|
||||
end = clang_getRangeEnd(clang_getCursorExtent(parent));
|
||||
}
|
||||
else if (kind == CXCursor_ParmDecl && !token_after_is(tu, file, end, "]", -1))
|
||||
// need to shrink range by one
|
||||
end = get_next_location(tu, file, end, -1);
|
||||
else if (kind == CXCursor_FieldDecl || kind == CXCursor_NonTypeTemplateParameter
|
||||
|| kind == CXCursor_TemplateTemplateParameter
|
||||
#if CINDEX_VERSION_MINOR < 37
|
||||
|| clang_isExpression(kind) || kind == CXCursor_CXXBaseSpecifier
|
||||
|| kind == CXCursor_TemplateTypeParameter
|
||||
#endif
|
||||
)
|
||||
// need to shrink range by one
|
||||
end = get_next_location(tu, file, end, -1);
|
||||
else if (kind == CXCursor_UnexposedDecl)
|
||||
{
|
||||
// include semicolon, if necessary
|
||||
if (token_after_is(tu, file, end, ";", 0))
|
||||
end = get_next_location(tu, file, end);
|
||||
}
|
||||
|
||||
return clang_getRange(begin, end);
|
||||
}
|
||||
|
||||
if (cursor_is_function(kind) || cursor_is_function(clang_getTemplateCursorKind(cur)))
|
||||
{
|
||||
auto is_definition = false;
|
||||
// if a function we need to remove the body
|
||||
// it does not need to be parsed
|
||||
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||
if (clang_getCursorKind(child) == CXCursor_CompoundStmt
|
||||
|| clang_getCursorKind(child) == CXCursor_CXXTryStmt
|
||||
|| clang_getCursorKind(child) == CXCursor_InitListExpr)
|
||||
{
|
||||
auto child_extent = clang_getCursorExtent(child);
|
||||
end = clang_getRangeStart(child_extent);
|
||||
is_definition = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!is_definition)
|
||||
{
|
||||
// i have no idea why this is necessary
|
||||
is_definition = token_after_is(tu, file, end, "{", 0)
|
||||
|| token_after_is(tu, file, end, "try", 0)
|
||||
|| token_after_is(tu, file, end, ":", 0);
|
||||
if (is_definition)
|
||||
// need to extend range here to include the token
|
||||
end = get_next_location(tu, file, end);
|
||||
}
|
||||
|
||||
if (!is_definition && !token_after_is(tu, file, end, ";", 0))
|
||||
{
|
||||
// we do not have a body, but it is not a declaration either
|
||||
do
|
||||
{
|
||||
end = get_next_location(tu, file, end);
|
||||
} while (!token_after_is(tu, file, end, ";", 0));
|
||||
}
|
||||
else if (kind == CXCursor_CXXMethod)
|
||||
// necessary for some reason
|
||||
begin = get_next_location(tu, file, begin, -1);
|
||||
else if (kind == CXCursor_Destructor && token_after_is(tu, file, end, ")", 0))
|
||||
// necessary for some other reason
|
||||
end = get_next_location(tu, file, end);
|
||||
}
|
||||
else if (kind == CXCursor_TemplateTypeParameter && token_after_is(tu, file, end, "(", 0))
|
||||
{
|
||||
// if you have decltype as default argument for a type template parameter
|
||||
// libclang doesn't include the parameters
|
||||
auto next = get_next_location(tu, file, end);
|
||||
auto prev = end;
|
||||
for (auto paren_count = 1; paren_count != 0; next = get_next_location(tu, file, next))
|
||||
{
|
||||
if (token_after_is(tu, file, next, "(", 0))
|
||||
++paren_count;
|
||||
else if (token_after_is(tu, file, next, ")", 0))
|
||||
--paren_count;
|
||||
prev = next;
|
||||
}
|
||||
#if CINDEX_VERSION_MINOR < 37
|
||||
end = prev;
|
||||
#else
|
||||
end = next;
|
||||
#endif
|
||||
}
|
||||
else if (kind == CXCursor_TemplateTemplateParameter && token_after_is(tu, file, end, "<", 0))
|
||||
{
|
||||
// if you have a template template parameter in a template template parameter,
|
||||
// the tokens are all messed up, only contain the `template`
|
||||
|
||||
// first: skip to closing angle bracket
|
||||
// luckily no need to handle expressions here
|
||||
auto next = get_next_location(tu, file, end, 2);
|
||||
for (auto angle_count = 1; angle_count != 0; next = get_next_location(tu, file, next))
|
||||
{
|
||||
if (token_after_is(tu, file, next, ">", 0))
|
||||
--angle_count;
|
||||
else if (token_after_is(tu, file, next, ">>", 0))
|
||||
angle_count -= 2;
|
||||
else if (token_after_is(tu, file, next, "<", 0))
|
||||
++angle_count;
|
||||
}
|
||||
|
||||
// second: skip until end of parameter
|
||||
// no need to handle default, so look for '>' or ','
|
||||
while (!token_after_is(tu, file, next, ">", 0) && !token_after_is(tu, file, next, ",", 0))
|
||||
next = get_next_location(tu, file, next);
|
||||
// now we found the proper end of the token
|
||||
end = get_next_location(tu, file, next, -1);
|
||||
}
|
||||
else if ((kind == CXCursor_TemplateTypeParameter || kind == CXCursor_NonTypeTemplateParameter
|
||||
|| kind == CXCursor_TemplateTemplateParameter)
|
||||
&& token_after_is(tu, file, end, "...", 0))
|
||||
{
|
||||
// variadic tokens in unnamed parameter not included
|
||||
end = get_next_location(tu, file, end, 3);
|
||||
if (token_after_is(tu, file, end, ".", 0))
|
||||
// extra whitespace, so bump again
|
||||
// this should all go away once I redid the whole token thing...
|
||||
end = get_next_location(tu, file, end, 1);
|
||||
|
||||
DEBUG_ASSERT(token_after_is(tu, file, end, ">", 0) || token_after_is(tu, file, end, ",", 0),
|
||||
detail::parse_error_handler{}, cur,
|
||||
"unexpected token in variadic parameter workaround");
|
||||
}
|
||||
else if ((kind == CXCursor_TemplateTypeParameter || kind == CXCursor_NonTypeTemplateParameter
|
||||
|| kind == CXCursor_TemplateTemplateParameter)
|
||||
&& !token_after_is(tu, file, end, ">", 0) && !token_after_is(tu, file, end, ",", 0))
|
||||
{
|
||||
DEBUG_ASSERT(token_after_is(tu, file, get_next_location(tu, file, end, -2), ">>", 0),
|
||||
detail::parse_error_handler{}, cur,
|
||||
"unexpected token in maximal munch workaround");
|
||||
unmunch = true;
|
||||
// need to shrink range anyway
|
||||
end = get_next_location(tu, file, end, -1);
|
||||
}
|
||||
else if (kind == CXCursor_EnumDecl && !token_after_is(tu, file, end, ";", 0))
|
||||
{
|
||||
while (!token_after_is(tu, file, end, ";", 0))
|
||||
end = get_next_location(tu, file, end);
|
||||
}
|
||||
else if (kind == CXCursor_EnumConstantDecl && !token_after_is(tu, file, end, ",", 0))
|
||||
{
|
||||
// need to support attributes
|
||||
// just give up and extend the range to the range of the entire enum...
|
||||
auto parent = clang_getCursorLexicalParent(cur);
|
||||
end = clang_getRangeEnd(clang_getCursorExtent(parent));
|
||||
}
|
||||
else if (kind == CXCursor_ParmDecl && !token_after_is(tu, file, end, "]", -1))
|
||||
// need to shrink range by one
|
||||
end = get_next_location(tu, file, end, -1);
|
||||
else if (kind == CXCursor_FieldDecl || kind == CXCursor_NonTypeTemplateParameter
|
||||
|| kind == CXCursor_TemplateTemplateParameter
|
||||
#if CINDEX_VERSION_MINOR < 37
|
||||
|| clang_isExpression(kind) || kind == CXCursor_CXXBaseSpecifier
|
||||
|| kind == CXCursor_TemplateTypeParameter
|
||||
#endif
|
||||
)
|
||||
// need to shrink range by one
|
||||
end = get_next_location(tu, file, end, -1);
|
||||
else if (kind == CXCursor_UnexposedDecl)
|
||||
{
|
||||
// include semicolon, if necessary
|
||||
if (token_after_is(tu, file, end, ";", 0))
|
||||
end = get_next_location(tu, file, end);
|
||||
}
|
||||
|
||||
return clang_getRange(begin, end);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
detail::cxtokenizer::cxtokenizer(const CXTranslationUnit& tu, const CXFile& file,
|
||||
|
|
@ -326,15 +318,15 @@ void detail::skip(detail::cxtoken_stream& stream, const char* str)
|
|||
|
||||
namespace
|
||||
{
|
||||
bool starts_with(const char*& str, const detail::cxtoken& t)
|
||||
{
|
||||
if (std::strncmp(str, t.c_str(), t.value().length()) != 0)
|
||||
return false;
|
||||
str += t.value().length();
|
||||
while (*str == ' ' || *str == '\t')
|
||||
++str;
|
||||
return true;
|
||||
}
|
||||
bool starts_with(const char*& str, const detail::cxtoken& t)
|
||||
{
|
||||
if (std::strncmp(str, t.c_str(), t.value().length()) != 0)
|
||||
return false;
|
||||
str += t.value().length();
|
||||
while (*str == ' ' || *str == '\t')
|
||||
++str;
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool detail::skip_if(detail::cxtoken_stream& stream, const char* str, bool multi_token)
|
||||
|
|
@ -359,16 +351,16 @@ bool detail::skip_if(detail::cxtoken_stream& stream, const char* str, bool multi
|
|||
|
||||
namespace
|
||||
{
|
||||
// whether or not the current angle bracket can be a comparison
|
||||
// note: this is a heuristic I hope works often enough
|
||||
bool is_comparison(CXTokenKind last_kind, const detail::cxtoken& cur, CXTokenKind next_kind)
|
||||
{
|
||||
if (cur == "<")
|
||||
return last_kind == CXToken_Literal;
|
||||
else if (cur == ">")
|
||||
return next_kind == CXToken_Literal;
|
||||
return false;
|
||||
}
|
||||
// whether or not the current angle bracket can be a comparison
|
||||
// note: this is a heuristic I hope works often enough
|
||||
bool is_comparison(CXTokenKind last_kind, const detail::cxtoken& cur, CXTokenKind next_kind)
|
||||
{
|
||||
if (cur == "<")
|
||||
return last_kind == CXToken_Literal;
|
||||
else if (cur == ">")
|
||||
return next_kind == CXToken_Literal;
|
||||
return false;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
detail::cxtoken_iterator detail::find_closing_bracket(detail::cxtoken_stream stream)
|
||||
|
|
@ -430,161 +422,160 @@ void detail::skip_brackets(detail::cxtoken_stream& stream)
|
|||
|
||||
namespace
|
||||
{
|
||||
type_safe::optional<std::string> parse_attribute_using(detail::cxtoken_stream& stream)
|
||||
type_safe::optional<std::string> parse_attribute_using(detail::cxtoken_stream& stream)
|
||||
{
|
||||
// using identifier :
|
||||
if (skip_if(stream, "using"))
|
||||
{
|
||||
// using identifier :
|
||||
if (skip_if(stream, "using"))
|
||||
{
|
||||
DEBUG_ASSERT(stream.peek().kind() == CXToken_Identifier, detail::parse_error_handler{},
|
||||
stream.cursor(), "expected identifier");
|
||||
auto scope = stream.get().value().std_str();
|
||||
skip(stream, ":");
|
||||
DEBUG_ASSERT(stream.peek().kind() == CXToken_Identifier, detail::parse_error_handler{},
|
||||
stream.cursor(), "expected identifier");
|
||||
auto scope = stream.get().value().std_str();
|
||||
skip(stream, ":");
|
||||
|
||||
return scope;
|
||||
}
|
||||
else
|
||||
return type_safe::nullopt;
|
||||
return scope;
|
||||
}
|
||||
else
|
||||
return type_safe::nullopt;
|
||||
}
|
||||
|
||||
cpp_attribute_kind get_attribute_kind(const std::string& name)
|
||||
cpp_attribute_kind get_attribute_kind(const std::string& name)
|
||||
{
|
||||
if (name == "carries_dependency")
|
||||
return cpp_attribute_kind::carries_dependency;
|
||||
else if (name == "deprecated")
|
||||
return cpp_attribute_kind::deprecated;
|
||||
else if (name == "fallthrough")
|
||||
return cpp_attribute_kind::fallthrough;
|
||||
else if (name == "maybe_unused")
|
||||
return cpp_attribute_kind::maybe_unused;
|
||||
else if (name == "nodiscard")
|
||||
return cpp_attribute_kind::nodiscard;
|
||||
else if (name == "noreturn")
|
||||
return cpp_attribute_kind::noreturn;
|
||||
else
|
||||
return cpp_attribute_kind::unknown;
|
||||
}
|
||||
|
||||
cpp_token_string parse_attribute_arguments(detail::cxtoken_stream& stream)
|
||||
{
|
||||
auto end = find_closing_bracket(stream);
|
||||
skip(stream, "(");
|
||||
|
||||
auto arguments = detail::to_string(stream, end);
|
||||
|
||||
stream.set_cur(end);
|
||||
skip(stream, ")");
|
||||
|
||||
return arguments;
|
||||
}
|
||||
|
||||
cpp_attribute parse_attribute_token(detail::cxtoken_stream& stream,
|
||||
type_safe::optional<std::string> scope)
|
||||
{
|
||||
// (identifier ::)_opt identifier ( '(' some tokens ')' )_opt ..._opt
|
||||
|
||||
// parse name
|
||||
DEBUG_ASSERT(stream.peek().kind() == CXToken_Identifier
|
||||
|| stream.peek().kind() == CXToken_Keyword,
|
||||
detail::parse_error_handler{}, stream.cursor(), "expected identifier");
|
||||
auto name = stream.get().value().std_str();
|
||||
if (skip_if(stream, "::"))
|
||||
{
|
||||
if (name == "carries_dependency")
|
||||
return cpp_attribute_kind::carries_dependency;
|
||||
else if (name == "deprecated")
|
||||
return cpp_attribute_kind::deprecated;
|
||||
else if (name == "fallthrough")
|
||||
return cpp_attribute_kind::fallthrough;
|
||||
else if (name == "maybe_unused")
|
||||
return cpp_attribute_kind::maybe_unused;
|
||||
else if (name == "nodiscard")
|
||||
return cpp_attribute_kind::nodiscard;
|
||||
else if (name == "noreturn")
|
||||
return cpp_attribute_kind::noreturn;
|
||||
else
|
||||
return cpp_attribute_kind::unknown;
|
||||
}
|
||||
// name was actually a scope, so parse name again
|
||||
DEBUG_ASSERT(!scope, detail::parse_error_handler{}, stream.cursor(),
|
||||
"attribute using + scope not allowed");
|
||||
scope = std::move(name);
|
||||
|
||||
cpp_token_string parse_attribute_arguments(detail::cxtoken_stream& stream)
|
||||
{
|
||||
auto end = find_closing_bracket(stream);
|
||||
skip(stream, "(");
|
||||
|
||||
auto arguments = detail::to_string(stream, end);
|
||||
|
||||
stream.set_cur(end);
|
||||
skip(stream, ")");
|
||||
|
||||
return arguments;
|
||||
}
|
||||
|
||||
cpp_attribute parse_attribute_token(detail::cxtoken_stream& stream,
|
||||
type_safe::optional<std::string> scope)
|
||||
{
|
||||
// (identifier ::)_opt identifier ( '(' some tokens ')' )_opt ..._opt
|
||||
|
||||
// parse name
|
||||
DEBUG_ASSERT(stream.peek().kind() == CXToken_Identifier
|
||||
|| stream.peek().kind() == CXToken_Keyword,
|
||||
detail::parse_error_handler{}, stream.cursor(), "expected identifier");
|
||||
auto name = stream.get().value().std_str();
|
||||
if (skip_if(stream, "::"))
|
||||
{
|
||||
// name was actually a scope, so parse name again
|
||||
DEBUG_ASSERT(!scope, detail::parse_error_handler{}, stream.cursor(),
|
||||
"attribute using + scope not allowed");
|
||||
scope = std::move(name);
|
||||
|
||||
DEBUG_ASSERT(stream.peek().kind() == CXToken_Identifier
|
||||
|| stream.peek().kind() == CXToken_Keyword,
|
||||
detail::parse_error_handler{}, stream.cursor(), "expected identifier");
|
||||
name = stream.get().value().std_str();
|
||||
}
|
||||
|
||||
// parse arguments
|
||||
type_safe::optional<cpp_token_string> arguments;
|
||||
if (stream.peek() == "(")
|
||||
arguments = parse_attribute_arguments(stream);
|
||||
|
||||
// parse variadic token
|
||||
auto is_variadic = skip_if(stream, "...");
|
||||
|
||||
// get kind
|
||||
auto kind = get_attribute_kind(name);
|
||||
if (!scope && kind != cpp_attribute_kind::unknown)
|
||||
return cpp_attribute(kind, std::move(arguments));
|
||||
else
|
||||
return cpp_attribute(std::move(scope), std::move(name), std::move(arguments),
|
||||
is_variadic);
|
||||
name = stream.get().value().std_str();
|
||||
}
|
||||
|
||||
bool parse_attribute_impl(cpp_attribute_list& result, detail::cxtoken_stream& stream)
|
||||
// parse arguments
|
||||
type_safe::optional<cpp_token_string> arguments;
|
||||
if (stream.peek() == "(")
|
||||
arguments = parse_attribute_arguments(stream);
|
||||
|
||||
// parse variadic token
|
||||
auto is_variadic = skip_if(stream, "...");
|
||||
|
||||
// get kind
|
||||
auto kind = get_attribute_kind(name);
|
||||
if (!scope && kind != cpp_attribute_kind::unknown)
|
||||
return cpp_attribute(kind, std::move(arguments));
|
||||
else
|
||||
return cpp_attribute(std::move(scope), std::move(name), std::move(arguments), is_variadic);
|
||||
}
|
||||
|
||||
bool parse_attribute_impl(cpp_attribute_list& result, detail::cxtoken_stream& stream)
|
||||
{
|
||||
if (skip_if(stream, "[") && stream.peek() == "[")
|
||||
{
|
||||
if (skip_if(stream, "[") && stream.peek() == "[")
|
||||
// C++11 attribute
|
||||
// [[<attribute>]]
|
||||
// ^
|
||||
skip(stream, "[");
|
||||
|
||||
auto scope = parse_attribute_using(stream);
|
||||
while (!skip_if(stream, "]"))
|
||||
{
|
||||
// C++11 attribute
|
||||
// [[<attribute>]]
|
||||
// ^
|
||||
skip(stream, "[");
|
||||
|
||||
auto scope = parse_attribute_using(stream);
|
||||
while (!skip_if(stream, "]"))
|
||||
{
|
||||
auto attribute = parse_attribute_token(stream, scope);
|
||||
result.push_back(std::move(attribute));
|
||||
detail::skip_if(stream, ",");
|
||||
}
|
||||
|
||||
// [[<attribute>]]
|
||||
// ^
|
||||
skip(stream, "]");
|
||||
return true;
|
||||
}
|
||||
else if (skip_if(stream, "alignas"))
|
||||
{
|
||||
// alignas specifier
|
||||
// alignas(<some arguments>)
|
||||
// ^
|
||||
auto arguments = parse_attribute_arguments(stream);
|
||||
result.push_back(cpp_attribute(cpp_attribute_kind::alignas_, std::move(arguments)));
|
||||
}
|
||||
else if (skip_if(stream, "__attribute__") && stream.peek() == "(")
|
||||
{
|
||||
// GCC/clang attributes
|
||||
// __attribute__((<attribute>))
|
||||
// ^^
|
||||
skip(stream, "(");
|
||||
skip(stream, "(");
|
||||
|
||||
auto scope = parse_attribute_using(stream);
|
||||
while (!skip_if(stream, ")"))
|
||||
{
|
||||
auto attribute = parse_attribute_token(stream, scope);
|
||||
result.push_back(std::move(attribute));
|
||||
detail::skip_if(stream, ",");
|
||||
}
|
||||
|
||||
skip(stream, ")");
|
||||
return true;
|
||||
}
|
||||
else if (skip_if(stream, "__declspec"))
|
||||
{
|
||||
// MSVC declspec
|
||||
// __declspec(<attribute>)
|
||||
// ^
|
||||
skip(stream, "(");
|
||||
auto scope = parse_attribute_using(stream);
|
||||
while (!skip_if(stream, ")"))
|
||||
{
|
||||
auto attribute = parse_attribute_token(stream, scope);
|
||||
result.push_back(std::move(attribute));
|
||||
detail::skip_if(stream, ",");
|
||||
}
|
||||
|
||||
return true;
|
||||
auto attribute = parse_attribute_token(stream, scope);
|
||||
result.push_back(std::move(attribute));
|
||||
detail::skip_if(stream, ",");
|
||||
}
|
||||
|
||||
return false;
|
||||
// [[<attribute>]]
|
||||
// ^
|
||||
skip(stream, "]");
|
||||
return true;
|
||||
}
|
||||
else if (skip_if(stream, "alignas"))
|
||||
{
|
||||
// alignas specifier
|
||||
// alignas(<some arguments>)
|
||||
// ^
|
||||
auto arguments = parse_attribute_arguments(stream);
|
||||
result.push_back(cpp_attribute(cpp_attribute_kind::alignas_, std::move(arguments)));
|
||||
}
|
||||
else if (skip_if(stream, "__attribute__") && stream.peek() == "(")
|
||||
{
|
||||
// GCC/clang attributes
|
||||
// __attribute__((<attribute>))
|
||||
// ^^
|
||||
skip(stream, "(");
|
||||
skip(stream, "(");
|
||||
|
||||
auto scope = parse_attribute_using(stream);
|
||||
while (!skip_if(stream, ")"))
|
||||
{
|
||||
auto attribute = parse_attribute_token(stream, scope);
|
||||
result.push_back(std::move(attribute));
|
||||
detail::skip_if(stream, ",");
|
||||
}
|
||||
|
||||
skip(stream, ")");
|
||||
return true;
|
||||
}
|
||||
else if (skip_if(stream, "__declspec"))
|
||||
{
|
||||
// MSVC declspec
|
||||
// __declspec(<attribute>)
|
||||
// ^
|
||||
skip(stream, "(");
|
||||
auto scope = parse_attribute_using(stream);
|
||||
while (!skip_if(stream, ")"))
|
||||
{
|
||||
auto attribute = parse_attribute_token(stream, scope);
|
||||
result.push_back(std::move(attribute));
|
||||
detail::skip_if(stream, ",");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
cpp_attribute_list detail::parse_attributes(detail::cxtoken_stream& stream, bool skip_anway)
|
||||
|
|
@ -602,37 +593,37 @@ cpp_attribute_list detail::parse_attributes(detail::cxtoken_stream& stream, bool
|
|||
|
||||
namespace
|
||||
{
|
||||
cpp_token_kind get_kind(const detail::cxtoken& token)
|
||||
cpp_token_kind get_kind(const detail::cxtoken& token)
|
||||
{
|
||||
switch (token.kind())
|
||||
{
|
||||
switch (token.kind())
|
||||
{
|
||||
case CXToken_Punctuation:
|
||||
return cpp_token_kind::punctuation;
|
||||
case CXToken_Keyword:
|
||||
return cpp_token_kind::keyword;
|
||||
case CXToken_Identifier:
|
||||
return cpp_token_kind::identifier;
|
||||
|
||||
case CXToken_Literal:
|
||||
{
|
||||
auto spelling = token.value().std_str();
|
||||
if (spelling.find('.') != std::string::npos)
|
||||
return cpp_token_kind::float_literal;
|
||||
else if (std::isdigit(spelling.front()))
|
||||
return cpp_token_kind::int_literal;
|
||||
else if (spelling.back() == '\'')
|
||||
return cpp_token_kind::char_literal;
|
||||
else
|
||||
return cpp_token_kind::string_literal;
|
||||
}
|
||||
|
||||
case CXToken_Comment:
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
case CXToken_Punctuation:
|
||||
return cpp_token_kind::punctuation;
|
||||
case CXToken_Keyword:
|
||||
return cpp_token_kind::keyword;
|
||||
case CXToken_Identifier:
|
||||
return cpp_token_kind::identifier;
|
||||
|
||||
case CXToken_Literal:
|
||||
{
|
||||
auto spelling = token.value().std_str();
|
||||
if (spelling.find('.') != std::string::npos)
|
||||
return cpp_token_kind::float_literal;
|
||||
else if (std::isdigit(spelling.front()))
|
||||
return cpp_token_kind::int_literal;
|
||||
else if (spelling.back() == '\'')
|
||||
return cpp_token_kind::char_literal;
|
||||
else
|
||||
return cpp_token_kind::string_literal;
|
||||
}
|
||||
|
||||
case CXToken_Comment:
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
return cpp_token_kind::punctuation;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
cpp_token_string detail::to_string(cxtoken_stream& stream, cxtoken_iterator end)
|
||||
|
|
|
|||
|
|
@ -15,194 +15,189 @@
|
|||
|
||||
namespace cppast
|
||||
{
|
||||
namespace detail
|
||||
namespace detail
|
||||
{
|
||||
class cxtoken
|
||||
{
|
||||
class cxtoken
|
||||
public:
|
||||
explicit cxtoken(const CXTranslationUnit& tu_unit, const CXToken& token);
|
||||
|
||||
const cxstring& value() const noexcept
|
||||
{
|
||||
public:
|
||||
explicit cxtoken(const CXTranslationUnit& tu_unit, const CXToken& token);
|
||||
|
||||
const cxstring& value() const noexcept
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
const char* c_str() const noexcept
|
||||
{
|
||||
return value_.c_str();
|
||||
}
|
||||
|
||||
CXTokenKind kind() const noexcept
|
||||
{
|
||||
return kind_;
|
||||
}
|
||||
|
||||
private:
|
||||
cxstring value_;
|
||||
CXTokenKind kind_;
|
||||
};
|
||||
|
||||
inline bool operator==(const cxtoken& tok, const char* str) noexcept
|
||||
{
|
||||
return tok.value() == str;
|
||||
return value_;
|
||||
}
|
||||
|
||||
inline bool operator==(const char* str, const cxtoken& tok) noexcept
|
||||
const char* c_str() const noexcept
|
||||
{
|
||||
return str == tok.value();
|
||||
return value_.c_str();
|
||||
}
|
||||
|
||||
inline bool operator!=(const cxtoken& tok, const char* str) noexcept
|
||||
CXTokenKind kind() const noexcept
|
||||
{
|
||||
return !(tok == str);
|
||||
return kind_;
|
||||
}
|
||||
|
||||
inline bool operator!=(const char* str, const cxtoken& tok) noexcept
|
||||
{
|
||||
return !(str == tok);
|
||||
}
|
||||
private:
|
||||
cxstring value_;
|
||||
CXTokenKind kind_;
|
||||
};
|
||||
|
||||
using cxtoken_iterator = std::vector<cxtoken>::const_iterator;
|
||||
|
||||
class cxtokenizer
|
||||
{
|
||||
public:
|
||||
explicit cxtokenizer(const CXTranslationUnit& tu, const CXFile& file,
|
||||
const CXCursor& cur);
|
||||
|
||||
cxtoken_iterator begin() const noexcept
|
||||
{
|
||||
return tokens_.begin();
|
||||
}
|
||||
|
||||
cxtoken_iterator end() const noexcept
|
||||
{
|
||||
return tokens_.end();
|
||||
}
|
||||
|
||||
// if it returns true, the last token is ">>",
|
||||
// but should haven been ">"
|
||||
// only a problem for template parameters
|
||||
bool unmunch() const noexcept
|
||||
{
|
||||
return unmunch_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<cxtoken> tokens_;
|
||||
bool unmunch_;
|
||||
};
|
||||
|
||||
class cxtoken_stream
|
||||
{
|
||||
public:
|
||||
explicit cxtoken_stream(const cxtokenizer& tokenizer, const CXCursor& cur)
|
||||
: cursor_(cur),
|
||||
begin_(tokenizer.begin()),
|
||||
cur_(begin_),
|
||||
end_(tokenizer.end()),
|
||||
unmunch_(tokenizer.unmunch())
|
||||
{
|
||||
}
|
||||
|
||||
const cxtoken& peek() const noexcept
|
||||
{
|
||||
if (done())
|
||||
return *std::prev(end_);
|
||||
return *cur_;
|
||||
}
|
||||
|
||||
void bump() noexcept
|
||||
{
|
||||
if (cur_ != end_)
|
||||
++cur_;
|
||||
}
|
||||
|
||||
void bump_back() noexcept
|
||||
{
|
||||
if (cur_ != begin_)
|
||||
--cur_;
|
||||
}
|
||||
|
||||
const cxtoken& get() noexcept
|
||||
{
|
||||
auto& result = peek();
|
||||
bump();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool done() const noexcept
|
||||
{
|
||||
return cur_ == end_;
|
||||
}
|
||||
|
||||
const CXCursor& cursor() const noexcept
|
||||
{
|
||||
return cursor_;
|
||||
}
|
||||
|
||||
cxtoken_iterator begin() const noexcept
|
||||
{
|
||||
return begin_;
|
||||
}
|
||||
|
||||
cxtoken_iterator cur() const noexcept
|
||||
{
|
||||
return cur_;
|
||||
}
|
||||
|
||||
cxtoken_iterator end() const noexcept
|
||||
{
|
||||
return end_;
|
||||
}
|
||||
|
||||
void set_cur(cxtoken_iterator iter) noexcept
|
||||
{
|
||||
cur_ = iter;
|
||||
}
|
||||
|
||||
bool unmunch() const noexcept
|
||||
{
|
||||
return unmunch_;
|
||||
}
|
||||
|
||||
private:
|
||||
CXCursor cursor_;
|
||||
cxtoken_iterator begin_, cur_, end_;
|
||||
bool unmunch_;
|
||||
};
|
||||
|
||||
// skips the next token
|
||||
// asserts that it has the given string
|
||||
void skip(cxtoken_stream& stream, const char* str);
|
||||
|
||||
// skips the next token if it has the given string
|
||||
// if multi_token == true, str can consist of multiple tokens optionally separated by whitespace
|
||||
bool skip_if(cxtoken_stream& stream, const char* str, bool multi_token = false);
|
||||
|
||||
// returns the location of the closing bracket
|
||||
// the current token must be (,[,{ or <
|
||||
// note: < might not work in the arguments of a template specialization
|
||||
cxtoken_iterator find_closing_bracket(cxtoken_stream stream);
|
||||
|
||||
// skips brackets
|
||||
// the current token must be (,[,{ or <
|
||||
// note: < might not work in the arguments of a template specialization
|
||||
void skip_brackets(cxtoken_stream& stream);
|
||||
|
||||
// parses attributes
|
||||
// if skip_anyway is true it will bump even if no attributes have been parsed
|
||||
cpp_attribute_list parse_attributes(cxtoken_stream& stream, bool skip_anyway = false);
|
||||
|
||||
// converts a token range to a string
|
||||
cpp_token_string to_string(cxtoken_stream& stream, cxtoken_iterator end);
|
||||
|
||||
// appends token to scope, if it is still valid
|
||||
// else clears it
|
||||
// note: does not consume the token if it is not valid,
|
||||
// returns false in that case
|
||||
bool append_scope(cxtoken_stream& stream, std::string& scope);
|
||||
inline bool operator==(const cxtoken& tok, const char* str) noexcept
|
||||
{
|
||||
return tok.value() == str;
|
||||
}
|
||||
} // namespace cppast::detail
|
||||
|
||||
inline bool operator==(const char* str, const cxtoken& tok) noexcept
|
||||
{
|
||||
return str == tok.value();
|
||||
}
|
||||
|
||||
inline bool operator!=(const cxtoken& tok, const char* str) noexcept
|
||||
{
|
||||
return !(tok == str);
|
||||
}
|
||||
|
||||
inline bool operator!=(const char* str, const cxtoken& tok) noexcept
|
||||
{
|
||||
return !(str == tok);
|
||||
}
|
||||
|
||||
using cxtoken_iterator = std::vector<cxtoken>::const_iterator;
|
||||
|
||||
class cxtokenizer
|
||||
{
|
||||
public:
|
||||
explicit cxtokenizer(const CXTranslationUnit& tu, const CXFile& file, const CXCursor& cur);
|
||||
|
||||
cxtoken_iterator begin() const noexcept
|
||||
{
|
||||
return tokens_.begin();
|
||||
}
|
||||
|
||||
cxtoken_iterator end() const noexcept
|
||||
{
|
||||
return tokens_.end();
|
||||
}
|
||||
|
||||
// if it returns true, the last token is ">>",
|
||||
// but should haven been ">"
|
||||
// only a problem for template parameters
|
||||
bool unmunch() const noexcept
|
||||
{
|
||||
return unmunch_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<cxtoken> tokens_;
|
||||
bool unmunch_;
|
||||
};
|
||||
|
||||
class cxtoken_stream
|
||||
{
|
||||
public:
|
||||
explicit cxtoken_stream(const cxtokenizer& tokenizer, const CXCursor& cur)
|
||||
: cursor_(cur), begin_(tokenizer.begin()), cur_(begin_), end_(tokenizer.end()),
|
||||
unmunch_(tokenizer.unmunch())
|
||||
{}
|
||||
|
||||
const cxtoken& peek() const noexcept
|
||||
{
|
||||
if (done())
|
||||
return *std::prev(end_);
|
||||
return *cur_;
|
||||
}
|
||||
|
||||
void bump() noexcept
|
||||
{
|
||||
if (cur_ != end_)
|
||||
++cur_;
|
||||
}
|
||||
|
||||
void bump_back() noexcept
|
||||
{
|
||||
if (cur_ != begin_)
|
||||
--cur_;
|
||||
}
|
||||
|
||||
const cxtoken& get() noexcept
|
||||
{
|
||||
auto& result = peek();
|
||||
bump();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool done() const noexcept
|
||||
{
|
||||
return cur_ == end_;
|
||||
}
|
||||
|
||||
const CXCursor& cursor() const noexcept
|
||||
{
|
||||
return cursor_;
|
||||
}
|
||||
|
||||
cxtoken_iterator begin() const noexcept
|
||||
{
|
||||
return begin_;
|
||||
}
|
||||
|
||||
cxtoken_iterator cur() const noexcept
|
||||
{
|
||||
return cur_;
|
||||
}
|
||||
|
||||
cxtoken_iterator end() const noexcept
|
||||
{
|
||||
return end_;
|
||||
}
|
||||
|
||||
void set_cur(cxtoken_iterator iter) noexcept
|
||||
{
|
||||
cur_ = iter;
|
||||
}
|
||||
|
||||
bool unmunch() const noexcept
|
||||
{
|
||||
return unmunch_;
|
||||
}
|
||||
|
||||
private:
|
||||
CXCursor cursor_;
|
||||
cxtoken_iterator begin_, cur_, end_;
|
||||
bool unmunch_;
|
||||
};
|
||||
|
||||
// skips the next token
|
||||
// asserts that it has the given string
|
||||
void skip(cxtoken_stream& stream, const char* str);
|
||||
|
||||
// skips the next token if it has the given string
|
||||
// if multi_token == true, str can consist of multiple tokens optionally separated by whitespace
|
||||
bool skip_if(cxtoken_stream& stream, const char* str, bool multi_token = false);
|
||||
|
||||
// returns the location of the closing bracket
|
||||
// the current token must be (,[,{ or <
|
||||
// note: < might not work in the arguments of a template specialization
|
||||
cxtoken_iterator find_closing_bracket(cxtoken_stream stream);
|
||||
|
||||
// skips brackets
|
||||
// the current token must be (,[,{ or <
|
||||
// note: < might not work in the arguments of a template specialization
|
||||
void skip_brackets(cxtoken_stream& stream);
|
||||
|
||||
// parses attributes
|
||||
// if skip_anyway is true it will bump even if no attributes have been parsed
|
||||
cpp_attribute_list parse_attributes(cxtoken_stream& stream, bool skip_anyway = false);
|
||||
|
||||
// converts a token range to a string
|
||||
cpp_token_string to_string(cxtoken_stream& stream, cxtoken_iterator end);
|
||||
|
||||
// appends token to scope, if it is still valid
|
||||
// else clears it
|
||||
// note: does not consume the token if it is not valid,
|
||||
// returns false in that case
|
||||
bool append_scope(cxtoken_stream& stream, std::string& scope);
|
||||
} // namespace detail
|
||||
} // namespace cppast
|
||||
|
||||
#endif // CPPAST_CXTOKENIZER_HPP_INCLUDED
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ detail::cxstring detail::get_type_kind_spelling(const CXType& type) noexcept
|
|||
|
||||
namespace
|
||||
{
|
||||
std::mutex mtx;
|
||||
std::mutex mtx;
|
||||
}
|
||||
|
||||
void detail::print_cursor_info(const CXCursor& cur) noexcept
|
||||
|
|
|
|||
|
|
@ -11,21 +11,21 @@
|
|||
|
||||
namespace cppast
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
cxstring get_display_name(const CXCursor& cur) noexcept;
|
||||
namespace detail
|
||||
{
|
||||
cxstring get_display_name(const CXCursor& cur) noexcept;
|
||||
|
||||
cxstring get_cursor_kind_spelling(const CXCursor& cur) noexcept;
|
||||
cxstring get_cursor_kind_spelling(const CXCursor& cur) noexcept;
|
||||
|
||||
cxstring get_type_kind_spelling(const CXType& type) noexcept;
|
||||
cxstring get_type_kind_spelling(const CXType& type) noexcept;
|
||||
|
||||
void print_cursor_info(const CXCursor& cur) noexcept;
|
||||
void print_cursor_info(const CXCursor& cur) noexcept;
|
||||
|
||||
void print_type_info(const CXType& type) noexcept;
|
||||
void print_type_info(const CXType& type) noexcept;
|
||||
|
||||
void print_tokens(const CXTranslationUnit& tu, const CXFile& file,
|
||||
const CXCursor& cur) noexcept;
|
||||
}
|
||||
} // namespace cppast::detail
|
||||
void print_tokens(const CXTranslationUnit& tu, const CXFile& file,
|
||||
const CXCursor& cur) noexcept;
|
||||
} // namespace detail
|
||||
} // namespace cppast
|
||||
|
||||
#endif // CPPAST_DEBUG_HELPER_HPP_INCLUDED
|
||||
|
|
|
|||
|
|
@ -4,80 +4,77 @@
|
|||
|
||||
#include <cppast/cpp_enum.hpp>
|
||||
|
||||
#include "parse_functions.hpp"
|
||||
#include "libclang_visitor.hpp"
|
||||
#include "parse_functions.hpp"
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
namespace
|
||||
{
|
||||
std::unique_ptr<cpp_enum_value> parse_enum_value(const detail::parse_context& context,
|
||||
const CXCursor& cur)
|
||||
std::unique_ptr<cpp_enum_value> parse_enum_value(const detail::parse_context& context,
|
||||
const CXCursor& cur)
|
||||
{
|
||||
if (clang_isAttribute(clang_getCursorKind(cur)))
|
||||
return nullptr;
|
||||
|
||||
DEBUG_ASSERT(cur.kind == CXCursor_EnumConstantDecl, detail::parse_error_handler{}, cur,
|
||||
"unexpected child cursor of enum");
|
||||
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
|
||||
// <identifier> [<attribute>],
|
||||
// or: <identifier> [<attribute>] = <expression>,
|
||||
auto& name = stream.get().value();
|
||||
auto attributes = detail::parse_attributes(stream);
|
||||
|
||||
std::unique_ptr<cpp_expression> value;
|
||||
if (detail::skip_if(stream, "="))
|
||||
{
|
||||
if (clang_isAttribute(clang_getCursorKind(cur)))
|
||||
return nullptr;
|
||||
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||
DEBUG_ASSERT(clang_isExpression(child.kind) && !value, detail::parse_error_handler{},
|
||||
cur, "unexpected child cursor of enum value");
|
||||
|
||||
DEBUG_ASSERT(cur.kind == CXCursor_EnumConstantDecl, detail::parse_error_handler{}, cur,
|
||||
"unexpected child cursor of enum");
|
||||
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
|
||||
// <identifier> [<attribute>],
|
||||
// or: <identifier> [<attribute>] = <expression>,
|
||||
auto& name = stream.get().value();
|
||||
auto attributes = detail::parse_attributes(stream);
|
||||
|
||||
std::unique_ptr<cpp_expression> value;
|
||||
if (detail::skip_if(stream, "="))
|
||||
{
|
||||
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||
DEBUG_ASSERT(clang_isExpression(child.kind) && !value,
|
||||
detail::parse_error_handler{}, cur,
|
||||
"unexpected child cursor of enum value");
|
||||
|
||||
value = detail::parse_expression(context, child);
|
||||
});
|
||||
}
|
||||
|
||||
auto result = cpp_enum_value::build(*context.idx, detail::get_entity_id(cur), name.c_str(),
|
||||
std::move(value));
|
||||
result->add_attribute(attributes);
|
||||
return result;
|
||||
value = detail::parse_expression(context, child);
|
||||
});
|
||||
}
|
||||
|
||||
cpp_enum::builder make_enum_builder(const detail::parse_context& context, const CXCursor& cur,
|
||||
type_safe::optional<cpp_entity_ref>& semantic_parent)
|
||||
{
|
||||
auto name = detail::get_cursor_name(cur);
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
|
||||
// enum [class/struct] [<attribute>] name [: type] {
|
||||
detail::skip(stream, "enum");
|
||||
auto scoped = detail::skip_if(stream, "class") || detail::skip_if(stream, "struct");
|
||||
auto attributes = detail::parse_attributes(stream);
|
||||
|
||||
std::string scope;
|
||||
while (!detail::skip_if(stream, name.c_str()))
|
||||
if (!detail::append_scope(stream, scope))
|
||||
DEBUG_UNREACHABLE(detail::parse_error_handler{}, cur,
|
||||
"unexpected tokens in enum name");
|
||||
if (!scope.empty())
|
||||
semantic_parent =
|
||||
cpp_entity_ref(detail::get_entity_id(clang_getCursorSemanticParent(cur)),
|
||||
std::move(scope));
|
||||
|
||||
// parse type
|
||||
auto type = detail::parse_type(context, cur, clang_getEnumDeclIntegerType(cur));
|
||||
auto type_given = detail::skip_if(stream, ":");
|
||||
|
||||
auto result = cpp_enum::builder(name.c_str(), scoped, std::move(type), type_given);
|
||||
result.get().add_attribute(attributes);
|
||||
return result;
|
||||
}
|
||||
auto result = cpp_enum_value::build(*context.idx, detail::get_entity_id(cur), name.c_str(),
|
||||
std::move(value));
|
||||
result->add_attribute(attributes);
|
||||
return result;
|
||||
}
|
||||
|
||||
cpp_enum::builder make_enum_builder(const detail::parse_context& context, const CXCursor& cur,
|
||||
type_safe::optional<cpp_entity_ref>& semantic_parent)
|
||||
{
|
||||
auto name = detail::get_cursor_name(cur);
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
|
||||
// enum [class/struct] [<attribute>] name [: type] {
|
||||
detail::skip(stream, "enum");
|
||||
auto scoped = detail::skip_if(stream, "class") || detail::skip_if(stream, "struct");
|
||||
auto attributes = detail::parse_attributes(stream);
|
||||
|
||||
std::string scope;
|
||||
while (!detail::skip_if(stream, name.c_str()))
|
||||
if (!detail::append_scope(stream, scope))
|
||||
DEBUG_UNREACHABLE(detail::parse_error_handler{}, cur, "unexpected tokens in enum name");
|
||||
if (!scope.empty())
|
||||
semantic_parent = cpp_entity_ref(detail::get_entity_id(clang_getCursorSemanticParent(cur)),
|
||||
std::move(scope));
|
||||
|
||||
// parse type
|
||||
auto type = detail::parse_type(context, cur, clang_getEnumDeclIntegerType(cur));
|
||||
auto type_given = detail::skip_if(stream, ":");
|
||||
|
||||
auto result = cpp_enum::builder(name.c_str(), scoped, std::move(type), type_given);
|
||||
result.get().add_attribute(attributes);
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_cpp_enum(const detail::parse_context& context,
|
||||
const CXCursor& cur)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
|
||||
#include <cppast/cpp_friend.hpp>
|
||||
|
||||
#include <cppast/cpp_template_parameter.hpp>
|
||||
#include <cppast/cpp_template.hpp>
|
||||
#include <cppast/cpp_template_parameter.hpp>
|
||||
|
||||
#include "parse_functions.hpp"
|
||||
#include "libclang_visitor.hpp"
|
||||
#include "parse_functions.hpp"
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
|
|
@ -45,9 +45,9 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_friend(const detail::parse_context
|
|||
// we can't use the other branch here,
|
||||
// as then the class name would be wrong
|
||||
auto name = detail::get_cursor_name(referenced);
|
||||
type =
|
||||
cpp_user_defined_type::build(cpp_type_ref(detail::get_entity_id(referenced),
|
||||
namespace_str + "::" + name.c_str()));
|
||||
type = cpp_user_defined_type::build(
|
||||
cpp_type_ref(detail::get_entity_id(referenced),
|
||||
namespace_str + "::" + name.c_str()));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
#include "parse_functions.hpp"
|
||||
|
||||
#include <cppast/cpp_language_linkage.hpp>
|
||||
#include <clang-c/Index.h>
|
||||
#include <cppast/cpp_language_linkage.hpp>
|
||||
|
||||
#include "libclang_visitor.hpp"
|
||||
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@
|
|||
|
||||
#include <clang-c/CXCompilationDatabase.h>
|
||||
|
||||
#include "cxtokenizer.hpp"
|
||||
#include "libclang_visitor.hpp"
|
||||
#include "raii_wrapper.hpp"
|
||||
#include "parse_error.hpp"
|
||||
#include "parse_functions.hpp"
|
||||
#include "preprocessor.hpp"
|
||||
#include "cxtokenizer.hpp"
|
||||
#include "raii_wrapper.hpp"
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
|
|
@ -81,22 +81,20 @@ bool libclang_compilation_database::has_config(const char* file_name) const
|
|||
|
||||
namespace
|
||||
{
|
||||
int parse_number(const char*& str)
|
||||
int parse_number(const char*& str)
|
||||
{
|
||||
auto result = 0;
|
||||
for (; *str && *str != '.'; ++str)
|
||||
{
|
||||
auto result = 0;
|
||||
for (; *str && *str != '.'; ++str)
|
||||
{
|
||||
result *= 10;
|
||||
result += int(*str - '0');
|
||||
}
|
||||
return result;
|
||||
result *= 10;
|
||||
result += int(*str - '0');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
libclang_compile_config::libclang_compile_config()
|
||||
: compile_config({}),
|
||||
write_preprocessed_(false),
|
||||
fast_preprocessing_(false),
|
||||
: compile_config({}), write_preprocessed_(false), fast_preprocessing_(false),
|
||||
remove_comments_in_macro_(false)
|
||||
{
|
||||
// set given clang binary
|
||||
|
|
@ -117,39 +115,38 @@ libclang_compile_config::libclang_compile_config()
|
|||
|
||||
namespace
|
||||
{
|
||||
struct cxcompile_commands_deleter
|
||||
struct cxcompile_commands_deleter
|
||||
{
|
||||
void operator()(CXCompileCommands cmds)
|
||||
{
|
||||
void operator()(CXCompileCommands cmds)
|
||||
{
|
||||
clang_CompileCommands_dispose(cmds);
|
||||
}
|
||||
};
|
||||
|
||||
using cxcompile_commands = detail::raii_wrapper<CXCompileCommands, cxcompile_commands_deleter>;
|
||||
|
||||
bool has_drive_prefix(const std::string& file)
|
||||
{
|
||||
return file.size() > 2 && file[1] == ':';
|
||||
clang_CompileCommands_dispose(cmds);
|
||||
}
|
||||
};
|
||||
|
||||
bool is_absolute(const std::string& file)
|
||||
{
|
||||
return !file.empty()
|
||||
&& (has_drive_prefix(file) || file.front() == '/' || file.front() == '\\');
|
||||
}
|
||||
using cxcompile_commands = detail::raii_wrapper<CXCompileCommands, cxcompile_commands_deleter>;
|
||||
|
||||
std::string get_full_path(const detail::cxstring& dir, const std::string& file)
|
||||
{
|
||||
if (is_absolute(file))
|
||||
// absolute file
|
||||
return file;
|
||||
else if (dir[dir.length() - 1] != '/' && dir[dir.length() - 1] != '\\')
|
||||
// relative needing separator
|
||||
return dir.std_str() + '/' + file;
|
||||
else
|
||||
// relative w/o separator
|
||||
return dir.std_str() + file;
|
||||
}
|
||||
bool has_drive_prefix(const std::string& file)
|
||||
{
|
||||
return file.size() > 2 && file[1] == ':';
|
||||
}
|
||||
|
||||
bool is_absolute(const std::string& file)
|
||||
{
|
||||
return !file.empty() && (has_drive_prefix(file) || file.front() == '/' || file.front() == '\\');
|
||||
}
|
||||
|
||||
std::string get_full_path(const detail::cxstring& dir, const std::string& file)
|
||||
{
|
||||
if (is_absolute(file))
|
||||
// absolute file
|
||||
return file;
|
||||
else if (dir[dir.length() - 1] != '/' && dir[dir.length() - 1] != '\\')
|
||||
// relative needing separator
|
||||
return dir.std_str() + '/' + file;
|
||||
else
|
||||
// relative w/o separator
|
||||
return dir.std_str() + file;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void detail::for_each_file(const libclang_compilation_database& database, void* user_data,
|
||||
|
|
@ -170,70 +167,70 @@ void detail::for_each_file(const libclang_compilation_database& database, void*
|
|||
|
||||
namespace
|
||||
{
|
||||
bool is_flag(const detail::cxstring& str)
|
||||
{
|
||||
return str.length() > 1u && str[0] == '-';
|
||||
}
|
||||
bool is_flag(const detail::cxstring& str)
|
||||
{
|
||||
return str.length() > 1u && str[0] == '-';
|
||||
}
|
||||
|
||||
const char* find_flag_arg_sep(const std::string& last_flag)
|
||||
{
|
||||
if (last_flag[1] == 'D')
|
||||
// no separator, equal is part of the arg
|
||||
return nullptr;
|
||||
return std::strchr(last_flag.c_str(), '=');
|
||||
}
|
||||
const char* find_flag_arg_sep(const std::string& last_flag)
|
||||
{
|
||||
if (last_flag[1] == 'D')
|
||||
// no separator, equal is part of the arg
|
||||
return nullptr;
|
||||
return std::strchr(last_flag.c_str(), '=');
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void parse_flags(CXCompileCommand cmd, Func callback)
|
||||
template <typename Func>
|
||||
void parse_flags(CXCompileCommand cmd, Func callback)
|
||||
{
|
||||
auto no_args = clang_CompileCommand_getNumArgs(cmd);
|
||||
std::string last_flag;
|
||||
for (auto i = 1u /* 0 is compiler executable */; i != no_args; ++i)
|
||||
{
|
||||
auto no_args = clang_CompileCommand_getNumArgs(cmd);
|
||||
std::string last_flag;
|
||||
for (auto i = 1u /* 0 is compiler executable */; i != no_args; ++i)
|
||||
detail::cxstring str(clang_CompileCommand_getArg(cmd, i));
|
||||
if (is_flag(str))
|
||||
{
|
||||
detail::cxstring str(clang_CompileCommand_getArg(cmd, i));
|
||||
if (is_flag(str))
|
||||
if (!last_flag.empty())
|
||||
{
|
||||
if (!last_flag.empty())
|
||||
// process last flag
|
||||
std::string args;
|
||||
if (auto ptr = find_flag_arg_sep(last_flag))
|
||||
{
|
||||
// process last flag
|
||||
std::string args;
|
||||
if (auto ptr = find_flag_arg_sep(last_flag))
|
||||
{
|
||||
auto pos = std::size_t(ptr - last_flag.c_str());
|
||||
++ptr;
|
||||
while (*ptr)
|
||||
args += *ptr++;
|
||||
last_flag.erase(pos);
|
||||
}
|
||||
else if (last_flag.size() > 2u)
|
||||
{
|
||||
// assume two character flag
|
||||
args = last_flag.substr(2u);
|
||||
last_flag.erase(2u);
|
||||
}
|
||||
|
||||
callback(std::move(last_flag), std::move(args));
|
||||
auto pos = std::size_t(ptr - last_flag.c_str());
|
||||
++ptr;
|
||||
while (*ptr)
|
||||
args += *ptr++;
|
||||
last_flag.erase(pos);
|
||||
}
|
||||
else if (last_flag.size() > 2u)
|
||||
{
|
||||
// assume two character flag
|
||||
args = last_flag.substr(2u);
|
||||
last_flag.erase(2u);
|
||||
}
|
||||
|
||||
last_flag = str.std_str();
|
||||
callback(std::move(last_flag), std::move(args));
|
||||
}
|
||||
else if (!last_flag.empty())
|
||||
{
|
||||
// we have flags + args
|
||||
callback(std::move(last_flag), str.std_str());
|
||||
last_flag.clear();
|
||||
}
|
||||
// else skip argument
|
||||
|
||||
last_flag = str.std_str();
|
||||
}
|
||||
else if (!last_flag.empty())
|
||||
{
|
||||
// we have flags + args
|
||||
callback(std::move(last_flag), str.std_str());
|
||||
last_flag.clear();
|
||||
}
|
||||
// else skip argument
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
libclang_compile_config::libclang_compile_config(const libclang_compilation_database& database,
|
||||
const std::string& file)
|
||||
: libclang_compile_config()
|
||||
{
|
||||
auto cxcommands =
|
||||
clang_CompilationDatabase_getCompileCommands(database.database_, file.c_str());
|
||||
auto cxcommands
|
||||
= clang_CompilationDatabase_getCompileCommands(database.database_, file.c_str());
|
||||
if (cxcommands == nullptr)
|
||||
throw libclang_error(detail::format("no compile commands specified for file '", file, "'"));
|
||||
cxcompile_commands commands(cxcommands);
|
||||
|
|
@ -353,8 +350,8 @@ type_safe::optional<libclang_compile_config> cppast::find_config_for(
|
|||
|
||||
if (database.has_config(file_name))
|
||||
return libclang_compile_config(database, std::move(file_name));
|
||||
static const char* extensions[] = {".h", ".hpp", ".cpp", ".h++", ".c++", ".hxx",
|
||||
".cxx", ".hh", ".cc", ".H", ".C"};
|
||||
static const char* extensions[]
|
||||
= {".h", ".hpp", ".cpp", ".h++", ".c++", ".hxx", ".cxx", ".hh", ".cc", ".H", ".C"};
|
||||
for (auto ext : extensions)
|
||||
{
|
||||
auto name = file_name + ext;
|
||||
|
|
@ -370,125 +367,122 @@ struct libclang_parser::impl
|
|||
detail::cxindex index;
|
||||
|
||||
impl() : index(clang_createIndex(0, 0)) // no diagnostic, other one is irrelevant
|
||||
{
|
||||
}
|
||||
{}
|
||||
};
|
||||
|
||||
libclang_parser::libclang_parser() : libclang_parser(default_logger()) {}
|
||||
|
||||
libclang_parser::libclang_parser(type_safe::object_ref<const diagnostic_logger> logger)
|
||||
: parser(logger), pimpl_(new impl)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
libclang_parser::~libclang_parser() noexcept {}
|
||||
|
||||
namespace
|
||||
{
|
||||
std::vector<const char*> get_arguments(const libclang_compile_config& config)
|
||||
std::vector<const char*> get_arguments(const libclang_compile_config& config)
|
||||
{
|
||||
std::vector<const char*> args
|
||||
= {"-x", "c++", "-I."}; // force C++ and enable current directory for include search
|
||||
for (auto& flag : detail::libclang_compile_config_access::flags(config))
|
||||
args.push_back(flag.c_str());
|
||||
return args;
|
||||
}
|
||||
|
||||
type_safe::optional<severity> get_severity(const CXDiagnostic& diag)
|
||||
{
|
||||
switch (clang_getDiagnosticSeverity(diag))
|
||||
{
|
||||
std::vector<const char*> args =
|
||||
{"-x", "c++", "-I."}; // force C++ and enable current directory for include search
|
||||
for (auto& flag : detail::libclang_compile_config_access::flags(config))
|
||||
args.push_back(flag.c_str());
|
||||
return args;
|
||||
}
|
||||
|
||||
type_safe::optional<severity> get_severity(const CXDiagnostic& diag)
|
||||
{
|
||||
switch (clang_getDiagnosticSeverity(diag))
|
||||
{
|
||||
case CXDiagnostic_Ignored:
|
||||
case CXDiagnostic_Note:
|
||||
case CXDiagnostic_Warning:
|
||||
// ignore those diagnostics
|
||||
return type_safe::nullopt;
|
||||
|
||||
case CXDiagnostic_Error:
|
||||
return severity::error;
|
||||
case CXDiagnostic_Fatal:
|
||||
return severity::critical;
|
||||
}
|
||||
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
case CXDiagnostic_Ignored:
|
||||
case CXDiagnostic_Note:
|
||||
case CXDiagnostic_Warning:
|
||||
// ignore those diagnostics
|
||||
return type_safe::nullopt;
|
||||
|
||||
case CXDiagnostic_Error:
|
||||
return severity::error;
|
||||
case CXDiagnostic_Fatal:
|
||||
return severity::critical;
|
||||
}
|
||||
|
||||
void print_diagnostics(const diagnostic_logger& logger, const CXTranslationUnit& tu)
|
||||
{
|
||||
auto no = clang_getNumDiagnostics(tu);
|
||||
for (auto i = 0u; i != no; ++i)
|
||||
{
|
||||
auto diag = clang_getDiagnostic(tu, i);
|
||||
auto sev = get_severity(diag);
|
||||
if (sev)
|
||||
{
|
||||
auto diag_loc = clang_getDiagnosticLocation(diag);
|
||||
CXString diag_file;
|
||||
unsigned line;
|
||||
clang_getPresumedLocation(diag_loc, &diag_file, &line, nullptr);
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
return type_safe::nullopt;
|
||||
}
|
||||
|
||||
auto loc = source_location::make_file(detail::cxstring(diag_file).c_str(), line);
|
||||
auto text = detail::cxstring(clang_getDiagnosticSpelling(diag));
|
||||
if (text != "too many errors emitted, stopping now")
|
||||
logger.log("libclang", diagnostic{text.c_str(), loc, sev.value()});
|
||||
}
|
||||
void print_diagnostics(const diagnostic_logger& logger, const CXTranslationUnit& tu)
|
||||
{
|
||||
auto no = clang_getNumDiagnostics(tu);
|
||||
for (auto i = 0u; i != no; ++i)
|
||||
{
|
||||
auto diag = clang_getDiagnostic(tu, i);
|
||||
auto sev = get_severity(diag);
|
||||
if (sev)
|
||||
{
|
||||
auto diag_loc = clang_getDiagnosticLocation(diag);
|
||||
CXString diag_file;
|
||||
unsigned line;
|
||||
clang_getPresumedLocation(diag_loc, &diag_file, &line, nullptr);
|
||||
|
||||
auto loc = source_location::make_file(detail::cxstring(diag_file).c_str(), line);
|
||||
auto text = detail::cxstring(clang_getDiagnosticSpelling(diag));
|
||||
if (text != "too many errors emitted, stopping now")
|
||||
logger.log("libclang", diagnostic{text.c_str(), loc, sev.value()});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
detail::cxtranslation_unit get_cxunit(const diagnostic_logger& logger,
|
||||
const detail::cxindex& idx,
|
||||
const libclang_compile_config& config, const char* path,
|
||||
const std::string& source)
|
||||
detail::cxtranslation_unit get_cxunit(const diagnostic_logger& logger, const detail::cxindex& idx,
|
||||
const libclang_compile_config& config, const char* path,
|
||||
const std::string& source)
|
||||
{
|
||||
CXUnsavedFile file;
|
||||
file.Filename = path;
|
||||
file.Contents = source.c_str();
|
||||
file.Length = source.length();
|
||||
|
||||
auto args = get_arguments(config);
|
||||
|
||||
CXTranslationUnit tu;
|
||||
auto flags = CXTranslationUnit_Incomplete | CXTranslationUnit_KeepGoing
|
||||
| CXTranslationUnit_DetailedPreprocessingRecord;
|
||||
|
||||
auto error
|
||||
= clang_parseTranslationUnit2(idx.get(), path, // index and path
|
||||
args.data(),
|
||||
static_cast<int>(args.size()), // arguments (ptr + size)
|
||||
&file, 1, // unsaved files (ptr + size)
|
||||
unsigned(flags), &tu);
|
||||
if (error != CXError_Success)
|
||||
{
|
||||
CXUnsavedFile file;
|
||||
file.Filename = path;
|
||||
file.Contents = source.c_str();
|
||||
file.Length = source.length();
|
||||
|
||||
auto args = get_arguments(config);
|
||||
|
||||
CXTranslationUnit tu;
|
||||
auto flags = CXTranslationUnit_Incomplete | CXTranslationUnit_KeepGoing
|
||||
| CXTranslationUnit_DetailedPreprocessingRecord;
|
||||
|
||||
auto error =
|
||||
clang_parseTranslationUnit2(idx.get(), path, // index and path
|
||||
args.data(),
|
||||
static_cast<int>(args.size()), // arguments (ptr + size)
|
||||
&file, 1, // unsaved files (ptr + size)
|
||||
unsigned(flags), &tu);
|
||||
if (error != CXError_Success)
|
||||
switch (error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case CXError_Success:
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
break;
|
||||
case CXError_Success:
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
break;
|
||||
|
||||
case CXError_Failure:
|
||||
throw libclang_error("clang_parseTranslationUnit: generic error");
|
||||
case CXError_Crashed:
|
||||
throw libclang_error("clang_parseTranslationUnit: libclang crashed :(");
|
||||
case CXError_InvalidArguments:
|
||||
throw libclang_error("clang_parseTranslationUnit: you shouldn't see this message");
|
||||
case CXError_ASTReadError:
|
||||
throw libclang_error("clang_parseTranslationUnit: AST deserialization error");
|
||||
}
|
||||
case CXError_Failure:
|
||||
throw libclang_error("clang_parseTranslationUnit: generic error");
|
||||
case CXError_Crashed:
|
||||
throw libclang_error("clang_parseTranslationUnit: libclang crashed :(");
|
||||
case CXError_InvalidArguments:
|
||||
throw libclang_error("clang_parseTranslationUnit: you shouldn't see this message");
|
||||
case CXError_ASTReadError:
|
||||
throw libclang_error("clang_parseTranslationUnit: AST deserialization error");
|
||||
}
|
||||
print_diagnostics(logger, tu);
|
||||
|
||||
return detail::cxtranslation_unit(tu);
|
||||
}
|
||||
print_diagnostics(logger, tu);
|
||||
|
||||
unsigned get_line_no(const CXCursor& cursor)
|
||||
{
|
||||
auto loc = clang_getCursorLocation(cursor);
|
||||
return detail::cxtranslation_unit(tu);
|
||||
}
|
||||
|
||||
unsigned line;
|
||||
clang_getPresumedLocation(loc, nullptr, &line, nullptr);
|
||||
return line;
|
||||
}
|
||||
unsigned get_line_no(const CXCursor& cursor)
|
||||
{
|
||||
auto loc = clang_getCursorLocation(cursor);
|
||||
|
||||
unsigned line;
|
||||
clang_getPresumedLocation(loc, nullptr, &line, nullptr);
|
||||
return line;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<cpp_file> libclang_parser::do_parse(const cpp_entity_index& idx, std::string path,
|
||||
|
|
@ -530,8 +524,8 @@ std::unique_ptr<cpp_file> libclang_parser::do_parse(const cpp_entity_index& idx,
|
|||
&& get_line_no(cur) >= include_iter->line,
|
||||
detail::assert_handler{});
|
||||
|
||||
auto full_path = include_iter->full_path.empty() ? include_iter->file_name :
|
||||
include_iter->full_path;
|
||||
auto full_path = include_iter->full_path.empty() ? include_iter->file_name
|
||||
: include_iter->full_path;
|
||||
|
||||
// if we got an absolute file path for the current file,
|
||||
// also use an absolute file path for the id
|
||||
|
|
@ -543,10 +537,10 @@ std::unique_ptr<cpp_file> libclang_parser::do_parse(const cpp_entity_index& idx,
|
|||
else
|
||||
id = cpp_entity_id(include_iter->file_name.c_str());
|
||||
|
||||
auto include =
|
||||
cpp_include_directive::build(cpp_file_ref(id,
|
||||
std::move(include_iter->file_name)),
|
||||
include_iter->kind, std::move(full_path));
|
||||
auto include
|
||||
= cpp_include_directive::build(cpp_file_ref(id,
|
||||
std::move(include_iter->file_name)),
|
||||
include_iter->kind, std::move(full_path));
|
||||
context.comments.match(*include, include_iter->line,
|
||||
false); // must not skip comments,
|
||||
// includes are not reported in order
|
||||
|
|
|
|||
|
|
@ -11,50 +11,50 @@
|
|||
|
||||
namespace cppast
|
||||
{
|
||||
namespace detail
|
||||
namespace detail
|
||||
{
|
||||
// visits direct children of an entity
|
||||
template <typename Func>
|
||||
void visit_children(CXCursor parent, Func f, bool recurse = false)
|
||||
{
|
||||
// visits direct children of an entity
|
||||
template <typename Func>
|
||||
void visit_children(CXCursor parent, Func f, bool recurse = false)
|
||||
{
|
||||
auto continue_lambda = [](CXCursor cur, CXCursor, CXClientData data) {
|
||||
auto& actual_cb = *static_cast<Func*>(data);
|
||||
actual_cb(cur);
|
||||
return CXChildVisit_Continue;
|
||||
};
|
||||
auto recurse_lambda = [](CXCursor cur, CXCursor, CXClientData data) {
|
||||
auto& actual_cb = *static_cast<Func*>(data);
|
||||
actual_cb(cur);
|
||||
return CXChildVisit_Recurse;
|
||||
};
|
||||
auto continue_lambda = [](CXCursor cur, CXCursor, CXClientData data) {
|
||||
auto& actual_cb = *static_cast<Func*>(data);
|
||||
actual_cb(cur);
|
||||
return CXChildVisit_Continue;
|
||||
};
|
||||
auto recurse_lambda = [](CXCursor cur, CXCursor, CXClientData data) {
|
||||
auto& actual_cb = *static_cast<Func*>(data);
|
||||
actual_cb(cur);
|
||||
return CXChildVisit_Recurse;
|
||||
};
|
||||
|
||||
if (recurse)
|
||||
clang_visitChildren(parent, recurse_lambda, &f);
|
||||
else
|
||||
clang_visitChildren(parent, continue_lambda, &f);
|
||||
}
|
||||
|
||||
// visits a translation unit
|
||||
// notes: only visits if directly defined in file, not included
|
||||
template <typename Func>
|
||||
void visit_tu(const cxtranslation_unit& tu, const char* path, Func f)
|
||||
{
|
||||
auto in_tu = [&](const CXCursor& cur) {
|
||||
auto location = clang_getCursorLocation(cur);
|
||||
|
||||
CXString cx_file_name;
|
||||
clang_getPresumedLocation(location, &cx_file_name, nullptr, nullptr);
|
||||
cxstring file_name(cx_file_name);
|
||||
|
||||
return file_name == path;
|
||||
};
|
||||
|
||||
visit_children(clang_getTranslationUnitCursor(tu.get()), [&](const CXCursor& cur) {
|
||||
if (in_tu(cur))
|
||||
f(cur);
|
||||
});
|
||||
}
|
||||
if (recurse)
|
||||
clang_visitChildren(parent, recurse_lambda, &f);
|
||||
else
|
||||
clang_visitChildren(parent, continue_lambda, &f);
|
||||
}
|
||||
} // namespace cppast::detail
|
||||
|
||||
// visits a translation unit
|
||||
// notes: only visits if directly defined in file, not included
|
||||
template <typename Func>
|
||||
void visit_tu(const cxtranslation_unit& tu, const char* path, Func f)
|
||||
{
|
||||
auto in_tu = [&](const CXCursor& cur) {
|
||||
auto location = clang_getCursorLocation(cur);
|
||||
|
||||
CXString cx_file_name;
|
||||
clang_getPresumedLocation(location, &cx_file_name, nullptr, nullptr);
|
||||
cxstring file_name(cx_file_name);
|
||||
|
||||
return file_name == path;
|
||||
};
|
||||
|
||||
visit_children(clang_getTranslationUnitCursor(tu.get()), [&](const CXCursor& cur) {
|
||||
if (in_tu(cur))
|
||||
f(cur);
|
||||
});
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace cppast
|
||||
|
||||
#endif // CPPAST_LIBCLANG_VISITOR_HPP_INCLUDED
|
||||
|
|
|
|||
|
|
@ -13,49 +13,48 @@ using namespace cppast;
|
|||
|
||||
namespace
|
||||
{
|
||||
cpp_namespace::builder make_ns_builder(const detail::parse_context& context,
|
||||
const CXCursor& cur)
|
||||
cpp_namespace::builder make_ns_builder(const detail::parse_context& context, const CXCursor& cur)
|
||||
{
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
// [inline] namespace|:: [<attribute>] <identifier> [{]
|
||||
|
||||
auto is_inline = false;
|
||||
if (skip_if(stream, "inline"))
|
||||
is_inline = true;
|
||||
|
||||
// C++17 nested namespace declarations get one cursor per nested name.
|
||||
// The first cursor starts with the `namespace` keyword, and the
|
||||
// following start with the `::` separator. Either way, it is skipped.
|
||||
auto is_nested = false;
|
||||
if (!detail::skip_if(stream, "namespace"))
|
||||
{
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
// [inline] namespace|:: [<attribute>] <identifier> [{]
|
||||
|
||||
auto is_inline = false;
|
||||
if (skip_if(stream, "inline"))
|
||||
is_inline = true;
|
||||
|
||||
// C++17 nested namespace declarations get one cursor per nested name.
|
||||
// The first cursor starts with the `namespace` keyword, and the
|
||||
// following start with the `::` separator. Either way, it is skipped.
|
||||
auto is_nested = false;
|
||||
if (!detail::skip_if(stream, "namespace"))
|
||||
{
|
||||
is_nested = true;
|
||||
skip(stream, "::");
|
||||
}
|
||||
|
||||
auto attributes = parse_attributes(stream);
|
||||
|
||||
// <identifier> {
|
||||
// or when anonymous: {
|
||||
if (detail::skip_if(stream, "{"))
|
||||
return cpp_namespace::builder("", is_inline, false);
|
||||
|
||||
auto& name = stream.get().value();
|
||||
|
||||
auto other_attributes = parse_attributes(stream);
|
||||
attributes.insert(attributes.end(), other_attributes.begin(), other_attributes.end());
|
||||
|
||||
// If the next token is not `::`, there are no more nested namespace
|
||||
// names, and we expect to see an opening brace.
|
||||
if (!detail::skip_if(stream, "::"))
|
||||
skip(stream, "{");
|
||||
|
||||
auto result = cpp_namespace::builder(name.c_str(), is_inline, is_nested);
|
||||
result.get().add_attribute(attributes);
|
||||
return result;
|
||||
is_nested = true;
|
||||
skip(stream, "::");
|
||||
}
|
||||
|
||||
auto attributes = parse_attributes(stream);
|
||||
|
||||
// <identifier> {
|
||||
// or when anonymous: {
|
||||
if (detail::skip_if(stream, "{"))
|
||||
return cpp_namespace::builder("", is_inline, false);
|
||||
|
||||
auto& name = stream.get().value();
|
||||
|
||||
auto other_attributes = parse_attributes(stream);
|
||||
attributes.insert(attributes.end(), other_attributes.begin(), other_attributes.end());
|
||||
|
||||
// If the next token is not `::`, there are no more nested namespace
|
||||
// names, and we expect to see an opening brace.
|
||||
if (!detail::skip_if(stream, "::"))
|
||||
skip(stream, "{");
|
||||
|
||||
auto result = cpp_namespace::builder(name.c_str(), is_inline, is_nested);
|
||||
result.get().add_attribute(attributes);
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_cpp_namespace(const detail::parse_context& context,
|
||||
cpp_entity& parent, const CXCursor& cur)
|
||||
|
|
@ -83,27 +82,27 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_namespace(const detail::parse_cont
|
|||
|
||||
namespace
|
||||
{
|
||||
cpp_entity_id parse_ns_target_cursor(const CXCursor& cur)
|
||||
{
|
||||
cpp_entity_id result("");
|
||||
detail::visit_children(cur,
|
||||
[&](const CXCursor& child) {
|
||||
auto referenced = clang_getCursorReferenced(child);
|
||||
auto kind = clang_getCursorKind(referenced);
|
||||
if (kind == CXCursor_Namespace)
|
||||
result = detail::get_entity_id(referenced);
|
||||
else if (kind == CXCursor_NamespaceAlias)
|
||||
// get target of namespace alias instead
|
||||
result = parse_ns_target_cursor(referenced);
|
||||
else
|
||||
DEBUG_UNREACHABLE(detail::parse_error_handler{}, cur,
|
||||
"unexpected target for namespace "
|
||||
"alias/using directive");
|
||||
},
|
||||
true);
|
||||
return result;
|
||||
}
|
||||
cpp_entity_id parse_ns_target_cursor(const CXCursor& cur)
|
||||
{
|
||||
cpp_entity_id result("");
|
||||
detail::visit_children(cur,
|
||||
[&](const CXCursor& child) {
|
||||
auto referenced = clang_getCursorReferenced(child);
|
||||
auto kind = clang_getCursorKind(referenced);
|
||||
if (kind == CXCursor_Namespace)
|
||||
result = detail::get_entity_id(referenced);
|
||||
else if (kind == CXCursor_NamespaceAlias)
|
||||
// get target of namespace alias instead
|
||||
result = parse_ns_target_cursor(referenced);
|
||||
else
|
||||
DEBUG_UNREACHABLE(detail::parse_error_handler{}, cur,
|
||||
"unexpected target for namespace "
|
||||
"alias/using directive");
|
||||
},
|
||||
true);
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_cpp_namespace_alias(const detail::parse_context& context,
|
||||
const CXCursor& cur)
|
||||
|
|
@ -155,54 +154,53 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_using_directive(const detail::pars
|
|||
|
||||
namespace
|
||||
{
|
||||
cpp_entity_ref parse_entity_target_cursor(const CXCursor& cur, std::string name)
|
||||
{
|
||||
type_safe::deferred_construction<cpp_entity_ref> result;
|
||||
detail::visit_children(cur,
|
||||
[&](const CXCursor& child) {
|
||||
if (result)
|
||||
return;
|
||||
cpp_entity_ref parse_entity_target_cursor(const CXCursor& cur, std::string name)
|
||||
{
|
||||
type_safe::deferred_construction<cpp_entity_ref> result;
|
||||
detail::visit_children(cur,
|
||||
[&](const CXCursor& child) {
|
||||
if (result)
|
||||
return;
|
||||
|
||||
switch (clang_getCursorKind(child))
|
||||
{
|
||||
case CXCursor_TypeRef:
|
||||
case CXCursor_TemplateRef:
|
||||
case CXCursor_MemberRef:
|
||||
case CXCursor_VariableRef:
|
||||
case CXCursor_DeclRefExpr:
|
||||
{
|
||||
auto referenced = clang_getCursorReferenced(child);
|
||||
result = cpp_entity_ref(detail::get_entity_id(referenced),
|
||||
std::move(name));
|
||||
break;
|
||||
}
|
||||
switch (clang_getCursorKind(child))
|
||||
{
|
||||
case CXCursor_TypeRef:
|
||||
case CXCursor_TemplateRef:
|
||||
case CXCursor_MemberRef:
|
||||
case CXCursor_VariableRef:
|
||||
case CXCursor_DeclRefExpr:
|
||||
{
|
||||
auto referenced = clang_getCursorReferenced(child);
|
||||
result = cpp_entity_ref(detail::get_entity_id(referenced),
|
||||
std::move(name));
|
||||
break;
|
||||
}
|
||||
|
||||
case CXCursor_OverloadedDeclRef:
|
||||
{
|
||||
auto size = clang_getNumOverloadedDecls(child);
|
||||
DEBUG_ASSERT(size >= 1u, detail::parse_error_handler{}, cur,
|
||||
"no target for using declaration");
|
||||
std::vector<cpp_entity_id> ids;
|
||||
for (auto i = 0u; i != size; ++i)
|
||||
ids.push_back(detail::get_entity_id(
|
||||
clang_getOverloadedDecl(child, i)));
|
||||
result = cpp_entity_ref(std::move(ids), std::move(name));
|
||||
break;
|
||||
}
|
||||
case CXCursor_OverloadedDeclRef:
|
||||
{
|
||||
auto size = clang_getNumOverloadedDecls(child);
|
||||
DEBUG_ASSERT(size >= 1u, detail::parse_error_handler{}, cur,
|
||||
"no target for using declaration");
|
||||
std::vector<cpp_entity_id> ids;
|
||||
for (auto i = 0u; i != size; ++i)
|
||||
ids.push_back(detail::get_entity_id(
|
||||
clang_getOverloadedDecl(child, i)));
|
||||
result = cpp_entity_ref(std::move(ids), std::move(name));
|
||||
break;
|
||||
}
|
||||
|
||||
case CXCursor_NamespaceRef:
|
||||
break; // wait for children
|
||||
case CXCursor_NamespaceRef:
|
||||
break; // wait for children
|
||||
|
||||
default:
|
||||
DEBUG_UNREACHABLE(detail::parse_error_handler{}, cur,
|
||||
"unexpected target for using declaration");
|
||||
}
|
||||
|
||||
},
|
||||
true);
|
||||
return result.value();
|
||||
}
|
||||
default:
|
||||
DEBUG_UNREACHABLE(detail::parse_error_handler{}, cur,
|
||||
"unexpected target for using declaration");
|
||||
}
|
||||
},
|
||||
true);
|
||||
return result.value();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_cpp_using_declaration(
|
||||
const detail::parse_context& context, const CXCursor& cur)
|
||||
|
|
|
|||
|
|
@ -7,89 +7,86 @@
|
|||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <debug_assert.hpp>
|
||||
#include <cppast/diagnostic.hpp>
|
||||
#include <debug_assert.hpp>
|
||||
|
||||
#include "debug_helper.hpp"
|
||||
|
||||
namespace cppast
|
||||
{
|
||||
namespace detail
|
||||
namespace detail
|
||||
{
|
||||
inline source_location make_location(const CXCursor& cur)
|
||||
{
|
||||
inline source_location make_location(const CXCursor& cur)
|
||||
{
|
||||
auto loc = clang_getCursorLocation(cur);
|
||||
auto loc = clang_getCursorLocation(cur);
|
||||
|
||||
CXString file;
|
||||
unsigned line;
|
||||
clang_getPresumedLocation(loc, &file, &line, nullptr);
|
||||
CXString file;
|
||||
unsigned line;
|
||||
clang_getPresumedLocation(loc, &file, &line, nullptr);
|
||||
|
||||
return source_location::make_file(cxstring(file).c_str(), line);
|
||||
}
|
||||
|
||||
inline source_location make_location(const CXFile& file, const CXCursor& cur)
|
||||
{
|
||||
return source_location::make_entity(get_display_name(cur).c_str(),
|
||||
cxstring(clang_getFileName(file)).c_str());
|
||||
}
|
||||
|
||||
inline source_location make_location(const CXType& type)
|
||||
{
|
||||
return source_location::make_entity(cxstring(clang_getTypeSpelling(type)).c_str());
|
||||
}
|
||||
|
||||
// thrown on a parsing error
|
||||
// not meant to escape to the user
|
||||
class parse_error : public std::logic_error
|
||||
{
|
||||
public:
|
||||
parse_error(source_location loc, std::string message)
|
||||
: std::logic_error(std::move(message)), location_(std::move(loc))
|
||||
{
|
||||
}
|
||||
|
||||
parse_error(const CXCursor& cur, std::string message)
|
||||
: parse_error(make_location(cur), std::move(message))
|
||||
{
|
||||
}
|
||||
|
||||
parse_error(const CXType& type, std::string message)
|
||||
: parse_error(make_location(type), std::move(message))
|
||||
{
|
||||
}
|
||||
|
||||
diagnostic get_diagnostic(const CXFile& file)
|
||||
{
|
||||
return get_diagnostic(cxstring(clang_getFileName(file)).c_str());
|
||||
}
|
||||
|
||||
diagnostic get_diagnostic(std::string file)
|
||||
{
|
||||
location_.file = std::move(file);
|
||||
return diagnostic{what(), location_, severity::error};
|
||||
}
|
||||
|
||||
private:
|
||||
source_location location_;
|
||||
};
|
||||
|
||||
// DEBUG_ASSERT handler for parse errors
|
||||
// throws a parse_error exception
|
||||
struct parse_error_handler : debug_assert::set_level<1>, debug_assert::allow_exception
|
||||
{
|
||||
static void handle(const debug_assert::source_location&, const char*,
|
||||
const CXCursor& cur, std::string message)
|
||||
{
|
||||
throw parse_error(cur, std::move(message));
|
||||
}
|
||||
|
||||
static void handle(const debug_assert::source_location&, const char*,
|
||||
const CXType& type, std::string message)
|
||||
{
|
||||
throw parse_error(type, std::move(message));
|
||||
}
|
||||
};
|
||||
return source_location::make_file(cxstring(file).c_str(), line);
|
||||
}
|
||||
} // namespace cppast::detail
|
||||
|
||||
inline source_location make_location(const CXFile& file, const CXCursor& cur)
|
||||
{
|
||||
return source_location::make_entity(get_display_name(cur).c_str(),
|
||||
cxstring(clang_getFileName(file)).c_str());
|
||||
}
|
||||
|
||||
inline source_location make_location(const CXType& type)
|
||||
{
|
||||
return source_location::make_entity(cxstring(clang_getTypeSpelling(type)).c_str());
|
||||
}
|
||||
|
||||
// thrown on a parsing error
|
||||
// not meant to escape to the user
|
||||
class parse_error : public std::logic_error
|
||||
{
|
||||
public:
|
||||
parse_error(source_location loc, std::string message)
|
||||
: std::logic_error(std::move(message)), location_(std::move(loc))
|
||||
{}
|
||||
|
||||
parse_error(const CXCursor& cur, std::string message)
|
||||
: parse_error(make_location(cur), std::move(message))
|
||||
{}
|
||||
|
||||
parse_error(const CXType& type, std::string message)
|
||||
: parse_error(make_location(type), std::move(message))
|
||||
{}
|
||||
|
||||
diagnostic get_diagnostic(const CXFile& file)
|
||||
{
|
||||
return get_diagnostic(cxstring(clang_getFileName(file)).c_str());
|
||||
}
|
||||
|
||||
diagnostic get_diagnostic(std::string file)
|
||||
{
|
||||
location_.file = std::move(file);
|
||||
return diagnostic{what(), location_, severity::error};
|
||||
}
|
||||
|
||||
private:
|
||||
source_location location_;
|
||||
};
|
||||
|
||||
// DEBUG_ASSERT handler for parse errors
|
||||
// throws a parse_error exception
|
||||
struct parse_error_handler : debug_assert::set_level<1>, debug_assert::allow_exception
|
||||
{
|
||||
static void handle(const debug_assert::source_location&, const char*, const CXCursor& cur,
|
||||
std::string message)
|
||||
{
|
||||
throw parse_error(cur, std::move(message));
|
||||
}
|
||||
|
||||
static void handle(const debug_assert::source_location&, const char*, const CXType& type,
|
||||
std::string message)
|
||||
{
|
||||
throw parse_error(type, std::move(message));
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
} // namespace cppast
|
||||
|
||||
#endif // CPPAST_PARSE_ERROR_HPP_INCLUDED
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
#include "parse_functions.hpp"
|
||||
|
||||
#include <cppast/cpp_storage_class_specifiers.hpp>
|
||||
#include <cppast/cpp_static_assert.hpp>
|
||||
#include <cppast/cpp_storage_class_specifiers.hpp>
|
||||
|
||||
#include "libclang_visitor.hpp"
|
||||
|
||||
|
|
@ -100,16 +100,16 @@ void detail::comment_context::match(cpp_entity& e, unsigned line, bool skip_comm
|
|||
|
||||
namespace
|
||||
{
|
||||
bool is_friend(const CXCursor& parent_cur)
|
||||
{
|
||||
bool is_friend(const CXCursor& parent_cur)
|
||||
{
|
||||
#if CPPAST_CINDEX_HAS_FRIEND
|
||||
return clang_getCursorKind(parent_cur) == CXCursor_FriendDecl;
|
||||
return clang_getCursorKind(parent_cur) == CXCursor_FriendDecl;
|
||||
#else
|
||||
(void)parent_cur;
|
||||
return false;
|
||||
(void)parent_cur;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& context,
|
||||
cpp_entity* parent, const CXCursor& cur,
|
||||
|
|
@ -165,25 +165,25 @@ std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& co
|
|||
return parse_cpp_member_variable(context, cur);
|
||||
|
||||
case CXCursor_FunctionDecl:
|
||||
if (auto tfunc =
|
||||
try_parse_cpp_function_template_specialization(context, cur, is_friend(parent_cur)))
|
||||
if (auto tfunc
|
||||
= try_parse_cpp_function_template_specialization(context, cur, is_friend(parent_cur)))
|
||||
return tfunc;
|
||||
return parse_cpp_function(context, cur, is_friend(parent_cur));
|
||||
case CXCursor_CXXMethod:
|
||||
if (auto tfunc =
|
||||
try_parse_cpp_function_template_specialization(context, cur, is_friend(parent_cur)))
|
||||
if (auto tfunc
|
||||
= try_parse_cpp_function_template_specialization(context, cur, is_friend(parent_cur)))
|
||||
return tfunc;
|
||||
else if (auto func = try_parse_static_cpp_function(context, cur))
|
||||
return func;
|
||||
return parse_cpp_member_function(context, cur, is_friend(parent_cur));
|
||||
case CXCursor_ConversionFunction:
|
||||
if (auto tfunc =
|
||||
try_parse_cpp_function_template_specialization(context, cur, is_friend(parent_cur)))
|
||||
if (auto tfunc
|
||||
= try_parse_cpp_function_template_specialization(context, cur, is_friend(parent_cur)))
|
||||
return tfunc;
|
||||
return parse_cpp_conversion_op(context, cur, is_friend(parent_cur));
|
||||
case CXCursor_Constructor:
|
||||
if (auto tfunc =
|
||||
try_parse_cpp_function_template_specialization(context, cur, is_friend(parent_cur)))
|
||||
if (auto tfunc
|
||||
= try_parse_cpp_function_template_specialization(context, cur, is_friend(parent_cur)))
|
||||
return tfunc;
|
||||
return parse_cpp_constructor(context, cur, is_friend(parent_cur));
|
||||
case CXCursor_Destructor:
|
||||
|
|
|
|||
|
|
@ -8,166 +8,161 @@
|
|||
#include <cppast/cpp_entity.hpp>
|
||||
#include <cppast/parser.hpp>
|
||||
|
||||
#include "raii_wrapper.hpp"
|
||||
#include "cxtokenizer.hpp" // for convenience
|
||||
#include "parse_error.hpp" // for convenience
|
||||
#include "preprocessor.hpp"
|
||||
#include "raii_wrapper.hpp"
|
||||
|
||||
#if CINDEX_VERSION_MINOR >= 36
|
||||
#define CPPAST_CINDEX_HAS_FRIEND 1
|
||||
# define CPPAST_CINDEX_HAS_FRIEND 1
|
||||
#else
|
||||
#define CPPAST_CINDEX_HAS_FRIEND 0
|
||||
# define CPPAST_CINDEX_HAS_FRIEND 0
|
||||
#endif
|
||||
|
||||
namespace cppast
|
||||
{
|
||||
class cpp_expression;
|
||||
class cpp_type;
|
||||
enum cpp_storage_class_specifiers : int;
|
||||
class cpp_expression;
|
||||
class cpp_type;
|
||||
enum cpp_storage_class_specifiers : int;
|
||||
|
||||
namespace detail
|
||||
namespace detail
|
||||
{
|
||||
cpp_entity_id get_entity_id(const CXCursor& cur);
|
||||
|
||||
// only use this if the name is just a single token
|
||||
// never where it is a reference to something (like base class name)
|
||||
// as then you won't get it "as-is"
|
||||
cxstring get_cursor_name(const CXCursor& cur);
|
||||
|
||||
// note: does not handle thread_local
|
||||
cpp_storage_class_specifiers get_storage_class(const CXCursor& cur);
|
||||
|
||||
class comment_context
|
||||
{
|
||||
cpp_entity_id get_entity_id(const CXCursor& cur);
|
||||
public:
|
||||
explicit comment_context(std::vector<pp_doc_comment>& comments)
|
||||
: cur_(comments.data()), end_(comments.data() + comments.size())
|
||||
{}
|
||||
|
||||
// only use this if the name is just a single token
|
||||
// never where it is a reference to something (like base class name)
|
||||
// as then you won't get it "as-is"
|
||||
cxstring get_cursor_name(const CXCursor& cur);
|
||||
// must be called for entities that want an associated comment
|
||||
// must be called *BEFORE* the children are added
|
||||
void match(cpp_entity& e, const CXCursor& cur) const;
|
||||
void match(cpp_entity& e, unsigned line, bool skip_comments = true) const;
|
||||
|
||||
// note: does not handle thread_local
|
||||
cpp_storage_class_specifiers get_storage_class(const CXCursor& cur);
|
||||
private:
|
||||
mutable pp_doc_comment* cur_;
|
||||
pp_doc_comment* end_;
|
||||
};
|
||||
|
||||
class comment_context
|
||||
{
|
||||
public:
|
||||
explicit comment_context(std::vector<pp_doc_comment>& comments)
|
||||
: cur_(comments.data()), end_(comments.data() + comments.size())
|
||||
{
|
||||
}
|
||||
struct parse_context
|
||||
{
|
||||
CXTranslationUnit tu;
|
||||
CXFile file;
|
||||
type_safe::object_ref<const diagnostic_logger> logger;
|
||||
type_safe::object_ref<const cpp_entity_index> idx;
|
||||
comment_context comments;
|
||||
mutable bool error;
|
||||
};
|
||||
|
||||
// must be called for entities that want an associated comment
|
||||
// must be called *BEFORE* the children are added
|
||||
void match(cpp_entity& e, const CXCursor& cur) const;
|
||||
void match(cpp_entity& e, unsigned line, bool skip_comments = true) const;
|
||||
// parse default value of variable, function parameter...
|
||||
std::unique_ptr<cpp_expression> parse_default_value(cpp_attribute_list& attributes,
|
||||
const parse_context& context,
|
||||
const CXCursor& cur, const char* name);
|
||||
|
||||
private:
|
||||
mutable pp_doc_comment* cur_;
|
||||
pp_doc_comment* end_;
|
||||
};
|
||||
std::unique_ptr<cpp_type> parse_type(const parse_context& context, const CXCursor& cur,
|
||||
const CXType& type);
|
||||
|
||||
struct parse_context
|
||||
{
|
||||
CXTranslationUnit tu;
|
||||
CXFile file;
|
||||
type_safe::object_ref<const diagnostic_logger> logger;
|
||||
type_safe::object_ref<const cpp_entity_index> idx;
|
||||
comment_context comments;
|
||||
mutable bool error;
|
||||
};
|
||||
// parse the type starting at the current token stream
|
||||
// and ends at the given iterator
|
||||
// this is required for situations where there is no type exposed,
|
||||
// like default type of a template type parameter
|
||||
std::unique_ptr<cpp_type> parse_raw_type(const parse_context& context, cxtoken_stream& stream,
|
||||
cxtoken_iterator end);
|
||||
|
||||
// parse default value of variable, function parameter...
|
||||
std::unique_ptr<cpp_expression> parse_default_value(cpp_attribute_list& attributes,
|
||||
const parse_context& context,
|
||||
const CXCursor& cur, const char* name);
|
||||
|
||||
std::unique_ptr<cpp_type> parse_type(const parse_context& context, const CXCursor& cur,
|
||||
const CXType& type);
|
||||
|
||||
// parse the type starting at the current token stream
|
||||
// and ends at the given iterator
|
||||
// this is required for situations where there is no type exposed,
|
||||
// like default type of a template type parameter
|
||||
std::unique_ptr<cpp_type> parse_raw_type(const parse_context& context,
|
||||
cxtoken_stream& stream, cxtoken_iterator end);
|
||||
|
||||
std::unique_ptr<cpp_expression> parse_expression(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
// parse the expression starting at the current token in the stream
|
||||
// and ends at the given iterator
|
||||
// this is required for situations where there is no expression cursor exposed,
|
||||
// like member initializers
|
||||
std::unique_ptr<cpp_expression> parse_raw_expression(const parse_context& context,
|
||||
cxtoken_stream& stream,
|
||||
cxtoken_iterator end,
|
||||
std::unique_ptr<cpp_type> type);
|
||||
|
||||
// parse_entity() dispatches on the cursor type
|
||||
// it calls one of the other parse functions defined elsewhere
|
||||
// try_parse_XXX are not exposed/differently exposed entities
|
||||
// they are called on corresponding cursor and see whether they match
|
||||
|
||||
// unexposed
|
||||
std::unique_ptr<cpp_entity> try_parse_cpp_language_linkage(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
// CXXMethod
|
||||
std::unique_ptr<cpp_entity> try_parse_static_cpp_function(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
|
||||
// on all function cursors except on destructor
|
||||
std::unique_ptr<cpp_entity> try_parse_cpp_function_template_specialization(
|
||||
const parse_context& context, const CXCursor& cur, bool is_friend);
|
||||
|
||||
// on class cursors
|
||||
std::unique_ptr<cpp_entity> try_parse_full_cpp_class_template_specialization(
|
||||
const parse_context& context, const CXCursor& cur);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_namespace(const parse_context& context,
|
||||
cpp_entity& parent, const CXCursor& cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_namespace_alias(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_using_directive(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_using_declaration(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_type_alias(const parse_context& context,
|
||||
const CXCursor& cur,
|
||||
const CXCursor& template_cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_enum(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_class(const parse_context& context,
|
||||
const CXCursor& cur,
|
||||
const CXCursor& parent_cur);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_variable(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
// also parses bitfields
|
||||
std::unique_ptr<cpp_entity> parse_cpp_member_variable(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_function(const parse_context& context,
|
||||
const CXCursor& cur, bool is_friend);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_member_function(const parse_context& context,
|
||||
const CXCursor& cur, bool is_friend);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_conversion_op(const parse_context& context,
|
||||
const CXCursor& cur, bool is_friend);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_constructor(const parse_context& context,
|
||||
const CXCursor& cur, bool is_friend);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_destructor(const parse_context& context,
|
||||
const CXCursor& cur, bool is_friend);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_friend(const parse_context& context,
|
||||
std::unique_ptr<cpp_expression> parse_expression(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
// parse the expression starting at the current token in the stream
|
||||
// and ends at the given iterator
|
||||
// this is required for situations where there is no expression cursor exposed,
|
||||
// like member initializers
|
||||
std::unique_ptr<cpp_expression> parse_raw_expression(const parse_context& context,
|
||||
cxtoken_stream& stream,
|
||||
cxtoken_iterator end,
|
||||
std::unique_ptr<cpp_type> type);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_alias_template(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_function_template(const parse_context& context,
|
||||
const CXCursor& cur,
|
||||
bool is_friend);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_class_template(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_class_template_specialization(
|
||||
const parse_context& context, const CXCursor& cur);
|
||||
// parse_entity() dispatches on the cursor type
|
||||
// it calls one of the other parse functions defined elsewhere
|
||||
// try_parse_XXX are not exposed/differently exposed entities
|
||||
// they are called on corresponding cursor and see whether they match
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_static_assert(const parse_context& context,
|
||||
// unexposed
|
||||
std::unique_ptr<cpp_entity> try_parse_cpp_language_linkage(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
// CXXMethod
|
||||
std::unique_ptr<cpp_entity> try_parse_static_cpp_function(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
|
||||
// on all function cursors except on destructor
|
||||
std::unique_ptr<cpp_entity> try_parse_cpp_function_template_specialization(
|
||||
const parse_context& context, const CXCursor& cur, bool is_friend);
|
||||
|
||||
// on class cursors
|
||||
std::unique_ptr<cpp_entity> try_parse_full_cpp_class_template_specialization(
|
||||
const parse_context& context, const CXCursor& cur);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_namespace(const parse_context& context,
|
||||
cpp_entity& parent, const CXCursor& cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_namespace_alias(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_using_directive(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_using_declaration(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
|
||||
// parent: used for nested namespace, doesn't matter otherwise
|
||||
// parent_cur: used when parsing templates or friends
|
||||
std::unique_ptr<cpp_entity> parse_entity(
|
||||
const parse_context& context, cpp_entity* parent, const CXCursor& cur,
|
||||
const CXCursor& parent_cur = clang_getNullCursor());
|
||||
}
|
||||
} // namespace cppast::detail
|
||||
std::unique_ptr<cpp_entity> parse_cpp_type_alias(const parse_context& context,
|
||||
const CXCursor& cur,
|
||||
const CXCursor& template_cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_enum(const parse_context& context, const CXCursor& cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_class(const parse_context& context, const CXCursor& cur,
|
||||
const CXCursor& parent_cur);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_variable(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
// also parses bitfields
|
||||
std::unique_ptr<cpp_entity> parse_cpp_member_variable(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_function(const parse_context& context,
|
||||
const CXCursor& cur, bool is_friend);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_member_function(const parse_context& context,
|
||||
const CXCursor& cur, bool is_friend);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_conversion_op(const parse_context& context,
|
||||
const CXCursor& cur, bool is_friend);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_constructor(const parse_context& context,
|
||||
const CXCursor& cur, bool is_friend);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_destructor(const parse_context& context,
|
||||
const CXCursor& cur, bool is_friend);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_friend(const parse_context& context, const CXCursor& cur);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_alias_template(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_function_template(const parse_context& context,
|
||||
const CXCursor& cur, bool is_friend);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_class_template(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_class_template_specialization(
|
||||
const parse_context& context, const CXCursor& cur);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_static_assert(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
|
||||
// parent: used for nested namespace, doesn't matter otherwise
|
||||
// parent_cur: used when parsing templates or friends
|
||||
std::unique_ptr<cpp_entity> parse_entity(const parse_context& context, cpp_entity* parent,
|
||||
const CXCursor& cur,
|
||||
const CXCursor& parent_cur = clang_getNullCursor());
|
||||
} // namespace detail
|
||||
} // namespace cppast
|
||||
|
||||
#endif // CPPAST_PARSE_FUNCTIONS_HPP_INCLUDED
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -10,46 +10,46 @@
|
|||
|
||||
namespace cppast
|
||||
{
|
||||
namespace detail
|
||||
namespace detail
|
||||
{
|
||||
struct pp_macro
|
||||
{
|
||||
struct pp_macro
|
||||
std::unique_ptr<cpp_macro_definition> macro;
|
||||
unsigned line;
|
||||
};
|
||||
|
||||
struct pp_include
|
||||
{
|
||||
std::string file_name, full_path;
|
||||
cpp_include_kind kind;
|
||||
unsigned line;
|
||||
};
|
||||
|
||||
struct pp_doc_comment
|
||||
{
|
||||
std::string comment;
|
||||
unsigned line;
|
||||
enum
|
||||
{
|
||||
std::unique_ptr<cpp_macro_definition> macro;
|
||||
unsigned line;
|
||||
};
|
||||
c,
|
||||
cpp,
|
||||
end_of_line,
|
||||
} kind;
|
||||
|
||||
struct pp_include
|
||||
{
|
||||
std::string file_name, full_path;
|
||||
cpp_include_kind kind;
|
||||
unsigned line;
|
||||
};
|
||||
bool matches(const cpp_entity& e, unsigned line);
|
||||
};
|
||||
|
||||
struct pp_doc_comment
|
||||
{
|
||||
std::string comment;
|
||||
unsigned line;
|
||||
enum
|
||||
{
|
||||
c,
|
||||
cpp,
|
||||
end_of_line,
|
||||
} kind;
|
||||
struct preprocessor_output
|
||||
{
|
||||
std::string source;
|
||||
std::vector<pp_include> includes;
|
||||
std::vector<pp_macro> macros;
|
||||
std::vector<pp_doc_comment> comments;
|
||||
};
|
||||
|
||||
bool matches(const cpp_entity& e, unsigned line);
|
||||
};
|
||||
|
||||
struct preprocessor_output
|
||||
{
|
||||
std::string source;
|
||||
std::vector<pp_include> includes;
|
||||
std::vector<pp_macro> macros;
|
||||
std::vector<pp_doc_comment> comments;
|
||||
};
|
||||
|
||||
preprocessor_output preprocess(const libclang_compile_config& config, const char* path,
|
||||
const diagnostic_logger& logger);
|
||||
}
|
||||
} // namespace cppast::detail
|
||||
preprocessor_output preprocess(const libclang_compile_config& config, const char* path,
|
||||
const diagnostic_logger& logger);
|
||||
} // namespace detail
|
||||
} // namespace cppast
|
||||
|
||||
#endif // CPPAST_PREPROCESSOR_HPP_INCLUDED
|
||||
|
|
|
|||
|
|
@ -16,170 +16,169 @@
|
|||
|
||||
namespace cppast
|
||||
{
|
||||
namespace detail
|
||||
namespace detail
|
||||
{
|
||||
template <typename T, class Deleter>
|
||||
class raii_wrapper : Deleter
|
||||
{
|
||||
template <typename T, class Deleter>
|
||||
class raii_wrapper : Deleter
|
||||
static_assert(std::is_pointer<T>::value, "");
|
||||
|
||||
public:
|
||||
raii_wrapper() noexcept : obj_(nullptr) {}
|
||||
|
||||
explicit raii_wrapper(T obj) noexcept : obj_(obj)
|
||||
{
|
||||
static_assert(std::is_pointer<T>::value, "");
|
||||
DEBUG_ASSERT(obj_, detail::assert_handler{});
|
||||
}
|
||||
|
||||
public:
|
||||
raii_wrapper() noexcept : obj_(nullptr) {}
|
||||
raii_wrapper(raii_wrapper&& other) noexcept : obj_(other.obj_)
|
||||
{
|
||||
DEBUG_ASSERT(obj_, detail::assert_handler{});
|
||||
other.obj_ = nullptr;
|
||||
}
|
||||
|
||||
explicit raii_wrapper(T obj) noexcept : obj_(obj)
|
||||
{
|
||||
DEBUG_ASSERT(obj_, detail::assert_handler{});
|
||||
}
|
||||
~raii_wrapper() noexcept
|
||||
{
|
||||
if (obj_)
|
||||
static_cast<Deleter&> (*this)(obj_);
|
||||
}
|
||||
|
||||
raii_wrapper(raii_wrapper&& other) noexcept : obj_(other.obj_)
|
||||
{
|
||||
DEBUG_ASSERT(obj_, detail::assert_handler{});
|
||||
other.obj_ = nullptr;
|
||||
}
|
||||
raii_wrapper& operator=(raii_wrapper&& other) noexcept
|
||||
{
|
||||
raii_wrapper tmp(std::move(other));
|
||||
swap(*this, tmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~raii_wrapper() noexcept
|
||||
{
|
||||
if (obj_)
|
||||
static_cast<Deleter&> (*this)(obj_);
|
||||
}
|
||||
friend void swap(raii_wrapper& a, raii_wrapper& b) noexcept
|
||||
{
|
||||
std::swap(a.obj_, b.obj_);
|
||||
}
|
||||
|
||||
raii_wrapper& operator=(raii_wrapper&& other) noexcept
|
||||
{
|
||||
raii_wrapper tmp(std::move(other));
|
||||
swap(*this, tmp);
|
||||
return *this;
|
||||
}
|
||||
T get() const noexcept
|
||||
{
|
||||
DEBUG_ASSERT(obj_, detail::assert_handler{});
|
||||
return obj_;
|
||||
}
|
||||
|
||||
friend void swap(raii_wrapper& a, raii_wrapper& b) noexcept
|
||||
{
|
||||
std::swap(a.obj_, b.obj_);
|
||||
}
|
||||
private:
|
||||
T obj_;
|
||||
};
|
||||
|
||||
T get() const noexcept
|
||||
{
|
||||
DEBUG_ASSERT(obj_, detail::assert_handler{});
|
||||
return obj_;
|
||||
}
|
||||
struct cxindex_deleter
|
||||
{
|
||||
void operator()(CXIndex idx) noexcept
|
||||
{
|
||||
clang_disposeIndex(idx);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
T obj_;
|
||||
using cxindex = raii_wrapper<CXIndex, cxindex_deleter>;
|
||||
|
||||
struct cxtranslation_unit_deleter
|
||||
{
|
||||
void operator()(CXTranslationUnit unit) noexcept
|
||||
{
|
||||
clang_disposeTranslationUnit(unit);
|
||||
}
|
||||
};
|
||||
|
||||
using cxtranslation_unit = raii_wrapper<CXTranslationUnit, cxtranslation_unit_deleter>;
|
||||
|
||||
class cxstring
|
||||
{
|
||||
public:
|
||||
explicit cxstring(CXString str) noexcept : str_(string(str)) {}
|
||||
|
||||
cxstring(cxstring&& other) noexcept : str_(other.str_)
|
||||
{
|
||||
other.str_.reset();
|
||||
}
|
||||
|
||||
cxstring& operator=(cxstring&& other) noexcept
|
||||
{
|
||||
if (str_)
|
||||
clang_disposeString(str_.value().str);
|
||||
str_ = other.str_;
|
||||
other.str_.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
~cxstring() noexcept
|
||||
{
|
||||
if (str_)
|
||||
clang_disposeString(str_.value().str);
|
||||
}
|
||||
|
||||
const char* c_str() const noexcept
|
||||
{
|
||||
return str_ ? str_.value().c_str : "";
|
||||
}
|
||||
|
||||
std::string std_str() const noexcept
|
||||
{
|
||||
return c_str();
|
||||
}
|
||||
|
||||
char operator[](std::size_t i) const noexcept
|
||||
{
|
||||
return c_str()[i];
|
||||
}
|
||||
|
||||
std::size_t length() const noexcept
|
||||
{
|
||||
return str_ ? str_.value().length : 0u;
|
||||
}
|
||||
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return length() == 0u;
|
||||
}
|
||||
|
||||
private:
|
||||
struct string
|
||||
{
|
||||
CXString str;
|
||||
const char* c_str;
|
||||
std::size_t length;
|
||||
|
||||
explicit string(CXString str)
|
||||
: str(std::move(str)), c_str(clang_getCString(str)), length(std::strlen(c_str))
|
||||
{}
|
||||
};
|
||||
type_safe::optional<string> str_;
|
||||
};
|
||||
|
||||
struct cxindex_deleter
|
||||
{
|
||||
void operator()(CXIndex idx) noexcept
|
||||
{
|
||||
clang_disposeIndex(idx);
|
||||
}
|
||||
};
|
||||
|
||||
using cxindex = raii_wrapper<CXIndex, cxindex_deleter>;
|
||||
|
||||
struct cxtranslation_unit_deleter
|
||||
{
|
||||
void operator()(CXTranslationUnit unit) noexcept
|
||||
{
|
||||
clang_disposeTranslationUnit(unit);
|
||||
}
|
||||
};
|
||||
|
||||
using cxtranslation_unit = raii_wrapper<CXTranslationUnit, cxtranslation_unit_deleter>;
|
||||
|
||||
class cxstring
|
||||
{
|
||||
public:
|
||||
explicit cxstring(CXString str) noexcept : str_(string(str)) {}
|
||||
|
||||
cxstring(cxstring&& other) noexcept : str_(other.str_)
|
||||
{
|
||||
other.str_.reset();
|
||||
}
|
||||
|
||||
cxstring& operator=(cxstring&& other) noexcept
|
||||
{
|
||||
if (str_)
|
||||
clang_disposeString(str_.value().str);
|
||||
str_ = other.str_;
|
||||
other.str_.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
~cxstring() noexcept
|
||||
{
|
||||
if (str_)
|
||||
clang_disposeString(str_.value().str);
|
||||
}
|
||||
|
||||
const char* c_str() const noexcept
|
||||
{
|
||||
return str_ ? str_.value().c_str : "";
|
||||
}
|
||||
|
||||
std::string std_str() const noexcept
|
||||
{
|
||||
return c_str();
|
||||
}
|
||||
|
||||
char operator[](std::size_t i) const noexcept
|
||||
{
|
||||
return c_str()[i];
|
||||
}
|
||||
|
||||
std::size_t length() const noexcept
|
||||
{
|
||||
return str_ ? str_.value().length : 0u;
|
||||
}
|
||||
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return length() == 0u;
|
||||
}
|
||||
|
||||
private:
|
||||
struct string
|
||||
{
|
||||
CXString str;
|
||||
const char* c_str;
|
||||
std::size_t length;
|
||||
|
||||
explicit string(CXString str)
|
||||
: str(std::move(str)), c_str(clang_getCString(str)), length(std::strlen(c_str))
|
||||
{
|
||||
}
|
||||
};
|
||||
type_safe::optional<string> str_;
|
||||
};
|
||||
|
||||
inline bool operator==(const cxstring& a, const cxstring& b) noexcept
|
||||
{
|
||||
return std::strcmp(a.c_str(), b.c_str()) == 0;
|
||||
}
|
||||
|
||||
inline bool operator==(const cxstring& a, const char* str) noexcept
|
||||
{
|
||||
return std::strcmp(a.c_str(), str) == 0;
|
||||
}
|
||||
|
||||
inline bool operator==(const char* str, const cxstring& b) noexcept
|
||||
{
|
||||
return std::strcmp(str, b.c_str()) == 0;
|
||||
}
|
||||
|
||||
inline bool operator!=(const cxstring& a, const cxstring& b) noexcept
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline bool operator!=(const cxstring& a, const char* str) noexcept
|
||||
{
|
||||
return !(a == str);
|
||||
}
|
||||
|
||||
inline bool operator!=(const char* str, const cxstring& b) noexcept
|
||||
{
|
||||
return !(str == b);
|
||||
}
|
||||
inline bool operator==(const cxstring& a, const cxstring& b) noexcept
|
||||
{
|
||||
return std::strcmp(a.c_str(), b.c_str()) == 0;
|
||||
}
|
||||
} // namespace cppast::detail
|
||||
|
||||
inline bool operator==(const cxstring& a, const char* str) noexcept
|
||||
{
|
||||
return std::strcmp(a.c_str(), str) == 0;
|
||||
}
|
||||
|
||||
inline bool operator==(const char* str, const cxstring& b) noexcept
|
||||
{
|
||||
return std::strcmp(str, b.c_str()) == 0;
|
||||
}
|
||||
|
||||
inline bool operator!=(const cxstring& a, const cxstring& b) noexcept
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
inline bool operator!=(const cxstring& a, const char* str) noexcept
|
||||
{
|
||||
return !(a == str);
|
||||
}
|
||||
|
||||
inline bool operator!=(const char* str, const cxstring& b) noexcept
|
||||
{
|
||||
return !(str == b);
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace cppast
|
||||
|
||||
#endif // CPPAST_RAII_WRAPPER_HPP_INCLUDED
|
||||
|
|
|
|||
|
|
@ -15,214 +15,209 @@ using namespace cppast;
|
|||
|
||||
namespace
|
||||
{
|
||||
template <typename TemplateT, typename EntityT, typename Predicate>
|
||||
type_safe::optional<typename TemplateT::builder> get_builder(
|
||||
const detail::parse_context& context, const CXCursor& cur, Predicate p)
|
||||
{
|
||||
// we need the actual entity first, then the parameters
|
||||
// so two visit calls are required
|
||||
template <typename TemplateT, typename EntityT, typename Predicate>
|
||||
type_safe::optional<typename TemplateT::builder> get_builder(const detail::parse_context& context,
|
||||
const CXCursor& cur, Predicate p)
|
||||
{
|
||||
// we need the actual entity first, then the parameters
|
||||
// so two visit calls are required
|
||||
|
||||
auto result = clang_getNullCursor();
|
||||
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||
auto kind = clang_getCursorKind(child);
|
||||
if (kind == CXCursor_TemplateTypeParameter || kind == CXCursor_NonTypeTemplateParameter
|
||||
|| kind == CXCursor_TemplateTemplateParameter)
|
||||
return;
|
||||
DEBUG_ASSERT(clang_Cursor_isNull(result), detail::parse_error_handler{}, cur,
|
||||
"unexpected child of template");
|
||||
result = child;
|
||||
});
|
||||
DEBUG_ASSERT(!clang_Cursor_isNull(result), detail::parse_error_handler{}, cur,
|
||||
"missing child of template");
|
||||
auto result = clang_getNullCursor();
|
||||
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||
auto kind = clang_getCursorKind(child);
|
||||
if (kind == CXCursor_TemplateTypeParameter || kind == CXCursor_NonTypeTemplateParameter
|
||||
|| kind == CXCursor_TemplateTemplateParameter)
|
||||
return;
|
||||
DEBUG_ASSERT(clang_Cursor_isNull(result), detail::parse_error_handler{}, cur,
|
||||
"unexpected child of template");
|
||||
result = child;
|
||||
});
|
||||
DEBUG_ASSERT(!clang_Cursor_isNull(result), detail::parse_error_handler{}, cur,
|
||||
"missing child of template");
|
||||
|
||||
auto entity = detail::parse_entity(context, nullptr, result, cur);
|
||||
if (!entity)
|
||||
return type_safe::nullopt;
|
||||
DEBUG_ASSERT(p(entity->kind()), detail::parse_error_handler{}, cur,
|
||||
"wrong child of template");
|
||||
return typename TemplateT::builder(
|
||||
std::unique_ptr<EntityT>(static_cast<EntityT*>(entity.release())));
|
||||
}
|
||||
auto entity = detail::parse_entity(context, nullptr, result, cur);
|
||||
if (!entity)
|
||||
return type_safe::nullopt;
|
||||
DEBUG_ASSERT(p(entity->kind()), detail::parse_error_handler{}, cur, "wrong child of template");
|
||||
return typename TemplateT::builder(
|
||||
std::unique_ptr<EntityT>(static_cast<EntityT*>(entity.release())));
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_template_parameter> parse_type_parameter(
|
||||
const detail::parse_context& context, const CXCursor& cur)
|
||||
{
|
||||
DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_TemplateTypeParameter,
|
||||
detail::assert_handler{});
|
||||
std::unique_ptr<cpp_template_parameter> parse_type_parameter(const detail::parse_context& context,
|
||||
const CXCursor& cur)
|
||||
{
|
||||
DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_TemplateTypeParameter,
|
||||
detail::assert_handler{});
|
||||
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
auto name = detail::get_cursor_name(cur);
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
auto name = detail::get_cursor_name(cur);
|
||||
|
||||
// syntax: typename/class [...] name [= ...]
|
||||
auto keyword = cpp_template_keyword::keyword_class;
|
||||
if (detail::skip_if(stream, "typename"))
|
||||
keyword = cpp_template_keyword::keyword_typename;
|
||||
else
|
||||
detail::skip(stream, "class");
|
||||
// syntax: typename/class [...] name [= ...]
|
||||
auto keyword = cpp_template_keyword::keyword_class;
|
||||
if (detail::skip_if(stream, "typename"))
|
||||
keyword = cpp_template_keyword::keyword_typename;
|
||||
else
|
||||
detail::skip(stream, "class");
|
||||
|
||||
auto variadic = false;
|
||||
if (detail::skip_if(stream, "..."))
|
||||
variadic = true;
|
||||
auto variadic = false;
|
||||
if (detail::skip_if(stream, "..."))
|
||||
variadic = true;
|
||||
|
||||
if (stream.peek() != "=")
|
||||
detail::skip(stream, name.c_str());
|
||||
|
||||
std::unique_ptr<cpp_type> def;
|
||||
if (detail::skip_if(stream, "="))
|
||||
// default type
|
||||
def = detail::parse_raw_type(context, stream, stream.end());
|
||||
|
||||
return cpp_template_type_parameter::build(*context.idx, detail::get_entity_id(cur),
|
||||
name.c_str(), keyword, variadic, std::move(def));
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_template_parameter> parse_non_type_parameter(
|
||||
const detail::parse_context& context, const CXCursor& cur)
|
||||
{
|
||||
DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_NonTypeTemplateParameter,
|
||||
detail::assert_handler{});
|
||||
|
||||
auto name = detail::get_cursor_name(cur);
|
||||
auto type = clang_getCursorType(cur);
|
||||
|
||||
cpp_attribute_list attributes;
|
||||
auto def = detail::parse_default_value(attributes, context, cur, name.c_str());
|
||||
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
|
||||
// see if it is variadic
|
||||
// syntax a): some-tokens ... name some-tokens
|
||||
// syntax b): some-tokens (some-tokens ... name) some-tokens-or-...
|
||||
// name might be empty, so can't loop until it occurs
|
||||
// some-tokens will not contain ... or parenthesis, however
|
||||
|
||||
auto is_variadic = false;
|
||||
for (; !stream.done(); stream.bump())
|
||||
{
|
||||
if (stream.peek() == "...")
|
||||
{
|
||||
is_variadic = true;
|
||||
break;
|
||||
}
|
||||
else if (stream.peek() == ")")
|
||||
break;
|
||||
}
|
||||
|
||||
auto result =
|
||||
cpp_non_type_template_parameter::build(*context.idx, detail::get_entity_id(cur),
|
||||
name.c_str(),
|
||||
detail::parse_type(context, cur, type),
|
||||
is_variadic, std::move(def));
|
||||
result->add_attribute(attributes);
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_template_template_parameter> parse_template_parameter(
|
||||
const detail::parse_context& context, const CXCursor& cur)
|
||||
{
|
||||
DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_TemplateTemplateParameter,
|
||||
detail::assert_handler{});
|
||||
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
auto name = detail::get_cursor_name(cur);
|
||||
|
||||
// syntax: template <…> class/typename [...] name [= …]
|
||||
detail::skip(stream, "template");
|
||||
detail::skip_brackets(stream);
|
||||
|
||||
auto keyword = cpp_template_keyword::keyword_class;
|
||||
if (detail::skip_if(stream, "typename"))
|
||||
keyword = cpp_template_keyword::keyword_typename;
|
||||
else
|
||||
detail::skip(stream, "class");
|
||||
|
||||
auto is_variadic = detail::skip_if(stream, "...");
|
||||
if (stream.peek() != "=")
|
||||
detail::skip(stream, name.c_str());
|
||||
|
||||
// now we can create the builder
|
||||
cpp_template_template_parameter::builder builder(name.c_str(), is_variadic);
|
||||
builder.keyword(keyword);
|
||||
std::unique_ptr<cpp_type> def;
|
||||
if (detail::skip_if(stream, "="))
|
||||
// default type
|
||||
def = detail::parse_raw_type(context, stream, stream.end());
|
||||
|
||||
// look for parameters and default
|
||||
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||
auto kind = clang_getCursorKind(child);
|
||||
if (kind == CXCursor_TemplateTypeParameter)
|
||||
builder.add_parameter(parse_type_parameter(context, child));
|
||||
else if (kind == CXCursor_NonTypeTemplateParameter)
|
||||
builder.add_parameter(parse_non_type_parameter(context, child));
|
||||
else if (kind == CXCursor_TemplateTemplateParameter)
|
||||
builder.add_parameter(parse_template_parameter(context, child));
|
||||
else if (kind == CXCursor_TemplateRef)
|
||||
{
|
||||
auto target = clang_getCursorReferenced(child);
|
||||
|
||||
// stream is after the keyword
|
||||
// syntax: = default
|
||||
detail::skip(stream, "=");
|
||||
|
||||
std::string spelling;
|
||||
while (!stream.done())
|
||||
spelling += stream.get().c_str();
|
||||
if (stream.unmunch())
|
||||
{
|
||||
DEBUG_ASSERT(!spelling.empty() && spelling.back() == '>',
|
||||
detail::assert_handler{});
|
||||
spelling.pop_back();
|
||||
DEBUG_ASSERT(!spelling.empty() && spelling.back() == '>',
|
||||
detail::assert_handler{});
|
||||
}
|
||||
|
||||
builder.default_template(
|
||||
cpp_template_ref(detail::get_entity_id(target), std::move(spelling)));
|
||||
}
|
||||
else
|
||||
DEBUG_ASSERT(clang_isReference(kind), detail::parse_error_handler{}, cur,
|
||||
"unexpected child of template template parameter");
|
||||
});
|
||||
|
||||
return builder.finish(*context.idx, detail::get_entity_id(cur));
|
||||
}
|
||||
|
||||
template <class Builder>
|
||||
void parse_parameters(Builder& builder, const detail::parse_context& context,
|
||||
const CXCursor& cur)
|
||||
{
|
||||
// now visit to get the parameters
|
||||
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||
auto kind = clang_getCursorKind(child);
|
||||
if (kind == CXCursor_TemplateTypeParameter)
|
||||
builder.add_parameter(parse_type_parameter(context, child));
|
||||
else if (kind == CXCursor_NonTypeTemplateParameter)
|
||||
builder.add_parameter(parse_non_type_parameter(context, child));
|
||||
else if (kind == CXCursor_TemplateTemplateParameter)
|
||||
builder.add_parameter(parse_template_parameter(context, child));
|
||||
});
|
||||
}
|
||||
|
||||
void handle_comment_attributes(cpp_entity& templ_entity, cpp_entity& non_template)
|
||||
{
|
||||
// steal comment
|
||||
auto comment = type_safe::copy(non_template.comment());
|
||||
non_template.set_comment(type_safe::nullopt);
|
||||
templ_entity.set_comment(std::move(comment));
|
||||
|
||||
// copy attributes over
|
||||
templ_entity.add_attribute(non_template.attributes());
|
||||
}
|
||||
return cpp_template_type_parameter::build(*context.idx, detail::get_entity_id(cur),
|
||||
name.c_str(), keyword, variadic, std::move(def));
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_template_parameter> parse_non_type_parameter(
|
||||
const detail::parse_context& context, const CXCursor& cur)
|
||||
{
|
||||
DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_NonTypeTemplateParameter,
|
||||
detail::assert_handler{});
|
||||
|
||||
auto name = detail::get_cursor_name(cur);
|
||||
auto type = clang_getCursorType(cur);
|
||||
|
||||
cpp_attribute_list attributes;
|
||||
auto def = detail::parse_default_value(attributes, context, cur, name.c_str());
|
||||
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
|
||||
// see if it is variadic
|
||||
// syntax a): some-tokens ... name some-tokens
|
||||
// syntax b): some-tokens (some-tokens ... name) some-tokens-or-...
|
||||
// name might be empty, so can't loop until it occurs
|
||||
// some-tokens will not contain ... or parenthesis, however
|
||||
|
||||
auto is_variadic = false;
|
||||
for (; !stream.done(); stream.bump())
|
||||
{
|
||||
if (stream.peek() == "...")
|
||||
{
|
||||
is_variadic = true;
|
||||
break;
|
||||
}
|
||||
else if (stream.peek() == ")")
|
||||
break;
|
||||
}
|
||||
|
||||
auto result = cpp_non_type_template_parameter::build(*context.idx, detail::get_entity_id(cur),
|
||||
name.c_str(),
|
||||
detail::parse_type(context, cur, type),
|
||||
is_variadic, std::move(def));
|
||||
result->add_attribute(attributes);
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_template_template_parameter> parse_template_parameter(
|
||||
const detail::parse_context& context, const CXCursor& cur)
|
||||
{
|
||||
DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_TemplateTemplateParameter,
|
||||
detail::assert_handler{});
|
||||
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
auto name = detail::get_cursor_name(cur);
|
||||
|
||||
// syntax: template <…> class/typename [...] name [= …]
|
||||
detail::skip(stream, "template");
|
||||
detail::skip_brackets(stream);
|
||||
|
||||
auto keyword = cpp_template_keyword::keyword_class;
|
||||
if (detail::skip_if(stream, "typename"))
|
||||
keyword = cpp_template_keyword::keyword_typename;
|
||||
else
|
||||
detail::skip(stream, "class");
|
||||
|
||||
auto is_variadic = detail::skip_if(stream, "...");
|
||||
detail::skip(stream, name.c_str());
|
||||
|
||||
// now we can create the builder
|
||||
cpp_template_template_parameter::builder builder(name.c_str(), is_variadic);
|
||||
builder.keyword(keyword);
|
||||
|
||||
// look for parameters and default
|
||||
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||
auto kind = clang_getCursorKind(child);
|
||||
if (kind == CXCursor_TemplateTypeParameter)
|
||||
builder.add_parameter(parse_type_parameter(context, child));
|
||||
else if (kind == CXCursor_NonTypeTemplateParameter)
|
||||
builder.add_parameter(parse_non_type_parameter(context, child));
|
||||
else if (kind == CXCursor_TemplateTemplateParameter)
|
||||
builder.add_parameter(parse_template_parameter(context, child));
|
||||
else if (kind == CXCursor_TemplateRef)
|
||||
{
|
||||
auto target = clang_getCursorReferenced(child);
|
||||
|
||||
// stream is after the keyword
|
||||
// syntax: = default
|
||||
detail::skip(stream, "=");
|
||||
|
||||
std::string spelling;
|
||||
while (!stream.done())
|
||||
spelling += stream.get().c_str();
|
||||
if (stream.unmunch())
|
||||
{
|
||||
DEBUG_ASSERT(!spelling.empty() && spelling.back() == '>', detail::assert_handler{});
|
||||
spelling.pop_back();
|
||||
DEBUG_ASSERT(!spelling.empty() && spelling.back() == '>', detail::assert_handler{});
|
||||
}
|
||||
|
||||
builder.default_template(
|
||||
cpp_template_ref(detail::get_entity_id(target), std::move(spelling)));
|
||||
}
|
||||
else
|
||||
DEBUG_ASSERT(clang_isReference(kind), detail::parse_error_handler{}, cur,
|
||||
"unexpected child of template template parameter");
|
||||
});
|
||||
|
||||
return builder.finish(*context.idx, detail::get_entity_id(cur));
|
||||
}
|
||||
|
||||
template <class Builder>
|
||||
void parse_parameters(Builder& builder, const detail::parse_context& context, const CXCursor& cur)
|
||||
{
|
||||
// now visit to get the parameters
|
||||
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||
auto kind = clang_getCursorKind(child);
|
||||
if (kind == CXCursor_TemplateTypeParameter)
|
||||
builder.add_parameter(parse_type_parameter(context, child));
|
||||
else if (kind == CXCursor_NonTypeTemplateParameter)
|
||||
builder.add_parameter(parse_non_type_parameter(context, child));
|
||||
else if (kind == CXCursor_TemplateTemplateParameter)
|
||||
builder.add_parameter(parse_template_parameter(context, child));
|
||||
});
|
||||
}
|
||||
|
||||
void handle_comment_attributes(cpp_entity& templ_entity, cpp_entity& non_template)
|
||||
{
|
||||
// steal comment
|
||||
auto comment = type_safe::copy(non_template.comment());
|
||||
non_template.set_comment(type_safe::nullopt);
|
||||
templ_entity.set_comment(std::move(comment));
|
||||
|
||||
// copy attributes over
|
||||
templ_entity.add_attribute(non_template.attributes());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_cpp_alias_template(const detail::parse_context& context,
|
||||
const CXCursor& cur)
|
||||
{
|
||||
DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_TypeAliasTemplateDecl,
|
||||
detail::assert_handler{});
|
||||
auto builder =
|
||||
get_builder<cpp_alias_template, cpp_type_alias>(context, cur, [](cpp_entity_kind k) {
|
||||
return k == cpp_entity_kind::type_alias_t;
|
||||
});
|
||||
auto builder
|
||||
= get_builder<cpp_alias_template, cpp_type_alias>(context, cur, [](cpp_entity_kind k) {
|
||||
return k == cpp_entity_kind::type_alias_t;
|
||||
});
|
||||
if (!builder)
|
||||
return nullptr;
|
||||
context.comments.match(builder.value().get(), cur);
|
||||
|
|
@ -274,28 +269,27 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_function_template(
|
|||
|
||||
namespace
|
||||
{
|
||||
template <class Builder>
|
||||
void parse_arguments(Builder& b, const detail::parse_context& context, const CXCursor& cur)
|
||||
template <class Builder>
|
||||
void parse_arguments(Builder& b, const detail::parse_context& context, const CXCursor& cur)
|
||||
{
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
|
||||
while (!stream.done() && !detail::skip_if(stream, detail::get_cursor_name(cur).c_str(), true))
|
||||
stream.bump();
|
||||
|
||||
if (stream.peek() == "<")
|
||||
{
|
||||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::cxtoken_stream stream(tokenizer, cur);
|
||||
auto iter = detail::find_closing_bracket(stream);
|
||||
stream.bump();
|
||||
|
||||
while (!stream.done()
|
||||
&& !detail::skip_if(stream, detail::get_cursor_name(cur).c_str(), true))
|
||||
stream.bump();
|
||||
|
||||
if (stream.peek() == "<")
|
||||
{
|
||||
auto iter = detail::find_closing_bracket(stream);
|
||||
stream.bump();
|
||||
|
||||
auto args = detail::to_string(stream, iter);
|
||||
b.add_unexposed_arguments(std::move(args));
|
||||
}
|
||||
else
|
||||
b.add_unexposed_arguments(cpp_token_string::builder().finish());
|
||||
auto args = detail::to_string(stream, iter);
|
||||
b.add_unexposed_arguments(std::move(args));
|
||||
}
|
||||
else
|
||||
b.add_unexposed_arguments(cpp_token_string::builder().finish());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::try_parse_cpp_function_template_specialization(
|
||||
const detail::parse_context& context, const CXCursor& cur, bool is_friend)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -64,8 +64,8 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_variable(const detail::parse_conte
|
|||
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
|
||||
for (auto& token : tokenizer)
|
||||
if (token.value() == "thread_local")
|
||||
storage_class =
|
||||
cpp_storage_class_specifiers(storage_class | cpp_storage_class_thread_local);
|
||||
storage_class
|
||||
= cpp_storage_class_specifiers(storage_class | cpp_storage_class_thread_local);
|
||||
else if (token.value() == "constexpr")
|
||||
is_constexpr = true;
|
||||
|
||||
|
|
@ -75,9 +75,9 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_variable(const detail::parse_conte
|
|||
std::unique_ptr<cpp_variable> result;
|
||||
if (clang_isCursorDefinition(cur))
|
||||
{
|
||||
result =
|
||||
cpp_variable::build(*context.idx, get_entity_id(cur), name.c_str(), std::move(type),
|
||||
std::move(default_value), storage_class, is_constexpr);
|
||||
result
|
||||
= cpp_variable::build(*context.idx, get_entity_id(cur), name.c_str(), std::move(type),
|
||||
std::move(default_value), storage_class, is_constexpr);
|
||||
}
|
||||
else
|
||||
result = cpp_variable::build_declaration(get_entity_id(cur), name.c_str(), std::move(type),
|
||||
|
|
|
|||
|
|
@ -18,47 +18,46 @@ using namespace cppast;
|
|||
|
||||
namespace
|
||||
{
|
||||
cpp_access_specifier_kind get_initial_access(const cpp_entity& e)
|
||||
{
|
||||
if (e.kind() == cpp_class::kind())
|
||||
return static_cast<const cpp_class&>(e).class_kind() == cpp_class_kind::class_t ?
|
||||
cpp_private :
|
||||
cpp_public;
|
||||
return cpp_public;
|
||||
}
|
||||
cpp_access_specifier_kind get_initial_access(const cpp_entity& e)
|
||||
{
|
||||
if (e.kind() == cpp_class::kind())
|
||||
return static_cast<const cpp_class&>(e).class_kind() == cpp_class_kind::class_t
|
||||
? cpp_private
|
||||
: cpp_public;
|
||||
return cpp_public;
|
||||
}
|
||||
|
||||
void update_access(cpp_access_specifier_kind& child_access, const cpp_entity& child)
|
||||
{
|
||||
if (child.kind() == cpp_access_specifier::kind())
|
||||
child_access = static_cast<const cpp_access_specifier&>(child).access_specifier();
|
||||
}
|
||||
void update_access(cpp_access_specifier_kind& child_access, const cpp_entity& child)
|
||||
{
|
||||
if (child.kind() == cpp_access_specifier::kind())
|
||||
child_access = static_cast<const cpp_access_specifier&>(child).access_specifier();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool handle_container(const cpp_entity& e, detail::visitor_callback_t cb, void* functor,
|
||||
cpp_access_specifier_kind cur_access, bool last_child)
|
||||
{
|
||||
auto& container = static_cast<const T&>(e);
|
||||
template <typename T>
|
||||
bool handle_container(const cpp_entity& e, detail::visitor_callback_t cb, void* functor,
|
||||
cpp_access_specifier_kind cur_access, bool last_child)
|
||||
{
|
||||
auto& container = static_cast<const T&>(e);
|
||||
|
||||
auto handle_children =
|
||||
cb(functor, container, {visitor_info::container_entity_enter, cur_access, last_child});
|
||||
if (handle_children)
|
||||
auto handle_children
|
||||
= cb(functor, container, {visitor_info::container_entity_enter, cur_access, last_child});
|
||||
if (handle_children)
|
||||
{
|
||||
auto child_access = get_initial_access(e);
|
||||
for (auto iter = container.begin(); iter != container.end();)
|
||||
{
|
||||
auto child_access = get_initial_access(e);
|
||||
for (auto iter = container.begin(); iter != container.end();)
|
||||
{
|
||||
auto& cur = *iter;
|
||||
++iter;
|
||||
auto& cur = *iter;
|
||||
++iter;
|
||||
|
||||
update_access(child_access, cur);
|
||||
update_access(child_access, cur);
|
||||
|
||||
if (!detail::visit(cur, cb, functor, child_access, iter == container.end()))
|
||||
return false;
|
||||
}
|
||||
if (!detail::visit(cur, cb, functor, child_access, iter == container.end()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return cb(functor, container,
|
||||
{visitor_info::container_entity_exit, cur_access, last_child});
|
||||
}
|
||||
|
||||
return cb(functor, container, {visitor_info::container_entity_exit, cur_access, last_child});
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool detail::visit(const cpp_entity& e, detail::visitor_callback_t cb, void* functor,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue