Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/librustc_resolve/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
55 changes: 55 additions & 0 deletions src/librustc_resolve/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.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 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
Expand Down
25 changes: 25 additions & 0 deletions src/test/ui/self/suggest-self-2.rs
Original file line number Diff line number Diff line change
@@ -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() {}
40 changes: 40 additions & 0 deletions src/test/ui/self/suggest-self-2.stderr
Original file line number Diff line number Diff line change
@@ -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`.