-
Notifications
You must be signed in to change notification settings - Fork 523
Report maybe division by zero in InvalidBinaryOperationRule #3419
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 1.12.x
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,11 +19,14 @@ class InvalidBinaryOperationRuleTest extends RuleTestCase | |
|
||
private bool $checkImplicitMixed = false; | ||
|
||
private bool $checkBenevolentUnionTypes = false; | ||
|
||
protected function getRule(): Rule | ||
{ | ||
return new InvalidBinaryOperationRule( | ||
new ExprPrinter(new Printer()), | ||
new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, true, false), | ||
new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, true, $this->checkBenevolentUnionTypes), | ||
true, | ||
true, | ||
); | ||
} | ||
|
@@ -282,7 +285,12 @@ public function testBug3515(): void | |
|
||
public function testBug8827(): void | ||
{ | ||
$this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-8827.php'], []); | ||
$this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-8827.php'], [ | ||
[ | ||
'Binary operation "/" between int<0, max> and int<0, max> might result in an error.', | ||
25, | ||
], | ||
]); | ||
} | ||
|
||
public function testRuleWithNullsafeVariant(): void | ||
|
@@ -659,6 +667,14 @@ public function testBenevolentUnion(): void | |
'Binary operation "/" between (array<string, string>|bool|int|object|resource) and BinaryOpBenevolentUnion\\Foo results in an error.', | ||
105, | ||
], | ||
[ | ||
'Binary operation "/" between (array<string, string>|bool|int|object|resource) and (array<string, string>|bool|int|object|resource) might result in an error.', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one. It might be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh I get it, but But: We can still create an artifical example for example of |
||
108, | ||
], | ||
[ | ||
'Binary operation "/=" between 1 and (array<string, string>|bool|int|object|resource) might result in an error.', | ||
111, | ||
], | ||
[ | ||
'Binary operation "/=" between array{} and (array<string, string>|bool|int|object|resource) results in an error.', | ||
114, | ||
|
@@ -667,14 +683,34 @@ public function testBenevolentUnion(): void | |
'Binary operation "/=" between BinaryOpBenevolentUnion\\Foo and (array<string, string>|bool|int|object|resource) results in an error.', | ||
117, | ||
], | ||
[ | ||
"Binary operation \"/=\" between '123' and (array<string, string>|bool|int|object|resource) might result in an error.", | ||
120, | ||
], | ||
[ | ||
'Binary operation "/=" between 1.23 and (array<string, string>|bool|int|object|resource) might result in an error.', | ||
123, | ||
], | ||
[ | ||
'Binary operation "/=" between (array<string, string>|bool|int|object|resource) and (array<string, string>|bool|int|object|resource) might result in an error.', | ||
126, | ||
], | ||
[ | ||
'Binary operation "%" between (array<string, string>|bool|int|object|resource) and array{} results in an error.', | ||
135, | ||
], | ||
[ | ||
'Binary operation "%" between (array<string, string>|bool|int|object|resource) and BinaryOpBenevolentUnion\\Foo results in an error.', | ||
'Binary operation "%" between (array<string, string>|bool|int|object|resource) and BinaryOpBenevolentUnion\Foo results in an error.', | ||
136, | ||
], | ||
[ | ||
'Binary operation "%" between (array<string, string>|bool|int|object|resource) and (array<string, string>|bool|int|object|resource) might result in an error.', | ||
139, | ||
], | ||
[ | ||
'Binary operation "%=" between 1 and (array<string, string>|bool|int|object|resource) might result in an error.', | ||
142, | ||
], | ||
[ | ||
'Binary operation "%=" between array{} and (array<string, string>|bool|int|object|resource) results in an error.', | ||
145, | ||
|
@@ -683,6 +719,18 @@ public function testBenevolentUnion(): void | |
'Binary operation "%=" between BinaryOpBenevolentUnion\\Foo and (array<string, string>|bool|int|object|resource) results in an error.', | ||
148, | ||
], | ||
[ | ||
"Binary operation \"%=\" between '123' and (array<string, string>|bool|int|object|resource) might result in an error.", | ||
151, | ||
], | ||
[ | ||
'Binary operation "%=" between 1.23 and (array<string, string>|bool|int|object|resource) might result in an error.', | ||
154, | ||
], | ||
[ | ||
'Binary operation "%=" between (array<string, string>|bool|int|object|resource) and (array<string, string>|bool|int|object|resource) might result in an error.', | ||
157, | ||
], | ||
[ | ||
'Binary operation "-" between (array<string, string>|bool|int|object|resource) and array{} results in an error.', | ||
166, | ||
|
@@ -810,4 +858,94 @@ public function testBug7863(): void | |
]); | ||
} | ||
|
||
/** | ||
* @dataProvider dataDivisionByMaybeZero | ||
* @param list<array{0: string, 1: int, 2?: string|null}> $expectedErrors | ||
*/ | ||
public function testDivisionByMaybeZero(bool $checkBenevolentUnionTypes, array $expectedErrors): void | ||
{ | ||
$this->checkBenevolentUnionTypes = $checkBenevolentUnionTypes; | ||
|
||
$this->analyse([__DIR__ . '/data/invalid-division.php'], $expectedErrors); | ||
} | ||
|
||
public function dataDivisionByMaybeZero(): iterable | ||
{ | ||
yield [ | ||
false, | ||
[ | ||
[ | ||
'Binary operation "/" between int and int<0, max> might result in an error.', | ||
12, | ||
], | ||
[ | ||
'Binary operation "/=" between int and int<0, max> might result in an error.', | ||
13, | ||
], | ||
[ | ||
'Binary operation "%" between int and int<0, max> might result in an error.', | ||
21, | ||
], | ||
[ | ||
'Binary operation "%=" between int and int<0, max> might result in an error.', | ||
22, | ||
], | ||
[ | ||
'Binary operation "/" between int and int<0, max> might result in an error.', | ||
61, | ||
], | ||
[ | ||
'Binary operation "/" between int and float|int might result in an error.', | ||
90, | ||
], | ||
[ | ||
'Binary operation "/" between int and (int|true) might result in an error.', | ||
106, | ||
], | ||
[ | ||
'Binary operation "/" between int and -5|int<0, max> might result in an error.', | ||
123, | ||
], | ||
], | ||
]; | ||
|
||
yield [ | ||
true, | ||
[ | ||
[ | ||
'Binary operation "/" between int and int<0, max> might result in an error.', | ||
12, | ||
], | ||
[ | ||
'Binary operation "/=" between int and int<0, max> might result in an error.', | ||
13, | ||
], | ||
[ | ||
'Binary operation "%" between int and int<0, max> might result in an error.', | ||
21, | ||
], | ||
[ | ||
'Binary operation "%=" between int and int<0, max> might result in an error.', | ||
22, | ||
], | ||
[ | ||
'Binary operation "/" between int and int<0, max> might result in an error.', | ||
61, | ||
], | ||
[ | ||
'Binary operation "/" between int and float|int might result in an error.', | ||
90, | ||
], | ||
[ | ||
'Binary operation "/" between int and (int|true) might result in an error.', | ||
106, | ||
], | ||
[ | ||
'Binary operation "/" between int and -5|int<0, max> might result in an error.', | ||
123, | ||
], | ||
], | ||
]; | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic should be implemented as a
$callback
for the RuleLevelHelper above instead. It will make sure this is correctly reported on level 2 (when it's always zero) and on level 7 (when it might be a zero).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the callback passed to
RuleLevelHelper
is only invoked for union types and intersection types.in our case we pass in a expr which is resolved into a IntegerRangeType, which means the callback does not have any effect in this context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get it. But still I'm missing at least asking for
$this->reportMaybes
so that maybe-zero is reported only on level 7+.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, it'd still be useful if the RuleLeveLHelper eliminated some situations. I can see that in the tests you're currently asserting an error that shouldn't be asserted because it's on a BenevolentUnionType.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried testing the benevolent case, but for some reason the benevolence is lost somewhere?
https://phpstan.org/r/c0d12375-468d-46a2-8778-fcedc0d5e26f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not how you type a benevolent union type in PHPDoc.
It's not officially supported, there's just a semi-secret pseudotype
__benevolent<...>
. Check the functionMap.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, hopefully I got it right now. my understanding about the expected results about the divisor are
$checkBenevolentUnionTypes
flag)$checkBenevolentUnionTypes
(e.g.(int|true)
)I tried endless variants of how to represent this condition via RuleLevelHelper callback, but couldn't find one which works for all this conditions