]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/trait_bounds.rs
Auto merge of #4372 - phansch:changelog_update, r=flip1995
[rust.git] / clippy_lints / src / trait_bounds.rs
1 use crate::utils::{in_macro, snippet, span_help_and_lint, SpanlessHash};
2 use rustc::hir::*;
3 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
4 use rustc::{declare_tool_lint, impl_lint_pass};
5 use rustc_data_structures::fx::FxHashMap;
6
7 #[derive(Copy, Clone)]
8 pub struct TraitBounds;
9
10 declare_clippy_lint! {
11     /// **What it does:** This lint warns about unnecessary type repetitions in trait bounds
12     ///
13     /// **Why is this bad?** Repeating the type for every bound makes the code
14     /// less readable than combining the bounds
15     ///
16     /// **Example:**
17     /// ```rust
18     /// pub fn foo<T>(t: T) where T: Copy, T: Clone {}
19     /// ```
20     ///
21     /// Could be written as:
22     ///
23     /// ```rust
24     /// pub fn foo<T>(t: T) where T: Copy + Clone {}
25     /// ```
26     pub TYPE_REPETITION_IN_BOUNDS,
27     pedantic,
28     "Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`"
29 }
30
31 impl_lint_pass!(TraitBounds => [TYPE_REPETITION_IN_BOUNDS]);
32
33 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TraitBounds {
34     fn check_generics(&mut self, cx: &LateContext<'a, 'tcx>, gen: &'tcx Generics) {
35         if in_macro(gen.span) {
36             return;
37         }
38         let hash = |ty| -> u64 {
39             let mut hasher = SpanlessHash::new(cx, cx.tables);
40             hasher.hash_ty(ty);
41             hasher.finish()
42         };
43         let mut map = FxHashMap::default();
44         for bound in &gen.where_clause.predicates {
45             if let WherePredicate::BoundPredicate(ref p) = bound {
46                 let h = hash(&p.bounded_ty);
47                 if let Some(ref v) = map.insert(h, p.bounds.iter().collect::<Vec<_>>()) {
48                     let mut hint_string = format!(
49                         "consider combining the bounds: `{}:",
50                         snippet(cx, p.bounded_ty.span, "_")
51                     );
52                     for b in v.iter() {
53                         if let GenericBound::Trait(ref poly_trait_ref, _) = b {
54                             let path = &poly_trait_ref.trait_ref.path;
55                             hint_string.push_str(&format!(" {} +", path));
56                         }
57                     }
58                     for b in p.bounds.iter() {
59                         if let GenericBound::Trait(ref poly_trait_ref, _) = b {
60                             let path = &poly_trait_ref.trait_ref.path;
61                             hint_string.push_str(&format!(" {} +", path));
62                         }
63                     }
64                     hint_string.truncate(hint_string.len() - 2);
65                     hint_string.push('`');
66                     span_help_and_lint(
67                         cx,
68                         TYPE_REPETITION_IN_BOUNDS,
69                         p.span,
70                         "this type has already been used as a bound predicate",
71                         &hint_string,
72                     );
73                 }
74             }
75         }
76     }
77 }