Skip to content

Commit c58d339

Browse files
committed
Numeric operands in arithmetic operations - more verbose error messages, don't skip mixed when the other side is wrong
1 parent c14b6e1 commit c58d339

14 files changed

+173
-73
lines changed

src/Rules/Operators/OperandsInArithmeticAdditionRule.php

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

55
use PHPStan\Type\ArrayType;
66
use PHPStan\Type\MixedType;
7+
use PHPStan\Type\VerbosityLevel;
78

89
class OperandsInArithmeticAdditionRule implements \PHPStan\Rules\Rule
910
{
@@ -22,18 +23,27 @@ public function processNode(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scop
2223
{
2324
$leftType = $scope->getType($node->left);
2425
$rightType = $scope->getType($node->right);
25-
26-
if (OperatorRuleHelper::isValidForArithmeticOperation($leftType, $rightType)) {
27-
return [];
28-
}
29-
3026
$mixedArrayType = new ArrayType(new MixedType(), new MixedType());
3127

3228
if ($mixedArrayType->isSuperTypeOf($leftType)->yes() && $mixedArrayType->isSuperTypeOf($rightType)->yes()) {
3329
return [];
3430
}
3531

36-
return ['Only numeric types or arrays are allowed in arithmetic addition.'];
32+
$messages = [];
33+
if (!OperatorRuleHelper::isValidForArithmeticOperation($leftType)) {
34+
$messages[] = sprintf(
35+
'Only numeric types are allowed in +, %s given on the left side.',
36+
$leftType->describe(VerbosityLevel::typeOnly())
37+
);
38+
}
39+
if (!OperatorRuleHelper::isValidForArithmeticOperation($rightType)) {
40+
$messages[] = sprintf(
41+
'Only numeric types are allowed in +, %s given on the right side.',
42+
$rightType->describe(VerbosityLevel::typeOnly())
43+
);
44+
}
45+
46+
return $messages;
3747
}
3848

3949
}

src/Rules/Operators/OperandsInArithmeticDivisionRule.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace PHPStan\Rules\Operators;
44

5+
use PHPStan\Type\VerbosityLevel;
6+
57
class OperandsInArithmeticDivisionRule implements \PHPStan\Rules\Rule
68
{
79

@@ -17,14 +19,24 @@ public function getNodeType(): string
1719
*/
1820
public function processNode(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope): array
1921
{
22+
$messages = [];
2023
$leftType = $scope->getType($node->left);
21-
$rightType = $scope->getType($node->right);
24+
if (!OperatorRuleHelper::isValidForArithmeticOperation($leftType)) {
25+
$messages[] = sprintf(
26+
'Only numeric types are allowed in /, %s given on the left side.',
27+
$leftType->describe(VerbosityLevel::typeOnly())
28+
);
29+
}
2230

23-
if (OperatorRuleHelper::isValidForArithmeticOperation($leftType, $rightType)) {
24-
return [];
31+
$rightType = $scope->getType($node->right);
32+
if (!OperatorRuleHelper::isValidForArithmeticOperation($rightType)) {
33+
$messages[] = sprintf(
34+
'Only numeric types are allowed in /, %s given on the right side.',
35+
$rightType->describe(VerbosityLevel::typeOnly())
36+
);
2537
}
2638

27-
return ['Only numeric types are allowed in arithmetic division.'];
39+
return $messages;
2840
}
2941

3042
}

src/Rules/Operators/OperandsInArithmeticExponentiationRule.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace PHPStan\Rules\Operators;
44

5+
use PHPStan\Type\VerbosityLevel;
6+
57
class OperandsInArithmeticExponentiationRule implements \PHPStan\Rules\Rule
68
{
79

@@ -17,14 +19,24 @@ public function getNodeType(): string
1719
*/
1820
public function processNode(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope): array
1921
{
22+
$messages = [];
2023
$leftType = $scope->getType($node->left);
21-
$rightType = $scope->getType($node->right);
24+
if (!OperatorRuleHelper::isValidForArithmeticOperation($leftType)) {
25+
$messages[] = sprintf(
26+
'Only numeric types are allowed in **, %s given on the left side.',
27+
$leftType->describe(VerbosityLevel::typeOnly())
28+
);
29+
}
2230

23-
if (OperatorRuleHelper::isValidForArithmeticOperation($leftType, $rightType)) {
24-
return [];
31+
$rightType = $scope->getType($node->right);
32+
if (!OperatorRuleHelper::isValidForArithmeticOperation($rightType)) {
33+
$messages[] = sprintf(
34+
'Only numeric types are allowed in **, %s given on the right side.',
35+
$rightType->describe(VerbosityLevel::typeOnly())
36+
);
2537
}
2638

27-
return ['Only numeric types are allowed in arithmetic exponentiation.'];
39+
return $messages;
2840
}
2941

3042
}

src/Rules/Operators/OperandsInArithmeticModuloRule.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace PHPStan\Rules\Operators;
44

5+
use PHPStan\Type\VerbosityLevel;
6+
57
class OperandsInArithmeticModuloRule implements \PHPStan\Rules\Rule
68
{
79

@@ -17,14 +19,24 @@ public function getNodeType(): string
1719
*/
1820
public function processNode(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope): array
1921
{
22+
$messages = [];
2023
$leftType = $scope->getType($node->left);
21-
$rightType = $scope->getType($node->right);
24+
if (!OperatorRuleHelper::isValidForArithmeticOperation($leftType)) {
25+
$messages[] = sprintf(
26+
'Only numeric types are allowed in %%, %s given on the left side.',
27+
$leftType->describe(VerbosityLevel::typeOnly())
28+
);
29+
}
2230

23-
if (OperatorRuleHelper::isValidForArithmeticOperation($leftType, $rightType)) {
24-
return [];
31+
$rightType = $scope->getType($node->right);
32+
if (!OperatorRuleHelper::isValidForArithmeticOperation($rightType)) {
33+
$messages[] = sprintf(
34+
'Only numeric types are allowed in %%, %s given on the right side.',
35+
$rightType->describe(VerbosityLevel::typeOnly())
36+
);
2537
}
2638

27-
return ['Only numeric types are allowed in arithmetic modulo.'];
39+
return $messages;
2840
}
2941

3042
}

src/Rules/Operators/OperandsInArithmeticMultiplicationRule.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace PHPStan\Rules\Operators;
44

5+
use PHPStan\Type\VerbosityLevel;
6+
57
class OperandsInArithmeticMultiplicationRule implements \PHPStan\Rules\Rule
68
{
79

@@ -17,14 +19,24 @@ public function getNodeType(): string
1719
*/
1820
public function processNode(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope): array
1921
{
22+
$messages = [];
2023
$leftType = $scope->getType($node->left);
21-
$rightType = $scope->getType($node->right);
24+
if (!OperatorRuleHelper::isValidForArithmeticOperation($leftType)) {
25+
$messages[] = sprintf(
26+
'Only numeric types are allowed in *, %s given on the left side.',
27+
$leftType->describe(VerbosityLevel::typeOnly())
28+
);
29+
}
2230

23-
if (OperatorRuleHelper::isValidForArithmeticOperation($leftType, $rightType)) {
24-
return [];
31+
$rightType = $scope->getType($node->right);
32+
if (!OperatorRuleHelper::isValidForArithmeticOperation($rightType)) {
33+
$messages[] = sprintf(
34+
'Only numeric types are allowed in *, %s given on the right side.',
35+
$rightType->describe(VerbosityLevel::typeOnly())
36+
);
2537
}
2638

27-
return ['Only numeric types are allowed in arithmetic multiplication.'];
39+
return $messages;
2840
}
2941

3042
}

src/Rules/Operators/OperandsInArithmeticSubtractionRule.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace PHPStan\Rules\Operators;
44

5+
use PHPStan\Type\VerbosityLevel;
6+
57
class OperandsInArithmeticSubtractionRule implements \PHPStan\Rules\Rule
68
{
79

@@ -17,14 +19,24 @@ public function getNodeType(): string
1719
*/
1820
public function processNode(\PhpParser\Node $node, \PHPStan\Analyser\Scope $scope): array
1921
{
22+
$messages = [];
2023
$leftType = $scope->getType($node->left);
21-
$rightType = $scope->getType($node->right);
24+
if (!OperatorRuleHelper::isValidForArithmeticOperation($leftType)) {
25+
$messages[] = sprintf(
26+
'Only numeric types are allowed in -, %s given on the left side.',
27+
$leftType->describe(VerbosityLevel::typeOnly())
28+
);
29+
}
2230

23-
if (OperatorRuleHelper::isValidForArithmeticOperation($leftType, $rightType)) {
24-
return [];
31+
$rightType = $scope->getType($node->right);
32+
if (!OperatorRuleHelper::isValidForArithmeticOperation($rightType)) {
33+
$messages[] = sprintf(
34+
'Only numeric types are allowed in -, %s given on the right side.',
35+
$rightType->describe(VerbosityLevel::typeOnly())
36+
);
2537
}
2638

27-
return ['Only numeric types are allowed in arithmetic subtraction.'];
39+
return $messages;
2840
}
2941

3042
}

src/Rules/Operators/OperatorRuleHelper.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@
1111
class OperatorRuleHelper
1212
{
1313

14-
public static function isValidForArithmeticOperation(Type $leftType, Type $rightType): bool
14+
public static function isValidForArithmeticOperation(Type $type): bool
1515
{
16-
if ($leftType instanceof MixedType || $rightType instanceof MixedType) {
16+
if ($type instanceof MixedType) {
1717
return true;
1818
}
1919

2020
$acceptedType = new UnionType([new IntegerType(), new FloatType()]);
2121

22-
return $acceptedType->isSuperTypeOf($leftType)->yes() && $acceptedType->isSuperTypeOf($rightType)->yes();
22+
return $acceptedType->isSuperTypeOf($type)->yes();
2323
}
2424

2525
}

tests/Rules/Operators/OperandsInArithmeticAdditionRuleTest.php

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,45 @@ public function testRule(): void
1616
{
1717
$this->analyse([__DIR__ . '/data/operators.php'], [
1818
[
19-
'Only numeric types or arrays are allowed in arithmetic addition.',
19+
'Only numeric types are allowed in +, string given on the right side.',
2020
25,
2121
],
2222
[
23-
'Only numeric types or arrays are allowed in arithmetic addition.',
23+
'Only numeric types are allowed in +, array given on the right side.',
2424
26,
2525
],
2626
[
27-
'Only numeric types or arrays are allowed in arithmetic addition.',
27+
'Only numeric types are allowed in +, stdClass given on the right side.',
2828
27,
2929
],
3030
[
31-
'Only numeric types or arrays are allowed in arithmetic addition.',
31+
'Only numeric types are allowed in +, null given on the right side.',
3232
28,
3333
],
3434
[
35-
'Only numeric types or arrays are allowed in arithmetic addition.',
35+
'Only numeric types are allowed in +, null given on the right side.',
3636
29,
3737
],
3838
[
39-
'Only numeric types or arrays are allowed in arithmetic addition.',
39+
'Only numeric types are allowed in +, string given on the right side.',
4040
29,
4141
],
4242
[
43-
'Only numeric types or arrays are allowed in arithmetic addition.',
43+
'Only numeric types are allowed in +, array given on the right side.',
4444
30,
4545
],
46+
[
47+
'Only numeric types are allowed in +, array given on the left side.',
48+
30,
49+
],
50+
[
51+
'Only numeric types are allowed in +, string given on the right side.',
52+
101,
53+
],
54+
[
55+
'Only numeric types are allowed in +, string given on the left side.',
56+
102,
57+
],
4658
]);
4759
}
4860

tests/Rules/Operators/OperandsInArithmeticDivisionRuleTest.php

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,35 @@ public function testRule(): void
1616
{
1717
$this->analyse([__DIR__ . '/data/operators.php'], [
1818
[
19-
'Only numeric types are allowed in arithmetic division.',
19+
'Only numeric types are allowed in /, string given on the right side.',
2020
64,
2121
],
2222
[
23-
'Only numeric types are allowed in arithmetic division.',
23+
'Only numeric types are allowed in /, array given on the right side.',
2424
65,
2525
],
2626
[
27-
'Only numeric types are allowed in arithmetic division.',
27+
'Only numeric types are allowed in /, stdClass given on the right side.',
2828
66,
2929
],
3030
[
31-
'Only numeric types are allowed in arithmetic division.',
31+
'Only numeric types are allowed in /, null given on the right side.',
3232
67,
3333
],
3434
[
35-
'Only numeric types are allowed in arithmetic division.',
35+
'Only numeric types are allowed in /, null given on the right side.',
3636
68,
3737
],
3838
[
39-
'Only numeric types are allowed in arithmetic division.',
39+
'Only numeric types are allowed in /, string given on the right side.',
4040
68,
4141
],
4242
[
43-
'Only numeric types are allowed in arithmetic division.',
43+
'Only numeric types are allowed in /, array given on the right side.',
44+
69,
45+
],
46+
[
47+
'Only numeric types are allowed in /, array given on the left side.',
4448
69,
4549
],
4650
]);

tests/Rules/Operators/OperandsInArithmeticExponentiationRuleTest.php

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,35 @@ public function testRule(): void
1616
{
1717
$this->analyse([__DIR__ . '/data/operators.php'], [
1818
[
19-
'Only numeric types are allowed in arithmetic exponentiation.',
19+
'Only numeric types are allowed in **, string given on the right side.',
2020
77,
2121
],
2222
[
23-
'Only numeric types are allowed in arithmetic exponentiation.',
23+
'Only numeric types are allowed in **, array given on the right side.',
2424
78,
2525
],
2626
[
27-
'Only numeric types are allowed in arithmetic exponentiation.',
27+
'Only numeric types are allowed in **, stdClass given on the right side.',
2828
79,
2929
],
3030
[
31-
'Only numeric types are allowed in arithmetic exponentiation.',
31+
'Only numeric types are allowed in **, null given on the right side.',
3232
80,
3333
],
3434
[
35-
'Only numeric types are allowed in arithmetic exponentiation.',
35+
'Only numeric types are allowed in **, string given on the left side.',
3636
81,
3737
],
3838
[
39-
'Only numeric types are allowed in arithmetic exponentiation.',
39+
'Only numeric types are allowed in **, null given on the right side.',
40+
81,
41+
],
42+
[
43+
'Only numeric types are allowed in **, array given on the left side.',
4044
82,
4145
],
4246
[
43-
'Only numeric types are allowed in arithmetic exponentiation.',
47+
'Only numeric types are allowed in **, array given on the left side.',
4448
82,
4549
],
4650
]);

0 commit comments

Comments
 (0)