Skip to content

Commit

Permalink
Rollup merge of rust-lang#66913 - VirrageS:help-self, r=varkor
Browse files Browse the repository at this point in the history
Suggest calling method when first argument is `self`

Closes: rust-lang#66782

I've explored different approaches for this MR but I think the most straightforward is the best one.

I've tried to find out if the methods for given type exist (to maybe have a better suggestion), but we don't collect them anywhere and collecting them is quite problematic. Moreover, collecting all the methods would require rewriting big part of the code and also could potentially include performance degradation, which I don't think is necessary for this simple case.
  • Loading branch information
Centril authored Dec 22, 2019
2 parents 699a2c7 + 9273f59 commit 3849ccd
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 8 deletions.
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
64 changes: 57 additions & 7 deletions src/librustc_resolve/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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()) {
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`.

0 comments on commit 3849ccd

Please sign in to comment.