Of React’s 3,529 analyzed functions, 402 are rated critical — and the five highest-risk hotspots are all concentrated in two actively developed subsystems: the React Compiler’s HIR builder (BuildHIR.ts) and the eslint-plugin-react-hooks exhaustive-deps rule (ExhaustiveDeps.ts). The top-ranked function, lowerStatement, sits in the “fire” quadrant with a cyclomatic complexity of 150 and a recent commit activity of 20.2, meaning it is both structurally extreme and actively changing right now — a live regression risk, not a backlog cleanup item. Every one of the top five functions shares the same pattern fingerprint: god-function, complex branching, deep nesting, exit-heavy, and long — a consistent structural signature across two of React’s most actively evolved components.
BuildHIR.ts is where React’s new compiler does its heaviest lifting: three of the top five hotspots in this analysis live in that single file, each responsible for translating a different syntactic category into the compiler’s high-level IR. The other two sit in ExhaustiveDeps.ts, the exhaustive-deps lint rule’s core analysis logic. Both files are under active development simultaneously — making this a story of two packages accumulating structural debt in real time, not dormant code waiting to be cleaned up.
The table below ranks functions by activity-weighted risk — a score that multiplies structural complexity by recent commit frequency. A function that is both hard to understand (high cyclomatic complexity) and actively changing is a higher priority than one that is complex but untouched. CC = cyclomatic complexity (independent execution paths); ND = max nesting depth; FO = fan-out (distinct callees).
Top 5 Hotspots
| Function | File | Risk | CC | ND | FO |
|---|---|---|---|---|---|
lowerStatement | compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts | 25.4 | 150 | 8 | 63 |
lowerExpression | compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts | 23.8 | 141 | 6 | 76 |
lowerAssignment | compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts | 23.6 | 72 | 6 | 42 |
visitFunctionWithDependencies | packages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts | 20.9 | 131 | 10 | 74 |
create | packages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts | 20.8 | 125 | 10 | 89 |
Large Repo Analysis
react is a large repository. To stay within memory constraints, this analysis used hybrid touch mode: structural complexity — CC, ND, FO — is measured precisely for every function. Git activity is tracked at the function level (via git log -L) only for files with 5 or more commits in the last 30 days; other files use a file-level approximation. Rankings therefore surface functions that are both structurally complex and in the most actively-changing parts of the codebase. Dormant code with high structural complexity will rank lower than it would under a full per-function analysis — to surface it, run hotspots analyze . --per-function-touches on a machine with sufficient memory.
Hotspot Analysis
lowerStatement — compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts
CC 150. That number means 150 independent execution paths — one for every JavaScript statement type the compiler’s IR builder must handle. With nesting depth 8 and fan-out 63, lowerStatement has become the central routing table for BuildHIR.ts: every statement form added to JavaScript’s surface syntax lands here, adding branches that compound the existing count. Its activity risk of 25.4 is the highest in the repo, and it is being actively modified — complex code that is changing now, not later.
Recommendation: Write characterization tests scoped to individual statement types before any further feature work touches this function — the absence of a targeted test net is the most acute risk. Then apply extract-method refactoring to isolate each statement category (loops, conditionals, try/catch, declarations) into dedicated lower* helpers, reducing the CC-150 surface into individually testable units.
lowerExpression — compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts
Where lowerStatement is broad, lowerExpression is deeply coupled: its fan-out of 76 — the highest in this dataset — means a change here propagates through more downstream components than any other hotspot. At CC 141 and nesting depth 6, it handles the full expression surface of the language with the same accumulation pattern as its neighbor. The two functions are being modified in parallel, which compounds the risk: when statement-lowering and expression-lowering changes land in the same release, the blast radius overlaps across 63 and 76 callees respectively.
Before refactoring, map the 76 callees via fan-out analysis to identify which belong to the same conceptual cluster. Then extract expression-category sub-functions (member expressions, call expressions, literals) as independent units — this reduces both CC and coupling before the next compiler feature lands.
lowerAssignment — compiler/packages/babel-plugin-react-compiler/src/HIR/BuildHIR.ts
The third BuildHIR.ts function handles assignment expressions specifically: simple assignment, destructuring, compound assignment, optional chaining targets. CC 72 and fan-out 42 are lower than its neighbors but qualify as a god function by any reasonable threshold, and the fire-quadrant placement means it is changing alongside them. The priority here is coordination rather than isolated refactoring — start by extracting destructuring and compound-assignment branches, and use that work to surface shared utilities that may also simplify lowerStatement and lowerExpression in the same pass.
visitFunctionWithDependencies — packages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts
This function orchestrates the exhaustive-deps rule’s core analysis: it walks a hook’s callback, resolves its dependency scope, and validates the dependency array. CC 131 is severe, but the defining metric here is nesting depth of 10 — the deepest in this dataset. Ten control-structure levels means the innermost logic is ten conditional frames removed from the function signature, making local reasoning unreliable and test coverage hard to reason about without full execution traces.
Recommendation: Nesting depth is the most actionable signal. Identify the innermost nested blocks and extract them into named helper functions with clear input contracts — this makes the dependency-resolution logic independently unit-testable without exercising the full visitor path. Each extracted helper will inherit a narrower scope of callee dependencies, reducing both ND and effective coupling per unit.
create — packages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts
create is the rule factory — the function ESLint calls to instantiate the exhaustive-deps rule’s visitor object. At CC 125 and fan-out 89, the highest callout count in this dataset, it has become the coordination hub for the entire rule. Unlike most entry points that delegate immediately, create has absorbed significant behavioral logic alongside its initialization role, making it both a structural hotspot and a coupling bottleneck: nearly every dependency-tracking path in the rule connects through this function.
Audit which of the 89 callees form cohesive sub-responsibilities — scope analysis, dependency tracking, write detection — and extract each into a dedicated visitor or helper. This reduces CC and coupling simultaneously and makes individual rule behaviors testable without instantiating the full rule factory.
Patterns Found
Antipatterns detected across the top functions in this snapshot:
| Pattern | Occurrences |
|---|---|
complex_branching | 5 |
deeply_nested | 5 |
exit_heavy | 5 |
god_function | 5 |
long_function | 5 |
cyclic_hub | 1 |
These labels belong to two tiers — Tier 1 (structural): complex_branching, deeply_nested, exit_heavy, long_function, god_function. Tier 2 (relational/temporal): hub_function, cyclic_hub, middle_man, neighbor_risk, stale_complex, churn_magnet, shotgun_target, volatile_god.
Reproduce This Analysis
git clone https://github.com/facebook/react
cd react
git checkout ad5dfc82b7107728da1430dd142f75b97b684dac
hotspots analyze . --mode snapshot --explain-patterns --force --hybrid-touches 5
To run the same analysis on your own codebase, run hotspots analyze . --mode snapshot in any local git repo — no configuration required.
Hotspots highlights structural and activity risk — not “bad code.” Findings are a prioritization aid, not a bug predictor. Editorial policy →