-
Notifications
You must be signed in to change notification settings - Fork 473
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
Detect enum duplicated values #2371
Detect enum duplicated values #2371
Conversation
You've opened the pull request against the latest branch 1.11.x. If your code is relevant on 1.10.x and you want it to be released sooner, please rebase your pull request and change its target to 1.10.x. |
786b68e
to
36d2b9c
Compare
src/Rules/Classes/EnumSanityRule.php
Outdated
|
||
$enumCases = []; | ||
foreach ($node->stmts as $stmt) { | ||
if (!($stmt instanceof Node\Stmt\EnumCase && ($stmt->expr instanceof Node\Scalar\LNumber || $stmt->expr instanceof Node\Scalar\String_))) { |
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.
You could check more things here. Like:
- Wrong case value type against the type declared in
$node->scalarType
. - Missing case value in backed enum, and extra case value in case of non-backed enum.
All three cases here should fail: https://phpstan.org/r/3ca06994-1a6e-4686-a57c-6083c6bdb34e
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.
Thanks for the suggestions, I'll implement them.
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.
@ondrejmirtes Done. 3 tests are failing but they seem like unrelated to my changes.
->line($stmt->getLine()) | ||
->nonIgnorable() | ||
->build(); | ||
} |
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.
Here I had to use early return (if (!$isStringBackedWithoutStringCase) {
) because linter forced me to do that.
Early return is a great rule to reduce code complexity, but in my opinion in this situation it made the code a bit harder to follow. Because instead of this code:
foreach ($enumCases as $enumCase) {
if ($isIntBackedWithoutIntValue) {
// add error
}
if ($isStringBackedWithoutStringValue) {
// add error
}
}
we got:
foreach ($enumCases as $enumCase) {
if ($isIntBackedWithoutIntValue) {
// add error
}
if (!$isStringBackedWithoutStringValue) {
continue;
}
// add error
}
I saw that this rule was even suppressed once in phpstan repository:
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.
You might want to look into fine-tuning https://github.com/slevomat/coding-standard/blob/master/doc/control-structures.md#slevomatcodingstandardcontrolstructuresearlyexit-
I obviously can't speak for Ondřej, but the last time a similar thing like this was discussed it sounded like he is open to look into adapting it.
1f1e5cc
to
7edd4dd
Compare
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.
Hi, I just pushed some cosmetic changes that make the rule more consistent with others.
I still need a few changes from you:
- Missing case value in backed enum should have a special message - put
if ($stmt->expr === null)
belowif ($node->scalarType === null)
and handle it separately. This should make the test suite not crash again. - Wrong scalar type like
float
orobject
is not yet reported AFAIK.
ad012f9
to
7edd4dd
Compare
I've implemented what you asked. Let's summarize what is done: 1. Detecting duplicate values. The rule checks that there are at least 2 duplicate case values. 2. Inconsistent case type and backed type The rule checks that enum's scalar type and all the case types match. 3. Enum isn't backed, but has a backed case The rule triggers when scalar type is empty, but a case isn't 4. Enum is backed, but one of the cases has value missed UPD: I have added one more example because I mistakenly hardcoded the error message: https://github.com/phpstan/phpstan-src/pull/2371/files#diff-ff846fb46bb3972dcf0a281f7d686cd1fbc84f2d282966d6acdd0d7965e94a77R110 The rule triggers when scalar type isn't empty, but a case is. |
It has been already implemented:
|
@ondrejmirtes I have a question regarding your fix: 7edd4dd phpstan-src/src/Rules/Classes/EnumSanityRule.php Lines 191 to 200 in 7edd4dd
You've replaced This line has triggered PHPStan, because due to line 192 it will always evaluate to false (it's great that PHPStan noticed it!). But as I understand the code should be reverted. enum Test: string
{
case case1 = 'a';
case case2 = 'a';
case case3 = 'b';
} So when we see that a value has at least 2 corresponding cases - we report duplication. So I brought it back to make PHPStan check pass. Let me know if it needs to be improved somehow. |
Thank you. |
Fixes: phpstan/phpstan#9184