Skip to content

Commit

Permalink
Suggest calling method when first argument is self
Browse files Browse the repository at this point in the history
  • Loading branch information
VirrageS committed Dec 10, 2019
1 parent 8960acf commit f13b8fb
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 14 deletions.
2 changes: 1 addition & 1 deletion src/doc/rustc-guide
10 changes: 5 additions & 5 deletions src/librustc_resolve/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -719,8 +719,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
// These items live in both the type and value namespaces.
ItemKind::Struct(ref vdata, _) => {
// Define a name in the type namespace.
let def_id = self.r.definitions.local_def_id(item.id);
let res = Res::Def(DefKind::Struct, def_id);
let item_def_id = self.r.definitions.local_def_id(item.id);
let res = Res::Def(DefKind::Struct, item_def_id);
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));

// Record field names for error reporting.
Expand Down Expand Up @@ -757,12 +757,12 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
}

ItemKind::Union(ref vdata, _) => {
let def_id = self.r.definitions.local_def_id(item.id);
let res = Res::Def(DefKind::Union, def_id);
let item_def_id = self.r.definitions.local_def_id(item.id);
let res = Res::Def(DefKind::Union, item_def_id);
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));

// Record field names for error reporting.
self.insert_field_names_local(def_id, vdata);
self.insert_field_names_local(item_def_id, vdata);
}

ItemKind::Impl(.., ref impl_items) => {
Expand Down
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
45 changes: 38 additions & 7 deletions src/librustc_resolve/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,37 @@ impl<'a> LateResolutionVisitor<'a, '_> {
}
return (err, candidates);
}

// Check if the first argument is `self` and suggest calling a method.
let mut has_self_arg = false;
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.first().unwrap().kind;
loop {
match expr_kind {
ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => {
has_self_arg = arg_name.segments[0].ident.name == kw::SelfLower;
break;
},
ExprKind::AddrOf(_, _, expr) => { expr_kind = &expr.kind; }
_ => break,
}
}
}
_ => (),
}
};

if has_self_arg {
err.span_suggestion(
span,
&"try calling method instead of passing `self` as parameter",
format!("self.{}", path_str),
Applicability::MachineApplicable,
);
return (err, candidates);
}
}

// Try Levenshtein algorithm.
Expand Down Expand Up @@ -553,13 +584,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
22 changes: 22 additions & 0 deletions src/test/ui/self/suggest-self-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
struct Foo {}

impl Foo {
fn foo(&self) {
bar(self);
//~^ ERROR cannot find function `bar` in this scope
//~| HELP try calling method instead of passing `self` as parameter


bar(&self);
//~^ ERROR cannot find function `bar` in this scope
//~| HELP try calling method instead of passing `self` as parameter

bar();
//~^ ERROR cannot find function `bar` in this scope

self.bar();
//~^ ERROR no method named `bar` found for type
}
}

fn main() {}
28 changes: 28 additions & 0 deletions src/test/ui/self/suggest-self-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
error[E0425]: cannot find function `bar` in this scope
--> $DIR/suggest-self-2.rs:5:9
|
LL | bar(self);
| ^^^ help: try calling method instead of passing `self` as parameter: `self.bar`

error[E0425]: cannot find function `bar` in this scope
--> $DIR/suggest-self-2.rs:10:9
|
LL | bar(&self);
| ^^^ help: try calling method instead of passing `self` as parameter: `self.bar`

error[E0425]: cannot find function `bar` in this scope
--> $DIR/suggest-self-2.rs:14: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:17:14
|
LL | self.bar();
| ^^^ method not found in `&Foo`

error: aborting due to 4 previous errors

Some errors have detailed explanations: E0425, E0599.
For more information about an error, try `rustc --explain E0425`.

0 comments on commit f13b8fb

Please sign in to comment.