Skip to content

Update FileTypeMapper name scope with use statements encountered after scope creation#5714

Closed
phpstan-bot wants to merge 1 commit into
phpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-i4o8ws7
Closed

Update FileTypeMapper name scope with use statements encountered after scope creation#5714
phpstan-bot wants to merge 1 commit into
phpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-i4o8ws7

Conversation

@phpstan-bot
Copy link
Copy Markdown
Collaborator

Summary

When use statements appear after a comment-only PHP block (e.g. <?php // comment ?>) followed by inline HTML, PHPStan failed to resolve class names in PHPDocs through those use statements. The error message showed unresolved class names (e.g. myClass instead of path\to\myClass).

Changes

  • Modified src/Type/FileTypeMapper.php: After processing Use_ and GroupUse nodes, if the current name scope key already exists in $nameScopeMap, replace it with an updated IntermediaryNameScope that includes the newly collected $uses and $constUses.
  • The Use_ and GroupUse branches are now combined under a single elseif condition to share the name scope update logic.
  • Added regression test in tests/PHPStan/Rules/PhpDoc/InvalidPhpDocVarTagTypeRuleTest.php and tests/PHPStan/Rules/PhpDoc/data/bug-14648.php.

Root cause

FileTypeMapper::createPhpDocNodeMap() walks the AST depth-first and creates a name scope entry at the first non-excluded statement for each scope key (file-level, class-level, function-level). The entry captures the current $uses map at creation time and is never updated afterward.

In template-style PHP files like:

<?php // comment ?>
<p>HTML</p>
<?php
use Foo\Bar;
/** @var Bar $x */
$x = new Bar;

The AST contains a Nop node (from the comment), then InlineHTML (excluded), then Use_ (excluded), then the expression. The Nop node creates the name scope entry with an empty $uses map before the Use_ node is processed. Once the Use_ adds to $uses, the already-created entry is stale.

The fix updates the name scope entry whenever new use statements are encountered, ensuring the entry always reflects the complete set of imports.

Test

  • testBug14648: Regression test with a PHP template file containing <?php // comment ?>, inline HTML, then use Bug14648Helper\MyClass; followed by a @var MyClass PHPDoc. Verifies the error message correctly shows the resolved class name Bug14648Helper\MyClass instead of the unresolved MyClass.
  • Verified existing tests testBug4486 and testBug4486Namespace still pass (these test PHPDocs appearing before use statements within a namespace).

Fixes phpstan/phpstan#14648

…after scope creation

- In `FileTypeMapper::createPhpDocNodeMap()`, the name scope entry for a
  file/namespace was created at the first non-excluded statement (e.g. a
  `Nop` node from `<?php // comment ?>`). If `use` statements appeared
  later in the file, they were collected into `$uses` but the already-
  created name scope entry was never updated.
- Fix: after processing `Use_` and `GroupUse` nodes, check if the current
  name scope key already exists in the map and replace it with an updated
  entry containing the newly collected `$uses` and `$constUses`.
- This affects template-style PHP files where inline HTML separates a
  comment-only PHP block from a later PHP block containing `use` statements.
- All PHPDoc tags (@var, @param, @return, @throws, @phpstan-assert, etc.)
  benefit from this fix since they all resolve names through the same
  `FileTypeMapper` name scope map.
@staabm
Copy link
Copy Markdown
Contributor

staabm commented May 19, 2026

bot got 1 step too far :)

grafik

@staabm staabm closed this May 19, 2026
@staabm staabm deleted the create-pull-request/patch-i4o8ws7 branch May 19, 2026 15:52
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.

2 participants