Answer per node class what resolveDependencies() can reach - #6478
Merged
Merged
Conversation
SanderMuller
force-pushed
the
node-profile-on-6475
branch
from
September 19, 2026 16:44
508a666 to
f648845
Compare
84.4 percent of the calls produce nothing at all: 648270 of 767955 on a phpstan-src src/ analysis return no reflections and no file paths, after walking all 29 branches of the chain to find out. The most frequent nodes are Expr\Variable, Arg, MethodCallExpressionNode and VariableAssignNode, and no branch matches any of them. Every question the method asks about a node depends only on its class, so the answer is computed once per class and reused: whether it can carry a @var tag, whether a branch matches it, whether it can produce an exported node, and whether it changes the PHPDoc name scope. There are 152 distinct node classes in the run. resolveDependencies() goes from 1.528s to 1.131s, 26 percent, on a single-process src/ analysis of about 61s. The analysis output is identical. Each of the three node-class lists mirrors a chain of instanceof checks somewhere else, and a branch added without an entry in its list would silently stop producing dependencies - a stale result cache rather than a failing test. NodeProfileMirrorsBranchesTest reads the lists back out of the source they mirror. It found four dead entries in the first version of this commit: a class member reaches ExportedNodeResolver through exportClassStatement(), never through resolve(). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
SanderMuller
force-pushed
the
node-profile-on-6475
branch
from
September 19, 2026 16:59
f648845 to
d0879cf
Compare
VincentLanglet
approved these changes
Sep 19, 2026
Member
|
Thank you! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #6475, in the same place. That one halved the work on the reading side; this one is
about the calls that reach it with nothing to say.
resolveDependencies()runs once per analysed node, and 84.4% of those calls produce nothing atall. On a
src/analysis of this repo, 648270 of 767955 return no reflections and no file paths.They walk all 29 branches of the chain to find that out. The most frequent nodes are
Expr\Variable,Arg,MethodCallExpressionNodeandVariableAssignNode, and no branch matchesany of them.
Every question the method asks about a node depends only on the node's class.
Can it carry a
@vartag, does a branch match it, can it produce an exported node, does it changethe PHPDoc name scope. So the answer is computed once per class and reused. A run
over
src/sees 152 distinct node classes.Numbers
Single process (
--debug), 1975 files, PHP 8.5.8, no turbo,hrtime()accumulator aroundresolveDependencies(). Three rounds, medians, base spread 1.5247-1.5279s:resolveDependencies()That is 0.40s of a 61s run, so 0.65% of it. Whole-run timings cannot separate the two arms, which is
why the figure comes from inside the method.
The lists mirror code elsewhere, so a test reads them back
Each of the three node-class lists mirrors a chain of
instanceofchecks in another method. A branchadded without an entry in its list would silently stop producing dependencies, which leaves a stale
result cache rather than a failing test.
NodeProfileMirrorsBranchesTestparses the three methodsand compares them to the constants.
It failed on its first run, which is the reason it is here.
The export list named
ClassMethod,Property,ClassConstandEnumCase.ExportedNodeResolver::resolve()handles none of them.A class member is exported through
exportClassStatement(), as part of the class declaring it.Dropping the four made this faster as well as correct.
Verification
src/run.file is re-analysed, the changed one, in both directions, and a second run is 0. A different
dependency graph or a different set of exported nodes could not produce that.
make testspasses, 21541 tests.make phpstanand phpcs are clean.e2e/result-cache-*scripts were run per case on both arms. Four fail on this machine, and thesame four fail identically on the base branch, so I can report no difference between the arms
rather than a clean local run. They need CI.