Fix issue with asymmetric common parents of friend function and friend
This commit is contained in:
parent
b3885bbb68
commit
49d77c5543
3 changed files with 86 additions and 16 deletions
|
|
@ -49,7 +49,7 @@ namespace cppast
|
|||
return semantic_parent_;
|
||||
}
|
||||
|
||||
/// \returns The name of the semantic parent, if it has own,
|
||||
/// \returns The name of the semantic parent, if it has one,
|
||||
/// else the empty string.
|
||||
/// \notes This may include template parameters.
|
||||
std::string semantic_scope() const noexcept
|
||||
|
|
|
|||
|
|
@ -100,6 +100,15 @@ namespace
|
|||
detail::skip_brackets(stream);
|
||||
}
|
||||
|
||||
std::vector<CXCursor> get_semantic_parents(CXCursor cur)
|
||||
{
|
||||
std::vector<CXCursor> result;
|
||||
for (; !clang_isTranslationUnit(clang_getCursorKind(cur));
|
||||
cur = clang_getCursorSemanticParent(cur))
|
||||
result.push_back(cur);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool is_class(const CXCursor& parent)
|
||||
{
|
||||
auto kind = clang_getCursorKind(parent);
|
||||
|
|
@ -108,6 +117,9 @@ namespace
|
|||
|| kind == CXCursor_ClassTemplatePartialSpecialization;
|
||||
}
|
||||
|
||||
// returns the scope where the function is contained in
|
||||
// for regular functions that is the lexcial parent
|
||||
// for friend functions it is the enclosing scope of the class
|
||||
CXCursor get_definition_scope(const CXCursor& cur, bool is_friend)
|
||||
{
|
||||
auto parent = clang_getCursorLexicalParent(cur);
|
||||
|
|
@ -138,25 +150,63 @@ namespace
|
|||
|
||||
type_safe::optional<cpp_entity_ref> parse_scope(const CXCursor& cur, bool is_friend)
|
||||
{
|
||||
std::string scope;
|
||||
// find the semantic parents we need until we're at the same level of the parent where the definition is
|
||||
// the semantic parents are all the scopes that need to be appended
|
||||
for (auto definition = get_definition_scope(cur, is_friend),
|
||||
parent = clang_getCursorSemanticParent(cur);
|
||||
!equivalent_cursor(definition, parent); parent = clang_getCursorSemanticParent(parent))
|
||||
std::string scope_name;
|
||||
|
||||
auto friended = clang_getCursorReferenced(cur);
|
||||
if (is_friend && !clang_Cursor_isNull(friended))
|
||||
{
|
||||
DEBUG_ASSERT(!clang_isTranslationUnit(clang_getCursorKind(parent)),
|
||||
// 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,
|
||||
"infinite loop while calculating scope");
|
||||
auto parent_name = detail::cxstring(clang_getCursorDisplayName(parent));
|
||||
scope = parent_name.std_str() + "::" + std::move(scope);
|
||||
"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.empty())
|
||||
if (scope_name.empty())
|
||||
return type_safe::nullopt;
|
||||
else
|
||||
return cpp_entity_ref(detail::get_entity_id(clang_getCursorSemanticParent(cur)),
|
||||
std::move(scope));
|
||||
std::move(scope_name));
|
||||
}
|
||||
|
||||
// just the tokens occurring in the prefix
|
||||
|
|
|
|||
|
|
@ -36,8 +36,21 @@ class g {};
|
|||
|
||||
namespace ns
|
||||
{
|
||||
namespace other_ns
|
||||
{
|
||||
namespace inner
|
||||
{
|
||||
/// h2
|
||||
void h2() {}
|
||||
}
|
||||
}
|
||||
|
||||
/// h
|
||||
class h {};
|
||||
class h
|
||||
{
|
||||
/// friend void other_ns::inner::h2();
|
||||
friend void other_ns::inner::h2();
|
||||
};
|
||||
}
|
||||
|
||||
/// b::f
|
||||
|
|
@ -115,7 +128,7 @@ int d() {}
|
|||
)";
|
||||
|
||||
cpp_entity_index idx;
|
||||
auto check_definition = [&](cpp_entity_id id, const char* name) {
|
||||
auto check_definition = [&](cpp_entity_id id, const char* name) {
|
||||
auto def = idx.lookup_definition(id);
|
||||
REQUIRE(def.has_value());
|
||||
REQUIRE(def.value().comment());
|
||||
|
|
@ -184,6 +197,13 @@ int d() {}
|
|||
REQUIRE(func.definition());
|
||||
check_definition(func.definition().value(), "b::f");
|
||||
}
|
||||
else if (func.name() == "h2")
|
||||
{
|
||||
REQUIRE(func.semantic_scope() == "other_ns::inner::");
|
||||
REQUIRE(func.is_declaration());
|
||||
REQUIRE(func.definition());
|
||||
check_definition(func.definition().value(), "h2");
|
||||
}
|
||||
else if (func.name() == "operator int")
|
||||
{
|
||||
REQUIRE(func.semantic_scope() == "b::");
|
||||
|
|
@ -269,5 +289,5 @@ int d() {}
|
|||
else
|
||||
REQUIRE(false);
|
||||
});
|
||||
REQUIRE(count == 17u);
|
||||
REQUIRE(count == 18u);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue