Auto merge of #10930 - y21:issue9956, r=blyxyas,xFrednet

[`redundant_closure_call`]: handle nested closures

Fixes #9956.

This ended up being a much larger change than I'd thought, and I ended up having to pretty much rewrite it as a late lint pass, because it needs access to certain things that I don't think are available in early lint passes (e.g. getting the parent expr). I think this'll be required to fi-x #10922 anyway, so this is probably fine.
(edit: had to write "fi-x" because "fix" makes github think that this PR fixes it, which it doesn't 😅 )

Previously, it would suggest changing `(|| || 42)()()` to `|| 42()`, which is a type error (it needs parens: `(|| 42)()`). In my opinion, though, the suggested fix should have really been `42`, so that's what this PR changes.

changelog: [`redundant_closure_call`]: handle nested closures and rewrite as a late lint pass
This commit is contained in:
bors 2023-06-19 20:30:35 +00:00
commit 5b60388e5a
5 changed files with 274 additions and 56 deletions

View file

@ -3,6 +3,7 @@
#![feature(async_closure)]
#![warn(clippy::redundant_closure_call)]
#![allow(clippy::redundant_async_block)]
#![allow(clippy::type_complexity)]
#![allow(unused)]
async fn something() -> u32 {
@ -38,4 +39,50 @@ fn main() {
};
}
m2!();
issue9956();
}
fn issue9956() {
assert_eq!(43, 42);
// ... and some more interesting cases I've found while implementing the fix
// not actually immediately calling the closure:
let a = (|| 42);
dbg!(a());
// immediately calling it inside of a macro
dbg!(42);
// immediately calling only one closure, so we can't remove the other ones
let a = (|| || 123);
dbg!(a()());
// nested async closures
let a = async { 1 };
let h = async { a.await };
// macro expansion tests
macro_rules! echo {
($e:expr) => {
$e
};
}
let a = 1;
assert_eq!(a, 1);
let a = 123;
assert_eq!(a, 123);
// chaining calls, but not closures
fn x() -> fn() -> fn() -> fn() -> i32 {
|| || || 42
}
let _ = x()()()();
fn bar() -> fn(i32, i32) {
foo
}
fn foo(_: i32, _: i32) {}
bar()(42, 5);
foo(42, 5);
}

View file

@ -3,6 +3,7 @@
#![feature(async_closure)]
#![warn(clippy::redundant_closure_call)]
#![allow(clippy::redundant_async_block)]
#![allow(clippy::type_complexity)]
#![allow(unused)]
async fn something() -> u32 {
@ -38,4 +39,50 @@ fn main() {
};
}
m2!();
issue9956();
}
fn issue9956() {
assert_eq!((|| || 43)()(), 42);
// ... and some more interesting cases I've found while implementing the fix
// not actually immediately calling the closure:
let a = (|| 42);
dbg!(a());
// immediately calling it inside of a macro
dbg!((|| 42)());
// immediately calling only one closure, so we can't remove the other ones
let a = (|| || || 123)();
dbg!(a()());
// nested async closures
let a = (|| || || || async || 1)()()()()();
let h = async { a.await };
// macro expansion tests
macro_rules! echo {
($e:expr) => {
$e
};
}
let a = (|| echo!(|| echo!(|| 1)))()()();
assert_eq!(a, 1);
let a = (|| echo!((|| 123)))()();
assert_eq!(a, 123);
// chaining calls, but not closures
fn x() -> fn() -> fn() -> fn() -> i32 {
|| || || 42
}
let _ = x()()()();
fn bar() -> fn(i32, i32) {
foo
}
fn foo(_: i32, _: i32) {}
bar()((|| || 42)()(), 5);
foo((|| || 42)()(), 5);
}

View file

@ -1,5 +1,5 @@
error: try not to call a closure in the expression where it is declared
--> $DIR/redundant_closure_call_fixable.rs:17:13
--> $DIR/redundant_closure_call_fixable.rs:18:13
|
LL | let a = (|| 42)();
| ^^^^^^^^^ help: try doing something like: `42`
@ -7,7 +7,7 @@ LL | let a = (|| 42)();
= note: `-D clippy::redundant-closure-call` implied by `-D warnings`
error: try not to call a closure in the expression where it is declared
--> $DIR/redundant_closure_call_fixable.rs:18:13
--> $DIR/redundant_closure_call_fixable.rs:19:13
|
LL | let b = (async || {
| _____________^
@ -27,7 +27,7 @@ LL ~ };
|
error: try not to call a closure in the expression where it is declared
--> $DIR/redundant_closure_call_fixable.rs:23:13
--> $DIR/redundant_closure_call_fixable.rs:24:13
|
LL | let c = (|| {
| _____________^
@ -47,13 +47,13 @@ LL ~ };
|
error: try not to call a closure in the expression where it is declared
--> $DIR/redundant_closure_call_fixable.rs:28:13
--> $DIR/redundant_closure_call_fixable.rs:29:13
|
LL | let d = (async || something().await)();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { something().await }`
error: try not to call a closure in the expression where it is declared
--> $DIR/redundant_closure_call_fixable.rs:37:13
--> $DIR/redundant_closure_call_fixable.rs:38:13
|
LL | (|| m!())()
| ^^^^^^^^^^^ help: try doing something like: `m!()`
@ -64,7 +64,7 @@ LL | m2!();
= note: this error originates in the macro `m2` (in Nightly builds, run with -Z macro-backtrace for more info)
error: try not to call a closure in the expression where it is declared
--> $DIR/redundant_closure_call_fixable.rs:32:13
--> $DIR/redundant_closure_call_fixable.rs:33:13
|
LL | (|| 0)()
| ^^^^^^^^ help: try doing something like: `0`
@ -74,5 +74,53 @@ LL | m2!();
|
= note: this error originates in the macro `m` which comes from the expansion of the macro `m2` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 6 previous errors
error: try not to call a closure in the expression where it is declared
--> $DIR/redundant_closure_call_fixable.rs:46:16
|
LL | assert_eq!((|| || 43)()(), 42);
| ^^^^^^^^^^^^^^ help: try doing something like: `43`
error: try not to call a closure in the expression where it is declared
--> $DIR/redundant_closure_call_fixable.rs:55:10
|
LL | dbg!((|| 42)());
| ^^^^^^^^^ help: try doing something like: `42`
error: try not to call a closure in the expression where it is declared
--> $DIR/redundant_closure_call_fixable.rs:58:13
|
LL | let a = (|| || || 123)();
| ^^^^^^^^^^^^^^^^ help: try doing something like: `(|| || 123)`
error: try not to call a closure in the expression where it is declared
--> $DIR/redundant_closure_call_fixable.rs:62:13
|
LL | let a = (|| || || || async || 1)()()()()();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { 1 }`
error: try not to call a closure in the expression where it is declared
--> $DIR/redundant_closure_call_fixable.rs:71:13
|
LL | let a = (|| echo!(|| echo!(|| 1)))()()();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `1`
error: try not to call a closure in the expression where it is declared
--> $DIR/redundant_closure_call_fixable.rs:73:13
|
LL | let a = (|| echo!((|| 123)))()();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `123`
error: try not to call a closure in the expression where it is declared
--> $DIR/redundant_closure_call_fixable.rs:86:11
|
LL | bar()((|| || 42)()(), 5);
| ^^^^^^^^^^^^^^ help: try doing something like: `42`
error: try not to call a closure in the expression where it is declared
--> $DIR/redundant_closure_call_fixable.rs:87:9
|
LL | foo((|| || 42)()(), 5);
| ^^^^^^^^^^^^^^ help: try doing something like: `42`
error: aborting due to 14 previous errors