Skip to content

Commit 988acfc

Browse files
github-actions[bot]phpstan-bot
authored andcommitted
Fix use imports ignored in trait PHPDoc when statement precedes use declarations
- 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
1 parent 2681e50 commit 988acfc

5 files changed

Lines changed: 118 additions & 0 deletions

File tree

src/Type/FileTypeMapper.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,7 @@ function (Node $node) use ($fileName, $lookForTrait, &$traitFound, $traitMethodA
542542
&& !($node instanceof Node\Stmt\Expression && $node->expr instanceof Node\Expr\Include_)
543543
)
544544
) && !array_key_exists($nameScopeKey, $nameScopeMap)
545+
&& ($lookForTrait === null || $traitFound)
545546
) {
546547
$parentNameScope = array_last($typeMapStack) ?? null;
547548
$typeAliasesMap = array_last($typeAliasStack) ?? [];
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug12639\Types;
4+
5+
/** @template T */
6+
class ObjectRefT
7+
{
8+
/** @var T */
9+
public $value;
10+
}
11+
12+
namespace Bug12639\Accounts;
13+
14+
class Account
15+
{
16+
}
17+
18+
namespace Bug12639\Policy;
19+
20+
if (true) {
21+
// some statement before use declarations
22+
}
23+
24+
use Bug12639\Types\ObjectRefT;
25+
use Bug12639\Accounts\Account;
26+
use function PHPStan\Testing\assertType;
27+
28+
trait BaseAccount
29+
{
30+
/**
31+
* @var ObjectRefT<Account>
32+
*/
33+
protected ObjectRefT $account;
34+
}
35+
36+
class StandardAccount
37+
{
38+
use BaseAccount;
39+
40+
public function doTest(): void
41+
{
42+
assertType('Bug12639\Types\ObjectRefT<Bug12639\Accounts\Account>', $this->account);
43+
}
44+
}
45+
46+
namespace Bug12639\OtherPlace;
47+
48+
use Bug12639\Policy\BaseAccount;
49+
use function PHPStan\Testing\assertType;
50+
51+
class AnotherUser
52+
{
53+
use BaseAccount;
54+
55+
public function doTest(): void
56+
{
57+
assertType('Bug12639\Types\ObjectRefT<Bug12639\Accounts\Account>', $this->account);
58+
}
59+
}

tests/PHPStan/Type/FileTypeMapperTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,36 @@ public function testFileWithCyclicPhpDocs(): void
196196
$this->assertSame('CyclicPhpDocs\Foo|iterable<CyclicPhpDocs\Foo>', $returnTag->getType()->describe(VerbosityLevel::precise()));
197197
}
198198

199+
public function testBug12639TraitPropertyPhpDocResolution(): void
200+
{
201+
self::createReflectionProvider();
202+
203+
/** @var FileTypeMapper $fileTypeMapper */
204+
$fileTypeMapper = self::getContainer()->getByType(FileTypeMapper::class);
205+
206+
$classRealpath = realpath(__DIR__ . '/data/bug-12639-class.php');
207+
if ($classRealpath === false) {
208+
throw new ShouldNotHappenException();
209+
}
210+
211+
$resolved = $fileTypeMapper->getResolvedPhpDoc(
212+
$classRealpath,
213+
'Bug12639Separate\OtherPlace\StandardAccount',
214+
'Bug12639Separate\Policy\BaseAccount',
215+
null,
216+
'/**
217+
* @var ObjectRefT<Account>
218+
*/',
219+
);
220+
221+
$varTags = $resolved->getVarTags();
222+
$this->assertArrayHasKey(0, $varTags);
223+
$this->assertSame(
224+
'Bug12639Separate\Types\ObjectRefT<Bug12639Separate\Accounts\Account>',
225+
$varTags[0]->getType()->describe(VerbosityLevel::precise()),
226+
);
227+
}
228+
199229
public function testFilesWithIdenticalPhpDocsUsingDifferentAliases(): void
200230
{
201231
/** @var FileTypeMapper $fileTypeMapper */
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug12639Separate\OtherPlace;
4+
5+
use Bug12639Separate\Policy\BaseAccount;
6+
7+
class StandardAccount
8+
{
9+
use BaseAccount;
10+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug12639Separate\Policy;
4+
5+
if (true) {
6+
// some statement before use declarations
7+
}
8+
9+
use Bug12639Separate\Types\ObjectRefT;
10+
use Bug12639Separate\Accounts\Account;
11+
12+
trait BaseAccount
13+
{
14+
/**
15+
* @var ObjectRefT<Account>
16+
*/
17+
protected ObjectRefT $account;
18+
}

0 commit comments

Comments
 (0)