@@ -80,6 +80,11 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
80
80
&& cx. tcx . is_diagnostic_item ( sym:: Into , middle_trait_ref. def_id )
81
81
&& !matches ! ( middle_trait_ref. substs. type_at( 1 ) . kind( ) , ty:: Alias ( ty:: Opaque , _) )
82
82
{
83
+ if !target_ty. find_self_aliases ( ) . is_empty ( ) {
84
+ // It's tricky to expand self-aliases correctly, we'll ignore it to not cause a
85
+ // bad suggestion/fix.
86
+ return ;
87
+ }
83
88
span_lint_and_then (
84
89
cx,
85
90
FROM_OVER_INTO ,
@@ -163,8 +168,7 @@ fn convert_to_from(
163
168
let PatKind :: Binding ( .., self_ident, None ) = input. pat . kind else { return None } ;
164
169
165
170
let from = snippet_opt ( cx, self_ty. span ) ?;
166
- // If Self is used, it refers to `self_ty`, which is now out `from` snippet
167
- let into = replace_self ( & snippet_opt ( cx, target_ty. span ) ?, & from) ;
171
+ let into = snippet_opt ( cx, target_ty. span ) ?;
168
172
169
173
let mut suggestions = vec ! [
170
174
// impl Into<T> for U -> impl From<T> for U
@@ -213,75 +217,3 @@ fn convert_to_from(
213
217
214
218
Some ( suggestions)
215
219
}
216
-
217
- fn replace_self ( input : & str , replace_with : & str ) -> String {
218
- const SELF : & str = "Self" ;
219
- let mut chunks = input. split ( SELF ) . peekable ( ) ;
220
- if let Some ( first) = chunks. next ( ) {
221
- let mut last_ended_with_break = false ;
222
- // Heuristic, we're making a guess that the expansion probably doesn't exceed `input.len() * 2`
223
- let mut output = String :: with_capacity ( input. len ( ) * 2 ) ;
224
- if first. is_empty ( ) || first. ends_with ( word_break) {
225
- last_ended_with_break = true ;
226
- }
227
- output. push_str ( first) ;
228
- while let Some ( val) = chunks. next ( ) {
229
- let is_last = chunks. peek ( ) . is_none ( ) ;
230
- if last_ended_with_break && is_last && val. is_empty ( ) {
231
- output. push_str ( replace_with) ;
232
- break ;
233
- }
234
- let this_starts_with_break = val. starts_with ( word_break) ;
235
- let this_ends_with_break = val. ends_with ( word_break) ;
236
- if this_starts_with_break && last_ended_with_break {
237
- output. push_str ( replace_with) ;
238
- } else {
239
- output. push_str ( SELF ) ;
240
- }
241
- output. push_str ( val) ;
242
- last_ended_with_break = this_ends_with_break;
243
- }
244
- output
245
- } else {
246
- input. to_string ( )
247
- }
248
- }
249
-
250
- #[ inline]
251
- fn word_break ( ch : char ) -> bool {
252
- !ch. is_alphanumeric ( )
253
- }
254
-
255
- #[ cfg( test) ]
256
- mod tests {
257
- use crate :: from_over_into:: replace_self;
258
-
259
- #[ test]
260
- fn replace_doesnt_touch_coincidental_self ( ) {
261
- let input = "impl Into<SelfType> for String {" ;
262
- assert_eq ! ( input, & replace_self( input, "T" ) ) ;
263
- }
264
-
265
- #[ test]
266
- fn replace_replaces_self ( ) {
267
- let input = "impl Into<Self> for String {" ;
268
- assert_eq ! ( "impl Into<String> for String {" , & replace_self( input, "String" ) ) ;
269
- }
270
- #[ test]
271
- fn replace_replaces_self_many ( ) {
272
- let input = "impl Into<Self<Self<SelfSelfSelfSelf>>> for Self {" ;
273
- assert_eq ! (
274
- "impl Into<String<String<SelfSelfSelfSelf>>> for String {" ,
275
- & replace_self( input, "String" )
276
- ) ;
277
- }
278
-
279
- #[ test]
280
- fn replace_replaces_self_many_starts_ends_self ( ) {
281
- let input = "Self impl Into<Self<Self<SelfSelf>>> for Self" ;
282
- assert_eq ! (
283
- "String impl Into<String<String<SelfSelf>>> for String" ,
284
- & replace_self( input, "String" )
285
- ) ;
286
- }
287
- }
0 commit comments