]> git.proxmox.com Git - rustc.git/blob - src/tools/clippy/clippy_lints/src/methods/mod.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / methods / mod.rs
1 mod bind_instead_of_map;
2 mod bytes_nth;
3 mod chars_cmp;
4 mod chars_cmp_with_unwrap;
5 mod chars_last_cmp;
6 mod chars_last_cmp_with_unwrap;
7 mod chars_next_cmp;
8 mod chars_next_cmp_with_unwrap;
9 mod clone_on_copy;
10 mod clone_on_ref_ptr;
11 mod cloned_instead_of_copied;
12 mod expect_fun_call;
13 mod expect_used;
14 mod extend_with_drain;
15 mod filetype_is_file;
16 mod filter_map;
17 mod filter_map_identity;
18 mod filter_map_next;
19 mod filter_next;
20 mod flat_map_identity;
21 mod flat_map_option;
22 mod from_iter_instead_of_collect;
23 mod get_unwrap;
24 mod implicit_clone;
25 mod inefficient_to_string;
26 mod inspect_for_each;
27 mod into_iter_on_ref;
28 mod iter_cloned_collect;
29 mod iter_count;
30 mod iter_next_slice;
31 mod iter_nth;
32 mod iter_nth_zero;
33 mod iter_skip_next;
34 mod iterator_step_by_zero;
35 mod manual_saturating_arithmetic;
36 mod manual_str_repeat;
37 mod map_collect_result_unit;
38 mod map_flatten;
39 mod map_identity;
40 mod map_unwrap_or;
41 mod ok_expect;
42 mod option_as_ref_deref;
43 mod option_map_or_none;
44 mod option_map_unwrap_or;
45 mod or_fun_call;
46 mod search_is_some;
47 mod single_char_add_str;
48 mod single_char_insert_string;
49 mod single_char_pattern;
50 mod single_char_push_string;
51 mod skip_while_next;
52 mod string_extend_chars;
53 mod suspicious_map;
54 mod suspicious_splitn;
55 mod uninit_assumed_init;
56 mod unnecessary_filter_map;
57 mod unnecessary_fold;
58 mod unnecessary_lazy_eval;
59 mod unwrap_used;
60 mod useless_asref;
61 mod utils;
62 mod wrong_self_convention;
63 mod zst_offset;
64
65 use bind_instead_of_map::BindInsteadOfMap;
66 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
67 use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
68 use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
69 use if_chain::if_chain;
70 use rustc_hir as hir;
71 use rustc_hir::def::Res;
72 use rustc_hir::{Expr, ExprKind, PrimTy, QPath, TraitItem, TraitItemKind};
73 use rustc_lint::{LateContext, LateLintPass, LintContext};
74 use rustc_middle::lint::in_external_macro;
75 use rustc_middle::ty::{self, TraitRef, Ty, TyS};
76 use rustc_semver::RustcVersion;
77 use rustc_session::{declare_tool_lint, impl_lint_pass};
78 use rustc_span::symbol::SymbolStr;
79 use rustc_span::{sym, Span};
80 use rustc_typeck::hir_ty_to_ty;
81
82 declare_clippy_lint! {
83 /// **What it does:** Checks for usages of `cloned()` on an `Iterator` or `Option` where
84 /// `copied()` could be used instead.
85 ///
86 /// **Why is this bad?** `copied()` is better because it guarantees that the type being cloned
87 /// implements `Copy`.
88 ///
89 /// **Known problems:** None.
90 ///
91 /// **Example:**
92 ///
93 /// ```rust
94 /// [1, 2, 3].iter().cloned();
95 /// ```
96 /// Use instead:
97 /// ```rust
98 /// [1, 2, 3].iter().copied();
99 /// ```
100 pub CLONED_INSTEAD_OF_COPIED,
101 pedantic,
102 "used `cloned` where `copied` could be used instead"
103 }
104
105 declare_clippy_lint! {
106 /// **What it does:** Checks for usages of `Iterator::flat_map()` where `filter_map()` could be
107 /// used instead.
108 ///
109 /// **Why is this bad?** When applicable, `filter_map()` is more clear since it shows that
110 /// `Option` is used to produce 0 or 1 items.
111 ///
112 /// **Known problems:** None.
113 ///
114 /// **Example:**
115 ///
116 /// ```rust
117 /// let nums: Vec<i32> = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect();
118 /// ```
119 /// Use instead:
120 /// ```rust
121 /// let nums: Vec<i32> = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect();
122 /// ```
123 pub FLAT_MAP_OPTION,
124 pedantic,
125 "used `flat_map` where `filter_map` could be used instead"
126 }
127
128 declare_clippy_lint! {
129 /// **What it does:** Checks for `.unwrap()` calls on `Option`s and on `Result`s.
130 ///
131 /// **Why is this bad?** It is better to handle the `None` or `Err` case,
132 /// or at least call `.expect(_)` with a more helpful message. Still, for a lot of
133 /// quick-and-dirty code, `unwrap` is a good choice, which is why this lint is
134 /// `Allow` by default.
135 ///
136 /// `result.unwrap()` will let the thread panic on `Err` values.
137 /// Normally, you want to implement more sophisticated error handling,
138 /// and propagate errors upwards with `?` operator.
139 ///
140 /// Even if you want to panic on errors, not all `Error`s implement good
141 /// messages on display. Therefore, it may be beneficial to look at the places
142 /// where they may get displayed. Activate this lint to do just that.
143 ///
144 /// **Known problems:** None.
145 ///
146 /// **Examples:**
147 /// ```rust
148 /// # let opt = Some(1);
149 ///
150 /// // Bad
151 /// opt.unwrap();
152 ///
153 /// // Good
154 /// opt.expect("more helpful message");
155 /// ```
156 ///
157 /// // or
158 ///
159 /// ```rust
160 /// # let res: Result<usize, ()> = Ok(1);
161 ///
162 /// // Bad
163 /// res.unwrap();
164 ///
165 /// // Good
166 /// res.expect("more helpful message");
167 /// ```
168 pub UNWRAP_USED,
169 restriction,
170 "using `.unwrap()` on `Result` or `Option`, which should at least get a better message using `expect()`"
171 }
172
173 declare_clippy_lint! {
174 /// **What it does:** Checks for `.expect()` calls on `Option`s and `Result`s.
175 ///
176 /// **Why is this bad?** Usually it is better to handle the `None` or `Err` case.
177 /// Still, for a lot of quick-and-dirty code, `expect` is a good choice, which is why
178 /// this lint is `Allow` by default.
179 ///
180 /// `result.expect()` will let the thread panic on `Err`
181 /// values. Normally, you want to implement more sophisticated error handling,
182 /// and propagate errors upwards with `?` operator.
183 ///
184 /// **Known problems:** None.
185 ///
186 /// **Examples:**
187 /// ```rust,ignore
188 /// # let opt = Some(1);
189 ///
190 /// // Bad
191 /// opt.expect("one");
192 ///
193 /// // Good
194 /// let opt = Some(1);
195 /// opt?;
196 /// ```
197 ///
198 /// // or
199 ///
200 /// ```rust
201 /// # let res: Result<usize, ()> = Ok(1);
202 ///
203 /// // Bad
204 /// res.expect("one");
205 ///
206 /// // Good
207 /// res?;
208 /// # Ok::<(), ()>(())
209 /// ```
210 pub EXPECT_USED,
211 restriction,
212 "using `.expect()` on `Result` or `Option`, which might be better handled"
213 }
214
215 declare_clippy_lint! {
216 /// **What it does:** Checks for methods that should live in a trait
217 /// implementation of a `std` trait (see [llogiq's blog
218 /// post](http://llogiq.github.io/2015/07/30/traits.html) for further
219 /// information) instead of an inherent implementation.
220 ///
221 /// **Why is this bad?** Implementing the traits improve ergonomics for users of
222 /// the code, often with very little cost. Also people seeing a `mul(...)`
223 /// method
224 /// may expect `*` to work equally, so you should have good reason to disappoint
225 /// them.
226 ///
227 /// **Known problems:** None.
228 ///
229 /// **Example:**
230 /// ```rust
231 /// struct X;
232 /// impl X {
233 /// fn add(&self, other: &X) -> X {
234 /// // ..
235 /// # X
236 /// }
237 /// }
238 /// ```
239 pub SHOULD_IMPLEMENT_TRAIT,
240 style,
241 "defining a method that should be implementing a std trait"
242 }
243
244 declare_clippy_lint! {
245 /// **What it does:** Checks for methods with certain name prefixes and which
246 /// doesn't match how self is taken. The actual rules are:
247 ///
248 /// |Prefix |Postfix |`self` taken | `self` type |
249 /// |-------|------------|-----------------------|--------------|
250 /// |`as_` | none |`&self` or `&mut self` | any |
251 /// |`from_`| none | none | any |
252 /// |`into_`| none |`self` | any |
253 /// |`is_` | none |`&self` or none | any |
254 /// |`to_` | `_mut` |`&mut self` | any |
255 /// |`to_` | not `_mut` |`self` | `Copy` |
256 /// |`to_` | not `_mut` |`&self` | not `Copy` |
257 ///
258 /// Note: Clippy doesn't trigger methods with `to_` prefix in:
259 /// - Traits definition.
260 /// Clippy can not tell if a type that implements a trait is `Copy` or not.
261 /// - Traits implementation, when `&self` is taken.
262 /// The method signature is controlled by the trait and often `&self` is required for all types that implement the trait
263 /// (see e.g. the `std::string::ToString` trait).
264 ///
265 /// Please find more info here:
266 /// https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
267 ///
268 /// **Why is this bad?** Consistency breeds readability. If you follow the
269 /// conventions, your users won't be surprised that they, e.g., need to supply a
270 /// mutable reference to a `as_..` function.
271 ///
272 /// **Known problems:** None.
273 ///
274 /// **Example:**
275 /// ```rust
276 /// # struct X;
277 /// impl X {
278 /// fn as_str(self) -> &'static str {
279 /// // ..
280 /// # ""
281 /// }
282 /// }
283 /// ```
284 pub WRONG_SELF_CONVENTION,
285 style,
286 "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
287 }
288
289 declare_clippy_lint! {
290 /// **What it does:** Checks for usage of `ok().expect(..)`.
291 ///
292 /// **Why is this bad?** Because you usually call `expect()` on the `Result`
293 /// directly to get a better error message.
294 ///
295 /// **Known problems:** The error type needs to implement `Debug`
296 ///
297 /// **Example:**
298 /// ```rust
299 /// # let x = Ok::<_, ()>(());
300 ///
301 /// // Bad
302 /// x.ok().expect("why did I do this again?");
303 ///
304 /// // Good
305 /// x.expect("why did I do this again?");
306 /// ```
307 pub OK_EXPECT,
308 style,
309 "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result"
310 }
311
312 declare_clippy_lint! {
313 /// **What it does:** Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or
314 /// `result.map(_).unwrap_or_else(_)`.
315 ///
316 /// **Why is this bad?** Readability, these can be written more concisely (resp.) as
317 /// `option.map_or(_, _)`, `option.map_or_else(_, _)` and `result.map_or_else(_, _)`.
318 ///
319 /// **Known problems:** The order of the arguments is not in execution order
320 ///
321 /// **Examples:**
322 /// ```rust
323 /// # let x = Some(1);
324 ///
325 /// // Bad
326 /// x.map(|a| a + 1).unwrap_or(0);
327 ///
328 /// // Good
329 /// x.map_or(0, |a| a + 1);
330 /// ```
331 ///
332 /// // or
333 ///
334 /// ```rust
335 /// # let x: Result<usize, ()> = Ok(1);
336 /// # fn some_function(foo: ()) -> usize { 1 }
337 ///
338 /// // Bad
339 /// x.map(|a| a + 1).unwrap_or_else(some_function);
340 ///
341 /// // Good
342 /// x.map_or_else(some_function, |a| a + 1);
343 /// ```
344 pub MAP_UNWRAP_OR,
345 pedantic,
346 "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)`"
347 }
348
349 declare_clippy_lint! {
350 /// **What it does:** Checks for usage of `_.map_or(None, _)`.
351 ///
352 /// **Why is this bad?** Readability, this can be written more concisely as
353 /// `_.and_then(_)`.
354 ///
355 /// **Known problems:** The order of the arguments is not in execution order.
356 ///
357 /// **Example:**
358 /// ```rust
359 /// # let opt = Some(1);
360 ///
361 /// // Bad
362 /// opt.map_or(None, |a| Some(a + 1));
363 ///
364 /// // Good
365 /// opt.and_then(|a| Some(a + 1));
366 /// ```
367 pub OPTION_MAP_OR_NONE,
368 style,
369 "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`"
370 }
371
372 declare_clippy_lint! {
373 /// **What it does:** Checks for usage of `_.map_or(None, Some)`.
374 ///
375 /// **Why is this bad?** Readability, this can be written more concisely as
376 /// `_.ok()`.
377 ///
378 /// **Known problems:** None.
379 ///
380 /// **Example:**
381 ///
382 /// Bad:
383 /// ```rust
384 /// # let r: Result<u32, &str> = Ok(1);
385 /// assert_eq!(Some(1), r.map_or(None, Some));
386 /// ```
387 ///
388 /// Good:
389 /// ```rust
390 /// # let r: Result<u32, &str> = Ok(1);
391 /// assert_eq!(Some(1), r.ok());
392 /// ```
393 pub RESULT_MAP_OR_INTO_OPTION,
394 style,
395 "using `Result.map_or(None, Some)`, which is more succinctly expressed as `ok()`"
396 }
397
398 declare_clippy_lint! {
399 /// **What it does:** Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or
400 /// `_.or_else(|x| Err(y))`.
401 ///
402 /// **Why is this bad?** Readability, this can be written more concisely as
403 /// `_.map(|x| y)` or `_.map_err(|x| y)`.
404 ///
405 /// **Known problems:** None
406 ///
407 /// **Example:**
408 ///
409 /// ```rust
410 /// # fn opt() -> Option<&'static str> { Some("42") }
411 /// # fn res() -> Result<&'static str, &'static str> { Ok("42") }
412 /// let _ = opt().and_then(|s| Some(s.len()));
413 /// let _ = res().and_then(|s| if s.len() == 42 { Ok(10) } else { Ok(20) });
414 /// let _ = res().or_else(|s| if s.len() == 42 { Err(10) } else { Err(20) });
415 /// ```
416 ///
417 /// The correct use would be:
418 ///
419 /// ```rust
420 /// # fn opt() -> Option<&'static str> { Some("42") }
421 /// # fn res() -> Result<&'static str, &'static str> { Ok("42") }
422 /// let _ = opt().map(|s| s.len());
423 /// let _ = res().map(|s| if s.len() == 42 { 10 } else { 20 });
424 /// let _ = res().map_err(|s| if s.len() == 42 { 10 } else { 20 });
425 /// ```
426 pub BIND_INSTEAD_OF_MAP,
427 complexity,
428 "using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`"
429 }
430
431 declare_clippy_lint! {
432 /// **What it does:** Checks for usage of `_.filter(_).next()`.
433 ///
434 /// **Why is this bad?** Readability, this can be written more concisely as
435 /// `_.find(_)`.
436 ///
437 /// **Known problems:** None.
438 ///
439 /// **Example:**
440 /// ```rust
441 /// # let vec = vec![1];
442 /// vec.iter().filter(|x| **x == 0).next();
443 /// ```
444 /// Could be written as
445 /// ```rust
446 /// # let vec = vec![1];
447 /// vec.iter().find(|x| **x == 0);
448 /// ```
449 pub FILTER_NEXT,
450 complexity,
451 "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`"
452 }
453
454 declare_clippy_lint! {
455 /// **What it does:** Checks for usage of `_.skip_while(condition).next()`.
456 ///
457 /// **Why is this bad?** Readability, this can be written more concisely as
458 /// `_.find(!condition)`.
459 ///
460 /// **Known problems:** None.
461 ///
462 /// **Example:**
463 /// ```rust
464 /// # let vec = vec![1];
465 /// vec.iter().skip_while(|x| **x == 0).next();
466 /// ```
467 /// Could be written as
468 /// ```rust
469 /// # let vec = vec![1];
470 /// vec.iter().find(|x| **x != 0);
471 /// ```
472 pub SKIP_WHILE_NEXT,
473 complexity,
474 "using `skip_while(p).next()`, which is more succinctly expressed as `.find(!p)`"
475 }
476
477 declare_clippy_lint! {
478 /// **What it does:** Checks for usage of `_.map(_).flatten(_)` on `Iterator` and `Option`
479 ///
480 /// **Why is this bad?** Readability, this can be written more concisely as
481 /// `_.flat_map(_)`
482 ///
483 /// **Known problems:**
484 ///
485 /// **Example:**
486 /// ```rust
487 /// let vec = vec![vec![1]];
488 ///
489 /// // Bad
490 /// vec.iter().map(|x| x.iter()).flatten();
491 ///
492 /// // Good
493 /// vec.iter().flat_map(|x| x.iter());
494 /// ```
495 pub MAP_FLATTEN,
496 pedantic,
497 "using combinations of `flatten` and `map` which can usually be written as a single method call"
498 }
499
500 declare_clippy_lint! {
501 /// **What it does:** Checks for usage of `_.filter(_).map(_)` that can be written more simply
502 /// as `filter_map(_)`.
503 ///
504 /// **Why is this bad?** Redundant code in the `filter` and `map` operations is poor style and
505 /// less performant.
506 ///
507 /// **Known problems:** None.
508 ///
509 /// **Example:**
510 /// Bad:
511 /// ```rust
512 /// (0_i32..10)
513 /// .filter(|n| n.checked_add(1).is_some())
514 /// .map(|n| n.checked_add(1).unwrap());
515 /// ```
516 ///
517 /// Good:
518 /// ```rust
519 /// (0_i32..10).filter_map(|n| n.checked_add(1));
520 /// ```
521 pub MANUAL_FILTER_MAP,
522 complexity,
523 "using `_.filter(_).map(_)` in a way that can be written more simply as `filter_map(_)`"
524 }
525
526 declare_clippy_lint! {
527 /// **What it does:** Checks for usage of `_.find(_).map(_)` that can be written more simply
528 /// as `find_map(_)`.
529 ///
530 /// **Why is this bad?** Redundant code in the `find` and `map` operations is poor style and
531 /// less performant.
532 ///
533 /// **Known problems:** None.
534 ///
535 /// **Example:**
536 /// Bad:
537 /// ```rust
538 /// (0_i32..10)
539 /// .find(|n| n.checked_add(1).is_some())
540 /// .map(|n| n.checked_add(1).unwrap());
541 /// ```
542 ///
543 /// Good:
544 /// ```rust
545 /// (0_i32..10).find_map(|n| n.checked_add(1));
546 /// ```
547 pub MANUAL_FIND_MAP,
548 complexity,
549 "using `_.find(_).map(_)` in a way that can be written more simply as `find_map(_)`"
550 }
551
552 declare_clippy_lint! {
553 /// **What it does:** Checks for usage of `_.filter_map(_).next()`.
554 ///
555 /// **Why is this bad?** Readability, this can be written more concisely as
556 /// `_.find_map(_)`.
557 ///
558 /// **Known problems:** None
559 ///
560 /// **Example:**
561 /// ```rust
562 /// (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next();
563 /// ```
564 /// Can be written as
565 ///
566 /// ```rust
567 /// (0..3).find_map(|x| if x == 2 { Some(x) } else { None });
568 /// ```
569 pub FILTER_MAP_NEXT,
570 pedantic,
571 "using combination of `filter_map` and `next` which can usually be written as a single method call"
572 }
573
574 declare_clippy_lint! {
575 /// **What it does:** Checks for usage of `flat_map(|x| x)`.
576 ///
577 /// **Why is this bad?** Readability, this can be written more concisely by using `flatten`.
578 ///
579 /// **Known problems:** None
580 ///
581 /// **Example:**
582 /// ```rust
583 /// # let iter = vec![vec![0]].into_iter();
584 /// iter.flat_map(|x| x);
585 /// ```
586 /// Can be written as
587 /// ```rust
588 /// # let iter = vec![vec![0]].into_iter();
589 /// iter.flatten();
590 /// ```
591 pub FLAT_MAP_IDENTITY,
592 complexity,
593 "call to `flat_map` where `flatten` is sufficient"
594 }
595
596 declare_clippy_lint! {
597 /// **What it does:** Checks for an iterator or string search (such as `find()`,
598 /// `position()`, or `rposition()`) followed by a call to `is_some()` or `is_none()`.
599 ///
600 /// **Why is this bad?** Readability, this can be written more concisely as:
601 /// * `_.any(_)`, or `_.contains(_)` for `is_some()`,
602 /// * `!_.any(_)`, or `!_.contains(_)` for `is_none()`.
603 ///
604 /// **Known problems:** None.
605 ///
606 /// **Example:**
607 /// ```rust
608 /// let vec = vec![1];
609 /// vec.iter().find(|x| **x == 0).is_some();
610 ///
611 /// let _ = "hello world".find("world").is_none();
612 /// ```
613 /// Could be written as
614 /// ```rust
615 /// let vec = vec![1];
616 /// vec.iter().any(|x| *x == 0);
617 ///
618 /// let _ = !"hello world".contains("world");
619 /// ```
620 pub SEARCH_IS_SOME,
621 complexity,
622 "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()`)"
623 }
624
625 declare_clippy_lint! {
626 /// **What it does:** Checks for usage of `.chars().next()` on a `str` to check
627 /// if it starts with a given char.
628 ///
629 /// **Why is this bad?** Readability, this can be written more concisely as
630 /// `_.starts_with(_)`.
631 ///
632 /// **Known problems:** None.
633 ///
634 /// **Example:**
635 /// ```rust
636 /// let name = "foo";
637 /// if name.chars().next() == Some('_') {};
638 /// ```
639 /// Could be written as
640 /// ```rust
641 /// let name = "foo";
642 /// if name.starts_with('_') {};
643 /// ```
644 pub CHARS_NEXT_CMP,
645 style,
646 "using `.chars().next()` to check if a string starts with a char"
647 }
648
649 declare_clippy_lint! {
650 /// **What it does:** Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
651 /// etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or
652 /// `unwrap_or_default` instead.
653 ///
654 /// **Why is this bad?** The function will always be called and potentially
655 /// allocate an object acting as the default.
656 ///
657 /// **Known problems:** If the function has side-effects, not calling it will
658 /// change the semantic of the program, but you shouldn't rely on that anyway.
659 ///
660 /// **Example:**
661 /// ```rust
662 /// # let foo = Some(String::new());
663 /// foo.unwrap_or(String::new());
664 /// ```
665 /// this can instead be written:
666 /// ```rust
667 /// # let foo = Some(String::new());
668 /// foo.unwrap_or_else(String::new);
669 /// ```
670 /// or
671 /// ```rust
672 /// # let foo = Some(String::new());
673 /// foo.unwrap_or_default();
674 /// ```
675 pub OR_FUN_CALL,
676 perf,
677 "using any `*or` method with a function call, which suggests `*or_else`"
678 }
679
680 declare_clippy_lint! {
681 /// **What it does:** Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`,
682 /// etc., and suggests to use `unwrap_or_else` instead
683 ///
684 /// **Why is this bad?** The function will always be called.
685 ///
686 /// **Known problems:** If the function has side-effects, not calling it will
687 /// change the semantics of the program, but you shouldn't rely on that anyway.
688 ///
689 /// **Example:**
690 /// ```rust
691 /// # let foo = Some(String::new());
692 /// # let err_code = "418";
693 /// # let err_msg = "I'm a teapot";
694 /// foo.expect(&format!("Err {}: {}", err_code, err_msg));
695 /// ```
696 /// or
697 /// ```rust
698 /// # let foo = Some(String::new());
699 /// # let err_code = "418";
700 /// # let err_msg = "I'm a teapot";
701 /// foo.expect(format!("Err {}: {}", err_code, err_msg).as_str());
702 /// ```
703 /// this can instead be written:
704 /// ```rust
705 /// # let foo = Some(String::new());
706 /// # let err_code = "418";
707 /// # let err_msg = "I'm a teapot";
708 /// foo.unwrap_or_else(|| panic!("Err {}: {}", err_code, err_msg));
709 /// ```
710 pub EXPECT_FUN_CALL,
711 perf,
712 "using any `expect` method with a function call"
713 }
714
715 declare_clippy_lint! {
716 /// **What it does:** Checks for usage of `.clone()` on a `Copy` type.
717 ///
718 /// **Why is this bad?** The only reason `Copy` types implement `Clone` is for
719 /// generics, not for using the `clone` method on a concrete type.
720 ///
721 /// **Known problems:** None.
722 ///
723 /// **Example:**
724 /// ```rust
725 /// 42u64.clone();
726 /// ```
727 pub CLONE_ON_COPY,
728 complexity,
729 "using `clone` on a `Copy` type"
730 }
731
732 declare_clippy_lint! {
733 /// **What it does:** Checks for usage of `.clone()` on a ref-counted pointer,
734 /// (`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified
735 /// function syntax instead (e.g., `Rc::clone(foo)`).
736 ///
737 /// **Why is this bad?** Calling '.clone()' on an Rc, Arc, or Weak
738 /// can obscure the fact that only the pointer is being cloned, not the underlying
739 /// data.
740 ///
741 /// **Example:**
742 /// ```rust
743 /// # use std::rc::Rc;
744 /// let x = Rc::new(1);
745 ///
746 /// // Bad
747 /// x.clone();
748 ///
749 /// // Good
750 /// Rc::clone(&x);
751 /// ```
752 pub CLONE_ON_REF_PTR,
753 restriction,
754 "using 'clone' on a ref-counted pointer"
755 }
756
757 declare_clippy_lint! {
758 /// **What it does:** Checks for usage of `.clone()` on an `&&T`.
759 ///
760 /// **Why is this bad?** Cloning an `&&T` copies the inner `&T`, instead of
761 /// cloning the underlying `T`.
762 ///
763 /// **Known problems:** None.
764 ///
765 /// **Example:**
766 /// ```rust
767 /// fn main() {
768 /// let x = vec![1];
769 /// let y = &&x;
770 /// let z = y.clone();
771 /// println!("{:p} {:p}", *y, z); // prints out the same pointer
772 /// }
773 /// ```
774 pub CLONE_DOUBLE_REF,
775 correctness,
776 "using `clone` on `&&T`"
777 }
778
779 declare_clippy_lint! {
780 /// **What it does:** Checks for usage of `.to_string()` on an `&&T` where
781 /// `T` implements `ToString` directly (like `&&str` or `&&String`).
782 ///
783 /// **Why is this bad?** This bypasses the specialized implementation of
784 /// `ToString` and instead goes through the more expensive string formatting
785 /// facilities.
786 ///
787 /// **Known problems:** None.
788 ///
789 /// **Example:**
790 /// ```rust
791 /// // Generic implementation for `T: Display` is used (slow)
792 /// ["foo", "bar"].iter().map(|s| s.to_string());
793 ///
794 /// // OK, the specialized impl is used
795 /// ["foo", "bar"].iter().map(|&s| s.to_string());
796 /// ```
797 pub INEFFICIENT_TO_STRING,
798 pedantic,
799 "using `to_string` on `&&T` where `T: ToString`"
800 }
801
802 declare_clippy_lint! {
803 /// **What it does:** Checks for `new` not returning a type that contains `Self`.
804 ///
805 /// **Why is this bad?** As a convention, `new` methods are used to make a new
806 /// instance of a type.
807 ///
808 /// **Known problems:** None.
809 ///
810 /// **Example:**
811 /// In an impl block:
812 /// ```rust
813 /// # struct Foo;
814 /// # struct NotAFoo;
815 /// impl Foo {
816 /// fn new() -> NotAFoo {
817 /// # NotAFoo
818 /// }
819 /// }
820 /// ```
821 ///
822 /// ```rust
823 /// # struct Foo;
824 /// struct Bar(Foo);
825 /// impl Foo {
826 /// // Bad. The type name must contain `Self`
827 /// fn new() -> Bar {
828 /// # Bar(Foo)
829 /// }
830 /// }
831 /// ```
832 ///
833 /// ```rust
834 /// # struct Foo;
835 /// # struct FooError;
836 /// impl Foo {
837 /// // Good. Return type contains `Self`
838 /// fn new() -> Result<Foo, FooError> {
839 /// # Ok(Foo)
840 /// }
841 /// }
842 /// ```
843 ///
844 /// Or in a trait definition:
845 /// ```rust
846 /// pub trait Trait {
847 /// // Bad. The type name must contain `Self`
848 /// fn new();
849 /// }
850 /// ```
851 ///
852 /// ```rust
853 /// pub trait Trait {
854 /// // Good. Return type contains `Self`
855 /// fn new() -> Self;
856 /// }
857 /// ```
858 pub NEW_RET_NO_SELF,
859 style,
860 "not returning type containing `Self` in a `new` method"
861 }
862
863 declare_clippy_lint! {
864 /// **What it does:** Checks for string methods that receive a single-character
865 /// `str` as an argument, e.g., `_.split("x")`.
866 ///
867 /// **Why is this bad?** Performing these methods using a `char` is faster than
868 /// using a `str`.
869 ///
870 /// **Known problems:** Does not catch multi-byte unicode characters.
871 ///
872 /// **Example:**
873 /// ```rust,ignore
874 /// // Bad
875 /// _.split("x");
876 ///
877 /// // Good
878 /// _.split('x');
879 pub SINGLE_CHAR_PATTERN,
880 perf,
881 "using a single-character str where a char could be used, e.g., `_.split(\"x\")`"
882 }
883
884 declare_clippy_lint! {
885 /// **What it does:** Checks for calling `.step_by(0)` on iterators which panics.
886 ///
887 /// **Why is this bad?** This very much looks like an oversight. Use `panic!()` instead if you
888 /// actually intend to panic.
889 ///
890 /// **Known problems:** None.
891 ///
892 /// **Example:**
893 /// ```rust,should_panic
894 /// for x in (0..100).step_by(0) {
895 /// //..
896 /// }
897 /// ```
898 pub ITERATOR_STEP_BY_ZERO,
899 correctness,
900 "using `Iterator::step_by(0)`, which will panic at runtime"
901 }
902
903 declare_clippy_lint! {
904 /// **What it does:** Checks for indirect collection of populated `Option`
905 ///
906 /// **Why is this bad?** `Option` is like a collection of 0-1 things, so `flatten`
907 /// automatically does this without suspicious-looking `unwrap` calls.
908 ///
909 /// **Known problems:** None.
910 ///
911 /// **Example:**
912 ///
913 /// ```rust
914 /// let _ = std::iter::empty::<Option<i32>>().filter(Option::is_some).map(Option::unwrap);
915 /// ```
916 /// Use instead:
917 /// ```rust
918 /// let _ = std::iter::empty::<Option<i32>>().flatten();
919 /// ```
920 pub OPTION_FILTER_MAP,
921 complexity,
922 "filtering `Option` for `Some` then force-unwrapping, which can be one type-safe operation"
923 }
924
925 declare_clippy_lint! {
926 /// **What it does:** Checks for the use of `iter.nth(0)`.
927 ///
928 /// **Why is this bad?** `iter.next()` is equivalent to
929 /// `iter.nth(0)`, as they both consume the next element,
930 /// but is more readable.
931 ///
932 /// **Known problems:** None.
933 ///
934 /// **Example:**
935 ///
936 /// ```rust
937 /// # use std::collections::HashSet;
938 /// // Bad
939 /// # let mut s = HashSet::new();
940 /// # s.insert(1);
941 /// let x = s.iter().nth(0);
942 ///
943 /// // Good
944 /// # let mut s = HashSet::new();
945 /// # s.insert(1);
946 /// let x = s.iter().next();
947 /// ```
948 pub ITER_NTH_ZERO,
949 style,
950 "replace `iter.nth(0)` with `iter.next()`"
951 }
952
953 declare_clippy_lint! {
954 /// **What it does:** Checks for use of `.iter().nth()` (and the related
955 /// `.iter_mut().nth()`) on standard library types with O(1) element access.
956 ///
957 /// **Why is this bad?** `.get()` and `.get_mut()` are more efficient and more
958 /// readable.
959 ///
960 /// **Known problems:** None.
961 ///
962 /// **Example:**
963 /// ```rust
964 /// let some_vec = vec![0, 1, 2, 3];
965 /// let bad_vec = some_vec.iter().nth(3);
966 /// let bad_slice = &some_vec[..].iter().nth(3);
967 /// ```
968 /// The correct use would be:
969 /// ```rust
970 /// let some_vec = vec![0, 1, 2, 3];
971 /// let bad_vec = some_vec.get(3);
972 /// let bad_slice = &some_vec[..].get(3);
973 /// ```
974 pub ITER_NTH,
975 perf,
976 "using `.iter().nth()` on a standard library type with O(1) element access"
977 }
978
979 declare_clippy_lint! {
980 /// **What it does:** Checks for use of `.skip(x).next()` on iterators.
981 ///
982 /// **Why is this bad?** `.nth(x)` is cleaner
983 ///
984 /// **Known problems:** None.
985 ///
986 /// **Example:**
987 /// ```rust
988 /// let some_vec = vec![0, 1, 2, 3];
989 /// let bad_vec = some_vec.iter().skip(3).next();
990 /// let bad_slice = &some_vec[..].iter().skip(3).next();
991 /// ```
992 /// The correct use would be:
993 /// ```rust
994 /// let some_vec = vec![0, 1, 2, 3];
995 /// let bad_vec = some_vec.iter().nth(3);
996 /// let bad_slice = &some_vec[..].iter().nth(3);
997 /// ```
998 pub ITER_SKIP_NEXT,
999 style,
1000 "using `.skip(x).next()` on an iterator"
1001 }
1002
1003 declare_clippy_lint! {
1004 /// **What it does:** Checks for use of `.get().unwrap()` (or
1005 /// `.get_mut().unwrap`) on a standard library type which implements `Index`
1006 ///
1007 /// **Why is this bad?** Using the Index trait (`[]`) is more clear and more
1008 /// concise.
1009 ///
1010 /// **Known problems:** Not a replacement for error handling: Using either
1011 /// `.unwrap()` or the Index trait (`[]`) carries the risk of causing a `panic`
1012 /// if the value being accessed is `None`. If the use of `.get().unwrap()` is a
1013 /// temporary placeholder for dealing with the `Option` type, then this does
1014 /// not mitigate the need for error handling. If there is a chance that `.get()`
1015 /// will be `None` in your program, then it is advisable that the `None` case
1016 /// is handled in a future refactor instead of using `.unwrap()` or the Index
1017 /// trait.
1018 ///
1019 /// **Example:**
1020 /// ```rust
1021 /// let mut some_vec = vec![0, 1, 2, 3];
1022 /// let last = some_vec.get(3).unwrap();
1023 /// *some_vec.get_mut(0).unwrap() = 1;
1024 /// ```
1025 /// The correct use would be:
1026 /// ```rust
1027 /// let mut some_vec = vec![0, 1, 2, 3];
1028 /// let last = some_vec[3];
1029 /// some_vec[0] = 1;
1030 /// ```
1031 pub GET_UNWRAP,
1032 restriction,
1033 "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead"
1034 }
1035
1036 declare_clippy_lint! {
1037 /// **What it does:** Checks for occurrences where one vector gets extended instead of append
1038 ///
1039 /// **Why is this bad?** Using `append` instead of `extend` is more concise and faster
1040 ///
1041 /// **Known problems:** None.
1042 ///
1043 /// **Example:**
1044 ///
1045 /// ```rust
1046 /// let mut a = vec![1, 2, 3];
1047 /// let mut b = vec![4, 5, 6];
1048 ///
1049 /// // Bad
1050 /// a.extend(b.drain(..));
1051 ///
1052 /// // Good
1053 /// a.append(&mut b);
1054 /// ```
1055 pub EXTEND_WITH_DRAIN,
1056 perf,
1057 "using vec.append(&mut vec) to move the full range of a vecor to another"
1058 }
1059
1060 declare_clippy_lint! {
1061 /// **What it does:** Checks for the use of `.extend(s.chars())` where s is a
1062 /// `&str` or `String`.
1063 ///
1064 /// **Why is this bad?** `.push_str(s)` is clearer
1065 ///
1066 /// **Known problems:** None.
1067 ///
1068 /// **Example:**
1069 /// ```rust
1070 /// let abc = "abc";
1071 /// let def = String::from("def");
1072 /// let mut s = String::new();
1073 /// s.extend(abc.chars());
1074 /// s.extend(def.chars());
1075 /// ```
1076 /// The correct use would be:
1077 /// ```rust
1078 /// let abc = "abc";
1079 /// let def = String::from("def");
1080 /// let mut s = String::new();
1081 /// s.push_str(abc);
1082 /// s.push_str(&def);
1083 /// ```
1084 pub STRING_EXTEND_CHARS,
1085 style,
1086 "using `x.extend(s.chars())` where s is a `&str` or `String`"
1087 }
1088
1089 declare_clippy_lint! {
1090 /// **What it does:** Checks for the use of `.cloned().collect()` on slice to
1091 /// create a `Vec`.
1092 ///
1093 /// **Why is this bad?** `.to_vec()` is clearer
1094 ///
1095 /// **Known problems:** None.
1096 ///
1097 /// **Example:**
1098 /// ```rust
1099 /// let s = [1, 2, 3, 4, 5];
1100 /// let s2: Vec<isize> = s[..].iter().cloned().collect();
1101 /// ```
1102 /// The better use would be:
1103 /// ```rust
1104 /// let s = [1, 2, 3, 4, 5];
1105 /// let s2: Vec<isize> = s.to_vec();
1106 /// ```
1107 pub ITER_CLONED_COLLECT,
1108 style,
1109 "using `.cloned().collect()` on slice to create a `Vec`"
1110 }
1111
1112 declare_clippy_lint! {
1113 /// **What it does:** Checks for usage of `_.chars().last()` or
1114 /// `_.chars().next_back()` on a `str` to check if it ends with a given char.
1115 ///
1116 /// **Why is this bad?** Readability, this can be written more concisely as
1117 /// `_.ends_with(_)`.
1118 ///
1119 /// **Known problems:** None.
1120 ///
1121 /// **Example:**
1122 /// ```rust
1123 /// # let name = "_";
1124 ///
1125 /// // Bad
1126 /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-');
1127 ///
1128 /// // Good
1129 /// name.ends_with('_') || name.ends_with('-');
1130 /// ```
1131 pub CHARS_LAST_CMP,
1132 style,
1133 "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char"
1134 }
1135
1136 declare_clippy_lint! {
1137 /// **What it does:** Checks for usage of `.as_ref()` or `.as_mut()` where the
1138 /// types before and after the call are the same.
1139 ///
1140 /// **Why is this bad?** The call is unnecessary.
1141 ///
1142 /// **Known problems:** None.
1143 ///
1144 /// **Example:**
1145 /// ```rust
1146 /// # fn do_stuff(x: &[i32]) {}
1147 /// let x: &[i32] = &[1, 2, 3, 4, 5];
1148 /// do_stuff(x.as_ref());
1149 /// ```
1150 /// The correct use would be:
1151 /// ```rust
1152 /// # fn do_stuff(x: &[i32]) {}
1153 /// let x: &[i32] = &[1, 2, 3, 4, 5];
1154 /// do_stuff(x);
1155 /// ```
1156 pub USELESS_ASREF,
1157 complexity,
1158 "using `as_ref` where the types before and after the call are the same"
1159 }
1160
1161 declare_clippy_lint! {
1162 /// **What it does:** Checks for using `fold` when a more succinct alternative exists.
1163 /// Specifically, this checks for `fold`s which could be replaced by `any`, `all`,
1164 /// `sum` or `product`.
1165 ///
1166 /// **Why is this bad?** Readability.
1167 ///
1168 /// **Known problems:** None.
1169 ///
1170 /// **Example:**
1171 /// ```rust
1172 /// let _ = (0..3).fold(false, |acc, x| acc || x > 2);
1173 /// ```
1174 /// This could be written as:
1175 /// ```rust
1176 /// let _ = (0..3).any(|x| x > 2);
1177 /// ```
1178 pub UNNECESSARY_FOLD,
1179 style,
1180 "using `fold` when a more succinct alternative exists"
1181 }
1182
1183 declare_clippy_lint! {
1184 /// **What it does:** Checks for `filter_map` calls which could be replaced by `filter` or `map`.
1185 /// More specifically it checks if the closure provided is only performing one of the
1186 /// filter or map operations and suggests the appropriate option.
1187 ///
1188 /// **Why is this bad?** Complexity. The intent is also clearer if only a single
1189 /// operation is being performed.
1190 ///
1191 /// **Known problems:** None
1192 ///
1193 /// **Example:**
1194 /// ```rust
1195 /// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None });
1196 ///
1197 /// // As there is no transformation of the argument this could be written as:
1198 /// let _ = (0..3).filter(|&x| x > 2);
1199 /// ```
1200 ///
1201 /// ```rust
1202 /// let _ = (0..4).filter_map(|x| Some(x + 1));
1203 ///
1204 /// // As there is no conditional check on the argument this could be written as:
1205 /// let _ = (0..4).map(|x| x + 1);
1206 /// ```
1207 pub UNNECESSARY_FILTER_MAP,
1208 complexity,
1209 "using `filter_map` when a more succinct alternative exists"
1210 }
1211
1212 declare_clippy_lint! {
1213 /// **What it does:** Checks for `into_iter` calls on references which should be replaced by `iter`
1214 /// or `iter_mut`.
1215 ///
1216 /// **Why is this bad?** Readability. Calling `into_iter` on a reference will not move out its
1217 /// content into the resulting iterator, which is confusing. It is better just call `iter` or
1218 /// `iter_mut` directly.
1219 ///
1220 /// **Known problems:** None
1221 ///
1222 /// **Example:**
1223 ///
1224 /// ```rust
1225 /// // Bad
1226 /// let _ = (&vec![3, 4, 5]).into_iter();
1227 ///
1228 /// // Good
1229 /// let _ = (&vec![3, 4, 5]).iter();
1230 /// ```
1231 pub INTO_ITER_ON_REF,
1232 style,
1233 "using `.into_iter()` on a reference"
1234 }
1235
1236 declare_clippy_lint! {
1237 /// **What it does:** Checks for calls to `map` followed by a `count`.
1238 ///
1239 /// **Why is this bad?** It looks suspicious. Maybe `map` was confused with `filter`.
1240 /// If the `map` call is intentional, this should be rewritten. Or, if you intend to
1241 /// drive the iterator to completion, you can just use `for_each` instead.
1242 ///
1243 /// **Known problems:** None
1244 ///
1245 /// **Example:**
1246 ///
1247 /// ```rust
1248 /// let _ = (0..3).map(|x| x + 2).count();
1249 /// ```
1250 pub SUSPICIOUS_MAP,
1251 suspicious,
1252 "suspicious usage of map"
1253 }
1254
1255 declare_clippy_lint! {
1256 /// **What it does:** Checks for `MaybeUninit::uninit().assume_init()`.
1257 ///
1258 /// **Why is this bad?** For most types, this is undefined behavior.
1259 ///
1260 /// **Known problems:** For now, we accept empty tuples and tuples / arrays
1261 /// of `MaybeUninit`. There may be other types that allow uninitialized
1262 /// data, but those are not yet rigorously defined.
1263 ///
1264 /// **Example:**
1265 ///
1266 /// ```rust
1267 /// // Beware the UB
1268 /// use std::mem::MaybeUninit;
1269 ///
1270 /// let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
1271 /// ```
1272 ///
1273 /// Note that the following is OK:
1274 ///
1275 /// ```rust
1276 /// use std::mem::MaybeUninit;
1277 ///
1278 /// let _: [MaybeUninit<bool>; 5] = unsafe {
1279 /// MaybeUninit::uninit().assume_init()
1280 /// };
1281 /// ```
1282 pub UNINIT_ASSUMED_INIT,
1283 correctness,
1284 "`MaybeUninit::uninit().assume_init()`"
1285 }
1286
1287 declare_clippy_lint! {
1288 /// **What it does:** Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`.
1289 ///
1290 /// **Why is this bad?** These can be written simply with `saturating_add/sub` methods.
1291 ///
1292 /// **Example:**
1293 ///
1294 /// ```rust
1295 /// # let y: u32 = 0;
1296 /// # let x: u32 = 100;
1297 /// let add = x.checked_add(y).unwrap_or(u32::MAX);
1298 /// let sub = x.checked_sub(y).unwrap_or(u32::MIN);
1299 /// ```
1300 ///
1301 /// can be written using dedicated methods for saturating addition/subtraction as:
1302 ///
1303 /// ```rust
1304 /// # let y: u32 = 0;
1305 /// # let x: u32 = 100;
1306 /// let add = x.saturating_add(y);
1307 /// let sub = x.saturating_sub(y);
1308 /// ```
1309 pub MANUAL_SATURATING_ARITHMETIC,
1310 style,
1311 "`.chcked_add/sub(x).unwrap_or(MAX/MIN)`"
1312 }
1313
1314 declare_clippy_lint! {
1315 /// **What it does:** Checks for `offset(_)`, `wrapping_`{`add`, `sub`}, etc. on raw pointers to
1316 /// zero-sized types
1317 ///
1318 /// **Why is this bad?** This is a no-op, and likely unintended
1319 ///
1320 /// **Known problems:** None
1321 ///
1322 /// **Example:**
1323 /// ```rust
1324 /// unsafe { (&() as *const ()).offset(1) };
1325 /// ```
1326 pub ZST_OFFSET,
1327 correctness,
1328 "Check for offset calculations on raw pointers to zero-sized types"
1329 }
1330
1331 declare_clippy_lint! {
1332 /// **What it does:** Checks for `FileType::is_file()`.
1333 ///
1334 /// **Why is this bad?** When people testing a file type with `FileType::is_file`
1335 /// they are testing whether a path is something they can get bytes from. But
1336 /// `is_file` doesn't cover special file types in unix-like systems, and doesn't cover
1337 /// symlink in windows. Using `!FileType::is_dir()` is a better way to that intention.
1338 ///
1339 /// **Example:**
1340 ///
1341 /// ```rust
1342 /// # || {
1343 /// let metadata = std::fs::metadata("foo.txt")?;
1344 /// let filetype = metadata.file_type();
1345 ///
1346 /// if filetype.is_file() {
1347 /// // read file
1348 /// }
1349 /// # Ok::<_, std::io::Error>(())
1350 /// # };
1351 /// ```
1352 ///
1353 /// should be written as:
1354 ///
1355 /// ```rust
1356 /// # || {
1357 /// let metadata = std::fs::metadata("foo.txt")?;
1358 /// let filetype = metadata.file_type();
1359 ///
1360 /// if !filetype.is_dir() {
1361 /// // read file
1362 /// }
1363 /// # Ok::<_, std::io::Error>(())
1364 /// # };
1365 /// ```
1366 pub FILETYPE_IS_FILE,
1367 restriction,
1368 "`FileType::is_file` is not recommended to test for readable file type"
1369 }
1370
1371 declare_clippy_lint! {
1372 /// **What it does:** Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str).
1373 ///
1374 /// **Why is this bad?** Readability, this can be written more concisely as
1375 /// `_.as_deref()`.
1376 ///
1377 /// **Known problems:** None.
1378 ///
1379 /// **Example:**
1380 /// ```rust
1381 /// # let opt = Some("".to_string());
1382 /// opt.as_ref().map(String::as_str)
1383 /// # ;
1384 /// ```
1385 /// Can be written as
1386 /// ```rust
1387 /// # let opt = Some("".to_string());
1388 /// opt.as_deref()
1389 /// # ;
1390 /// ```
1391 pub OPTION_AS_REF_DEREF,
1392 complexity,
1393 "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`"
1394 }
1395
1396 declare_clippy_lint! {
1397 /// **What it does:** Checks for usage of `iter().next()` on a Slice or an Array
1398 ///
1399 /// **Why is this bad?** These can be shortened into `.get()`
1400 ///
1401 /// **Known problems:** None.
1402 ///
1403 /// **Example:**
1404 /// ```rust
1405 /// # let a = [1, 2, 3];
1406 /// # let b = vec![1, 2, 3];
1407 /// a[2..].iter().next();
1408 /// b.iter().next();
1409 /// ```
1410 /// should be written as:
1411 /// ```rust
1412 /// # let a = [1, 2, 3];
1413 /// # let b = vec![1, 2, 3];
1414 /// a.get(2);
1415 /// b.get(0);
1416 /// ```
1417 pub ITER_NEXT_SLICE,
1418 style,
1419 "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`"
1420 }
1421
1422 declare_clippy_lint! {
1423 /// **What it does:** Warns when using `push_str`/`insert_str` with a single-character string literal
1424 /// where `push`/`insert` with a `char` would work fine.
1425 ///
1426 /// **Why is this bad?** It's less clear that we are pushing a single character.
1427 ///
1428 /// **Known problems:** None
1429 ///
1430 /// **Example:**
1431 /// ```rust
1432 /// let mut string = String::new();
1433 /// string.insert_str(0, "R");
1434 /// string.push_str("R");
1435 /// ```
1436 /// Could be written as
1437 /// ```rust
1438 /// let mut string = String::new();
1439 /// string.insert(0, 'R');
1440 /// string.push('R');
1441 /// ```
1442 pub SINGLE_CHAR_ADD_STR,
1443 style,
1444 "`push_str()` or `insert_str()` used with a single-character string literal as parameter"
1445 }
1446
1447 declare_clippy_lint! {
1448 /// **What it does:** As the counterpart to `or_fun_call`, this lint looks for unnecessary
1449 /// lazily evaluated closures on `Option` and `Result`.
1450 ///
1451 /// This lint suggests changing the following functions, when eager evaluation results in
1452 /// simpler code:
1453 /// - `unwrap_or_else` to `unwrap_or`
1454 /// - `and_then` to `and`
1455 /// - `or_else` to `or`
1456 /// - `get_or_insert_with` to `get_or_insert`
1457 /// - `ok_or_else` to `ok_or`
1458 ///
1459 /// **Why is this bad?** Using eager evaluation is shorter and simpler in some cases.
1460 ///
1461 /// **Known problems:** It is possible, but not recommended for `Deref` and `Index` to have
1462 /// side effects. Eagerly evaluating them can change the semantics of the program.
1463 ///
1464 /// **Example:**
1465 ///
1466 /// ```rust
1467 /// // example code where clippy issues a warning
1468 /// let opt: Option<u32> = None;
1469 ///
1470 /// opt.unwrap_or_else(|| 42);
1471 /// ```
1472 /// Use instead:
1473 /// ```rust
1474 /// let opt: Option<u32> = None;
1475 ///
1476 /// opt.unwrap_or(42);
1477 /// ```
1478 pub UNNECESSARY_LAZY_EVALUATIONS,
1479 style,
1480 "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation"
1481 }
1482
1483 declare_clippy_lint! {
1484 /// **What it does:** Checks for usage of `_.map(_).collect::<Result<(), _>()`.
1485 ///
1486 /// **Why is this bad?** Using `try_for_each` instead is more readable and idiomatic.
1487 ///
1488 /// **Known problems:** None
1489 ///
1490 /// **Example:**
1491 ///
1492 /// ```rust
1493 /// (0..3).map(|t| Err(t)).collect::<Result<(), _>>();
1494 /// ```
1495 /// Use instead:
1496 /// ```rust
1497 /// (0..3).try_for_each(|t| Err(t));
1498 /// ```
1499 pub MAP_COLLECT_RESULT_UNIT,
1500 style,
1501 "using `.map(_).collect::<Result<(),_>()`, which can be replaced with `try_for_each`"
1502 }
1503
1504 declare_clippy_lint! {
1505 /// **What it does:** Checks for `from_iter()` function calls on types that implement the `FromIterator`
1506 /// trait.
1507 ///
1508 /// **Why is this bad?** It is recommended style to use collect. See
1509 /// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html)
1510 ///
1511 /// **Known problems:** None.
1512 ///
1513 /// **Example:**
1514 ///
1515 /// ```rust
1516 /// use std::iter::FromIterator;
1517 ///
1518 /// let five_fives = std::iter::repeat(5).take(5);
1519 ///
1520 /// let v = Vec::from_iter(five_fives);
1521 ///
1522 /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
1523 /// ```
1524 /// Use instead:
1525 /// ```rust
1526 /// let five_fives = std::iter::repeat(5).take(5);
1527 ///
1528 /// let v: Vec<i32> = five_fives.collect();
1529 ///
1530 /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
1531 /// ```
1532 pub FROM_ITER_INSTEAD_OF_COLLECT,
1533 pedantic,
1534 "use `.collect()` instead of `::from_iter()`"
1535 }
1536
1537 declare_clippy_lint! {
1538 /// **What it does:** Checks for usage of `inspect().for_each()`.
1539 ///
1540 /// **Why is this bad?** It is the same as performing the computation
1541 /// inside `inspect` at the beginning of the closure in `for_each`.
1542 ///
1543 /// **Known problems:** None.
1544 ///
1545 /// **Example:**
1546 ///
1547 /// ```rust
1548 /// [1,2,3,4,5].iter()
1549 /// .inspect(|&x| println!("inspect the number: {}", x))
1550 /// .for_each(|&x| {
1551 /// assert!(x >= 0);
1552 /// });
1553 /// ```
1554 /// Can be written as
1555 /// ```rust
1556 /// [1,2,3,4,5].iter()
1557 /// .for_each(|&x| {
1558 /// println!("inspect the number: {}", x);
1559 /// assert!(x >= 0);
1560 /// });
1561 /// ```
1562 pub INSPECT_FOR_EACH,
1563 complexity,
1564 "using `.inspect().for_each()`, which can be replaced with `.for_each()`"
1565 }
1566
1567 declare_clippy_lint! {
1568 /// **What it does:** Checks for usage of `filter_map(|x| x)`.
1569 ///
1570 /// **Why is this bad?** Readability, this can be written more concisely by using `flatten`.
1571 ///
1572 /// **Known problems:** None.
1573 ///
1574 /// **Example:**
1575 ///
1576 /// ```rust
1577 /// # let iter = vec![Some(1)].into_iter();
1578 /// iter.filter_map(|x| x);
1579 /// ```
1580 /// Use instead:
1581 /// ```rust
1582 /// # let iter = vec![Some(1)].into_iter();
1583 /// iter.flatten();
1584 /// ```
1585 pub FILTER_MAP_IDENTITY,
1586 complexity,
1587 "call to `filter_map` where `flatten` is sufficient"
1588 }
1589
1590 declare_clippy_lint! {
1591 /// **What it does:** Checks for instances of `map(f)` where `f` is the identity function.
1592 ///
1593 /// **Why is this bad?** It can be written more concisely without the call to `map`.
1594 ///
1595 /// **Known problems:** None.
1596 ///
1597 /// **Example:**
1598 ///
1599 /// ```rust
1600 /// let x = [1, 2, 3];
1601 /// let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect();
1602 /// ```
1603 /// Use instead:
1604 /// ```rust
1605 /// let x = [1, 2, 3];
1606 /// let y: Vec<_> = x.iter().map(|x| 2*x).collect();
1607 /// ```
1608 pub MAP_IDENTITY,
1609 complexity,
1610 "using iterator.map(|x| x)"
1611 }
1612
1613 declare_clippy_lint! {
1614 /// **What it does:** Checks for the use of `.bytes().nth()`.
1615 ///
1616 /// **Why is this bad?** `.as_bytes().get()` is more efficient and more
1617 /// readable.
1618 ///
1619 /// **Known problems:** None.
1620 ///
1621 /// **Example:**
1622 ///
1623 /// ```rust
1624 /// // Bad
1625 /// let _ = "Hello".bytes().nth(3);
1626 ///
1627 /// // Good
1628 /// let _ = "Hello".as_bytes().get(3);
1629 /// ```
1630 pub BYTES_NTH,
1631 style,
1632 "replace `.bytes().nth()` with `.as_bytes().get()`"
1633 }
1634
1635 declare_clippy_lint! {
1636 /// **What it does:** Checks for the usage of `_.to_owned()`, `vec.to_vec()`, or similar when calling `_.clone()` would be clearer.
1637 ///
1638 /// **Why is this bad?** These methods do the same thing as `_.clone()` but may be confusing as
1639 /// to why we are calling `to_vec` on something that is already a `Vec` or calling `to_owned` on something that is already owned.
1640 ///
1641 /// **Known problems:** None.
1642 ///
1643 /// **Example:**
1644 ///
1645 /// ```rust
1646 /// let a = vec![1, 2, 3];
1647 /// let b = a.to_vec();
1648 /// let c = a.to_owned();
1649 /// ```
1650 /// Use instead:
1651 /// ```rust
1652 /// let a = vec![1, 2, 3];
1653 /// let b = a.clone();
1654 /// let c = a.clone();
1655 /// ```
1656 pub IMPLICIT_CLONE,
1657 pedantic,
1658 "implicitly cloning a value by invoking a function on its dereferenced type"
1659 }
1660
1661 declare_clippy_lint! {
1662 /// **What it does:** Checks for the use of `.iter().count()`.
1663 ///
1664 /// **Why is this bad?** `.len()` is more efficient and more
1665 /// readable.
1666 ///
1667 /// **Known problems:** None.
1668 ///
1669 /// **Example:**
1670 ///
1671 /// ```rust
1672 /// // Bad
1673 /// let some_vec = vec![0, 1, 2, 3];
1674 /// let _ = some_vec.iter().count();
1675 /// let _ = &some_vec[..].iter().count();
1676 ///
1677 /// // Good
1678 /// let some_vec = vec![0, 1, 2, 3];
1679 /// let _ = some_vec.len();
1680 /// let _ = &some_vec[..].len();
1681 /// ```
1682 pub ITER_COUNT,
1683 complexity,
1684 "replace `.iter().count()` with `.len()`"
1685 }
1686
1687 declare_clippy_lint! {
1688 /// **What it does:** Checks for calls to [`splitn`]
1689 /// (https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and
1690 /// related functions with either zero or one splits.
1691 ///
1692 /// **Why is this bad?** These calls don't actually split the value and are
1693 /// likely to be intended as a different number.
1694 ///
1695 /// **Known problems:** None.
1696 ///
1697 /// **Example:**
1698 ///
1699 /// ```rust
1700 /// // Bad
1701 /// let s = "";
1702 /// for x in s.splitn(1, ":") {
1703 /// // use x
1704 /// }
1705 ///
1706 /// // Good
1707 /// let s = "";
1708 /// for x in s.splitn(2, ":") {
1709 /// // use x
1710 /// }
1711 /// ```
1712 pub SUSPICIOUS_SPLITN,
1713 correctness,
1714 "checks for `.splitn(0, ..)` and `.splitn(1, ..)`"
1715 }
1716
1717 declare_clippy_lint! {
1718 /// **What it does:** Checks for manual implementations of `str::repeat`
1719 ///
1720 /// **Why is this bad?** These are both harder to read, as well as less performant.
1721 ///
1722 /// **Known problems:** None.
1723 ///
1724 /// **Example:**
1725 ///
1726 /// ```rust
1727 /// // Bad
1728 /// let x: String = std::iter::repeat('x').take(10).collect();
1729 ///
1730 /// // Good
1731 /// let x: String = "x".repeat(10);
1732 /// ```
1733 pub MANUAL_STR_REPEAT,
1734 perf,
1735 "manual implementation of `str::repeat`"
1736 }
1737
1738 pub struct Methods {
1739 avoid_breaking_exported_api: bool,
1740 msrv: Option<RustcVersion>,
1741 }
1742
1743 impl Methods {
1744 #[must_use]
1745 pub fn new(avoid_breaking_exported_api: bool, msrv: Option<RustcVersion>) -> Self {
1746 Self {
1747 avoid_breaking_exported_api,
1748 msrv,
1749 }
1750 }
1751 }
1752
1753 impl_lint_pass!(Methods => [
1754 UNWRAP_USED,
1755 EXPECT_USED,
1756 SHOULD_IMPLEMENT_TRAIT,
1757 WRONG_SELF_CONVENTION,
1758 OK_EXPECT,
1759 MAP_UNWRAP_OR,
1760 RESULT_MAP_OR_INTO_OPTION,
1761 OPTION_MAP_OR_NONE,
1762 BIND_INSTEAD_OF_MAP,
1763 OR_FUN_CALL,
1764 EXPECT_FUN_CALL,
1765 CHARS_NEXT_CMP,
1766 CHARS_LAST_CMP,
1767 CLONE_ON_COPY,
1768 CLONE_ON_REF_PTR,
1769 CLONE_DOUBLE_REF,
1770 CLONED_INSTEAD_OF_COPIED,
1771 FLAT_MAP_OPTION,
1772 INEFFICIENT_TO_STRING,
1773 NEW_RET_NO_SELF,
1774 SINGLE_CHAR_PATTERN,
1775 SINGLE_CHAR_ADD_STR,
1776 SEARCH_IS_SOME,
1777 FILTER_NEXT,
1778 SKIP_WHILE_NEXT,
1779 FILTER_MAP_IDENTITY,
1780 MAP_IDENTITY,
1781 MANUAL_FILTER_MAP,
1782 MANUAL_FIND_MAP,
1783 OPTION_FILTER_MAP,
1784 FILTER_MAP_NEXT,
1785 FLAT_MAP_IDENTITY,
1786 MAP_FLATTEN,
1787 ITERATOR_STEP_BY_ZERO,
1788 ITER_NEXT_SLICE,
1789 ITER_COUNT,
1790 ITER_NTH,
1791 ITER_NTH_ZERO,
1792 BYTES_NTH,
1793 ITER_SKIP_NEXT,
1794 GET_UNWRAP,
1795 STRING_EXTEND_CHARS,
1796 ITER_CLONED_COLLECT,
1797 USELESS_ASREF,
1798 UNNECESSARY_FOLD,
1799 UNNECESSARY_FILTER_MAP,
1800 INTO_ITER_ON_REF,
1801 SUSPICIOUS_MAP,
1802 UNINIT_ASSUMED_INIT,
1803 MANUAL_SATURATING_ARITHMETIC,
1804 ZST_OFFSET,
1805 FILETYPE_IS_FILE,
1806 OPTION_AS_REF_DEREF,
1807 UNNECESSARY_LAZY_EVALUATIONS,
1808 MAP_COLLECT_RESULT_UNIT,
1809 FROM_ITER_INSTEAD_OF_COLLECT,
1810 INSPECT_FOR_EACH,
1811 IMPLICIT_CLONE,
1812 SUSPICIOUS_SPLITN,
1813 MANUAL_STR_REPEAT,
1814 EXTEND_WITH_DRAIN
1815 ]);
1816
1817 /// Extracts a method call name, args, and `Span` of the method name.
1818 fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(SymbolStr, &'tcx [hir::Expr<'tcx>], Span)> {
1819 if let ExprKind::MethodCall(path, span, args, _) = recv.kind {
1820 if !args.iter().any(|e| e.span.from_expansion()) {
1821 return Some((path.ident.name.as_str(), args, span));
1822 }
1823 }
1824 None
1825 }
1826
1827 /// Same as `method_call` but the `SymbolStr` is dereferenced into a temporary `&str`
1828 macro_rules! method_call {
1829 ($expr:expr) => {
1830 method_call($expr)
1831 .as_ref()
1832 .map(|&(ref name, args, span)| (&**name, args, span))
1833 };
1834 }
1835
1836 impl<'tcx> LateLintPass<'tcx> for Methods {
1837 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
1838 if in_macro(expr.span) {
1839 return;
1840 }
1841
1842 check_methods(cx, expr, self.msrv.as_ref());
1843
1844 match expr.kind {
1845 hir::ExprKind::Call(func, args) => {
1846 from_iter_instead_of_collect::check(cx, expr, args, func);
1847 },
1848 hir::ExprKind::MethodCall(method_call, ref method_span, args, _) => {
1849 or_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args);
1850 expect_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args);
1851 clone_on_copy::check(cx, expr, method_call.ident.name, args);
1852 clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args);
1853 inefficient_to_string::check(cx, expr, method_call.ident.name, args);
1854 single_char_add_str::check(cx, expr, args);
1855 into_iter_on_ref::check(cx, expr, *method_span, method_call.ident.name, args);
1856 single_char_pattern::check(cx, expr, method_call.ident.name, args);
1857 },
1858 hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
1859 let mut info = BinaryExprInfo {
1860 expr,
1861 chain: lhs,
1862 other: rhs,
1863 eq: op.node == hir::BinOpKind::Eq,
1864 };
1865 lint_binary_expr_with_method_call(cx, &mut info);
1866 },
1867 _ => (),
1868 }
1869 }
1870
1871 #[allow(clippy::too_many_lines)]
1872 fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
1873 if in_external_macro(cx.sess(), impl_item.span) {
1874 return;
1875 }
1876 let name = impl_item.ident.name.as_str();
1877 let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
1878 let item = cx.tcx.hir().expect_item(parent);
1879 let self_ty = cx.tcx.type_of(item.def_id);
1880
1881 let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
1882 if_chain! {
1883 if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind;
1884 if let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next();
1885
1886 let method_sig = cx.tcx.fn_sig(impl_item.def_id);
1887 let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
1888
1889 let first_arg_ty = &method_sig.inputs().iter().next();
1890
1891 // check conventions w.r.t. conversion method names and predicates
1892 if let Some(first_arg_ty) = first_arg_ty;
1893
1894 then {
1895 // if this impl block implements a trait, lint in trait definition instead
1896 if !implements_trait && cx.access_levels.is_exported(impl_item.hir_id()) {
1897 // check missing trait implementations
1898 for method_config in &TRAIT_METHODS {
1899 if name == method_config.method_name &&
1900 sig.decl.inputs.len() == method_config.param_count &&
1901 method_config.output_type.matches(&sig.decl.output) &&
1902 method_config.self_kind.matches(cx, self_ty, first_arg_ty) &&
1903 fn_header_equals(method_config.fn_header, sig.header) &&
1904 method_config.lifetime_param_cond(impl_item)
1905 {
1906 span_lint_and_help(
1907 cx,
1908 SHOULD_IMPLEMENT_TRAIT,
1909 impl_item.span,
1910 &format!(
1911 "method `{}` can be confused for the standard trait method `{}::{}`",
1912 method_config.method_name,
1913 method_config.trait_name,
1914 method_config.method_name
1915 ),
1916 None,
1917 &format!(
1918 "consider implementing the trait `{}` or choosing a less ambiguous method name",
1919 method_config.trait_name
1920 )
1921 );
1922 }
1923 }
1924 }
1925
1926 if sig.decl.implicit_self.has_implicit_self()
1927 && !(self.avoid_breaking_exported_api
1928 && cx.access_levels.is_exported(impl_item.hir_id()))
1929 {
1930 wrong_self_convention::check(
1931 cx,
1932 &name,
1933 self_ty,
1934 first_arg_ty,
1935 first_arg.pat.span,
1936 implements_trait,
1937 false
1938 );
1939 }
1940 }
1941 }
1942
1943 // if this impl block implements a trait, lint in trait definition instead
1944 if implements_trait {
1945 return;
1946 }
1947
1948 if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
1949 let ret_ty = return_ty(cx, impl_item.hir_id());
1950
1951 // walk the return type and check for Self (this does not check associated types)
1952 if let Some(self_adt) = self_ty.ty_adt_def() {
1953 if contains_adt_constructor(ret_ty, self_adt) {
1954 return;
1955 }
1956 } else if contains_ty(ret_ty, self_ty) {
1957 return;
1958 }
1959
1960 // if return type is impl trait, check the associated types
1961 if let ty::Opaque(def_id, _) = *ret_ty.kind() {
1962 // one of the associated types must be Self
1963 for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
1964 if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
1965 // walk the associated type and check for Self
1966 if let Some(self_adt) = self_ty.ty_adt_def() {
1967 if contains_adt_constructor(projection_predicate.ty, self_adt) {
1968 return;
1969 }
1970 } else if contains_ty(projection_predicate.ty, self_ty) {
1971 return;
1972 }
1973 }
1974 }
1975 }
1976
1977 if name == "new" && !TyS::same_type(ret_ty, self_ty) {
1978 span_lint(
1979 cx,
1980 NEW_RET_NO_SELF,
1981 impl_item.span,
1982 "methods called `new` usually return `Self`",
1983 );
1984 }
1985 }
1986 }
1987
1988 fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
1989 if in_external_macro(cx.tcx.sess, item.span) {
1990 return;
1991 }
1992
1993 if_chain! {
1994 if let TraitItemKind::Fn(ref sig, _) = item.kind;
1995 if sig.decl.implicit_self.has_implicit_self();
1996 if let Some(first_arg_ty) = sig.decl.inputs.iter().next();
1997
1998 then {
1999 let first_arg_span = first_arg_ty.span;
2000 let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
2001 let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty();
2002 wrong_self_convention::check(
2003 cx,
2004 &item.ident.name.as_str(),
2005 self_ty,
2006 first_arg_ty,
2007 first_arg_span,
2008 false,
2009 true
2010 );
2011 }
2012 }
2013
2014 if_chain! {
2015 if item.ident.name == sym::new;
2016 if let TraitItemKind::Fn(_, _) = item.kind;
2017 let ret_ty = return_ty(cx, item.hir_id());
2018 let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty();
2019 if !contains_ty(ret_ty, self_ty);
2020
2021 then {
2022 span_lint(
2023 cx,
2024 NEW_RET_NO_SELF,
2025 item.span,
2026 "methods called `new` usually return `Self`",
2027 );
2028 }
2029 }
2030 }
2031
2032 extract_msrv_attr!(LateContext);
2033 }
2034
2035 #[allow(clippy::too_many_lines)]
2036 fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option<&RustcVersion>) {
2037 if let Some((name, [recv, args @ ..], span)) = method_call!(expr) {
2038 match (name, args) {
2039 ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
2040 zst_offset::check(cx, expr, recv);
2041 },
2042 ("and_then", [arg]) => {
2043 let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
2044 let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg);
2045 if !biom_option_linted && !biom_result_linted {
2046 unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
2047 }
2048 },
2049 ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
2050 ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
2051 ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
2052 ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, msrv),
2053 ("collect", []) => match method_call!(recv) {
2054 Some(("cloned", [recv2], _)) => iter_cloned_collect::check(cx, expr, recv2),
2055 Some(("map", [m_recv, m_arg], _)) => {
2056 map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
2057 },
2058 Some(("take", [take_self_arg, take_arg], _)) => {
2059 if meets_msrv(msrv, &msrvs::STR_REPEAT) {
2060 manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
2061 }
2062 },
2063 _ => {},
2064 },
2065 ("count", []) => match method_call!(recv) {
2066 Some((name @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
2067 iter_count::check(cx, expr, recv2, name);
2068 },
2069 Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
2070 _ => {},
2071 },
2072 ("expect", [_]) => match method_call!(recv) {
2073 Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
2074 _ => expect_used::check(cx, expr, recv),
2075 },
2076 ("extend", [arg]) => {
2077 string_extend_chars::check(cx, expr, recv, arg);
2078 extend_with_drain::check(cx, expr, recv, arg);
2079 },
2080 ("filter_map", [arg]) => {
2081 unnecessary_filter_map::check(cx, expr, arg);
2082 filter_map_identity::check(cx, expr, arg, span);
2083 },
2084 ("flat_map", [arg]) => {
2085 flat_map_identity::check(cx, expr, arg, span);
2086 flat_map_option::check(cx, expr, arg, span);
2087 },
2088 ("flatten", []) => {
2089 if let Some(("map", [recv, map_arg], _)) = method_call!(recv) {
2090 map_flatten::check(cx, expr, recv, map_arg);
2091 }
2092 },
2093 ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
2094 ("for_each", [_]) => {
2095 if let Some(("inspect", [_, _], span2)) = method_call!(recv) {
2096 inspect_for_each::check(cx, expr, span2);
2097 }
2098 },
2099 ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
2100 ("is_file", []) => filetype_is_file::check(cx, expr, recv),
2101 ("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
2102 ("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
2103 ("map", [m_arg]) => {
2104 if let Some((name, [recv2, args @ ..], span2)) = method_call!(recv) {
2105 match (name, args) {
2106 ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, msrv),
2107 ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv),
2108 ("filter", [f_arg]) => {
2109 filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
2110 },
2111 ("find", [f_arg]) => filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true),
2112 _ => {},
2113 }
2114 }
2115 map_identity::check(cx, expr, recv, m_arg, span);
2116 },
2117 ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
2118 ("next", []) => {
2119 if let Some((name, [recv, args @ ..], _)) = method_call!(recv) {
2120 match (name, args) {
2121 ("filter", [arg]) => filter_next::check(cx, expr, recv, arg),
2122 ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv, arg, msrv),
2123 ("iter", []) => iter_next_slice::check(cx, expr, recv),
2124 ("skip", [arg]) => iter_skip_next::check(cx, expr, recv, arg),
2125 ("skip_while", [_]) => skip_while_next::check(cx, expr),
2126 _ => {},
2127 }
2128 }
2129 },
2130 ("nth", [n_arg]) => match method_call!(recv) {
2131 Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
2132 Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
2133 Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
2134 _ => iter_nth_zero::check(cx, expr, recv, n_arg),
2135 },
2136 ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
2137 ("or_else", [arg]) => {
2138 if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
2139 unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
2140 }
2141 },
2142 ("splitn" | "splitn_mut" | "rsplitn" | "rsplitn_mut", [count_arg, _]) => {
2143 suspicious_splitn::check(cx, name, expr, recv, count_arg);
2144 },
2145 ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
2146 ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
2147 implicit_clone::check(cx, name, expr, recv, span);
2148 },
2149 ("unwrap", []) => match method_call!(recv) {
2150 Some(("get", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, false),
2151 Some(("get_mut", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, true),
2152 _ => unwrap_used::check(cx, expr, recv),
2153 },
2154 ("unwrap_or", [u_arg]) => match method_call!(recv) {
2155 Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
2156 manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
2157 },
2158 Some(("map", [m_recv, m_arg], span)) => {
2159 option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
2160 },
2161 _ => {},
2162 },
2163 ("unwrap_or_else", [u_arg]) => match method_call!(recv) {
2164 Some(("map", [recv, map_arg], _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, msrv) => {},
2165 _ => unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"),
2166 },
2167 _ => {},
2168 }
2169 }
2170 }
2171
2172 fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
2173 if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call!(recv) {
2174 search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
2175 }
2176 }
2177
2178 /// Used for `lint_binary_expr_with_method_call`.
2179 #[derive(Copy, Clone)]
2180 struct BinaryExprInfo<'a> {
2181 expr: &'a hir::Expr<'a>,
2182 chain: &'a hir::Expr<'a>,
2183 other: &'a hir::Expr<'a>,
2184 eq: bool,
2185 }
2186
2187 /// Checks for the `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
2188 fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExprInfo<'_>) {
2189 macro_rules! lint_with_both_lhs_and_rhs {
2190 ($func:expr, $cx:expr, $info:ident) => {
2191 if !$func($cx, $info) {
2192 ::std::mem::swap(&mut $info.chain, &mut $info.other);
2193 if $func($cx, $info) {
2194 return;
2195 }
2196 }
2197 };
2198 }
2199
2200 lint_with_both_lhs_and_rhs!(chars_next_cmp::check, cx, info);
2201 lint_with_both_lhs_and_rhs!(chars_last_cmp::check, cx, info);
2202 lint_with_both_lhs_and_rhs!(chars_next_cmp_with_unwrap::check, cx, info);
2203 lint_with_both_lhs_and_rhs!(chars_last_cmp_with_unwrap::check, cx, info);
2204 }
2205
2206 const FN_HEADER: hir::FnHeader = hir::FnHeader {
2207 unsafety: hir::Unsafety::Normal,
2208 constness: hir::Constness::NotConst,
2209 asyncness: hir::IsAsync::NotAsync,
2210 abi: rustc_target::spec::abi::Abi::Rust,
2211 };
2212
2213 struct ShouldImplTraitCase {
2214 trait_name: &'static str,
2215 method_name: &'static str,
2216 param_count: usize,
2217 fn_header: hir::FnHeader,
2218 // implicit self kind expected (none, self, &self, ...)
2219 self_kind: SelfKind,
2220 // checks against the output type
2221 output_type: OutType,
2222 // certain methods with explicit lifetimes can't implement the equivalent trait method
2223 lint_explicit_lifetime: bool,
2224 }
2225 impl ShouldImplTraitCase {
2226 const fn new(
2227 trait_name: &'static str,
2228 method_name: &'static str,
2229 param_count: usize,
2230 fn_header: hir::FnHeader,
2231 self_kind: SelfKind,
2232 output_type: OutType,
2233 lint_explicit_lifetime: bool,
2234 ) -> ShouldImplTraitCase {
2235 ShouldImplTraitCase {
2236 trait_name,
2237 method_name,
2238 param_count,
2239 fn_header,
2240 self_kind,
2241 output_type,
2242 lint_explicit_lifetime,
2243 }
2244 }
2245
2246 fn lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool {
2247 self.lint_explicit_lifetime
2248 || !impl_item.generics.params.iter().any(|p| {
2249 matches!(
2250 p.kind,
2251 hir::GenericParamKind::Lifetime {
2252 kind: hir::LifetimeParamKind::Explicit
2253 }
2254 )
2255 })
2256 }
2257 }
2258
2259 #[rustfmt::skip]
2260 const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
2261 ShouldImplTraitCase::new("std::ops::Add", "add", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
2262 ShouldImplTraitCase::new("std::convert::AsMut", "as_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
2263 ShouldImplTraitCase::new("std::convert::AsRef", "as_ref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
2264 ShouldImplTraitCase::new("std::ops::BitAnd", "bitand", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
2265 ShouldImplTraitCase::new("std::ops::BitOr", "bitor", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
2266 ShouldImplTraitCase::new("std::ops::BitXor", "bitxor", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
2267 ShouldImplTraitCase::new("std::borrow::Borrow", "borrow", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
2268 ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
2269 ShouldImplTraitCase::new("std::clone::Clone", "clone", 1, FN_HEADER, SelfKind::Ref, OutType::Any, true),
2270 ShouldImplTraitCase::new("std::cmp::Ord", "cmp", 2, FN_HEADER, SelfKind::Ref, OutType::Any, true),
2271 // FIXME: default doesn't work
2272 ShouldImplTraitCase::new("std::default::Default", "default", 0, FN_HEADER, SelfKind::No, OutType::Any, true),
2273 ShouldImplTraitCase::new("std::ops::Deref", "deref", 1, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
2274 ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut", 1, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
2275 ShouldImplTraitCase::new("std::ops::Div", "div", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
2276 ShouldImplTraitCase::new("std::ops::Drop", "drop", 1, FN_HEADER, SelfKind::RefMut, OutType::Unit, true),
2277 ShouldImplTraitCase::new("std::cmp::PartialEq", "eq", 2, FN_HEADER, SelfKind::Ref, OutType::Bool, true),
2278 ShouldImplTraitCase::new("std::iter::FromIterator", "from_iter", 1, FN_HEADER, SelfKind::No, OutType::Any, true),
2279 ShouldImplTraitCase::new("std::str::FromStr", "from_str", 1, FN_HEADER, SelfKind::No, OutType::Any, true),
2280 ShouldImplTraitCase::new("std::hash::Hash", "hash", 2, FN_HEADER, SelfKind::Ref, OutType::Unit, true),
2281 ShouldImplTraitCase::new("std::ops::Index", "index", 2, FN_HEADER, SelfKind::Ref, OutType::Ref, true),
2282 ShouldImplTraitCase::new("std::ops::IndexMut", "index_mut", 2, FN_HEADER, SelfKind::RefMut, OutType::Ref, true),
2283 ShouldImplTraitCase::new("std::iter::IntoIterator", "into_iter", 1, FN_HEADER, SelfKind::Value, OutType::Any, true),
2284 ShouldImplTraitCase::new("std::ops::Mul", "mul", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
2285 ShouldImplTraitCase::new("std::ops::Neg", "neg", 1, FN_HEADER, SelfKind::Value, OutType::Any, true),
2286 ShouldImplTraitCase::new("std::iter::Iterator", "next", 1, FN_HEADER, SelfKind::RefMut, OutType::Any, false),
2287 ShouldImplTraitCase::new("std::ops::Not", "not", 1, FN_HEADER, SelfKind::Value, OutType::Any, true),
2288 ShouldImplTraitCase::new("std::ops::Rem", "rem", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
2289 ShouldImplTraitCase::new("std::ops::Shl", "shl", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
2290 ShouldImplTraitCase::new("std::ops::Shr", "shr", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
2291 ShouldImplTraitCase::new("std::ops::Sub", "sub", 2, FN_HEADER, SelfKind::Value, OutType::Any, true),
2292 ];
2293
2294 #[derive(Clone, Copy, PartialEq, Debug)]
2295 enum SelfKind {
2296 Value,
2297 Ref,
2298 RefMut,
2299 No,
2300 }
2301
2302 impl SelfKind {
2303 fn matches<'a>(self, cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
2304 fn matches_value<'a>(cx: &LateContext<'a>, parent_ty: Ty<'_>, ty: Ty<'_>) -> bool {
2305 if ty == parent_ty {
2306 true
2307 } else if ty.is_box() {
2308 ty.boxed_ty() == parent_ty
2309 } else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) {
2310 if let ty::Adt(_, substs) = ty.kind() {
2311 substs.types().next().map_or(false, |t| t == parent_ty)
2312 } else {
2313 false
2314 }
2315 } else {
2316 false
2317 }
2318 }
2319
2320 fn matches_ref<'a>(cx: &LateContext<'a>, mutability: hir::Mutability, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
2321 if let ty::Ref(_, t, m) = *ty.kind() {
2322 return m == mutability && t == parent_ty;
2323 }
2324
2325 let trait_path = match mutability {
2326 hir::Mutability::Not => &paths::ASREF_TRAIT,
2327 hir::Mutability::Mut => &paths::ASMUT_TRAIT,
2328 };
2329
2330 let trait_def_id = match get_trait_def_id(cx, trait_path) {
2331 Some(did) => did,
2332 None => return false,
2333 };
2334 implements_trait(cx, ty, trait_def_id, &[parent_ty.into()])
2335 }
2336
2337 match self {
2338 Self::Value => matches_value(cx, parent_ty, ty),
2339 Self::Ref => matches_ref(cx, hir::Mutability::Not, parent_ty, ty) || ty == parent_ty && is_copy(cx, ty),
2340 Self::RefMut => matches_ref(cx, hir::Mutability::Mut, parent_ty, ty),
2341 Self::No => ty != parent_ty,
2342 }
2343 }
2344
2345 #[must_use]
2346 fn description(self) -> &'static str {
2347 match self {
2348 Self::Value => "`self` by value",
2349 Self::Ref => "`self` by reference",
2350 Self::RefMut => "`self` by mutable reference",
2351 Self::No => "no `self`",
2352 }
2353 }
2354 }
2355
2356 #[derive(Clone, Copy)]
2357 enum OutType {
2358 Unit,
2359 Bool,
2360 Any,
2361 Ref,
2362 }
2363
2364 impl OutType {
2365 fn matches(self, ty: &hir::FnRetTy<'_>) -> bool {
2366 let is_unit = |ty: &hir::Ty<'_>| matches!(ty.kind, hir::TyKind::Tup(&[]));
2367 match (self, ty) {
2368 (Self::Unit, &hir::FnRetTy::DefaultReturn(_)) => true,
2369 (Self::Unit, &hir::FnRetTy::Return(ty)) if is_unit(ty) => true,
2370 (Self::Bool, &hir::FnRetTy::Return(ty)) if is_bool(ty) => true,
2371 (Self::Any, &hir::FnRetTy::Return(ty)) if !is_unit(ty) => true,
2372 (Self::Ref, &hir::FnRetTy::Return(ty)) => matches!(ty.kind, hir::TyKind::Rptr(_, _)),
2373 _ => false,
2374 }
2375 }
2376 }
2377
2378 fn is_bool(ty: &hir::Ty<'_>) -> bool {
2379 if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
2380 matches!(path.res, Res::PrimTy(PrimTy::Bool))
2381 } else {
2382 false
2383 }
2384 }
2385
2386 fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
2387 expected.constness == actual.constness
2388 && expected.unsafety == actual.unsafety
2389 && expected.asyncness == actual.asyncness
2390 }