Skip to content

[perf] Cache resolved used names per version in UnusedImportRemovingPostRector - #8702

Merged
TomasVotruba merged 1 commit into
mainfrom
tv-cache-unused-import-used-names
Oct 18, 2026
Merged

TomasVotruba merged 1 commit into
mainfrom
tv-cache-unused-import-used-names

Conversation

@TomasVotruba

Copy link
Copy Markdown
Member

Follow-up to #8701.

Why

To find unused use imports, UnusedImportRemovingPostRector::enterNode() resolves every name referenced in the file via two full-AST traversals (findNonUseImportNames + findNamesInDocBlocks). That resolution was recomputed on every call.

The post-rector chain re-runs this node across the file convergence iterations. On the iterations where the stmts did not change, the exact same name set was resolved again from scratch.

What

Cache the resolved names per (file, stmts version):

  • a new getNewStmtsVersion() re-resolves (stmts changed - the referenced names may differ)
  • an unchanged version reuses the previous result
  • the cache resets when the file changes, so it never leaks across files or serves a stale map

Removing unused use statements does not change the referenced-name set, and any rule that does change the body bumps the stmts version - so the version key stays correct.

Bench

bench/unused_import_removing_bench.php re-enters the same unchanged node (stable version), which is the ceiling case where every re-entry after the first is a cache hit. 40 repeats x 400 enters:

CPU
before (#8701 guard) ~11.7s
after (version cache) ~0.14s

The bench shows the ceiling; the real-world saving is the resolve cost on every convergence iteration after the first where the stmts are unchanged.

Tests

tests/Issues (incl. NamespacedUse, NoNamespaced, NamespacedUseAutoImport), rules-tests/CodingStyle, rules-tests/Renaming all green. ECS and PHPStan level 8 clean on the changed file.

…ostRector

To find unused `use` imports, enterNode() resolves every referenced name via
two full-AST traversals (findNonUseImportNames + findNamesInDocBlocks), and
that resolution was recomputed on every call. The post-rector chain re-runs
this node across the file convergence iterations, so on iterations where the
stmts did not change the same names were resolved again from scratch.

Cache the resolved names per (file, stmts version): a new version re-resolves,
an unchanged one reuses the previous result. The cache is reset when the file
changes, so it never leaks across files or serves a stale map.

Extends bench/unused_import_removing_bench.php (sets the file so the cached
path is exercised).
@TomasVotruba
TomasVotruba merged commit 8a4dc70 into main Oct 18, 2026
49 checks passed
@TomasVotruba
TomasVotruba deleted the tv-cache-unused-import-used-names branch October 18, 2026 20:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant