]> git.lizzy.rs Git - rust.git/blobdiff - crates/ide_completion/src/completions/dot.rs
Merge #11393
[rust.git] / crates / ide_completion / src / completions / dot.rs
index fdd6e59ffe9c50030fb16faf043b4e9ddc2178b0..b8bab941706f8e4480da65b3316359c90ed3df4e 100644 (file)
@@ -1,7 +1,6 @@
 //! Completes references after dot (fields and method calls).
 
 use either::Either;
-use hir::ScopeDef;
 use rustc_hash::FxHashSet;
 
 use crate::{context::CompletionContext, patterns::ImmediateLocation, Completions};
@@ -36,24 +35,22 @@ fn complete_undotted_self(acc: &mut Completions, ctx: &CompletionContext) {
     if !ctx.is_trivial_path() || ctx.is_path_disallowed() || !ctx.expects_expression() {
         return;
     }
-    ctx.scope.process_all_names(&mut |name, def| {
-        if let ScopeDef::Local(local) = &def {
-            if local.is_self(ctx.db) {
-                let ty = local.ty(ctx.db);
-                complete_fields(ctx, &ty, |field, ty| match field {
-                    either::Either::Left(field) => {
-                        acc.add_field(ctx, Some(name.clone()), field, &ty)
-                    }
-                    either::Either::Right(tuple_idx) => {
-                        acc.add_tuple_field(ctx, Some(name.clone()), tuple_idx, &ty)
-                    }
-                });
-                complete_methods(ctx, &ty, |func| {
-                    acc.add_method(ctx, func, Some(name.clone()), None)
-                });
-            }
+    if let Some(func) = ctx.function_def.as_ref().and_then(|fn_| ctx.sema.to_def(fn_)) {
+        if let Some(self_) = func.self_param(ctx.db) {
+            let ty = self_.ty(ctx.db);
+            complete_fields(ctx, &ty, |field, ty| match field {
+                either::Either::Left(field) => {
+                    acc.add_field(ctx, Some(hir::known::SELF_PARAM), field, &ty)
+                }
+                either::Either::Right(tuple_idx) => {
+                    acc.add_tuple_field(ctx, Some(hir::known::SELF_PARAM), tuple_idx, &ty)
+                }
+            });
+            complete_methods(ctx, &ty, |func| {
+                acc.add_method(ctx, func, Some(hir::known::SELF_PARAM), None)
+            });
         }
-    });
+    }
 }
 
 fn complete_fields(
@@ -63,9 +60,6 @@ fn complete_fields(
 ) {
     for receiver in receiver.autoderef(ctx.db) {
         for (field, ty) in receiver.fields(ctx.db) {
-            if !ctx.is_visible(&field) {
-                continue;
-            }
             f(Either::Left(field), ty);
         }
         for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() {
@@ -82,16 +76,27 @@ fn complete_methods(
 ) {
     if let Some(krate) = ctx.krate {
         let mut seen_methods = FxHashSet::default();
-        let traits_in_scope = ctx.scope.traits_in_scope();
-        receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| {
-            if func.self_param(ctx.db).is_some()
-                && ctx.is_visible(&func)
-                && seen_methods.insert(func.name(ctx.db))
-            {
-                f(func);
-            }
-            None::<()>
-        });
+        let mut traits_in_scope = ctx.scope.visible_traits();
+
+        // Remove drop from the environment as calling `Drop::drop` is not allowed
+        if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() {
+            cov_mark::hit!(dot_remove_drop_trait);
+            traits_in_scope.remove(&drop_trait.into());
+        }
+
+        receiver.iterate_method_candidates(
+            ctx.db,
+            krate,
+            &traits_in_scope,
+            ctx.module,
+            None,
+            |_ty, func| {
+                if func.self_param(ctx.db).is_some() && seen_methods.insert(func.name(ctx.db)) {
+                    f(func);
+                }
+                None::<()>
+            },
+        );
     }
 }
 
@@ -99,13 +104,10 @@ fn complete_methods(
 mod tests {
     use expect_test::{expect, Expect};
 
-    use crate::{
-        tests::{check_edit, filtered_completion_list},
-        CompletionKind,
-    };
+    use crate::tests::{check_edit, completion_list_no_kw};
 
     fn check(ra_fixture: &str, expect: Expect) {
-        let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference);
+        let actual = completion_list_no_kw(ra_fixture);
         expect.assert_eq(&actual);
     }
 
@@ -166,7 +168,7 @@ fn test_no_struct_field_completion_for_method_call() {
 struct A { the_field: u32 }
 fn foo(a: A) { a.$0() }
 "#,
-            expect![[""]],
+            expect![[r#""#]],
         );
     }
 
@@ -270,6 +272,37 @@ fn foo(a: lib::A) { a.$0 }
         );
     }
 
+    #[test]
+    fn test_local_impls() {
+        check(
+            r#"
+//- /lib.rs crate:lib
+pub struct A {}
+mod m {
+    impl super::A {
+        pub fn pub_module_method(&self) {}
+    }
+    fn f() {
+        impl super::A {
+            pub fn pub_foreign_local_method(&self) {}
+        }
+    }
+}
+//- /main.rs crate:main deps:lib
+fn foo(a: lib::A) {
+    impl lib::A {
+        fn local_method(&self) {}
+    }
+    a.$0
+}
+"#,
+            expect![[r#"
+                me local_method()      fn(&self)
+                me pub_module_method() fn(&self)
+            "#]],
+        );
+    }
+
     #[test]
     fn test_doc_hidden_filtering() {
         check(
@@ -405,7 +438,7 @@ fn foo(a: A) {
    a.$0
 }
 "#,
-            expect![[""]],
+            expect![[r#""#]],
         );
     }
 
@@ -654,6 +687,7 @@ impl Foo { fn foo(&self) { $0 } }"#,
                 lc self       &Foo
                 sp Self
                 st Foo
+                bt u32
                 fd self.field i32
                 me self.foo() fn(&self)
             "#]],
@@ -667,9 +701,87 @@ impl Foo { fn foo(&mut self) { $0 } }"#,
                 lc self       &mut Foo
                 sp Self
                 st Foo
+                bt u32
                 fd self.0     i32
                 me self.foo() fn(&mut self)
             "#]],
         );
     }
+
+    #[test]
+    fn macro_completion_after_dot() {
+        check(
+            r#"
+macro_rules! m {
+    ($e:expr) => { $e };
+}
+
+struct Completable;
+
+impl Completable {
+    fn method(&self) {}
+}
+
+fn f() {
+    let c = Completable;
+    m!(c.$0);
+}
+    "#,
+            expect![[r#"
+                me method() fn(&self)
+            "#]],
+        );
+    }
+
+    #[test]
+    fn completes_method_call_when_receiver_type_has_errors_issue_10297() {
+        check(
+            r#"
+//- minicore: iterator, sized
+struct Vec<T>;
+impl<T> IntoIterator for Vec<T> {
+    type Item = ();
+    type IntoIter = ();
+    fn into_iter(self);
+}
+fn main() {
+    let x: Vec<_>;
+    x.$0;
+}
+"#,
+            expect![[r#"
+                me into_iter() (as IntoIterator) fn(self) -> <Self as IntoIterator>::IntoIter
+            "#]],
+        )
+    }
+
+    #[test]
+    fn postfix_drop_completion() {
+        cov_mark::check!(dot_remove_drop_trait);
+        cov_mark::check!(postfix_drop_completion);
+        check_edit(
+            "drop",
+            r#"
+//- minicore: drop
+struct Vec<T>(T);
+impl<T> Drop for Vec<T> {
+    fn drop(&mut self) {}
+}
+fn main() {
+    let x = Vec(0u32)
+    x.$0;
+}
+"#,
+            r"
+struct Vec<T>(T);
+impl<T> Drop for Vec<T> {
+    fn drop(&mut self) {}
+}
+fn main() {
+    let x = Vec(0u32)
+    drop($0x);
+}
+",
+        )
+    }
 }