]>
Commit | Line | Data |
---|---|---|
04454e1e FG |
1 | // FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934 |
2 | // // run-rustfix | |
04454e1e | 3 | #![warn(clippy::significant_drop_in_scrutinee)] |
2b03887a FG |
4 | #![allow(dead_code, unused_assignments)] |
5 | #![allow(clippy::match_single_binding, clippy::single_match, clippy::uninlined_format_args)] | |
04454e1e | 6 | |
923072b8 | 7 | use std::num::ParseIntError; |
04454e1e FG |
8 | use std::ops::Deref; |
9 | use std::sync::atomic::{AtomicU64, Ordering}; | |
923072b8 | 10 | use std::sync::RwLock; |
04454e1e FG |
11 | use std::sync::{Mutex, MutexGuard}; |
12 | ||
13 | struct State {} | |
14 | ||
15 | impl State { | |
16 | fn foo(&self) -> bool { | |
17 | true | |
18 | } | |
19 | ||
20 | fn bar(&self) {} | |
21 | } | |
22 | ||
23 | fn should_not_trigger_lint_with_mutex_guard_outside_match() { | |
24 | let mutex = Mutex::new(State {}); | |
25 | ||
26 | // Should not trigger lint because the temporary should drop at the `;` on line before the match | |
27 | let is_foo = mutex.lock().unwrap().foo(); | |
28 | match is_foo { | |
29 | true => { | |
30 | mutex.lock().unwrap().bar(); | |
923072b8 FG |
31 | }, |
32 | false => {}, | |
04454e1e FG |
33 | }; |
34 | } | |
35 | ||
36 | fn should_not_trigger_lint_with_mutex_guard_when_taking_ownership_in_match() { | |
37 | let mutex = Mutex::new(State {}); | |
38 | ||
39 | // Should not trigger lint because the scrutinee is explicitly returning the MutexGuard, | |
40 | // so its lifetime should not be surprising. | |
41 | match mutex.lock() { | |
42 | Ok(guard) => { | |
43 | guard.foo(); | |
44 | mutex.lock().unwrap().bar(); | |
923072b8 FG |
45 | }, |
46 | _ => {}, | |
04454e1e FG |
47 | }; |
48 | } | |
49 | ||
50 | fn should_trigger_lint_with_mutex_guard_in_match_scrutinee() { | |
51 | let mutex = Mutex::new(State {}); | |
52 | ||
53 | // Should trigger lint because the lifetime of the temporary MutexGuard is surprising because it | |
54 | // is preserved until the end of the match, but there is no clear indication that this is the | |
55 | // case. | |
56 | match mutex.lock().unwrap().foo() { | |
57 | true => { | |
58 | mutex.lock().unwrap().bar(); | |
923072b8 FG |
59 | }, |
60 | false => {}, | |
04454e1e FG |
61 | }; |
62 | } | |
63 | ||
064997fb FG |
64 | fn should_not_trigger_lint_with_mutex_guard_in_match_scrutinee_when_lint_allowed() { |
65 | let mutex = Mutex::new(State {}); | |
66 | ||
67 | // Lint should not be triggered because it is "allowed" below. | |
68 | #[allow(clippy::significant_drop_in_scrutinee)] | |
69 | match mutex.lock().unwrap().foo() { | |
70 | true => { | |
71 | mutex.lock().unwrap().bar(); | |
72 | }, | |
73 | false => {}, | |
74 | }; | |
75 | } | |
76 | ||
04454e1e FG |
77 | fn should_not_trigger_lint_for_insignificant_drop() { |
78 | // Should not trigger lint because there are no temporaries whose drops have a significant | |
79 | // side effect. | |
80 | match 1u64.to_string().is_empty() { | |
81 | true => { | |
82 | println!("It was empty") | |
923072b8 | 83 | }, |
04454e1e FG |
84 | false => { |
85 | println!("It was not empty") | |
923072b8 | 86 | }, |
04454e1e FG |
87 | } |
88 | } | |
89 | ||
90 | struct StateWithMutex { | |
91 | m: Mutex<u64>, | |
92 | } | |
93 | ||
94 | struct MutexGuardWrapper<'a> { | |
95 | mg: MutexGuard<'a, u64>, | |
96 | } | |
97 | ||
98 | impl<'a> MutexGuardWrapper<'a> { | |
99 | fn get_the_value(&self) -> u64 { | |
100 | *self.mg.deref() | |
101 | } | |
102 | } | |
103 | ||
104 | struct MutexGuardWrapperWrapper<'a> { | |
105 | mg: MutexGuardWrapper<'a>, | |
106 | } | |
107 | ||
108 | impl<'a> MutexGuardWrapperWrapper<'a> { | |
109 | fn get_the_value(&self) -> u64 { | |
110 | *self.mg.mg.deref() | |
111 | } | |
112 | } | |
113 | ||
114 | impl StateWithMutex { | |
115 | fn lock_m(&self) -> MutexGuardWrapper<'_> { | |
116 | MutexGuardWrapper { | |
117 | mg: self.m.lock().unwrap(), | |
118 | } | |
119 | } | |
120 | ||
121 | fn lock_m_m(&self) -> MutexGuardWrapperWrapper<'_> { | |
122 | MutexGuardWrapperWrapper { | |
123 | mg: MutexGuardWrapper { | |
124 | mg: self.m.lock().unwrap(), | |
125 | }, | |
126 | } | |
127 | } | |
128 | ||
129 | fn foo(&self) -> bool { | |
130 | true | |
131 | } | |
132 | ||
133 | fn bar(&self) {} | |
134 | } | |
135 | ||
136 | fn should_trigger_lint_with_wrapped_mutex() { | |
137 | let s = StateWithMutex { m: Mutex::new(1) }; | |
138 | ||
139 | // Should trigger lint because a temporary contains a type with a significant drop and its | |
140 | // lifetime is not obvious. Additionally, it is not obvious from looking at the scrutinee that | |
141 | // the temporary contains such a type, making it potentially even more surprising. | |
142 | match s.lock_m().get_the_value() { | |
143 | 1 => { | |
144 | println!("Got 1. Is it still 1?"); | |
145 | println!("{}", s.lock_m().get_the_value()); | |
923072b8 | 146 | }, |
04454e1e FG |
147 | 2 => { |
148 | println!("Got 2. Is it still 2?"); | |
149 | println!("{}", s.lock_m().get_the_value()); | |
923072b8 FG |
150 | }, |
151 | _ => {}, | |
04454e1e FG |
152 | } |
153 | println!("All done!"); | |
154 | } | |
155 | ||
156 | fn should_trigger_lint_with_double_wrapped_mutex() { | |
157 | let s = StateWithMutex { m: Mutex::new(1) }; | |
158 | ||
159 | // Should trigger lint because a temporary contains a type which further contains a type with a | |
160 | // significant drop and its lifetime is not obvious. Additionally, it is not obvious from | |
161 | // looking at the scrutinee that the temporary contains such a type, making it potentially even | |
162 | // more surprising. | |
163 | match s.lock_m_m().get_the_value() { | |
164 | 1 => { | |
165 | println!("Got 1. Is it still 1?"); | |
166 | println!("{}", s.lock_m().get_the_value()); | |
923072b8 | 167 | }, |
04454e1e FG |
168 | 2 => { |
169 | println!("Got 2. Is it still 2?"); | |
170 | println!("{}", s.lock_m().get_the_value()); | |
923072b8 FG |
171 | }, |
172 | _ => {}, | |
04454e1e FG |
173 | } |
174 | println!("All done!"); | |
175 | } | |
176 | ||
177 | struct Counter { | |
178 | i: AtomicU64, | |
179 | } | |
180 | ||
181 | #[clippy::has_significant_drop] | |
182 | struct CounterWrapper<'a> { | |
183 | counter: &'a Counter, | |
184 | } | |
185 | ||
186 | impl<'a> CounterWrapper<'a> { | |
187 | fn new(counter: &Counter) -> CounterWrapper { | |
188 | counter.i.fetch_add(1, Ordering::Relaxed); | |
189 | CounterWrapper { counter } | |
190 | } | |
191 | } | |
192 | ||
193 | impl<'a> Drop for CounterWrapper<'a> { | |
194 | fn drop(&mut self) { | |
195 | self.counter.i.fetch_sub(1, Ordering::Relaxed); | |
196 | } | |
197 | } | |
198 | ||
199 | impl Counter { | |
200 | fn temp_increment(&self) -> Vec<CounterWrapper> { | |
201 | vec![CounterWrapper::new(self), CounterWrapper::new(self)] | |
202 | } | |
203 | } | |
204 | ||
205 | fn should_trigger_lint_for_vec() { | |
206 | let counter = Counter { i: AtomicU64::new(0) }; | |
207 | ||
208 | // Should trigger lint because the temporary in the scrutinee returns a collection of types | |
209 | // which have significant drops. The types with significant drops are also non-obvious when | |
210 | // reading the expression in the scrutinee. | |
211 | match counter.temp_increment().len() { | |
212 | 2 => { | |
213 | let current_count = counter.i.load(Ordering::Relaxed); | |
214 | println!("Current count {}", current_count); | |
215 | assert_eq!(current_count, 0); | |
923072b8 FG |
216 | }, |
217 | 1 => {}, | |
218 | 3 => {}, | |
219 | _ => {}, | |
04454e1e FG |
220 | }; |
221 | } | |
222 | ||
223 | struct StateWithField { | |
224 | s: String, | |
225 | } | |
226 | ||
227 | // Should trigger lint only on the type in the tuple which is created using a temporary | |
228 | // with a significant drop. Additionally, this test ensures that the format of the tuple | |
229 | // is preserved correctly in the suggestion. | |
230 | fn should_trigger_lint_for_tuple_in_scrutinee() { | |
231 | let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() }); | |
232 | ||
233 | { | |
234 | match (mutex1.lock().unwrap().s.len(), true) { | |
235 | (3, _) => { | |
236 | println!("started"); | |
237 | mutex1.lock().unwrap().s.len(); | |
238 | println!("done"); | |
923072b8 FG |
239 | }, |
240 | (_, _) => {}, | |
04454e1e FG |
241 | }; |
242 | ||
243 | match (true, mutex1.lock().unwrap().s.len(), true) { | |
244 | (_, 3, _) => { | |
245 | println!("started"); | |
246 | mutex1.lock().unwrap().s.len(); | |
247 | println!("done"); | |
923072b8 FG |
248 | }, |
249 | (_, _, _) => {}, | |
04454e1e FG |
250 | }; |
251 | ||
252 | let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() }); | |
253 | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) { | |
254 | (3, _, 3) => { | |
255 | println!("started"); | |
256 | mutex1.lock().unwrap().s.len(); | |
257 | mutex2.lock().unwrap().s.len(); | |
258 | println!("done"); | |
923072b8 FG |
259 | }, |
260 | (_, _, _) => {}, | |
04454e1e FG |
261 | }; |
262 | ||
263 | let mutex3 = Mutex::new(StateWithField { s: "three".to_owned() }); | |
264 | match mutex3.lock().unwrap().s.as_str() { | |
265 | "three" => { | |
266 | println!("started"); | |
267 | mutex1.lock().unwrap().s.len(); | |
268 | mutex2.lock().unwrap().s.len(); | |
269 | println!("done"); | |
923072b8 FG |
270 | }, |
271 | _ => {}, | |
04454e1e FG |
272 | }; |
273 | ||
04454e1e FG |
274 | match (true, mutex3.lock().unwrap().s.as_str()) { |
275 | (_, "three") => { | |
276 | println!("started"); | |
277 | mutex1.lock().unwrap().s.len(); | |
278 | mutex2.lock().unwrap().s.len(); | |
279 | println!("done"); | |
923072b8 FG |
280 | }, |
281 | (_, _) => {}, | |
04454e1e FG |
282 | }; |
283 | } | |
284 | } | |
285 | ||
286 | // Should trigger lint when either side of a binary operation creates a temporary with a | |
287 | // significant drop. | |
288 | // To avoid potential unnecessary copies or creating references that would trigger the significant | |
289 | // drop problem, the lint recommends moving the entire binary operation. | |
290 | fn should_trigger_lint_for_accessing_field_in_mutex_in_one_side_of_binary_op() { | |
291 | let mutex = Mutex::new(StateWithField { s: "state".to_owned() }); | |
292 | ||
293 | match mutex.lock().unwrap().s.len() > 1 { | |
294 | true => { | |
295 | mutex.lock().unwrap().s.len(); | |
923072b8 FG |
296 | }, |
297 | false => {}, | |
04454e1e FG |
298 | }; |
299 | ||
300 | match 1 < mutex.lock().unwrap().s.len() { | |
301 | true => { | |
302 | mutex.lock().unwrap().s.len(); | |
923072b8 FG |
303 | }, |
304 | false => {}, | |
04454e1e FG |
305 | }; |
306 | } | |
307 | ||
308 | // Should trigger lint when both sides of a binary operation creates a temporary with a | |
309 | // significant drop. | |
310 | // To avoid potential unnecessary copies or creating references that would trigger the significant | |
311 | // drop problem, the lint recommends moving the entire binary operation. | |
312 | fn should_trigger_lint_for_accessing_fields_in_mutex_in_both_sides_of_binary_op() { | |
313 | let mutex1 = Mutex::new(StateWithField { s: "state".to_owned() }); | |
923072b8 FG |
314 | let mutex2 = Mutex::new(StateWithField { |
315 | s: "statewithfield".to_owned(), | |
316 | }); | |
04454e1e FG |
317 | |
318 | match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() { | |
319 | true => { | |
923072b8 FG |
320 | println!( |
321 | "{} < {}", | |
322 | mutex1.lock().unwrap().s.len(), | |
323 | mutex2.lock().unwrap().s.len() | |
324 | ); | |
325 | }, | |
326 | false => {}, | |
04454e1e FG |
327 | }; |
328 | ||
329 | match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() { | |
330 | true => { | |
923072b8 FG |
331 | println!( |
332 | "{} >= {}", | |
333 | mutex1.lock().unwrap().s.len(), | |
334 | mutex2.lock().unwrap().s.len() | |
335 | ); | |
336 | }, | |
337 | false => {}, | |
04454e1e FG |
338 | }; |
339 | } | |
340 | ||
341 | fn should_not_trigger_lint_for_closure_in_scrutinee() { | |
342 | let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() }); | |
343 | ||
344 | let get_mutex_guard = || mutex1.lock().unwrap().s.len(); | |
345 | ||
346 | // Should not trigger lint because the temporary with a significant drop will be dropped | |
347 | // at the end of the closure, so the MutexGuard will be unlocked and not have a potentially | |
348 | // surprising lifetime. | |
349 | match get_mutex_guard() > 1 { | |
350 | true => { | |
351 | mutex1.lock().unwrap().s.len(); | |
923072b8 FG |
352 | }, |
353 | false => {}, | |
04454e1e FG |
354 | }; |
355 | } | |
356 | ||
357 | fn should_trigger_lint_for_return_from_closure_in_scrutinee() { | |
358 | let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() }); | |
359 | ||
360 | let get_mutex_guard = || mutex1.lock().unwrap(); | |
361 | ||
362 | // Should trigger lint because the temporary with a significant drop is returned from the | |
363 | // closure but not used directly in any match arms, so it has a potentially surprising lifetime. | |
364 | match get_mutex_guard().s.len() > 1 { | |
365 | true => { | |
366 | mutex1.lock().unwrap().s.len(); | |
923072b8 FG |
367 | }, |
368 | false => {}, | |
04454e1e FG |
369 | }; |
370 | } | |
371 | ||
372 | fn should_trigger_lint_for_return_from_match_in_scrutinee() { | |
373 | let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() }); | |
374 | let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() }); | |
375 | ||
376 | let i = 100; | |
377 | ||
378 | // Should trigger lint because the nested match within the scrutinee returns a temporary with a | |
379 | // significant drop is but not used directly in any match arms, so it has a potentially | |
380 | // surprising lifetime. | |
923072b8 FG |
381 | match match i { |
382 | 100 => mutex1.lock().unwrap(), | |
383 | _ => mutex2.lock().unwrap(), | |
384 | } | |
385 | .s | |
386 | .len() | |
387 | > 1 | |
388 | { | |
04454e1e FG |
389 | true => { |
390 | mutex1.lock().unwrap().s.len(); | |
923072b8 | 391 | }, |
04454e1e FG |
392 | false => { |
393 | println!("nothing to do here"); | |
923072b8 | 394 | }, |
04454e1e FG |
395 | }; |
396 | } | |
397 | ||
398 | fn should_trigger_lint_for_return_from_if_in_scrutinee() { | |
399 | let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() }); | |
400 | let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() }); | |
401 | ||
402 | let i = 100; | |
403 | ||
404 | // Should trigger lint because the nested if-expression within the scrutinee returns a temporary | |
405 | // with a significant drop is but not used directly in any match arms, so it has a potentially | |
406 | // surprising lifetime. | |
923072b8 FG |
407 | match if i > 1 { |
408 | mutex1.lock().unwrap() | |
409 | } else { | |
410 | mutex2.lock().unwrap() | |
411 | } | |
412 | .s | |
413 | .len() | |
414 | > 1 | |
415 | { | |
04454e1e FG |
416 | true => { |
417 | mutex1.lock().unwrap().s.len(); | |
923072b8 FG |
418 | }, |
419 | false => {}, | |
04454e1e FG |
420 | }; |
421 | } | |
422 | ||
423 | fn should_not_trigger_lint_for_if_in_scrutinee() { | |
424 | let mutex = Mutex::new(StateWithField { s: "state".to_owned() }); | |
425 | ||
426 | let i = 100; | |
427 | ||
428 | // Should not trigger the lint because the temporary with a significant drop *is* dropped within | |
429 | // the body of the if-expression nested within the match scrutinee, and therefore does not have | |
430 | // a potentially surprising lifetime. | |
923072b8 FG |
431 | match if i > 1 { |
432 | mutex.lock().unwrap().s.len() > 1 | |
433 | } else { | |
434 | false | |
435 | } { | |
04454e1e FG |
436 | true => { |
437 | mutex.lock().unwrap().s.len(); | |
923072b8 FG |
438 | }, |
439 | false => {}, | |
04454e1e FG |
440 | }; |
441 | } | |
442 | ||
443 | struct StateWithBoxedMutexGuard { | |
444 | u: Mutex<u64>, | |
445 | } | |
446 | ||
447 | impl StateWithBoxedMutexGuard { | |
448 | fn new() -> StateWithBoxedMutexGuard { | |
449 | StateWithBoxedMutexGuard { u: Mutex::new(42) } | |
450 | } | |
451 | fn lock(&self) -> Box<MutexGuard<u64>> { | |
452 | Box::new(self.u.lock().unwrap()) | |
453 | } | |
454 | } | |
455 | ||
456 | fn should_trigger_lint_for_boxed_mutex_guard() { | |
457 | let s = StateWithBoxedMutexGuard::new(); | |
458 | ||
459 | // Should trigger lint because a temporary Box holding a type with a significant drop in a match | |
460 | // scrutinee may have a potentially surprising lifetime. | |
461 | match s.lock().deref().deref() { | |
462 | 0 | 1 => println!("Value was less than 2"), | |
463 | _ => println!("Value is {}", s.lock().deref()), | |
464 | }; | |
465 | } | |
466 | ||
467 | struct StateStringWithBoxedMutexGuard { | |
468 | s: Mutex<String>, | |
469 | } | |
470 | ||
471 | impl StateStringWithBoxedMutexGuard { | |
472 | fn new() -> StateStringWithBoxedMutexGuard { | |
923072b8 FG |
473 | StateStringWithBoxedMutexGuard { |
474 | s: Mutex::new("A String".to_owned()), | |
475 | } | |
04454e1e FG |
476 | } |
477 | fn lock(&self) -> Box<MutexGuard<String>> { | |
478 | Box::new(self.s.lock().unwrap()) | |
479 | } | |
480 | } | |
481 | ||
482 | fn should_trigger_lint_for_boxed_mutex_guard_holding_string() { | |
483 | let s = StateStringWithBoxedMutexGuard::new(); | |
484 | ||
485 | let matcher = String::from("A String"); | |
486 | ||
487 | // Should trigger lint because a temporary Box holding a type with a significant drop in a match | |
488 | // scrutinee may have a potentially surprising lifetime. | |
489 | match s.lock().deref().deref() { | |
490 | matcher => println!("Value is {}", s.lock().deref()), | |
491 | _ => println!("Value was not a match"), | |
492 | }; | |
493 | } | |
494 | ||
04454e1e FG |
495 | struct StateWithIntField { |
496 | i: u64, | |
497 | } | |
498 | ||
499 | // Should trigger lint when either side of an assign expression contains a temporary with a | |
500 | // significant drop, because the temporary's lifetime will be extended to the end of the match. | |
501 | // To avoid potential unnecessary copies or creating references that would trigger the significant | |
502 | // drop problem, the lint recommends moving the entire binary operation. | |
503 | fn should_trigger_lint_in_assign_expr() { | |
504 | let mutex = Mutex::new(StateWithIntField { i: 10 }); | |
505 | ||
506 | let mut i = 100; | |
507 | ||
508 | match mutex.lock().unwrap().i = i { | |
509 | _ => { | |
510 | println!("{}", mutex.lock().unwrap().i); | |
923072b8 | 511 | }, |
04454e1e FG |
512 | }; |
513 | ||
514 | match i = mutex.lock().unwrap().i { | |
515 | _ => { | |
516 | println!("{}", mutex.lock().unwrap().i); | |
923072b8 | 517 | }, |
04454e1e FG |
518 | }; |
519 | ||
520 | match mutex.lock().unwrap().i += 1 { | |
521 | _ => { | |
522 | println!("{}", mutex.lock().unwrap().i); | |
923072b8 | 523 | }, |
04454e1e FG |
524 | }; |
525 | ||
526 | match i += mutex.lock().unwrap().i { | |
527 | _ => { | |
528 | println!("{}", mutex.lock().unwrap().i); | |
923072b8 | 529 | }, |
04454e1e FG |
530 | }; |
531 | } | |
532 | ||
533 | #[derive(Debug)] | |
534 | enum RecursiveEnum { | |
923072b8 | 535 | Foo(Option<Box<RecursiveEnum>>), |
04454e1e FG |
536 | } |
537 | ||
538 | #[derive(Debug)] | |
539 | enum GenericRecursiveEnum<T> { | |
923072b8 | 540 | Foo(T, Option<Box<GenericRecursiveEnum<T>>>), |
04454e1e FG |
541 | } |
542 | ||
543 | fn should_not_cause_stack_overflow() { | |
544 | // Test that when a type recursively contains itself, a stack overflow does not occur when | |
545 | // checking sub-types for significant drops. | |
546 | let f = RecursiveEnum::Foo(Some(Box::new(RecursiveEnum::Foo(None)))); | |
547 | match f { | |
548 | RecursiveEnum::Foo(Some(f)) => { | |
549 | println!("{:?}", f) | |
923072b8 | 550 | }, |
04454e1e FG |
551 | RecursiveEnum::Foo(f) => { |
552 | println!("{:?}", f) | |
923072b8 | 553 | }, |
04454e1e FG |
554 | } |
555 | ||
556 | let f = GenericRecursiveEnum::Foo(1u64, Some(Box::new(GenericRecursiveEnum::Foo(2u64, None)))); | |
557 | match f { | |
558 | GenericRecursiveEnum::Foo(i, Some(f)) => { | |
559 | println!("{} {:?}", i, f) | |
923072b8 | 560 | }, |
04454e1e FG |
561 | GenericRecursiveEnum::Foo(i, f) => { |
562 | println!("{} {:?}", i, f) | |
923072b8 FG |
563 | }, |
564 | } | |
565 | } | |
566 | ||
567 | fn should_not_produce_lint_for_try_desugar() -> Result<u64, ParseIntError> { | |
568 | // TryDesugar (i.e. using `?` for a Result type) will turn into a match but is out of scope | |
569 | // for this lint | |
570 | let rwlock = RwLock::new("1".to_string()); | |
571 | let result = rwlock.read().unwrap().parse::<u64>()?; | |
572 | println!("{}", result); | |
573 | rwlock.write().unwrap().push('2'); | |
574 | Ok(result) | |
575 | } | |
576 | ||
577 | struct ResultReturner { | |
578 | s: String, | |
579 | } | |
580 | ||
581 | impl ResultReturner { | |
582 | fn to_number(&self) -> Result<i64, ParseIntError> { | |
583 | self.s.parse::<i64>() | |
584 | } | |
585 | } | |
586 | ||
587 | fn should_trigger_lint_for_non_ref_move_and_clone_suggestion() { | |
588 | let rwlock = RwLock::<ResultReturner>::new(ResultReturner { s: "1".to_string() }); | |
589 | match rwlock.read().unwrap().to_number() { | |
590 | Ok(n) => println!("Converted to number: {}", n), | |
591 | Err(e) => println!("Could not convert {} to number", e), | |
592 | }; | |
593 | } | |
594 | ||
595 | fn should_trigger_lint_for_read_write_lock_for_loop() { | |
596 | // For-in loops desugar to match expressions and are prone to the type of deadlock this lint is | |
597 | // designed to look for. | |
598 | let rwlock = RwLock::<Vec<String>>::new(vec!["1".to_string()]); | |
599 | for s in rwlock.read().unwrap().iter() { | |
600 | println!("{}", s); | |
04454e1e FG |
601 | } |
602 | } | |
603 | ||
064997fb FG |
604 | fn do_bar(mutex: &Mutex<State>) { |
605 | mutex.lock().unwrap().bar(); | |
606 | } | |
607 | ||
608 | fn should_trigger_lint_without_significant_drop_in_arm() { | |
609 | let mutex = Mutex::new(State {}); | |
610 | ||
611 | // Should trigger lint because the lifetime of the temporary MutexGuard is surprising because it | |
612 | // is preserved until the end of the match, but there is no clear indication that this is the | |
613 | // case. | |
614 | match mutex.lock().unwrap().foo() { | |
615 | true => do_bar(&mutex), | |
616 | false => {}, | |
617 | }; | |
618 | } | |
619 | ||
620 | fn should_not_trigger_on_significant_iterator_drop() { | |
621 | let lines = std::io::stdin().lines(); | |
622 | for line in lines { | |
623 | println!("foo: {}", line.unwrap()); | |
624 | } | |
625 | } | |
626 | ||
04454e1e | 627 | fn main() {} |