-
Notifications
You must be signed in to change notification settings - Fork 58
Expand file tree
/
Copy pathOperatorRuleHelper.php
More file actions
103 lines (81 loc) · 2.41 KB
/
OperatorRuleHelper.php
File metadata and controls
103 lines (81 loc) · 2.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Operators;
use PhpParser\Node\Expr;
use PHPStan\Analyser\Scope;
use PHPStan\Php\PhpVersion;
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\Type\Accessory\AccessoryNumericStringType;
use PHPStan\Type\BenevolentUnionType;
use PHPStan\Type\ErrorType;
use PHPStan\Type\FloatType;
use PHPStan\Type\IntegerType;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\MixedType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
class OperatorRuleHelper
{
private RuleLevelHelper $ruleLevelHelper;
private PhpVersion $phpVersion;
public function __construct(RuleLevelHelper $ruleLevelHelper, PhpVersion $phpVersion)
{
$this->ruleLevelHelper = $ruleLevelHelper;
$this->phpVersion = $phpVersion;
}
public function isValidForArithmeticOperation(Scope $scope, Expr $expr): bool
{
$type = $scope->getType($expr);
if ($type instanceof MixedType) {
return true;
}
// already reported by PHPStan core
if ($type->toNumber() instanceof ErrorType) {
return true;
}
return $this->isSubtypeOfNumber($scope, $expr);
}
public function isValidForIncrement(Scope $scope, Expr $expr): bool
{
$type = $scope->getType($expr);
if ($type instanceof MixedType) {
return true;
}
if ($type->isString()->yes()) {
// Because `$a = 'a'; $a++;` is valid
return true;
}
return $this->isSubtypeOfNumber($scope, $expr);
}
public function isValidForDecrement(Scope $scope, Expr $expr): bool
{
$type = $scope->getType($expr);
if ($type instanceof MixedType) {
return true;
}
return $this->isSubtypeOfNumber($scope, $expr);
}
private function isSubtypeOfNumber(Scope $scope, Expr $expr): bool
{
$acceptedTypes = [new IntegerType(), new FloatType(), new IntersectionType([new StringType(), new AccessoryNumericStringType()])];
if ($this->phpVersion->supportsBcMathNumberOperatorOverloading()) {
$acceptedTypes[] = new ObjectType('BcMath\Number');
}
$acceptedType = new UnionType($acceptedTypes);
$type = $this->ruleLevelHelper->findTypeToCheck(
$scope,
$expr,
'',
static fn (Type $type): bool => $acceptedType->isSuperTypeOf($type)->yes(),
)->getType();
if ($type instanceof ErrorType) {
return true;
}
$isSuperType = $acceptedType->isSuperTypeOf($type);
if ($type instanceof BenevolentUnionType) {
return !$isSuperType->no();
}
return $isSuperType->yes();
}
}