Skip to content

Commit 934aed9

Browse files
committed
Fix conversion of in() and notIn() to native enums when called with non-arrays
1 parent 0f82b99 commit 934aed9

File tree

9 files changed

+65
-7
lines changed

9 files changed

+65
-7
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
## 6.11.1
11+
12+
### Fixed
13+
14+
- Fix conversion of `in()` and `notIn()` to native enums when called with non-arrays
15+
1016
## 6.11.0
1117

1218
### Added

phpstan.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ parameters:
1414
- '#unknown class Illuminate\\Support\\Facades\\Process#'
1515
- '#unknown class Illuminate\\Process#'
1616
- '#invalid type Illuminate\\Process#'
17+
- '#^Attribute class PHPUnit\\Framework\\Attributes\\DataProvider does not exist\.$#' # Only available with newer PHPUnit versions
1718
excludePaths:
1819
- tests/Enums/ToNativeFixtures # Fails with PHP < 8.1
1920
- tests/PHPStan/Fixtures

src/Rector/ToNativeUsagesRector.php

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use BenSampo\Enum\Enum;
66
use BenSampo\Enum\Tests\Enums\UserType;
77
use Illuminate\Support\Arr;
8+
use Illuminate\Support\Enumerable;
89
use PhpParser\Node;
910
use PhpParser\Node\Arg;
1011
use PhpParser\Node\Expr;
@@ -565,7 +566,9 @@ protected function refactorMaybeMagicStaticCall(StaticCall $call): ?Node
565566
*/
566567
protected function refactorIsOrIsNot(MethodCall|NullsafeMethodCall $call, bool $is): ?Node
567568
{
568-
$comparison = $is ? Identical::class : NotIdentical::class;
569+
$comparison = $is
570+
? Identical::class
571+
: NotIdentical::class;
569572

570573
if ($call->isFirstClassCallable()) {
571574
$param = new Variable('value');
@@ -601,19 +604,38 @@ protected function refactorInOrNotIn(MethodCall|NullsafeMethodCall $call, bool $
601604
{
602605
$args = $call->args;
603606
if (isset($args[0]) && $args[0] instanceof Arg) {
604-
$needle = new Arg($call->var);
605-
$haystack = $args[0];
607+
$enumArg = new Arg($call->var);
608+
$valuesArg = $args[0];
606609

607-
$haystackValue = $haystack->value;
608-
if ($haystackValue instanceof Array_) {
609-
foreach ($haystackValue->items as $item) {
610+
$valuesValue = $valuesArg->value;
611+
if ($valuesValue instanceof Array_) {
612+
foreach ($valuesValue->items as $item) {
610613
$item->setAttribute(self::COMPARED_AGAINST_ENUM_INSTANCE, true);
611614
}
612615
}
613616

617+
if ($this->isObjectType($valuesValue, new ObjectType(Enumerable::class))) {
618+
return new MethodCall(
619+
$valuesValue,
620+
new Identifier($in
621+
? 'contains'
622+
: 'doesntContain'),
623+
[$enumArg],
624+
);
625+
}
626+
627+
$haystackArg = $this->getType($valuesValue)->isArray()->yes()
628+
? $valuesArg
629+
: new Arg(
630+
new FuncCall(
631+
new Name('iterator_to_array'),
632+
[$valuesArg],
633+
),
634+
);
635+
614636
$inArray = new FuncCall(
615637
new Name('in_array'),
616-
[$needle, $haystack],
638+
[$enumArg, $haystackArg],
617639
[self::COMPARED_AGAINST_ENUM_INSTANCE => true],
618640
);
619641

tests/EnumAnnotateCommandTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
namespace BenSampo\Enum\Tests;
44

55
use Illuminate\Filesystem\Filesystem;
6+
use PHPUnit\Framework\Attributes\DataProvider;
67

78
final class EnumAnnotateCommandTest extends ApplicationTestCase
89
{
910
/** @dataProvider classes */
11+
#[DataProvider('classes')]
1012
public function testAnnotateClass(string $class): void
1113
{
1214
$filesystem = $this->filesystem();
@@ -19,6 +21,7 @@ public function testAnnotateClass(string $class): void
1921
}
2022

2123
/** @dataProvider classes */
24+
#[DataProvider('classes')]
2225
public function testAnnotateClassAlreadyAnnotated(string $class): void
2326
{
2427
$filesystem = $this->filesystem();
@@ -48,6 +51,7 @@ public static function sources(): iterable
4851
}
4952

5053
/** @dataProvider sources */
54+
#[DataProvider('sources')]
5155
public function testAnnotateFolder(string $source): void
5256
{
5357
$filesystem = $this->filesystem();

tests/PHPStan/UniqueValuesRuleTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,9 @@ public function testRule(): void
2828
],
2929
);
3030
}
31+
32+
protected function shouldFailOnPhpErrors(): bool
33+
{
34+
return false;
35+
}
3136
}

tests/Rector/ToNativeImplementationRectorTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
namespace BenSampo\Enum\Tests\Rector;
44

5+
use PHPUnit\Framework\Attributes\DataProvider;
56
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
67

78
/** @see \BenSampo\Enum\Rector\ToNativeImplementationRector */
89
final class ToNativeImplementationRectorTest extends AbstractRectorTestCase
910
{
1011
/** @dataProvider provideData */
12+
#[DataProvider('provideData')]
1113
public function test(string $filePath): void
1214
{
1315
$this->doTestFile($filePath);

tests/Rector/ToNativeUsagesRectorTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
namespace BenSampo\Enum\Tests\Rector;
44

5+
use PHPUnit\Framework\Attributes\DataProvider;
56
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
67

78
/** @see \BenSampo\Enum\Rector\ToNativeUsagesRector */
89
final class ToNativeUsagesRectorTest extends AbstractRectorTestCase
910
{
1011
/** @dataProvider provideData */
12+
#[DataProvider('provideData')]
1113
public function test(string $filePath): void
1214
{
1315
$this->doTestFile($filePath);

tests/Rector/Usages/in.php.inc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ use BenSampo\Enum\Tests\Enums\UserType;
55
/** @var UserType $userType */
66
$userType->in([UserType::Administrator, UserType::Subscriber(), null]);
77
$userType?->in([UserType::Administrator, $userType, null]);
8+
/** @var iterable<UserType> $iterable */
9+
$userType->in($iterable);
10+
/** @var \Illuminate\Support\Collection $collection */
11+
$userType->in($collection);
812
-----
913
<?php
1014

@@ -13,3 +17,7 @@ use BenSampo\Enum\Tests\Enums\UserType;
1317
/** @var UserType $userType */
1418
in_array($userType, [UserType::Administrator, UserType::Subscriber, null]);
1519
in_array($userType, [UserType::Administrator, $userType, null]);
20+
/** @var iterable<UserType> $iterable */
21+
in_array($userType, iterator_to_array($iterable));
22+
/** @var \Illuminate\Support\Collection $collection */
23+
$collection->contains($userType);

tests/Rector/Usages/notIn.php.inc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ use BenSampo\Enum\Tests\Enums\UserType;
55
/** @var UserType $userType */
66
$userType->notIn([UserType::Administrator]);
77
$userType?->notIn([UserType::Administrator, $userType]);
8+
/** @var iterable<UserType> $userTypes */
9+
$userType->notIn($userTypes);
10+
/** @var \Illuminate\Support\Collection $collection */
11+
$userType->notIn($collection);
812
-----
913
<?php
1014

@@ -13,3 +17,7 @@ use BenSampo\Enum\Tests\Enums\UserType;
1317
/** @var UserType $userType */
1418
!in_array($userType, [UserType::Administrator]);
1519
!in_array($userType, [UserType::Administrator, $userType]);
20+
/** @var iterable<UserType> $userTypes */
21+
!in_array($userType, iterator_to_array($userTypes));
22+
/** @var \Illuminate\Support\Collection $collection */
23+
$collection->doesntContain($userType);

0 commit comments

Comments
 (0)