@@ -10,7 +10,7 @@ use oxc_macros::declare_oxc_lint;
1010use oxc_span:: { GetSpan , Span } ;
1111use oxc_syntax:: operator:: { AssignmentOperator , BinaryOperator , UnaryOperator , UpdateOperator } ;
1212
13- use crate :: { AstNode , context:: LintContext , rule:: Rule } ;
13+ use crate :: { AstNode , context:: LintContext , rule:: Rule , utils :: is_same_expression } ;
1414
1515fn prefer_for_of_diagnostic ( span : Span ) -> OxcDiagnostic {
1616 OxcDiagnostic :: warn (
@@ -145,7 +145,7 @@ impl Rule for PreferForOf {
145145 return ;
146146 }
147147
148- let array_name = {
148+ let ( array_name, array_expr ) = {
149149 let Some ( mem_expr) = test_expr. right . as_member_expression ( ) else {
150150 return ;
151151 } ;
@@ -154,7 +154,8 @@ impl Rule for PreferForOf {
154154 return ;
155155 }
156156
157- match mem_expr. object ( ) {
157+ let array_expr = mem_expr. object ( ) ;
158+ let array_name = match mem_expr. object ( ) {
158159 Expression :: Identifier ( id) => id. name . as_str ( ) ,
159160 expr @ match_member_expression ! ( Expression ) => {
160161 match expr. to_member_expression ( ) . static_property_name ( ) {
@@ -163,7 +164,9 @@ impl Rule for PreferForOf {
163164 }
164165 }
165166 _ => return ,
166- }
167+ } ;
168+
169+ ( array_name, array_expr)
167170 } ;
168171
169172 let Some ( update_expr) = & for_stmt. update else {
@@ -198,7 +201,7 @@ impl Rule for PreferForOf {
198201 }
199202
200203 // Check if this is a non-array access that prevents conversion
201- prevents_for_of_non_array_access ( parent, array_name )
204+ prevents_for_of_non_array_access ( parent, array_expr , ctx )
202205 } ) {
203206 return ;
204207 }
@@ -264,20 +267,15 @@ fn prevents_for_of_array_access(
264267}
265268
266269/// Check if this is a non-array access that prevents conversion
267- fn prevents_for_of_non_array_access ( parent : & AstNode , array_name : & str ) -> bool {
270+ fn prevents_for_of_non_array_access (
271+ parent : & AstNode ,
272+ array_expr : & Expression ,
273+ ctx : & LintContext ,
274+ ) -> bool {
268275 let parent_kind = parent. kind ( ) ;
269276
270277 if let Some ( mem_expr) = parent_kind. as_member_expression_kind ( ) {
271- match & mem_expr. object ( ) {
272- Expression :: Identifier ( id) => id. name . as_str ( ) != array_name,
273- expr if expr. is_member_expression ( ) => {
274- match expr. to_member_expression ( ) . static_property_name ( ) {
275- Some ( prop_name) => prop_name != array_name,
276- None => true ,
277- }
278- }
279- _ => true ,
280- }
278+ !is_same_expression ( mem_expr. object ( ) , array_expr, ctx)
281279 } else {
282280 true
283281 }
@@ -370,6 +368,18 @@ fn test() {
370368 "for (var j = 0; j < 10; j++) {}" ,
371369 "const arr = [];
372370 for (i = 0; i < arr.length; i++) { el = arr[i]; console.log(i, el); }" ,
371+ "for (let x = 0; x < series.data.length; x++) { let newValue = series.data[x].y; for (const otherSeries of subseries) { newValue -= otherSeries.data[x].y; } series.data[x].y = newValue; }" ,
372+ // Deep nesting test cases
373+ "const a = { b: { c: { d: { e: [1, 2, 3] } } } };
374+ const x = { b: { c: { d: { e: [4, 5, 6] } } } };
375+ for (let i = 0; i < a.b.c.d.e.length; i++) {
376+ console.log(x.b.c.d.e[i]); // Different object with same path
377+ }" ,
378+ "const obj1 = { a: { b: [1, 2, 3] } };
379+ const obj2 = { a: { b: [4, 5, 6] } };
380+ for (let i = 0; i < obj1.a.b.length; i++) {
381+ console.log(obj2.a.b[i]); // Different object
382+ }" ,
373383 ] ;
374384
375385 let fail = vec ! [
@@ -401,6 +411,15 @@ fn test() {
401411 "const array = []; for (let i = 0; i < array.length; i++) { let foo = array[i]; }" ,
402412 "const array = []; for (let i = 0; i < array.length; i++) { const foo = array[i]; }" ,
403413 "const array = []; for (let i = 0; i < array.length; i++) { var foo = array[i], bar = 1; }" ,
414+ // Deep nesting test cases that should trigger warning
415+ "const a = { b: { c: { d: { e: [1, 2, 3] } } } };
416+ for (let i = 0; i < a.b.c.d.e.length; i++) {
417+ console.log(a.b.c.d.e[i]); // Same deeply nested array
418+ }" ,
419+ "const obj = { a: { b: [1, 2, 3] } };
420+ for (let i = 0; i < obj.a.b.length; i++) {
421+ console.log(obj.a.b[i]); // Same nested array
422+ }" ,
404423 ] ;
405424
406425 Tester :: new ( PreferForOf :: NAME , PreferForOf :: PLUGIN , pass, fail) . test_and_snapshot ( ) ;
0 commit comments