Skip to content

Commit 2e9161a

Browse files
committed
ForbidArithmeticOperationOnNonNumberRule: add support for BcMath\Number
1 parent af834c5 commit 2e9161a

File tree

4 files changed

+136
-1
lines changed

4 files changed

+136
-1
lines changed

src/Rule/ForbidArithmeticOperationOnNonNumberRule.php

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use PHPStan\Rules\RuleErrorBuilder;
1919
use PHPStan\Type\FloatType;
2020
use PHPStan\Type\IntegerType;
21+
use PHPStan\Type\ObjectType;
2122
use PHPStan\Type\Type;
2223
use PHPStan\Type\UnionType;
2324
use PHPStan\Type\VerbosityLevel;
@@ -113,6 +114,12 @@ private function processBinary(
113114
return []; // array merge syntax
114115
}
115116

117+
if (($this->isBcMathNumber($leftType) && $this->isFloat($rightType))
118+
|| ($this->isFloat($leftType) && $this->isBcMathNumber($rightType))
119+
) {
120+
return $this->buildBinaryErrors($operator, 'BcMath\\Number and float', $leftType, $rightType);
121+
}
122+
116123
if (
117124
$operator === '%' &&
118125
(!$leftType->isInteger()->yes() || !$rightType->isInteger()->yes())
@@ -136,7 +143,8 @@ private function isNumeric(Type $type): bool
136143
return $int->isSuperTypeOf($type)->yes()
137144
|| $float->isSuperTypeOf($type)->yes()
138145
|| $intOrFloat->isSuperTypeOf($type)->yes()
139-
|| ($this->allowNumericString && $type->isNumericString()->yes());
146+
|| ($this->allowNumericString && $type->isNumericString()->yes())
147+
|| $this->isBcMathNumber($type);
140148
}
141149

142150
/**
@@ -164,4 +172,18 @@ private function buildBinaryErrors(
164172
return [$error];
165173
}
166174

175+
private function isBcMathNumber(Type $type): bool
176+
{
177+
$bcMathNumber = new ObjectType('BcMath\Number');
178+
179+
return $type->isSuperTypeOf($bcMathNumber)->yes();
180+
}
181+
182+
private function isFloat(Type $type): bool
183+
{
184+
$float = new FloatType();
185+
186+
return $type->isSuperTypeOf($float)->yes();
187+
}
188+
167189
}

tests/Rule/ForbidArithmeticOperationOnNonNumberRuleTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use LogicException;
66
use PHPStan\Rules\Rule;
77
use ShipMonk\PHPStan\RuleTestCase;
8+
use const PHP_VERSION_ID;
89

910
/**
1011
* @extends RuleTestCase<ForbidArithmeticOperationOnNonNumberRule>
@@ -35,6 +36,26 @@ public function testNoNumericString(): void
3536
$this->analyseFile(__DIR__ . '/data/ForbidArithmeticOperationOnNonNumberRule/no-numeric-string.php');
3637
}
3738

39+
public function testBcMathNumber(): void
40+
{
41+
if (PHP_VERSION_ID < 80_400) {
42+
self::markTestSkipped('Requires PHP 8.4');
43+
}
44+
45+
$this->allowNumericString = true;
46+
$this->analyseFile(__DIR__ . '/data/ForbidArithmeticOperationOnNonNumberRule/bcmath-number.php');
47+
}
48+
49+
public function testBcMathNumberNoNumeric(): void
50+
{
51+
if (PHP_VERSION_ID < 80_400) {
52+
self::markTestSkipped('Requires PHP 8.4');
53+
}
54+
55+
$this->allowNumericString = false;
56+
$this->analyseFile(__DIR__ . '/data/ForbidArithmeticOperationOnNonNumberRule/bcmath-number-no-numeric.php');
57+
}
58+
3859
protected function shouldFailOnPhpErrors(): bool
3960
{
4061
return false; // https://github.com/phpstan/phpstan-src/pull/3031
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace ShipMonk\PHPStan\Rule\data\ForbidArithmeticOperationOnNonNumberRule;
4+
use BcMath\Number;
5+
6+
class BcMathNumberNoNumeric {
7+
8+
/**
9+
* @param numeric-string $ns
10+
*/
11+
public function testBcMathNumbers(Number $n, string $ns, int $int, float $float, int|float $intFloat): void {
12+
+$n;
13+
-$n;
14+
15+
$x = $n + $n;
16+
$x = $n - $n;
17+
$x = $n * $n;
18+
$x = $n / $n;
19+
20+
$x = $n + $int;
21+
$x = $int + $n;
22+
$x = $n + $ns; // error: Using + over non-number (BcMath\Number + string)
23+
$x = $ns + $n; // error: Using + over non-number (string + BcMath\Number)
24+
$x = $n - $int;
25+
$x = $int - $n;
26+
$x = $n - $ns; // error: Using - over non-number (BcMath\Number - string)
27+
$x = $ns - $n; // error: Using - over non-number (string - BcMath\Number)
28+
$x = $n * $int;
29+
$x = $int * $n;
30+
$x = $n * $ns; // error: Using * over non-number (BcMath\Number * string)
31+
$x = $ns * $n; // error: Using * over non-number (string * BcMath\Number)
32+
$x = $n / $int;
33+
$x = $int / $n;
34+
$x = $n / $ns; // error: Using / over non-number (BcMath\Number / string)
35+
$x = $ns / $n; // error: Using / over non-number (string / BcMath\Number)
36+
}
37+
}
38+
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace ForbidArithmeticOperationOnNonNumberRule;
4+
use BcMath\Number;
5+
6+
class BcMathNumber {
7+
8+
/**
9+
* @param numeric-string $ns
10+
*/
11+
public function testBcMathNumbers(Number $n, string $ns, int $int, float $float, int|float $intFloat): void {
12+
+$n;
13+
-$n;
14+
15+
$x = $n + $n;
16+
$x = $n - $n;
17+
$x = $n * $n;
18+
$x = $n / $n;
19+
20+
$x = $n + $int;
21+
$x = $int + $n;
22+
$x = $n + $ns;
23+
$x = $ns + $n;
24+
$x = $n - $int;
25+
$x = $int - $n;
26+
$x = $n - $ns;
27+
$x = $ns - $n;
28+
$x = $n * $int;
29+
$x = $int * $n;
30+
$x = $n * $ns;
31+
$x = $ns * $n;
32+
$x = $n / $int;
33+
$x = $int / $n;
34+
$x = $n / $ns;
35+
$x = $ns / $n;
36+
37+
$x = $n + $float; // error: Using + over BcMath\Number and float (BcMath\Number + float)
38+
$x = $float + $n; // error: Using + over BcMath\Number and float (float + BcMath\Number)
39+
$x = $n - $float; // error: Using - over BcMath\Number and float (BcMath\Number - float)
40+
$x = $float - $n; // error: Using - over BcMath\Number and float (float - BcMath\Number)
41+
$x = $n * $float; // error: Using * over BcMath\Number and float (BcMath\Number * float)
42+
$x = $float * $n; // error: Using * over BcMath\Number and float (float * BcMath\Number)
43+
$x = $n / $float; // error: Using / over BcMath\Number and float (BcMath\Number / float)
44+
$x = $float / $n; // error: Using / over BcMath\Number and float (float / BcMath\Number)
45+
$x = $n % $float; // error: Using % over BcMath\Number and float (BcMath\Number % float)
46+
$x = $float % $n; // error: Using % over BcMath\Number and float (float % BcMath\Number)
47+
$x = $n ** $float; // error: Using ** over BcMath\Number and float (BcMath\Number ** float)
48+
$x = $float ** $n; // error: Using ** over BcMath\Number and float (float ** BcMath\Number)
49+
50+
$x = $n + $intFloat; // error: Using + over BcMath\Number and float (BcMath\Number + float|int)
51+
$x = $intFloat + $n; // error: Using + over BcMath\Number and float (float|int + BcMath\Number)
52+
}
53+
}
54+

0 commit comments

Comments
 (0)