Skip to content

Fix #12639: phpstan ignoring use paths in trait context#5081

Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-zpo5ljv
Open

Fix #12639: phpstan ignoring use paths in trait context#5081
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-zpo5ljv

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

When a trait file has a statement (like if (!defined('Foo')) die();) before use declarations, PHPStan incorrectly resolves PHPDoc types in trait properties using the current namespace instead of the imported class names. This caused false-positive "unknown class" errors where the class name was resolved to the wrong namespace.

Changes

  • Added condition && ($lookForTrait === null || $traitFound) in src/Type/FileTypeMapper.php (line 545) to prevent premature name scope map entry creation when recursively processing trait files
  • New NSRT regression test: tests/PHPStan/Analyser/nsrt/bug-12639.php
  • New FileTypeMapper unit test: testBug12639TraitPropertyPhpDocResolution in tests/PHPStan/Type/FileTypeMapperTest.php
  • New test data files: tests/PHPStan/Type/data/bug-12639-trait.php and tests/PHPStan/Type/data/bug-12639-class.php

Root cause

In FileTypeMapper::createPhpDocNodeMap(), when recursively processing a trait file (with $lookForTrait set), any statement encountered before the trait declaration would trigger creation of a name scope map entry with the current (incomplete) $uses array. Since the $uses array hadn't been populated yet (the use declarations come after the statement), the entry was created with empty imports. The !array_key_exists($nameScopeKey, $nameScopeMap) guard prevented the correct entry from being created later when the trait was actually found and $uses was properly populated.

The fix adds a check that skips name scope entry creation for statements that appear before the target trait is found during recursive trait file processing.

Test

  • NSRT test (bug-12639.php): Verifies that @var ObjectRefT<Account> in a trait with if (true) {} before use declarations correctly resolves to Bug12639\Types\ObjectRefT<Bug12639\Accounts\Account> both in the same namespace and from a different namespace
  • FileTypeMapper test: Directly tests getResolvedPhpDoc() with a trait in a separate file that has a statement before use declarations, verifying the PHPDoc type is resolved using the trait's imports

Fixes phpstan/phpstan#12639

…eclarations

- When a trait file had a statement (e.g. `if/die`) before `use` declarations,
  FileTypeMapper::createPhpDocNodeMap() would create a premature name scope
  entry with empty `$uses` for non-trait statements during recursive trait
  processing, preventing the correct entry from being created later
- Added condition to skip name scope map entries for statements before the
  trait is found during recursive trait file processing ($lookForTrait)
- New regression tests in FileTypeMapperTest, NSRT, and test data files

Closes phpstan/phpstan#12639
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.

1 participant