Skip to content

Commit 32e2511

Browse files
committed
extract lint emitting into separate fn
1 parent 7262145 commit 32e2511

File tree

1 file changed

+96
-74
lines changed

1 file changed

+96
-74
lines changed

clippy_lints/src/implied_bounds_in_impls.rs

Lines changed: 96 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,93 @@ declare_clippy_lint! {
5050
}
5151
declare_lint_pass!(ImpliedBoundsInImpls => [IMPLIED_BOUNDS_IN_IMPLS]);
5252

53+
#[allow(clippy::too_many_arguments)]
54+
fn emit_lint(
55+
cx: &LateContext<'_>,
56+
poly_trait: &rustc_hir::PolyTraitRef<'_>,
57+
opaque_ty: &rustc_hir::OpaqueTy<'_>,
58+
index: usize,
59+
implied_bindings: &[rustc_hir::TypeBinding<'_>],
60+
implied_by_bindings: &[rustc_hir::TypeBinding<'_>],
61+
implied_by_args: &[GenericArg<'_>],
62+
implied_by_span: Span,
63+
) {
64+
let implied_by = snippet(cx, implied_by_span, "..");
65+
66+
span_lint_and_then(
67+
cx,
68+
IMPLIED_BOUNDS_IN_IMPLS,
69+
poly_trait.span,
70+
&format!("this bound is already specified as the supertrait of `{implied_by}`"),
71+
|diag| {
72+
// If we suggest removing a bound, we may also need extend the span
73+
// to include the `+` token that is ahead or behind,
74+
// so we don't end up with something like `impl + B` or `impl A + `
75+
76+
let implied_span_extended = if let Some(next_bound) = opaque_ty.bounds.get(index + 1) {
77+
poly_trait.span.to(next_bound.span().shrink_to_lo())
78+
} else if index > 0
79+
&& let Some(prev_bound) = opaque_ty.bounds.get(index - 1)
80+
{
81+
prev_bound.span().shrink_to_hi().to(poly_trait.span.shrink_to_hi())
82+
} else {
83+
poly_trait.span
84+
};
85+
86+
let mut sugg = vec![(implied_span_extended, String::new())];
87+
88+
// We also might need to include associated type binding that were specified in the implied bound,
89+
// but omitted in the implied-by bound:
90+
// `fn f() -> impl Deref<Target = u8> + DerefMut`
91+
// If we're going to suggest removing `Deref<..>`, we'll need to put `<Target = u8>` on `DerefMut`
92+
let omitted_assoc_tys: Vec<_> = implied_bindings
93+
.iter()
94+
.filter(|binding| !implied_by_bindings.iter().any(|b| b.ident == binding.ident))
95+
.collect();
96+
97+
if !omitted_assoc_tys.is_empty() {
98+
// `<>` needs to be added if there aren't yet any generic arguments or bindings
99+
let needs_angle_brackets = implied_by_args.is_empty() && implied_by_bindings.is_empty();
100+
let insert_span = match (implied_by_args, implied_by_bindings) {
101+
([.., arg], [.., binding]) => arg.span().max(binding.span).shrink_to_hi(),
102+
([.., arg], []) => arg.span().shrink_to_hi(),
103+
([], [.., binding]) => binding.span.shrink_to_hi(),
104+
([], []) => implied_by_span.shrink_to_hi(),
105+
};
106+
107+
let mut associated_tys_sugg = if needs_angle_brackets {
108+
"<".to_owned()
109+
} else {
110+
// If angle brackets aren't needed (i.e., there are already generic arguments or bindings),
111+
// we need to add a comma:
112+
// `impl A<B, C >`
113+
// ^ if we insert `Assoc=i32` without a comma here, that'd be invalid syntax:
114+
// `impl A<B, C Assoc=i32>`
115+
", ".to_owned()
116+
};
117+
118+
for (index, binding) in omitted_assoc_tys.into_iter().enumerate() {
119+
if index > 0 {
120+
associated_tys_sugg += ", ";
121+
}
122+
associated_tys_sugg += &snippet(cx, binding.span, "..");
123+
}
124+
if needs_angle_brackets {
125+
associated_tys_sugg += ">";
126+
}
127+
sugg.push((insert_span, associated_tys_sugg));
128+
}
129+
130+
diag.multipart_suggestion_with_style(
131+
"try removing this bound",
132+
sugg,
133+
Applicability::MachineApplicable,
134+
SuggestionStyle::ShowAlways,
135+
);
136+
},
137+
);
138+
}
139+
53140
/// Tries to "resolve" a type.
54141
/// The index passed to this function must start with `Self=0`, i.e. it must be a valid
55142
/// type parameter index.
@@ -189,80 +276,15 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
189276
})
190277
})
191278
{
192-
let implied_by = snippet(cx, implied_by_span, "..");
193-
span_lint_and_then(
194-
cx, IMPLIED_BOUNDS_IN_IMPLS,
195-
poly_trait.span,
196-
&format!("this bound is already specified as the supertrait of `{implied_by}`"),
197-
|diag| {
198-
// If we suggest removing a bound, we may also need extend the span
199-
// to include the `+` token that is ahead or behind,
200-
// so we don't end up with something like `impl + B` or `impl A + `
201-
202-
let implied_span_extended = if let Some(next_bound) = opaque_ty.bounds.get(index + 1) {
203-
poly_trait.span.to(next_bound.span().shrink_to_lo())
204-
} else if index > 0
205-
&& let Some(prev_bound) = opaque_ty.bounds.get(index - 1)
206-
{
207-
prev_bound.span().shrink_to_hi().to(poly_trait.span.shrink_to_hi())
208-
} else {
209-
poly_trait.span
210-
};
211-
212-
let mut sugg = vec![
213-
(implied_span_extended, String::new()),
214-
];
215-
216-
// We also might need to include associated type binding that were specified in the implied bound,
217-
// but omitted in the implied-by bound:
218-
// `fn f() -> impl Deref<Target = u8> + DerefMut`
219-
// If we're going to suggest removing `Deref<..>`, we'll need to put `<Target = u8>` on `DerefMut`
220-
let omitted_assoc_tys: Vec<_> = implied_bindings
221-
.iter()
222-
.filter(|binding| {
223-
implied_by_bindings
224-
.iter()
225-
// TODO: is checking idents enough for stuff like `<Target: Sized> == <Target = u8>`
226-
.find(|b| b.ident == binding.ident)
227-
.is_none()
228-
})
229-
.collect();
230-
231-
if !omitted_assoc_tys.is_empty() {
232-
// `<>` needs to be added if there aren't yet any generic arguments or bindings
233-
let needs_angle_brackets = implied_by_args.is_empty() && implied_by_bindings.is_empty();
234-
let insert_span = match (implied_by_args, implied_by_bindings) {
235-
([.., arg], [.., binding]) => arg.span().max(binding.span).shrink_to_hi(),
236-
([.., arg], []) => arg.span().shrink_to_hi(),
237-
([], [.., binding]) => binding.span.shrink_to_hi(),
238-
([], []) => implied_by_span.shrink_to_hi(),
239-
};
240-
241-
let mut associated_tys_sugg = if needs_angle_brackets {
242-
"<".to_owned()
243-
} else {
244-
// If angle brackets aren't needed (i.e., there are already generic arguments or bindings),
245-
// we need to add a comma:
246-
// `impl A<B, C >`
247-
// ^ if we insert `Assoc=i32` without a comma here, that'd be invalid syntax:
248-
// `impl A<B, C Assoc=i32>`
249-
", ".to_owned()
250-
};
251-
252-
for (index, binding) in omitted_assoc_tys.into_iter().enumerate() {
253-
if index > 0 {
254-
associated_tys_sugg += ", ";
255-
}
256-
associated_tys_sugg += &snippet(cx, binding.span, "..");
257-
}
258-
if needs_angle_brackets {
259-
associated_tys_sugg += ">";
260-
}
261-
sugg.push((insert_span, associated_tys_sugg));
262-
}
263-
264-
diag.multipart_suggestion_with_style("try removing this bound", sugg, Applicability::MachineApplicable, SuggestionStyle::ShowAlways);
265-
}
279+
emit_lint(
280+
cx,
281+
poly_trait,
282+
opaque_ty,
283+
index,
284+
implied_bindings,
285+
implied_by_bindings,
286+
implied_by_args,
287+
implied_by_span
266288
);
267289
}
268290
}

0 commit comments

Comments
 (0)