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