diff --git a/src/libclang/friend_parser.cpp b/src/libclang/friend_parser.cpp index 14830e8..9649fa5 100644 --- a/src/libclang/friend_parser.cpp +++ b/src/libclang/friend_parser.cpp @@ -74,7 +74,7 @@ std::unique_ptr detail::parse_cpp_friend(const detail::parse_context } else if (clang_isDeclaration(kind)) { - entity = parse_entity(context, child); + entity = parse_entity(context, child, cur); if (entity) { // steal comment diff --git a/src/libclang/function_parser.cpp b/src/libclang/function_parser.cpp index cc92d1a..3491f9e 100644 --- a/src/libclang/function_parser.cpp +++ b/src/libclang/function_parser.cpp @@ -85,13 +85,72 @@ namespace detail::skip_brackets(stream); } + bool is_class(const CXCursor& parent) + { + auto kind = clang_getCursorKind(parent); + return kind == CXCursor_ClassDecl || kind == CXCursor_StructDecl + || kind == CXCursor_UnionDecl || kind == CXCursor_ClassTemplate + || kind == CXCursor_ClassTemplatePartialSpecialization; + } + + CXCursor get_definition_scope(const CXCursor& cur, bool is_friend) + { + auto parent = clang_getCursorLexicalParent(cur); + if (is_friend) + { + // find the lexical parent that isn't a class + // as the definition scope is a namespace + while (is_class(parent)) + parent = clang_getCursorSemanticParent(parent); + + DEBUG_ASSERT(clang_getCursorKind(parent) == CXCursor_Namespace + || clang_getCursorKind(parent) == CXCursor_TranslationUnit, + detail::parse_error_handler{}, cur, + "unable to find definition scope of friend"); + } + return parent; + } + + bool equivalent_cursor(const CXCursor& a, const CXCursor& b) + { + if (clang_getCursorKind(a) == clang_getCursorKind(b) + && clang_getCursorKind(a) == CXCursor_Namespace) + return detail::cxstring(clang_getCursorUSR(a)) + == detail::cxstring(clang_getCursorUSR(b)); + else + return clang_equalCursors(a, b) == 1; + } + + type_safe::optional 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)) + { + 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 = parent_name.std_str() + "::" + std::move(scope); + } + + if (scope.empty()) + return type_safe::nullopt; + else + return cpp_entity_ref(detail::get_entity_id(clang_getCursorSemanticParent(cur)), + std::move(scope)); + } + // just the tokens occurring in the prefix struct prefix_info { - type_safe::optional semantic_parent; - bool is_constexpr = false; - bool is_virtual = false; - bool is_explicit = false; + bool is_constexpr = false; + bool is_virtual = false; + bool is_explicit = false; + bool is_friend = false; }; bool prefix_end(detail::token_stream& stream, const char* name, bool is_ctor) @@ -137,25 +196,15 @@ namespace { prefix_info result; - std::string scope; while (!stream.done() && !prefix_end(stream, name, is_ctor)) { if (detail::skip_if(stream, "constexpr")) - { result.is_constexpr = true; - scope.clear(); - } else if (detail::skip_if(stream, "virtual")) - { result.is_virtual = true; - scope.clear(); - } else if (detail::skip_if(stream, "explicit")) - { result.is_explicit = true; - scope.clear(); - } - else if (!detail::append_scope(stream, scope)) + else stream.bump(); } DEBUG_ASSERT(!stream.done(), detail::parse_error_handler{}, stream.cursor(), @@ -164,14 +213,6 @@ namespace { // function name can be enclosed in parentheses } - if (!scope.empty() && scope.back() == ':') - { - result.semantic_parent = - cpp_entity_ref(detail::get_entity_id( - clang_getCursorSemanticParent(stream.cursor())), - std::move(scope)); - } - return result; } @@ -372,7 +413,8 @@ namespace } std::unique_ptr parse_cpp_function_impl(const detail::parse_context& context, - const CXCursor& cur, bool is_static) + const CXCursor& cur, bool is_static, + bool is_friend) { auto name = detail::get_cursor_name(cur); @@ -405,21 +447,21 @@ namespace if (is_templated_cursor(cur)) return builder.finish(detail::get_entity_id(cur), suffix.body_kind, - std::move(prefix.semantic_parent)); + parse_scope(cur, is_friend)); else return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind, - std::move(prefix.semantic_parent)); + parse_scope(cur, is_friend)); } } std::unique_ptr detail::parse_cpp_function(const detail::parse_context& context, - const CXCursor& cur) + const CXCursor& cur, bool is_friend) { DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_FunctionDecl || clang_getTemplateCursorKind(cur) == CXCursor_FunctionDecl, detail::assert_handler{}); type_safe::optional semantic_parent; - return parse_cpp_function_impl(context, cur, false); + return parse_cpp_function_impl(context, cur, false, is_friend); } std::unique_ptr detail::try_parse_static_cpp_function( @@ -429,7 +471,7 @@ std::unique_ptr detail::try_parse_static_cpp_function( || clang_getTemplateCursorKind(cur) == CXCursor_CXXMethod, detail::assert_handler{}); if (clang_CXXMethod_isStatic(cur)) - return parse_cpp_function_impl(context, cur, true); + return parse_cpp_function_impl(context, cur, true, false); return nullptr; } @@ -521,7 +563,7 @@ namespace } std::unique_ptr detail::parse_cpp_member_function(const detail::parse_context& context, - const CXCursor& cur) + const CXCursor& cur, bool is_friend) { DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_CXXMethod || clang_getTemplateCursorKind(cur) == CXCursor_CXXMethod, @@ -548,11 +590,11 @@ std::unique_ptr detail::parse_cpp_member_function(const detail::pars skip_parameters(stream); return handle_suffix(context, cur, builder, stream, prefix.is_virtual, - std::move(prefix.semantic_parent)); + parse_scope(cur, is_friend)); } std::unique_ptr detail::parse_cpp_conversion_op(const detail::parse_context& context, - const CXCursor& cur) + const CXCursor& cur, bool is_friend) { DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_ConversionFunction || clang_getTemplateCursorKind(cur) == CXCursor_ConversionFunction, @@ -609,11 +651,11 @@ std::unique_ptr detail::parse_cpp_conversion_op(const detail::parse_ builder.is_constexpr(); return handle_suffix(context, cur, builder, stream, prefix.is_virtual, - std::move(prefix.semantic_parent)); + parse_scope(cur, is_friend)); } std::unique_ptr detail::parse_cpp_constructor(const detail::parse_context& context, - const CXCursor& cur) + const CXCursor& cur, bool is_friend) { DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_Constructor || clang_getTemplateCursorKind(cur) == CXCursor_Constructor, @@ -648,14 +690,14 @@ std::unique_ptr detail::parse_cpp_constructor(const detail::parse_co if (is_templated_cursor(cur)) return builder.finish(detail::get_entity_id(cur), suffix.body_kind, - std::move(prefix.semantic_parent)); + parse_scope(cur, is_friend)); else return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind, - std::move(prefix.semantic_parent)); + parse_scope(cur, is_friend)); } std::unique_ptr detail::parse_cpp_destructor(const detail::parse_context& context, - const CXCursor& cur) + const CXCursor& cur, bool is_friend) { DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_Destructor, detail::assert_handler{}); @@ -672,5 +714,5 @@ std::unique_ptr 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, - std::move(prefix_info.semantic_parent)); + parse_scope(cur, is_friend)); } diff --git a/src/libclang/parse_functions.cpp b/src/libclang/parse_functions.cpp index d17aa6f..4940cdd 100644 --- a/src/libclang/parse_functions.cpp +++ b/src/libclang/parse_functions.cpp @@ -91,6 +91,19 @@ void detail::comment_context::match(cpp_entity& e, unsigned line) const e.set_comment(std::move(cur_++->comment)); } +namespace +{ + bool is_friend(const CXCursor& parent_cur) + { +#if CPPAST_CINDEX_HAS_FRIEND + return clang_getCursorKind(parent_cur) == CXCursor_FriendDecl; +#else + (void)parent_cur; + return false; +#endif + } +} + std::unique_ptr detail::parse_entity(const detail::parse_context& context, const CXCursor& cur, const CXCursor& parent_cur) try @@ -145,25 +158,29 @@ std::unique_ptr 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)) + if (auto tfunc = + try_parse_cpp_function_template_specialization(context, cur, is_friend(parent_cur))) return tfunc; - return parse_cpp_function(context, cur); + return parse_cpp_function(context, cur, is_friend(parent_cur)); case CXCursor_CXXMethod: - if (auto tfunc = try_parse_cpp_function_template_specialization(context, 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); + 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)) + if (auto tfunc = + try_parse_cpp_function_template_specialization(context, cur, is_friend(parent_cur))) return tfunc; - return parse_cpp_conversion_op(context, cur); + 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)) + if (auto tfunc = + try_parse_cpp_function_template_specialization(context, cur, is_friend(parent_cur))) return tfunc; - return parse_cpp_constructor(context, cur); + return parse_cpp_constructor(context, cur, is_friend(parent_cur)); case CXCursor_Destructor: - return parse_cpp_destructor(context, cur); + return parse_cpp_destructor(context, cur, is_friend(parent_cur)); #if CPPAST_CINDEX_HAS_FRIEND case CXCursor_FriendDecl: @@ -173,7 +190,7 @@ std::unique_ptr detail::parse_entity(const detail::parse_context& co case CXCursor_TypeAliasTemplateDecl: return parse_cpp_alias_template(context, cur); case CXCursor_FunctionTemplate: - return parse_cpp_function_template(context, cur); + return parse_cpp_function_template(context, cur, is_friend(parent_cur)); case CXCursor_ClassTemplate: return parse_cpp_class_template(context, cur); case CXCursor_ClassTemplatePartialSpecialization: diff --git a/src/libclang/parse_functions.hpp b/src/libclang/parse_functions.hpp index db84937..4572437 100644 --- a/src/libclang/parse_functions.hpp +++ b/src/libclang/parse_functions.hpp @@ -103,7 +103,7 @@ namespace cppast // on all function cursors except on destructor std::unique_ptr try_parse_cpp_function_template_specialization( - const parse_context& context, const CXCursor& cur); + const parse_context& context, const CXCursor& cur, bool is_friend); // on class cursors std::unique_ptr try_parse_full_cpp_class_template_specialization( @@ -134,15 +134,15 @@ namespace cppast const CXCursor& cur); std::unique_ptr parse_cpp_function(const parse_context& context, - const CXCursor& cur); + const CXCursor& cur, bool is_friend); std::unique_ptr parse_cpp_member_function(const parse_context& context, - const CXCursor& cur); + const CXCursor& cur, bool is_friend); std::unique_ptr parse_cpp_conversion_op(const parse_context& context, - const CXCursor& cur); + const CXCursor& cur, bool is_friend); std::unique_ptr parse_cpp_constructor(const parse_context& context, - const CXCursor& cur); + const CXCursor& cur, bool is_friend); std::unique_ptr parse_cpp_destructor(const parse_context& context, - const CXCursor& cur); + const CXCursor& cur, bool is_friend); std::unique_ptr parse_cpp_friend(const parse_context& context, const CXCursor& cur); @@ -150,7 +150,8 @@ namespace cppast std::unique_ptr parse_cpp_alias_template(const parse_context& context, const CXCursor& cur); std::unique_ptr parse_cpp_function_template(const parse_context& context, - const CXCursor& cur); + const CXCursor& cur, + bool is_friend); std::unique_ptr parse_cpp_class_template(const parse_context& context, const CXCursor& cur); std::unique_ptr parse_cpp_class_template_specialization( diff --git a/src/libclang/template_parser.cpp b/src/libclang/template_parser.cpp index ef25975..1b4ca78 100644 --- a/src/libclang/template_parser.cpp +++ b/src/libclang/template_parser.cpp @@ -216,7 +216,7 @@ std::unique_ptr detail::parse_cpp_alias_template(const detail::parse } std::unique_ptr detail::parse_cpp_function_template( - const detail::parse_context& context, const CXCursor& cur) + const detail::parse_context& context, const CXCursor& cur, bool is_friend) { DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_FunctionTemplate, detail::assert_handler{}); @@ -224,19 +224,19 @@ std::unique_ptr detail::parse_cpp_function_template( switch (clang_getTemplateCursorKind(cur)) { case CXCursor_FunctionDecl: - func = detail::parse_cpp_function(context, cur); + func = detail::parse_cpp_function(context, cur, is_friend); break; case CXCursor_CXXMethod: if (auto sfunc = detail::try_parse_static_cpp_function(context, cur)) func = std::move(sfunc); else - func = detail::parse_cpp_member_function(context, cur); + func = detail::parse_cpp_member_function(context, cur, is_friend); break; case CXCursor_ConversionFunction: - func = detail::parse_cpp_conversion_op(context, cur); + func = detail::parse_cpp_conversion_op(context, cur, is_friend); break; case CXCursor_Constructor: - func = detail::parse_cpp_constructor(context, cur); + func = detail::parse_cpp_constructor(context, cur, is_friend); break; default: @@ -284,7 +284,7 @@ namespace } std::unique_ptr detail::try_parse_cpp_function_template_specialization( - const detail::parse_context& context, const CXCursor& cur) + const detail::parse_context& context, const CXCursor& cur, bool is_friend) { auto templ = clang_getSpecializedCursorTemplate(cur); if (clang_Cursor_isNull(templ)) @@ -294,19 +294,19 @@ std::unique_ptr detail::try_parse_cpp_function_template_specializati switch (clang_getCursorKind(cur)) { case CXCursor_FunctionDecl: - func = detail::parse_cpp_function(context, cur); + func = detail::parse_cpp_function(context, cur, is_friend); break; case CXCursor_CXXMethod: if (auto sfunc = detail::try_parse_static_cpp_function(context, cur)) func = std::move(sfunc); else - func = detail::parse_cpp_member_function(context, cur); + func = detail::parse_cpp_member_function(context, cur, is_friend); break; case CXCursor_ConversionFunction: - func = detail::parse_cpp_conversion_op(context, cur); + func = detail::parse_cpp_conversion_op(context, cur, is_friend); break; case CXCursor_Constructor: - func = detail::parse_cpp_constructor(context, cur); + func = detail::parse_cpp_constructor(context, cur, is_friend); break; default: