about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs49
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs61
2 files changed, 102 insertions, 8 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
index 11201afb8a7..7e03eb30304 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
@@ -2421,4 +2421,53 @@ impl other_file_2::Trait for MyStruct {
 }"#,
         );
     }
+
+    #[test]
+    fn test_qualify_ident_pat_in_default_members() {
+        check_assist(
+            add_missing_default_members,
+            r#"
+//- /lib.rs crate:b new_source_root:library
+pub enum State {
+    Active,
+    Inactive,
+}
+
+use State::*;
+
+pub trait Checker {
+    fn check(&self) -> State;
+
+    fn is_active(&self) -> bool {
+        match self.check() {
+            Active => true,
+            Inactive => false,
+        }
+    }
+}
+//- /main.rs crate:a deps:b
+struct MyChecker;
+
+impl b::Checker for MyChecker {
+    fn check(&self) -> b::State {
+        todo!();
+    }$0
+}"#,
+            r#"
+struct MyChecker;
+
+impl b::Checker for MyChecker {
+    fn check(&self) -> b::State {
+        todo!();
+    }
+
+    $0fn is_active(&self) -> bool {
+        match self.check() {
+            b::State::Active => true,
+            b::State::Inactive => false,
+        }
+    }
+}"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
index 5d88afec509..a76a0551dd8 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
@@ -11,7 +11,7 @@ use rustc_hash::FxHashMap;
 use span::Edition;
 use syntax::{
     NodeOrToken, SyntaxNode,
-    ast::{self, AstNode, HasGenericArgs, make},
+    ast::{self, AstNode, HasGenericArgs, HasName, make},
     syntax_editor::{self, SyntaxEditor},
 };
 
@@ -315,32 +315,49 @@ impl Ctx<'_> {
     }
 
     fn transform_path(&self, path: &SyntaxNode) -> SyntaxNode {
-        fn find_child_paths(root_path: &SyntaxNode) -> Vec<ast::Path> {
-            let mut result = Vec::new();
+        fn find_child_paths_and_ident_pats(
+            root_path: &SyntaxNode,
+        ) -> Vec<Either<ast::Path, ast::IdentPat>> {
+            let mut result: Vec<Either<ast::Path, ast::IdentPat>> = Vec::new();
             for child in root_path.children() {
                 if let Some(child_path) = ast::Path::cast(child.clone()) {
-                    result.push(child_path);
+                    result.push(either::Left(child_path));
+                } else if let Some(child_ident_pat) = ast::IdentPat::cast(child.clone()) {
+                    result.push(either::Right(child_ident_pat));
                 } else {
-                    result.extend(find_child_paths(&child));
+                    result.extend(find_child_paths_and_ident_pats(&child));
                 }
             }
             result
         }
+
         let root_path = path.clone_subtree();
-        let result = find_child_paths(&root_path);
+
+        let result = find_child_paths_and_ident_pats(&root_path);
         let mut editor = SyntaxEditor::new(root_path.clone());
         for sub_path in result {
             let new = self.transform_path(sub_path.syntax());
             editor.replace(sub_path.syntax(), new);
         }
+
         let update_sub_item = editor.finish().new_root().clone().clone_subtree();
-        let item = find_child_paths(&update_sub_item);
+        let item = find_child_paths_and_ident_pats(&update_sub_item);
         let mut editor = SyntaxEditor::new(update_sub_item);
         for sub_path in item {
-            self.transform_path_(&mut editor, &sub_path);
+            self.transform_path_or_ident_pat(&mut editor, &sub_path);
         }
         editor.finish().new_root().clone()
     }
+    fn transform_path_or_ident_pat(
+        &self,
+        editor: &mut SyntaxEditor,
+        item: &Either<ast::Path, ast::IdentPat>,
+    ) -> Option<()> {
+        match item {
+            Either::Left(path) => self.transform_path_(editor, path),
+            Either::Right(ident_pat) => self.transform_ident_pat(editor, ident_pat),
+        }
+    }
 
     fn transform_path_(&self, editor: &mut SyntaxEditor, path: &ast::Path) -> Option<()> {
         if path.qualifier().is_some() {
@@ -515,6 +532,34 @@ impl Ctx<'_> {
         }
         Some(())
     }
+
+    fn transform_ident_pat(
+        &self,
+        editor: &mut SyntaxEditor,
+        ident_pat: &ast::IdentPat,
+    ) -> Option<()> {
+        let name = ident_pat.name()?;
+
+        let temp_path = make::path_from_text(&name.text());
+
+        let resolution = self.source_scope.speculative_resolve(&temp_path)?;
+
+        match resolution {
+            hir::PathResolution::Def(def) if def.as_assoc_item(self.source_scope.db).is_none() => {
+                let cfg = ImportPathConfig {
+                    prefer_no_std: false,
+                    prefer_prelude: true,
+                    prefer_absolute: false,
+                    allow_unstable: true,
+                };
+                let found_path = self.target_module.find_path(self.source_scope.db, def, cfg)?;
+                let res = mod_path_to_ast(&found_path, self.target_edition).clone_for_update();
+                editor.replace(ident_pat.syntax(), res.syntax());
+                Some(())
+            }
+            _ => None,
+        }
+    }
 }
 
 // FIXME: It would probably be nicer if we could get this via HIR (i.e. get the