diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index cdac4e41a9d8..6d572a836163 100644 --- a/crates/ide_completion/src/completions.rs +++ b/crates/ide_completion/src/completions.rs @@ -26,7 +26,7 @@ render::{ const_::render_const, enum_variant::render_variant, - function::render_fn, + function::{render_fn, render_method}, macro_::render_macro, pattern::{render_struct_pat, render_variant_pat}, render_field, render_resolution, render_tuple_field, @@ -123,6 +123,17 @@ pub(crate) fn add_function( } } + pub(crate) fn add_method( + &mut self, + ctx: &CompletionContext, + func: hir::Function, + local_name: Option, + ) { + if let Some(item) = render_method(RenderContext::new(ctx), None, local_name, func) { + self.add(item) + } + } + pub(crate) fn add_variant_pat( &mut self, ctx: &CompletionContext, diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs index cec2d0c3a37e..7e4efe589814 100644 --- a/crates/ide_completion/src/completions/dot.rs +++ b/crates/ide_completion/src/completions/dot.rs @@ -51,7 +51,7 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T && ctx.scope.module().map_or(true, |m| func.is_visible_from(ctx.db, m)) && seen_methods.insert(func.name(ctx.db)) { - acc.add_function(ctx, func, None); + acc.add_method(ctx, func, None); } None::<()> }); diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index 23e00aa471a3..9ce49074f9d1 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs @@ -148,8 +148,10 @@ fn add_field(&mut self, field: hir::Field, ty: &Type) -> CompletionItem { ..CompletionRelevance::default() }); - if let Some(ref_match) = compute_ref_match(self.ctx.completion, ty) { - item.ref_match(ref_match); + if let Some(_ref_match) = compute_ref_match(self.ctx.completion, ty) { + // FIXME + // For now we don't properly calculate the edits for ref match + // completions on struct fields, so we've disabled them. See #8058. } item.build() @@ -1313,4 +1315,42 @@ fn main() [] "#]], ) } + + #[test] + fn struct_field_method_ref() { + check( + r#" +struct Foo { bar: u32 } +impl Foo { fn baz(&self) -> u32 { 0 } } + +fn foo(f: Foo) { let _: &u32 = f.b$0 } +"#, + // FIXME + // Ideally we'd also suggest &f.bar and &f.baz() as exact + // type matches. See #8058. + expect![[r#" + [ + CompletionItem { + label: "bar", + source_range: 98..99, + delete: 98..99, + insert: "bar", + kind: SymbolKind( + Field, + ), + detail: "u32", + }, + CompletionItem { + label: "baz()", + source_range: 98..99, + delete: 98..99, + insert: "baz()$0", + kind: Method, + lookup: "baz", + detail: "fn(&self) -> u32", + }, + ] + "#]], + ); + } } diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs index 010303182903..b1eba20e8260 100644 --- a/crates/ide_completion/src/render/function.rs +++ b/crates/ide_completion/src/render/function.rs @@ -20,7 +20,17 @@ pub(crate) fn render_fn<'a>( fn_: hir::Function, ) -> Option { let _p = profile::span("render_fn"); - Some(FunctionRender::new(ctx, local_name, fn_)?.render(import_to_add)) + Some(FunctionRender::new(ctx, local_name, fn_, false)?.render(import_to_add)) +} + +pub(crate) fn render_method<'a>( + ctx: RenderContext<'a>, + import_to_add: Option, + local_name: Option, + fn_: hir::Function, +) -> Option { + let _p = profile::span("render_method"); + Some(FunctionRender::new(ctx, local_name, fn_, true)?.render(import_to_add)) } #[derive(Debug)] @@ -29,6 +39,7 @@ struct FunctionRender<'a> { name: String, func: hir::Function, ast_node: Fn, + is_method: bool, } impl<'a> FunctionRender<'a> { @@ -36,11 +47,12 @@ fn new( ctx: RenderContext<'a>, local_name: Option, fn_: hir::Function, + is_method: bool, ) -> Option> { let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string()); let ast_node = fn_.source(ctx.db())?.value; - Some(FunctionRender { ctx, name, func: fn_, ast_node }) + Some(FunctionRender { ctx, name, func: fn_, ast_node, is_method }) } fn render(self, import_to_add: Option) -> CompletionItem { @@ -67,7 +79,12 @@ fn render(self, import_to_add: Option) -> CompletionItem { }); if let Some(ref_match) = compute_ref_match(self.ctx.completion, &ret_type) { - item.ref_match(ref_match); + // FIXME + // For now we don't properly calculate the edits for ref match + // completions on methods, so we've disabled them. See #8058. + if !self.is_method { + item.ref_match(ref_match); + } } item.build()