Skip to content

Commit cc46063

Browse files
Fix false positive for needless_character_iteration lint
1 parent 4f3180a commit cc46063

File tree

5 files changed

+33
-12
lines changed

5 files changed

+33
-12
lines changed

clippy_lints/src/methods/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4485,7 +4485,7 @@ impl Methods {
44854485
},
44864486
("all", [arg]) => {
44874487
unused_enumerate_index::check(cx, expr, recv, arg);
4488-
needless_character_iteration::check(cx, expr, recv, arg);
4488+
needless_character_iteration::check(cx, expr, recv, arg, true);
44894489
if let Some(("cloned", recv2, [], _, _)) = method_call(recv) {
44904490
iter_overeager_cloned::check(
44914491
cx,
@@ -4506,6 +4506,7 @@ impl Methods {
45064506
},
45074507
("any", [arg]) => {
45084508
unused_enumerate_index::check(cx, expr, recv, arg);
4509+
needless_character_iteration::check(cx, expr, recv, arg, false);
45094510
match method_call(recv) {
45104511
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
45114512
cx,

clippy_lints/src/methods/needless_character_iteration.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ fn handle_expr(
2424
span: Span,
2525
before_chars: Span,
2626
revert: bool,
27+
is_all: bool,
2728
) {
2829
match expr.kind {
2930
ExprKind::MethodCall(method, receiver, [], _) => {
@@ -32,6 +33,9 @@ fn handle_expr(
3233
&& let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs()
3334
&& *char_arg_ty.kind() == ty::Char
3435
&& let Some(snippet) = snippet_opt(cx, before_chars)
36+
// If we have `!is_ascii`, then only `.any()` should warn. And if the condition is
37+
// `is_ascii`, then only `.all()` should warn.
38+
&& revert != is_all
3539
{
3640
span_lint_and_sugg(
3741
cx,
@@ -55,16 +59,19 @@ fn handle_expr(
5559
&& let Some(last_chain_binding_id) =
5660
get_last_chain_binding_hir_id(first_param, block.stmts)
5761
{
58-
handle_expr(cx, block_expr, last_chain_binding_id, span, before_chars, revert);
62+
handle_expr(cx, block_expr, last_chain_binding_id, span, before_chars, revert, is_all);
5963
}
6064
},
61-
ExprKind::Unary(UnOp::Not, expr) => handle_expr(cx, expr, first_param, span, before_chars, !revert),
65+
ExprKind::Unary(UnOp::Not, expr) => handle_expr(cx, expr, first_param, span, before_chars, !revert, is_all),
6266
ExprKind::Call(fn_path, [arg]) => {
6367
if let ExprKind::Path(path) = fn_path.kind
6468
&& let Some(fn_def_id) = cx.qpath_res(&path, fn_path.hir_id).opt_def_id()
6569
&& match_def_path(cx, fn_def_id, &["core", "char", "methods", "<impl char>", "is_ascii"])
6670
&& path_to_local_id(peels_expr_ref(arg), first_param)
6771
&& let Some(snippet) = snippet_opt(cx, before_chars)
72+
// If we have `!is_ascii`, then only `.any()` should warn. And if the condition is
73+
// `is_ascii`, then only `.all()` should warn.
74+
&& revert != is_all
6875
{
6976
span_lint_and_sugg(
7077
cx,
@@ -81,7 +88,7 @@ fn handle_expr(
8188
}
8289
}
8390

84-
pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>) {
91+
pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>, is_all: bool) {
8592
if let ExprKind::Closure(&Closure { body, .. }) = closure_arg.kind
8693
&& let body = cx.tcx.hir().body(body)
8794
&& let Some(first_param) = body.params.first()
@@ -103,6 +110,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
103110
recv.span.with_hi(call_expr.span.hi()),
104111
recv.span.with_hi(expr_start.hi()),
105112
false,
113+
is_all,
106114
);
107115
}
108116
}

tests/ui/needless_character_iteration.fixed

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,10 @@ fn main() {
4848

4949
// Should not lint!
5050
"foo".chars().map(|c| c).all(|c| !char::is_ascii(&c));
51+
52+
// Should not lint!
53+
"foo".chars().all(|c| !c.is_ascii());
54+
55+
// Should not lint!
56+
"foo".chars().any(|c| c.is_ascii());
5157
}

tests/ui/needless_character_iteration.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,25 @@ fn magic(_: char) {}
1717
fn main() {
1818
"foo".chars().all(|c| c.is_ascii());
1919
//~^ ERROR: checking if a string is ascii using iterators
20-
"foo".chars().all(|c| !c.is_ascii());
20+
"foo".chars().any(|c| !c.is_ascii());
2121
//~^ ERROR: checking if a string is ascii using iterators
2222
"foo".chars().all(|c| char::is_ascii(&c));
2323
//~^ ERROR: checking if a string is ascii using iterators
24-
"foo".chars().all(|c| !char::is_ascii(&c));
24+
"foo".chars().any(|c| !char::is_ascii(&c));
2525
//~^ ERROR: checking if a string is ascii using iterators
2626

2727
let s = String::new();
2828
s.chars().all(|c| c.is_ascii());
2929
//~^ ERROR: checking if a string is ascii using iterators
30-
"foo".to_string().chars().all(|c| !c.is_ascii());
30+
"foo".to_string().chars().any(|c| !c.is_ascii());
3131
//~^ ERROR: checking if a string is ascii using iterators
3232

3333
"foo".chars().all(|c| {
3434
//~^ ERROR: checking if a string is ascii using iterators
3535
let x = c;
3636
x.is_ascii()
3737
});
38-
"foo".chars().all(|c| {
38+
"foo".chars().any(|c| {
3939
//~^ ERROR: checking if a string is ascii using iterators
4040
let x = c;
4141
!x.is_ascii()
@@ -56,4 +56,10 @@ fn main() {
5656

5757
// Should not lint!
5858
"foo".chars().map(|c| c).all(|c| !char::is_ascii(&c));
59+
60+
// Should not lint!
61+
"foo".chars().all(|c| !c.is_ascii());
62+
63+
// Should not lint!
64+
"foo".chars().any(|c| c.is_ascii());
5965
}

tests/ui/needless_character_iteration.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ LL | "foo".chars().all(|c| c.is_ascii());
1010
error: checking if a string is ascii using iterators
1111
--> tests/ui/needless_character_iteration.rs:20:5
1212
|
13-
LL | "foo".chars().all(|c| !c.is_ascii());
13+
LL | "foo".chars().any(|c| !c.is_ascii());
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".is_ascii()`
1515

1616
error: checking if a string is ascii using iterators
@@ -22,7 +22,7 @@ LL | "foo".chars().all(|c| char::is_ascii(&c));
2222
error: checking if a string is ascii using iterators
2323
--> tests/ui/needless_character_iteration.rs:24:5
2424
|
25-
LL | "foo".chars().all(|c| !char::is_ascii(&c));
25+
LL | "foo".chars().any(|c| !char::is_ascii(&c));
2626
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".is_ascii()`
2727

2828
error: checking if a string is ascii using iterators
@@ -34,7 +34,7 @@ LL | s.chars().all(|c| c.is_ascii());
3434
error: checking if a string is ascii using iterators
3535
--> tests/ui/needless_character_iteration.rs:30:5
3636
|
37-
LL | "foo".to_string().chars().all(|c| !c.is_ascii());
37+
LL | "foo".to_string().chars().any(|c| !c.is_ascii());
3838
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".to_string().is_ascii()`
3939

4040
error: checking if a string is ascii using iterators
@@ -50,7 +50,7 @@ LL | | });
5050
error: checking if a string is ascii using iterators
5151
--> tests/ui/needless_character_iteration.rs:38:5
5252
|
53-
LL | / "foo".chars().all(|c| {
53+
LL | / "foo".chars().any(|c| {
5454
LL | |
5555
LL | | let x = c;
5656
LL | | !x.is_ascii()

0 commit comments

Comments
 (0)