]> git.lizzy.rs Git - rust.git/commitdiff
Move unprefixed field/method completion to `dot`
authorLukas Wirth <lukastw97@gmail.com>
Fri, 28 May 2021 13:09:10 +0000 (15:09 +0200)
committerLukas Wirth <lukastw97@gmail.com>
Mon, 31 May 2021 13:10:20 +0000 (15:10 +0200)
crates/ide_completion/src/completions.rs
crates/ide_completion/src/completions/dot.rs
crates/ide_completion/src/completions/unqualified_path.rs

index dd92bc51097e49c64be952d6169514577633aa79..ffdcdc930a943973cef3521950eb1db8ad5c80fc 100644 (file)
 
 use std::iter;
 
-use either::Either;
-use hir::{known, HasVisibility};
+use hir::known;
 use ide_db::SymbolKind;
-use rustc_hash::FxHashSet;
 
 use crate::{
     item::{Builder, CompletionKind},
@@ -254,44 +252,3 @@ fn complete_enum_variants(
         }
     }
 }
-
-fn complete_fields(
-    ctx: &CompletionContext,
-    receiver: &hir::Type,
-    mut f: impl FnMut(Either<hir::Field, usize>, hir::Type),
-) {
-    for receiver in receiver.autoderef(ctx.db) {
-        for (field, ty) in receiver.fields(ctx.db) {
-            if ctx.scope.module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) {
-                // Skip private field. FIXME: If the definition location of the
-                // field is editable, we should show the completion
-                continue;
-            }
-            f(Either::Left(field), ty);
-        }
-        for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() {
-            // FIXME: Handle visibility
-            f(Either::Right(i), ty);
-        }
-    }
-}
-
-fn complete_methods(
-    ctx: &CompletionContext,
-    receiver: &hir::Type,
-    mut f: impl FnMut(hir::Function),
-) {
-    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.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m))
-                && seen_methods.insert(func.name(ctx.db))
-            {
-                f(func);
-            }
-            None::<()>
-        });
-    }
-}
index 93f7bd6d4e3e6f8398363836b83d5da12b32d9fc..886251639e74e02a90b9fa31fbc1eadd0aceb5ee 100644 (file)
@@ -1,6 +1,8 @@
 //! Completes references after dot (fields and method calls).
 
 use either::Either;
+use hir::{HasVisibility, ScopeDef};
+use rustc_hash::FxHashSet;
 
 use crate::{context::CompletionContext, Completions};
 
@@ -8,7 +10,7 @@
 pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
     let dot_receiver = match &ctx.dot_receiver {
         Some(expr) => expr,
-        _ => return,
+        _ => return complete_undotted_self(acc, ctx),
     };
 
     let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) {
@@ -19,12 +21,77 @@ pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
     if ctx.is_call {
         cov_mark::hit!(test_no_struct_field_completion_for_method_call);
     } else {
-        super::complete_fields(ctx, &receiver_ty, |field, ty| match field {
+        complete_fields(ctx, &receiver_ty, |field, ty| match field {
             Either::Left(field) => acc.add_field(ctx, None, field, &ty),
             Either::Right(tuple_idx) => acc.add_tuple_field(ctx, None, tuple_idx, &ty),
         });
     }
-    super::complete_methods(ctx, &receiver_ty, |func| acc.add_method(ctx, func, None, None));
+    complete_methods(ctx, &receiver_ty, |func| acc.add_method(ctx, func, None, None));
+}
+
+fn complete_undotted_self(acc: &mut Completions, ctx: &CompletionContext) {
+    if !ctx.is_trivial_path {
+        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)
+                });
+            }
+        }
+    });
+}
+
+fn complete_fields(
+    ctx: &CompletionContext,
+    receiver: &hir::Type,
+    mut f: impl FnMut(Either<hir::Field, usize>, hir::Type),
+) {
+    for receiver in receiver.autoderef(ctx.db) {
+        for (field, ty) in receiver.fields(ctx.db) {
+            if ctx.scope.module().map_or(false, |m| !field.is_visible_from(ctx.db, m)) {
+                // Skip private field. FIXME: If the definition location of the
+                // field is editable, we should show the completion
+                continue;
+            }
+            f(Either::Left(field), ty);
+        }
+        for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() {
+            // FIXME: Handle visibility
+            f(Either::Right(i), ty);
+        }
+    }
+}
+
+fn complete_methods(
+    ctx: &CompletionContext,
+    receiver: &hir::Type,
+    mut f: impl FnMut(hir::Function),
+) {
+    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.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m))
+                && seen_methods.insert(func.name(ctx.db))
+            {
+                f(func);
+            }
+            None::<()>
+        });
+    }
 }
 
 #[cfg(test)]
@@ -453,4 +520,34 @@ fn f(&mut self, v: Foo) {
             "#]],
         );
     }
+
+    #[test]
+    fn completes_bare_fields_and_methods_in_methods() {
+        check(
+            r#"
+struct Foo { field: i32 }
+
+impl Foo { fn foo(&self) { $0 } }"#,
+            expect![[r#"
+                lc self       &Foo
+                sp Self
+                st Foo
+                fd self.field i32
+                me self.foo() fn(&self)
+            "#]],
+        );
+        check(
+            r#"
+struct Foo(i32);
+
+impl Foo { fn foo(&mut self) { $0 } }"#,
+            expect![[r#"
+                lc self       &mut Foo
+                sp Self
+                st Foo
+                fd self.0     i32
+                me self.foo() fn(&mut self)
+            "#]],
+        );
+    }
 }
index 83cb671010bd1348befa3504ca74f5268044265c..20188a7ddc600f75154e00aa62d9ece23d09bbc3 100644 (file)
@@ -47,22 +47,6 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
             cov_mark::hit!(skip_lifetime_completion);
             return;
         }
-        if let ScopeDef::Local(local) = &res {
-            if local.is_self(ctx.db) {
-                let ty = local.ty(ctx.db);
-                super::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)
-                    }
-                });
-                super::complete_methods(ctx, &ty, |func| {
-                    acc.add_method(ctx, func, Some(name.clone()), None)
-                });
-            }
-        }
         acc.add_resolution(ctx, name, &res);
     });
 }
@@ -393,36 +377,6 @@ fn completes_self_in_methods() {
         );
     }
 
-    #[test]
-    fn completes_qualified_fields_and_methods_in_methods() {
-        check(
-            r#"
-struct Foo { field: i32 }
-
-impl Foo { fn foo(&self) { $0 } }"#,
-            expect![[r#"
-                fd self.field i32
-                me self.foo() fn(&self)
-                lc self       &Foo
-                sp Self
-                st Foo
-            "#]],
-        );
-        check(
-            r#"
-struct Foo(i32);
-
-impl Foo { fn foo(&mut self) { $0 } }"#,
-            expect![[r#"
-                fd self.0     i32
-                me self.foo() fn(&mut self)
-                lc self       &mut Foo
-                sp Self
-                st Foo
-            "#]],
-        );
-    }
-
     #[test]
     fn completes_prelude() {
         check(