Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-completion/src/completions/dot.rs')
| -rw-r--r-- | crates/ide-completion/src/completions/dot.rs | 132 |
1 files changed, 105 insertions, 27 deletions
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs index 8b4f315ac5..9c2e0dcf1c 100644 --- a/crates/ide-completion/src/completions/dot.rs +++ b/crates/ide-completion/src/completions/dot.rs @@ -25,9 +25,7 @@ pub(crate) fn complete_dot( _ => return, }; - let is_field_access = matches!(dot_access.kind, DotAccessKind::Field { .. }); - let is_method_access_with_parens = - matches!(dot_access.kind, DotAccessKind::Method { has_parens: true }); + let has_parens = matches!(dot_access.kind, DotAccessKind::Method); let traits_in_scope = ctx.traits_in_scope(); // Suggest .await syntax for types that implement Future trait @@ -48,7 +46,7 @@ pub(crate) fn complete_dot( DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => { DotAccessKind::Field { receiver_is_ambiguous_float_literal: false } } - it @ DotAccessKind::Method { .. } => *it, + it @ DotAccessKind::Method => *it, }; let dot_access = DotAccess { receiver: dot_access.receiver.clone(), @@ -67,8 +65,7 @@ pub(crate) fn complete_dot( acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty) }, |acc, field, ty| acc.add_tuple_field(ctx, Some(await_str.clone()), field, &ty), - is_field_access, - is_method_access_with_parens, + has_parens, ); complete_methods(ctx, &future_output, &traits_in_scope, |func| { acc.add_method(ctx, &dot_access, func, Some(await_str.clone()), None) @@ -82,8 +79,7 @@ pub(crate) fn complete_dot( receiver_ty, |acc, field, ty| acc.add_field(ctx, dot_access, None, field, &ty), |acc, field, ty| acc.add_tuple_field(ctx, None, field, &ty), - is_field_access, - is_method_access_with_parens, + has_parens, ); complete_methods(ctx, receiver_ty, &traits_in_scope, |func| { acc.add_method(ctx, dot_access, func, None, None) @@ -95,9 +91,9 @@ pub(crate) fn complete_dot( // its return type, so we instead check for `<&Self as IntoIterator>::IntoIter`. // Does <&receiver_ty as IntoIterator>::IntoIter` exist? Assume `iter` is valid let iter = receiver_ty - .strip_references() - .add_reference(hir::Mutability::Shared) - .into_iterator_iter(ctx.db) + .autoderef(ctx.db) + .map(|ty| ty.strip_references().add_reference(hir::Mutability::Shared)) + .find_map(|ty| ty.into_iterator_iter(ctx.db)) .map(|ty| (ty, SmolStr::new_static("iter()"))); // Does <receiver_ty as IntoIterator>::IntoIter` exist? let into_iter = || { @@ -112,7 +108,7 @@ pub(crate) fn complete_dot( DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => { DotAccessKind::Field { receiver_is_ambiguous_float_literal: false } } - it @ DotAccessKind::Method { .. } => *it, + it @ DotAccessKind::Method => *it, }; let dot_access = DotAccess { receiver: dot_access.receiver.clone(), @@ -173,7 +169,6 @@ pub(crate) fn complete_undotted_self( ) }, |acc, field, ty| acc.add_tuple_field(ctx, Some(SmolStr::new_static("self")), field, &ty), - true, false, ); complete_methods(ctx, &ty, &ctx.traits_in_scope(), |func| { @@ -182,7 +177,7 @@ pub(crate) fn complete_undotted_self( &DotAccess { receiver: None, receiver_ty: None, - kind: DotAccessKind::Method { has_parens: false }, + kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }, ctx: DotAccessExprCtx { in_block_expr: expr_ctx.in_block_expr, in_breakable: expr_ctx.in_breakable, @@ -201,15 +196,13 @@ fn complete_fields( receiver: &hir::Type<'_>, mut named_field: impl FnMut(&mut Completions, hir::Field, hir::Type<'_>), mut tuple_index: impl FnMut(&mut Completions, usize, hir::Type<'_>), - is_field_access: bool, - is_method_access_with_parens: bool, + has_parens: bool, ) { let mut seen_names = FxHashSet::default(); for receiver in receiver.autoderef(ctx.db) { for (field, ty) in receiver.fields(ctx.db) { if seen_names.insert(field.name(ctx.db)) - && (is_field_access - || (is_method_access_with_parens && (ty.is_fn() || ty.is_closure()))) + && (!has_parens || ty.is_fn() || ty.is_closure()) { named_field(acc, field, ty); } @@ -218,8 +211,7 @@ fn complete_fields( // Tuples are always the last type in a deref chain, so just check if the name is // already seen without inserting into the hashset. if !seen_names.contains(&hir::Name::new_tuple_field(i)) - && (is_field_access - || (is_method_access_with_parens && (ty.is_fn() || ty.is_closure()))) + && (!has_parens || ty.is_fn() || ty.is_closure()) { // Tuple fields are always public (tuple struct fields are handled above). tuple_index(acc, i, ty); @@ -278,7 +270,6 @@ fn complete_methods( ctx.db, &ctx.scope, traits_in_scope, - Some(ctx.module), None, Callback { ctx, f, seen_methods: FxHashSet::default() }, ); @@ -605,7 +596,6 @@ fn foo(a: A) { } "#, expect![[r#" - me local_method() fn(&self) me pub_module_method() fn(&self) "#]], ); @@ -794,8 +784,7 @@ struct T(S); impl T { fn foo(&self) { - // FIXME: This doesn't work without the trailing `a` as `0.` is a float - self.0.a$0 + self.0.$0 } } "#, @@ -1365,18 +1354,71 @@ fn foo() { r#" struct Foo { baz: fn() } impl Foo { - fn bar<T>(self, t: T): T { t } + fn bar<T>(self, t: T) -> T { t } } fn baz() { let foo = Foo{ baz: || {} }; - foo.ba$0::<>; + foo.ba$0; } "#, expect![[r#" - me bar(…) fn(self, T) + fd baz fn() + me bar(…) fn(self, T) -> T "#]], ); + + check_edit( + "baz", + r#" +struct Foo { baz: fn() } +impl Foo { + fn bar<T>(self, t: T) -> T { t } +} + +fn baz() { + let foo = Foo{ baz: || {} }; + foo.ba$0; +} +"#, + r#" +struct Foo { baz: fn() } +impl Foo { + fn bar<T>(self, t: T) -> T { t } +} + +fn baz() { + let foo = Foo{ baz: || {} }; + (foo.baz)(); +} +"#, + ); + + check_edit( + "bar", + r#" +struct Foo { baz: fn() } +impl Foo { + fn bar<T>(self, t: T) -> T { t } +} + +fn baz() { + let foo = Foo{ baz: || {} }; + foo.ba$0; +} +"#, + r#" +struct Foo { baz: fn() } +impl Foo { + fn bar<T>(self, t: T) -> T { t } +} + +fn baz() { + let foo = Foo{ baz: || {} }; + foo.bar(${1:t})$0; +} +"#, + ); } #[test] @@ -1424,6 +1466,40 @@ fn foo() { me into_iter().nth(…) (as Iterator) fn(&mut self, usize) -> Option<<Self as Iterator>::Item> "#]], ); + check_no_kw( + r#" +//- minicore: iterator, deref +struct Foo; +impl Foo { fn iter(&self) -> Iter { Iter } } +impl IntoIterator for &Foo { + type Item = (); + type IntoIter = Iter; + fn into_iter(self) -> Self::IntoIter { Iter } +} +struct Ref; +impl core::ops::Deref for Ref { + type Target = Foo; + fn deref(&self) -> &Self::Target { &Foo } +} +struct Iter; +impl Iterator for Iter { + type Item = (); + fn next(&mut self) -> Option<Self::Item> { None } +} +fn foo() { + Ref.$0 +} +"#, + expect![[r#" + me deref() (use core::ops::Deref) fn(&self) -> &<Self as Deref>::Target + me into_iter() (as IntoIterator) fn(self) -> <Self as IntoIterator>::IntoIter + me iter() fn(&self) -> Iter + me iter().by_ref() (as Iterator) fn(&mut self) -> &mut Self + me iter().into_iter() (as IntoIterator) fn(self) -> <Self as IntoIterator>::IntoIter + me iter().next() (as Iterator) fn(&mut self) -> Option<<Self as Iterator>::Item> + me iter().nth(…) (as Iterator) fn(&mut self, usize) -> Option<<Self as Iterator>::Item> + "#]], + ); } #[test] @@ -1482,6 +1558,8 @@ async fn bar() { check_no_kw( r#" //- minicore: receiver +#![feature(arbitrary_self_types)] + use core::ops::Receiver; struct Foo; |