@@ -71,7 +71,7 @@ use rustc_macros::{Decodable, Encodable};
71
71
pub use rustc_span:: ErrorGuaranteed ;
72
72
pub use rustc_span:: fatal_error:: { FatalError , FatalErrorMarker } ;
73
73
use rustc_span:: source_map:: SourceMap ;
74
- use rustc_span:: { DUMMY_SP , Loc , Span } ;
74
+ use rustc_span:: { BytePos , DUMMY_SP , Loc , Span } ;
75
75
pub use snippet:: Style ;
76
76
// Used by external projects such as `rust-gpu`.
77
77
// See https://github.com/rust-lang/rust/pull/115393.
@@ -237,10 +237,9 @@ impl SubstitutionPart {
237
237
/// it with "abx" is, since the "c" character is lost.
238
238
pub fn is_destructive_replacement ( & self , sm : & SourceMap ) -> bool {
239
239
self . is_replacement ( sm)
240
- && !sm. span_to_snippet ( self . span ) . is_ok_and ( |snippet| {
241
- self . snippet . trim_start ( ) . starts_with ( snippet. trim_start ( ) )
242
- || self . snippet . trim_end ( ) . ends_with ( snippet. trim_end ( ) )
243
- } )
240
+ && !sm
241
+ . span_to_snippet ( self . span )
242
+ . is_ok_and ( |snippet| as_substr ( snippet. trim ( ) , self . snippet . trim ( ) ) . is_some ( ) )
244
243
}
245
244
246
245
fn replaces_meaningful_content ( & self , sm : & SourceMap ) -> bool {
@@ -257,16 +256,40 @@ impl SubstitutionPart {
257
256
let Ok ( snippet) = sm. span_to_snippet ( self . span ) else {
258
257
return ;
259
258
} ;
260
- if self . snippet . starts_with ( & snippet) {
261
- self . span = self . span . shrink_to_hi ( ) ;
262
- self . snippet = self . snippet [ snippet. len ( ) ..] . to_string ( ) ;
263
- } else if self . snippet . ends_with ( & snippet) {
264
- self . span = self . span . shrink_to_lo ( ) ;
265
- self . snippet = self . snippet [ ..self . snippet . len ( ) - snippet. len ( ) ] . to_string ( ) ;
259
+
260
+ if let Some ( ( prefix, substr, suffix) ) = as_substr ( & snippet, & self . snippet ) {
261
+ self . span = Span :: new (
262
+ self . span . lo ( ) + BytePos ( prefix as u32 ) ,
263
+ self . span . hi ( ) - BytePos ( suffix as u32 ) ,
264
+ self . span . ctxt ( ) ,
265
+ self . span . parent ( ) ,
266
+ ) ;
267
+ self . snippet = substr. to_string ( ) ;
266
268
}
267
269
}
268
270
}
269
271
272
+ /// Given an original string like `AACC`, and a suggestion like `AABBCC`, try to detect
273
+ /// the case where a substring of the suggestion is "sandwiched" in the original, like
274
+ /// `BB` is. Return the length of the prefix, the "trimmed" suggestion, and the length
275
+ /// of the suffix.
276
+ fn as_substr < ' a > ( original : & ' a str , suggestion : & ' a str ) -> Option < ( usize , & ' a str , usize ) > {
277
+ let common_prefix = original
278
+ . chars ( )
279
+ . zip ( suggestion. chars ( ) )
280
+ . take_while ( |( c1, c2) | c1 == c2)
281
+ . map ( |( c, _) | c. len_utf8 ( ) )
282
+ . sum ( ) ;
283
+ let original = & original[ common_prefix..] ;
284
+ let suggestion = & suggestion[ common_prefix..] ;
285
+ if suggestion. ends_with ( original) {
286
+ let common_suffix = original. len ( ) ;
287
+ Some ( ( common_prefix, & suggestion[ ..suggestion. len ( ) - original. len ( ) ] , common_suffix) )
288
+ } else {
289
+ None
290
+ }
291
+ }
292
+
270
293
impl CodeSuggestion {
271
294
/// Returns the assembled code suggestions, whether they should be shown with an underline
272
295
/// and whether the substitution only differs in capitalization.
0 commit comments