Generate let binding variable name for some cases

Given a map call like `x.field.map ...` the suggestion will contain:
`if let Some(x_field) ...`

Given a map call like `x.map ...` the suggestion will contain:
`if let Some(_x) ...`

Otherwise it will suggest: `if let Some(_) ...`
This commit is contained in:
Philipp Hansch 2018-04-15 11:37:35 +02:00
parent d87385b406
commit d54f70f1f6
No known key found for this signature in database
GPG key ID: B6FA06A6E0E2665B
3 changed files with 62 additions and 6 deletions

View file

@ -133,6 +133,20 @@ fn unit_closure<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'a hir::Expr) -> Op
None
}
/// Builds a name for the let binding variable (var_arg)
///
/// `x.field` => `x_field`
/// `y` => `_y`
///
/// Anything else will return `_`.
fn let_binding_name(cx: &LateContext, var_arg: &hir::Expr) -> String {
match &var_arg.node {
hir::ExprField(_, _) => snippet(cx, var_arg.span, "_").replace(".", "_"),
hir::ExprPath(_) => format!("_{}", snippet(cx, var_arg.span, "")),
_ => "_".to_string()
}
}
fn lint_map_unit_fn(cx: &LateContext, stmt: &hir::Stmt, expr: &hir::Expr, map_args: &[hir::Expr]) {
let var_arg = &map_args[0];
let fn_arg = &map_args[1];
@ -143,7 +157,8 @@ fn lint_map_unit_fn(cx: &LateContext, stmt: &hir::Stmt, expr: &hir::Expr, map_ar
if is_unit_function(cx, fn_arg) {
let msg = "called `map(f)` on an Option value where `f` is a unit function";
let suggestion = format!("if let Some(...) = {0} {{ {1}(...) }}",
let suggestion = format!("if let Some({0}) = {1} {{ {2}(...) }}",
let_binding_name(cx, var_arg),
snippet(cx, var_arg.span, "_"),
snippet(cx, fn_arg.span, "_"));

View file

@ -86,4 +86,13 @@ fn main() {
do_nothing(value)
});
x.field.map(|value| { do_nothing(value); do_nothing(value); });
// The following should suggest `if let Some(_X) ...` as it's difficult to generate a proper let variable name for them
Some(42).map(diverge);
"12".parse::<i32>().ok().map(diverge);
Some(plus_one(1)).map(do_nothing);
// Should suggest `if let Some(_y) ...` to not override the existing foo variable
let y = Some(42);
y.map(do_nothing);
}

View file

@ -4,7 +4,7 @@ error: called `map(f)` on an Option value where `f` is a unit function
33 | x.field.map(do_nothing);
| ^^^^^^^^^^^^^^^^^^^^^^^-
| |
| help: try this: `if let Some(...) = x.field { do_nothing(...) }`
| help: try this: `if let Some(x_field) = x.field { do_nothing(...) }`
|
= note: `-D option-map-unit-fn` implied by `-D warnings`
@ -14,7 +14,7 @@ error: called `map(f)` on an Option value where `f` is a unit function
35 | x.field.map(do_nothing);
| ^^^^^^^^^^^^^^^^^^^^^^^-
| |
| help: try this: `if let Some(...) = x.field { do_nothing(...) }`
| help: try this: `if let Some(x_field) = x.field { do_nothing(...) }`
error: called `map(f)` on an Option value where `f` is a unit function
--> $DIR/option_map_unit_fn.rs:37:5
@ -22,7 +22,7 @@ error: called `map(f)` on an Option value where `f` is a unit function
37 | x.field.map(diverge);
| ^^^^^^^^^^^^^^^^^^^^-
| |
| help: try this: `if let Some(...) = x.field { diverge(...) }`
| help: try this: `if let Some(x_field) = x.field { diverge(...) }`
error: called `map(f)` on an Option value where `f` is a unit closure
--> $DIR/option_map_unit_fn.rs:43:5
@ -164,7 +164,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
87 | || });
| ||______^- help: try this: `if let Some(value) = x.field { ... }`
| |_______|
|
|
error: called `map(f)` on an Option value where `f` is a unit closure
--> $DIR/option_map_unit_fn.rs:88:5
@ -174,5 +174,37 @@ error: called `map(f)` on an Option value where `f` is a unit closure
| |
| help: try this: `if let Some(value) = x.field { ... }`
error: aborting due to 21 previous errors
error: called `map(f)` on an Option value where `f` is a unit function
--> $DIR/option_map_unit_fn.rs:91:5
|
91 | Some(42).map(diverge);
| ^^^^^^^^^^^^^^^^^^^^^-
| |
| help: try this: `if let Some(_) = Some(42) { diverge(...) }`
error: called `map(f)` on an Option value where `f` is a unit function
--> $DIR/option_map_unit_fn.rs:92:5
|
92 | "12".parse::<i32>().ok().map(diverge);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
| help: try this: `if let Some(_) = "12".parse::<i32>().ok() { diverge(...) }`
error: called `map(f)` on an Option value where `f` is a unit function
--> $DIR/option_map_unit_fn.rs:93:5
|
93 | Some(plus_one(1)).map(do_nothing);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
| help: try this: `if let Some(_) = Some(plus_one(1)) { do_nothing(...) }`
error: called `map(f)` on an Option value where `f` is a unit function
--> $DIR/option_map_unit_fn.rs:97:5
|
97 | y.map(do_nothing);
| ^^^^^^^^^^^^^^^^^-
| |
| help: try this: `if let Some(_y) = y { do_nothing(...) }`
error: aborting due to 25 previous errors