@@ -78,8 +78,17 @@ pub struct Environment<'a> {
78
78
/// local_variable_usages is a stack of scopes. When a local variable is created it is
79
79
/// added to the top scope. When a local variable is used we crawl down the scope
80
80
/// stack for a variable with that name and mark it as used.
81
- /// NOTE: The bool in the tuple here tracks if the variable has been used
82
- pub local_variable_usages : Vec < HashMap < EcoString , ( VariableOrigin , SrcSpan , bool ) > > ,
81
+ ///
82
+ /// NOTE: The usize in the tuple here tracks the number of times the variable has
83
+ /// been used.
84
+ pub local_variable_usages : Vec < HashMap < EcoString , ( VariableOrigin , SrcSpan , usize ) > > ,
85
+
86
+ /// Used to determine if an argument is only used unchanged in recursive
87
+ /// calls, and could thus be removed.
88
+ /// For each of the function's arguments keeps track of the usages in
89
+ /// recursive calls.
90
+ ///
91
+ pub recursive_argument_usages : HashMap < SrcSpan , Vec < SrcSpan > > ,
83
92
84
93
/// Used to determine if all functions/constants need to support the current
85
94
/// compilation target.
@@ -134,6 +143,7 @@ impl<'a> Environment<'a> {
134
143
importable_modules,
135
144
current_module,
136
145
local_variable_usages : vec ! [ HashMap :: new( ) ] ,
146
+ recursive_argument_usages : HashMap :: new ( ) ,
137
147
target_support,
138
148
names,
139
149
module_type_aliases : HashMap :: new ( ) ,
@@ -658,15 +668,15 @@ impl Environment<'_> {
658
668
location : SrcSpan ,
659
669
problems : & mut Problems ,
660
670
) {
661
- if let Some ( ( origin, location, false ) ) = self
671
+ if let Some ( ( origin, location, 0 ) ) = self
662
672
. local_variable_usages
663
673
. last_mut ( )
664
674
. expect ( "Attempted to access non-existent entity usages scope" )
665
- . insert ( name. clone ( ) , ( origin, location, false ) )
675
+ . insert ( name. clone ( ) , ( origin, location, 0 ) )
666
676
{
667
677
// an entity was overwritten in the top most scope without being used
668
678
let mut unused = HashMap :: with_capacity ( 1 ) ;
669
- let _ = unused. insert ( name, ( origin, location, false ) ) ;
679
+ let _ = unused. insert ( name, ( origin, location, 0 ) ) ;
670
680
self . handle_unused_variables ( unused, problems) ;
671
681
}
672
682
}
@@ -681,7 +691,7 @@ impl Environment<'_> {
681
691
. rev ( )
682
692
. find_map ( |scope| scope. get_mut ( & name) )
683
693
{
684
- * used = true ;
694
+ * used += 1 ;
685
695
}
686
696
}
687
697
@@ -795,13 +805,25 @@ impl Environment<'_> {
795
805
796
806
fn handle_unused_variables (
797
807
& mut self ,
798
- unused : HashMap < EcoString , ( VariableOrigin , SrcSpan , bool ) > ,
808
+ unused : HashMap < EcoString , ( VariableOrigin , SrcSpan , usize ) > ,
799
809
problems : & mut Problems ,
800
810
) {
801
- for ( origin, location, used ) in unused. into_values ( ) {
802
- if !used {
811
+ for ( origin, location, usages ) in unused. into_values ( ) {
812
+ if usages == 0 {
803
813
problems. warning ( Warning :: UnusedVariable { location, origin } ) ;
804
814
}
815
+ // If the function parameter is actually used somewhere, but all the
816
+ // usages are just passing it along in a recursive call, then it
817
+ // counts as being unused too.
818
+ else if origin. is_function_parameter ( )
819
+ && let Some ( recursive_usages) = self . recursive_argument_usages . get ( & location)
820
+ && recursive_usages. len ( ) == usages
821
+ {
822
+ problems. warning ( Warning :: UnusedRecursiveArgument {
823
+ location,
824
+ usages : recursive_usages. clone ( ) ,
825
+ } ) ;
826
+ }
805
827
}
806
828
}
807
829
0 commit comments