From 599f2bbff8e4620cfb580cb9a3461d1ee97b3a3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20M=C3=BCller?= Date: Fri, 14 Apr 2017 16:44:25 +0200 Subject: [PATCH] Add semantic parent to forward declarable entities --- include/cppast/cpp_class.hpp | 5 +- include/cppast/cpp_enum.hpp | 7 +- include/cppast/cpp_forward_declarable.hpp | 29 +++++++- include/cppast/cpp_function.hpp | 14 ++-- src/code_generator.cpp | 12 +++- src/cpp_class.cpp | 13 ++-- src/cpp_variable.cpp | 2 +- src/libclang/class_parser.cpp | 31 ++++++++- src/libclang/enum_parser.cpp | 19 ++++-- src/libclang/friend_parser.cpp | 9 ++- src/libclang/function_parser.cpp | 80 ++++++++++------------- src/libclang/tokenizer.cpp | 32 +++++++++ src/libclang/tokenizer.hpp | 6 ++ test/cpp_class.cpp | 11 ++-- test/cpp_enum.cpp | 25 +++++-- test/cpp_friend.cpp | 9 ++- test/cpp_function.cpp | 19 +++--- test/cpp_function_template.cpp | 17 +++-- test/cpp_member_function.cpp | 20 ++++-- test/test_parser.hpp | 9 ++- 20 files changed, 260 insertions(+), 109 deletions(-) diff --git a/include/cppast/cpp_class.hpp b/include/cppast/cpp_class.hpp index 043f99b..e59b1fe 100644 --- a/include/cppast/cpp_class.hpp +++ b/include/cppast/cpp_class.hpp @@ -178,7 +178,8 @@ namespace cppast /// \effects Registers the class in the [cppast::cpp_entity_index](), /// using the given [cppast::cpp_entity_id](). /// \returns The finished class. - std::unique_ptr finish(const cpp_entity_index& idx, cpp_entity_id id); + std::unique_ptr finish(const cpp_entity_index& idx, cpp_entity_id id, + type_safe::optional semantic_parent); /// \effects Marks the class as forward declaration. /// \returns The finished class. @@ -187,7 +188,7 @@ namespace cppast /// \effects Returns the finished class without registering it. /// \notes This is intended for templated classes only. - std::unique_ptr finish(); + std::unique_ptr finish(type_safe::optional semantic_parent); /// \effects Returns the finish class without registering it and marks it as forward declaration. /// \notes This is intended for templated classes only. diff --git a/include/cppast/cpp_enum.hpp b/include/cppast/cpp_enum.hpp index 2ddbd45..ee55ccc 100644 --- a/include/cppast/cpp_enum.hpp +++ b/include/cppast/cpp_enum.hpp @@ -85,8 +85,11 @@ namespace cppast /// \effects Registers the enum in the [cppast::cpp_entity_index](), /// using the given [cppast::cpp_entity_id](). /// \returns The finished enum. - std::unique_ptr finish(const cpp_entity_index& idx, cpp_entity_id id) noexcept + std::unique_ptr finish( + const cpp_entity_index& idx, cpp_entity_id id, + type_safe::optional semantic_parent) noexcept { + enum_->set_semantic_parent(std::move(semantic_parent)); idx.register_definition(std::move(id), type_safe::ref(*enum_)); return std::move(enum_); } @@ -96,7 +99,7 @@ namespace cppast std::unique_ptr finish_declaration(const cpp_entity_index& idx, cpp_entity_id definition_id) noexcept { - enum_->set_definition(definition_id); + enum_->mark_declaration(definition_id); idx.register_forward_declaration(std::move(definition_id), type_safe::ref(*enum_)); return std::move(enum_); } diff --git a/include/cppast/cpp_forward_declarable.hpp b/include/cppast/cpp_forward_declarable.hpp index c9c7b6b..66bd055 100644 --- a/include/cppast/cpp_forward_declarable.hpp +++ b/include/cppast/cpp_forward_declarable.hpp @@ -41,6 +41,22 @@ namespace cppast return definition_; } + /// \returns A reference to the semantic parent of the entity. + /// This applies only to out-of-line definitions + /// and is the entity which owns the declaration. + const type_safe::optional& semantic_parent() const noexcept + { + return semantic_parent_; + } + + /// \returns The name of the semantic parent, if it has own, + /// else the empty string. + /// \notes This may include template parameters. + std::string semantic_scope() const noexcept + { + return semantic_parent_.map(&cpp_entity_ref::name).value_or(""); + } + protected: /// \effects Marks the entity as definition. /// \notes If it is not a definition, @@ -49,15 +65,22 @@ namespace cppast ~cpp_forward_declarable() noexcept = default; - /// \effects Sets the definition of the entity, + /// \effects Sets the definition entity, /// marking it as a forward declaration. - void set_definition(cpp_entity_id def) noexcept + void mark_declaration(cpp_entity_id def) noexcept { definition_ = std::move(def); } + /// \effects Sets the semantic parent of the entity. + void set_semantic_parent(type_safe::optional semantic_parent) noexcept + { + semantic_parent_ = std::move(semantic_parent); + } + private: - type_safe::optional definition_; + type_safe::optional semantic_parent_; + type_safe::optional definition_; }; /// \returns Whether or not the given entity is a definition. diff --git a/include/cppast/cpp_function.hpp b/include/cppast/cpp_function.hpp index fffadbf..61dce82 100644 --- a/include/cppast/cpp_function.hpp +++ b/include/cppast/cpp_function.hpp @@ -137,14 +137,16 @@ namespace cppast /// Else marks it as a declaration. /// \returns The finished function. std::unique_ptr finish(const cpp_entity_index& idx, cpp_entity_id id, - cpp_function_body_kind body_kind) + cpp_function_body_kind body_kind, + type_safe::optional semantic_parent) { function->body_ = body_kind; + function->set_semantic_parent(std::move(semantic_parent)); if (cppast::is_definition(body_kind)) idx.register_definition(std::move(id), type_safe::ref(*function)); else { - function->set_definition(id); + function->mark_declaration(id); idx.register_forward_declaration(std::move(id), type_safe::ref(*function)); } return std::move(function); @@ -152,11 +154,13 @@ namespace cppast /// \returns The finished function without registering it. /// \notes This is intended for templated functions only. - std::unique_ptr finish(cpp_entity_id id, cpp_function_body_kind body_kind) + std::unique_ptr finish(cpp_entity_id id, cpp_function_body_kind body_kind, + type_safe::optional semantic_parent) { - if (!cppast::is_definition(body_kind)) - function->set_definition(id); function->body_ = body_kind; + function->set_semantic_parent(std::move(semantic_parent)); + if (!cppast::is_definition(body_kind)) + function->mark_declaration(id); return std::move(function); } diff --git a/src/code_generator.cpp b/src/code_generator.cpp index d10e946..a54e938 100644 --- a/src/code_generator.cpp +++ b/src/code_generator.cpp @@ -205,7 +205,7 @@ namespace output << keyword("enum"); if (e.is_scoped()) output << whitespace << keyword("class"); - output << whitespace << identifier(e.name()); + output << whitespace << identifier(e.semantic_scope()) << identifier(e.name()); if (e.has_explicit_type()) { output << newl << punctuation(":"); @@ -285,6 +285,7 @@ namespace output << keyword("friend") << whitespace; output << keyword(to_string(c.class_kind())) << whitespace; + output << identifier(c.semantic_scope()); if (spec) { output << spec.value().primary_template(); @@ -492,6 +493,7 @@ namespace output << whitespace; } + output << identifier(func.semantic_scope()); if (spec) { output << spec.value().primary_template(); @@ -585,6 +587,7 @@ namespace output << whitespace; } + output << identifier(func.semantic_scope()); if (spec) { output << spec.value().primary_template(); @@ -621,6 +624,8 @@ namespace else write_prefix_virtual(output, op.virtual_info()); + output << identifier(op.semantic_scope()); + auto pos = op.name().find("operator"); output << identifier(op.name().substr(0u, pos)) << keyword("operator") << whitespace; detail::write_type(output, op.return_type(), ""); @@ -645,7 +650,7 @@ namespace if (ctor.is_constexpr()) output << keyword("constexpr") << whitespace; - output << identifier(ctor.name()); + output << identifier(ctor.semantic_scope()) << identifier(ctor.name()); write_function_parameters(output, ctor); write_noexcept(output, ctor, false); @@ -661,7 +666,8 @@ namespace if (is_friended(dtor)) output << keyword("friend") << whitespace; write_prefix_virtual(output, dtor.virtual_info()); - output << identifier(dtor.name()) << punctuation("(") << punctuation(")"); + output << identifier(dtor.semantic_scope()) << identifier(dtor.name()) + << punctuation("(") << punctuation(")"); write_noexcept(output, dtor, false); write_suffix_virtual(output, dtor.virtual_info()); diff --git a/src/cpp_class.cpp b/src/cpp_class.cpp index 3878d1d..84a801d 100644 --- a/src/cpp_class.cpp +++ b/src/cpp_class.cpp @@ -9,8 +9,11 @@ using namespace cppast; -std::unique_ptr cpp_class::builder::finish(const cpp_entity_index& idx, cpp_entity_id id) +std::unique_ptr cpp_class::builder::finish( + const cpp_entity_index& idx, cpp_entity_id id, + type_safe::optional semantic_parent) { + class_->set_semantic_parent(std::move(semantic_parent)); idx.register_definition(std::move(id), type_safe::ref(*class_)); return std::move(class_); } @@ -18,19 +21,21 @@ std::unique_ptr cpp_class::builder::finish(const cpp_entity_index& id std::unique_ptr cpp_class::builder::finish_declaration(const cpp_entity_index& idx, cpp_entity_id definition_id) { - class_->set_definition(definition_id); + class_->mark_declaration(definition_id); idx.register_forward_declaration(std::move(definition_id), type_safe::ref(*class_)); return std::move(class_); } -std::unique_ptr cpp_class::builder::finish() +std::unique_ptr cpp_class::builder::finish( + type_safe::optional semantic_parent) { + class_->set_semantic_parent(std::move(semantic_parent)); return std::move(class_); } std::unique_ptr cpp_class::builder::finish_declaration(cpp_entity_id definition_id) { - class_->set_definition(definition_id); + class_->mark_declaration(definition_id); return std::move(class_); } diff --git a/src/cpp_variable.cpp b/src/cpp_variable.cpp index eefe9b3..49781a8 100644 --- a/src/cpp_variable.cpp +++ b/src/cpp_variable.cpp @@ -33,7 +33,7 @@ std::unique_ptr cpp_variable::build_declaration(cpp_entity_id defi { auto result = std::unique_ptr( new cpp_variable(std::move(name), std::move(type), nullptr, spec, is_constexpr)); - result->set_definition(definition_id); + result->mark_declaration(definition_id); return result; } diff --git a/src/libclang/class_parser.cpp b/src/libclang/class_parser.cpp index 8ac26d4..d7068a5 100644 --- a/src/libclang/class_parser.cpp +++ b/src/libclang/class_parser.cpp @@ -99,9 +99,34 @@ std::unique_ptr detail::parse_cpp_class(const detail::parse_context& auto is_friend = false; #endif - auto builder = make_class_builder(cur); + auto builder = make_class_builder(cur); + type_safe::optional semantic_parent; if (!is_friend) { + if (!clang_equalCursors(clang_getCursorSemanticParent(cur), + clang_getCursorLexicalParent(cur))) + { + // out-of-line definition + detail::tokenizer tokenizer(context.tu, context.file, cur); + detail::token_stream stream(tokenizer, cur); + + std::string name = detail::get_cursor_name(cur).c_str(); + auto pos = name.find('<'); + if (pos != std::string::npos) + name.erase(pos, std::string::npos); + + std::string scope; + while (!detail::skip_if(stream, name.c_str())) + { + if (!detail::append_scope(stream, scope)) + stream.bump(); + } + if (!scope.empty()) + semantic_parent = + cpp_entity_ref(detail::get_entity_id(clang_getCursorSemanticParent(cur)), + std::move(scope)); + } + context.comments.match(builder.get(), cur); detail::visit_children(cur, [&](const CXCursor& child) { auto kind = clang_getCursorKind(child); @@ -123,7 +148,9 @@ std::unique_ptr detail::parse_cpp_class(const detail::parse_context& } if (!is_friend && clang_isCursorDefinition(cur)) - return is_templated ? builder.finish() : builder.finish(*context.idx, get_entity_id(cur)); + 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)); diff --git a/src/libclang/enum_parser.cpp b/src/libclang/enum_parser.cpp index bcb4e3d..b65ceb5 100644 --- a/src/libclang/enum_parser.cpp +++ b/src/libclang/enum_parser.cpp @@ -41,8 +41,10 @@ namespace std::move(value)); } - cpp_enum::builder make_enum_builder(const detail::parse_context& context, const CXCursor& cur) + cpp_enum::builder make_enum_builder(const detail::parse_context& context, const CXCursor& cur, + type_safe::optional& semantic_parent) { + auto name = detail::get_cursor_name(cur); detail::tokenizer tokenizer(context.tu, context.file, cur); detail::token_stream stream(tokenizer, cur); @@ -51,7 +53,15 @@ namespace detail::skip(stream, "enum"); auto scoped = detail::skip_if(stream, "class"); detail::skip_attribute(stream); - auto& name = stream.get().value(); + 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)); @@ -66,7 +76,8 @@ std::unique_ptr detail::parse_cpp_enum(const detail::parse_context& { DEBUG_ASSERT(cur.kind == CXCursor_EnumDecl, detail::assert_handler{}); - auto builder = make_enum_builder(context, cur); + type_safe::optional semantic_parent; + auto builder = make_enum_builder(context, cur, semantic_parent); context.comments.match(builder.get(), cur); detail::visit_children(cur, [&](const CXCursor& child) { try @@ -82,7 +93,7 @@ std::unique_ptr detail::parse_cpp_enum(const detail::parse_context& } }); if (clang_isCursorDefinition(cur)) - return builder.finish(*context.idx, get_entity_id(cur)); + return builder.finish(*context.idx, get_entity_id(cur), std::move(semantic_parent)); else return builder.finish_declaration(*context.idx, get_entity_id(cur)); } diff --git a/src/libclang/friend_parser.cpp b/src/libclang/friend_parser.cpp index f1ccf32..14830e8 100644 --- a/src/libclang/friend_parser.cpp +++ b/src/libclang/friend_parser.cpp @@ -75,9 +75,12 @@ std::unique_ptr detail::parse_cpp_friend(const detail::parse_context else if (clang_isDeclaration(kind)) { entity = parse_entity(context, child); - // steal comment - comment = type_safe::copy(entity->comment()).value_or(""); - entity->set_comment(type_safe::nullopt); + if (entity) + { + // steal comment + comment = type_safe::copy(entity->comment()).value_or(""); + entity->set_comment(type_safe::nullopt); + } } else if (inst_builder && clang_isExpression(kind)) { diff --git a/src/libclang/function_parser.cpp b/src/libclang/function_parser.cpp index 836c3c9..73b1518 100644 --- a/src/libclang/function_parser.cpp +++ b/src/libclang/function_parser.cpp @@ -86,10 +86,10 @@ namespace // just the tokens occurring in the prefix struct prefix_info { - std::string scope_name; - bool is_constexpr = false; - bool is_virtual = false; - bool is_explicit = false; + type_safe::optional semantic_parent; + bool is_constexpr = false; + bool is_virtual = false; + bool is_explicit = false; }; bool prefix_end(detail::token_stream& stream, const char* name, bool is_ctor) @@ -153,38 +153,18 @@ namespace result.is_explicit = true; scope.clear(); } - // add identifiers and "::" to current scope name, - // clear if there is any other token in between, or mismatched combination - else if (stream.peek().kind() == CXToken_Identifier) - { - if (!scope.empty() && scope.back() != ':') - scope.clear(); - scope += stream.get().c_str(); - } - else if (stream.peek() == "::") - { - if (!scope.empty() && scope.back() == ':') - scope.clear(); - scope += stream.get().c_str(); - } - else if (stream.peek() == "<") - { - auto iter = detail::find_closing_bracket(stream); - scope += detail::to_string(stream, iter); - if (!detail::skip_if(stream, ">>")) - detail::skip(stream, ">"); - scope += ">"; - } - else - { + else if (!detail::append_scope(stream, scope)) stream.bump(); - scope.clear(); - } } DEBUG_ASSERT(!stream.done(), detail::parse_error_handler{}, stream.cursor(), "unable to find end of function prefix"); if (!scope.empty() && scope.back() == ':') - result.scope_name = std::move(scope); + { + result.semantic_parent = + cpp_entity_ref(detail::get_entity_id( + clang_getCursorSemanticParent(stream.cursor())), + std::move(scope)); + } return result; } @@ -392,7 +372,7 @@ namespace DEBUG_ASSERT(!prefix.is_virtual && !prefix.is_explicit, detail::parse_error_handler{}, cur, "free function cannot be virtual or explicit"); - cpp_function::builder builder(prefix.scope_name + name.c_str(), + cpp_function::builder builder(name.c_str(), detail::parse_type(context, cur, clang_getCursorResultType(cur))); context.comments.match(builder.get(), cur); @@ -413,9 +393,11 @@ namespace builder.noexcept_condition(std::move(suffix.noexcept_condition)); if (is_templated_cursor(cur)) - return builder.finish(detail::get_entity_id(cur), suffix.body_kind); + return builder.finish(detail::get_entity_id(cur), suffix.body_kind, + std::move(prefix.semantic_parent)); else - return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind); + return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind, + std::move(prefix.semantic_parent)); } } @@ -425,6 +407,7 @@ std::unique_ptr detail::parse_cpp_function(const detail::parse_conte 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); } @@ -510,7 +493,8 @@ namespace template std::unique_ptr handle_suffix(const detail::parse_context& context, const CXCursor& cur, Builder& builder, - detail::token_stream& stream, bool is_virtual) + detail::token_stream& stream, bool is_virtual, + type_safe::optional semantic_parent) { auto allow_qualifiers = set_qualifier(0, builder, cpp_cv_none, cpp_ref_none); @@ -522,9 +506,11 @@ namespace builder.virtual_info(virt.value()); if (is_templated_cursor(cur)) - return builder.finish(detail::get_entity_id(cur), suffix.body_kind); + return builder.finish(detail::get_entity_id(cur), suffix.body_kind, + std::move(semantic_parent)); else - return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind); + return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind, + std::move(semantic_parent)); } } @@ -543,7 +529,7 @@ std::unique_ptr detail::parse_cpp_member_function(const detail::pars DEBUG_ASSERT(!prefix.is_explicit, detail::parse_error_handler{}, cur, "member function cannot be explicit"); - cpp_member_function::builder builder(prefix.scope_name + name.c_str(), + cpp_member_function::builder builder(name.c_str(), detail::parse_type(context, cur, clang_getCursorResultType(cur))); context.comments.match(builder.get(), cur); @@ -555,7 +541,8 @@ std::unique_ptr detail::parse_cpp_member_function(const detail::pars builder.is_constexpr(); skip_parameters(stream); - return handle_suffix(context, cur, builder, stream, prefix.is_virtual); + return handle_suffix(context, cur, builder, stream, prefix.is_virtual, + std::move(prefix.semantic_parent)); } std::unique_ptr detail::parse_cpp_conversion_op(const detail::parse_context& context, @@ -604,7 +591,7 @@ std::unique_ptr detail::parse_cpp_conversion_op(const detail::parse_ detail::skip(stream, ")"); auto type = clang_getCursorResultType(cur); - cpp_conversion_op::builder builder(prefix.scope_name + "operator " + type_spelling, + cpp_conversion_op::builder builder("operator " + type_spelling, detail::parse_type(context, cur, type)); context.comments.match(builder.get(), cur); if (prefix.is_explicit) @@ -612,7 +599,8 @@ std::unique_ptr detail::parse_cpp_conversion_op(const detail::parse_ else if (prefix.is_constexpr) builder.is_constexpr(); - return handle_suffix(context, cur, builder, stream, prefix.is_virtual); + return handle_suffix(context, cur, builder, stream, prefix.is_virtual, + std::move(prefix.semantic_parent)); } std::unique_ptr detail::parse_cpp_constructor(const detail::parse_context& context, @@ -633,7 +621,7 @@ std::unique_ptr detail::parse_cpp_constructor(const detail::parse_co DEBUG_ASSERT(!prefix.is_virtual, detail::parse_error_handler{}, cur, "constructor cannot be virtual"); - cpp_constructor::builder builder(prefix.scope_name + name.c_str()); + cpp_constructor::builder builder(name.c_str()); context.comments.match(builder.get(), cur); add_parameters(context, builder, cur); if (clang_Cursor_isVariadic(cur)) @@ -650,9 +638,11 @@ std::unique_ptr detail::parse_cpp_constructor(const detail::parse_co builder.noexcept_condition(std::move(suffix.noexcept_condition)); if (is_templated_cursor(cur)) - return builder.finish(detail::get_entity_id(cur), suffix.body_kind); + return builder.finish(detail::get_entity_id(cur), suffix.body_kind, + std::move(prefix.semantic_parent)); else - return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind); + return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind, + std::move(prefix.semantic_parent)); } std::unique_ptr detail::parse_cpp_destructor(const detail::parse_context& context, @@ -671,5 +661,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, is_virtual); + return handle_suffix(context, cur, builder, stream, is_virtual, type_safe::nullopt); } diff --git a/src/libclang/tokenizer.cpp b/src/libclang/tokenizer.cpp index fc59d3c..07ac0d0 100644 --- a/src/libclang/tokenizer.cpp +++ b/src/libclang/tokenizer.cpp @@ -389,3 +389,35 @@ std::string detail::to_string(token_stream& stream, token_iterator end) } return result; } + +bool detail::append_scope(detail::token_stream& stream, std::string& scope) +{ + // add identifiers and "::" to current scope name, + // clear if there is any other token in between, or mismatched combination + if (stream.peek().kind() == CXToken_Identifier) + { + if (!scope.empty() && scope.back() != ':') + scope.clear(); + scope += stream.get().c_str(); + } + else if (stream.peek() == "::") + { + if (!scope.empty() && scope.back() == ':') + scope.clear(); + scope += stream.get().c_str(); + } + else if (stream.peek() == "<") + { + auto iter = detail::find_closing_bracket(stream); + scope += detail::to_string(stream, iter); + if (!detail::skip_if(stream, ">>")) + detail::skip(stream, ">"); + scope += ">"; + } + else + { + scope.clear(); + return false; + } + return true; +} diff --git a/src/libclang/tokenizer.hpp b/src/libclang/tokenizer.hpp index e841a3d..5b204a8 100644 --- a/src/libclang/tokenizer.hpp +++ b/src/libclang/tokenizer.hpp @@ -191,6 +191,12 @@ namespace cppast // converts a token range to a string, adding whitespace where necessary std::string to_string(token_stream& stream, token_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(token_stream& stream, std::string& scope); } } // namespace cppast::detail diff --git a/test/cpp_class.cpp b/test/cpp_class.cpp index 1935141..93a0a0c 100644 --- a/test/cpp_class.cpp +++ b/test/cpp_class.cpp @@ -70,11 +70,14 @@ class e namespace ns { - /// struct base{ - /// }; - struct base {}; + /// struct base; + struct base; } +/// struct ns::base{ +/// }; +struct ns::base {}; + /// struct f /// :ns::base,virtual protected e{ /// }; @@ -296,5 +299,5 @@ struct g else REQUIRE(false); }); - REQUIRE(count == 11u); + REQUIRE(count == 12u); } diff --git a/test/cpp_enum.cpp b/test/cpp_enum.cpp index 8b7c96c..53c62bb 100644 --- a/test/cpp_enum.cpp +++ b/test/cpp_enum.cpp @@ -41,9 +41,17 @@ enum class b : int b_c }; -/// enum c -/// :int; -enum c : int; +namespace ns +{ + /// enum c + /// :int; + enum c : int; +} + +/// enum ns::c +/// :int{ +/// }; +enum ns::c : int {}; )"; cpp_entity_index idx; @@ -137,18 +145,21 @@ enum c : int; } else if (e.name() == "c") { - REQUIRE(e.is_declaration()); - REQUIRE(!e.is_definition()); + if (e.semantic_scope() == "ns::") + REQUIRE(e.is_definition()); + else + REQUIRE(e.is_declaration()); + REQUIRE(!e.is_scoped()); REQUIRE(e.has_explicit_type()); REQUIRE(equal_types(idx, e.underlying_type(), *cpp_builtin_type::build(cpp_int))); REQUIRE(count_children(e) == 0u); auto definition = get_definition(idx, e); - REQUIRE(!definition); + REQUIRE(definition); } else REQUIRE(false); }); - REQUIRE(count == 4u); + REQUIRE(count == 5u); } diff --git a/test/cpp_friend.cpp b/test/cpp_friend.cpp index 12381c6..e435e0b 100644 --- a/test/cpp_friend.cpp +++ b/test/cpp_friend.cpp @@ -170,20 +170,23 @@ int d() {} } else if (func.name() == "e") REQUIRE(func.is_definition()); - else if (func.name() == "b::b") + else if (func.name() == "b") { + REQUIRE(func.semantic_scope() == "b::"); REQUIRE(func.is_declaration()); REQUIRE(func.definition()); check_definition(func.definition().value(), "b::b"); } - else if (func.name() == "b::f") + else if (func.name() == "f") { + REQUIRE(func.semantic_scope() == "b::"); REQUIRE(func.is_declaration()); REQUIRE(func.definition()); check_definition(func.definition().value(), "b::f"); } - else if (func.name() == "b::operator int") + else if (func.name() == "operator int") { + REQUIRE(func.semantic_scope() == "b::"); REQUIRE(func.is_declaration()); REQUIRE(func.definition()); check_definition(func.definition().value(), "operator int"); diff --git a/test/cpp_function.cpp b/test/cpp_function.cpp index ba7a835..a08b0cb 100644 --- a/test/cpp_function.cpp +++ b/test/cpp_function.cpp @@ -198,7 +198,7 @@ void ns::l() REQUIRE(func.storage_class() == cpp_storage_class_static); } } - else if (func.name() == "k" || func.name() == "l" || func.name() == "ns::l") + else if (func.name() == "k" || func.name() == "l") { REQUIRE(equal_types(idx, func.return_type(), *cpp_builtin_type::build(cpp_void))); REQUIRE(count_children(func.parameters()) == 0u); @@ -210,9 +210,12 @@ void ns::l() if (func.name() == "k") check_body(func, cpp_function_deleted); else if (func.name() == "l") - check_body(func, cpp_function_declaration); - else if (func.name() == "ns::l") - check_body(func, cpp_function_definition); + { + if (func.semantic_scope() == "ns::") + check_body(func, cpp_function_definition); + else + check_body(func, cpp_function_declaration); + } } else REQUIRE(false); @@ -247,16 +250,16 @@ void foo::a() {} REQUIRE(count_children(func.parameters()) == 0u); REQUIRE(func.storage_class() == cpp_storage_class_static); - if (func.name() == "a" || func.name() == "foo::a") + if (func.name() == "a") { REQUIRE(equal_types(idx, func.return_type(), *cpp_builtin_type::build(cpp_void))); REQUIRE(!func.noexcept_condition()); REQUIRE(!func.is_constexpr()); - if (func.name() == "a") - REQUIRE(func.body_kind() == cpp_function_declaration); - else + if (func.semantic_scope() == "foo::") REQUIRE(func.body_kind() == cpp_function_definition); + else + REQUIRE(func.body_kind() == cpp_function_declaration); } else if (func.name() == "b") { diff --git a/test/cpp_function_template.cpp b/test/cpp_function_template.cpp index 51071db..3d3ae21 100644 --- a/test/cpp_function_template.cpp +++ b/test/cpp_function_template.cpp @@ -185,11 +185,12 @@ d::d(const int&); REQUIRE(!tfunc.arguments_exposed()); auto templ = tfunc.primary_template(); - if (tfunc.name() == "d::operator int") + if (tfunc.name() == "operator int") REQUIRE(equal_ref(idx, templ, cpp_template_ref(cpp_entity_id(""), tfunc.name()), "d::operator T")); else - REQUIRE(equal_ref(idx, templ, cpp_template_ref(cpp_entity_id(""), tfunc.name()))); + REQUIRE(equal_ref(idx, templ, cpp_template_ref(cpp_entity_id(""), tfunc.name()), + (tfunc.function().semantic_scope() + tfunc.name()).c_str())); if (tfunc.name() == "a") { @@ -197,6 +198,7 @@ d::d(const int&); REQUIRE(tfunc.function().kind() == cpp_entity_kind::function_t); auto& func = static_cast(tfunc.function()); + REQUIRE(func.semantic_scope() == ""); REQUIRE(equal_types(idx, func.return_type(), *cpp_builtin_type::build(cpp_int))); @@ -214,12 +216,13 @@ d::d(const int&); } REQUIRE(count == 1u); } - else if (tfunc.name() == "d::b") + else if (tfunc.name() == "b") { REQUIRE(tfunc.unexposed_arguments() == "0,int"); REQUIRE(tfunc.function().kind() == cpp_entity_kind::function_t); auto& func = static_cast(tfunc.function()); + REQUIRE(func.semantic_scope() == "d::"); cpp_template_instantiation_type::builder builder( cpp_template_ref(cpp_entity_id(""), "type")); @@ -234,17 +237,18 @@ d::d(const int&); } REQUIRE(count == 1u); } - else if (tfunc.name() == "d::c") + else if (tfunc.name() == "c") { REQUIRE(tfunc.unexposed_arguments() == ""); REQUIRE(tfunc.function().kind() == cpp_entity_kind::member_function_t); auto& func = static_cast(tfunc.function()); + REQUIRE(func.semantic_scope() == "d::"); REQUIRE(func.cv_qualifier() == cpp_cv_none); REQUIRE(equal_types(idx, func.return_type(), *cpp_builtin_type::build(cpp_int))); } - else if (tfunc.name() == "d::operator int") + else if (tfunc.name() == "operator int") { REQUIRE(tfunc.unexposed_arguments() == ""); @@ -254,12 +258,13 @@ d::d(const int&); REQUIRE(equal_types(idx, func.return_type(), *cpp_builtin_type::build(cpp_int))); } - else if (tfunc.name() == "d::d") + else if (tfunc.name() == "d") { REQUIRE(tfunc.unexposed_arguments() == ""); REQUIRE(tfunc.function().kind() == cpp_entity_kind::constructor_t); auto& func = static_cast(tfunc.function()); + REQUIRE(func.semantic_scope() == "d::"); auto count = 0u; for (auto& param : func.parameters()) diff --git a/test/cpp_member_function.cpp b/test/cpp_member_function.cpp index e489766..61402e7 100644 --- a/test/cpp_member_function.cpp +++ b/test/cpp_member_function.cpp @@ -12,6 +12,7 @@ TEST_CASE("cpp_member_function") { auto code = R"( // no need to test parameters/return types +template struct foo { /// void a(); @@ -39,7 +40,11 @@ struct foo void j() = delete; }; -struct bar : foo +/// void foo::a(); +template +void foo::a() {} + +struct bar : foo { /// virtual void g() override; void g(); @@ -59,11 +64,13 @@ struct bar : foo REQUIRE(!func.noexcept_condition()); if (func.name() != "g" && func.name() != "h") REQUIRE(!func.virtual_info()); - if (func.name() != "i" && func.name() != "j") + if (func.semantic_scope().empty() && func.name() != "i" && func.name() != "j") REQUIRE(func.body_kind() == cpp_function_declaration); if (func.name() == "a") { + if (func.semantic_scope() == "foo::") + REQUIRE(func.is_definition()); REQUIRE(func.cv_qualifier() == cpp_cv_none); REQUIRE(func.ref_qualifier() == cpp_ref_none); } @@ -140,7 +147,7 @@ struct bar : foo else REQUIRE(false); }); - REQUIRE(count == 12u); + REQUIRE(count == 13u); } TEST_CASE("cpp_conversion_op") @@ -248,13 +255,14 @@ foo::foo(int) {} auto file = parse(idx, "cpp_constructor.cpp", code); auto count = test_visit(*file, [&](const cpp_constructor& cont) { REQUIRE(!cont.is_variadic()); + REQUIRE(cont.name() == "foo"); - if (cont.is_definition() && count_children(cont.parameters()) == 1u) + if (cont.semantic_parent()) { if (is_template) - REQUIRE(cont.name() == "foo::foo"); + REQUIRE(cont.semantic_parent().value().name() == "foo::"); else - REQUIRE(cont.name() == "foo::foo"); + REQUIRE(cont.semantic_parent().value().name() == "foo::"); REQUIRE(!cont.noexcept_condition()); REQUIRE(!cont.is_constexpr()); } diff --git a/test/test_parser.hpp b/test/test_parser.hpp index 3d545a7..85f4f78 100644 --- a/test/test_parser.hpp +++ b/test/test_parser.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -157,7 +158,13 @@ inline std::string full_name(const cppast::cpp_entity& e) scopes = cur_scope.name() + "::" + scopes; }); - return scopes + e.name(); + if (e.kind() == cppast::cpp_entity_kind::class_t) + { + auto& c = static_cast(e); + return scopes + c.semantic_scope() + c.name(); + } + else + return scopes + e.name(); } // checks the full name/parent