Skip to content

Commit ef9ace2

Browse files
authored
[CodeQuality] Skip AssertIssetToSpecificMethodRector on ArrayAccess objects (#692)
isset($obj[$key]) on an ArrayAccess object is not equivalent to assertArrayHasKey($key, $obj): the key may be any type (assertArrayHasKey() requires int|string) and offsetExists() semantics can differ from array_key_exists(). Converting it produced code that throws for non-scalar keys. Skip the rule when the subject is an ArrayAccess object.
1 parent af52365 commit ef9ace2

3 files changed

Lines changed: 50 additions & 0 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\AssertIssetToSpecificMethodRector\Fixture;
4+
5+
use Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\AssertIssetToSpecificMethodRector\Source\SomeArrayAccessStore;
6+
7+
final class SkipArrayAccessObject extends \PHPUnit\Framework\TestCase
8+
{
9+
public function test()
10+
{
11+
$store = new SomeArrayAccessStore();
12+
13+
$this->assertTrue(isset($store[$key]), 'message');
14+
$this->assertFalse(isset($store[$key]));
15+
}
16+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\PHPUnit\Tests\CodeQuality\Rector\MethodCall\AssertIssetToSpecificMethodRector\Source;
6+
7+
final class SomeArrayAccessStore implements \ArrayAccess
8+
{
9+
public function offsetExists($offset): bool
10+
{
11+
return true;
12+
}
13+
14+
public function offsetGet($offset): mixed
15+
{
16+
return null;
17+
}
18+
19+
public function offsetSet($offset, $value): void
20+
{
21+
}
22+
23+
public function offsetUnset($offset): void
24+
{
25+
}
26+
}

rules/CodeQuality/Rector/MethodCall/AssertIssetToSpecificMethodRector.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use PhpParser\Node\Expr\Isset_;
1010
use PhpParser\Node\Expr\MethodCall;
1111
use PhpParser\Node\Expr\StaticCall;
12+
use PHPStan\Type\ObjectType;
1213
use Rector\PHPUnit\Enum\AssertMethod;
1314
use Rector\PHPUnit\NodeAnalyzer\IdentifierManipulator;
1415
use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer;
@@ -77,6 +78,13 @@ public function refactor(Node $node): ?Node
7778
return null;
7879
}
7980

81+
// isset() on an ArrayAccess object is not equivalent to assertArrayHasKey():
82+
// the key may be any type (assertArrayHasKey() requires int|string) and offsetExists()
83+
// semantics can differ from array_key_exists()
84+
if ($this->isObjectType($issetExpr->var, new ObjectType('ArrayAccess'))) {
85+
return null;
86+
}
87+
8088
return $this->refactorArrayDimFetchNode($node, $issetExpr);
8189
}
8290

0 commit comments

Comments
 (0)