@@ -10,17 +10,64 @@ use rustc_span::{sym, Span};
1010
1111use super :: UNNECESSARY_FALLIBLE_CONVERSIONS ;
1212
13+ #[ derive( Copy , Clone ) ]
14+ enum SpansKind {
15+ TraitFn { trait_span : Span , fn_span : Span } ,
16+ Fn { fn_span : Span } ,
17+ }
18+
1319/// What function is being called and whether that call is written as a method call or a function
1420/// call
15- #[ derive( Clone ) ]
21+ #[ derive( Copy , Clone ) ]
1622#[ expect( clippy:: enum_variant_names) ]
1723enum FunctionKind {
1824 /// `T::try_from(U)`
19- TryFromFunction ( Option < Vec < Span > > ) ,
25+ TryFromFunction ( Option < SpansKind > ) ,
2026 /// `t.try_into()`
2127 TryIntoMethod ,
2228 /// `U::try_into(t)`
23- TryIntoFunction ( Option < Vec < Span > > ) ,
29+ TryIntoFunction ( Option < SpansKind > ) ,
30+ }
31+
32+ impl FunctionKind {
33+ fn applicability ( & self , parent_unwrap_call : & Option < Span > ) -> Applicability {
34+ if parent_unwrap_call. is_none ( ) {
35+ return Applicability :: Unspecified ;
36+ }
37+ match & self {
38+ FunctionKind :: TryFromFunction ( None ) | FunctionKind :: TryIntoFunction ( None ) => Applicability :: Unspecified ,
39+ _ => Applicability :: MachineApplicable ,
40+ }
41+ }
42+
43+ fn default_sugg ( & self , primary_span : Span ) -> Vec < ( Span , String ) > {
44+ match * self {
45+ FunctionKind :: TryFromFunction ( _) => vec ! [ ( primary_span, String :: from( "From::from" ) ) ] ,
46+ FunctionKind :: TryIntoFunction ( _) => vec ! [ ( primary_span, String :: from( "Into::into" ) ) ] ,
47+ FunctionKind :: TryIntoMethod => vec ! [ ( primary_span, String :: from( "into" ) ) ] ,
48+ }
49+ }
50+
51+ fn machine_applicable_sugg ( & self , primary_span : Span , unwrap_span : Span ) -> Vec < ( Span , String ) > {
52+ let mut sugg = match * self {
53+ FunctionKind :: TryFromFunction ( Some ( spans) ) => match spans {
54+ SpansKind :: TraitFn { trait_span, fn_span } => {
55+ vec ! [ ( trait_span, String :: from( "From" ) ) , ( fn_span, String :: from( "from" ) ) ]
56+ } ,
57+ SpansKind :: Fn { fn_span } => vec ! [ ( fn_span, String :: from( "from" ) ) ] ,
58+ } ,
59+ FunctionKind :: TryIntoFunction ( Some ( spans) ) => match spans {
60+ SpansKind :: TraitFn { trait_span, fn_span } => {
61+ vec ! [ ( trait_span, String :: from( "Into" ) ) , ( fn_span, String :: from( "into" ) ) ]
62+ } ,
63+ SpansKind :: Fn { fn_span } => vec ! [ ( fn_span, String :: from( "into" ) ) ] ,
64+ } ,
65+ FunctionKind :: TryIntoMethod => vec ! [ ( primary_span, String :: from( "into" ) ) ] ,
66+ _ => unreachable ! ( ) ,
67+ } ;
68+ sugg. push ( ( unwrap_span, String :: new ( ) ) ) ;
69+ sugg
70+ }
2471}
2572
2673fn check < ' tcx > (
@@ -69,47 +116,17 @@ fn check<'tcx>(
69116 primary_span
70117 } ;
71118
72- let ( source_ty, target_ty, sugg, applicability) = match ( kind, parent_unwrap_call) {
73- ( FunctionKind :: TryIntoMethod , Some ( unwrap_span) ) => {
74- let sugg = vec ! [ ( primary_span, String :: from( "into" ) ) , ( unwrap_span, String :: new( ) ) ] ;
75- ( self_ty, other_ty, sugg, Applicability :: MachineApplicable )
76- } ,
77- ( FunctionKind :: TryFromFunction ( Some ( spans) ) , Some ( unwrap_span) ) => {
78- let sugg = match spans. len ( ) {
79- 1 => vec ! [ ( spans[ 0 ] , String :: from( "from" ) ) , ( unwrap_span, String :: new( ) ) ] ,
80- 2 => vec ! [
81- ( spans[ 0 ] , String :: from( "From" ) ) ,
82- ( spans[ 1 ] , String :: from( "from" ) ) ,
83- ( unwrap_span, String :: new( ) ) ,
84- ] ,
85- _ => unreachable ! ( ) ,
86- } ;
87- ( other_ty, self_ty, sugg, Applicability :: MachineApplicable )
88- } ,
89- ( FunctionKind :: TryIntoFunction ( Some ( spans) ) , Some ( unwrap_span) ) => {
90- let sugg = match spans. len ( ) {
91- 1 => vec ! [ ( spans[ 0 ] , String :: from( "into" ) ) , ( unwrap_span, String :: new( ) ) ] ,
92- 2 => vec ! [
93- ( spans[ 0 ] , String :: from( "Into" ) ) ,
94- ( spans[ 1 ] , String :: from( "into" ) ) ,
95- ( unwrap_span, String :: new( ) ) ,
96- ] ,
97- _ => unreachable ! ( ) ,
98- } ;
99- ( self_ty, other_ty, sugg, Applicability :: MachineApplicable )
100- } ,
101- ( FunctionKind :: TryFromFunction ( _) , _) => {
102- let sugg = vec ! [ ( primary_span, String :: from( "From::from" ) ) ] ;
103- ( other_ty, self_ty, sugg, Applicability :: Unspecified )
104- } ,
105- ( FunctionKind :: TryIntoFunction ( _) , _) => {
106- let sugg = vec ! [ ( primary_span, String :: from( "Into::into" ) ) ] ;
107- ( self_ty, other_ty, sugg, Applicability :: Unspecified )
108- } ,
109- ( FunctionKind :: TryIntoMethod , _) => {
110- let sugg = vec ! [ ( primary_span, String :: from( "into" ) ) ] ;
111- ( self_ty, other_ty, sugg, Applicability :: Unspecified )
112- } ,
119+ let ( source_ty, target_ty) = match kind {
120+ FunctionKind :: TryIntoMethod | FunctionKind :: TryIntoFunction ( _) => ( self_ty, other_ty) ,
121+ FunctionKind :: TryFromFunction ( _) => ( other_ty, self_ty) ,
122+ } ;
123+
124+ let applicability = kind. applicability ( & parent_unwrap_call) ;
125+
126+ let sugg = if applicability == Applicability :: MachineApplicable {
127+ kind. machine_applicable_sugg ( primary_span, parent_unwrap_call. unwrap ( ) )
128+ } else {
129+ kind. default_sugg ( primary_span)
113130 } ;
114131
115132 span_lint_and_then (
@@ -151,10 +168,18 @@ pub(super) fn check_function(cx: &LateContext<'_>, expr: &Expr<'_>, callee: &Exp
151168 {
152169 let qpath_spans = match qpath {
153170 QPath :: Resolved ( _, path) => {
154- let segments = path. segments . iter ( ) . map ( |seg| seg. ident ) . collect :: < Vec < _ > > ( ) ;
155- ( segments. len ( ) == 2 ) . then ( || vec ! [ segments[ 0 ] . span, segments[ 1 ] . span] )
171+ if let [ trait_seg, fn_seg] = path. segments {
172+ Some ( SpansKind :: TraitFn {
173+ trait_span : trait_seg. ident . span ,
174+ fn_span : fn_seg. ident . span ,
175+ } )
176+ } else {
177+ None
178+ }
156179 } ,
157- QPath :: TypeRelative ( _, seg) => Some ( vec ! [ seg. ident. span] ) ,
180+ QPath :: TypeRelative ( _, seg) => Some ( SpansKind :: Fn {
181+ fn_span : seg. ident . span ,
182+ } ) ,
158183 QPath :: LangItem ( _, _) => unreachable ! ( "`TryFrom` and `TryInto` are not lang items" ) ,
159184 } ;
160185
0 commit comments