Skip to content

Commit 2067a01

Browse files
committed
Auto merge of rust-lang#6267 - camsteffen:or-fun-idx, r=flip1995
Fix or_fun_call for index operator changelog: Fix or_fun_call for index operator Fixes rust-lang#6266
2 parents 040d0ca + 9cab084 commit 2067a01

File tree

5 files changed

+68
-40
lines changed

5 files changed

+68
-40
lines changed

clippy_lints/src/methods/mod.rs

Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1797,12 +1797,20 @@ fn lint_or_fun_call<'tcx>(
17971797
cx: &LateContext<'tcx>,
17981798
name: &str,
17991799
method_span: Span,
1800-
fun_span: Span,
18011800
self_expr: &hir::Expr<'_>,
18021801
arg: &'tcx hir::Expr<'_>,
1803-
or_has_args: bool,
18041802
span: Span,
1803+
// None if lambda is required
1804+
fun_span: Option<Span>,
18051805
) {
1806+
// (path, fn_has_argument, methods, suffix)
1807+
static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [
1808+
(&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
1809+
(&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
1810+
(&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
1811+
(&paths::RESULT, true, &["or", "unwrap_or"], "else"),
1812+
];
1813+
18061814
if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind {
18071815
if path.ident.as_str() == "len" {
18081816
let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs();
@@ -1818,32 +1826,32 @@ fn lint_or_fun_call<'tcx>(
18181826
}
18191827
}
18201828

1821-
// (path, fn_has_argument, methods, suffix)
1822-
let know_types: &[(&[_], _, &[_], _)] = &[
1823-
(&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
1824-
(&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
1825-
(&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
1826-
(&paths::RESULT, true, &["or", "unwrap_or"], "else"),
1827-
];
1828-
18291829
if_chain! {
1830-
if know_types.iter().any(|k| k.2.contains(&name));
1830+
if KNOW_TYPES.iter().any(|k| k.2.contains(&name));
18311831

18321832
if is_lazyness_candidate(cx, arg);
18331833
if !contains_return(&arg);
18341834

18351835
let self_ty = cx.typeck_results().expr_ty(self_expr);
18361836

18371837
if let Some(&(_, fn_has_arguments, poss, suffix)) =
1838-
know_types.iter().find(|&&i| match_type(cx, self_ty, i.0));
1838+
KNOW_TYPES.iter().find(|&&i| match_type(cx, self_ty, i.0));
18391839

18401840
if poss.contains(&name);
18411841

18421842
then {
1843-
let sugg: Cow<'_, _> = match (fn_has_arguments, !or_has_args) {
1844-
(true, _) => format!("|_| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(),
1845-
(false, false) => format!("|| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(),
1846-
(false, true) => snippet_with_macro_callsite(cx, fun_span, ".."),
1843+
let sugg: Cow<'_, str> = {
1844+
let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) {
1845+
(false, Some(fun_span)) => (fun_span, false),
1846+
_ => (arg.span, true),
1847+
};
1848+
let snippet = snippet_with_macro_callsite(cx, snippet_span, "..");
1849+
if use_lambda {
1850+
let l_arg = if fn_has_arguments { "_" } else { "" };
1851+
format!("|{}| {}", l_arg, snippet).into()
1852+
} else {
1853+
snippet
1854+
}
18471855
};
18481856
let span_replace_word = method_span.with_hi(span.hi());
18491857
span_lint_and_sugg(
@@ -1864,28 +1872,13 @@ fn lint_or_fun_call<'tcx>(
18641872
hir::ExprKind::Call(ref fun, ref or_args) => {
18651873
let or_has_args = !or_args.is_empty();
18661874
if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) {
1867-
check_general_case(
1868-
cx,
1869-
name,
1870-
method_span,
1871-
fun.span,
1872-
&args[0],
1873-
&args[1],
1874-
or_has_args,
1875-
expr.span,
1876-
);
1875+
let fun_span = if or_has_args { None } else { Some(fun.span) };
1876+
check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, fun_span);
18771877
}
18781878
},
1879-
hir::ExprKind::MethodCall(_, span, ref or_args, _) => check_general_case(
1880-
cx,
1881-
name,
1882-
method_span,
1883-
span,
1884-
&args[0],
1885-
&args[1],
1886-
!or_args.is_empty(),
1887-
expr.span,
1888-
),
1879+
hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
1880+
check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None);
1881+
},
18891882
_ => {},
18901883
}
18911884
}

clippy_lints/src/utils/eager_or_lazy.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
//! - or-fun-call
1010
//! - option-if-let-else
1111
12-
use crate::utils::is_ctor_or_promotable_const_function;
12+
use crate::utils::{is_ctor_or_promotable_const_function, is_type_diagnostic_item, match_type, paths};
1313
use rustc_hir::def::{DefKind, Res};
1414

1515
use rustc_hir::intravisit;
@@ -96,6 +96,11 @@ fn identify_some_potentially_expensive_patterns<'tcx>(cx: &LateContext<'tcx>, ex
9696
let call_found = match &expr.kind {
9797
// ignore enum and struct constructors
9898
ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr),
99+
ExprKind::Index(obj, _) => {
100+
let ty = self.cx.typeck_results().expr_ty(obj);
101+
is_type_diagnostic_item(self.cx, ty, sym!(hashmap_type))
102+
|| match_type(self.cx, ty, &paths::BTREEMAP)
103+
},
99104
ExprKind::MethodCall(..) => true,
100105
_ => false,
101106
};

tests/ui/or_fun_call.fixed

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ fn or_fun_call() {
7070
let opt = Some(1);
7171
let hello = "Hello";
7272
let _ = opt.ok_or(format!("{} world.", hello));
73+
74+
// index
75+
let map = HashMap::<u64, u64>::new();
76+
let _ = Some(1).unwrap_or_else(|| map[&1]);
77+
let map = BTreeMap::<u64, u64>::new();
78+
let _ = Some(1).unwrap_or_else(|| map[&1]);
79+
// don't lint index vec
80+
let vec = vec![1];
81+
let _ = Some(1).unwrap_or(vec[1]);
7382
}
7483

7584
struct Foo(u8);

tests/ui/or_fun_call.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ fn or_fun_call() {
7070
let opt = Some(1);
7171
let hello = "Hello";
7272
let _ = opt.ok_or(format!("{} world.", hello));
73+
74+
// index
75+
let map = HashMap::<u64, u64>::new();
76+
let _ = Some(1).unwrap_or(map[&1]);
77+
let map = BTreeMap::<u64, u64>::new();
78+
let _ = Some(1).unwrap_or(map[&1]);
79+
// don't lint index vec
80+
let vec = vec![1];
81+
let _ = Some(1).unwrap_or(vec[1]);
7382
}
7483

7584
struct Foo(u8);

tests/ui/or_fun_call.stderr

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,29 @@ error: use of `unwrap_or` followed by a function call
7878
LL | let _ = stringy.unwrap_or("".to_owned());
7979
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())`
8080

81+
error: use of `unwrap_or` followed by a function call
82+
--> $DIR/or_fun_call.rs:76:21
83+
|
84+
LL | let _ = Some(1).unwrap_or(map[&1]);
85+
| ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])`
86+
87+
error: use of `unwrap_or` followed by a function call
88+
--> $DIR/or_fun_call.rs:78:21
89+
|
90+
LL | let _ = Some(1).unwrap_or(map[&1]);
91+
| ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])`
92+
8193
error: use of `or` followed by a function call
82-
--> $DIR/or_fun_call.rs:93:35
94+
--> $DIR/or_fun_call.rs:102:35
8395
|
8496
LL | let _ = Some("a".to_string()).or(Some("b".to_string()));
8597
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))`
8698

8799
error: use of `or` followed by a function call
88-
--> $DIR/or_fun_call.rs:97:10
100+
--> $DIR/or_fun_call.rs:106:10
89101
|
90102
LL | .or(Some(Bar(b, Duration::from_secs(2))));
91103
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))`
92104

93-
error: aborting due to 15 previous errors
105+
error: aborting due to 17 previous errors
94106

0 commit comments

Comments
 (0)