1
+ use clippy_config:: Conf ;
2
+ use clippy_config:: types:: InherentImplLintScope ;
1
3
use clippy_utils:: diagnostics:: span_lint_and_then;
2
- use clippy_utils:: is_lint_allowed ;
4
+ use clippy_utils:: fulfill_or_allowed ;
3
5
use rustc_data_structures:: fx:: FxHashMap ;
4
- use rustc_hir:: def_id:: LocalDefId ;
6
+ use rustc_hir:: def_id:: { LocalDefId , LocalModDefId } ;
5
7
use rustc_hir:: { Item , ItemKind , Node } ;
6
8
use rustc_lint:: { LateContext , LateLintPass } ;
7
- use rustc_session:: declare_lint_pass ;
8
- use rustc_span:: Span ;
9
+ use rustc_session:: impl_lint_pass ;
10
+ use rustc_span:: { FileName , Span } ;
9
11
use std:: collections:: hash_map:: Entry ;
10
12
11
13
declare_clippy_lint ! {
12
14
/// ### What it does
13
15
/// Checks for multiple inherent implementations of a struct
14
16
///
17
+ /// The config option controls the scope in which multiple inherent `impl` blocks for the same
18
+ /// struct are linted, allowing values of `module` (only within the same module), `file`
19
+ /// (within the same file), or `crate` (anywhere in the crate, default).
20
+ ///
15
21
/// ### Why restrict this?
16
22
/// Splitting the implementation of a type makes the code harder to navigate.
17
23
///
@@ -41,7 +47,26 @@ declare_clippy_lint! {
41
47
"Multiple inherent impl that could be grouped"
42
48
}
43
49
44
- declare_lint_pass ! ( MultipleInherentImpl => [ MULTIPLE_INHERENT_IMPL ] ) ;
50
+ impl_lint_pass ! ( MultipleInherentImpl => [ MULTIPLE_INHERENT_IMPL ] ) ;
51
+
52
+ pub struct MultipleInherentImpl {
53
+ scope : InherentImplLintScope ,
54
+ }
55
+
56
+ impl MultipleInherentImpl {
57
+ pub fn new ( conf : & ' static Conf ) -> Self {
58
+ Self {
59
+ scope : conf. inherent_impl_lint_scope ,
60
+ }
61
+ }
62
+ }
63
+
64
+ #[ derive( Hash , Eq , PartialEq , Clone ) ]
65
+ enum Criterion {
66
+ Module ( LocalModDefId ) ,
67
+ File ( FileName ) ,
68
+ Crate ,
69
+ }
45
70
46
71
impl < ' tcx > LateLintPass < ' tcx > for MultipleInherentImpl {
47
72
fn check_crate_post ( & mut self , cx : & LateContext < ' tcx > ) {
@@ -56,17 +81,26 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
56
81
for ( & id, impl_ids) in & impls. inherent_impls {
57
82
if impl_ids. len ( ) < 2
58
83
// Check for `#[allow]` on the type definition
59
- || is_lint_allowed (
84
+ || fulfill_or_allowed (
60
85
cx,
61
86
MULTIPLE_INHERENT_IMPL ,
62
- cx. tcx . local_def_id_to_hir_id ( id) ,
87
+ [ cx. tcx . local_def_id_to_hir_id ( id) ] ,
63
88
) {
64
89
continue ;
65
90
}
66
91
67
92
for impl_id in impl_ids. iter ( ) . map ( |id| id. expect_local ( ) ) {
68
93
let impl_ty = cx. tcx . type_of ( impl_id) . instantiate_identity ( ) ;
69
- match type_map. entry ( impl_ty) {
94
+ let hir_id = cx. tcx . local_def_id_to_hir_id ( impl_id) ;
95
+ let criterion = match self . scope {
96
+ InherentImplLintScope :: Module => Criterion :: Module ( cx. tcx . parent_module ( hir_id) ) ,
97
+ InherentImplLintScope :: File => {
98
+ let span = cx. tcx . hir_span ( hir_id) ;
99
+ Criterion :: File ( cx. tcx . sess . source_map ( ) . lookup_source_file ( span. lo ( ) ) . name . clone ( ) )
100
+ } ,
101
+ InherentImplLintScope :: Crate => Criterion :: Crate ,
102
+ } ;
103
+ match type_map. entry ( ( impl_ty, criterion) ) {
70
104
Entry :: Vacant ( e) => {
71
105
// Store the id for the first impl block of this type. The span is retrieved lazily.
72
106
e. insert ( IdOrSpan :: Id ( impl_id) ) ;
@@ -97,7 +131,6 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
97
131
// Switching to the next type definition, no need to keep the current entries around.
98
132
type_map. clear ( ) ;
99
133
}
100
-
101
134
// `TyCtxt::crate_inherent_impls` doesn't have a defined order. Sort the lint output first.
102
135
lint_spans. sort_by_key ( |x| x. 0 . lo ( ) ) ;
103
136
for ( span, first_span) in lint_spans {
@@ -125,7 +158,7 @@ fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option<Span> {
125
158
{
126
159
( !span. from_expansion ( )
127
160
&& impl_item. generics . params . is_empty ( )
128
- && !is_lint_allowed ( cx, MULTIPLE_INHERENT_IMPL , id ) )
161
+ && !fulfill_or_allowed ( cx, MULTIPLE_INHERENT_IMPL , [ id ] ) )
129
162
. then_some ( span)
130
163
} else {
131
164
None
0 commit comments