2 #![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)]
5 clippy
::needless_borrow
,
6 clippy
::needless_pass_by_value
,
8 clippy
::option_map_unit_fn
,
9 clippy
::redundant_closure_call
,
10 clippy
::uninlined_format_args
13 use std
::path
::{Path, PathBuf}
;
21 macro_rules
! closure_mac
{
28 let a
= Some(1u8).map(|a
| foo(a
));
29 let c
= Some(1u8).map(|a
| {1+2; foo}
(a
));
30 true.then(|| mac
!()); // don't lint function in macro expansion
31 Some(1).map(closure_mac
!()); // don't lint closure in macro expansion
32 let _
: Option
<Vec
<u8>> = true.then(|| vec
![]); // special case vec!
33 let d
= Some(1u8).map(|a
| foo((|b
| foo2(b
))(a
))); //is adjusted?
34 all(&[1, 2, 3], &&2, |x
, y
| below(x
, y
)); //is adjusted
36 Some(1u8).map(|a
| unsafe_fn(a
)); // unsafe fn
40 let e
= Some(1u8).map(|a
| divergent(a
));
41 let e
= Some(1u8).map(|a
| generic(a
));
42 let e
= Some(1u8).map(generic
);
44 let a
: Option
<Box
<dyn (::std
::ops
::Deref
<Target
= [i32]>)>> =
45 Some(vec
![1i32, 2]).map(|v
| -> Box
<dyn (::std
::ops
::Deref
<Target
= [i32]>)> { Box::new(v) }
);
48 let _
: Option
<Vec
<u32>> = Some(0).map(|_
| vec
![]);
52 fn trait_foo(self) -> bool
;
53 fn trait_foo_ref(&self) -> bool
;
56 struct TestStruct
<'a
> {
60 impl<'a
> TestStruct
<'a
> {
61 fn foo(self) -> bool
{
64 unsafe fn foo_unsafe(self) -> bool
{
69 impl<'a
> TestTrait
for TestStruct
<'a
> {
70 fn trait_foo(self) -> bool
{
73 fn trait_foo_ref(&self) -> bool
{
78 impl<'a
> std
::ops
::Deref
for TestStruct
<'a
> {
80 fn deref(&self) -> &char {
85 fn test_redundant_closures_containing_method_calls() {
87 let e
= Some(TestStruct { some_ref: &i }
).map(|a
| a
.foo());
88 let e
= Some(TestStruct { some_ref: &i }
).map(|a
| a
.trait_foo());
89 let e
= Some(TestStruct { some_ref: &i }
).map(|a
| a
.trait_foo_ref());
90 let e
= Some(&mut vec
![1, 2, 3]).map(|v
| v
.clear());
92 let e
= Some(TestStruct { some_ref: &i }
).map(|a
| a
.foo_unsafe());
94 let e
= Some("str").map(|s
| s
.to_string());
95 let e
= Some('a'
).map(|s
| s
.to_uppercase());
96 let e
: std
::vec
::Vec
<usize> = vec
!['a'
, 'b'
, 'c'
].iter().map(|c
| c
.len_utf8()).collect();
97 let e
: std
::vec
::Vec
<char> = vec
!['a'
, 'b'
, 'c'
].iter().map(|c
| c
.to_ascii_uppercase()).collect();
98 let e
= Some(PathBuf
::new()).as_ref().and_then(|s
| s
.to_str());
99 let c
= Some(TestStruct { some_ref: &i }
)
101 .map(|c
| c
.to_ascii_uppercase());
103 fn test_different_borrow_levels
<T
>(t
: &[&T
])
107 t
.iter().filter(|x
| x
.trait_foo_ref());
108 t
.iter().map(|x
| x
.trait_foo_ref());
112 struct Thunk
<T
>(Box
<dyn FnMut() -> T
>);
115 fn new
<F
: '
static + FnOnce() -> T
>(f
: F
) -> Thunk
<T
> {
116 let mut option
= Some(f
);
117 // This should not trigger redundant_closure (#1439)
118 Thunk(Box
::new(move || option
.take().unwrap()()))
121 fn unwrap(self) -> T
{
122 let Thunk(mut f
) = self;
128 let thunk
= Thunk
::new(|| println
!("Hello, world!"));
134 fn foo2(_
: u8) -> u8 {
138 fn all
<X
, F
>(x
: &[X
], y
: &X
, f
: F
) -> bool
140 F
: Fn(&X
, &X
) -> bool
,
142 x
.iter().all(|e
| f(e
, y
))
145 fn below(x
: &u8, y
: &u8) -> bool
{
149 unsafe fn unsafe_fn(_
: u8) {}
151 fn divergent(_
: u8) -> ! {
155 fn generic
<T
>(_
: T
) -> u8 {
159 fn passes_fn_mut(mut x
: Box
<dyn FnMut()>) {
160 requires_fn_once(|| x());
162 fn requires_fn_once
<T
: FnOnce()>(_
: T
) {}
164 fn test_redundant_closure_with_function_pointer() {
165 type FnPtrType
= fn(u8);
166 let foo_ptr
: FnPtrType
= foo
;
167 let a
= Some(1u8).map(|a
| foo_ptr(a
));
170 fn test_redundant_closure_with_another_closure() {
171 let closure
= |a
| println
!("{}", a
);
172 let a
= Some(1u8).map(|a
| closure(a
));
175 fn make_lazy(f
: impl Fn() -> fn(u8) -> u8) -> impl Fn(u8) -> u8 {
176 // Currently f is called when result of make_lazy is called.
177 // If the closure is removed, f will be called when make_lazy itself is
178 // called. This changes semantics, so the closure must stay.
179 Box
::new(move |x
| f()(x
))
182 fn call
<F
: FnOnce(&mut String
) -> String
>(f
: F
) -> String
{
183 f(&mut "Hello".to_owned())
185 fn test_difference_in_mutability() {
190 impl std
::ops
::Deref
for Bar
{
192 fn deref(&self) -> &str {
197 fn test_deref_with_trait_method() {
198 let _
= [Bar
].iter().map(|s
| s
.to_string()).collect
::<Vec
<_
>>();
201 fn mutable_closure_used_again(x
: Vec
<i32>, y
: Vec
<i32>, z
: Vec
<i32>) {
202 let mut res
= Vec
::new();
203 let mut add_to_res
= |n
| res
.push(n
);
204 x
.into_iter().for_each(|x
| add_to_res(x
));
205 y
.into_iter().for_each(|x
| add_to_res(x
));
206 z
.into_iter().for_each(|x
| add_to_res(x
));
209 fn mutable_closure_in_loop() {
211 let mut closure
= |n
| value
+= n
;
213 Some(1).map(|n
| closure(n
));
216 let mut in_loop
= |n
| value
+= n
;
217 Some(1).map(|n
| in_loop(n
));
221 fn late_bound_lifetimes() {
222 fn take_asref_path
<P
: AsRef
<Path
>>(path
: P
) {}
224 fn map_str
<F
>(thunk
: F
)
230 fn map_str_to_path
<F
>(thunk
: F
)
232 F
: FnOnce(&str) -> &Path
,
235 map_str(|s
| take_asref_path(s
));
236 map_str_to_path(|s
| s
.as_ref());
239 mod type_param_bound
{
244 fn take
<T
: '
static>(_
: T
) {}
246 fn test
<X
: Trait
>() {
247 // don't lint, but it's questionable that rust requires a cast
249 take(X
::fun
as fn());
253 // #8073 Don't replace closure with `Arc<F>` or `Rc<F>`
255 let rc
= std
::rc
::Rc
::new(|| 7);
256 let arc
= std
::sync
::Arc
::new(|n
| n
+ 1);
257 let ref_arc
= &std
::sync
::Arc
::new(|_
| 5);
260 (0..5).map(|n
| arc(n
));
261 Some(4).map(|n
| ref_arc(n
));
264 // #8460 Don't replace closures with params bounded as `ref`
269 impl From
<&A
> for B
{
270 fn from(A
: &A
) -> Self {
277 Some(A
).map(|a
| B
::from(&a
));
279 Some(A
).map(|ref a
| B
::from(a
));
283 // #7812 False positive on coerced closure
284 fn coerced_closure() {
285 fn function_returning_unit
<F
: FnMut(i32)>(f
: F
) {}
286 function_returning_unit(|x
| std
::process
::exit(x
));
288 fn arr() -> &'
static [u8; 0] {
291 fn slice_fn(_
: impl FnOnce() -> &'
static [u8]) {}
295 // https://github.com/rust-lang/rust-clippy/issues/7861
297 fn f(_
: impl Fn(usize) -> Box
<dyn std
::any
::Any
>) {}
301 // https://github.com/rust-lang/rust-clippy/issues/5939
302 fn not_general_enough() {
303 fn f(_
: impl FnMut(&Path
) -> std
::io
::Result
<()>) {}
304 f(|path
| std
::fs
::remove_file(path
));
307 // https://github.com/rust-lang/rust-clippy/issues/9369
308 pub fn mutable_impl_fn_mut(mut f
: impl FnMut(), mut f_used_once
: impl FnMut()) -> impl FnMut() {
309 fn takes_fn_mut(_
: impl FnMut()) {}
310 takes_fn_mut(|| f());
312 fn takes_fn_once(_
: impl FnOnce()) {}
313 takes_fn_once(|| f());
317 move || takes_fn_mut(|| f_used_once())
320 impl dyn TestTrait
+ '_
{
321 fn method_on_dyn(&self) -> bool
{
326 // https://github.com/rust-lang/rust-clippy/issues/7746
327 fn angle_brackets_and_substs() {
328 let array_opt
: Option
<&[u8; 3]> = Some(&[4, 8, 7]);
329 array_opt
.map(|a
| a
.as_slice());
331 let slice_opt
: Option
<&[u8]> = Some(b
"slice");
332 slice_opt
.map(|s
| s
.len());
334 let ptr_opt
: Option
<*const usize> = Some(&487);
335 ptr_opt
.map(|p
| p
.is_null());
337 let test_struct
= TestStruct { some_ref: &487 }
;
338 let dyn_opt
: Option
<&dyn TestTrait
> = Some(&test_struct
);
339 dyn_opt
.map(|d
| d
.method_on_dyn());