Skip to content

Commit 42f96b2

Browse files
committed
Auto merge of rust-lang#4164 - mikerite:fix-4144, r=mikerite
Fix .map(..).unwrap_or_else(..) bad suggestion Closes rust-lang#4144
2 parents 20da8f4 + 3b7d6ee commit 42f96b2

File tree

3 files changed

+38
-9
lines changed

3 files changed

+38
-9
lines changed

clippy_lints/src/methods/mod.rs

+14
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use syntax::symbol::LocalInternedString;
2020

2121
use crate::utils::paths;
2222
use crate::utils::sugg;
23+
use crate::utils::usage::mutated_variables;
2324
use crate::utils::{
2425
get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, is_copy,
2526
is_ctor_function, is_expn_of, is_self, is_self_ty, iter_input_pats, last_path_segment, match_def_path, match_path,
@@ -1880,7 +1881,20 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(
18801881
// lint if the caller of `map()` is an `Option`
18811882
let is_option = match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::OPTION);
18821883
let is_result = match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::RESULT);
1884+
18831885
if is_option || is_result {
1886+
// Don't make a suggestion that may fail to compile due to mutably borrowing
1887+
// the same variable twice.
1888+
let map_mutated_vars = mutated_variables(&map_args[0], cx);
1889+
let unwrap_mutated_vars = mutated_variables(&unwrap_args[1], cx);
1890+
if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) {
1891+
if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() {
1892+
return;
1893+
}
1894+
} else {
1895+
return;
1896+
}
1897+
18841898
// lint message
18851899
let msg = if is_option {
18861900
"called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling \

tests/ui/methods.rs

+15
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,21 @@ fn option_methods() {
203203
// Macro case.
204204
// Should not lint.
205205
let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0);
206+
207+
// Issue #4144
208+
{
209+
let mut frequencies = HashMap::new();
210+
let word = "foo";
211+
212+
frequencies
213+
.get_mut(word)
214+
.map(|count| {
215+
*count += 1;
216+
})
217+
.unwrap_or_else(|| {
218+
frequencies.insert(word.to_owned(), 1);
219+
});
220+
}
206221
}
207222

208223
/// Checks implementation of `FILTER_NEXT` lint.

tests/ui/methods.stderr

+9-9
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ LL | | );
130130
| |_________________^
131131

132132
error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead.
133-
--> $DIR/methods.rs:214:13
133+
--> $DIR/methods.rs:229:13
134134
|
135135
LL | let _ = v.iter().filter(|&x| *x < 0).next();
136136
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -139,7 +139,7 @@ LL | let _ = v.iter().filter(|&x| *x < 0).next();
139139
= note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)`
140140

141141
error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead.
142-
--> $DIR/methods.rs:217:13
142+
--> $DIR/methods.rs:232:13
143143
|
144144
LL | let _ = v.iter().filter(|&x| {
145145
| _____________^
@@ -149,7 +149,7 @@ LL | | ).next();
149149
| |___________________________^
150150

151151
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
152-
--> $DIR/methods.rs:233:13
152+
--> $DIR/methods.rs:248:13
153153
|
154154
LL | let _ = v.iter().find(|&x| *x < 0).is_some();
155155
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -158,7 +158,7 @@ LL | let _ = v.iter().find(|&x| *x < 0).is_some();
158158
= note: replace `find(|&x| *x < 0).is_some()` with `any(|x| *x < 0)`
159159

160160
error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
161-
--> $DIR/methods.rs:236:13
161+
--> $DIR/methods.rs:251:13
162162
|
163163
LL | let _ = v.iter().find(|&x| {
164164
| _____________^
@@ -168,15 +168,15 @@ LL | | ).is_some();
168168
| |______________________________^
169169

170170
error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
171-
--> $DIR/methods.rs:242:13
171+
--> $DIR/methods.rs:257:13
172172
|
173173
LL | let _ = v.iter().position(|&x| x < 0).is_some();
174174
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
175175
|
176176
= note: replace `position(|&x| x < 0).is_some()` with `any(|&x| x < 0)`
177177

178178
error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
179-
--> $DIR/methods.rs:245:13
179+
--> $DIR/methods.rs:260:13
180180
|
181181
LL | let _ = v.iter().position(|&x| {
182182
| _____________^
@@ -186,15 +186,15 @@ LL | | ).is_some();
186186
| |______________________________^
187187

188188
error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
189-
--> $DIR/methods.rs:251:13
189+
--> $DIR/methods.rs:266:13
190190
|
191191
LL | let _ = v.iter().rposition(|&x| x < 0).is_some();
192192
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
193193
|
194194
= note: replace `rposition(|&x| x < 0).is_some()` with `any(|&x| x < 0)`
195195

196196
error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
197-
--> $DIR/methods.rs:254:13
197+
--> $DIR/methods.rs:269:13
198198
|
199199
LL | let _ = v.iter().rposition(|&x| {
200200
| _____________^
@@ -204,7 +204,7 @@ LL | | ).is_some();
204204
| |______________________________^
205205

206206
error: used unwrap() on an Option value. If you don't want to handle the None case gracefully, consider using expect() to provide a better panic message
207-
--> $DIR/methods.rs:269:13
207+
--> $DIR/methods.rs:284:13
208208
|
209209
LL | let _ = opt.unwrap();
210210
| ^^^^^^^^^^^^

0 commit comments

Comments
 (0)