|
3 | 3 | namespace PHPStan\Rules\Operators; |
4 | 4 |
|
5 | 5 | use PhpParser\Node; |
6 | | -use PHPStan\Analyser\MutatingScope; |
7 | 6 | use PHPStan\Analyser\Scope; |
8 | 7 | use PHPStan\DependencyInjection\RegisteredRule; |
| 8 | +use PHPStan\Node\Expr\TypeExpr; |
9 | 9 | use PHPStan\Node\Printer\ExprPrinter; |
10 | 10 | use PHPStan\Rules\Rule; |
11 | 11 | use PHPStan\Rules\RuleErrorBuilder; |
12 | 12 | use PHPStan\Rules\RuleLevelHelper; |
13 | 13 | use PHPStan\ShouldNotHappenException; |
14 | | -use PHPStan\TrinaryLogic; |
15 | 14 | use PHPStan\Type\ErrorType; |
16 | 15 | use PHPStan\Type\Type; |
17 | 16 | use PHPStan\Type\VerbosityLevel; |
18 | 17 | use function sprintf; |
19 | 18 | use function strlen; |
| 19 | +use function strpos; |
20 | 20 | use function substr; |
21 | 21 |
|
22 | 22 | /** |
@@ -47,26 +47,14 @@ public function processNode(Node $node, Scope $scope): array |
47 | 47 | return []; |
48 | 48 | } |
49 | 49 |
|
50 | | - $leftName = '__PHPSTAN__LEFT__'; |
51 | | - $rightName = '__PHPSTAN__RIGHT__'; |
52 | | - $leftVariable = new Node\Expr\Variable($leftName); |
53 | | - $rightVariable = new Node\Expr\Variable($rightName); |
54 | 50 | if ($node instanceof Node\Expr\AssignOp) { |
55 | 51 | $identifier = 'assignOp'; |
56 | | - $newNode = clone $node; |
57 | | - $newNode->setAttribute('phpstan_cache_printer', null); |
58 | 52 | $left = $node->var; |
59 | 53 | $right = $node->expr; |
60 | | - $newNode->var = $leftVariable; |
61 | | - $newNode->expr = $rightVariable; |
62 | 54 | } else { |
63 | 55 | $identifier = 'binaryOp'; |
64 | | - $newNode = clone $node; |
65 | | - $newNode->setAttribute('phpstan_cache_printer', null); |
66 | 56 | $left = $node->left; |
67 | 57 | $right = $node->right; |
68 | | - $newNode->left = $leftVariable; |
69 | | - $newNode->right = $rightVariable; |
70 | 58 | } |
71 | 59 |
|
72 | 60 | 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 |
97 | 85 | return []; |
98 | 86 | } |
99 | 87 |
|
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; |
102 | 102 | } |
103 | 103 |
|
104 | | - $scope = $scope |
105 | | - ->assignVariable($leftName, $leftType, $leftType, TrinaryLogic::createYes()) |
106 | | - ->assignVariable($rightName, $rightType, $rightType, TrinaryLogic::createYes()); |
107 | | - |
108 | 104 | if (!$scope->getType($newNode) instanceof ErrorType) { |
109 | 105 | return []; |
110 | 106 | } |
111 | 107 |
|
| 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 | + |
112 | 117 | return [ |
113 | 118 | RuleErrorBuilder::message(sprintf( |
114 | 119 | '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), |
116 | 121 | $scope->getType($left)->describe(VerbosityLevel::value()), |
117 | 122 | $scope->getType($right)->describe(VerbosityLevel::value()), |
118 | 123 | )) |
|
0 commit comments