|
1 | | -use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_help}; |
2 | | -use clippy_utils::source::{snippet, snippet_with_applicability, snippet_opt}; |
| 1 | +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; |
| 2 | +use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; |
3 | 3 | use clippy_utils::{SpanlessEq, SpanlessHash}; |
4 | 4 | use core::hash::{Hash, Hasher}; |
5 | 5 | use if_chain::if_chain; |
@@ -290,98 +290,60 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { |
290 | 290 | } |
291 | 291 |
|
292 | 292 | fn check_bounds_or_where_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { |
293 | | - if gen.span.from_expansion() { |
294 | | - return; |
295 | | - } |
296 | | - |
297 | | - for param in gen.params { |
| 293 | + fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) { |
298 | 294 | let mut map = FxHashMap::default(); |
299 | 295 | let mut repeated_spans = false; |
300 | | - if let ParamName::Plain(name) = param.name { // other alternatives are errors and elided which won't have duplicates |
301 | | - for bound in param.bounds.iter().filter_map(get_trait_info_from_bound) { |
302 | | - let (definition, _, span_direct) = bound; |
303 | | - if let Some(_) = map.insert(definition, span_direct) { |
304 | | - repeated_spans = true; |
305 | | - } |
| 296 | + for bound in bounds.iter().filter_map(get_trait_info_from_bound) { |
| 297 | + let (definition, _, span_direct) = bound; |
| 298 | + if map.insert(definition, span_direct).is_some() { |
| 299 | + repeated_spans = true; |
306 | 300 | } |
| 301 | + } |
307 | 302 |
|
308 | | - if repeated_spans { |
309 | | - let all_trait_span = param |
310 | | - .bounds |
311 | | - .get(0) |
312 | | - .unwrap() |
313 | | - .span() |
314 | | - .to( |
315 | | - param |
316 | | - .bounds |
317 | | - .iter() |
318 | | - .last() |
319 | | - .unwrap() |
320 | | - .span()); |
| 303 | + if repeated_spans { |
| 304 | + if_chain! { |
| 305 | + if let Some(first_trait) = bounds.get(0); |
| 306 | + if let Some(last_trait) = bounds.iter().last(); |
| 307 | + then { |
| 308 | + let all_trait_span = first_trait.span().to(last_trait.span()); |
321 | 309 |
|
322 | | - let mut traits = map.values() |
323 | | - .filter_map(|span| snippet_opt(cx, *span)) |
324 | | - .collect::<Vec<_>>(); |
325 | | - traits.sort_unstable(); |
326 | | - let traits = traits.join(" + "); |
| 310 | + let mut traits = map.values() |
| 311 | + .filter_map(|span| snippet_opt(cx, *span)) |
| 312 | + .collect::<Vec<_>>(); |
| 313 | + traits.sort_unstable(); |
| 314 | + let traits = traits.join(" + "); |
327 | 315 |
|
328 | | - span_lint_and_sugg( |
329 | | - cx, |
330 | | - REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND, |
331 | | - all_trait_span, |
332 | | - "this trait bound contains repeated elements", |
333 | | - "try", |
334 | | - traits, |
335 | | - Applicability::MachineApplicable |
336 | | - ); |
| 316 | + span_lint_and_sugg( |
| 317 | + cx, |
| 318 | + REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND, |
| 319 | + all_trait_span, |
| 320 | + msg, |
| 321 | + "try", |
| 322 | + traits, |
| 323 | + Applicability::MachineApplicable |
| 324 | + ); |
| 325 | + } |
337 | 326 | } |
338 | 327 | } |
339 | 328 | } |
| 329 | + if gen.span.from_expansion() || (gen.params.is_empty() && gen.where_clause.predicates.is_empty()) { |
| 330 | + return; |
| 331 | + } |
| 332 | + |
| 333 | + for param in gen.params { |
| 334 | + if let ParamName::Plain(_) = param.name { |
| 335 | + // other alternatives are errors and elided which won't have duplicates |
| 336 | + rollup_traits(cx, param.bounds, "this trait bound contains repeated elements"); |
| 337 | + } |
| 338 | + } |
340 | 339 |
|
341 | 340 | for predicate in gen.where_clause.predicates { |
342 | 341 | if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate { |
343 | | - let mut where_clauses = FxHashMap::default(); |
344 | | - let mut repeated_spans = false; |
345 | | - |
346 | | - for (definition, _, span_direct) in bound_predicate |
347 | | - .bounds |
348 | | - .iter() |
349 | | - .filter_map(get_trait_info_from_bound) |
350 | | - { |
351 | | - if let Some(_) = where_clauses.insert(definition, span_direct) { |
352 | | - repeated_spans = true; |
353 | | - } |
354 | | - } |
355 | | - |
356 | | - if repeated_spans { |
357 | | - let all_trait_span = bound_predicate |
358 | | - .bounds |
359 | | - .get(0) |
360 | | - .unwrap() |
361 | | - .span() |
362 | | - .to( |
363 | | - bound_predicate |
364 | | - .bounds |
365 | | - .iter() |
366 | | - .last() |
367 | | - .unwrap() |
368 | | - .span()); |
369 | | - |
370 | | - let mut traits = where_clauses.values() |
371 | | - .filter_map(|span| snippet_opt(cx, *span)) |
372 | | - .collect::<Vec<_>>(); |
373 | | - traits.sort_unstable(); |
374 | | - let traits = traits.join(" + "); |
375 | | - span_lint_and_sugg( |
376 | | - cx, |
377 | | - REPEATED_WHERE_CLAUSE_OR_TRAIT_BOUND, |
378 | | - all_trait_span, |
379 | | - "this where clause has already been specified", |
380 | | - "try", |
381 | | - traits, |
382 | | - Applicability::MachineApplicable |
383 | | - ); |
384 | | - } |
| 342 | + rollup_traits( |
| 343 | + cx, |
| 344 | + bound_predicate.bounds, |
| 345 | + "this where clause contains repeated elements", |
| 346 | + ); |
385 | 347 | } |
386 | 348 | } |
387 | 349 | } |
|
0 commit comments