about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_resolve/late.rs2
-rw-r--r--src/librustc_resolve/late/diagnostics.rs55
-rw-r--r--src/test/ui/self/suggest-self-2.rs25
-rw-r--r--src/test/ui/self/suggest-self-2.stderr40
4 files changed, 121 insertions, 1 deletions
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index a0d59fa4829..325921b5982 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<NodeId>,
 
-    /// The current enclosing funciton (used for better errors).
+    /// The current enclosing function (used for better errors).
     current_function: Option<Span>,
 
     /// 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 5e59efac536..3a6bb37269f 100644
--- a/src/librustc_resolve/late/diagnostics.rs
+++ b/src/librustc_resolve/late/diagnostics.rs
@@ -259,6 +259,24 @@ impl<'a> LateResolutionVisitor<'a, '_> {
                 }
                 return (err, candidates);
             }
+
+            // If the first argument in call is `self` suggest calling a method.
+            if let Some((call_span, args_span)) = self.call_has_self_arg(source) {
+                let mut args_snippet = String::new();
+                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.
@@ -298,6 +316,43 @@ impl<'a> LateResolutionVisitor<'a, '_> {
         (err, candidates)
     }
 
+    /// Check if the source is call expression and the first argument is `self`. If true,
+    /// return the span of whole call and the span for all arguments expect the first one (`self`).
+    fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option<Span>)> {
+        let mut has_self_arg = None;
+        if let PathSource::Expr(parent) = source {
+            match &parent?.kind {
+                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 tail_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, tail_args_span));
+                                }
+                                break;
+                            }
+                            ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind,
+                            _ => break,
+                        }
+                    }
+                }
+                _ => (),
+            }
+        };
+        return has_self_arg;
+    }
+
     fn followed_by_brace(&self, span: Span) -> (bool, Option<(Span, String)>) {
         // HACK(estebank): find a better way to figure out that this was a
         // parser issue where a struct literal is being used on an expression
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 00000000000..d6bf5433527
--- /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 00000000000..452c3127515
--- /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`.