Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-completion/src/context/analysis.rs')
| -rw-r--r-- | crates/ide-completion/src/context/analysis.rs | 51 |
1 files changed, 39 insertions, 12 deletions
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index dfceb67f20..87380067e8 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -720,12 +720,14 @@ fn classify_name_ref( }; let generic_arg_location = |arg: ast::GenericArg| { + let mut override_location = None; let location = find_opt_node_in_file_compensated( sema, original_file, arg.syntax().parent().and_then(ast::GenericArgList::cast), ) .map(|args| { + let mut in_trait = None; let param = (|| { let parent = args.syntax().parent()?; let params = match_ast! { @@ -743,7 +745,31 @@ fn classify_name_ref( variant.parent_enum(sema.db).source(sema.db)?.value.generic_param_list() } hir::ModuleDef::Trait(trait_) => { - trait_.source(sema.db)?.value.generic_param_list() + if let ast::GenericArg::AssocTypeArg(arg) = &arg { + let arg_name = arg.name_ref()?; + let arg_name = arg_name.text(); + for item in trait_.items_with_supertraits(sema.db) { + match item { + hir::AssocItem::TypeAlias(assoc_ty) => { + if assoc_ty.name(sema.db).as_str()? == arg_name { + override_location = Some(TypeLocation::AssocTypeEq); + return None; + } + }, + hir::AssocItem::Const(const_) => { + if const_.name(sema.db)?.as_str()? == arg_name { + override_location = Some(TypeLocation::AssocConstEq); + return None; + } + }, + _ => (), + } + } + return None; + } else { + in_trait = Some(trait_); + trait_.source(sema.db)?.value.generic_param_list() + } } hir::ModuleDef::TraitAlias(trait_) => { trait_.source(sema.db)?.value.generic_param_list() @@ -765,10 +791,12 @@ fn classify_name_ref( match sema.resolve_path(&trait_.parent_path().top_path())? { hir::PathResolution::Def(def) => match def { hir::ModuleDef::Trait(trait_) => { - let trait_items = trait_.items(sema.db); + let arg_name = arg.name_ref()?; + let arg_name = arg_name.text(); + let trait_items = trait_.items_with_supertraits(sema.db); let assoc_ty = trait_items.iter().find_map(|item| match item { hir::AssocItem::TypeAlias(assoc_ty) => { - (assoc_ty.name(sema.db).as_str()? == arg.name_ref()?.text()) + (assoc_ty.name(sema.db).as_str()? == arg_name) .then_some(assoc_ty) }, _ => None, @@ -784,11 +812,10 @@ fn classify_name_ref( } }?; // Determine the index of the argument in the `GenericArgList` and match it with - // the corresponding parameter in the `GenericParamList`. - // Since lifetime parameters are often omitted, ignore them for the purposes of - // matching the argument with its parameter unless a lifetime argument is provided - // explicitly. That is, for `struct S<'a, 'b, T>`, match `S::<$0>` to to `T` and - // `S::<'a, $0, _>` to `'b`. + // the corresponding parameter in the `GenericParamList`. Since lifetime parameters + // are often omitted, ignore them for the purposes of matching the argument with + // its parameter unless a lifetime argument is provided explicitly. That is, for + // `struct S<'a, 'b, T>`, match `S::<$0>` to `T` and `S::<'a, $0, _>` to `'b`. let mut explicit_lifetime_arg = false; let arg_idx = arg .syntax() @@ -806,9 +833,9 @@ fn classify_name_ref( }; params.generic_params().nth(param_idx) })(); - (args, param) + (args, in_trait, param) }); - TypeLocation::GenericArgList(location) + override_location.unwrap_or(TypeLocation::GenericArg(location)) }; let type_location = |node: &SyntaxNode| { @@ -870,8 +897,8 @@ fn classify_name_ref( // is this case needed? ast::GenericArgList(it) => { let location = find_opt_node_in_file_compensated(sema, original_file, Some(it)) - .map(|node| (node, None)); - TypeLocation::GenericArgList(location) + .map(|node| (node, None, None)); + TypeLocation::GenericArg(location) }, ast::TupleField(_) => TypeLocation::TupleField, _ => return None, |