]> git.lizzy.rs Git - rust.git/commitdiff
Make search for applicable generics more precise
authorDorian Scheidt <dorian.scheidt@gmail.com>
Wed, 13 Jul 2022 15:20:55 +0000 (10:20 -0500)
committerDorian Scheidt <dorian.scheidt@gmail.com>
Wed, 13 Jul 2022 19:54:17 +0000 (14:54 -0500)
crates/ide-assists/src/handlers/extract_function.rs

index aa1c3a548c97040dbbf12181ec7f82a56bf73eda..94b638d4c600ec10cc8c6608c2ef68e9b9f16438 100644 (file)
@@ -823,8 +823,9 @@ fn analyze_container(&self, sema: &Semantics<RootDatabase>) -> Option<ContainerI
             });
 
         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 @@ fn has_usages_after_body(&self, usages: &LocalUsages) -> bool {
     }
 }
 
-fn parent_where_clauses(parent: &SyntaxNode) -> Vec<ast::WhereClause> {
-    let mut where_clause: Vec<ast::WhereClause> = 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<ast::GenericParamList> {
-    let mut generic_param_list: Vec<ast::GenericParamList> = 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<ast::GenericParamList> {
+        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<ast::WhereClause> {
+        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<GenericParent> {
+    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