Parse semantic parent of variable definitions

Fixes #151.
This commit is contained in:
Jonathan Müller 2022-12-07 12:59:30 +01:00
commit 05bd2f4caf
3 changed files with 79 additions and 73 deletions

View file

@ -154,66 +154,6 @@ bool equivalent_cursor(const CXCursor& a, const CXCursor& b)
return clang_equalCursors(a, b) == 1;
}
type_safe::optional<cpp_entity_ref> parse_scope(const CXCursor& cur, bool is_friend)
{
std::string scope_name;
auto friended = clang_getCursorReferenced(cur);
if (is_friend && !clang_Cursor_isNull(friended))
{
// it refers to another function
// find the common parent between the two cursors
// scope is the scope from the common parent down to the function
auto friended_parents = get_semantic_parents(friended);
auto cur_parents = get_semantic_parents(get_definition_scope(cur, true));
// remove common parents
while (!friended_parents.empty() && !cur_parents.empty()
&& equivalent_cursor(friended_parents.back(), cur_parents.back()))
{
friended_parents.pop_back();
cur_parents.pop_back();
}
DEBUG_ASSERT(!clang_isTranslationUnit(clang_getCursorKind(friended_parents.back()))
&& !friended_parents.empty(),
detail::parse_error_handler{}, cur,
"invalid common parent of friend and friended");
// scope consists of all remaining parents of friended
// (last one is cursor itself)
for (auto iter = friended_parents.rbegin(); iter != std::prev(friended_parents.rend());
++iter)
{
auto parent_name = detail::cxstring(clang_getCursorDisplayName(*iter));
scope_name += parent_name.std_str() + "::";
}
}
else
{
// find the difference between the definition scope parent and semantic parent
// all semantic parents in between form the scope
// the definition scope is the lexical parent for regular functions,
// and the scope outside of the class for friend functions
for (auto definition = get_definition_scope(cur, is_friend),
parent = clang_getCursorSemanticParent(cur);
!equivalent_cursor(definition, parent); parent = clang_getCursorSemanticParent(parent))
{
DEBUG_ASSERT(!clang_isTranslationUnit(clang_getCursorKind(parent)),
detail::parse_error_handler{}, cur,
"infinite loop while calculating scope");
auto parent_name = detail::cxstring(clang_getCursorDisplayName(parent));
scope_name = parent_name.std_str() + "::" + std::move(scope_name);
}
}
if (scope_name.empty())
return type_safe::nullopt;
else
return cpp_entity_ref(detail::get_entity_id(clang_getCursorSemanticParent(cur)),
std::move(scope_name));
}
// just the tokens occurring in the prefix
struct prefix_info
{
@ -553,13 +493,73 @@ std::unique_ptr<cpp_entity> parse_cpp_function_impl(const detail::parse_context&
if (is_templated_cursor(cur))
return builder.finish(detail::get_entity_id(cur), suffix.body_kind,
parse_scope(cur, is_friend));
cppast::detail::get_semantic_parent(cur, is_friend));
else
return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind,
parse_scope(cur, is_friend));
cppast::detail::get_semantic_parent(cur, is_friend));
}
} // namespace
type_safe::optional<cpp_entity_ref> detail::get_semantic_parent(const CXCursor& cur, bool is_friend)
{
std::string scope_name;
auto friended = clang_getCursorReferenced(cur);
if (is_friend && !clang_Cursor_isNull(friended))
{
// it refers to another function
// find the common parent between the two cursors
// scope is the scope from the common parent down to the function
auto friended_parents = get_semantic_parents(friended);
auto cur_parents = get_semantic_parents(get_definition_scope(cur, true));
// remove common parents
while (!friended_parents.empty() && !cur_parents.empty()
&& equivalent_cursor(friended_parents.back(), cur_parents.back()))
{
friended_parents.pop_back();
cur_parents.pop_back();
}
DEBUG_ASSERT(!clang_isTranslationUnit(clang_getCursorKind(friended_parents.back()))
&& !friended_parents.empty(),
detail::parse_error_handler{}, cur,
"invalid common parent of friend and friended");
// scope consists of all remaining parents of friended
// (last one is cursor itself)
for (auto iter = friended_parents.rbegin(); iter != std::prev(friended_parents.rend());
++iter)
{
auto parent_name = detail::cxstring(clang_getCursorDisplayName(*iter));
scope_name += parent_name.std_str() + "::";
}
}
else
{
// find the difference between the definition scope parent and semantic parent
// all semantic parents in between form the scope
// the definition scope is the lexical parent for regular functions,
// and the scope outside of the class for friend functions
for (auto definition = get_definition_scope(cur, is_friend),
parent = clang_getCursorSemanticParent(cur);
!equivalent_cursor(definition, parent); parent = clang_getCursorSemanticParent(parent))
{
DEBUG_ASSERT(!clang_isTranslationUnit(clang_getCursorKind(parent)),
detail::parse_error_handler{}, cur,
"infinite loop while calculating scope");
auto parent_name = detail::cxstring(clang_getCursorDisplayName(parent));
scope_name = parent_name.std_str() + "::" + std::move(scope_name);
}
}
if (scope_name.empty())
return type_safe::nullopt;
else
return cpp_entity_ref(detail::get_entity_id(clang_getCursorSemanticParent(cur)),
std::move(scope_name));
}
std::unique_ptr<cpp_entity> detail::parse_cpp_function(const detail::parse_context& context,
const CXCursor& cur, bool is_friend)
{
@ -699,7 +699,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_member_function(const detail::pars
skip_parameters(stream);
return handle_suffix(context, cur, builder, stream, prefix.is_virtual,
parse_scope(cur, is_friend));
get_semantic_parent(cur, is_friend));
}
std::unique_ptr<cpp_entity> detail::parse_cpp_conversion_op(const detail::parse_context& context,
@ -764,7 +764,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_conversion_op(const detail::parse_
builder.is_consteval();
return handle_suffix(context, cur, builder, stream, prefix.is_virtual,
parse_scope(cur, is_friend));
get_semantic_parent(cur, is_friend));
}
std::unique_ptr<cpp_entity> detail::parse_cpp_constructor(const detail::parse_context& context,
@ -808,10 +808,10 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_constructor(const detail::parse_co
if (is_templated_cursor(cur))
return builder.finish(detail::get_entity_id(cur), suffix.body_kind,
parse_scope(cur, is_friend));
get_semantic_parent(cur, is_friend));
else
return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind,
parse_scope(cur, is_friend));
get_semantic_parent(cur, is_friend));
}
std::unique_ptr<cpp_entity> detail::parse_cpp_destructor(const detail::parse_context& context,
@ -833,5 +833,5 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_destructor(const detail::parse_con
detail::skip(stream, "(");
detail::skip(stream, ")");
return handle_suffix(context, cur, builder, stream, prefix_info.is_virtual,
parse_scope(cur, is_friend));
get_semantic_parent(cur, is_friend));
}

View file

@ -62,6 +62,8 @@ namespace detail
const parse_context& context,
const CXCursor& cur, const char* name);
type_safe::optional<cpp_entity_ref> get_semantic_parent(const CXCursor& cur, bool is_friend);
std::unique_ptr<cpp_type> parse_type(const parse_context& context, const CXCursor& cur,
const CXType& type);
@ -91,8 +93,8 @@ namespace detail
// unexposed
std::unique_ptr<cpp_entity> try_parse_cpp_language_linkage(const parse_context& context,
const CXCursor& cur);
//unexposed
// unexposed
std::unique_ptr<cpp_entity> try_parse_cpp_concept(const parse_context& context,
const CXCursor& cur);

View file

@ -71,16 +71,20 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_variable(const detail::parse_conte
cpp_attribute_list attributes;
auto default_value = parse_default_value(attributes, context, cur, name.c_str());
auto parent = get_semantic_parent(cur, false);
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, std::move(parent));
}
else
{
result = cpp_variable::build_declaration(get_entity_id(cur), name.c_str(), std::move(type),
storage_class, is_constexpr);
storage_class, is_constexpr, std::move(parent));
}
context.comments.match(*result, cur);
result->add_attribute(attributes);
return result;