1+ use clippy_config:: Conf ;
2+ use clippy_config:: types:: InherentImplLintScope ;
13use clippy_utils:: diagnostics:: span_lint_and_then;
2- use clippy_utils:: is_lint_allowed ;
4+ use clippy_utils:: fulfill_or_allowed ;
35use rustc_data_structures:: fx:: FxHashMap ;
4- use rustc_hir:: def_id:: LocalDefId ;
6+ use rustc_hir:: def_id:: { LocalDefId , LocalModDefId } ;
57use rustc_hir:: { Item , ItemKind , Node } ;
68use 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 } ;
911use std:: collections:: hash_map:: Entry ;
1012
1113declare_clippy_lint ! {
1214 /// ### What it does
1315 /// Checks for multiple inherent implementations of a struct
1416 ///
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+ ///
1521 /// ### Why restrict this?
1622 /// Splitting the implementation of a type makes the code harder to navigate.
1723 ///
@@ -41,7 +47,26 @@ declare_clippy_lint! {
4147 "Multiple inherent impl that could be grouped"
4248}
4349
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+ }
4570
4671impl < ' tcx > LateLintPass < ' tcx > for MultipleInherentImpl {
4772 fn check_crate_post ( & mut self , cx : & LateContext < ' tcx > ) {
@@ -55,18 +80,27 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
5580
5681 for ( & id, impl_ids) in & impls. inherent_impls {
5782 if impl_ids. len ( ) < 2
58- // Check for `#[allow]` on the type definition
59- || is_lint_allowed (
83+ // Check for `#[expect]` or `#[ allow]` on the type definition
84+ || fulfill_or_allowed (
6085 cx,
6186 MULTIPLE_INHERENT_IMPL ,
62- cx. tcx . local_def_id_to_hir_id ( id) ,
87+ [ cx. tcx . local_def_id_to_hir_id ( id) ] ,
6388 ) {
6489 continue ;
6590 }
6691
6792 for impl_id in impl_ids. iter ( ) . map ( |id| id. expect_local ( ) ) {
6893 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) ) {
70104 Entry :: Vacant ( e) => {
71105 // Store the id for the first impl block of this type. The span is retrieved lazily.
72106 e. insert ( IdOrSpan :: Id ( impl_id) ) ;
@@ -97,7 +131,6 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
97131 // Switching to the next type definition, no need to keep the current entries around.
98132 type_map. clear ( ) ;
99133 }
100-
101134 // `TyCtxt::crate_inherent_impls` doesn't have a defined order. Sort the lint output first.
102135 lint_spans. sort_by_key ( |x| x. 0 . lo ( ) ) ;
103136 for ( span, first_span) in lint_spans {
@@ -125,7 +158,7 @@ fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option<Span> {
125158 {
126159 ( !span. from_expansion ( )
127160 && impl_item. generics . params . is_empty ( )
128- && !is_lint_allowed ( cx, MULTIPLE_INHERENT_IMPL , id ) )
161+ && !fulfill_or_allowed ( cx, MULTIPLE_INHERENT_IMPL , [ id ] ) )
129162 . then_some ( span)
130163 } else {
131164 None
0 commit comments