about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/ide-assists/src/handlers/generate_delegate_methods.rs63
1 files changed, 55 insertions, 8 deletions
diff --git a/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/crates/ide-assists/src/handlers/generate_delegate_methods.rs
index ed1b8f4e28d..aecb3826e47 100644
--- a/crates/ide-assists/src/handlers/generate_delegate_methods.rs
+++ b/crates/ide-assists/src/handlers/generate_delegate_methods.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use hir::{self, HasCrate, HasSource, HasVisibility};
 use syntax::ast::{self, make, AstNode, HasGenericParams, HasName, HasVisibility as _};
 
@@ -63,16 +65,23 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
     };
 
     let sema_field_ty = ctx.sema.resolve_type(&field_ty)?;
-    let krate = sema_field_ty.krate(ctx.db());
     let mut methods = vec![];
-    sema_field_ty.iterate_assoc_items(ctx.db(), krate, |item| {
-        if let hir::AssocItem::Function(f) = item {
-            if f.self_param(ctx.db()).is_some() && f.is_visible_from(ctx.db(), current_module) {
-                methods.push(f)
+    let mut seen_names = HashSet::new();
+
+    for ty in sema_field_ty.autoderef(ctx.db()) {
+        let krate = ty.krate(ctx.db());
+        ty.iterate_assoc_items(ctx.db(), krate, |item| {
+            if let hir::AssocItem::Function(f) = item {
+                if f.self_param(ctx.db()).is_some()
+                    && f.is_visible_from(ctx.db(), current_module)
+                    && seen_names.insert(f.name(ctx.db()))
+                {
+                    methods.push(f)
+                }
             }
-        }
-        Option::<()>::None
-    });
+            Option::<()>::None
+        });
+    }
 
     for method in methods {
         let adt = ast::Adt::Struct(strukt.clone());
@@ -315,6 +324,44 @@ impl<T> Person<T> {
     }
 
     #[test]
+    fn test_generates_delegate_autoderef() {
+        check_assist(
+            generate_delegate_methods,
+            r#"
+//- minicore: deref
+struct Age(u8);
+impl Age {
+    fn age(&self) -> u8 {
+        self.0
+    }
+}
+struct AgeDeref(Age);
+impl core::ops::Deref for AgeDeref { type Target = Age; }
+struct Person {
+    ag$0e: AgeDeref,
+}
+impl Person {}"#,
+            r#"
+struct Age(u8);
+impl Age {
+    fn age(&self) -> u8 {
+        self.0
+    }
+}
+struct AgeDeref(Age);
+impl core::ops::Deref for AgeDeref { type Target = Age; }
+struct Person {
+    age: AgeDeref,
+}
+impl Person {
+    $0fn age(&self) -> u8 {
+        self.age.age()
+    }
+}"#,
+        );
+    }
+
+    #[test]
     fn test_generate_delegate_visibility() {
         check_assist_not_applicable(
             generate_delegate_methods,