Skip to content

Preserve complete PHPDoc name scopes across partial analyses - #6739

Open
drewmt wants to merge 2 commits into
phpstan:2.3.xfrom
drewmt:fix/phpdoc-name-scope-cache
Open

drewmt wants to merge 2 commits into
phpstan:2.3.xfrom
drewmt:fix/phpdoc-name-scope-cache

Conversation

@drewmt

@drewmt drewmt commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Fixes phpstan/phpstan#15475

FileTypeMapper caches name scopes by file contents, but its parser currently depends on which paths are being analysed. When a file is only scanned for symbols, CleaningParser removes function bodies, including classes declared inside them. The incomplete name-scope map survives later full analyses because the file has not changed. In the reported example, the anonymous class constructor loses its Closure(string): list<string> PHPDoc, and search() is incorrectly reported as returning mixed.

Use a separate parser route for FileTypeMapper that always retains the full AST. It shares the existing cached rich parser and preserves the PHP 8 parser route for version-independent stub files. Normal analysis/reflection routing and the explicit stub-file mapper remain unchanged. Bump the name-scope cache format to v8 so existing incomplete entries are rebuilt rather than reused.

The E2E regression checks a cold full analysis, then a partial analysis followed by a full analysis with the same PHPDoc cache. It fails before the fix with return.type and passes afterward. The workflow runs it on PHP 8.3 and with Turbo enabled.

Validation on the current 2.3.x base (62ed20078):

  • Regression E2E passes on PHP 8.3.33, PHP 8.4.12 and active Turbo.
  • An existing v7 cache reproduces the error before the fix and is recovered by v8 without deleting the cache.
  • Full suite: PHP 8.4 and Turbo each 22,460 tests / 96,882 assertions / 106 existing skips; PHP 8.3 22,313 tests / 96,633 assertions / 204 existing skips.
  • FileTypeMapperTest: 6 tests / 90 assertions.
  • Self-analysis passes with and without Turbo; scoped PHPCS, PHP syntax, Bash syntax, workflow YAML parsing and actionlint 1.7.12 pass.
  • Strict native build, smoke tests, signature parity (16,390 members), method parity and identical regression CLI output pass. No native source changed, so the extension version remains unchanged.

To reproduce the regression test:

bash e2e/result-cache-name-scopes/test.sh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PHPDoc of a class declared inside a function is lost once an analysis of other paths has cached that file's name scopes

1 participant