Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggest calling method when first argument is self #66913

Merged
merged 6 commits into from
Jan 4, 2020
Merged
Show file tree
Hide file tree
Changes from all 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?.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
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()`
VirrageS marked this conversation as resolved.
Show resolved Hide resolved

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`.