Skip to content

Commit 745d02b

Browse files
committed
Adjust rules for GeneratorScope
1 parent 65c10b7 commit 745d02b

12 files changed

+144
-58
lines changed

src/Analyser/MutatingScope.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
use PHPStan\Node\Expr\GetIterableKeyTypeExpr;
3434
use PHPStan\Node\Expr\GetIterableValueTypeExpr;
3535
use PHPStan\Node\Expr\GetOffsetValueTypeExpr;
36+
use PHPStan\Node\Expr\IdentifiedTypeExpr;
3637
use PHPStan\Node\Expr\IntertwinedVariableByReferenceWithExpr;
3738
use PHPStan\Node\Expr\NativeTypeExpr;
3839
use PHPStan\Node\Expr\OriginalForeachKeyExpr;
@@ -894,6 +895,10 @@ private function resolveType(string $exprString, Expr $node): Type
894895
return $this->expressionTypes[$exprString]->getType();
895896
}
896897

898+
if ($node instanceof IdentifiedTypeExpr) {
899+
return $node->getExprType();
900+
}
901+
897902
if ($node instanceof AlwaysRememberedExpr) {
898903
return $this->nativeTypesPromoted ? $node->getNativeExprType() : $node->getExprType();
899904
}

src/Analyser/RicherScopeGetTypeHelper.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PhpParser\Node;
66
use PhpParser\Node\Expr\BinaryOp\Identical;
77
use PhpParser\Node\Expr\Variable;
8+
use PHPStan\Analyser\Generator\GeneratorScope;
89
use PHPStan\DependencyInjection\AutowiredService;
910
use PHPStan\Reflection\InitializerExprTypeResolver;
1011
use PHPStan\Rules\Properties\PropertyReflectionFinder;
@@ -42,7 +43,7 @@ public function getIdenticalResult(Scope $scope, Identical $expr): TypeResult
4243
$leftType = $scope->getType($expr->left);
4344
$rightType = $scope->getType($expr->right);
4445

45-
if (!$scope instanceof MutatingScope) {
46+
if (!$scope instanceof MutatingScope && !$scope instanceof GeneratorScope) {
4647
return $this->initializerExprTypeResolver->resolveIdenticalType($leftType, $rightType);
4748
}
4849

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Node\Expr;
4+
5+
use Override;
6+
use PhpParser\Node\Expr;
7+
use PHPStan\Node\VirtualNode;
8+
use PHPStan\Type\Type;
9+
10+
/**
11+
* @api
12+
*/
13+
final class IdentifiedTypeExpr extends Expr implements VirtualNode
14+
{
15+
16+
/** @api */
17+
public function __construct(private Type $exprType, public Expr $expr)
18+
{
19+
parent::__construct();
20+
}
21+
22+
public function getExprType(): Type
23+
{
24+
return $this->exprType;
25+
}
26+
27+
#[Override]
28+
public function getType(): string
29+
{
30+
return 'PHPStan_Node_IdentifiedTypeExpr';
31+
}
32+
33+
/**
34+
* @return string[]
35+
*/
36+
#[Override]
37+
public function getSubNodeNames(): array
38+
{
39+
return ['expr'];
40+
}
41+
42+
}

src/Node/Printer/Printer.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PHPStan\Node\Expr\GetIterableKeyTypeExpr;
1111
use PHPStan\Node\Expr\GetIterableValueTypeExpr;
1212
use PHPStan\Node\Expr\GetOffsetValueTypeExpr;
13+
use PHPStan\Node\Expr\IdentifiedTypeExpr;
1314
use PHPStan\Node\Expr\IntertwinedVariableByReferenceWithExpr;
1415
use PHPStan\Node\Expr\NativeTypeExpr;
1516
use PHPStan\Node\Expr\OriginalForeachKeyExpr;
@@ -41,6 +42,11 @@ protected function pPHPStan_Node_NativeTypeExpr(NativeTypeExpr $expr): string //
4142
return sprintf('__phpstanNativeType(%s, %s)', $expr->getPhpDocType()->describe(VerbosityLevel::precise()), $expr->getNativeType()->describe(VerbosityLevel::precise()));
4243
}
4344

45+
protected function pPHPStan_Node_IdentifiedTypeExpr(IdentifiedTypeExpr $expr): string // phpcs:ignore
46+
{
47+
return sprintf('__phpstanIdentifiedType(%s, %s)', $this->p($expr->expr), $expr->getExprType()->describe(VerbosityLevel::precise()));
48+
}
49+
4450
protected function pPHPStan_Node_GetOffsetValueTypeExpr(GetOffsetValueTypeExpr $expr): string // phpcs:ignore
4551
{
4652
return sprintf('__phpstanGetOffsetValueType(%s, %s)', $this->p($expr->getVar()), $this->p($expr->getDim()));

src/Reflection/ParametersAcceptorSelector.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Closure;
66
use PhpParser\Node;
77
use PHPStan\Analyser\ArgumentsNormalizer;
8+
use PHPStan\Analyser\Generator\GeneratorScope;
89
use PHPStan\Analyser\MutatingScope;
910
use PHPStan\Analyser\Scope;
1011
use PHPStan\Node\Expr\ParameterVariableOriginalValueExpr;
@@ -494,13 +495,13 @@ public static function selectFromArgs(
494495
}
495496
}
496497

497-
if ($parameter !== null && $scope instanceof MutatingScope) {
498+
if ($parameter !== null && ($scope instanceof MutatingScope || $scope instanceof GeneratorScope)) {
498499
$scope = $scope->pushInFunctionCall(null, $parameter);
499500
}
500501

501502
$type = $scope->getType($originalArg->value);
502503

503-
if ($parameter !== null && $scope instanceof MutatingScope) {
504+
if ($parameter !== null && ($scope instanceof MutatingScope || $scope instanceof GeneratorScope)) {
504505
$scope = $scope->popInFunctionCall();
505506
}
506507

src/Rules/Comparison/ImpossibleCheckTypeHelper.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PhpParser\Node\Expr\FuncCall;
99
use PhpParser\Node\Expr\MethodCall;
1010
use PhpParser\Node\Expr\StaticCall;
11+
use PHPStan\Analyser\Generator\GeneratorScope;
1112
use PHPStan\Analyser\MutatingScope;
1213
use PHPStan\Analyser\Scope;
1314
use PHPStan\Analyser\TypeSpecifier;
@@ -248,7 +249,7 @@ public function findSpecifiedType(
248249
}
249250
}
250251

251-
if (!$scope instanceof MutatingScope) {
252+
if (!$scope instanceof MutatingScope && !$scope instanceof GeneratorScope) {
252253
throw new ShouldNotHappenException();
253254
}
254255

src/Rules/Comparison/StrictComparisonOfDifferentTypesRule.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\Rules\Comparison;
44

55
use PhpParser\Node;
6+
use PHPStan\Analyser\Generator\GeneratorScope;
67
use PHPStan\Analyser\MutatingScope;
78
use PHPStan\Analyser\RicherScopeGetTypeHelper;
89
use PHPStan\Analyser\Scope;
@@ -44,7 +45,7 @@ public function getNodeType(): string
4445

4546
public function processNode(Node $node, Scope $scope): array
4647
{
47-
if (!$scope instanceof MutatingScope) {
48+
if (!$scope instanceof MutatingScope && !$scope instanceof GeneratorScope) {
4849
throw new ShouldNotHappenException();
4950
}
5051

src/Rules/Debug/DebugScopeRule.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\Rules\Debug;
44

55
use PhpParser\Node;
6+
use PHPStan\Analyser\Generator\GeneratorScope;
67
use PHPStan\Analyser\MutatingScope;
78
use PHPStan\Analyser\Scope;
89
use PHPStan\DependencyInjection\AutowiredService;
@@ -45,7 +46,7 @@ public function processNode(Node $node, Scope $scope): array
4546
return [];
4647
}
4748

48-
if (!$scope instanceof MutatingScope) {
49+
if (!$scope instanceof MutatingScope && !$scope instanceof GeneratorScope) {
4950
return [];
5051
}
5152

src/Rules/FunctionCallParametersCheck.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use PhpParser\Node;
66
use PhpParser\Node\Expr;
7+
use PHPStan\Analyser\Generator\GeneratorScope;
78
use PHPStan\Analyser\MutatingScope;
89
use PHPStan\Analyser\Scope;
910
use PHPStan\DependencyInjection\AutowiredParameter;
@@ -318,12 +319,12 @@ public function check(
318319
}
319320

320321
if ($argumentValueType === null) {
321-
if ($scope instanceof MutatingScope) {
322+
if ($scope instanceof MutatingScope || $scope instanceof GeneratorScope) {
322323
$scope = $scope->pushInFunctionCall(null, $parameter);
323324
}
324325
$argumentValueType = $scope->getType($argumentValue);
325326

326-
if ($scope instanceof MutatingScope) {
327+
if ($scope instanceof MutatingScope || $scope instanceof GeneratorScope) {
327328
$scope = $scope->popInFunctionCall();
328329
}
329330
}

src/Rules/Operators/InvalidBinaryOperationRule.php

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@
33
namespace PHPStan\Rules\Operators;
44

55
use PhpParser\Node;
6-
use PHPStan\Analyser\MutatingScope;
76
use PHPStan\Analyser\Scope;
87
use PHPStan\DependencyInjection\RegisteredRule;
8+
use PHPStan\Node\Expr\TypeExpr;
99
use PHPStan\Node\Printer\ExprPrinter;
1010
use PHPStan\Rules\Rule;
1111
use PHPStan\Rules\RuleErrorBuilder;
1212
use PHPStan\Rules\RuleLevelHelper;
1313
use PHPStan\ShouldNotHappenException;
14-
use PHPStan\TrinaryLogic;
1514
use PHPStan\Type\ErrorType;
1615
use PHPStan\Type\Type;
1716
use PHPStan\Type\VerbosityLevel;
1817
use function sprintf;
1918
use function strlen;
19+
use function strpos;
2020
use function substr;
2121

2222
/**
@@ -47,26 +47,14 @@ public function processNode(Node $node, Scope $scope): array
4747
return [];
4848
}
4949

50-
$leftName = '__PHPSTAN__LEFT__';
51-
$rightName = '__PHPSTAN__RIGHT__';
52-
$leftVariable = new Node\Expr\Variable($leftName);
53-
$rightVariable = new Node\Expr\Variable($rightName);
5450
if ($node instanceof Node\Expr\AssignOp) {
5551
$identifier = 'assignOp';
56-
$newNode = clone $node;
57-
$newNode->setAttribute('phpstan_cache_printer', null);
5852
$left = $node->var;
5953
$right = $node->expr;
60-
$newNode->var = $leftVariable;
61-
$newNode->expr = $rightVariable;
6254
} else {
6355
$identifier = 'binaryOp';
64-
$newNode = clone $node;
65-
$newNode->setAttribute('phpstan_cache_printer', null);
6656
$left = $node->left;
6757
$right = $node->right;
68-
$newNode->left = $leftVariable;
69-
$newNode->right = $rightVariable;
7058
}
7159

7260
if ($node instanceof Node\Expr\AssignOp\Concat || $node instanceof Node\Expr\BinaryOp\Concat) {
@@ -97,22 +85,39 @@ public function processNode(Node $node, Scope $scope): array
9785
return [];
9886
}
9987

100-
if (!$scope instanceof MutatingScope) {
101-
throw new ShouldNotHappenException();
88+
if ($node instanceof Node\Expr\AssignOp) {
89+
$newNode = clone $node;
90+
$newNode->setAttribute('phpstan_cache_printer', null);
91+
$newNode->var = new TypeExpr($leftType);
92+
$newNode->expr = new TypeExpr($rightType);
93+
$newLeft = $newNode->var;
94+
$newRight = $newNode->expr;
95+
} else {
96+
$newNode = clone $node;
97+
$newNode->setAttribute('phpstan_cache_printer', null);
98+
$newNode->left = new TypeExpr($leftType);
99+
$newNode->right = new TypeExpr($rightType);
100+
$newLeft = $newNode->left;
101+
$newRight = $newNode->right;
102102
}
103103

104-
$scope = $scope
105-
->assignVariable($leftName, $leftType, $leftType, TrinaryLogic::createYes())
106-
->assignVariable($rightName, $rightType, $rightType, TrinaryLogic::createYes());
107-
108104
if (!$scope->getType($newNode) instanceof ErrorType) {
109105
return [];
110106
}
111107

108+
$leftPrinted = $this->exprPrinter->printExpr($newLeft);
109+
$rightPrinted = $this->exprPrinter->printExpr($newRight);
110+
111+
$opLeftSideTrimmed = substr($this->exprPrinter->printExpr($newNode), strlen($leftPrinted) + 1);
112+
$pos = strpos($opLeftSideTrimmed, $rightPrinted);
113+
if ($pos === false) {
114+
throw new ShouldNotHappenException();
115+
}
116+
112117
return [
113118
RuleErrorBuilder::message(sprintf(
114119
'Binary operation "%s" between %s and %s results in an error.',
115-
substr(substr($this->exprPrinter->printExpr($newNode), strlen($leftName) + 2), 0, -(strlen($rightName) + 2)),
120+
substr($opLeftSideTrimmed, 0, $pos - 1),
116121
$scope->getType($left)->describe(VerbosityLevel::value()),
117122
$scope->getType($right)->describe(VerbosityLevel::value()),
118123
))

0 commit comments

Comments
 (0)