]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/inherent_impl.rs
Add license header to Rust files
[rust.git] / clippy_lints / src / inherent_impl.rs
1 // Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9
10
11 //! lint on inherent implementations
12
13 use crate::rustc::hir::*;
14 use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
15 use crate::rustc::{declare_tool_lint, lint_array};
16 use crate::rustc_data_structures::fx::FxHashMap;
17 use std::default::Default;
18 use crate::syntax_pos::Span;
19 use crate::utils::span_lint_and_then;
20
21 /// **What it does:** Checks for multiple inherent implementations of a struct
22 ///
23 /// **Why is this bad?** Splitting the implementation of a type makes the code harder to navigate.
24 ///
25 /// **Known problems:** None.
26 ///
27 /// **Example:**
28 /// ```rust
29 /// struct X;
30 /// impl X {
31 ///     fn one() {}
32 /// }
33 /// impl X {
34 ///     fn other() {}
35 /// }
36 /// ```
37 ///
38 /// Could be written:
39 ///
40 /// ```rust
41 /// struct X;
42 /// impl X {
43 ///     fn one() {}
44 ///     fn other() {}
45 /// }
46 /// ```
47 declare_clippy_lint! {
48     pub MULTIPLE_INHERENT_IMPL,
49     restriction,
50     "Multiple inherent impl that could be grouped"
51 }
52
53 pub struct Pass {
54     impls: FxHashMap<def_id::DefId, (Span, Generics)>,
55 }
56
57 impl Default for Pass {
58     fn default() -> Self {
59         Self { impls: FxHashMap::default() }
60     }
61 }
62
63 impl LintPass for Pass {
64     fn get_lints(&self) -> LintArray {
65         lint_array!(MULTIPLE_INHERENT_IMPL)
66     }
67 }
68
69 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
70     fn check_item(&mut self, _: &LateContext<'a, 'tcx>, item: &'tcx Item) {
71         if let ItemKind::Impl(_, _, _, ref generics, None, _, _) = item.node {
72             // Remember for each inherent implementation encoutered its span and generics
73             self.impls
74                 .insert(item.hir_id.owner_def_id(), (item.span, generics.clone()));
75         }
76     }
77
78     fn check_crate_post(&mut self, cx: &LateContext<'a, 'tcx>, krate: &'tcx Crate) {
79         if let Some(item) = krate.items.values().nth(0) {
80             // Retrieve all inherent implementations from the crate, grouped by type
81             for impls in cx
82                 .tcx
83                 .crate_inherent_impls(item.hir_id.owner_def_id().krate)
84                 .inherent_impls
85                 .values()
86             {
87                 // Filter out implementations that have generic params (type or lifetime)
88                 let mut impl_spans = impls
89                     .iter()
90                     .filter_map(|impl_def| self.impls.get(impl_def))
91                     .filter_map(|(span, generics)| if generics.params.len() == 0 {
92                         Some(span)
93                     } else {
94                         None
95                     });
96                 if let Some(initial_span) = impl_spans.nth(0) {
97                     impl_spans.for_each(|additional_span| {
98                         span_lint_and_then(
99                             cx,
100                             MULTIPLE_INHERENT_IMPL,
101                             *additional_span,
102                             "Multiple implementations of this structure",
103                             |db| {
104                                 db.span_note(
105                                     *initial_span,
106                                     "First implementation here",
107                                 );
108                             },
109                         )
110                     })
111                 }
112             }
113         }
114     }
115 }