+
+fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
+ if gen.span.from_expansion() || gen.params.is_empty() || gen.where_clause.predicates.is_empty() {
+ return;
+ }
+
+ let mut map = FxHashMap::default();
+ for param in gen.params {
+ if let ParamName::Plain(ref ident) = param.name {
+ let res = param
+ .bounds
+ .iter()
+ .filter_map(get_trait_res_span_from_bound)
+ .collect::<Vec<_>>();
+ map.insert(*ident, res);
+ }
+ }
+
+ for predicate in gen.where_clause.predicates {
+ if_chain! {
+ if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
+ if !bound_predicate.span.from_expansion();
+ if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
+ if let Some(segment) = segments.first();
+ if let Some(trait_resolutions_direct) = map.get(&segment.ident);
+ then {
+ for (res_where, _) in bound_predicate.bounds.iter().filter_map(get_trait_res_span_from_bound) {
+ if let Some((_, span_direct)) = trait_resolutions_direct
+ .iter()
+ .find(|(res_direct, _)| *res_direct == res_where) {
+ span_lint_and_help(
+ cx,
+ TRAIT_DUPLICATION_IN_BOUNDS,
+ *span_direct,
+ "this trait bound is already specified in the where clause",
+ None,
+ "consider removing this trait bound",
+ );
+ }
+ }
+ }
+ }
+ }
+}