diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index aa1c3a548c..94b638d4c6 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -823,8 +823,9 @@ impl FunctionBody { }); let parent = self.parent()?; - let generic_param_lists = parent_generic_param_lists(&parent); - let where_clauses = parent_where_clauses(&parent); + let parents = generic_parents(&parent); + let generic_param_lists = parents.iter().filter_map(|it| it.generic_param_list()).collect(); + let where_clauses = parents.iter().filter_map(|it| it.where_clause()).collect(); Some(ContainerInfo { is_in_tail, @@ -990,24 +991,54 @@ impl FunctionBody { } } -fn parent_where_clauses(parent: &SyntaxNode) -> Vec { - let mut where_clause: Vec = parent - .ancestors() - .filter_map(ast::AnyHasGenericParams::cast) - .filter_map(|it| it.where_clause()) - .collect(); - where_clause.reverse(); - where_clause +enum GenericParent { + Fn(ast::Fn), + Impl(ast::Impl), + Trait(ast::Trait), } -fn parent_generic_param_lists(parent: &SyntaxNode) -> Vec { - let mut generic_param_list: Vec = parent - .ancestors() - .filter_map(ast::AnyHasGenericParams::cast) - .filter_map(|it| it.generic_param_list()) - .collect(); - generic_param_list.reverse(); - generic_param_list +impl GenericParent { + fn generic_param_list(&self) -> Option { + match self { + GenericParent::Fn(fn_) => fn_.generic_param_list(), + GenericParent::Impl(impl_) => impl_.generic_param_list(), + GenericParent::Trait(trait_) => trait_.generic_param_list(), + } + } + + fn where_clause(&self) -> Option { + match self { + GenericParent::Fn(fn_) => fn_.where_clause(), + GenericParent::Impl(impl_) => impl_.where_clause(), + GenericParent::Trait(trait_) => trait_.where_clause(), + } + } +} + +/// Search `parent`'s ancestors for items with potentially applicable generic parameters +fn generic_parents(parent: &SyntaxNode) -> Vec { + let mut list = Vec::new(); + if let Some(parent_item) = parent.ancestors().find_map(ast::Item::cast) { + match parent_item { + ast::Item::Fn(ref fn_) => { + if let Some(parent_parent) = parent_item + .syntax() + .parent() + .and_then(|it| it.parent()) + .and_then(ast::Item::cast) + { + match parent_parent { + ast::Item::Impl(impl_) => list.push(GenericParent::Impl(impl_)), + ast::Item::Trait(trait_) => list.push(GenericParent::Trait(trait_)), + _ => (), + } + } + list.push(GenericParent::Fn(fn_.clone())); + } + _ => (), + } + } + list } /// checks if relevant var is used with `&mut` access inside body