Skip to content

[perf] Collect short names in a single AST walk in ShortNameResolver - #8700

Merged
TomasVotruba merged 1 commit into
mainfrom
tv-short-name-single-walk
Oct 18, 2026
Merged

TomasVotruba merged 1 commit into
mainfrom
tv-short-name-single-walk

Conversation

@TomasVotruba

Copy link
Copy Markdown
Member

Why

ShortNameResolver::resolveFromFile() builds the shortName => FQN map that feeds the use-import conflict checks in ClassNameImportSkipper. It built that map with two separate full-AST traversals of the same stmts:

  • one for ClassLike + Name nodes
  • one for docblock short names (PhpDocInfo per node)

The map is version-cached, so during the file convergence loop it is rebuilt once per stmts-version bump - paying for two full traversals each time.

What

Merge both into a single traversal. Docblock short names are collected in the same callback, then fqnized and merged afterwards. The result is byte-for-byte identical, the stmts tree is walked once instead of twice.

Bench

Adds bench/short_name_resolver_traversal_bench.php, which forces a re-resolve on every call (no cache hits) to isolate the rebuild cost. Measured on the name-heavy bench/Source/ManyNamesSource.php fixture, 40 repeats x 200 rebuilds, CPU time:

CPU
before (2 walks) ~21.1s
after (1 walk) ~19.8s

~6% on this fixture. The per-node PhpDocInfo build still dominates the docblock pass, so the saving is the second raw-traversal pass itself.

Tests

rules-tests/CodingStyle/ClassNameImport + tests/Issues + Import/ShortName/Namespace filters all green. ECS and PHPStan level 8 clean.

resolveFromFile() built its short-name map with two separate full-AST
traversals of the same stmts - one for class-like and Name nodes, one for
docblock short names. The map is version-cached, so during a convergence
loop it is rebuilt once per stmts-version bump, paying for two traversals
each time.

Merge both into a single traversal: the docblock short names are collected
in the same callback, then fqnized and merged afterwards. Result is
identical, the stmts tree is walked once instead of twice.

Adds bench/short_name_resolver_traversal_bench.php, which forces a
re-resolve on every call to isolate the rebuild cost.
@TomasVotruba
TomasVotruba force-pushed the tv-short-name-single-walk branch from 21ec2dd to cd96b35 Compare October 18, 2026 20:06
@TomasVotruba
TomasVotruba enabled auto-merge (squash) October 18, 2026 20:06
@TomasVotruba
TomasVotruba merged commit 07cfb5a into main Oct 18, 2026
49 checks passed
@TomasVotruba
TomasVotruba deleted the tv-short-name-single-walk branch October 18, 2026 20:07
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