@@ -3,18 +3,18 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
33use clippy_utils:: { SpanlessEq , SpanlessHash } ;
44use core:: hash:: { Hash , Hasher } ;
55use if_chain:: if_chain;
6+ use itertools:: Itertools ;
67use rustc_data_structures:: fx:: FxHashMap ;
78use rustc_data_structures:: unhash:: UnhashMap ;
89use rustc_errors:: Applicability ;
910use rustc_hir:: def:: Res ;
1011use rustc_hir:: {
11- GenericBound , Generics , Item , ItemKind , Node , Path , PathSegment , PredicateOrigin , QPath , TraitItem , Ty , TyKind ,
12- WherePredicate ,
12+ GenericBound , Generics , Item , ItemKind , Node , Path , PathSegment , PredicateOrigin , QPath , TraitBoundModifier ,
13+ TraitItem , Ty , TyKind , WherePredicate ,
1314} ;
1415use rustc_lint:: { LateContext , LateLintPass } ;
1516use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
16- use rustc_span:: Span ;
17- use std:: fmt:: Write as _;
17+ use rustc_span:: { BytePos , Span } ;
1818
1919declare_clippy_lint ! {
2020 /// ### What it does
@@ -178,30 +178,18 @@ impl TraitBounds {
178178 ) ;
179179
180180 then {
181- let mut hint_string = format!(
182- "consider combining the bounds: `{}:" ,
183- snippet( cx, p. bounded_ty. span, "_" )
181+ let trait_bounds = v
182+ . iter( )
183+ . copied( )
184+ . chain( p. bounds. iter( ) )
185+ . filter_map( get_trait_info_from_bound)
186+ . map( |( _, _, span) | snippet_with_applicability( cx, span, ".." , & mut applicability) )
187+ . join( " + " ) ;
188+ let hint_string = format!(
189+ "consider combining the bounds: `{}: {}`" ,
190+ snippet( cx, p. bounded_ty. span, "_" ) ,
191+ trait_bounds,
184192 ) ;
185- for b in v. iter( ) {
186- if let GenericBound :: Trait ( ref poly_trait_ref, _) = b {
187- let path = & poly_trait_ref. trait_ref. path;
188- let _ = write!( hint_string,
189- " {} +" ,
190- snippet_with_applicability( cx, path. span, ".." , & mut applicability)
191- ) ;
192- }
193- }
194- for b in p. bounds. iter( ) {
195- if let GenericBound :: Trait ( ref poly_trait_ref, _) = b {
196- let path = & poly_trait_ref. trait_ref. path;
197- let _ = write!( hint_string,
198- " {} +" ,
199- snippet_with_applicability( cx, path. span, ".." , & mut applicability)
200- ) ;
201- }
202- }
203- hint_string. truncate( hint_string. len( ) - 2 ) ;
204- hint_string. push( '`' ) ;
205193 span_lint_and_help(
206194 cx,
207195 TYPE_REPETITION_IN_BOUNDS ,
@@ -254,8 +242,17 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
254242}
255243
256244fn get_trait_info_from_bound < ' a > ( bound : & ' a GenericBound < ' _ > ) -> Option < ( Res , & ' a [ PathSegment < ' a > ] , Span ) > {
257- if let GenericBound :: Trait ( t, _) = bound {
258- Some ( ( t. trait_ref . path . res , t. trait_ref . path . segments , t. span ) )
245+ if let GenericBound :: Trait ( t, tbm) = bound {
246+ let trait_path = t. trait_ref . path ;
247+ let trait_span = {
248+ let path_span = trait_path. span ;
249+ if let TraitBoundModifier :: Maybe = tbm {
250+ path_span. with_lo ( path_span. lo ( ) - BytePos ( 1 ) ) // include the `?`
251+ } else {
252+ path_span
253+ }
254+ } ;
255+ Some ( ( trait_path. res , trait_path. segments , trait_span) )
259256 } else {
260257 None
261258 }
0 commit comments