diff --git a/src/libclang/type_parser.cpp b/src/libclang/type_parser.cpp index 5de1d98..3cbf86f 100644 --- a/src/libclang/type_parser.cpp +++ b/src/libclang/type_parser.cpp @@ -392,32 +392,38 @@ namespace const std::string& templ_name) { // look if the type has a declaration that is a template - auto decl = clang_getTypeDeclaration(type); - if (is_direct_templated(decl)) + auto decl = clang_getTypeDeclaration(type); + auto count = clang_Type_getNumTemplateArguments(clang_getCursorType(decl)); + if (count > 0 || is_direct_templated(decl)) return decl; - - // look if the templ_name matches a template template parameter - auto param = clang_getNullCursor(); - detail::visit_children(cur, [&](const CXCursor& child) { - if (clang_getCursorKind(child) == CXCursor_TemplateTemplateParameter - && detail::get_cursor_name(child) == templ_name.c_str()) - { - DEBUG_ASSERT(clang_Cursor_isNull(param), detail::parse_error_handler{}, cur, - "multiple template template parameters with the same name?!"); - param = child; - } - }); - return param; + else + { + // look if the templ_name matches a template template parameter + auto param = clang_getNullCursor(); + detail::visit_children(cur, [&](const CXCursor& child) { + if (clang_getCursorKind(child) == CXCursor_TemplateTemplateParameter + && detail::get_cursor_name(child) == templ_name.c_str()) + { + DEBUG_ASSERT(clang_Cursor_isNull(param), detail::parse_error_handler{}, cur, + "multiple template template parameters with the same name?!"); + param = child; + } + }); + return param; + } } std::unique_ptr try_parse_instantiation_type(const detail::parse_context&, const CXCursor& cur, const CXType& type) { return make_leave_type(type, [&](std::string&& spelling) -> std::unique_ptr { - auto ptr = spelling.c_str(); + auto ptr = spelling.c_str(); + std::string templ_name; for (; *ptr && *ptr != '<'; ++ptr) templ_name += *ptr; + if (*ptr != '<') + return nullptr; ++ptr; auto templ = get_instantiation_template(cur, type, templ_name); @@ -429,7 +435,8 @@ namespace // parse arguments // i.e. not parse really, just add the string - DEBUG_ASSERT(!spelling.empty() && spelling.back() == '>', detail::assert_handler{}); + if (spelling.empty() || spelling.back() != '>') + return nullptr; spelling.pop_back(); builder.add_unexposed_arguments(ptr); diff --git a/test/cpp_member_function.cpp b/test/cpp_member_function.cpp index 24687e3..f44b506 100644 --- a/test/cpp_member_function.cpp +++ b/test/cpp_member_function.cpp @@ -157,18 +157,36 @@ TEST_CASE("cpp_conversion_op") namespace ns { template - using type = char; + struct type {}; } // most of it only need to be check in member function struct foo { /// operator int&(); - operator int&(); + operator int&() + { + static int i; + return i; + } + /// explicit operator bool()const; - explicit operator bool() const; + explicit operator bool() const + { + return false; + } + /// constexpr operator ns::type(); - constexpr operator ns::type(); + constexpr operator ns::type() + { + return {}; + } + + /// constexpr operator ns::type(); + constexpr operator ns::type() + { + return {}; + } }; )"; @@ -177,7 +195,7 @@ struct foo auto count = test_visit(*file, [&](const cpp_conversion_op& op) { REQUIRE(count_children(op.parameters()) == 0u); REQUIRE(!op.is_variadic()); - REQUIRE(op.body_kind() == cpp_function_declaration); + REQUIRE(op.body_kind() == cpp_function_definition); REQUIRE(op.ref_qualifier() == cpp_ref_none); REQUIRE(!op.virtual_info()); REQUIRE(!op.noexcept_condition()); @@ -198,17 +216,32 @@ struct foo } else if (!op.is_explicit() && op.is_constexpr()) { - REQUIRE(op.name() == "operator ns::type"); - cpp_template_instantiation_type::builder builder( - cpp_template_ref(cpp_entity_id(""), "ns::type")); - builder.add_unexposed_arguments("int"); - REQUIRE(equal_types(idx, op.return_type(), *builder.finish())); REQUIRE(op.cv_qualifier() == cpp_cv_none); + if (op.name() == "operator ns::type") + { + REQUIRE(op.return_type().kind() == cpp_type_kind::template_instantiation_t); + auto& inst = static_cast(op.return_type()); + + REQUIRE(inst.primary_template().name() == "ns::type"); + REQUIRE(!inst.arguments_exposed()); + REQUIRE(inst.unexposed_arguments() == "int"); + } + else if (op.name() == "operator ns::type") + { + REQUIRE(op.return_type().kind() == cpp_type_kind::template_instantiation_t); + auto& inst = static_cast(op.return_type()); + + REQUIRE(inst.primary_template().name() == "ns::type"); + REQUIRE(!inst.arguments_exposed()); + REQUIRE(inst.unexposed_arguments() == "char"); + } + else + REQUIRE(false); } else REQUIRE(false); }); - REQUIRE(count == 3u); + REQUIRE(count == 4u); } TEST_CASE("cpp_constructor")