Skip to content

Commit 57d488a

Browse files
committed
multiple_inherent_impl code cleanup
1 parent d693380 commit 57d488a

File tree

1 file changed

+25
-16
lines changed

1 file changed

+25
-16
lines changed

clippy_lints/src/inherent_impl.rs

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ declare_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]);
4848

4949
impl<'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.
102122
fn 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

Comments
 (0)