@@ -504,7 +504,13 @@ impl Rule for ExhaustiveDeps {
504
504
return false ;
505
505
}
506
506
507
- if !is_identifier_a_dependency ( dep. name , dep. reference_id , ctx, component_scope_id) {
507
+ if !is_identifier_a_dependency (
508
+ dep. name ,
509
+ dep. reference_id ,
510
+ dep. span ,
511
+ ctx,
512
+ component_scope_id,
513
+ ) {
508
514
return false ;
509
515
}
510
516
true
@@ -779,6 +785,7 @@ fn concat_members<'a, 'b>(
779
785
fn is_identifier_a_dependency < ' a > (
780
786
ident_name : Atom < ' a > ,
781
787
ident_reference_id : ReferenceId ,
788
+ ident_span : Span ,
782
789
ctx : & ' _ LintContext < ' a > ,
783
790
component_scope_id : ScopeId ,
784
791
) -> bool {
@@ -835,6 +842,17 @@ fn is_identifier_a_dependency<'a>(
835
842
return false ;
836
843
}
837
844
845
+ // Using a declaration recursively is ok
846
+ // ```tsx
847
+ // function MyComponent() {
848
+ // const recursive = useCallback((n: number): number => (n <= 0 ? 0 : n + recursive(n - 1)), []);
849
+ // return recursive
850
+ // }
851
+ // ```
852
+ if declaration. span ( ) . contains_inclusive ( ident_span) {
853
+ return false ;
854
+ }
855
+
838
856
true
839
857
}
840
858
@@ -969,7 +987,13 @@ fn is_function_stable<'a, 'b>(
969
987
970
988
deps. iter ( ) . all ( |dep| {
971
989
dep. symbol_id . zip ( function_symbol_id) . is_none_or ( |( l, r) | l != r)
972
- && !is_identifier_a_dependency ( dep. name , dep. reference_id , ctx, component_scope_id)
990
+ && !is_identifier_a_dependency (
991
+ dep. name ,
992
+ dep. reference_id ,
993
+ dep. span ,
994
+ ctx,
995
+ component_scope_id,
996
+ )
973
997
} )
974
998
}
975
999
@@ -2159,6 +2183,7 @@ fn test() {
2159
2183
return null;
2160
2184
}
2161
2185
"# ,
2186
+ r"function MyComponent() { const recursive = useCallback((n: number): number => (n <= 0 ? 0 : n + recursive(n - 1)), []); return recursive }" ,
2162
2187
] ;
2163
2188
2164
2189
let fail = vec ! [
0 commit comments