6 clippy::redundant_closure_call,
7 clippy::needless_pass_by_value,
8 clippy::option_map_unit_fn,
9 clippy::needless_borrow
11 #![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)]
13 use std::path::{Path, PathBuf};
21 macro_rules! closure_mac {
28 let a = Some(1u8).map(foo);
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(std::vec::Vec::new); // special case vec!
33 let d = Some(1u8).map(|a| foo(foo2(a))); //is adjusted?
34 all(&[1, 2, 3], &&2, below); //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(generic);
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(TestStruct::foo);
88 let e = Some(TestStruct { some_ref: &i }).map(TestTrait::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(std::vec::Vec::clear);
92 let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo_unsafe());
94 let e = Some("str").map(std::string::ToString::to_string);
95 let e = Some('a').map(char::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(char::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()>) {
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(foo_ptr);
170 fn test_redundant_closure_with_another_closure() {
171 let closure = |a| println!("{}", a);
172 let a = Some(1u8).map(closure);
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(&mut add_to_res);
205 y.into_iter().for_each(&mut add_to_res);
206 z.into_iter().for_each(add_to_res);
209 fn mutable_closure_in_loop() {
211 let mut closure = |n| value += n;
213 Some(1).map(&mut closure);
216 let mut in_loop = |n| value += n;
217 Some(1).map(in_loop);
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));