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_;
|
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.
|
/// else the empty string.
|
||||||
/// \notes This may include template parameters.
|
/// \notes This may include template parameters.
|
||||||
std::string semantic_scope() const noexcept
|
std::string semantic_scope() const noexcept
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,15 @@ namespace
|
||||||
detail::skip_brackets(stream);
|
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)
|
bool is_class(const CXCursor& parent)
|
||||||
{
|
{
|
||||||
auto kind = clang_getCursorKind(parent);
|
auto kind = clang_getCursorKind(parent);
|
||||||
|
|
@ -108,6 +117,9 @@ namespace
|
||||||
|| kind == CXCursor_ClassTemplatePartialSpecialization;
|
|| 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)
|
CXCursor get_definition_scope(const CXCursor& cur, bool is_friend)
|
||||||
{
|
{
|
||||||
auto parent = clang_getCursorLexicalParent(cur);
|
auto parent = clang_getCursorLexicalParent(cur);
|
||||||
|
|
@ -138,25 +150,63 @@ namespace
|
||||||
|
|
||||||
type_safe::optional<cpp_entity_ref> parse_scope(const CXCursor& cur, bool is_friend)
|
type_safe::optional<cpp_entity_ref> parse_scope(const CXCursor& cur, bool is_friend)
|
||||||
{
|
{
|
||||||
std::string scope;
|
std::string scope_name;
|
||||||
// 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
|
auto friended = clang_getCursorReferenced(cur);
|
||||||
for (auto definition = get_definition_scope(cur, is_friend),
|
if (is_friend && !clang_Cursor_isNull(friended))
|
||||||
parent = clang_getCursorSemanticParent(cur);
|
|
||||||
!equivalent_cursor(definition, parent); parent = clang_getCursorSemanticParent(parent))
|
|
||||||
{
|
{
|
||||||
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,
|
detail::parse_error_handler{}, cur,
|
||||||
"infinite loop while calculating scope");
|
"invalid common parent of friend and friended");
|
||||||
auto parent_name = detail::cxstring(clang_getCursorDisplayName(parent));
|
|
||||||
scope = parent_name.std_str() + "::" + std::move(scope);
|
// 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;
|
return type_safe::nullopt;
|
||||||
else
|
else
|
||||||
return cpp_entity_ref(detail::get_entity_id(clang_getCursorSemanticParent(cur)),
|
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
|
// just the tokens occurring in the prefix
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,21 @@ class g {};
|
||||||
|
|
||||||
namespace ns
|
namespace ns
|
||||||
{
|
{
|
||||||
|
namespace other_ns
|
||||||
|
{
|
||||||
|
namespace inner
|
||||||
|
{
|
||||||
|
/// h2
|
||||||
|
void h2() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// h
|
/// h
|
||||||
class h {};
|
class h
|
||||||
|
{
|
||||||
|
/// friend void other_ns::inner::h2();
|
||||||
|
friend void other_ns::inner::h2();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// b::f
|
/// b::f
|
||||||
|
|
@ -115,7 +128,7 @@ int d() {}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
cpp_entity_index idx;
|
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);
|
auto def = idx.lookup_definition(id);
|
||||||
REQUIRE(def.has_value());
|
REQUIRE(def.has_value());
|
||||||
REQUIRE(def.value().comment());
|
REQUIRE(def.value().comment());
|
||||||
|
|
@ -184,6 +197,13 @@ int d() {}
|
||||||
REQUIRE(func.definition());
|
REQUIRE(func.definition());
|
||||||
check_definition(func.definition().value(), "b::f");
|
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")
|
else if (func.name() == "operator int")
|
||||||
{
|
{
|
||||||
REQUIRE(func.semantic_scope() == "b::");
|
REQUIRE(func.semantic_scope() == "b::");
|
||||||
|
|
@ -269,5 +289,5 @@ int d() {}
|
||||||
else
|
else
|
||||||
REQUIRE(false);
|
REQUIRE(false);
|
||||||
});
|
});
|
||||||
REQUIRE(count == 17u);
|
REQUIRE(count == 18u);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue