1 mod bind_instead_of_map;
2 mod bytecount;
3 mod bytes_count_to_len;
4 mod bytes_nth;
5 mod case_sensitive_file_extension_comparisons;
6 mod chars_cmp;
7 mod chars_cmp_with_unwrap;
8 mod chars_last_cmp;
9 mod chars_last_cmp_with_unwrap;
10 mod chars_next_cmp;
11 mod chars_next_cmp_with_unwrap;
12 mod clear_with_drain;
13 mod clone_on_copy;
14 mod clone_on_ref_ptr;
15 mod cloned_instead_of_copied;
16 mod collapsible_str_replace;
17 mod drain_collect;
18 mod err_expect;
19 mod expect_fun_call;
20 mod expect_used;
21 mod extend_with_drain;
22 mod filetype_is_file;
23 mod filter_map;
24 mod filter_map_identity;
25 mod filter_map_next;
26 mod filter_next;
27 mod flat_map_identity;
28 mod flat_map_option;
29 mod from_iter_instead_of_collect;
30 mod get_first;
31 mod get_last_with_len;
32 mod get_unwrap;
33 mod implicit_clone;
34 mod inefficient_to_string;
35 mod inspect_for_each;
36 mod into_iter_on_ref;
37 mod is_digit_ascii_radix;
38 mod iter_cloned_collect;
39 mod iter_count;
40 mod iter_kv_map;
41 mod iter_next_slice;
42 mod iter_nth;
43 mod iter_nth_zero;
44 mod iter_on_single_or_empty_collections;
45 mod iter_overeager_cloned;
46 mod iter_skip_next;
47 mod iter_with_drain;
48 mod iterator_step_by_zero;
49 mod manual_next_back;
50 mod manual_ok_or;
51 mod manual_saturating_arithmetic;
52 mod manual_str_repeat;
53 mod manual_try_fold;
54 mod map_clone;
55 mod map_collect_result_unit;
56 mod map_err_ignore;
57 mod map_flatten;
58 mod map_identity;
59 mod map_unwrap_or;
60 mod mut_mutex_lock;
61 mod needless_collect;
62 mod needless_option_as_deref;
63 mod needless_option_take;
64 mod no_effect_replace;
65 mod obfuscated_if_else;
66 mod ok_expect;
67 mod open_options;
68 mod option_as_ref_deref;
69 mod option_map_or_none;
70 mod option_map_unwrap_or;
71 mod or_fun_call;
72 mod or_then_unwrap;
73 mod path_buf_push_overwrite;
74 mod range_zip_with_len;
75 mod repeat_once;
76 mod search_is_some;
77 mod seek_from_current;
78 mod seek_to_start_instead_of_rewind;
79 mod single_char_add_str;
80 mod single_char_insert_string;
81 mod single_char_pattern;
82 mod single_char_push_string;
83 mod skip_while_next;
84 mod stable_sort_primitive;
85 mod str_splitn;
86 mod string_extend_chars;
87 mod suspicious_command_arg_space;
88 mod suspicious_map;
89 mod suspicious_splitn;
90 mod suspicious_to_owned;
91 mod uninit_assumed_init;
92 mod unit_hash;
93 mod unnecessary_filter_map;
94 mod unnecessary_fold;
95 mod unnecessary_iter_cloned;
96 mod unnecessary_join;
97 mod unnecessary_lazy_eval;
98 mod unnecessary_literal_unwrap;
99 mod unnecessary_sort_by;
100 mod unnecessary_to_owned;
101 mod unwrap_or_else_default;
102 mod unwrap_used;
103 mod useless_asref;
104 mod utils;
105 mod vec_resize_to_zero;
106 mod verbose_file_reads;
107 mod wrong_self_convention;
108 mod zst_offset;
109
110 use bind_instead_of_map::BindInsteadOfMap;
111 use clippy_utils::consts::{constant, Constant};
112 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
113 use clippy_utils::msrvs::{self, Msrv};
114 use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
115 use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, return_ty};
116 use if_chain::if_chain;
117 use rustc_hir as hir;
118 use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind};
119 use rustc_hir_analysis::hir_ty_to_ty;
120 use rustc_lint::{LateContext, LateLintPass, LintContext};
121 use rustc_middle::lint::in_external_macro;
122 use rustc_middle::ty::{self, TraitRef, Ty};
123 use rustc_session::{declare_tool_lint, impl_lint_pass};
124 use rustc_span::{sym, Span};
125
126 declare_clippy_lint! {
127 /// ### What it does
128 /// Checks for usage of `cloned()` on an `Iterator` or `Option` where
129 /// `copied()` could be used instead.
130 ///
131 /// ### Why is this bad?
132 /// `copied()` is better because it guarantees that the type being cloned
133 /// implements `Copy`.
134 ///
135 /// ### Example
136 /// ```rust
137 /// [1, 2, 3].iter().cloned();
138 /// ```
139 /// Use instead:
140 /// ```rust
141 /// [1, 2, 3].iter().copied();
142 /// ```
143 #[clippy::version = "1.53.0"]
144 pub CLONED_INSTEAD_OF_COPIED,
145 pedantic,
146 "used `cloned` where `copied` could be used instead"
147 }
148
149 declare_clippy_lint! {
150 /// ### What it does
151 /// Checks for consecutive calls to `str::replace` (2 or more)
152 /// that can be collapsed into a single call.
153 ///
154 /// ### Why is this bad?
155 /// Consecutive `str::replace` calls scan the string multiple times
156 /// with repetitive code.
157 ///
158 /// ### Example
159 /// ```rust
160 /// let hello = "hesuo worpd"
161 /// .replace('s', "l")
162 /// .replace("u", "l")
163 /// .replace('p', "l");
164 /// ```
165 /// Use instead:
166 /// ```rust
167 /// let hello = "hesuo worpd".replace(['s', 'u', 'p'], "l");
168 /// ```
169 #[clippy::version = "1.65.0"]
170 pub COLLAPSIBLE_STR_REPLACE,
171 perf,
172 "collapse consecutive calls to str::replace (2 or more) into a single call"
173 }
174
175 declare_clippy_lint! {
176 /// ### What it does
177 /// Checks for usage of `_.cloned().<func>()` where call to `.cloned()` can be postponed.
178 ///
179 /// ### Why is this bad?
180 /// It's often inefficient to clone all elements of an iterator, when eventually, only some
181 /// of them will be consumed.
182 ///
183 /// ### Known Problems
184 /// This `lint` removes the side of effect of cloning items in the iterator.
185 /// A code that relies on that side-effect could fail.
186 ///
187 /// ### Examples
188 /// ```rust
189 /// # let vec = vec!["string".to_string()];
190 /// vec.iter().cloned().take(10);
191 /// vec.iter().cloned().last();
192 /// ```
193 ///
194 /// Use instead:
195 /// ```rust
196 /// # let vec = vec!["string".to_string()];
197 /// vec.iter().take(10).cloned();
198 /// vec.iter().last().cloned();
199 /// ```
200 #[clippy::version = "1.60.0"]
201 pub ITER_OVEREAGER_CLONED,
202 perf,
203 "using `cloned()` early with `Iterator::iter()` can lead to some performance inefficiencies"
204 }
205
206 declare_clippy_lint! {
207 /// ### What it does
208 /// Checks for usage of `Iterator::flat_map()` where `filter_map()` could be
209 /// used instead.
210 ///
211 /// ### Why is this bad?
212 /// When applicable, `filter_map()` is more clear since it shows that
213 /// `Option` is used to produce 0 or 1 items.
214 ///
215 /// ### Example
216 /// ```rust
217 /// let nums: Vec<i32> = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect();
218 /// ```
219 /// Use instead:
220 /// ```rust
221 /// let nums: Vec<i32> = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect();
222 /// ```
223 #[clippy::version = "1.53.0"]
224 pub FLAT_MAP_OPTION,
225 pedantic,
226 "used `flat_map` where `filter_map` could be used instead"
227 }
228
229 declare_clippy_lint! {
230 /// ### What it does
231 /// Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s.
232 ///
233 /// ### Why is this bad?
234 /// It is better to handle the `None` or `Err` case,
235 /// or at least call `.expect(_)` with a more helpful message. Still, for a lot of
236 /// quick-and-dirty code, `unwrap` is a good choice, which is why this lint is
237 /// `Allow` by default.
238 ///
239 /// `result.unwrap()` will let the thread panic on `Err` values.
240 /// Normally, you want to implement more sophisticated error handling,
241 /// and propagate errors upwards with `?` operator.
242 ///
243 /// Even if you want to panic on errors, not all `Error`s implement good
244 /// messages on display. Therefore, it may be beneficial to look at the places
245 /// where they may get displayed. Activate this lint to do just that.
246 ///
247 /// ### Examples
248 /// ```rust
249 /// # let option = Some(1);
250 /// # let result: Result<usize, ()> = Ok(1);
251 /// option.unwrap();
252 /// result.unwrap();
253 /// ```
254 ///
255 /// Use instead:
256 /// ```rust
257 /// # let option = Some(1);
258 /// # let result: Result<usize, ()> = Ok(1);
259 /// option.expect("more helpful message");
260 /// result.expect("more helpful message");
261 /// ```
262 ///
263 /// If [expect_used](#expect_used) is enabled, instead:
264 /// ```rust,ignore
265 /// # let option = Some(1);
266 /// # let result: Result<usize, ()> = Ok(1);
267 /// option?;
268 ///
269 /// // or
270 ///
271 /// result?;
272 /// ```
273 #[clippy::version = "1.45.0"]
274 pub UNWRAP_USED,
275 restriction,
276 "using `.unwrap()` on `Result` or `Option`, which should at least get a better message using `expect()`"
277 }
278
279 declare_clippy_lint! {
280 /// ### What it does
281 /// Checks for `.unwrap()` related calls on `Result`s and `Option`s that are constructed.
282 ///
283 /// ### Why is this bad?
284 /// It is better to write the value directly without the indirection.
285 ///
286 /// ### Examples
287 /// ```rust
288 /// let val1 = Some(1).unwrap();
289 /// let val2 = Ok::<_, ()>(1).unwrap();
290 /// let val3 = Err::<(), _>(1).unwrap_err();
291 /// ```
292 ///
293 /// Use instead:
294 /// ```rust
295 /// let val1 = 1;
296 /// let val2 = 1;
297 /// let val3 = 1;
298 /// ```
299 #[clippy::version = "1.69.0"]
300 pub UNNECESSARY_LITERAL_UNWRAP,
301 complexity,
302 "using `unwrap()` related calls on `Result` and `Option` constructors"
303 }
304
305 declare_clippy_lint! {
306 /// ### What it does
307 /// Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s.
308 ///
309 /// ### Why is this bad?
310 /// Usually it is better to handle the `None` or `Err` case.
311 /// Still, for a lot of quick-and-dirty code, `expect` is a good choice, which is why
312 /// this lint is `Allow` by default.
313 ///
314 /// `result.expect()` will let the thread panic on `Err`
315 /// values. Normally, you want to implement more sophisticated error handling,
316 /// and propagate errors upwards with `?` operator.
317 ///
318 /// ### Examples
319 /// ```rust,ignore
320 /// # let option = Some(1);
321 /// # let result: Result<usize, ()> = Ok(1);
322 /// option.expect("one");
323 /// result.expect("one");
324 /// ```
325 ///
326 /// Use instead:
327 /// ```rust,ignore
328 /// # let option = Some(1);
329 /// # let result: Result<usize, ()> = Ok(1);
330 /// option?;
331 ///
332 /// // or
333 ///
334 /// result?;
335 /// ```
336 #[clippy::version = "1.45.0"]
337 pub EXPECT_USED,
338 restriction,
339 "using `.expect()` on `Result` or `Option`, which might be better handled"
340 }
341
342 declare_clippy_lint! {
343 /// ### What it does
344 /// Checks for methods that should live in a trait
345 /// implementation of a `std` trait (see [llogiq's blog
346 /// post](http://llogiq.github.io/2015/07/30/traits.html) for further
347 /// information) instead of an inherent implementation.
348 ///
349 /// ### Why is this bad?
350 /// Implementing the traits improve ergonomics for users of
351 /// the code, often with very little cost. Also people seeing a `mul(...)`
352 /// method
353 /// may expect `*` to work equally, so you should have good reason to disappoint
354 /// them.
355 ///
356 /// ### Example
357 /// ```rust
358 /// struct X;
359 /// impl X {
360 /// fn add(&self, other: &X) -> X {
361 /// // ..
362 /// # X
363 /// }
364 /// }
365 /// ```
366 #[clippy::version = "pre 1.29.0"]
367 pub SHOULD_IMPLEMENT_TRAIT,
368 style,
369 "defining a method that should be implementing a std trait"
370 }
371
372 declare_clippy_lint! {
373 /// ### What it does
374 /// Checks for methods with certain name prefixes or suffixes, and which
375 /// do not adhere to standard conventions regarding how `self` is taken.
376 /// The actual rules are:
377 ///
378 /// |Prefix |Postfix |`self` taken | `self` type |
379 /// |-------|------------|-------------------------------|--------------|
380 /// |`as_` | none |`&self` or `&mut self` | any |
381 /// |`from_`| none | none | any |
382 /// |`into_`| none |`self` | any |
383 /// |`is_` | none |`&mut self` or `&self` or none | any |
384 /// |`to_` | `_mut` |`&mut self` | any |
385 /// |`to_` | not `_mut` |`self` | `Copy` |
386 /// |`to_` | not `_mut` |`&self` | not `Copy` |
387 ///
388 /// Note: Clippy doesn't trigger methods with `to_` prefix in:
389 /// - Traits definition.
390 /// Clippy can not tell if a type that implements a trait is `Copy` or not.
391 /// - Traits implementation, when `&self` is taken.
392 /// The method signature is controlled by the trait and often `&self` is required for all types that implement the trait
393 /// (see e.g. the `std::string::ToString` trait).
394 ///
395 /// Clippy allows `Pin<&Self>` and `Pin<&mut Self>` if `&self` and `&mut self` is required.
396 ///
397 /// Please find more info here:
398 /// https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
399 ///
400 /// ### Why is this bad?
401 /// Consistency breeds readability. If you follow the
402 /// conventions, your users won't be surprised that they, e.g., need to supply a
403 /// mutable reference to a `as_..` function.
404 ///
405 /// ### Example
406 /// ```rust
407 /// # struct X;
408 /// impl X {
409 /// fn as_str(self) -> &'static str {
410 /// // ..
411 /// # ""
412 /// }
413 /// }
414 /// ```
415 #[clippy::version = "pre 1.29.0"]
416 pub WRONG_SELF_CONVENTION,
417 style,
418 "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
419 }
420
421 declare_clippy_lint! {
422 /// ### What it does
423 /// Checks for usage of `ok().expect(..)`.
424 ///
425 /// ### Why is this bad?
426 /// Because you usually call `expect()` on the `Result`
427 /// directly to get a better error message.
428 ///
429 /// ### Known problems
430 /// The error type needs to implement `Debug`
431 ///
432 /// ### Example
433 /// ```rust
434 /// # let x = Ok::<_, ()>(());
435 /// x.ok().expect("why did I do this again?");
436 /// ```
437 ///
438 /// Use instead:
439 /// ```rust
440 /// # let x = Ok::<_, ()>(());
441 /// x.expect("why did I do this again?");
442 /// ```
443 #[clippy::version = "pre 1.29.0"]
444 pub OK_EXPECT,
445 style,
446 "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result"
447 }
448
449 declare_clippy_lint! {
450 /// ### What it does
451 /// Checks for `.err().expect()` calls on the `Result` type.
452 ///
453 /// ### Why is this bad?
454 /// `.expect_err()` can be called directly to avoid the extra type conversion from `err()`.
455 ///
456 /// ### Example
457 /// ```should_panic
458 /// let x: Result<u32, &str> = Ok(10);
459 /// x.err().expect("Testing err().expect()");
460 /// ```
461 /// Use instead:
462 /// ```should_panic
463 /// let x: Result<u32, &str> = Ok(10);
464 /// x.expect_err("Testing expect_err");
465 /// ```
466 #[clippy::version = "1.62.0"]
467 pub ERR_EXPECT,
468 style,
469 r#"using `.err().expect("")` when `.expect_err("")` can be used"#
470 }
471
472 declare_clippy_lint! {
473 /// ### What it does
474 /// Checks for usage of `_.unwrap_or_else(Default::default)` on `Option` and
475 /// `Result` values.
476 ///
477 /// ### Why is this bad?
478 /// Readability, these can be written as `_.unwrap_or_default`, which is
479 /// simpler and more concise.
480 ///
481 /// ### Examples
482 /// ```rust
483 /// # let x = Some(1);
484 /// x.unwrap_or_else(Default::default);
485 /// x.unwrap_or_else(u32::default);
486 /// ```
487 ///
488 /// Use instead:
489 /// ```rust
490 /// # let x = Some(1);
491 /// x.unwrap_or_default();
492 /// ```
493 #[clippy::version = "1.56.0"]
494 pub UNWRAP_OR_ELSE_DEFAULT,
495 style,
496 "using `.unwrap_or_else(Default::default)`, which is more succinctly expressed as `.unwrap_or_default()`"
497 }
498
499 declare_clippy_lint! {
500 /// ### What it does
501 /// Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or
502 /// `result.map(_).unwrap_or_else(_)`.
503 ///
504 /// ### Why is this bad?
505 /// Readability, these can be written more concisely (resp.) as
506 /// `option.map_or(_, _)`, `option.map_or_else(_, _)` and `result.map_or_else(_, _)`.
507 ///
508 /// ### Known problems
509 /// The order of the arguments is not in execution order
510 ///
511 /// ### Examples
512 /// ```rust
513 /// # let option = Some(1);
514 /// # let result: Result<usize, ()> = Ok(1);
515 /// # fn some_function(foo: ()) -> usize { 1 }
516 /// option.map(|a| a + 1).unwrap_or(0);
517 /// option.map(|a| a > 10).unwrap_or(false);
518 /// result.map(|a| a + 1).unwrap_or_else(some_function);
519 /// ```
520 ///
521 /// Use instead:
522 /// ```rust
523 /// # let option = Some(1);
524 /// # let result: Result<usize, ()> = Ok(1);
525 /// # fn some_function(foo: ()) -> usize { 1 }
526 /// option.map_or(0, |a| a + 1);
527 /// option.is_some_and(|a| a > 10);
528 /// result.map_or_else(some_function, |a| a + 1);
529 /// ```
530 #[clippy::version = "1.45.0"]
531 pub MAP_UNWRAP_OR,
532 pedantic,
533 "using `.map(f).unwrap_or(a)` or `.map(f).unwrap_or_else(func)`, which are more succinctly expressed as `map_or(a, f)` or `map_or_else(a, f)`"
534 }
535
536 declare_clippy_lint! {
537 /// ### What it does
538 /// Checks for usage of `_.map_or(None, _)`.
539 ///
540 /// ### Why is this bad?
541 /// Readability, this can be written more concisely as
542 /// `_.and_then(_)`.
543 ///
544 /// ### Known problems
545 /// The order of the arguments is not in execution order.
546 ///
547 /// ### Example
548 /// ```rust
549 /// # let opt = Some(1);
550 /// opt.map_or(None, |a| Some(a + 1));
551 /// ```
552 ///
553 /// Use instead:
554 /// ```rust
555 /// # let opt = Some(1);
556 /// opt.and_then(|a| Some(a + 1));
557 /// ```
558 #[clippy::version = "pre 1.29.0"]
559 pub OPTION_MAP_OR_NONE,
560 style,
561 "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`"
562 }
563
564 declare_clippy_lint! {
565 /// ### What it does
566 /// Checks for usage of `_.map_or(None, Some)`.
567 ///
568 /// ### Why is this bad?
569 /// Readability, this can be written more concisely as
570 /// `_.ok()`.
571 ///
572 /// ### Example
573 /// ```rust
574 /// # let r: Result<u32, &str> = Ok(1);
575 /// assert_eq!(Some(1), r.map_or(None, Some));
576 /// ```
577 ///
578 /// Use instead:
579 /// ```rust
580 /// # let r: Result<u32, &str> = Ok(1);
581 /// assert_eq!(Some(1), r.ok());
582 /// ```
583 #[clippy::version = "1.44.0"]
584 pub RESULT_MAP_OR_INTO_OPTION,
585 style,
586 "using `Result.map_or(None, Some)`, which is more succinctly expressed as `ok()`"
587 }
588
589 declare_clippy_lint! {
590 /// ### What it does
591 /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or
592 /// `_.or_else(|x| Err(y))`.
593 ///
594 /// ### Why is this bad?
595 /// Readability, this can be written more concisely as
596 /// `_.map(|x| y)` or `_.map_err(|x| y)`.
597 ///
598 /// ### Example
599 /// ```rust
600 /// # fn opt() -> Option<&'static str> { Some("42") }
601 /// # fn res() -> Result<&'static str, &'static str> { Ok("42") }
602 /// let _ = opt().and_then(|s| Some(s.len()));
603 /// let _ = res().and_then(|s| if s.len() == 42 { Ok(10) } else { Ok(20) });
604 /// let _ = res().or_else(|s| if s.len() == 42 { Err(10) } else { Err(20) });
605 /// ```
606 ///
607 /// The correct use would be:
608 ///
609 /// ```rust
610 /// # fn opt() -> Option<&'static str> { Some("42") }
611 /// # fn res() -> Result<&'static str, &'static str> { Ok("42") }
612 /// let _ = opt().map(|s| s.len());
613 /// let _ = res().map(|s| if s.len() == 42 { 10 } else { 20 });
614 /// let _ = res().map_err(|s| if s.len() == 42 { 10 } else { 20 });
615 /// ```
616 #[clippy::version = "1.45.0"]
617 pub BIND_INSTEAD_OF_MAP,
618 complexity,
619 "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`"
620 }
621
622 declare_clippy_lint! {
623 /// ### What it does
624 /// Checks for usage of `_.filter(_).next()`.
625 ///
626 /// ### Why is this bad?
627 /// Readability, this can be written more concisely as
628 /// `_.find(_)`.
629 ///
630 /// ### Example
631 /// ```rust
632 /// # let vec = vec![1];
633 /// vec.iter().filter(|x| **x == 0).next();
634 /// ```
635 ///
636 /// Use instead:
637 /// ```rust
638 /// # let vec = vec![1];
639 /// vec.iter().find(|x| **x == 0);
640 /// ```
641 #[clippy::version = "pre 1.29.0"]
642 pub FILTER_NEXT,
643 complexity,
644 "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`"
645 }
646
647 declare_clippy_lint! {
648 /// ### What it does
649 /// Checks for usage of `_.skip_while(condition).next()`.
650 ///
651 /// ### Why is this bad?
652 /// Readability, this can be written more concisely as
653 /// `_.find(!condition)`.
654 ///
655 /// ### Example
656 /// ```rust
657 /// # let vec = vec![1];
658 /// vec.iter().skip_while(|x| **x == 0).next();
659 /// ```
660 ///
661 /// Use instead:
662 /// ```rust
663 /// # let vec = vec![1];
664 /// vec.iter().find(|x| **x != 0);
665 /// ```
666 #[clippy::version = "1.42.0"]
667 pub SKIP_WHILE_NEXT,
668 complexity,
669 "using `skip_while(p).next()`, which is more succinctly expressed as `.find(!p)`"
670 }
671
672 declare_clippy_lint! {
673 /// ### What it does
674 /// Checks for usage of `_.map(_).flatten(_)` on `Iterator` and `Option`
675 ///
676 /// ### Why is this bad?
677 /// Readability, this can be written more concisely as
678 /// `_.flat_map(_)` for `Iterator` or `_.and_then(_)` for `Option`
679 ///
680 /// ### Example
681 /// ```rust
682 /// let vec = vec![vec![1]];
683 /// let opt = Some(5);
684 ///
685 /// vec.iter().map(|x| x.iter()).flatten();
686 /// opt.map(|x| Some(x * 2)).flatten();
687 /// ```
688 ///
689 /// Use instead:
690 /// ```rust
691 /// # let vec = vec![vec![1]];
692 /// # let opt = Some(5);
693 /// vec.iter().flat_map(|x| x.iter());
694 /// opt.and_then(|x| Some(x * 2));
695 /// ```
696 #[clippy::version = "1.31.0"]
697 pub MAP_FLATTEN,
698 complexity,
699 "using combinations of `flatten` and `map` which can usually be written as a single method call"
700 }
701
702 declare_clippy_lint! {
703 /// ### What it does
704 /// Checks for usage of `_.filter(_).map(_)` that can be written more simply
705 /// as `filter_map(_)`.
706 ///
707 /// ### Why is this bad?
708 /// Redundant code in the `filter` and `map` operations is poor style and
709 /// less performant.
710 ///
711 /// ### Example
712 /// ```rust
713 /// # #![allow(unused)]
714 /// (0_i32..10)
715 /// .filter(|n| n.checked_add(1).is_some())
716 /// .map(|n| n.checked_add(1).unwrap());
717 /// ```
718 ///
719 /// Use instead:
720 /// ```rust
721 /// # #[allow(unused)]
722 /// (0_i32..10).filter_map(|n| n.checked_add(1));
723 /// ```
724 #[clippy::version = "1.51.0"]
725 pub MANUAL_FILTER_MAP,
726 complexity,
727 "using `_.filter(_).map(_)` in a way that can be written more simply as `filter_map(_)`"
728 }
729
730 declare_clippy_lint! {
731 /// ### What it does
732 /// Checks for usage of `_.find(_).map(_)` that can be written more simply
733 /// as `find_map(_)`.
734 ///
735 /// ### Why is this bad?
736 /// Redundant code in the `find` and `map` operations is poor style and
737 /// less performant.
738 ///
739 /// ### Example
740 /// ```rust
741 /// (0_i32..10)
742 /// .find(|n| n.checked_add(1).is_some())
743 /// .map(|n| n.checked_add(1).unwrap());
744 /// ```
745 ///
746 /// Use instead:
747 /// ```rust
748 /// (0_i32..10).find_map(|n| n.checked_add(1));
749 /// ```
750 #[clippy::version = "1.51.0"]
751 pub MANUAL_FIND_MAP,
752 complexity,
753 "using `_.find(_).map(_)` in a way that can be written more simply as `find_map(_)`"
754 }
755
756 declare_clippy_lint! {
757 /// ### What it does
758 /// Checks for usage of `_.filter_map(_).next()`.
759 ///
760 /// ### Why is this bad?
761 /// Readability, this can be written more concisely as
762 /// `_.find_map(_)`.
763 ///
764 /// ### Example
765 /// ```rust
766 /// (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next();
767 /// ```
768 /// Can be written as
769 ///
770 /// ```rust
771 /// (0..3).find_map(|x| if x == 2 { Some(x) } else { None });
772 /// ```
773 #[clippy::version = "1.36.0"]
774 pub FILTER_MAP_NEXT,
775 pedantic,
776 "using combination of `filter_map` and `next` which can usually be written as a single method call"
777 }
778
779 declare_clippy_lint! {
780 /// ### What it does
781 /// Checks for usage of `flat_map(|x| x)`.
782 ///
783 /// ### Why is this bad?
784 /// Readability, this can be written more concisely by using `flatten`.
785 ///
786 /// ### Example
787 /// ```rust
788 /// # let iter = vec![vec![0]].into_iter();
789 /// iter.flat_map(|x| x);
790 /// ```
791 /// Can be written as
792 /// ```rust
793 /// # let iter = vec![vec![0]].into_iter();
794 /// iter.flatten();
795 /// ```
796 #[clippy::version = "1.39.0"]
797 pub FLAT_MAP_IDENTITY,
798 complexity,
799 "call to `flat_map` where `flatten` is sufficient"
800 }
801
802 declare_clippy_lint! {
803 /// ### What it does
804 /// Checks for an iterator or string search (such as `find()`,
805 /// `position()`, or `rposition()`) followed by a call to `is_some()` or `is_none()`.
806 ///
807 /// ### Why is this bad?
808 /// Readability, this can be written more concisely as:
809 /// * `_.any(_)`, or `_.contains(_)` for `is_some()`,
810 /// * `!_.any(_)`, or `!_.contains(_)` for `is_none()`.
811 ///
812 /// ### Example
813 /// ```rust
814 /// # #![allow(unused)]
815 /// let vec = vec![1];
816 /// vec.iter().find(|x| **x == 0).is_some();
817 ///
818 /// "hello world".find("world").is_none();
819 /// ```
820 ///
821 /// Use instead:
822 /// ```rust
823 /// let vec = vec![1];
824 /// vec.iter().any(|x| *x == 0);
825 ///
826 /// # #[allow(unused)]
827 /// !"hello world".contains("world");
828 /// ```
829 #[clippy::version = "pre 1.29.0"]
830 pub SEARCH_IS_SOME,
831 complexity,
832 "using an iterator or string search followed by `is_some()` or `is_none()`, which is more succinctly expressed as a call to `any()` or `contains()` (with negation in case of `is_none()`)"
833 }
834
835 declare_clippy_lint! {
836 /// ### What it does
837 /// Checks for usage of `.chars().next()` on a `str` to check
838 /// if it starts with a given char.
839 ///
840 /// ### Why is this bad?
841 /// Readability, this can be written more concisely as
842 /// `_.starts_with(_)`.
843 ///
844 /// ### Example
845 /// ```rust
846 /// let name = "foo";
847 /// if name.chars().next() == Some('_') {};
848 /// ```
849 ///
850 /// Use instead:
851 /// ```rust
852 /// let name = "foo";
853 /// if name.starts_with('_') {};
854 /// ```
855 #[clippy::version = "pre 1.29.0"]
856 pub CHARS_NEXT_CMP,
857 style,
858 "using `.chars().next()` to check if a string starts with a char"
859 }
860
861 declare_clippy_lint! {
862 /// ### What it does
863 /// Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
864 /// `.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`,
865 /// `.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()`
866 /// etc. instead.
867 ///
868 /// ### Why is this bad?
869 /// The function will always be called. This is only bad if it allocates or
870 /// does some non-trivial amount of work.
871 ///
872 /// ### Known problems
873 /// If the function has side-effects, not calling it will change the
874 /// semantic of the program, but you shouldn't rely on that.
875 ///
876 /// The lint also cannot figure out whether the function you call is
877 /// actually expensive to call or not.
878 ///
879 /// ### Example
880 /// ```rust
881 /// # let foo = Some(String::new());
882 /// foo.unwrap_or(String::from("empty"));
883 /// ```
884 ///
885 /// Use instead:
886 /// ```rust
887 /// # let foo = Some(String::new());
888 /// foo.unwrap_or_else(|| String::from("empty"));
889 /// ```
890 #[clippy::version = "pre 1.29.0"]
891 pub OR_FUN_CALL,
892 nursery,
893 "using any `*or` method with a function call, which suggests `*or_else`"
894 }
895
896 declare_clippy_lint! {
897 /// ### What it does
898 /// Checks for `.or(…).unwrap()` calls to Options and Results.
899 ///
900 /// ### Why is this bad?
901 /// You should use `.unwrap_or(…)` instead for clarity.
902 ///
903 /// ### Example
904 /// ```rust
905 /// # let fallback = "fallback";
906 /// // Result
907 /// # type Error = &'static str;
908 /// # let result: Result<&str, Error> = Err("error");
909 /// let value = result.or::<Error>(Ok(fallback)).unwrap();
910 ///
911 /// // Option
912 /// # let option: Option<&str> = None;
913 /// let value = option.or(Some(fallback)).unwrap();
914 /// ```
915 /// Use instead:
916 /// ```rust
917 /// # let fallback = "fallback";
918 /// // Result
919 /// # let result: Result<&str, &str> = Err("error");
920 /// let value = result.unwrap_or(fallback);
921 ///
922 /// // Option
923 /// # let option: Option<&str> = None;
924 /// let value = option.unwrap_or(fallback);
925 /// ```
926 #[clippy::version = "1.61.0"]
927 pub OR_THEN_UNWRAP,
928 complexity,
929 "checks for `.or(…).unwrap()` calls to Options and Results."
930 }
931
932 declare_clippy_lint! {
933 /// ### What it does
934 /// Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`,
935 /// etc., and suggests to use `unwrap_or_else` instead
936 ///
937 /// ### Why is this bad?
938 /// The function will always be called.
939 ///
940 /// ### Known problems
941 /// If the function has side-effects, not calling it will
942 /// change the semantics of the program, but you shouldn't rely on that anyway.
943 ///
944 /// ### Example
945 /// ```rust
946 /// # let foo = Some(String::new());
947 /// # let err_code = "418";
948 /// # let err_msg = "I'm a teapot";
949 /// foo.expect(&format!("Err {}: {}", err_code, err_msg));
950 ///
951 /// // or
952 ///
953 /// # let foo = Some(String::new());
954 /// foo.expect(format!("Err {}: {}", err_code, err_msg).as_str());
955 /// ```
956 ///
957 /// Use instead:
958 /// ```rust
959 /// # let foo = Some(String::new());
960 /// # let err_code = "418";
961 /// # let err_msg = "I'm a teapot";
962 /// foo.unwrap_or_else(|| panic!("Err {}: {}", err_code, err_msg));
963 /// ```
964 #[clippy::version = "pre 1.29.0"]
965 pub EXPECT_FUN_CALL,
966 perf,
967 "using any `expect` method with a function call"
968 }
969
970 declare_clippy_lint! {
971 /// ### What it does
972 /// Checks for usage of `.clone()` on a `Copy` type.
973 ///
974 /// ### Why is this bad?
975 /// The only reason `Copy` types implement `Clone` is for
976 /// generics, not for using the `clone` method on a concrete type.
977 ///
978 /// ### Example
979 /// ```rust
980 /// 42u64.clone();
981 /// ```
982 #[clippy::version = "pre 1.29.0"]
983 pub CLONE_ON_COPY,
984 complexity,
985 "using `clone` on a `Copy` type"
986 }
987
988 declare_clippy_lint! {
989 /// ### What it does
990 /// Checks for usage of `.clone()` on a ref-counted pointer,
991 /// (`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified
992 /// function syntax instead (e.g., `Rc::clone(foo)`).
993 ///
994 /// ### Why is this bad?
995 /// Calling '.clone()' on an Rc, Arc, or Weak
996 /// can obscure the fact that only the pointer is being cloned, not the underlying
997 /// data.
998 ///
999 /// ### Example
1000 /// ```rust
1001 /// # use std::rc::Rc;
1002 /// let x = Rc::new(1);
1003 ///
1004 /// x.clone();
1005 /// ```
1006 ///
1007 /// Use instead:
1008 /// ```rust
1009 /// # use std::rc::Rc;
1010 /// # let x = Rc::new(1);
1011 /// Rc::clone(&x);
1012 /// ```
1013 #[clippy::version = "pre 1.29.0"]
1014 pub CLONE_ON_REF_PTR,
1015 restriction,
1016 "using 'clone' on a ref-counted pointer"
1017 }
1018
1019 declare_clippy_lint! {
1020 /// ### What it does
1021 /// Checks for usage of `.to_string()` on an `&&T` where
1022 /// `T` implements `ToString` directly (like `&&str` or `&&String`).
1023 ///
1024 /// ### Why is this bad?
1025 /// This bypasses the specialized implementation of
1026 /// `ToString` and instead goes through the more expensive string formatting
1027 /// facilities.
1028 ///
1029 /// ### Example
1030 /// ```rust
1031 /// // Generic implementation for `T: Display` is used (slow)
1032 /// ["foo", "bar"].iter().map(|s| s.to_string());
1033 ///
1034 /// // OK, the specialized impl is used
1035 /// ["foo", "bar"].iter().map(|&s| s.to_string());
1036 /// ```
1037 #[clippy::version = "1.40.0"]
1038 pub INEFFICIENT_TO_STRING,
1039 pedantic,
1040 "using `to_string` on `&&T` where `T: ToString`"
1041 }
1042
1043 declare_clippy_lint! {
1044 /// ### What it does
1045 /// Checks for `new` not returning a type that contains `Self`.
1046 ///
1047 /// ### Why is this bad?
1048 /// As a convention, `new` methods are used to make a new
1049 /// instance of a type.
1050 ///
1051 /// ### Example
1052 /// In an impl block:
1053 /// ```rust
1054 /// # struct Foo;
1055 /// # struct NotAFoo;
1056 /// impl Foo {
1057 /// fn new() -> NotAFoo {
1058 /// # NotAFoo
1059 /// }
1060 /// }
1061 /// ```
1062 ///
1063 /// ```rust
1064 /// # struct Foo;
1065 /// struct Bar(Foo);
1066 /// impl Foo {
1067 /// // Bad. The type name must contain `Self`
1068 /// fn new() -> Bar {
1069 /// # Bar(Foo)
1070 /// }
1071 /// }
1072 /// ```
1073 ///
1074 /// ```rust
1075 /// # struct Foo;
1076 /// # struct FooError;
1077 /// impl Foo {
1078 /// // Good. Return type contains `Self`
1079 /// fn new() -> Result<Foo, FooError> {
1080 /// # Ok(Foo)
1081 /// }
1082 /// }
1083 /// ```
1084 ///
1085 /// Or in a trait definition:
1086 /// ```rust
1087 /// pub trait Trait {
1088 /// // Bad. The type name must contain `Self`
1089 /// fn new();
1090 /// }
1091 /// ```
1092 ///
1093 /// ```rust
1094 /// pub trait Trait {
1095 /// // Good. Return type contains `Self`
1096 /// fn new() -> Self;
1097 /// }
1098 /// ```
1099 #[clippy::version = "pre 1.29.0"]
1100 pub NEW_RET_NO_SELF,
1101 style,
1102 "not returning type containing `Self` in a `new` method"
1103 }
1104
1105 declare_clippy_lint! {
1106 /// ### What it does
1107 /// Checks for string methods that receive a single-character
1108 /// `str` as an argument, e.g., `_.split("x")`.
1109 ///
1110 /// ### Why is this bad?
1111 /// Performing these methods using a `char` is faster than
1112 /// using a `str`.
1113 ///
1114 /// ### Known problems
1115 /// Does not catch multi-byte unicode characters.
1116 ///
1117 /// ### Example
1118 /// ```rust,ignore
1119 /// _.split("x");
1120 /// ```
1121 ///
1122 /// Use instead:
1123 /// ```rust,ignore
1124 /// _.split('x');
1125 /// ```
1126 #[clippy::version = "pre 1.29.0"]
1127 pub SINGLE_CHAR_PATTERN,
1128 perf,
1129 "using a single-character str where a char could be used, e.g., `_.split(\"x\")`"
1130 }
1131
1132 declare_clippy_lint! {
1133 /// ### What it does
1134 /// Checks for calling `.step_by(0)` on iterators which panics.
1135 ///
1136 /// ### Why is this bad?
1137 /// This very much looks like an oversight. Use `panic!()` instead if you
1138 /// actually intend to panic.
1139 ///
1140 /// ### Example
1141 /// ```rust,should_panic
1142 /// for x in (0..100).step_by(0) {
1143 /// //..
1144 /// }
1145 /// ```
1146 #[clippy::version = "pre 1.29.0"]
1147 pub ITERATOR_STEP_BY_ZERO,
1148 correctness,
1149 "using `Iterator::step_by(0)`, which will panic at runtime"
1150 }
1151
1152 declare_clippy_lint! {
1153 /// ### What it does
1154 /// Checks for indirect collection of populated `Option`
1155 ///
1156 /// ### Why is this bad?
1157 /// `Option` is like a collection of 0-1 things, so `flatten`
1158 /// automatically does this without suspicious-looking `unwrap` calls.
1159 ///
1160 /// ### Example
1161 /// ```rust
1162 /// let _ = std::iter::empty::<Option<i32>>().filter(Option::is_some).map(Option::unwrap);
1163 /// ```
1164 /// Use instead:
1165 /// ```rust
1166 /// let _ = std::iter::empty::<Option<i32>>().flatten();
1167 /// ```
1168 #[clippy::version = "1.53.0"]
1169 pub OPTION_FILTER_MAP,
1170 complexity,
1171 "filtering `Option` for `Some` then force-unwrapping, which can be one type-safe operation"
1172 }
1173
1174 declare_clippy_lint! {
1175 /// ### What it does
1176 /// Checks for the use of `iter.nth(0)`.
1177 ///
1178 /// ### Why is this bad?
1179 /// `iter.next()` is equivalent to
1180 /// `iter.nth(0)`, as they both consume the next element,
1181 /// but is more readable.
1182 ///
1183 /// ### Example
1184 /// ```rust
1185 /// # use std::collections::HashSet;
1186 /// # let mut s = HashSet::new();
1187 /// # s.insert(1);
1188 /// let x = s.iter().nth(0);
1189 /// ```
1190 ///
1191 /// Use instead:
1192 /// ```rust
1193 /// # use std::collections::HashSet;
1194 /// # let mut s = HashSet::new();
1195 /// # s.insert(1);
1196 /// let x = s.iter().next();
1197 /// ```
1198 #[clippy::version = "1.42.0"]
1199 pub ITER_NTH_ZERO,
1200 style,
1201 "replace `iter.nth(0)` with `iter.next()`"
1202 }
1203
1204 declare_clippy_lint! {
1205 /// ### What it does
1206 /// Checks for usage of `.iter().nth()` (and the related
1207 /// `.iter_mut().nth()`) on standard library types with *O*(1) element access.
1208 ///
1209 /// ### Why is this bad?
1210 /// `.get()` and `.get_mut()` are more efficient and more
1211 /// readable.
1212 ///
1213 /// ### Example
1214 /// ```rust
1215 /// let some_vec = vec![0, 1, 2, 3];
1216 /// let bad_vec = some_vec.iter().nth(3);
1217 /// let bad_slice = &some_vec[..].iter().nth(3);
1218 /// ```
1219 /// The correct use would be:
1220 /// ```rust
1221 /// let some_vec = vec![0, 1, 2, 3];
1222 /// let bad_vec = some_vec.get(3);
1223 /// let bad_slice = &some_vec[..].get(3);
1224 /// ```
1225 #[clippy::version = "pre 1.29.0"]
1226 pub ITER_NTH,
1227 perf,
1228 "using `.iter().nth()` on a standard library type with O(1) element access"
1229 }
1230
1231 declare_clippy_lint! {
1232 /// ### What it does
1233 /// Checks for usage of `.skip(x).next()` on iterators.
1234 ///
1235 /// ### Why is this bad?
1236 /// `.nth(x)` is cleaner
1237 ///
1238 /// ### Example
1239 /// ```rust
1240 /// let some_vec = vec![0, 1, 2, 3];
1241 /// let bad_vec = some_vec.iter().skip(3).next();
1242 /// let bad_slice = &some_vec[..].iter().skip(3).next();
1243 /// ```
1244 /// The correct use would be:
1245 /// ```rust
1246 /// let some_vec = vec![0, 1, 2, 3];
1247 /// let bad_vec = some_vec.iter().nth(3);
1248 /// let bad_slice = &some_vec[..].iter().nth(3);
1249 /// ```
1250 #[clippy::version = "pre 1.29.0"]
1251 pub ITER_SKIP_NEXT,
1252 style,
1253 "using `.skip(x).next()` on an iterator"
1254 }
1255
1256 declare_clippy_lint! {
1257 /// ### What it does
1258 /// Checks for usage of `.drain(..)` on `Vec` and `VecDeque` for iteration.
1259 ///
1260 /// ### Why is this bad?
1261 /// `.into_iter()` is simpler with better performance.
1262 ///
1263 /// ### Example
1264 /// ```rust
1265 /// # use std::collections::HashSet;
1266 /// let mut foo = vec![0, 1, 2, 3];
1267 /// let bar: HashSet<usize> = foo.drain(..).collect();
1268 /// ```
1269 /// Use instead:
1270 /// ```rust
1271 /// # use std::collections::HashSet;
1272 /// let foo = vec![0, 1, 2, 3];
1273 /// let bar: HashSet<usize> = foo.into_iter().collect();
1274 /// ```
1275 #[clippy::version = "1.61.0"]
1276 pub ITER_WITH_DRAIN,
1277 nursery,
1278 "replace `.drain(..)` with `.into_iter()`"
1279 }
1280
1281 declare_clippy_lint! {
1282 /// ### What it does
1283 /// Checks for usage of `x.get(x.len() - 1)` instead of
1284 /// `x.last()`.
1285 ///
1286 /// ### Why is this bad?
1287 /// Using `x.last()` is easier to read and has the same
1288 /// result.
1289 ///
1290 /// Note that using `x[x.len() - 1]` is semantically different from
1291 /// `x.last()`. Indexing into the array will panic on out-of-bounds
1292 /// accesses, while `x.get()` and `x.last()` will return `None`.
1293 ///
1294 /// There is another lint (get_unwrap) that covers the case of using
1295 /// `x.get(index).unwrap()` instead of `x[index]`.
1296 ///
1297 /// ### Example
1298 /// ```rust
1299 /// let x = vec![2, 3, 5];
1300 /// let last_element = x.get(x.len() - 1);
1301 /// ```
1302 ///
1303 /// Use instead:
1304 /// ```rust
1305 /// let x = vec![2, 3, 5];
1306 /// let last_element = x.last();
1307 /// ```
1308 #[clippy::version = "1.37.0"]
1309 pub GET_LAST_WITH_LEN,
1310 complexity,
1311 "Using `x.get(x.len() - 1)` when `x.last()` is correct and simpler"
1312 }
1313
1314 declare_clippy_lint! {
1315 /// ### What it does
1316 /// Checks for usage of `.get().unwrap()` (or
1317 /// `.get_mut().unwrap`) on a standard library type which implements `Index`
1318 ///
1319 /// ### Why is this bad?
1320 /// Using the Index trait (`[]`) is more clear and more
1321 /// concise.
1322 ///
1323 /// ### Known problems
1324 /// Not a replacement for error handling: Using either
1325 /// `.unwrap()` or the Index trait (`[]`) carries the risk of causing a `panic`
1326 /// if the value being accessed is `None`. If the use of `.get().unwrap()` is a
1327 /// temporary placeholder for dealing with the `Option` type, then this does
1328 /// not mitigate the need for error handling. If there is a chance that `.get()`
1329 /// will be `None` in your program, then it is advisable that the `None` case
1330 /// is handled in a future refactor instead of using `.unwrap()` or the Index
1331 /// trait.
1332 ///
1333 /// ### Example
1334 /// ```rust
1335 /// let mut some_vec = vec![0, 1, 2, 3];
1336 /// let last = some_vec.get(3).unwrap();
1337 /// *some_vec.get_mut(0).unwrap() = 1;
1338 /// ```
1339 /// The correct use would be:
1340 /// ```rust
1341 /// let mut some_vec = vec![0, 1, 2, 3];
1342 /// let last = some_vec[3];
1343 /// some_vec[0] = 1;
1344 /// ```
1345 #[clippy::version = "pre 1.29.0"]
1346 pub GET_UNWRAP,
1347 restriction,
1348 "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead"
1349 }
1350
1351 declare_clippy_lint! {
1352 /// ### What it does
1353 /// Checks for occurrences where one vector gets extended instead of append
1354 ///
1355 /// ### Why is this bad?
1356 /// Using `append` instead of `extend` is more concise and faster
1357 ///
1358 /// ### Example
1359 /// ```rust
1360 /// let mut a = vec![1, 2, 3];
1361 /// let mut b = vec![4, 5, 6];
1362 ///
1363 /// a.extend(b.drain(..));
1364 /// ```
1365 ///
1366 /// Use instead:
1367 /// ```rust
1368 /// let mut a = vec![1, 2, 3];
1369 /// let mut b = vec![4, 5, 6];
1370 ///
1371 /// a.append(&mut b);
1372 /// ```
1373 #[clippy::version = "1.55.0"]
1374 pub EXTEND_WITH_DRAIN,
1375 perf,
1376 "using vec.append(&mut vec) to move the full range of a vector to another"
1377 }
1378
1379 declare_clippy_lint! {
1380 /// ### What it does
1381 /// Checks for the use of `.extend(s.chars())` where s is a
1382 /// `&str` or `String`.
1383 ///
1384 /// ### Why is this bad?
1385 /// `.push_str(s)` is clearer
1386 ///
1387 /// ### Example
1388 /// ```rust
1389 /// let abc = "abc";
1390 /// let def = String::from("def");
1391 /// let mut s = String::new();
1392 /// s.extend(abc.chars());
1393 /// s.extend(def.chars());
1394 /// ```
1395 /// The correct use would be:
1396 /// ```rust
1397 /// let abc = "abc";
1398 /// let def = String::from("def");
1399 /// let mut s = String::new();
1400 /// s.push_str(abc);
1401 /// s.push_str(&def);
1402 /// ```
1403 #[clippy::version = "pre 1.29.0"]
1404 pub STRING_EXTEND_CHARS,
1405 style,
1406 "using `x.extend(s.chars())` where s is a `&str` or `String`"
1407 }
1408
1409 declare_clippy_lint! {
1410 /// ### What it does
1411 /// Checks for the use of `.cloned().collect()` on slice to
1412 /// create a `Vec`.
1413 ///
1414 /// ### Why is this bad?
1415 /// `.to_vec()` is clearer
1416 ///
1417 /// ### Example
1418 /// ```rust
1419 /// let s = [1, 2, 3, 4, 5];
1420 /// let s2: Vec<isize> = s[..].iter().cloned().collect();
1421 /// ```
1422 /// The better use would be:
1423 /// ```rust
1424 /// let s = [1, 2, 3, 4, 5];
1425 /// let s2: Vec<isize> = s.to_vec();
1426 /// ```
1427 #[clippy::version = "pre 1.29.0"]
1428 pub ITER_CLONED_COLLECT,
1429 style,
1430 "using `.cloned().collect()` on slice to create a `Vec`"
1431 }
1432
1433 declare_clippy_lint! {
1434 /// ### What it does
1435 /// Checks for usage of `_.chars().last()` or
1436 /// `_.chars().next_back()` on a `str` to check if it ends with a given char.
1437 ///
1438 /// ### Why is this bad?
1439 /// Readability, this can be written more concisely as
1440 /// `_.ends_with(_)`.
1441 ///
1442 /// ### Example
1443 /// ```rust
1444 /// # let name = "_";
1445 /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-');
1446 /// ```
1447 ///
1448 /// Use instead:
1449 /// ```rust
1450 /// # let name = "_";
1451 /// name.ends_with('_') || name.ends_with('-');
1452 /// ```
1453 #[clippy::version = "pre 1.29.0"]
1454 pub CHARS_LAST_CMP,
1455 style,
1456 "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char"
1457 }
1458
1459 declare_clippy_lint! {
1460 /// ### What it does
1461 /// Checks for usage of `.as_ref()` or `.as_mut()` where the
1462 /// types before and after the call are the same.
1463 ///
1464 /// ### Why is this bad?
1465 /// The call is unnecessary.
1466 ///
1467 /// ### Example
1468 /// ```rust
1469 /// # fn do_stuff(x: &[i32]) {}
1470 /// let x: &[i32] = &[1, 2, 3, 4, 5];
1471 /// do_stuff(x.as_ref());
1472 /// ```
1473 /// The correct use would be:
1474 /// ```rust
1475 /// # fn do_stuff(x: &[i32]) {}
1476 /// let x: &[i32] = &[1, 2, 3, 4, 5];
1477 /// do_stuff(x);
1478 /// ```
1479 #[clippy::version = "pre 1.29.0"]
1480 pub USELESS_ASREF,
1481 complexity,
1482 "using `as_ref` where the types before and after the call are the same"
1483 }
1484
1485 declare_clippy_lint! {
1486 /// ### What it does
1487 /// Checks for usage of `fold` when a more succinct alternative exists.
1488 /// Specifically, this checks for `fold`s which could be replaced by `any`, `all`,
1489 /// `sum` or `product`.
1490 ///
1491 /// ### Why is this bad?
1492 /// Readability.
1493 ///
1494 /// ### Example
1495 /// ```rust
1496 /// # #[allow(unused)]
1497 /// (0..3).fold(false, |acc, x| acc || x > 2);
1498 /// ```
1499 ///
1500 /// Use instead:
1501 /// ```rust
1502 /// (0..3).any(|x| x > 2);
1503 /// ```
1504 #[clippy::version = "pre 1.29.0"]
1505 pub UNNECESSARY_FOLD,
1506 style,
1507 "using `fold` when a more succinct alternative exists"
1508 }
1509
1510 declare_clippy_lint! {
1511 /// ### What it does
1512 /// Checks for `filter_map` calls that could be replaced by `filter` or `map`.
1513 /// More specifically it checks if the closure provided is only performing one of the
1514 /// filter or map operations and suggests the appropriate option.
1515 ///
1516 /// ### Why is this bad?
1517 /// Complexity. The intent is also clearer if only a single
1518 /// operation is being performed.
1519 ///
1520 /// ### Example
1521 /// ```rust
1522 /// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None });
1523 ///
1524 /// // As there is no transformation of the argument this could be written as:
1525 /// let _ = (0..3).filter(|&x| x > 2);
1526 /// ```
1527 ///
1528 /// ```rust
1529 /// let _ = (0..4).filter_map(|x| Some(x + 1));
1530 ///
1531 /// // As there is no conditional check on the argument this could be written as:
1532 /// let _ = (0..4).map(|x| x + 1);
1533 /// ```
1534 #[clippy::version = "1.31.0"]
1535 pub UNNECESSARY_FILTER_MAP,
1536 complexity,
1537 "using `filter_map` when a more succinct alternative exists"
1538 }
1539
1540 declare_clippy_lint! {
1541 /// ### What it does
1542 /// Checks for `find_map` calls that could be replaced by `find` or `map`. More
1543 /// specifically it checks if the closure provided is only performing one of the
1544 /// find or map operations and suggests the appropriate option.
1545 ///
1546 /// ### Why is this bad?
1547 /// Complexity. The intent is also clearer if only a single
1548 /// operation is being performed.
1549 ///
1550 /// ### Example
1551 /// ```rust
1552 /// let _ = (0..3).find_map(|x| if x > 2 { Some(x) } else { None });
1553 ///
1554 /// // As there is no transformation of the argument this could be written as:
1555 /// let _ = (0..3).find(|&x| x > 2);
1556 /// ```
1557 ///
1558 /// ```rust
1559 /// let _ = (0..4).find_map(|x| Some(x + 1));
1560 ///
1561 /// // As there is no conditional check on the argument this could be written as:
1562 /// let _ = (0..4).map(|x| x + 1).next();
1563 /// ```
1564 #[clippy::version = "1.61.0"]
1565 pub UNNECESSARY_FIND_MAP,
1566 complexity,
1567 "using `find_map` when a more succinct alternative exists"
1568 }
1569
1570 declare_clippy_lint! {
1571 /// ### What it does
1572 /// Checks for `into_iter` calls on references which should be replaced by `iter`
1573 /// or `iter_mut`.
1574 ///
1575 /// ### Why is this bad?
1576 /// Readability. Calling `into_iter` on a reference will not move out its
1577 /// content into the resulting iterator, which is confusing. It is better just call `iter` or
1578 /// `iter_mut` directly.
1579 ///
1580 /// ### Example
1581 /// ```rust
1582 /// # let vec = vec![3, 4, 5];
1583 /// (&vec).into_iter();
1584 /// ```
1585 ///
1586 /// Use instead:
1587 /// ```rust
1588 /// # let vec = vec![3, 4, 5];
1589 /// (&vec).iter();
1590 /// ```
1591 #[clippy::version = "1.32.0"]
1592 pub INTO_ITER_ON_REF,
1593 style,
1594 "using `.into_iter()` on a reference"
1595 }
1596
1597 declare_clippy_lint! {
1598 /// ### What it does
1599 /// Checks for calls to `map` followed by a `count`.
1600 ///
1601 /// ### Why is this bad?
1602 /// It looks suspicious. Maybe `map` was confused with `filter`.
1603 /// If the `map` call is intentional, this should be rewritten
1604 /// using `inspect`. Or, if you intend to drive the iterator to
1605 /// completion, you can just use `for_each` instead.
1606 ///
1607 /// ### Example
1608 /// ```rust
1609 /// let _ = (0..3).map(|x| x + 2).count();
1610 /// ```
1611 #[clippy::version = "1.39.0"]
1612 pub SUSPICIOUS_MAP,
1613 suspicious,
1614 "suspicious usage of map"
1615 }
1616
1617 declare_clippy_lint! {
1618 /// ### What it does
1619 /// Checks for `MaybeUninit::uninit().assume_init()`.
1620 ///
1621 /// ### Why is this bad?
1622 /// For most types, this is undefined behavior.
1623 ///
1624 /// ### Known problems
1625 /// For now, we accept empty tuples and tuples / arrays
1626 /// of `MaybeUninit`. There may be other types that allow uninitialized
1627 /// data, but those are not yet rigorously defined.
1628 ///
1629 /// ### Example
1630 /// ```rust
1631 /// // Beware the UB
1632 /// use std::mem::MaybeUninit;
1633 ///
1634 /// let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
1635 /// ```
1636 ///
1637 /// Note that the following is OK:
1638 ///
1639 /// ```rust
1640 /// use std::mem::MaybeUninit;
1641 ///
1642 /// let _: [MaybeUninit<bool>; 5] = unsafe {
1643 /// MaybeUninit::uninit().assume_init()
1644 /// };
1645 /// ```
1646 #[clippy::version = "1.39.0"]
1647 pub UNINIT_ASSUMED_INIT,
1648 correctness,
1649 "`MaybeUninit::uninit().assume_init()`"
1650 }
1651
1652 declare_clippy_lint! {
1653 /// ### What it does
1654 /// Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`.
1655 ///
1656 /// ### Why is this bad?
1657 /// These can be written simply with `saturating_add/sub` methods.
1658 ///
1659 /// ### Example
1660 /// ```rust
1661 /// # let y: u32 = 0;
1662 /// # let x: u32 = 100;
1663 /// let add = x.checked_add(y).unwrap_or(u32::MAX);
1664 /// let sub = x.checked_sub(y).unwrap_or(u32::MIN);
1665 /// ```
1666 ///
1667 /// can be written using dedicated methods for saturating addition/subtraction as:
1668 ///
1669 /// ```rust
1670 /// # let y: u32 = 0;
1671 /// # let x: u32 = 100;
1672 /// let add = x.saturating_add(y);
1673 /// let sub = x.saturating_sub(y);
1674 /// ```
1675 #[clippy::version = "1.39.0"]
1676 pub MANUAL_SATURATING_ARITHMETIC,
1677 style,
1678 "`.checked_add/sub(x).unwrap_or(MAX/MIN)`"
1679 }
1680
1681 declare_clippy_lint! {
1682 /// ### What it does
1683 /// Checks for `offset(_)`, `wrapping_`{`add`, `sub`}, etc. on raw pointers to
1684 /// zero-sized types
1685 ///
1686 /// ### Why is this bad?
1687 /// This is a no-op, and likely unintended
1688 ///
1689 /// ### Example
1690 /// ```rust
1691 /// unsafe { (&() as *const ()).offset(1) };
1692 /// ```
1693 #[clippy::version = "1.41.0"]
1694 pub ZST_OFFSET,
1695 correctness,
1696 "Check for offset calculations on raw pointers to zero-sized types"
1697 }
1698
1699 declare_clippy_lint! {
1700 /// ### What it does
1701 /// Checks for `FileType::is_file()`.
1702 ///
1703 /// ### Why is this bad?
1704 /// When people testing a file type with `FileType::is_file`
1705 /// they are testing whether a path is something they can get bytes from. But
1706 /// `is_file` doesn't cover special file types in unix-like systems, and doesn't cover
1707 /// symlink in windows. Using `!FileType::is_dir()` is a better way to that intention.
1708 ///
1709 /// ### Example
1710 /// ```rust
1711 /// # || {
1712 /// let metadata = std::fs::metadata("foo.txt")?;
1713 /// let filetype = metadata.file_type();
1714 ///
1715 /// if filetype.is_file() {
1716 /// // read file
1717 /// }
1718 /// # Ok::<_, std::io::Error>(())
1719 /// # };
1720 /// ```
1721 ///
1722 /// should be written as:
1723 ///
1724 /// ```rust
1725 /// # || {
1726 /// let metadata = std::fs::metadata("foo.txt")?;
1727 /// let filetype = metadata.file_type();
1728 ///
1729 /// if !filetype.is_dir() {
1730 /// // read file
1731 /// }
1732 /// # Ok::<_, std::io::Error>(())
1733 /// # };
1734 /// ```
1735 #[clippy::version = "1.42.0"]
1736 pub FILETYPE_IS_FILE,
1737 restriction,
1738 "`FileType::is_file` is not recommended to test for readable file type"
1739 }
1740
1741 declare_clippy_lint! {
1742 /// ### What it does
1743 /// Checks for usage of `_.as_ref().map(Deref::deref)` or its aliases (such as String::as_str).
1744 ///
1745 /// ### Why is this bad?
1746 /// Readability, this can be written more concisely as
1747 /// `_.as_deref()`.
1748 ///
1749 /// ### Example
1750 /// ```rust
1751 /// # let opt = Some("".to_string());
1752 /// opt.as_ref().map(String::as_str)
1753 /// # ;
1754 /// ```
1755 /// Can be written as
1756 /// ```rust
1757 /// # let opt = Some("".to_string());
1758 /// opt.as_deref()
1759 /// # ;
1760 /// ```
1761 #[clippy::version = "1.42.0"]
1762 pub OPTION_AS_REF_DEREF,
1763 complexity,
1764 "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`"
1765 }
1766
1767 declare_clippy_lint! {
1768 /// ### What it does
1769 /// Checks for usage of `iter().next()` on a Slice or an Array
1770 ///
1771 /// ### Why is this bad?
1772 /// These can be shortened into `.get()`
1773 ///
1774 /// ### Example
1775 /// ```rust
1776 /// # let a = [1, 2, 3];
1777 /// # let b = vec![1, 2, 3];
1778 /// a[2..].iter().next();
1779 /// b.iter().next();
1780 /// ```
1781 /// should be written as:
1782 /// ```rust
1783 /// # let a = [1, 2, 3];
1784 /// # let b = vec![1, 2, 3];
1785 /// a.get(2);
1786 /// b.get(0);
1787 /// ```
1788 #[clippy::version = "1.46.0"]
1789 pub ITER_NEXT_SLICE,
1790 style,
1791 "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`"
1792 }
1793
1794 declare_clippy_lint! {
1795 /// ### What it does
1796 /// Warns when using `push_str`/`insert_str` with a single-character string literal
1797 /// where `push`/`insert` with a `char` would work fine.
1798 ///
1799 /// ### Why is this bad?
1800 /// It's less clear that we are pushing a single character.
1801 ///
1802 /// ### Example
1803 /// ```rust
1804 /// # let mut string = String::new();
1805 /// string.insert_str(0, "R");
1806 /// string.push_str("R");
1807 /// ```
1808 ///
1809 /// Use instead:
1810 /// ```rust
1811 /// # let mut string = String::new();
1812 /// string.insert(0, 'R');
1813 /// string.push('R');
1814 /// ```
1815 #[clippy::version = "1.49.0"]
1816 pub SINGLE_CHAR_ADD_STR,
1817 style,
1818 "`push_str()` or `insert_str()` used with a single-character string literal as parameter"
1819 }
1820
1821 declare_clippy_lint! {
1822 /// ### What it does
1823 /// As the counterpart to `or_fun_call`, this lint looks for unnecessary
1824 /// lazily evaluated closures on `Option` and `Result`.
1825 ///
1826 /// This lint suggests changing the following functions, when eager evaluation results in
1827 /// simpler code:
1828 /// - `unwrap_or_else` to `unwrap_or`
1829 /// - `and_then` to `and`
1830 /// - `or_else` to `or`
1831 /// - `get_or_insert_with` to `get_or_insert`
1832 /// - `ok_or_else` to `ok_or`
1833 /// - `then` to `then_some` (for msrv >= 1.62.0)
1834 ///
1835 /// ### Why is this bad?
1836 /// Using eager evaluation is shorter and simpler in some cases.
1837 ///
1838 /// ### Known problems
1839 /// It is possible, but not recommended for `Deref` and `Index` to have
1840 /// side effects. Eagerly evaluating them can change the semantics of the program.
1841 ///
1842 /// ### Example
1843 /// ```rust
1844 /// // example code where clippy issues a warning
1845 /// let opt: Option<u32> = None;
1846 ///
1847 /// opt.unwrap_or_else(|| 42);
1848 /// ```
1849 /// Use instead:
1850 /// ```rust
1851 /// let opt: Option<u32> = None;
1852 ///
1853 /// opt.unwrap_or(42);
1854 /// ```
1855 #[clippy::version = "1.48.0"]
1856 pub UNNECESSARY_LAZY_EVALUATIONS,
1857 style,
1858 "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation"
1859 }
1860
1861 declare_clippy_lint! {
1862 /// ### What it does
1863 /// Checks for usage of `_.map(_).collect::<Result<(), _>()`.
1864 ///
1865 /// ### Why is this bad?
1866 /// Using `try_for_each` instead is more readable and idiomatic.
1867 ///
1868 /// ### Example
1869 /// ```rust
1870 /// (0..3).map(|t| Err(t)).collect::<Result<(), _>>();
1871 /// ```
1872 /// Use instead:
1873 /// ```rust
1874 /// (0..3).try_for_each(|t| Err(t));
1875 /// ```
1876 #[clippy::version = "1.49.0"]
1877 pub MAP_COLLECT_RESULT_UNIT,
1878 style,
1879 "using `.map(_).collect::<Result<(),_>()`, which can be replaced with `try_for_each`"
1880 }
1881
1882 declare_clippy_lint! {
1883 /// ### What it does
1884 /// Checks for `from_iter()` function calls on types that implement the `FromIterator`
1885 /// trait.
1886 ///
1887 /// ### Why is this bad?
1888 /// It is recommended style to use collect. See
1889 /// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html)
1890 ///
1891 /// ### Example
1892 /// ```rust
1893 /// let five_fives = std::iter::repeat(5).take(5);
1894 ///
1895 /// let v = Vec::from_iter(five_fives);
1896 ///
1897 /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
1898 /// ```
1899 /// Use instead:
1900 /// ```rust
1901 /// let five_fives = std::iter::repeat(5).take(5);
1902 ///
1903 /// let v: Vec<i32> = five_fives.collect();
1904 ///
1905 /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
1906 /// ```
1907 #[clippy::version = "1.49.0"]
1908 pub FROM_ITER_INSTEAD_OF_COLLECT,
1909 pedantic,
1910 "use `.collect()` instead of `::from_iter()`"
1911 }
1912
1913 declare_clippy_lint! {
1914 /// ### What it does
1915 /// Checks for usage of `inspect().for_each()`.
1916 ///
1917 /// ### Why is this bad?
1918 /// It is the same as performing the computation
1919 /// inside `inspect` at the beginning of the closure in `for_each`.
1920 ///
1921 /// ### Example
1922 /// ```rust
1923 /// [1,2,3,4,5].iter()
1924 /// .inspect(|&x| println!("inspect the number: {}", x))
1925 /// .for_each(|&x| {
1926 /// assert!(x >= 0);
1927 /// });
1928 /// ```
1929 /// Can be written as
1930 /// ```rust
1931 /// [1,2,3,4,5].iter()
1932 /// .for_each(|&x| {
1933 /// println!("inspect the number: {}", x);
1934 /// assert!(x >= 0);
1935 /// });
1936 /// ```
1937 #[clippy::version = "1.51.0"]
1938 pub INSPECT_FOR_EACH,
1939 complexity,
1940 "using `.inspect().for_each()`, which can be replaced with `.for_each()`"
1941 }
1942
1943 declare_clippy_lint! {
1944 /// ### What it does
1945 /// Checks for usage of `filter_map(|x| x)`.
1946 ///
1947 /// ### Why is this bad?
1948 /// Readability, this can be written more concisely by using `flatten`.
1949 ///
1950 /// ### Example
1951 /// ```rust
1952 /// # let iter = vec![Some(1)].into_iter();
1953 /// iter.filter_map(|x| x);
1954 /// ```
1955 /// Use instead:
1956 /// ```rust
1957 /// # let iter = vec![Some(1)].into_iter();
1958 /// iter.flatten();
1959 /// ```
1960 #[clippy::version = "1.52.0"]
1961 pub FILTER_MAP_IDENTITY,
1962 complexity,
1963 "call to `filter_map` where `flatten` is sufficient"
1964 }
1965
1966 declare_clippy_lint! {
1967 /// ### What it does
1968 /// Checks for instances of `map(f)` where `f` is the identity function.
1969 ///
1970 /// ### Why is this bad?
1971 /// It can be written more concisely without the call to `map`.
1972 ///
1973 /// ### Example
1974 /// ```rust
1975 /// let x = [1, 2, 3];
1976 /// let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect();
1977 /// ```
1978 /// Use instead:
1979 /// ```rust
1980 /// let x = [1, 2, 3];
1981 /// let y: Vec<_> = x.iter().map(|x| 2*x).collect();
1982 /// ```
1983 #[clippy::version = "1.47.0"]
1984 pub MAP_IDENTITY,
1985 complexity,
1986 "using iterator.map(|x| x)"
1987 }
1988
1989 declare_clippy_lint! {
1990 /// ### What it does
1991 /// Checks for the use of `.bytes().nth()`.
1992 ///
1993 /// ### Why is this bad?
1994 /// `.as_bytes().get()` is more efficient and more
1995 /// readable.
1996 ///
1997 /// ### Example
1998 /// ```rust
1999 /// # #[allow(unused)]
2000 /// "Hello".bytes().nth(3);
2001 /// ```
2002 ///
2003 /// Use instead:
2004 /// ```rust
2005 /// # #[allow(unused)]
2006 /// "Hello".as_bytes().get(3);
2007 /// ```
2008 #[clippy::version = "1.52.0"]
2009 pub BYTES_NTH,
2010 style,
2011 "replace `.bytes().nth()` with `.as_bytes().get()`"
2012 }
2013
2014 declare_clippy_lint! {
2015 /// ### What it does
2016 /// Checks for the usage of `_.to_owned()`, `vec.to_vec()`, or similar when calling `_.clone()` would be clearer.
2017 ///
2018 /// ### Why is this bad?
2019 /// These methods do the same thing as `_.clone()` but may be confusing as
2020 /// to why we are calling `to_vec` on something that is already a `Vec` or calling `to_owned` on something that is already owned.
2021 ///
2022 /// ### Example
2023 /// ```rust
2024 /// let a = vec![1, 2, 3];
2025 /// let b = a.to_vec();
2026 /// let c = a.to_owned();
2027 /// ```
2028 /// Use instead:
2029 /// ```rust
2030 /// let a = vec![1, 2, 3];
2031 /// let b = a.clone();
2032 /// let c = a.clone();
2033 /// ```
2034 #[clippy::version = "1.52.0"]
2035 pub IMPLICIT_CLONE,
2036 pedantic,
2037 "implicitly cloning a value by invoking a function on its dereferenced type"
2038 }
2039
2040 declare_clippy_lint! {
2041 /// ### What it does
2042 /// Checks for the use of `.iter().count()`.
2043 ///
2044 /// ### Why is this bad?
2045 /// `.len()` is more efficient and more
2046 /// readable.
2047 ///
2048 /// ### Example
2049 /// ```rust
2050 /// # #![allow(unused)]
2051 /// let some_vec = vec![0, 1, 2, 3];
2052 ///
2053 /// some_vec.iter().count();
2054 /// &some_vec[..].iter().count();
2055 /// ```
2056 ///
2057 /// Use instead:
2058 /// ```rust
2059 /// let some_vec = vec![0, 1, 2, 3];
2060 ///
2061 /// some_vec.len();
2062 /// &some_vec[..].len();
2063 /// ```
2064 #[clippy::version = "1.52.0"]
2065 pub ITER_COUNT,
2066 complexity,
2067 "replace `.iter().count()` with `.len()`"
2068 }
2069
2070 declare_clippy_lint! {
2071 /// ### What it does
2072 /// Checks for the usage of `_.to_owned()`, on a `Cow<'_, _>`.
2073 ///
2074 /// ### Why is this bad?
2075 /// Calling `to_owned()` on a `Cow` creates a clone of the `Cow`
2076 /// itself, without taking ownership of the `Cow` contents (i.e.
2077 /// it's equivalent to calling `Cow::clone`).
2078 /// The similarly named `into_owned` method, on the other hand,
2079 /// clones the `Cow` contents, effectively turning any `Cow::Borrowed`
2080 /// into a `Cow::Owned`.
2081 ///
2082 /// Given the potential ambiguity, consider replacing `to_owned`
2083 /// with `clone` for better readability or, if getting a `Cow::Owned`
2084 /// was the original intent, using `into_owned` instead.
2085 ///
2086 /// ### Example
2087 /// ```rust
2088 /// # use std::borrow::Cow;
2089 /// let s = "Hello world!";
2090 /// let cow = Cow::Borrowed(s);
2091 ///
2092 /// let data = cow.to_owned();
2093 /// assert!(matches!(data, Cow::Borrowed(_)))
2094 /// ```
2095 /// Use instead:
2096 /// ```rust
2097 /// # use std::borrow::Cow;
2098 /// let s = "Hello world!";
2099 /// let cow = Cow::Borrowed(s);
2100 ///
2101 /// let data = cow.clone();
2102 /// assert!(matches!(data, Cow::Borrowed(_)))
2103 /// ```
2104 /// or
2105 /// ```rust
2106 /// # use std::borrow::Cow;
2107 /// let s = "Hello world!";
2108 /// let cow = Cow::Borrowed(s);
2109 ///
2110 /// let _data: String = cow.into_owned();
2111 /// ```
2112 #[clippy::version = "1.65.0"]
2113 pub SUSPICIOUS_TO_OWNED,
2114 suspicious,
2115 "calls to `to_owned` on a `Cow<'_, _>` might not do what they are expected"
2116 }
2117
2118 declare_clippy_lint! {
2119 /// ### What it does
2120 /// Checks for calls to [`splitn`]
2121 /// (https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and
2122 /// related functions with either zero or one splits.
2123 ///
2124 /// ### Why is this bad?
2125 /// These calls don't actually split the value and are
2126 /// likely to be intended as a different number.
2127 ///
2128 /// ### Example
2129 /// ```rust
2130 /// # let s = "";
2131 /// for x in s.splitn(1, ":") {
2132 /// // ..
2133 /// }
2134 /// ```
2135 ///
2136 /// Use instead:
2137 /// ```rust
2138 /// # let s = "";
2139 /// for x in s.splitn(2, ":") {
2140 /// // ..
2141 /// }
2142 /// ```
2143 #[clippy::version = "1.54.0"]
2144 pub SUSPICIOUS_SPLITN,
2145 correctness,
2146 "checks for `.splitn(0, ..)` and `.splitn(1, ..)`"
2147 }
2148
2149 declare_clippy_lint! {
2150 /// ### What it does
2151 /// Checks for manual implementations of `str::repeat`
2152 ///
2153 /// ### Why is this bad?
2154 /// These are both harder to read, as well as less performant.
2155 ///
2156 /// ### Example
2157 /// ```rust
2158 /// let x: String = std::iter::repeat('x').take(10).collect();
2159 /// ```
2160 ///
2161 /// Use instead:
2162 /// ```rust
2163 /// let x: String = "x".repeat(10);
2164 /// ```
2165 #[clippy::version = "1.54.0"]
2166 pub MANUAL_STR_REPEAT,
2167 perf,
2168 "manual implementation of `str::repeat`"
2169 }
2170
2171 declare_clippy_lint! {
2172 /// ### What it does
2173 /// Checks for usage of `str::splitn(2, _)`
2174 ///
2175 /// ### Why is this bad?
2176 /// `split_once` is both clearer in intent and slightly more efficient.
2177 ///
2178 /// ### Example
2179 /// ```rust,ignore
2180 /// let s = "key=value=add";
2181 /// let (key, value) = s.splitn(2, '=').next_tuple()?;
2182 /// let value = s.splitn(2, '=').nth(1)?;
2183 ///
2184 /// let mut parts = s.splitn(2, '=');
2185 /// let key = parts.next()?;
2186 /// let value = parts.next()?;
2187 /// ```
2188 ///
2189 /// Use instead:
2190 /// ```rust,ignore
2191 /// let s = "key=value=add";
2192 /// let (key, value) = s.split_once('=')?;
2193 /// let value = s.split_once('=')?.1;
2194 ///
2195 /// let (key, value) = s.split_once('=')?;
2196 /// ```
2197 ///
2198 /// ### Limitations
2199 /// The multiple statement variant currently only detects `iter.next()?`/`iter.next().unwrap()`
2200 /// in two separate `let` statements that immediately follow the `splitn()`
2201 #[clippy::version = "1.57.0"]
2202 pub MANUAL_SPLIT_ONCE,
2203 complexity,
2204 "replace `.splitn(2, pat)` with `.split_once(pat)`"
2205 }
2206
2207 declare_clippy_lint! {
2208 /// ### What it does
2209 /// Checks for usage of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same.
2210 /// ### Why is this bad?
2211 /// The function `split` is simpler and there is no performance difference in these cases, considering
2212 /// that both functions return a lazy iterator.
2213 /// ### Example
2214 /// ```rust
2215 /// let str = "key=value=add";
2216 /// let _ = str.splitn(3, '=').next().unwrap();
2217 /// ```
2218 ///
2219 /// Use instead:
2220 /// ```rust
2221 /// let str = "key=value=add";
2222 /// let _ = str.split('=').next().unwrap();
2223 /// ```
2224 #[clippy::version = "1.59.0"]
2225 pub NEEDLESS_SPLITN,
2226 complexity,
2227 "usages of `str::splitn` that can be replaced with `str::split`"
2228 }
2229
2230 declare_clippy_lint! {
2231 /// ### What it does
2232 /// Checks for unnecessary calls to [`ToOwned::to_owned`](https://doc.rust-lang.org/std/borrow/trait.ToOwned.html#tymethod.to_owned)
2233 /// and other `to_owned`-like functions.
2234 ///
2235 /// ### Why is this bad?
2236 /// The unnecessary calls result in useless allocations.
2237 ///
2238 /// ### Known problems
2239 /// `unnecessary_to_owned` can falsely trigger if `IntoIterator::into_iter` is applied to an
2240 /// owned copy of a resource and the resource is later used mutably. See
2241 /// [#8148](https://github.com/rust-lang/rust-clippy/issues/8148).
2242 ///
2243 /// ### Example
2244 /// ```rust
2245 /// let path = std::path::Path::new("x");
2246 /// foo(&path.to_string_lossy().to_string());
2247 /// fn foo(s: &str) {}
2248 /// ```
2249 /// Use instead:
2250 /// ```rust
2251 /// let path = std::path::Path::new("x");
2252 /// foo(&path.to_string_lossy());
2253 /// fn foo(s: &str) {}
2254 /// ```
2255 #[clippy::version = "1.59.0"]
2256 pub UNNECESSARY_TO_OWNED,
2257 perf,
2258 "unnecessary calls to `to_owned`-like functions"
2259 }
2260
2261 declare_clippy_lint! {
2262 /// ### What it does
2263 /// Checks for usage of `.collect::<Vec<String>>().join("")` on iterators.
2264 ///
2265 /// ### Why is this bad?
2266 /// `.collect::<String>()` is more concise and might be more performant
2267 ///
2268 /// ### Example
2269 /// ```rust
2270 /// let vector = vec!["hello", "world"];
2271 /// let output = vector.iter().map(|item| item.to_uppercase()).collect::<Vec<String>>().join("");
2272 /// println!("{}", output);
2273 /// ```
2274 /// The correct use would be:
2275 /// ```rust
2276 /// let vector = vec!["hello", "world"];
2277 /// let output = vector.iter().map(|item| item.to_uppercase()).collect::<String>();
2278 /// println!("{}", output);
2279 /// ```
2280 /// ### Known problems
2281 /// While `.collect::<String>()` is sometimes more performant, there are cases where
2282 /// using `.collect::<String>()` over `.collect::<Vec<String>>().join("")`
2283 /// will prevent loop unrolling and will result in a negative performance impact.
2284 ///
2285 /// Additionally, differences have been observed between aarch64 and x86_64 assembly output,
2286 /// with aarch64 tending to producing faster assembly in more cases when using `.collect::<String>()`
2287 #[clippy::version = "1.61.0"]
2288 pub UNNECESSARY_JOIN,
2289 pedantic,
2290 "using `.collect::<Vec<String>>().join(\"\")` on an iterator"
2291 }
2292
2293 declare_clippy_lint! {
2294 /// ### What it does
2295 /// Checks for no-op uses of `Option::{as_deref, as_deref_mut}`,
2296 /// for example, `Option<&T>::as_deref()` returns the same type.
2297 ///
2298 /// ### Why is this bad?
2299 /// Redundant code and improving readability.
2300 ///
2301 /// ### Example
2302 /// ```rust
2303 /// let a = Some(&1);
2304 /// let b = a.as_deref(); // goes from Option<&i32> to Option<&i32>
2305 /// ```
2306 ///
2307 /// Use instead:
2308 /// ```rust
2309 /// let a = Some(&1);
2310 /// let b = a;
2311 /// ```
2312 #[clippy::version = "1.57.0"]
2313 pub NEEDLESS_OPTION_AS_DEREF,
2314 complexity,
2315 "no-op use of `deref` or `deref_mut` method to `Option`."
2316 }
2317
2318 declare_clippy_lint! {
2319 /// ### What it does
2320 /// Finds usages of [`char::is_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_digit) that
2321 /// can be replaced with [`is_ascii_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_digit) or
2322 /// [`is_ascii_hexdigit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_hexdigit).
2323 ///
2324 /// ### Why is this bad?
2325 /// `is_digit(..)` is slower and requires specifying the radix.
2326 ///
2327 /// ### Example
2328 /// ```rust
2329 /// let c: char = '6';
2330 /// c.is_digit(10);
2331 /// c.is_digit(16);
2332 /// ```
2333 /// Use instead:
2334 /// ```rust
2335 /// let c: char = '6';
2336 /// c.is_ascii_digit();
2337 /// c.is_ascii_hexdigit();
2338 /// ```
2339 #[clippy::version = "1.62.0"]
2340 pub IS_DIGIT_ASCII_RADIX,
2341 style,
2342 "use of `char::is_digit(..)` with literal radix of 10 or 16"
2343 }
2344
2345 declare_clippy_lint! {
2346 /// ### What it does
2347 /// Checks for calling `take` function after `as_ref`.
2348 ///
2349 /// ### Why is this bad?
2350 /// Redundant code. `take` writes `None` to its argument.
2351 /// In this case the modification is useless as it's a temporary that cannot be read from afterwards.
2352 ///
2353 /// ### Example
2354 /// ```rust
2355 /// let x = Some(3);
2356 /// x.as_ref().take();
2357 /// ```
2358 /// Use instead:
2359 /// ```rust
2360 /// let x = Some(3);
2361 /// x.as_ref();
2362 /// ```
2363 #[clippy::version = "1.62.0"]
2364 pub NEEDLESS_OPTION_TAKE,
2365 complexity,
2366 "using `.as_ref().take()` on a temporary value"
2367 }
2368
2369 declare_clippy_lint! {
2370 /// ### What it does
2371 /// Checks for `replace` statements which have no effect.
2372 ///
2373 /// ### Why is this bad?
2374 /// It's either a mistake or confusing.
2375 ///
2376 /// ### Example
2377 /// ```rust
2378 /// "1234".replace("12", "12");
2379 /// "1234".replacen("12", "12", 1);
2380 /// ```
2381 #[clippy::version = "1.63.0"]
2382 pub NO_EFFECT_REPLACE,
2383 suspicious,
2384 "replace with no effect"
2385 }
2386
2387 declare_clippy_lint! {
2388 /// ### What it does
2389 /// Checks for usage of `.then_some(..).unwrap_or(..)`
2390 ///
2391 /// ### Why is this bad?
2392 /// This can be written more clearly with `if .. else ..`
2393 ///
2394 /// ### Limitations
2395 /// This lint currently only looks for usages of
2396 /// `.then_some(..).unwrap_or(..)`, but will be expanded
2397 /// to account for similar patterns.
2398 ///
2399 /// ### Example
2400 /// ```rust
2401 /// let x = true;
2402 /// x.then_some("a").unwrap_or("b");
2403 /// ```
2404 /// Use instead:
2405 /// ```rust
2406 /// let x = true;
2407 /// if x { "a" } else { "b" };
2408 /// ```
2409 #[clippy::version = "1.64.0"]
2410 pub OBFUSCATED_IF_ELSE,
2411 style,
2412 "use of `.then_some(..).unwrap_or(..)` can be written \
2413 more clearly with `if .. else ..`"
2414 }
2415
2416 declare_clippy_lint! {
2417 /// ### What it does
2418 ///
2419 /// Checks for calls to `iter`, `iter_mut` or `into_iter` on collections containing a single item
2420 ///
2421 /// ### Why is this bad?
2422 ///
2423 /// It is simpler to use the once function from the standard library:
2424 ///
2425 /// ### Example
2426 ///
2427 /// ```rust
2428 /// let a = [123].iter();
2429 /// let b = Some(123).into_iter();
2430 /// ```
2431 /// Use instead:
2432 /// ```rust
2433 /// use std::iter;
2434 /// let a = iter::once(&123);
2435 /// let b = iter::once(123);
2436 /// ```
2437 ///
2438 /// ### Known problems
2439 ///
2440 /// The type of the resulting iterator might become incompatible with its usage
2441 #[clippy::version = "1.65.0"]
2442 pub ITER_ON_SINGLE_ITEMS,
2443 nursery,
2444 "Iterator for array of length 1"
2445 }
2446
2447 declare_clippy_lint! {
2448 /// ### What it does
2449 ///
2450 /// Checks for calls to `iter`, `iter_mut` or `into_iter` on empty collections
2451 ///
2452 /// ### Why is this bad?
2453 ///
2454 /// It is simpler to use the empty function from the standard library:
2455 ///
2456 /// ### Example
2457 ///
2458 /// ```rust
2459 /// use std::{slice, option};
2460 /// let a: slice::Iter<i32> = [].iter();
2461 /// let f: option::IntoIter<i32> = None.into_iter();
2462 /// ```
2463 /// Use instead:
2464 /// ```rust
2465 /// use std::iter;
2466 /// let a: iter::Empty<i32> = iter::empty();
2467 /// let b: iter::Empty<i32> = iter::empty();
2468 /// ```
2469 ///
2470 /// ### Known problems
2471 ///
2472 /// The type of the resulting iterator might become incompatible with its usage
2473 #[clippy::version = "1.65.0"]
2474 pub ITER_ON_EMPTY_COLLECTIONS,
2475 nursery,
2476 "Iterator for empty array"
2477 }
2478
2479 declare_clippy_lint! {
2480 /// ### What it does
2481 /// Checks for naive byte counts
2482 ///
2483 /// ### Why is this bad?
2484 /// The [`bytecount`](https://crates.io/crates/bytecount)
2485 /// crate has methods to count your bytes faster, especially for large slices.
2486 ///
2487 /// ### Known problems
2488 /// If you have predominantly small slices, the
2489 /// `bytecount::count(..)` method may actually be slower. However, if you can
2490 /// ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be
2491 /// faster in those cases.
2492 ///
2493 /// ### Example
2494 /// ```rust
2495 /// # let vec = vec![1_u8];
2496 /// let count = vec.iter().filter(|x| **x == 0u8).count();
2497 /// ```
2498 ///
2499 /// Use instead:
2500 /// ```rust,ignore
2501 /// # let vec = vec![1_u8];
2502 /// let count = bytecount::count(&vec, 0u8);
2503 /// ```
2504 #[clippy::version = "pre 1.29.0"]
2505 pub NAIVE_BYTECOUNT,
2506 pedantic,
2507 "use of naive `<slice>.filter(|&x| x == y).count()` to count byte values"
2508 }
2509
2510 declare_clippy_lint! {
2511 /// ### What it does
2512 /// It checks for `str::bytes().count()` and suggests replacing it with
2513 /// `str::len()`.
2514 ///
2515 /// ### Why is this bad?
2516 /// `str::bytes().count()` is longer and may not be as performant as using
2517 /// `str::len()`.
2518 ///
2519 /// ### Example
2520 /// ```rust
2521 /// "hello".bytes().count();
2522 /// String::from("hello").bytes().count();
2523 /// ```
2524 /// Use instead:
2525 /// ```rust
2526 /// "hello".len();
2527 /// String::from("hello").len();
2528 /// ```
2529 #[clippy::version = "1.62.0"]
2530 pub BYTES_COUNT_TO_LEN,
2531 complexity,
2532 "Using `bytes().count()` when `len()` performs the same functionality"
2533 }
2534
2535 declare_clippy_lint! {
2536 /// ### What it does
2537 /// Checks for calls to `ends_with` with possible file extensions
2538 /// and suggests to use a case-insensitive approach instead.
2539 ///
2540 /// ### Why is this bad?
2541 /// `ends_with` is case-sensitive and may not detect files with a valid extension.
2542 ///
2543 /// ### Example
2544 /// ```rust
2545 /// fn is_rust_file(filename: &str) -> bool {
2546 /// filename.ends_with(".rs")
2547 /// }
2548 /// ```
2549 /// Use instead:
2550 /// ```rust
2551 /// fn is_rust_file(filename: &str) -> bool {
2552 /// let filename = std::path::Path::new(filename);
2553 /// filename.extension()
2554 /// .map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))
2555 /// }
2556 /// ```
2557 #[clippy::version = "1.51.0"]
2558 pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
2559 pedantic,
2560 "Checks for calls to ends_with with case-sensitive file extensions"
2561 }
2562
2563 declare_clippy_lint! {
2564 /// ### What it does
2565 /// Checks for usage of `x.get(0)` instead of
2566 /// `x.first()`.
2567 ///
2568 /// ### Why is this bad?
2569 /// Using `x.first()` is easier to read and has the same
2570 /// result.
2571 ///
2572 /// ### Example
2573 /// ```rust
2574 /// let x = vec![2, 3, 5];
2575 /// let first_element = x.get(0);
2576 /// ```
2577 ///
2578 /// Use instead:
2579 /// ```rust
2580 /// let x = vec![2, 3, 5];
2581 /// let first_element = x.first();
2582 /// ```
2583 #[clippy::version = "1.63.0"]
2584 pub GET_FIRST,
2585 style,
2586 "Using `x.get(0)` when `x.first()` is simpler"
2587 }
2588
2589 declare_clippy_lint! {
2590 /// ### What it does
2591 ///
2592 /// Finds patterns that reimplement `Option::ok_or`.
2593 ///
2594 /// ### Why is this bad?
2595 ///
2596 /// Concise code helps focusing on behavior instead of boilerplate.
2597 ///
2598 /// ### Examples
2599 /// ```rust
2600 /// let foo: Option<i32> = None;
2601 /// foo.map_or(Err("error"), |v| Ok(v));
2602 /// ```
2603 ///
2604 /// Use instead:
2605 /// ```rust
2606 /// let foo: Option<i32> = None;
2607 /// foo.ok_or("error");
2608 /// ```
2609 #[clippy::version = "1.49.0"]
2610 pub MANUAL_OK_OR,
2611 pedantic,
2612 "finds patterns that can be encoded more concisely with `Option::ok_or`"
2613 }
2614
2615 declare_clippy_lint! {
2616 /// ### What it does
2617 /// Checks for usage of `map(|x| x.clone())` or
2618 /// dereferencing closures for `Copy` types, on `Iterator` or `Option`,
2619 /// and suggests `cloned()` or `copied()` instead
2620 ///
2621 /// ### Why is this bad?
2622 /// Readability, this can be written more concisely
2623 ///
2624 /// ### Example
2625 /// ```rust
2626 /// let x = vec![42, 43];
2627 /// let y = x.iter();
2628 /// let z = y.map(|i| *i);
2629 /// ```
2630 ///
2631 /// The correct use would be:
2632 ///
2633 /// ```rust
2634 /// let x = vec![42, 43];
2635 /// let y = x.iter();
2636 /// let z = y.cloned();
2637 /// ```
2638 #[clippy::version = "pre 1.29.0"]
2639 pub MAP_CLONE,
2640 style,
2641 "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
2642 }
2643
2644 declare_clippy_lint! {
2645 /// ### What it does
2646 /// Checks for instances of `map_err(|_| Some::Enum)`
2647 ///
2648 /// ### Why is this bad?
2649 /// This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error
2650 ///
2651 /// ### Example
2652 /// Before:
2653 /// ```rust
2654 /// use std::fmt;
2655 ///
2656 /// #[derive(Debug)]
2657 /// enum Error {
2658 /// Indivisible,
2659 /// Remainder(u8),
2660 /// }
2661 ///
2662 /// impl fmt::Display for Error {
2663 /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2664 /// match self {
2665 /// Error::Indivisible => write!(f, "could not divide input by three"),
2666 /// Error::Remainder(remainder) => write!(
2667 /// f,
2668 /// "input is not divisible by three, remainder = {}",
2669 /// remainder
2670 /// ),
2671 /// }
2672 /// }
2673 /// }
2674 ///
2675 /// impl std::error::Error for Error {}
2676 ///
2677 /// fn divisible_by_3(input: &str) -> Result<(), Error> {
2678 /// input
2679 /// .parse::<i32>()
2680 /// .map_err(|_| Error::Indivisible)
2681 /// .map(|v| v % 3)
2682 /// .and_then(|remainder| {
2683 /// if remainder == 0 {
2684 /// Ok(())
2685 /// } else {
2686 /// Err(Error::Remainder(remainder as u8))
2687 /// }
2688 /// })
2689 /// }
2690 /// ```
2691 ///
2692 /// After:
2693 /// ```rust
2694 /// use std::{fmt, num::ParseIntError};
2695 ///
2696 /// #[derive(Debug)]
2697 /// enum Error {
2698 /// Indivisible(ParseIntError),
2699 /// Remainder(u8),
2700 /// }
2701 ///
2702 /// impl fmt::Display for Error {
2703 /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2704 /// match self {
2705 /// Error::Indivisible(_) => write!(f, "could not divide input by three"),
2706 /// Error::Remainder(remainder) => write!(
2707 /// f,
2708 /// "input is not divisible by three, remainder = {}",
2709 /// remainder
2710 /// ),
2711 /// }
2712 /// }
2713 /// }
2714 ///
2715 /// impl std::error::Error for Error {
2716 /// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
2717 /// match self {
2718 /// Error::Indivisible(source) => Some(source),
2719 /// _ => None,
2720 /// }
2721 /// }
2722 /// }
2723 ///
2724 /// fn divisible_by_3(input: &str) -> Result<(), Error> {
2725 /// input
2726 /// .parse::<i32>()
2727 /// .map_err(Error::Indivisible)
2728 /// .map(|v| v % 3)
2729 /// .and_then(|remainder| {
2730 /// if remainder == 0 {
2731 /// Ok(())
2732 /// } else {
2733 /// Err(Error::Remainder(remainder as u8))
2734 /// }
2735 /// })
2736 /// }
2737 /// ```
2738 #[clippy::version = "1.48.0"]
2739 pub MAP_ERR_IGNORE,
2740 restriction,
2741 "`map_err` should not ignore the original error"
2742 }
2743
2744 declare_clippy_lint! {
2745 /// ### What it does
2746 /// Checks for `&mut Mutex::lock` calls
2747 ///
2748 /// ### Why is this bad?
2749 /// `Mutex::lock` is less efficient than
2750 /// calling `Mutex::get_mut`. In addition you also have a statically
2751 /// guarantee that the mutex isn't locked, instead of just a runtime
2752 /// guarantee.
2753 ///
2754 /// ### Example
2755 /// ```rust
2756 /// use std::sync::{Arc, Mutex};
2757 ///
2758 /// let mut value_rc = Arc::new(Mutex::new(42_u8));
2759 /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
2760 ///
2761 /// let mut value = value_mutex.lock().unwrap();
2762 /// *value += 1;
2763 /// ```
2764 /// Use instead:
2765 /// ```rust
2766 /// use std::sync::{Arc, Mutex};
2767 ///
2768 /// let mut value_rc = Arc::new(Mutex::new(42_u8));
2769 /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
2770 ///
2771 /// let value = value_mutex.get_mut().unwrap();
2772 /// *value += 1;
2773 /// ```
2774 #[clippy::version = "1.49.0"]
2775 pub MUT_MUTEX_LOCK,
2776 style,
2777 "`&mut Mutex::lock` does unnecessary locking"
2778 }
2779
2780 declare_clippy_lint! {
2781 /// ### What it does
2782 /// Checks for duplicate open options as well as combinations
2783 /// that make no sense.
2784 ///
2785 /// ### Why is this bad?
2786 /// In the best case, the code will be harder to read than
2787 /// necessary. I don't know the worst case.
2788 ///
2789 /// ### Example
2790 /// ```rust
2791 /// use std::fs::OpenOptions;
2792 ///
2793 /// OpenOptions::new().read(true).truncate(true);
2794 /// ```
2795 #[clippy::version = "pre 1.29.0"]
2796 pub NONSENSICAL_OPEN_OPTIONS,
2797 correctness,
2798 "nonsensical combination of options for opening a file"
2799 }
2800
2801 declare_clippy_lint! {
2802 /// ### What it does
2803 ///* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push)
2804 /// calls on `PathBuf` that can cause overwrites.
2805 ///
2806 /// ### Why is this bad?
2807 /// Calling `push` with a root path at the start can overwrite the
2808 /// previous defined path.
2809 ///
2810 /// ### Example
2811 /// ```rust
2812 /// use std::path::PathBuf;
2813 ///
2814 /// let mut x = PathBuf::from("/foo");
2815 /// x.push("/bar");
2816 /// assert_eq!(x, PathBuf::from("/bar"));
2817 /// ```
2818 /// Could be written:
2819 ///
2820 /// ```rust
2821 /// use std::path::PathBuf;
2822 ///
2823 /// let mut x = PathBuf::from("/foo");
2824 /// x.push("bar");
2825 /// assert_eq!(x, PathBuf::from("/foo/bar"));
2826 /// ```
2827 #[clippy::version = "1.36.0"]
2828 pub PATH_BUF_PUSH_OVERWRITE,
2829 nursery,
2830 "calling `push` with file system root on `PathBuf` can overwrite it"
2831 }
2832
2833 declare_clippy_lint! {
2834 /// ### What it does
2835 /// Checks for zipping a collection with the range of
2836 /// `0.._.len()`.
2837 ///
2838 /// ### Why is this bad?
2839 /// The code is better expressed with `.enumerate()`.
2840 ///
2841 /// ### Example
2842 /// ```rust
2843 /// # let x = vec![1];
2844 /// let _ = x.iter().zip(0..x.len());
2845 /// ```
2846 ///
2847 /// Use instead:
2848 /// ```rust
2849 /// # let x = vec![1];
2850 /// let _ = x.iter().enumerate();
2851 /// ```
2852 #[clippy::version = "pre 1.29.0"]
2853 pub RANGE_ZIP_WITH_LEN,
2854 complexity,
2855 "zipping iterator with a range when `enumerate()` would do"
2856 }
2857
2858 declare_clippy_lint! {
2859 /// ### What it does
2860 /// Checks for usage of `.repeat(1)` and suggest the following method for each types.
2861 /// - `.to_string()` for `str`
2862 /// - `.clone()` for `String`
2863 /// - `.to_vec()` for `slice`
2864 ///
2865 /// The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if
2866 /// they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306))
2867 ///
2868 /// ### Why is this bad?
2869 /// For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning
2870 /// the string is the intention behind this, `clone()` should be used.
2871 ///
2872 /// ### Example
2873 /// ```rust
2874 /// fn main() {
2875 /// let x = String::from("hello world").repeat(1);
2876 /// }
2877 /// ```
2878 /// Use instead:
2879 /// ```rust
2880 /// fn main() {
2881 /// let x = String::from("hello world").clone();
2882 /// }
2883 /// ```
2884 #[clippy::version = "1.47.0"]
2885 pub REPEAT_ONCE,
2886 complexity,
2887 "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` "
2888 }
2889
2890 declare_clippy_lint! {
2891 /// ### What it does
2892 /// When sorting primitive values (integers, bools, chars, as well
2893 /// as arrays, slices, and tuples of such items), it is typically better to
2894 /// use an unstable sort than a stable sort.
2895 ///
2896 /// ### Why is this bad?
2897 /// Typically, using a stable sort consumes more memory and cpu cycles.
2898 /// Because values which compare equal are identical, preserving their
2899 /// relative order (the guarantee that a stable sort provides) means
2900 /// nothing, while the extra costs still apply.
2901 ///
2902 /// ### Known problems
2903 ///
2904 /// As pointed out in
2905 /// [issue #8241](https://github.com/rust-lang/rust-clippy/issues/8241),
2906 /// a stable sort can instead be significantly faster for certain scenarios
2907 /// (eg. when a sorted vector is extended with new data and resorted).
2908 ///
2909 /// For more information and benchmarking results, please refer to the
2910 /// issue linked above.
2911 ///
2912 /// ### Example
2913 /// ```rust
2914 /// let mut vec = vec![2, 1, 3];
2915 /// vec.sort();
2916 /// ```
2917 /// Use instead:
2918 /// ```rust
2919 /// let mut vec = vec![2, 1, 3];
2920 /// vec.sort_unstable();
2921 /// ```
2922 #[clippy::version = "1.47.0"]
2923 pub STABLE_SORT_PRIMITIVE,
2924 pedantic,
2925 "use of sort() when sort_unstable() is equivalent"
2926 }
2927
2928 declare_clippy_lint! {
2929 /// ### What it does
2930 /// Detects `().hash(_)`.
2931 ///
2932 /// ### Why is this bad?
2933 /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op.
2934 ///
2935 /// ### Example
2936 /// ```rust
2937 /// # use std::hash::Hash;
2938 /// # use std::collections::hash_map::DefaultHasher;
2939 /// # enum Foo { Empty, WithValue(u8) }
2940 /// # use Foo::*;
2941 /// # let mut state = DefaultHasher::new();
2942 /// # let my_enum = Foo::Empty;
2943 /// match my_enum {
2944 /// Empty => ().hash(&mut state),
2945 /// WithValue(x) => x.hash(&mut state),
2946 /// }
2947 /// ```
2948 /// Use instead:
2949 /// ```rust
2950 /// # use std::hash::Hash;
2951 /// # use std::collections::hash_map::DefaultHasher;
2952 /// # enum Foo { Empty, WithValue(u8) }
2953 /// # use Foo::*;
2954 /// # let mut state = DefaultHasher::new();
2955 /// # let my_enum = Foo::Empty;
2956 /// match my_enum {
2957 /// Empty => 0_u8.hash(&mut state),
2958 /// WithValue(x) => x.hash(&mut state),
2959 /// }
2960 /// ```
2961 #[clippy::version = "1.58.0"]
2962 pub UNIT_HASH,
2963 correctness,
2964 "hashing a unit value, which does nothing"
2965 }
2966
2967 declare_clippy_lint! {
2968 /// ### What it does
2969 /// Checks for usage of `Vec::sort_by` passing in a closure
2970 /// which compares the two arguments, either directly or indirectly.
2971 ///
2972 /// ### Why is this bad?
2973 /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if
2974 /// possible) than to use `Vec::sort_by` and a more complicated
2975 /// closure.
2976 ///
2977 /// ### Known problems
2978 /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already
2979 /// imported by a use statement, then it will need to be added manually.
2980 ///
2981 /// ### Example
2982 /// ```rust
2983 /// # struct A;
2984 /// # impl A { fn foo(&self) {} }
2985 /// # let mut vec: Vec<A> = Vec::new();
2986 /// vec.sort_by(|a, b| a.foo().cmp(&b.foo()));
2987 /// ```
2988 /// Use instead:
2989 /// ```rust
2990 /// # struct A;
2991 /// # impl A { fn foo(&self) {} }
2992 /// # let mut vec: Vec<A> = Vec::new();
2993 /// vec.sort_by_key(|a| a.foo());
2994 /// ```
2995 #[clippy::version = "1.46.0"]
2996 pub UNNECESSARY_SORT_BY,
2997 complexity,
2998 "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer"
2999 }
3000
3001 declare_clippy_lint! {
3002 /// ### What it does
3003 /// Finds occurrences of `Vec::resize(0, an_int)`
3004 ///
3005 /// ### Why is this bad?
3006 /// This is probably an argument inversion mistake.
3007 ///
3008 /// ### Example
3009 /// ```rust
3010 /// vec!(1, 2, 3, 4, 5).resize(0, 5)
3011 /// ```
3012 ///
3013 /// Use instead:
3014 /// ```rust
3015 /// vec!(1, 2, 3, 4, 5).clear()
3016 /// ```
3017 #[clippy::version = "1.46.0"]
3018 pub VEC_RESIZE_TO_ZERO,
3019 correctness,
3020 "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake"
3021 }
3022
3023 declare_clippy_lint! {
3024 /// ### What it does
3025 /// Checks for usage of File::read_to_end and File::read_to_string.
3026 ///
3027 /// ### Why is this bad?
3028 /// `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values.
3029 /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html)
3030 ///
3031 /// ### Example
3032 /// ```rust,no_run
3033 /// # use std::io::Read;
3034 /// # use std::fs::File;
3035 /// let mut f = File::open("foo.txt").unwrap();
3036 /// let mut bytes = Vec::new();
3037 /// f.read_to_end(&mut bytes).unwrap();
3038 /// ```
3039 /// Can be written more concisely as
3040 /// ```rust,no_run
3041 /// # use std::fs;
3042 /// let mut bytes = fs::read("foo.txt").unwrap();
3043 /// ```
3044 #[clippy::version = "1.44.0"]
3045 pub VERBOSE_FILE_READS,
3046 restriction,
3047 "use of `File::read_to_end` or `File::read_to_string`"
3048 }
3049
3050 declare_clippy_lint! {
3051 /// ### What it does
3052 ///
3053 /// Checks for iterating a map (`HashMap` or `BTreeMap`) and
3054 /// ignoring either the keys or values.
3055 ///
3056 /// ### Why is this bad?
3057 ///
3058 /// Readability. There are `keys` and `values` methods that
3059 /// can be used to express that we only need the keys or the values.
3060 ///
3061 /// ### Example
3062 ///
3063 /// ```
3064 /// # use std::collections::HashMap;
3065 /// let map: HashMap<u32, u32> = HashMap::new();
3066 /// let values = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
3067 /// ```
3068 ///
3069 /// Use instead:
3070 /// ```
3071 /// # use std::collections::HashMap;
3072 /// let map: HashMap<u32, u32> = HashMap::new();
3073 /// let values = map.values().collect::<Vec<_>>();
3074 /// ```
3075 #[clippy::version = "1.66.0"]
3076 pub ITER_KV_MAP,
3077 complexity,
3078 "iterating on map using `iter` when `keys` or `values` would do"
3079 }
3080
3081 declare_clippy_lint! {
3082 /// ### What it does
3083 ///
3084 /// Checks an argument of `seek` method of `Seek` trait
3085 /// and if it start seek from `SeekFrom::Current(0)`, suggests `stream_position` instead.
3086 ///
3087 /// ### Why is this bad?
3088 ///
3089 /// Readability. Use dedicated method.
3090 ///
3091 /// ### Example
3092 ///
3093 /// ```rust,no_run
3094 /// use std::fs::File;
3095 /// use std::io::{self, Write, Seek, SeekFrom};
3096 ///
3097 /// fn main() -> io::Result<()> {
3098 /// let mut f = File::create("foo.txt")?;
3099 /// f.write_all(b"Hello")?;
3100 /// eprintln!("Written {} bytes", f.seek(SeekFrom::Current(0))?);
3101 ///
3102 /// Ok(())
3103 /// }
3104 /// ```
3105 /// Use instead:
3106 /// ```rust,no_run
3107 /// use std::fs::File;
3108 /// use std::io::{self, Write, Seek, SeekFrom};
3109 ///
3110 /// fn main() -> io::Result<()> {
3111 /// let mut f = File::create("foo.txt")?;
3112 /// f.write_all(b"Hello")?;
3113 /// eprintln!("Written {} bytes", f.stream_position()?);
3114 ///
3115 /// Ok(())
3116 /// }
3117 /// ```
3118 #[clippy::version = "1.67.0"]
3119 pub SEEK_FROM_CURRENT,
3120 complexity,
3121 "use dedicated method for seek from current position"
3122 }
3123
3124 declare_clippy_lint! {
3125 /// ### What it does
3126 ///
3127 /// Checks for jumps to the start of a stream that implements `Seek`
3128 /// and uses the `seek` method providing `Start` as parameter.
3129 ///
3130 /// ### Why is this bad?
3131 ///
3132 /// Readability. There is a specific method that was implemented for
3133 /// this exact scenario.
3134 ///
3135 /// ### Example
3136 /// ```rust
3137 /// # use std::io;
3138 /// fn foo<T: io::Seek>(t: &mut T) {
3139 /// t.seek(io::SeekFrom::Start(0));
3140 /// }
3141 /// ```
3142 /// Use instead:
3143 /// ```rust
3144 /// # use std::io;
3145 /// fn foo<T: io::Seek>(t: &mut T) {
3146 /// t.rewind();
3147 /// }
3148 /// ```
3149 #[clippy::version = "1.67.0"]
3150 pub SEEK_TO_START_INSTEAD_OF_REWIND,
3151 complexity,
3152 "jumping to the start of stream using `seek` method"
3153 }
3154
3155 declare_clippy_lint! {
3156 /// ### What it does
3157 /// Checks for functions collecting an iterator when collect
3158 /// is not needed.
3159 ///
3160 /// ### Why is this bad?
3161 /// `collect` causes the allocation of a new data structure,
3162 /// when this allocation may not be needed.
3163 ///
3164 /// ### Example
3165 /// ```rust
3166 /// # let iterator = vec![1].into_iter();
3167 /// let len = iterator.collect::<Vec<_>>().len();
3168 /// ```
3169 /// Use instead:
3170 /// ```rust
3171 /// # let iterator = vec![1].into_iter();
3172 /// let len = iterator.count();
3173 /// ```
3174 #[clippy::version = "1.30.0"]
3175 pub NEEDLESS_COLLECT,
3176 nursery,
3177 "collecting an iterator when collect is not needed"
3178 }
3179
3180 declare_clippy_lint! {
3181 /// ### What it does
3182 ///
3183 /// Checks for `Command::arg()` invocations that look like they
3184 /// should be multiple arguments instead, such as `arg("-t ext2")`.
3185 ///
3186 /// ### Why is this bad?
3187 ///
3188 /// `Command::arg()` does not split arguments by space. An argument like `arg("-t ext2")`
3189 /// will be passed as a single argument to the command,
3190 /// which is likely not what was intended.
3191 ///
3192 /// ### Example
3193 /// ```rust
3194 /// std::process::Command::new("echo").arg("-n hello").spawn().unwrap();
3195 /// ```
3196 /// Use instead:
3197 /// ```rust
3198 /// std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap();
3199 /// ```
3200 #[clippy::version = "1.69.0"]
3201 pub SUSPICIOUS_COMMAND_ARG_SPACE,
3202 suspicious,
3203 "single command line argument that looks like it should be multiple arguments"
3204 }
3205
3206 declare_clippy_lint! {
3207 /// ### What it does
3208 /// Checks for usage of `.drain(..)` for the sole purpose of clearing a container.
3209 ///
3210 /// ### Why is this bad?
3211 /// This creates an unnecessary iterator that is dropped immediately.
3212 ///
3213 /// Calling `.clear()` also makes the intent clearer.
3214 ///
3215 /// ### Example
3216 /// ```rust
3217 /// let mut v = vec![1, 2, 3];
3218 /// v.drain(..);
3219 /// ```
3220 /// Use instead:
3221 /// ```rust
3222 /// let mut v = vec![1, 2, 3];
3223 /// v.clear();
3224 /// ```
3225 #[clippy::version = "1.70.0"]
3226 pub CLEAR_WITH_DRAIN,
3227 nursery,
3228 "calling `drain` in order to `clear` a container"
3229 }
3230
3231 declare_clippy_lint! {
3232 /// ### What it does
3233 /// Checks for `.rev().next()` on a `DoubleEndedIterator`
3234 ///
3235 /// ### Why is this bad?
3236 /// `.next_back()` is cleaner.
3237 ///
3238 /// ### Example
3239 /// ```rust
3240 /// # let foo = [0; 10];
3241 /// foo.iter().rev().next();
3242 /// ```
3243 /// Use instead:
3244 /// ```rust
3245 /// # let foo = [0; 10];
3246 /// foo.iter().next_back();
3247 /// ```
3248 #[clippy::version = "1.71.0"]
3249 pub MANUAL_NEXT_BACK,
3250 style,
3251 "manual reverse iteration of `DoubleEndedIterator`"
3252 }
3253
3254 declare_clippy_lint! {
3255 /// ### What it does
3256 /// Checks for calls to `.drain()` that clear the collection, immediately followed by a call to `.collect()`.
3257 ///
3258 /// > "Collection" in this context refers to any type with a `drain` method:
3259 /// > `Vec`, `VecDeque`, `BinaryHeap`, `HashSet`,`HashMap`, `String`
3260 ///
3261 /// ### Why is this bad?
3262 /// Using `mem::take` is faster as it avoids the allocation.
3263 /// When using `mem::take`, the old collection is replaced with an empty one and ownership of
3264 /// the old collection is returned.
3265 ///
3266 /// ### Known issues
3267 /// `mem::take(&mut vec)` is almost equivalent to `vec.drain(..).collect()`, except that
3268 /// it also moves the **capacity**. The user might have explicitly written it this way
3269 /// to keep the capacity on the original `Vec`.
3270 ///
3271 /// ### Example
3272 /// ```rust
3273 /// fn remove_all(v: &mut Vec<i32>) -> Vec<i32> {
3274 /// v.drain(..).collect()
3275 /// }
3276 /// ```
3277 /// Use instead:
3278 /// ```rust
3279 /// use std::mem;
3280 /// fn remove_all(v: &mut Vec<i32>) -> Vec<i32> {
3281 /// mem::take(v)
3282 /// }
3283 /// ```
3284 #[clippy::version = "1.71.0"]
3285 pub DRAIN_COLLECT,
3286 perf,
3287 "calling `.drain(..).collect()` to move all elements into a new collection"
3288 }
3289
3290 declare_clippy_lint! {
3291 /// ### What it does
3292 /// Checks for usage of `Iterator::fold` with a type that implements `Try`.
3293 ///
3294 /// ### Why is this bad?
3295 /// The code should use `try_fold` instead, which short-circuits on failure, thus opening the
3296 /// door for additional optimizations not possible with `fold` as rustc can guarantee the
3297 /// function is never called on `None`, `Err`, etc., alleviating otherwise necessary checks. It's
3298 /// also slightly more idiomatic.
3299 ///
3300 /// ### Known issues
3301 /// This lint doesn't take into account whether a function does something on the failure case,
3302 /// i.e., whether short-circuiting will affect behavior. Refactoring to `try_fold` is not
3303 /// desirable in those cases.
3304 ///
3305 /// ### Example
3306 /// ```rust
3307 /// vec![1, 2, 3].iter().fold(Some(0i32), |sum, i| sum?.checked_add(*i));
3308 /// ```
3309 /// Use instead:
3310 /// ```rust
3311 /// vec![1, 2, 3].iter().try_fold(0i32, |sum, i| sum.checked_add(*i));
3312 /// ```
3313 #[clippy::version = "1.72.0"]
3314 pub MANUAL_TRY_FOLD,
3315 perf,
3316 "checks for usage of `Iterator::fold` with a type that implements `Try`"
3317 }
3318
3319 pub struct Methods {
3320 avoid_breaking_exported_api: bool,
3321 msrv: Msrv,
3322 allow_expect_in_tests: bool,
3323 allow_unwrap_in_tests: bool,
3324 }
3325
3326 impl Methods {
3327 #[must_use]
new( avoid_breaking_exported_api: bool, msrv: Msrv, allow_expect_in_tests: bool, allow_unwrap_in_tests: bool, ) -> Self3328 pub fn new(
3329 avoid_breaking_exported_api: bool,
3330 msrv: Msrv,
3331 allow_expect_in_tests: bool,
3332 allow_unwrap_in_tests: bool,
3333 ) -> Self {
3334 Self {
3335 avoid_breaking_exported_api,
3336 msrv,
3337 allow_expect_in_tests,
3338 allow_unwrap_in_tests,
3339 }
3340 }
3341 }
3342
3343 impl_lint_pass!(Methods => [
3344 UNWRAP_USED,
3345 EXPECT_USED,
3346 SHOULD_IMPLEMENT_TRAIT,
3347 WRONG_SELF_CONVENTION,
3348 OK_EXPECT,
3349 UNWRAP_OR_ELSE_DEFAULT,
3350 MAP_UNWRAP_OR,
3351 RESULT_MAP_OR_INTO_OPTION,
3352 OPTION_MAP_OR_NONE,
3353 BIND_INSTEAD_OF_MAP,
3354 OR_FUN_CALL,
3355 OR_THEN_UNWRAP,
3356 EXPECT_FUN_CALL,
3357 CHARS_NEXT_CMP,
3358 CHARS_LAST_CMP,
3359 CLONE_ON_COPY,
3360 CLONE_ON_REF_PTR,
3361 COLLAPSIBLE_STR_REPLACE,
3362 ITER_OVEREAGER_CLONED,
3363 CLONED_INSTEAD_OF_COPIED,
3364 FLAT_MAP_OPTION,
3365 INEFFICIENT_TO_STRING,
3366 NEW_RET_NO_SELF,
3367 SINGLE_CHAR_PATTERN,
3368 SINGLE_CHAR_ADD_STR,
3369 SEARCH_IS_SOME,
3370 FILTER_NEXT,
3371 SKIP_WHILE_NEXT,
3372 FILTER_MAP_IDENTITY,
3373 MAP_IDENTITY,
3374 MANUAL_FILTER_MAP,
3375 MANUAL_FIND_MAP,
3376 OPTION_FILTER_MAP,
3377 FILTER_MAP_NEXT,
3378 FLAT_MAP_IDENTITY,
3379 MAP_FLATTEN,
3380 ITERATOR_STEP_BY_ZERO,
3381 ITER_NEXT_SLICE,
3382 ITER_COUNT,
3383 ITER_NTH,
3384 ITER_NTH_ZERO,
3385 BYTES_NTH,
3386 ITER_SKIP_NEXT,
3387 GET_UNWRAP,
3388 GET_LAST_WITH_LEN,
3389 STRING_EXTEND_CHARS,
3390 ITER_CLONED_COLLECT,
3391 ITER_WITH_DRAIN,
3392 USELESS_ASREF,
3393 UNNECESSARY_FOLD,
3394 UNNECESSARY_FILTER_MAP,
3395 UNNECESSARY_FIND_MAP,
3396 INTO_ITER_ON_REF,
3397 SUSPICIOUS_MAP,
3398 UNINIT_ASSUMED_INIT,
3399 MANUAL_SATURATING_ARITHMETIC,
3400 ZST_OFFSET,
3401 FILETYPE_IS_FILE,
3402 OPTION_AS_REF_DEREF,
3403 UNNECESSARY_LAZY_EVALUATIONS,
3404 MAP_COLLECT_RESULT_UNIT,
3405 FROM_ITER_INSTEAD_OF_COLLECT,
3406 INSPECT_FOR_EACH,
3407 IMPLICIT_CLONE,
3408 SUSPICIOUS_TO_OWNED,
3409 SUSPICIOUS_SPLITN,
3410 MANUAL_STR_REPEAT,
3411 EXTEND_WITH_DRAIN,
3412 MANUAL_SPLIT_ONCE,
3413 NEEDLESS_SPLITN,
3414 UNNECESSARY_TO_OWNED,
3415 UNNECESSARY_JOIN,
3416 ERR_EXPECT,
3417 NEEDLESS_OPTION_AS_DEREF,
3418 IS_DIGIT_ASCII_RADIX,
3419 NEEDLESS_OPTION_TAKE,
3420 NO_EFFECT_REPLACE,
3421 OBFUSCATED_IF_ELSE,
3422 ITER_ON_SINGLE_ITEMS,
3423 ITER_ON_EMPTY_COLLECTIONS,
3424 NAIVE_BYTECOUNT,
3425 BYTES_COUNT_TO_LEN,
3426 CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
3427 GET_FIRST,
3428 MANUAL_OK_OR,
3429 MAP_CLONE,
3430 MAP_ERR_IGNORE,
3431 MUT_MUTEX_LOCK,
3432 NONSENSICAL_OPEN_OPTIONS,
3433 PATH_BUF_PUSH_OVERWRITE,
3434 RANGE_ZIP_WITH_LEN,
3435 REPEAT_ONCE,
3436 STABLE_SORT_PRIMITIVE,
3437 UNIT_HASH,
3438 UNNECESSARY_SORT_BY,
3439 VEC_RESIZE_TO_ZERO,
3440 VERBOSE_FILE_READS,
3441 ITER_KV_MAP,
3442 SEEK_FROM_CURRENT,
3443 SEEK_TO_START_INSTEAD_OF_REWIND,
3444 NEEDLESS_COLLECT,
3445 SUSPICIOUS_COMMAND_ARG_SPACE,
3446 CLEAR_WITH_DRAIN,
3447 MANUAL_NEXT_BACK,
3448 UNNECESSARY_LITERAL_UNWRAP,
3449 DRAIN_COLLECT,
3450 MANUAL_TRY_FOLD,
3451 ]);
3452
3453 /// Extracts a method call name, args, and `Span` of the method name.
method_call<'tcx>( recv: &'tcx hir::Expr<'tcx>, ) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span, Span)>3454 fn method_call<'tcx>(
3455 recv: &'tcx hir::Expr<'tcx>,
3456 ) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span, Span)> {
3457 if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind {
3458 if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() {
3459 let name = path.ident.name.as_str();
3460 return Some((name, receiver, args, path.ident.span, call_span));
3461 }
3462 }
3463 None
3464 }
3465
3466 impl<'tcx> LateLintPass<'tcx> for Methods {
check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>)3467 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
3468 if expr.span.from_expansion() {
3469 return;
3470 }
3471
3472 self.check_methods(cx, expr);
3473
3474 match expr.kind {
3475 hir::ExprKind::Call(func, args) => {
3476 from_iter_instead_of_collect::check(cx, expr, args, func);
3477 },
3478 hir::ExprKind::MethodCall(method_call, receiver, args, _) => {
3479 let method_span = method_call.ident.span;
3480 or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
3481 expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
3482 clone_on_copy::check(cx, expr, method_call.ident.name, receiver, args);
3483 clone_on_ref_ptr::check(cx, expr, method_call.ident.name, receiver, args);
3484 inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args);
3485 single_char_add_str::check(cx, expr, receiver, args);
3486 into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver);
3487 single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args);
3488 unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, &self.msrv);
3489 },
3490 hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
3491 let mut info = BinaryExprInfo {
3492 expr,
3493 chain: lhs,
3494 other: rhs,
3495 eq: op.node == hir::BinOpKind::Eq,
3496 };
3497 lint_binary_expr_with_method_call(cx, &mut info);
3498 },
3499 _ => (),
3500 }
3501 }
3502
3503 #[allow(clippy::too_many_lines)]
check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>)3504 fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
3505 if in_external_macro(cx.sess(), impl_item.span) {
3506 return;
3507 }
3508 let name = impl_item.ident.name.as_str();
3509 let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
3510 let item = cx.tcx.hir().expect_item(parent);
3511 let self_ty = cx.tcx.type_of(item.owner_id).subst_identity();
3512
3513 let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
3514 if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind {
3515 let method_sig = cx.tcx.fn_sig(impl_item.owner_id).subst_identity();
3516 let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
3517 let first_arg_ty_opt = method_sig.inputs().iter().next().copied();
3518 // if this impl block implements a trait, lint in trait definition instead
3519 if !implements_trait && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) {
3520 // check missing trait implementations
3521 for method_config in &TRAIT_METHODS {
3522 if name == method_config.method_name
3523 && sig.decl.inputs.len() == method_config.param_count
3524 && method_config.output_type.matches(&sig.decl.output)
3525 // in case there is no first arg, since we already have checked the number of arguments
3526 // it's should be always true
3527 && first_arg_ty_opt.map_or(true, |first_arg_ty| method_config
3528 .self_kind.matches(cx, self_ty, first_arg_ty)
3529 )
3530 && fn_header_equals(method_config.fn_header, sig.header)
3531 && method_config.lifetime_param_cond(impl_item)
3532 {
3533 span_lint_and_help(
3534 cx,
3535 SHOULD_IMPLEMENT_TRAIT,
3536 impl_item.span,
3537 &format!(
3538 "method `{}` can be confused for the standard trait method `{}::{}`",
3539 method_config.method_name, method_config.trait_name, method_config.method_name
3540 ),
3541 None,
3542 &format!(
3543 "consider implementing the trait `{}` or choosing a less ambiguous method name",
3544 method_config.trait_name
3545 ),
3546 );
3547 }
3548 }
3549 }
3550
3551 if sig.decl.implicit_self.has_implicit_self()
3552 && !(self.avoid_breaking_exported_api
3553 && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id))
3554 && let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next()
3555 && let Some(first_arg_ty) = first_arg_ty_opt
3556 {
3557 wrong_self_convention::check(
3558 cx,
3559 name,
3560 self_ty,
3561 first_arg_ty,
3562 first_arg.pat.span,
3563 implements_trait,
3564 false
3565 );
3566 }
3567 }
3568
3569 // if this impl block implements a trait, lint in trait definition instead
3570 if implements_trait {
3571 return;
3572 }
3573
3574 if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
3575 let ret_ty = return_ty(cx, impl_item.owner_id);
3576
3577 if contains_ty_adt_constructor_opaque(cx, ret_ty, self_ty) {
3578 return;
3579 }
3580
3581 if name == "new" && ret_ty != self_ty {
3582 span_lint(
3583 cx,
3584 NEW_RET_NO_SELF,
3585 impl_item.span,
3586 "methods called `new` usually return `Self`",
3587 );
3588 }
3589 }
3590 }
3591
check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>)3592 fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
3593 if in_external_macro(cx.tcx.sess, item.span) {
3594 return;
3595 }
3596
3597 if_chain! {
3598 if let TraitItemKind::Fn(ref sig, _) = item.kind;
3599 if sig.decl.implicit_self.has_implicit_self();
3600 if let Some(first_arg_ty) = sig.decl.inputs.iter().next();
3601
3602 then {
3603 let first_arg_span = first_arg_ty.span;
3604 let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
3605 let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
3606 .self_ty();
3607 wrong_self_convention::check(
3608 cx,
3609 item.ident.name.as_str(),
3610 self_ty,
3611 first_arg_ty,
3612 first_arg_span,
3613 false,
3614 true,
3615 );
3616 }
3617 }
3618
3619 if_chain! {
3620 if item.ident.name == sym::new;
3621 if let TraitItemKind::Fn(_, _) = item.kind;
3622 let ret_ty = return_ty(cx, item.owner_id);
3623 let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
3624 .self_ty();
3625 if !ret_ty.contains(self_ty);
3626
3627 then {
3628 span_lint(
3629 cx,
3630 NEW_RET_NO_SELF,
3631 item.span,
3632 "methods called `new` usually return `Self`",
3633 );
3634 }
3635 }
3636 }
3637
3638 extract_msrv_attr!(LateContext);
3639 }
3640
3641 impl Methods {
3642 #[allow(clippy::too_many_lines)]
check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)3643 fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
3644 if let Some((name, recv, args, span, call_span)) = method_call(expr) {
3645 match (name, args) {
3646 ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
3647 zst_offset::check(cx, expr, recv);
3648 },
3649 ("and_then", [arg]) => {
3650 let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
3651 let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg);
3652 if !biom_option_linted && !biom_result_linted {
3653 unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
3654 }
3655 },
3656 ("arg", [arg]) => {
3657 suspicious_command_arg_space::check(cx, recv, arg, span);
3658 }
3659 ("as_deref" | "as_deref_mut", []) => {
3660 needless_option_as_deref::check(cx, expr, recv, name);
3661 },
3662 ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
3663 ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
3664 ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
3665 ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, &self.msrv),
3666 ("collect", []) if is_trait_method(cx, expr, sym::Iterator) => {
3667 needless_collect::check(cx, span, expr, recv, call_span);
3668 match method_call(recv) {
3669 Some((name @ ("cloned" | "copied"), recv2, [], _, _)) => {
3670 iter_cloned_collect::check(cx, name, expr, recv2);
3671 },
3672 Some(("map", m_recv, [m_arg], _, _)) => {
3673 map_collect_result_unit::check(cx, expr, m_recv, m_arg);
3674 },
3675 Some(("take", take_self_arg, [take_arg], _, _)) => {
3676 if self.msrv.meets(msrvs::STR_REPEAT) {
3677 manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
3678 }
3679 },
3680 Some(("drain", recv, args, ..)) => {
3681 drain_collect::check(cx, args, expr, recv);
3682 }
3683 _ => {},
3684 }
3685 },
3686 ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
3687 Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
3688 Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _, _)) => {
3689 iter_count::check(cx, expr, recv2, name2);
3690 },
3691 Some(("map", _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg),
3692 Some(("filter", recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg),
3693 Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
3694 _ => {},
3695 },
3696 ("drain", ..) => {
3697 if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.hir().get_parent(expr.hir_id)
3698 && matches!(kind, StmtKind::Semi(_))
3699 && args.len() <= 1
3700 {
3701 clear_with_drain::check(cx, expr, recv, span, args.first());
3702 } else if let [arg] = args {
3703 iter_with_drain::check(cx, expr, recv, span, arg);
3704 }
3705 },
3706 ("ends_with", [arg]) => {
3707 if let ExprKind::MethodCall(.., span) = expr.kind {
3708 case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg);
3709 }
3710 },
3711 ("expect", [_]) => {
3712 match method_call(recv) {
3713 Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
3714 Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv),
3715 _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
3716 }
3717 unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
3718 },
3719 ("expect_err", [_]) => {
3720 unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
3721 expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests);
3722 },
3723 ("extend", [arg]) => {
3724 string_extend_chars::check(cx, expr, recv, arg);
3725 extend_with_drain::check(cx, expr, recv, arg);
3726 },
3727 ("filter_map", [arg]) => {
3728 unnecessary_filter_map::check(cx, expr, arg, name);
3729 filter_map_identity::check(cx, expr, arg, span);
3730 },
3731 ("find_map", [arg]) => {
3732 unnecessary_filter_map::check(cx, expr, arg, name);
3733 },
3734 ("flat_map", [arg]) => {
3735 flat_map_identity::check(cx, expr, arg, span);
3736 flat_map_option::check(cx, expr, arg, span);
3737 },
3738 ("flatten", []) => match method_call(recv) {
3739 Some(("map", recv, [map_arg], map_span, _)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
3740 Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
3741 _ => {},
3742 },
3743 ("fold", [init, acc]) => {
3744 manual_try_fold::check(cx, expr, init, acc, call_span, &self.msrv);
3745 unnecessary_fold::check(cx, expr, init, acc, span);
3746 },
3747 ("for_each", [_]) => {
3748 if let Some(("inspect", _, [_], span2, _)) = method_call(recv) {
3749 inspect_for_each::check(cx, expr, span2);
3750 }
3751 },
3752 ("get", [arg]) => {
3753 get_first::check(cx, expr, recv, arg);
3754 get_last_with_len::check(cx, expr, recv, arg);
3755 },
3756 ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
3757 ("hash", [arg]) => {
3758 unit_hash::check(cx, expr, recv, arg);
3759 },
3760 ("is_file", []) => filetype_is_file::check(cx, expr, recv),
3761 ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, &self.msrv),
3762 ("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
3763 ("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
3764 ("iter" | "iter_mut" | "into_iter", []) => {
3765 iter_on_single_or_empty_collections::check(cx, expr, name, recv);
3766 },
3767 ("join", [join_arg]) => {
3768 if let Some(("collect", _, _, span, _)) = method_call(recv) {
3769 unnecessary_join::check(cx, expr, recv, join_arg, span);
3770 }
3771 },
3772 ("last", []) | ("skip", [_]) => {
3773 if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
3774 if let ("cloned", []) = (name2, args2) {
3775 iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
3776 }
3777 }
3778 },
3779 ("lock", []) => {
3780 mut_mutex_lock::check(cx, expr, recv, span);
3781 },
3782 (name @ ("map" | "map_err"), [m_arg]) => {
3783 if name == "map" {
3784 map_clone::check(cx, expr, recv, m_arg, &self.msrv);
3785 if let Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) = method_call(recv) {
3786 iter_kv_map::check(cx, map_name, expr, recv2, m_arg);
3787 }
3788 } else {
3789 map_err_ignore::check(cx, expr, m_arg);
3790 }
3791 if let Some((name, recv2, args, span2,_)) = method_call(recv) {
3792 match (name, args) {
3793 ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, &self.msrv),
3794 ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, &self.msrv),
3795 ("filter", [f_arg]) => {
3796 filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
3797 },
3798 ("find", [f_arg]) => {
3799 filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true);
3800 },
3801 _ => {},
3802 }
3803 }
3804 map_identity::check(cx, expr, recv, m_arg, name, span);
3805 },
3806 ("map_or", [def, map]) => {
3807 option_map_or_none::check(cx, expr, recv, def, map);
3808 manual_ok_or::check(cx, expr, recv, def, map);
3809 },
3810 ("next", []) => {
3811 if let Some((name2, recv2, args2, _, _)) = method_call(recv) {
3812 match (name2, args2) {
3813 ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
3814 ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
3815 ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, &self.msrv),
3816 ("iter", []) => iter_next_slice::check(cx, expr, recv2),
3817 ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
3818 ("skip_while", [_]) => skip_while_next::check(cx, expr),
3819 ("rev", [])=> manual_next_back::check(cx, expr, recv, recv2),
3820 _ => {},
3821 }
3822 }
3823 },
3824 ("nth", [n_arg]) => match method_call(recv) {
3825 Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
3826 Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
3827 Some(("iter", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
3828 Some(("iter_mut", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
3829 _ => iter_nth_zero::check(cx, expr, recv, n_arg),
3830 },
3831 ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
3832 ("open", [_]) => {
3833 open_options::check(cx, expr, recv);
3834 },
3835 ("or_else", [arg]) => {
3836 if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
3837 unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
3838 }
3839 },
3840 ("push", [arg]) => {
3841 path_buf_push_overwrite::check(cx, expr, arg);
3842 },
3843 ("read_to_end", [_]) => {
3844 verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_END_MSG);
3845 },
3846 ("read_to_string", [_]) => {
3847 verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG);
3848 },
3849 ("repeat", [arg]) => {
3850 repeat_once::check(cx, expr, recv, arg);
3851 },
3852 (name @ ("replace" | "replacen"), [arg1, arg2] | [arg1, arg2, _]) => {
3853 no_effect_replace::check(cx, expr, arg1, arg2);
3854
3855 // Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint
3856 if self.msrv.meets(msrvs::PATTERN_TRAIT_CHAR_ARRAY)
3857 && name == "replace"
3858 && let Some(("replace", ..)) = method_call(recv)
3859 {
3860 collapsible_str_replace::check(cx, expr, arg1, arg2);
3861 }
3862 },
3863 ("resize", [count_arg, default_arg]) => {
3864 vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span);
3865 },
3866 ("seek", [arg]) => {
3867 if self.msrv.meets(msrvs::SEEK_FROM_CURRENT) {
3868 seek_from_current::check(cx, expr, recv, arg);
3869 }
3870 if self.msrv.meets(msrvs::SEEK_REWIND) {
3871 seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span);
3872 }
3873 },
3874 ("sort", []) => {
3875 stable_sort_primitive::check(cx, expr, recv);
3876 },
3877 ("sort_by", [arg]) => {
3878 unnecessary_sort_by::check(cx, expr, recv, arg, false);
3879 },
3880 ("sort_unstable_by", [arg]) => {
3881 unnecessary_sort_by::check(cx, expr, recv, arg, true);
3882 },
3883 ("splitn" | "rsplitn", [count_arg, pat_arg]) => {
3884 if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) {
3885 suspicious_splitn::check(cx, name, expr, recv, count);
3886 str_splitn::check(cx, name, expr, recv, pat_arg, count, &self.msrv);
3887 }
3888 },
3889 ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
3890 if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) {
3891 suspicious_splitn::check(cx, name, expr, recv, count);
3892 }
3893 },
3894 ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
3895 ("take", [_arg]) => {
3896 if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
3897 if let ("cloned", []) = (name2, args2) {
3898 iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
3899 }
3900 }
3901 },
3902 ("take", []) => needless_option_take::check(cx, expr, recv),
3903 ("then", [arg]) => {
3904 if !self.msrv.meets(msrvs::BOOL_THEN_SOME) {
3905 return;
3906 }
3907 unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some");
3908 },
3909 ("to_owned", []) => {
3910 if !suspicious_to_owned::check(cx, expr, recv) {
3911 implicit_clone::check(cx, name, expr, recv);
3912 }
3913 },
3914 ("to_os_string" | "to_path_buf" | "to_vec", []) => {
3915 implicit_clone::check(cx, name, expr, recv);
3916 },
3917 ("unwrap", []) => {
3918 match method_call(recv) {
3919 Some(("get", recv, [get_arg], _, _)) => {
3920 get_unwrap::check(cx, expr, recv, get_arg, false);
3921 },
3922 Some(("get_mut", recv, [get_arg], _, _)) => {
3923 get_unwrap::check(cx, expr, recv, get_arg, true);
3924 },
3925 Some(("or", recv, [or_arg], or_span, _)) => {
3926 or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
3927 },
3928 _ => {},
3929 }
3930 unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
3931 unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests);
3932 },
3933 ("unwrap_err", []) => {
3934 unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
3935 unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests);
3936 },
3937 ("unwrap_or", [u_arg]) => {
3938 match method_call(recv) {
3939 Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _, _)) => {
3940 manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
3941 },
3942 Some(("map", m_recv, [m_arg], span, _)) => {
3943 option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, &self.msrv);
3944 },
3945 Some(("then_some", t_recv, [t_arg], _, _)) => {
3946 obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg);
3947 },
3948 _ => {},
3949 }
3950 unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
3951 },
3952 ("unwrap_or_default", []) => {
3953 unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
3954 }
3955 ("unwrap_or_else", [u_arg]) => {
3956 match method_call(recv) {
3957 Some(("map", recv, [map_arg], _, _))
3958 if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, &self.msrv) => {},
3959 _ => {
3960 unwrap_or_else_default::check(cx, expr, recv, u_arg);
3961 unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
3962 },
3963 }
3964 unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
3965 },
3966 ("zip", [arg]) => {
3967 if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
3968 && name.ident.name == sym::iter
3969 {
3970 range_zip_with_len::check(cx, expr, iter_recv, arg);
3971 }
3972 },
3973 _ => {},
3974 }
3975 }
3976 }
3977 }
3978
check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool)3979 fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
3980 if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span, _)) = method_call(recv) {
3981 search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
3982 }
3983 }
3984
3985 /// Used for `lint_binary_expr_with_method_call`.
3986 #[derive(Copy, Clone)]
3987 struct BinaryExprInfo<'a> {
3988 expr: &'a hir::Expr<'a>,
3989 chain: &'a hir::Expr<'a>,
3990 other: &'a hir::Expr<'a>,
3991 eq: bool,
3992 }
3993
3994 /// Checks for the `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExprInfo<'_>)3995 fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExprInfo<'_>) {
3996 macro_rules! lint_with_both_lhs_and_rhs {
3997 ($func:expr, $cx:expr, $info:ident) => {
3998 if !$func($cx, $info) {
3999 ::std::mem::swap(&mut $info.chain, &mut $info.other);
4000 if $func($cx, $info) {
4001 return;
4002 }
4003 }
4004 };
4005 }
4006
4007 lint_with_both_lhs_and_rhs!(chars_next_cmp::check, cx, info);
4008 lint_with_both_lhs_and_rhs!(chars_last_cmp::check, cx, info);
4009 lint_with_both_lhs_and_rhs!(chars_next_cmp_with_unwrap::check, cx, info);
4010 lint_with_both_lhs_and_rhs!(chars_last_cmp_with_unwrap::check, cx, info);
4011 }
4012
4013 const FN_HEADER: hir::FnHeader = hir::FnHeader {
4014 unsafety: hir::Unsafety::Normal,
4015 constness: hir::Constness::NotConst,
4016 asyncness: hir::IsAsync::NotAsync,
4017 abi: rustc_target::spec::abi::Abi::Rust,
4018 };
4019
4020 struct ShouldImplTraitCase {
4021 trait_name: &'static str,
4022 method_name: &'static str,
4023 param_count: usize,
4024 fn_header: hir::FnHeader,
4025 // implicit self kind expected (none, self, &self, ...)
4026 self_kind: SelfKind,
4027 // checks against the output type
4028 output_type: OutType,
4029 // certain methods with explicit lifetimes can't implement the equivalent trait method
4030 lint_explicit_lifetime: bool,
4031 }
4032 impl ShouldImplTraitCase {
new( trait_name: &'static str, method_name: &'static str, param_count: usize, fn_header: hir::FnHeader, self_kind: SelfKind, output_type: OutType, lint_explicit_lifetime: bool, ) -> ShouldImplTraitCase4033 const fn new(
4034 trait_name: &'static str,
4035 method_name: &'static str,
4036 param_count: usize,
4037 fn_header: hir::FnHeader,
4038 self_kind: SelfKind,
4039 output_type: OutType,
4040 lint_explicit_lifetime: bool,
4041 ) -> ShouldImplTraitCase {
4042 ShouldImplTraitCase {
4043 trait_name,
4044 method_name,
4045 param_count,
4046 fn_header,
4047 self_kind,
4048 output_type,
4049 lint_explicit_lifetime,
4050 }
4051 }
4052
lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool4053 fn lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool {
4054 self.lint_explicit_lifetime
4055 || !impl_item.generics.params.iter().any(|p| {
4056 matches!(
4057 p.kind,
4058 hir::GenericParamKind::Lifetime {
4059 kind: hir::LifetimeParamKind::Explicit
4060 }
4061 )
4062 })
4063 }
4064 }
4065
4066 #[rustfmt::skip]
4067 const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
4068 ShouldImplTraitCase::new("std::ops::Add", "add", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
4069 ShouldImplTraitCase::new("std::convert::AsMut", "as_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
4070 ShouldImplTraitCase::new("std::convert::AsRef", "as_ref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
4071 ShouldImplTraitCase::new("std::ops::BitAnd", "bitand", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
4072 ShouldImplTraitCase::new("std::ops::BitOr", "bitor", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
4073 ShouldImplTraitCase::new("std::ops::BitXor", "bitxor", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
4074 ShouldImplTraitCase::new("std::borrow::Borrow", "borrow", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
4075 ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
4076 ShouldImplTraitCase::new("std::clone::Clone", "clone", 1, FN_HEADER, SelfKind::Ref, OutType::Any, true),
4077 ShouldImplTraitCase::new("std::cmp::Ord", "cmp", 2, FN_HEADER, SelfKind::Ref, OutType::Any, true),
4078 ShouldImplTraitCase::new("std::default::Default", "default", 0, FN_HEADER, SelfKind::No, OutType::Any, true),
4079 ShouldImplTraitCase::new("std::ops::Deref", "deref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
4080 ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
4081 ShouldImplTraitCase::new("std::ops::Div", "div", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
4082 ShouldImplTraitCase::new("std::ops::Drop", "drop", 1, FN_HEADER, SelfKind::RefMut, OutType::Unit, true),
4083 ShouldImplTraitCase::new("std::cmp::PartialEq", "eq", 2, FN_HEADER, SelfKind::Ref, OutType::Bool, true),
4084 ShouldImplTraitCase::new("std::iter::FromIterator", "from_iter", 1, FN_HEADER, SelfKind::No, OutType::Any, true),
4085 ShouldImplTraitCase::new("std::str::FromStr", "from_str", 1, FN_HEADER, SelfKind::No, OutType::Any, true),
4086 ShouldImplTraitCase::new("std::hash::Hash", "hash", 2, FN_HEADER, SelfKind::Ref, OutType::Unit, true),
4087 ShouldImplTraitCase::new("std::ops::Index", "index", 2, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
4088 ShouldImplTraitCase::new("std::ops::IndexMut", "index_mut", 2, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
4089 ShouldImplTraitCase::new("std::iter::IntoIterator", "into_iter", 1, FN_HEADER, SelfKind::Value, OutType::Any, true),
4090 ShouldImplTraitCase::new("std::ops::Mul", "mul", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
4091 ShouldImplTraitCase::new("std::ops::Neg", "neg", 1, FN_HEADER, SelfKind::Value, OutType::Any, true),
4092 ShouldImplTraitCase::new("std::iter::Iterator", "next", 1, FN_HEADER, SelfKind::RefMut, OutType::Any, false),
4093 ShouldImplTraitCase::new("std::ops::Not", "not", 1, FN_HEADER, SelfKind::Value, OutType::Any, true),
4094 ShouldImplTraitCase::new("std::ops::Rem", "rem", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
4095 ShouldImplTraitCase::new("std::ops::Shl", "shl", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
4096 ShouldImplTraitCase::new("std::ops::Shr", "shr", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
4097 ShouldImplTraitCase::new("std::ops::Sub", "sub", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
4098 ];
4099
4100 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
4101 enum SelfKind {
4102 Value,
4103 Ref,
4104 RefMut,
4105 No, // When we want the first argument type to be different than `Self`
4106 }
4107
4108 impl SelfKind {
matches<'a>(self, cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool4109 fn matches<'a>(self, cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
4110 fn matches_value<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
4111 if ty == parent_ty {
4112 true
4113 } else if ty.is_box() {
4114 ty.boxed_ty() == parent_ty
4115 } else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) {
4116 if let ty::Adt(_, substs) = ty.kind() {
4117 substs.types().next().map_or(false, |t| t == parent_ty)
4118 } else {
4119 false
4120 }
4121 } else {
4122 false
4123 }
4124 }
4125
4126 fn matches_ref<'a>(cx: &LateContext<'a>, mutability: hir::Mutability, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
4127 if let ty::Ref(_, t, m) = *ty.kind() {
4128 return m == mutability && t == parent_ty;
4129 }
4130
4131 let trait_sym = match mutability {
4132 hir::Mutability::Not => sym::AsRef,
4133 hir::Mutability::Mut => sym::AsMut,
4134 };
4135
4136 let Some(trait_def_id) = cx.tcx.get_diagnostic_item(trait_sym) else {
4137 return false
4138 };
4139 implements_trait(cx, ty, trait_def_id, &[parent_ty.into()])
4140 }
4141
4142 fn matches_none<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
4143 !matches_value(cx, parent_ty, ty)
4144 && !matches_ref(cx, hir::Mutability::Not, parent_ty, ty)
4145 && !matches_ref(cx, hir::Mutability::Mut, parent_ty, ty)
4146 }
4147
4148 match self {
4149 Self::Value => matches_value(cx, parent_ty, ty),
4150 Self::Ref => matches_ref(cx, hir::Mutability::Not, parent_ty, ty) || ty == parent_ty && is_copy(cx, ty),
4151 Self::RefMut => matches_ref(cx, hir::Mutability::Mut, parent_ty, ty),
4152 Self::No => matches_none(cx, parent_ty, ty),
4153 }
4154 }
4155
4156 #[must_use]
description(self) -> &'static str4157 fn description(self) -> &'static str {
4158 match self {
4159 Self::Value => "`self` by value",
4160 Self::Ref => "`self` by reference",
4161 Self::RefMut => "`self` by mutable reference",
4162 Self::No => "no `self`",
4163 }
4164 }
4165 }
4166
4167 #[derive(Clone, Copy)]
4168 enum OutType {
4169 Unit,
4170 Bool,
4171 Any,
4172 Ref,
4173 }
4174
4175 impl OutType {
matches(self, ty: &hir::FnRetTy<'_>) -> bool4176 fn matches(self, ty: &hir::FnRetTy<'_>) -> bool {
4177 let is_unit = |ty: &hir::Ty<'_>| matches!(ty.kind, hir::TyKind::Tup(&[]));
4178 match (self, ty) {
4179 (Self::Unit, &hir::FnRetTy::DefaultReturn(_)) => true,
4180 (Self::Unit, &hir::FnRetTy::Return(ty)) if is_unit(ty) => true,
4181 (Self::Bool, &hir::FnRetTy::Return(ty)) if is_bool(ty) => true,
4182 (Self::Any, &hir::FnRetTy::Return(ty)) if !is_unit(ty) => true,
4183 (Self::Ref, &hir::FnRetTy::Return(ty)) => matches!(ty.kind, hir::TyKind::Ref(_, _)),
4184 _ => false,
4185 }
4186 }
4187 }
4188
fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool4189 fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
4190 expected.constness == actual.constness
4191 && expected.unsafety == actual.unsafety
4192 && expected.asyncness == actual.asyncness
4193 }
4194