Skip to content

Commit 27481c3

Browse files
committed
Reworked @var support so that view files can be analysed successfully
1 parent d41f065 commit 27481c3

File tree

9 files changed

+74
-32
lines changed

9 files changed

+74
-32
lines changed

src/Analyser/MutatingScope.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,11 @@ public function enterDeclareStrictTypes(): self
292292
{
293293
return $this->scopeFactory->create(
294294
$this->context,
295-
true
295+
true,
296+
[],
297+
null,
298+
null,
299+
$this->variableTypes
296300
);
297301
}
298302

src/Analyser/NodeScopeResolver.php

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -336,21 +336,19 @@ private function processStmtNode(
336336
): StatementResult
337337
{
338338
if (
339-
$stmt instanceof Echo_
340-
|| (
341-
$stmt instanceof Node\Stmt\Expression
342-
&& !$stmt->expr instanceof Assign && !$stmt->expr instanceof AssignRef
343-
)
344-
|| $stmt instanceof If_
345-
|| $stmt instanceof While_
346-
|| $stmt instanceof Switch_
347-
) {
348-
$scope = $this->processStmtVarAnnotation($scope, $stmt, null);
349-
} elseif (
350339
$stmt instanceof Throw_
351340
|| $stmt instanceof Return_
352341
) {
353342
$scope = $this->processStmtVarAnnotation($scope, $stmt, $stmt->expr);
343+
} elseif (
344+
!$stmt instanceof Static_
345+
&& !$stmt instanceof Foreach_
346+
&& (
347+
!$stmt instanceof Node\Stmt\Expression
348+
|| !$stmt->expr instanceof Assign && !$stmt->expr instanceof AssignRef
349+
)
350+
) {
351+
$scope = $this->processStmtVarAnnotation($scope, $stmt, null);
354352
}
355353

356354
if ($stmt instanceof Node\Stmt\ClassMethod) {

src/Type/FileTypeMapper.php

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ private function shouldPhpDocNodeBeCachedToDisk(PhpDocNode $phpDocNode): bool
202202
private function getResolvedPhpDocMap(string $fileName): array
203203
{
204204
if (!isset($this->memoryCache[$fileName])) {
205-
$cacheKey = sprintf('%s-phpdocstring-v2', $fileName);
205+
$cacheKey = sprintf('%s-phpdocstring-v3', $fileName);
206206
$variableCacheKey = implode(',', array_map(static function (array $file): string {
207207
return sprintf('%s-%d', $file['filename'], $file['modifiedTime']);
208208
}, $this->getCachedDependentFilesWithTimestamps($fileName)));
@@ -353,12 +353,10 @@ function (\PhpParser\Node $node) use ($fileName, $lookForTrait, $traitMethodAlia
353353
return null;
354354
} elseif ($node instanceof \PhpParser\Node\Stmt\Namespace_) {
355355
$namespace = (string) $node->name;
356-
return null;
357356
} elseif ($node instanceof \PhpParser\Node\Stmt\Use_ && $node->type === \PhpParser\Node\Stmt\Use_::TYPE_NORMAL) {
358357
foreach ($node->uses as $use) {
359358
$uses[strtolower($use->getAlias()->name)] = (string) $use->name;
360359
}
361-
return null;
362360
} elseif ($node instanceof \PhpParser\Node\Stmt\GroupUse) {
363361
$prefix = (string) $node->prefix;
364362
foreach ($node->uses as $use) {
@@ -368,7 +366,6 @@ function (\PhpParser\Node $node) use ($fileName, $lookForTrait, $traitMethodAlia
368366

369367
$uses[strtolower($use->getAlias()->name)] = sprintf('%s\\%s', $prefix, (string) $use->name);
370368
}
371-
return null;
372369
} elseif ($node instanceof Node\Stmt\ClassMethod) {
373370
$functionName = $node->name->name;
374371
if (array_key_exists($functionName, $traitMethodAliases)) {
@@ -385,22 +382,11 @@ function (\PhpParser\Node $node) use ($fileName, $lookForTrait, $traitMethodAlia
385382
$resolvableTemplateTypes = true;
386383
} elseif ($node instanceof Node\Stmt\Property) {
387384
$resolvableTemplateTypes = true;
388-
} elseif (!in_array(get_class($node), [
389-
Node\Stmt\Foreach_::class,
390-
Node\Expr\Assign::class,
391-
Node\Expr\AssignRef::class,
392-
Node\Stmt\Class_::class,
393-
Node\Stmt\ClassConst::class,
394-
Node\Stmt\Static_::class,
395-
Node\Stmt\Echo_::class,
396-
Node\Stmt\Return_::class,
397-
Node\Stmt\Expression::class,
398-
Node\Stmt\Throw_::class,
399-
Node\Stmt\If_::class,
400-
Node\Stmt\While_::class,
401-
Node\Stmt\Switch_::class,
402-
Node\Stmt\Nop::class,
403-
], true)) {
385+
} elseif (
386+
!$node instanceof Node\Stmt
387+
&& !$node instanceof Node\Expr\Assign
388+
&& !$node instanceof Node\Expr\AssignRef
389+
) {
404390
return null;
405391
}
406392

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10710,6 +10710,16 @@ public function dataBug4351(): array
1071010710
return $this->gatherAssertTypes(__DIR__ . '/data/bug-4351.php');
1071110711
}
1071210712

10713+
public function dataVarAboveUse(): array
10714+
{
10715+
return $this->gatherAssertTypes(__DIR__ . '/data/var-above-use.php');
10716+
}
10717+
10718+
public function dataVarAboveDeclare(): array
10719+
{
10720+
return $this->gatherAssertTypes(__DIR__ . '/data/var-above-declare.php');
10721+
}
10722+
1071310723
/**
1071410724
* @param string $file
1071510725
* @return array<string, mixed[]>
@@ -10917,6 +10927,8 @@ private function gatherAssertTypes(string $file): array
1091710927
* @dataProvider dataBug4343
1091810928
* @dataProvider dataImpureMethod
1091910929
* @dataProvider dataBug4351
10930+
* @dataProvider dataVarAboveUse
10931+
* @dataProvider dataVarAboveDeclare
1092010932
* @param string $assertType
1092110933
* @param string $file
1092210934
* @param mixed ...$args
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
/**
4+
* @var string $foo
5+
*/
6+
7+
declare(strict_types = 1);
8+
9+
\PHPStan\Analyser\assertVariableCertainty(\PHPStan\TrinaryLogic::createYes(), $foo);
10+
\PHPStan\Analyser\assertType('string', $foo);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
/**
4+
* @var string $foo
5+
*/
6+
7+
use Foo\Bar\Baz;
8+
9+
\PHPStan\Analyser\assertVariableCertainty(\PHPStan\TrinaryLogic::createYes(), $foo);
10+
\PHPStan\Analyser\assertType('string', $foo);

tests/PHPStan/Rules/PhpDoc/WrongVariableNameInVarTagRuleTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,14 @@ public function testEmptyFileWithVarThis(): void
9090
$this->analyse([__DIR__ . '/data/wrong-variable-name-var-empty-this.php'], []);
9191
}
9292

93+
public function testAboveUse(): void
94+
{
95+
$this->analyse([__DIR__ . '/data/var-above-use.php'], []);
96+
}
97+
98+
public function testAboveDeclare(): void
99+
{
100+
$this->analyse([__DIR__ . '/data/var-above-declare.php'], []);
101+
}
102+
93103
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
/**
4+
* @var string $foo
5+
*/
6+
7+
declare(strict_types = 1);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
/** @var string $foo */
4+
5+
use Foo\Bar\Baz;

0 commit comments

Comments
 (0)