@@ -2,16 +2,22 @@ use std::borrow::Cow;
22
33use  oxc_codegen:: Codegen ; 
44use  oxc_diagnostics:: OxcDiagnostic ; 
5- use  oxc_span:: { GetSpan ,  Span } ; 
5+ use  oxc_span:: { GetSpan ,  Span ,   SPAN } ; 
66
77use  crate :: LintContext ; 
88
9- #[ derive( Debug ,  Clone ,   Default ) ]  
9+ #[ derive( Debug ,  Clone ) ]  
1010pub  struct  Fix < ' a >  { 
1111    pub  content :  Cow < ' a ,  str > , 
1212    pub  span :  Span , 
1313} 
1414
15+ impl  Default  for  Fix < ' _ >  { 
16+     fn  default ( )  -> Self  { 
17+         Self :: empty ( ) 
18+     } 
19+ } 
20+ 
1521impl < ' a >  Fix < ' a >  { 
1622    pub  const  fn  delete ( span :  Span )  -> Self  { 
1723        Self  {  content :  Cow :: Borrowed ( "" ) ,  span } 
@@ -20,10 +26,21 @@ impl<'a> Fix<'a> {
2026    pub  fn  new < T :  Into < Cow < ' a ,  str > > > ( content :  T ,  span :  Span )  -> Self  { 
2127        Self  {  content :  content. into ( ) ,  span } 
2228    } 
29+ 
30+     /// Creates a [`Fix`] that doesn't change the source code. 
31+ #[ inline]  
32+     pub  const  fn  empty ( )  -> Self  { 
33+         Self  {  content :  Cow :: Borrowed ( "" ) ,  span :  SPAN  } 
34+     } 
2335} 
2436
37+ #[ derive( Debug ,  Default ) ]  
2538pub  enum  CompositeFix < ' a >  { 
39+     /// No fixes 
40+ #[ default]  
41+     None , 
2642    Single ( Fix < ' a > ) , 
43+     /// Several fixes that will be merged into one, in order. 
2744Multiple ( Vec < Fix < ' a > > ) , 
2845} 
2946
@@ -33,9 +50,22 @@ impl<'a> From<Fix<'a>> for CompositeFix<'a> {
3350    } 
3451} 
3552
53+ impl < ' a >  From < Option < Fix < ' a > > >  for  CompositeFix < ' a >  { 
54+     fn  from ( fix :  Option < Fix < ' a > > )  -> Self  { 
55+         match  fix { 
56+             Some ( fix)  => CompositeFix :: Single ( fix) , 
57+             None  => CompositeFix :: None , 
58+         } 
59+     } 
60+ } 
61+ 
3662impl < ' a >  From < Vec < Fix < ' a > > >  for  CompositeFix < ' a >  { 
3763    fn  from ( fixes :  Vec < Fix < ' a > > )  -> Self  { 
38-         CompositeFix :: Multiple ( fixes) 
64+         if  fixes. is_empty ( )  { 
65+             CompositeFix :: None 
66+         }  else  { 
67+             CompositeFix :: Multiple ( fixes) 
68+         } 
3969    } 
4070} 
4171
@@ -46,19 +76,21 @@ impl<'a> CompositeFix<'a> {
4676        match  self  { 
4777            CompositeFix :: Single ( fix)  => fix, 
4878            CompositeFix :: Multiple ( fixes)  => Self :: merge_fixes ( fixes,  source_text) , 
79+             CompositeFix :: None  => Fix :: empty ( ) , 
4980        } 
5081    } 
51-     // Merges multiple fixes to one, returns an `Fix::default`(which will not fix anything) if: 
52-     // 1. `fixes` is empty 
53-     // 2. contains overlapped ranges 
54-     // 3. contains negative ranges (span.start > span.end) 
55-     // <https://github.com/eslint/eslint/blob/main/lib/linter/report-translator.js#L147-L179> 
82+     /// Merges multiple fixes to one, returns an `Fix::default`(which will not fix anything) if: 
83+ /// 
84+ /// 1. `fixes` is empty 
85+ /// 2. contains overlapped ranges 
86+ /// 3. contains negative ranges (span.start > span.end) 
87+ /// 
88+ /// <https://github.com/eslint/eslint/blob/main/lib/linter/report-translator.js#L147-L179> 
5689fn  merge_fixes ( fixes :  Vec < Fix < ' a > > ,  source_text :  & str )  -> Fix < ' a >  { 
5790        let  mut  fixes = fixes; 
58-         let  empty_fix = Fix :: default ( ) ; 
5991        if  fixes. is_empty ( )  { 
6092            // Do nothing 
61-             return  empty_fix ; 
93+             return  Fix :: empty ( ) ; 
6294        } 
6395        if  fixes. len ( )  == 1  { 
6496            return  fixes. pop ( ) . unwrap ( ) ; 
@@ -77,33 +109,35 @@ impl<'a> CompositeFix<'a> {
77109            // negative range or overlapping ranges is invalid 
78110            if  span. start  > span. end  { 
79111                debug_assert ! ( false ,  "Negative range is invalid: {span:?}" ) ; 
80-                 return  empty_fix ; 
112+                 return  Fix :: empty ( ) ; 
81113            } 
82114            if  last_pos > span. start  { 
83115                debug_assert ! ( 
84116                    false , 
85117                    "Fix must not be overlapped, last_pos: {}, span.start: {}" , 
86118                    last_pos,  span. start
87119                ) ; 
88-                 return  empty_fix ; 
120+                 return  Fix :: empty ( ) ; 
89121            } 
90122
91123            let  Some ( before)  = source_text. get ( ( last_pos)  as  usize ..span. start  as  usize )  else  { 
92124                debug_assert ! ( false ,  "Invalid range: {}, {}" ,  last_pos,  span. start) ; 
93-                 return  empty_fix ; 
125+                 return  Fix :: empty ( ) ; 
94126            } ; 
95127
128+             output. reserve ( before. len ( )  + content. len ( ) ) ; 
96129            output. push_str ( before) ; 
97130            output. push_str ( content) ; 
98131            last_pos = span. end ; 
99132        } 
100133
101134        let  Some ( after)  = source_text. get ( last_pos as  usize ..end as  usize )  else  { 
102135            debug_assert ! ( false ,  "Invalid range: {:?}" ,  last_pos as  usize ..end as  usize ) ; 
103-             return  empty_fix ; 
136+             return  Fix :: empty ( ) ; 
104137        } ; 
105138
106139        output. push_str ( after) ; 
140+         output. shrink_to_fit ( ) ; 
107141        Fix :: new ( output,  Span :: new ( start,  end) ) 
108142    } 
109143} 
@@ -121,6 +155,8 @@ impl<'c, 'a: 'c> RuleFixer<'c, 'a> {
121155        Self  {  ctx } 
122156    } 
123157
158+     /// Get a snippet of source text covered by the given [`Span`]. For details, 
159+ /// see [`Span::source_text`]. 
124160pub  fn  source_range ( self ,  span :  Span )  -> & ' a  str  { 
125161        self . ctx . source_range ( span) 
126162    } 
@@ -186,6 +222,11 @@ impl<'c, 'a: 'c> RuleFixer<'c, 'a> {
186222    pub  fn  codegen ( self )  -> Codegen < ' a ,  false >  { 
187223        Codegen :: < false > :: new ( ) 
188224    } 
225+ 
226+     #[ allow( clippy:: unused_self) ]  
227+     pub  fn  noop ( self )  -> Fix < ' a >  { 
228+         Fix :: empty ( ) 
229+     } 
189230} 
190231
191232pub  struct  FixResult < ' a >  { 
0 commit comments