@@ -48,7 +48,10 @@ declare_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]);
4848
4949impl < ' tcx > LateLintPass < ' tcx > for MultipleInherentImpl {
5050 fn check_crate_post ( & mut self , cx : & LateContext < ' tcx > , _: & ' tcx Crate < ' _ > ) {
51+ // Map from a type to it's first impl block. Needed to distinguish generic arguments.
52+ // e.g. `Foo<Bar>` and `Foo<Baz>`
5153 let mut type_map = FxHashMap :: default ( ) ;
54+ // List of spans to lint. (lint_span, first_span)
5255 let mut lint_spans = Vec :: new ( ) ;
5356
5457 for ( _, impl_ids) in cx
@@ -58,6 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
5861 . iter ( )
5962 . filter ( |( id, impls) | {
6063 impls. len ( ) > 1
64+ // Check for `#[allow]` on the type definition
6165 && !is_allowed (
6266 cx,
6367 MULTIPLE_INHERENT_IMPL ,
@@ -68,23 +72,38 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
6872 for impl_id in impl_ids. iter ( ) . map ( |id| id. expect_local ( ) ) {
6973 match type_map. entry ( cx. tcx . type_of ( impl_id) ) {
7074 Entry :: Vacant ( e) => {
75+ // Store the id for the first impl block of this type. The span is retrieved lazily.
7176 e. insert ( IdOrSpan :: Id ( impl_id) ) ;
7277 } ,
7378 Entry :: Occupied ( mut e) => {
7479 if let Some ( span) = get_impl_span ( cx, impl_id) {
75- if let Some ( first_span) = e. get_mut ( ) . as_span ( cx) {
76- lint_spans. push ( ( span, first_span) ) ;
77- } else {
78- * e. get_mut ( ) = IdOrSpan :: Span ( span) ;
79- }
80+ let first_span = match * e. get ( ) {
81+ IdOrSpan :: Span ( s) => s,
82+ IdOrSpan :: Id ( id) => match get_impl_span ( cx, id) {
83+ Some ( s) => {
84+ // Remember the span of the first block.
85+ * e. get_mut ( ) = IdOrSpan :: Span ( s) ;
86+ s
87+ } ,
88+ None => {
89+ // The first impl block isn't considered by the lint. Replace it with the
90+ // current one.
91+ * e. get_mut ( ) = IdOrSpan :: Span ( span) ;
92+ continue ;
93+ } ,
94+ } ,
95+ } ;
96+ lint_spans. push ( ( span, first_span) ) ;
8097 }
8198 } ,
8299 }
83100 }
84101
102+ // Switching to the next type definition, no need to keep the current entries around.
85103 type_map. clear ( ) ;
86104 }
87105
106+ // `TyCtxt::crate_inherent_impls` doesn't have a defined order. Sort the lint output first.
88107 lint_spans. sort_by_key ( |x| x. 0 . lo ( ) ) ;
89108 for ( span, first_span) in lint_spans {
90109 span_lint_and_note (
@@ -99,6 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
99118 }
100119}
101120
121+ /// Gets the span for the given impl block unless it's not being considered by the lint.
102122fn get_impl_span ( cx : & LateContext < ' _ > , id : LocalDefId ) -> Option < Span > {
103123 let id = cx. tcx . hir ( ) . local_def_id_to_hir_id ( id) ;
104124 if let Node :: Item ( & Item {
@@ -118,14 +138,3 @@ enum IdOrSpan {
118138 Id ( LocalDefId ) ,
119139 Span ( Span ) ,
120140}
121- impl IdOrSpan {
122- fn as_span ( & mut self , cx : & LateContext < ' _ > ) -> Option < Span > {
123- match * self {
124- Self :: Id ( id) => get_impl_span ( cx, id) . map ( |span| {
125- * self = Self :: Span ( span) ;
126- span
127- } ) ,
128- Self :: Span ( span) => Some ( span) ,
129- }
130- }
131- }
0 commit comments