@@ -836,6 +836,24 @@ fn is_identifier_a_dependency<'a>(
836836 ident_span : Span ,
837837 ctx : & ' _ LintContext < ' a > ,
838838 component_scope_id : ScopeId ,
839+ ) -> bool {
840+ let mut visited = FxHashSet :: default ( ) ;
841+ is_identifier_a_dependency_impl (
842+ ident_name,
843+ ident_reference_id,
844+ ident_span,
845+ ctx,
846+ component_scope_id,
847+ & mut visited,
848+ )
849+ }
850+ fn is_identifier_a_dependency_impl < ' a > (
851+ ident_name : Atom < ' a > ,
852+ ident_reference_id : ReferenceId ,
853+ ident_span : Span ,
854+ ctx : & ' _ LintContext < ' a > ,
855+ component_scope_id : ScopeId ,
856+ visited : & mut FxHashSet < SymbolId > ,
839857) -> bool {
840858 // if it is a global e.g. `console` or `window`, then it's not a dependency
841859 if ctx. scoping ( ) . root_unresolved_references ( ) . contains_key ( ident_name. as_str ( ) ) {
@@ -885,8 +903,14 @@ fn is_identifier_a_dependency<'a>(
885903 return false ;
886904 }
887905
888- // if the value is stable (for example the setter returned by useState), then it's not a dependency
889- if is_stable_value ( declaration, ident_name, ident_reference_id, ctx, component_scope_id) {
906+ if is_stable_value (
907+ declaration,
908+ ident_name,
909+ ident_reference_id,
910+ ctx,
911+ component_scope_id,
912+ visited,
913+ ) {
890914 return false ;
891915 }
892916
@@ -911,7 +935,14 @@ fn is_stable_value<'a, 'b>(
911935 ident_reference_id : ReferenceId ,
912936 ctx : & ' b LintContext < ' a > ,
913937 component_scope_id : ScopeId ,
938+ visited : & mut FxHashSet < SymbolId > ,
914939) -> bool {
940+ if let Some ( symbol_id) = ctx. scoping ( ) . get_reference ( ident_reference_id) . symbol_id ( ) {
941+ if !visited. insert ( symbol_id) {
942+ return true ;
943+ }
944+ }
945+
915946 match node. kind ( ) {
916947 AstKind :: VariableDeclaration ( declaration) => {
917948 if declaration. kind == VariableDeclarationKind :: Const {
@@ -942,6 +973,7 @@ fn is_stable_value<'a, 'b>(
942973 . map ( oxc_ast:: ast:: BindingIdentifier :: symbol_id) ,
943974 ctx,
944975 component_scope_id,
976+ visited,
945977 ) ;
946978 }
947979 }
@@ -1015,7 +1047,7 @@ fn is_stable_value<'a, 'b>(
10151047
10161048 let Some ( function_body) = function_body else { return false } ;
10171049
1018- is_function_stable ( function_body, None , ctx, component_scope_id)
1050+ is_function_stable ( function_body, None , ctx, component_scope_id, visited )
10191051 }
10201052 _ => false ,
10211053 }
@@ -1026,6 +1058,7 @@ fn is_function_stable<'a, 'b>(
10261058 function_symbol_id : Option < SymbolId > ,
10271059 ctx : & ' b LintContext < ' a > ,
10281060 component_scope_id : ScopeId ,
1061+ visited : & mut FxHashSet < SymbolId > ,
10291062) -> bool {
10301063 let deps = {
10311064 let mut collector = ExhaustiveDepsVisitor :: new ( ctx. semantic ( ) ) ;
@@ -1035,12 +1068,13 @@ fn is_function_stable<'a, 'b>(
10351068
10361069 deps. iter ( ) . all ( |dep| {
10371070 dep. symbol_id . zip ( function_symbol_id) . is_none_or ( |( l, r) | l != r)
1038- && !is_identifier_a_dependency (
1071+ && !is_identifier_a_dependency_impl (
10391072 dep. name ,
10401073 dep. reference_id ,
10411074 dep. span ,
10421075 ctx,
10431076 component_scope_id,
1077+ visited,
10441078 )
10451079 } )
10461080}
@@ -2434,6 +2468,7 @@ fn test() {
24342468}
24352469"# ,
24362470 r"function MyComponent() { const recursive = useCallback((n: number): number => (n <= 0 ? 0 : n + recursive(n - 1)), []); return recursive }" ,
2471+ r"function Foo2() { useEffect(() => { foo() }, []); const foo = () => { bar() }; function bar () { foo() } }" ,
24372472 ] ;
24382473
24392474 let fail = vec ! [
0 commit comments