1- use crate :: utils:: span_lint_and_sugg ;
2- use crate :: utils:: { snippet , snippet_opt} ;
1+ use crate :: utils:: span_lint_and_then ;
2+ use crate :: utils:: snippet_opt;
33use if_chain:: if_chain;
44use rustc_errors:: Applicability ;
5- use rustc_hir:: { GenericBound , GenericBounds , WherePredicate } ;
5+ use rustc_hir:: { GenericBound , WherePredicate } ;
66use rustc_lint:: { LateContext , LateLintPass } ;
77use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
88use rustc_span:: symbol:: sym;
9- use std:: borrow:: Cow ;
109
1110declare_clippy_lint ! {
1211 /// **What it does:** Checking for using of From or TryFrom trait as a generic bound.
@@ -51,42 +50,6 @@ impl LateLintPass<'tcx> for FromInsteadOfInto {
5150 }
5251 }
5352
54- fn get_reduced_bounds_str (
55- cx : & LateContext < ' tcx > ,
56- position : usize ,
57- bounds : GenericBounds < ' tcx > ,
58- ) -> Cow < ' tcx , str > {
59- let before;
60- if position == 0 {
61- before = None ;
62- } else {
63- let first_bound = & bounds[ 0 ] ;
64- let previous_bound = & bounds[ position - 1 ] ;
65- before = Some ( snippet (
66- cx,
67- first_bound. span ( ) . with_hi ( previous_bound. span ( ) . hi ( ) ) ,
68- ".." ,
69- ) ) ;
70- }
71-
72- let after;
73- let last_position = bounds. len ( ) - 1 ;
74- if position == last_position {
75- after = None ;
76- } else {
77- let last_bound = & bounds[ last_position] ;
78- let after_bound = & bounds[ position + 1 ] ;
79- after = Some ( snippet ( cx, after_bound. span ( ) . with_hi ( last_bound. span ( ) . hi ( ) ) , ".." ) ) ;
80- }
81-
82- match ( before, after) {
83- ( None , None ) => unreachable ! ( ) ,
84- ( Some ( b) , None ) => b,
85- ( None , Some ( a) ) => a,
86- ( Some ( b) , Some ( a) ) => b + " + " + a,
87- }
88- }
89-
9053 if let WherePredicate :: BoundPredicate ( wbp) = wp {
9154 if_chain ! {
9255 let bounds = wbp. bounds;
@@ -108,31 +71,47 @@ impl LateLintPass<'tcx> for FromInsteadOfInto {
10871 replace_trait_name = "TryInto" ;
10972 target_trait_name = "TryFrom" ;
11073 } else {
111- replace_trait_name = "" ;
112- target_trait_name = "" ;
74+ return ;
11375 }
76+ let message = format!( "{} trait is preferable than {} as a generic bound" , replace_trait_name, target_trait_name) ;
77+ let switched_predicate = format!( "{}: {}<{}>" , generic_arg_of_from_or_try_from, replace_trait_name, bounded_ty) ;
11478
115- if !replace_trait_name. is_empty( ) && !target_trait_name. is_empty( ) {
116- let message = format!( "{} trait is preferable than {} as a generic bound" , replace_trait_name, target_trait_name) ;
79+ let low;
80+ if position == 0 {
81+ low = wp. span( ) . lo( ) ;
82+ } else {
83+ let previous_bound = & bounds[ position -1 ] ;
84+ low = previous_bound. span( ) . hi( ) ;
85+ }
86+ let removed_span = target_bound. span( ) . with_lo( low) ;
11787
118- let extracted_where_predicate = format!( "{}: {}<{}>" , generic_arg_of_from_or_try_from, replace_trait_name, bounded_ty) ;
119- let sugg;
120- if bounds. len( ) == 1 {
121- sugg = extracted_where_predicate;
122- } else {
123- let bounds = get_reduced_bounds_str( cx, position, bounds) ;
124- sugg = format!( "{}, {}: {}" , extracted_where_predicate, bounded_ty, bounds) ;
88+ span_lint_and_then(
89+ cx,
90+ FROM_INSTEAD_OF_INTO ,
91+ wp. span( ) ,
92+ & message,
93+ |diag| {
94+ diag. span_suggestion(
95+ removed_span,
96+ & format!( "remove {} bound" , target_trait_name) ,
97+ "" . to_string( ) ,
98+ Applicability :: MaybeIncorrect ,
99+ ) ;
100+
101+ let sugg;
102+ if bounds. len( ) == 1 {
103+ sugg = switched_predicate;
104+ } else {
105+ sugg = format!( ", {}" , switched_predicate) ;
106+ }
107+ diag. span_suggestion(
108+ wp. span( ) . with_lo( wp. span( ) . hi( ) ) ,
109+ "Add this bound predicate" ,
110+ sugg,
111+ Applicability :: MaybeIncorrect ,
112+ ) ;
125113 }
126- span_lint_and_sugg(
127- cx,
128- FROM_INSTEAD_OF_INTO ,
129- wp. span( ) ,
130- & message,
131- "try" ,
132- sugg,
133- Applicability :: MaybeIncorrect
134- ) ;
135- }
114+ ) ;
136115 }
137116 }
138117 }
0 commit comments