diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index df81231cf9815..527dfae5745f8 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -345,7 +345,7 @@ struct DiagnosticMetadata { /// The current self item if inside an ADT (used for better errors). current_self_item: Option, - /// The current enclosing funciton (used for better errors). + /// The current enclosing function (used for better errors). current_function: Option, /// A list of labels as of yet unused. Labels will be removed from this map when diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index 3be033697d286..bbe62758e3ae1 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -253,6 +253,56 @@ impl<'a> LateResolutionVisitor<'a, '_> { } return (err, candidates); } + + // Check if the first argument is `self` and suggest calling a method. + let mut has_self_arg = None; + if let PathSource::Expr(parent) = source { + match &parent.map(|p| &p.kind) { + Some(ExprKind::Call(_, args)) if args.len() > 0 => { + let mut expr_kind = &args[0].kind; + loop { + match expr_kind { + ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => { + if arg_name.segments[0].ident.name == kw::SelfLower { + let call_span = parent.unwrap().span; + let args_span = if args.len() > 1 { + Some(Span::new( + args[1].span.lo(), + args.last().unwrap().span.hi(), + call_span.ctxt(), + )) + } else { + None + }; + has_self_arg = Some((call_span, args_span)); + } + break; + }, + ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind, + _ => break, + } + } + } + _ => (), + } + }; + + if let Some((call_span, args_span)) = has_self_arg { + let mut args_snippet: String = String::from(""); + if let Some(args_span) = args_span { + if let Ok(snippet) = self.r.session.source_map().span_to_snippet(args_span) { + args_snippet = snippet; + } + } + + err.span_suggestion( + call_span, + &format!("try calling `{}` as a method", ident), + format!("self.{}({})", path_str, args_snippet), + Applicability::MachineApplicable, + ); + return (err, candidates); + } } // Try Levenshtein algorithm. @@ -553,13 +603,13 @@ impl<'a> LateResolutionVisitor<'a, '_> { // Look for associated items in the current trait. if let Some((module, _)) = self.current_trait_ref { if let Ok(binding) = self.r.resolve_ident_in_module( - ModuleOrUniformRoot::Module(module), - ident, - ns, - &self.parent_scope, - false, - module.span, - ) { + ModuleOrUniformRoot::Module(module), + ident, + ns, + &self.parent_scope, + false, + module.span, + ) { let res = binding.res(); if filter_fn(res) { return Some(if self.r.has_self.contains(&res.def_id()) { diff --git a/src/test/ui/self/suggest-self-2.rs b/src/test/ui/self/suggest-self-2.rs new file mode 100644 index 0000000000000..d6bf543352701 --- /dev/null +++ b/src/test/ui/self/suggest-self-2.rs @@ -0,0 +1,25 @@ +struct Foo {} + +impl Foo { + fn foo(&self) { + bar(self); + //~^ ERROR cannot find function `bar` in this scope + //~| HELP try calling `bar` as a method + + bar(&&self, 102); + //~^ ERROR cannot find function `bar` in this scope + //~| HELP try calling `bar` as a method + + bar(&mut self, 102, &"str"); + //~^ ERROR cannot find function `bar` in this scope + //~| HELP try calling `bar` as a method + + bar(); + //~^ ERROR cannot find function `bar` in this scope + + self.bar(); + //~^ ERROR no method named `bar` found for type + } +} + +fn main() {} diff --git a/src/test/ui/self/suggest-self-2.stderr b/src/test/ui/self/suggest-self-2.stderr new file mode 100644 index 0000000000000..452c31275153a --- /dev/null +++ b/src/test/ui/self/suggest-self-2.stderr @@ -0,0 +1,40 @@ +error[E0425]: cannot find function `bar` in this scope + --> $DIR/suggest-self-2.rs:5:9 + | +LL | bar(self); + | ^^^------ + | | + | help: try calling `bar` as a method: `self.bar()` + +error[E0425]: cannot find function `bar` in this scope + --> $DIR/suggest-self-2.rs:9:9 + | +LL | bar(&&self, 102); + | ^^^------------- + | | + | help: try calling `bar` as a method: `self.bar(102)` + +error[E0425]: cannot find function `bar` in this scope + --> $DIR/suggest-self-2.rs:13:9 + | +LL | bar(&mut self, 102, &"str"); + | ^^^------------------------ + | | + | help: try calling `bar` as a method: `self.bar(102, &"str")` + +error[E0425]: cannot find function `bar` in this scope + --> $DIR/suggest-self-2.rs:17:9 + | +LL | bar(); + | ^^^ not found in this scope + +error[E0599]: no method named `bar` found for type `&Foo` in the current scope + --> $DIR/suggest-self-2.rs:20:14 + | +LL | self.bar(); + | ^^^ method not found in `&Foo` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0425, E0599. +For more information about an error, try `rustc --explain E0425`.