@@ -171,18 +171,17 @@ fn traverse<'a>(
171171 traverse ( & mut function. walk ( ) , rope, tracker) ?;
172172 }
173173
174- if function. kind ( ) == "identifier" && rope. byte_slice ( function. byte_range ( ) ) == "local"
175- {
174+ let new_scope = function. kind ( ) == "identifier"
175+ && rope. byte_slice ( function. byte_range ( ) ) == "local" ;
176+
177+ if new_scope {
176178 tracker. push_scope ( ) ;
179+ }
177180
178- let args = field ( node, "arguments" ) ?;
179- traverse ( & mut args. walk ( ) , rope, tracker) ?;
181+ traverse ( & mut field ( node, "arguments" ) ?. walk ( ) , rope, tracker) ?;
180182
183+ if new_scope {
181184 tracker. pop_scope ( ) ;
182- } else {
183- // Process arguments for regular function calls
184- let args = field ( node, "arguments" ) ?;
185- traverse ( & mut args. walk ( ) , rope, tracker) ?;
186185 }
187186 }
188187
@@ -408,4 +407,141 @@ mod tests {
408407 "The parameter 'a' should be marked as unused (line 1)"
409408 ) ;
410409 }
410+ #[ test]
411+ fn nested_scopes ( ) {
412+ let code = r#"
413+ function() {
414+ a <- 10
415+ local({
416+ b <- 20
417+ local({
418+ c <- 30
419+ print(a)
420+ print(b)
421+ })
422+ d <- 40
423+ })
424+ e <- 50
425+ print(e)
426+ }
427+ "# ;
428+
429+ let unused_vars = get_unused_var_names ( code) ;
430+ assert ! ( !unused_vars. contains( "a" ) ) ;
431+ assert ! ( !unused_vars. contains( "b" ) ) ;
432+ assert ! ( unused_vars. contains( "c" ) ) ;
433+ assert ! ( unused_vars. contains( "d" ) ) ;
434+ assert ! ( !unused_vars. contains( "e" ) ) ;
435+ }
436+
437+ #[ test]
438+ fn nested_functions ( ) {
439+ let code = r#"
440+ function() {
441+ outer <- 1
442+ unused <- 2
443+ f1 <- function() {
444+ mid <- 3
445+ f2 <- function() {
446+ inner <- 4
447+ print(outer)
448+ print(mid)
449+ }
450+ return(f2)
451+ }
452+ nested <- f1()
453+ nested()
454+ }
455+ "# ;
456+
457+ let unused_vars = get_unused_var_names ( code) ;
458+ assert ! ( !unused_vars. contains( "outer" ) ) ;
459+ assert ! ( unused_vars. contains( "unused" ) ) ;
460+ assert ! ( !unused_vars. contains( "mid" ) ) ;
461+ assert ! ( unused_vars. contains( "inner" ) ) ;
462+ assert ! ( !unused_vars. contains( "f1" ) ) ;
463+ assert ! ( !unused_vars. contains( "f2" ) ) ;
464+ assert ! ( !unused_vars. contains( "nested" ) ) ;
465+ }
466+
467+ #[ test]
468+ fn multiple_shadowing_levels ( ) {
469+ let code = r#"
470+ function() {
471+ x <- 1
472+ x <- 2
473+ x <- 3
474+ x <- 4
475+ x <- 5
476+ print(x)
477+ }
478+ "# ;
479+
480+ let diagnostics =
481+ analyze ( tree:: parse ( code, None ) . root_node ( ) , & Rope :: from_str ( code) ) . unwrap ( ) ;
482+ assert_eq ! (
483+ diagnostics. len( ) ,
484+ 4 ,
485+ "Should have 4 unused shadowed variables"
486+ ) ;
487+ }
488+
489+ #[ test]
490+ fn conditional_usage ( ) {
491+ let code = r#"
492+ function() {
493+ a <- 1
494+ b <- 2
495+ c <- 3
496+ if (TRUE) {
497+ print(a)
498+ } else {
499+ print(b)
500+ }
501+ }
502+ "# ;
503+
504+ let unused_vars = get_unused_var_names ( code) ;
505+ assert ! ( !unused_vars. contains( "a" ) ) ;
506+ assert ! ( !unused_vars. contains( "b" ) ) ;
507+ assert ! ( unused_vars. contains( "c" ) ) ;
508+ }
509+
510+ #[ test]
511+ fn complex_nested_scopes ( ) {
512+ let code = r#"
513+ function(param1, param2, param3) {
514+ outer1 <- 10
515+ outer2 <- 20
516+ local({
517+ inner1 <- 30
518+ inner2 <- 40
519+ print(param1)
520+ print(outer1)
521+ })
522+
523+ f <- function(x) {
524+ z <- x + outer2
525+ print(param2)
526+ return(z)
527+ }
528+
529+ result <- f(5)
530+ print(result)
531+ }
532+ "# ;
533+
534+ let unused_vars = get_unused_var_names ( code) ;
535+ assert ! ( !unused_vars. contains( "param1" ) ) ;
536+ assert ! ( !unused_vars. contains( "param2" ) ) ;
537+ assert ! ( unused_vars. contains( "param3" ) ) ;
538+ assert ! ( !unused_vars. contains( "outer1" ) ) ;
539+ assert ! ( !unused_vars. contains( "outer2" ) ) ;
540+ assert ! ( unused_vars. contains( "inner1" ) ) ;
541+ assert ! ( unused_vars. contains( "inner2" ) ) ;
542+ assert ! ( !unused_vars. contains( "f" ) ) ;
543+ assert ! ( !unused_vars. contains( "x" ) ) ;
544+ assert ! ( !unused_vars. contains( "z" ) ) ;
545+ assert ! ( !unused_vars. contains( "result" ) ) ;
546+ }
411547}
0 commit comments