@@ -3,18 +3,18 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
3
3
use clippy_utils:: { SpanlessEq , SpanlessHash } ;
4
4
use core:: hash:: { Hash , Hasher } ;
5
5
use if_chain:: if_chain;
6
+ use itertools:: Itertools ;
6
7
use rustc_data_structures:: fx:: FxHashMap ;
7
8
use rustc_data_structures:: unhash:: UnhashMap ;
8
9
use rustc_errors:: Applicability ;
9
10
use rustc_hir:: def:: Res ;
10
11
use 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 ,
13
14
} ;
14
15
use rustc_lint:: { LateContext , LateLintPass } ;
15
16
use 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 } ;
18
18
19
19
declare_clippy_lint ! {
20
20
/// ### What it does
@@ -178,30 +178,18 @@ impl TraitBounds {
178
178
) ;
179
179
180
180
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,
184
192
) ;
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( '`' ) ;
205
193
span_lint_and_help(
206
194
cx,
207
195
TYPE_REPETITION_IN_BOUNDS ,
@@ -254,8 +242,17 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
254
242
}
255
243
256
244
fn 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) )
259
256
} else {
260
257
None
261
258
}
0 commit comments