-
-
Notifications
You must be signed in to change notification settings - Fork 333
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[TypeDeclaration] Add BinaryOpNullableToInstanceofRector (#3631)
- Loading branch information
1 parent
e3e5146
commit a4c1d7e
Showing
11 changed files
with
321 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
.../BooleanAnd/BinaryOpNullableToInstanceofRector/BinaryOpNullableToInstanceofRectorTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector; | ||
|
||
use Iterator; | ||
use PHPUnit\Framework\Attributes\DataProvider; | ||
use Rector\Testing\PHPUnit\AbstractRectorTestCase; | ||
|
||
final class BinaryOpNullableToInstanceofRectorTest extends AbstractRectorTestCase | ||
{ | ||
#[DataProvider('provideData')] | ||
public function test(string $filePath): void | ||
{ | ||
$this->doTestFile($filePath); | ||
} | ||
|
||
public static function provideData(): Iterator | ||
{ | ||
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); | ||
} | ||
|
||
public function provideConfigFilePath(): string | ||
{ | ||
return __DIR__ . '/config/configured_rule.php'; | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
...eclaration/Rector/BooleanAnd/BinaryOpNullableToInstanceofRector/Fixture/binary_or.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
namespace Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Fixture; | ||
|
||
use Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Source\SomeInstance; | ||
|
||
function binaryOr(?SomeInstance $someClass) | ||
{ | ||
if ($someClass || $someClass->someMethod()) { | ||
return 'yes'; | ||
} | ||
|
||
return 'no'; | ||
} | ||
|
||
?> | ||
----- | ||
<?php | ||
|
||
namespace Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Fixture; | ||
|
||
use Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Source\SomeInstance; | ||
|
||
function binaryOr(?SomeInstance $someClass) | ||
{ | ||
if ($someClass instanceof \Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Source\SomeInstance || $someClass->someMethod()) { | ||
return 'yes'; | ||
} | ||
|
||
return 'no'; | ||
} | ||
|
||
?> |
35 changes: 35 additions & 0 deletions
35
...tion/Rector/BooleanAnd/BinaryOpNullableToInstanceofRector/Fixture/other_direciton.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<?php | ||
|
||
namespace Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Fixture; | ||
|
||
use Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Source\SomeInstance; | ||
|
||
function otherDirection(?SomeInstance $someClass) | ||
{ | ||
if (mt_rand(0,1) && $someClass) { | ||
return $someClass->someMethod(); | ||
|
||
} | ||
|
||
return 'no'; | ||
} | ||
|
||
?> | ||
----- | ||
<?php | ||
|
||
namespace Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Fixture; | ||
|
||
use Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Source\SomeInstance; | ||
|
||
function otherDirection(?SomeInstance $someClass) | ||
{ | ||
if (mt_rand(0,1) && $someClass instanceof \Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Source\SomeInstance) { | ||
return $someClass->someMethod(); | ||
|
||
} | ||
|
||
return 'no'; | ||
} | ||
|
||
?> |
33 changes: 33 additions & 0 deletions
33
...claration/Rector/BooleanAnd/BinaryOpNullableToInstanceofRector/Fixture/some_class.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
namespace Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Fixture; | ||
|
||
use Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Source\SomeInstance; | ||
|
||
function someFunction(?SomeInstance $someClass) | ||
{ | ||
if ($someClass && $someClass->someMethod()) { | ||
return 'yes'; | ||
} | ||
|
||
return 'no'; | ||
} | ||
|
||
?> | ||
----- | ||
<?php | ||
|
||
namespace Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Fixture; | ||
|
||
use Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Source\SomeInstance; | ||
|
||
function someFunction(?SomeInstance $someClass) | ||
{ | ||
if ($someClass instanceof \Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Source\SomeInstance && $someClass->someMethod()) { | ||
return 'yes'; | ||
} | ||
|
||
return 'no'; | ||
} | ||
|
||
?> |
43 changes: 43 additions & 0 deletions
43
...ration/Rector/BooleanAnd/BinaryOpNullableToInstanceofRector/Fixture/with_property.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<?php | ||
|
||
namespace Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Fixture; | ||
|
||
use Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Source\SomeInstance; | ||
|
||
final class WithProperty | ||
{ | ||
private ?SomeInstance $someClass; | ||
|
||
public function run() | ||
{ | ||
if ($this->someClass && $this->someClass->someMethod()) { | ||
return 'yes'; | ||
} | ||
|
||
return 'no'; | ||
} | ||
} | ||
|
||
?> | ||
----- | ||
<?php | ||
|
||
namespace Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Fixture; | ||
|
||
use Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Source\SomeInstance; | ||
|
||
final class WithProperty | ||
{ | ||
private ?SomeInstance $someClass; | ||
|
||
public function run() | ||
{ | ||
if ($this->someClass instanceof \Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Source\SomeInstance && $this->someClass->someMethod()) { | ||
return 'yes'; | ||
} | ||
|
||
return 'no'; | ||
} | ||
} | ||
|
||
?> |
10 changes: 10 additions & 0 deletions
10
...eDeclaration/Rector/BooleanAnd/BinaryOpNullableToInstanceofRector/Source/SomeInstance.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php | ||
|
||
namespace Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\Source; | ||
|
||
final class SomeInstance | ||
{ | ||
public function someMethod() | ||
{ | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
...claration/Rector/BooleanAnd/BinaryOpNullableToInstanceofRector/config/configured_rule.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
use Rector\Config\RectorConfig; | ||
use Rector\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector; | ||
|
||
return static function (RectorConfig $rectorConfig): void { | ||
$rectorConfig->rule(BinaryOpNullableToInstanceofRector::class); | ||
}; |
103 changes: 103 additions & 0 deletions
103
rules/TypeDeclaration/Rector/BooleanAnd/BinaryOpNullableToInstanceofRector.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Rector\TypeDeclaration\Rector\BooleanAnd; | ||
|
||
use PhpParser\Node; | ||
use PhpParser\Node\Expr; | ||
use PhpParser\Node\Expr\BinaryOp\BooleanAnd; | ||
use PhpParser\Node\Expr\BinaryOp\BooleanOr; | ||
use PhpParser\Node\Expr\Instanceof_; | ||
use PhpParser\Node\Name\FullyQualified; | ||
use PHPStan\Type\ObjectType; | ||
use PHPStan\Type\TypeCombinator; | ||
use Rector\Core\Rector\AbstractRector; | ||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; | ||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; | ||
|
||
/** | ||
* @see \Rector\Tests\TypeDeclaration\Rector\BooleanAnd\BinaryOpNullableToInstanceofRector\BinaryOpNullableToInstanceofRectorTest | ||
*/ | ||
final class BinaryOpNullableToInstanceofRector extends AbstractRector | ||
{ | ||
public function getRuleDefinition(): RuleDefinition | ||
{ | ||
return new RuleDefinition('Change && and || between nullable objects to instanceof compares', [ | ||
new CodeSample( | ||
<<<'CODE_SAMPLE' | ||
function someFunction(?SomeClass $someClass) | ||
{ | ||
if ($someClass && $someClass->someMethod()) { | ||
return 'yes'; | ||
} | ||
return 'no'; | ||
} | ||
CODE_SAMPLE | ||
|
||
, | ||
<<<'CODE_SAMPLE' | ||
function someFunction(?SomeClass $someClass) | ||
{ | ||
if ($someClass instanceof SomeClass && $someClass->someMethod()) { | ||
return 'yes'; | ||
} | ||
return 'no'; | ||
} | ||
CODE_SAMPLE | ||
), | ||
]); | ||
} | ||
|
||
/** | ||
* @return array<class-string<Node>> | ||
*/ | ||
public function getNodeTypes(): array | ||
{ | ||
return [BooleanAnd::class, BooleanOr::class]; | ||
} | ||
|
||
/** | ||
* @param BooleanAnd|BooleanOr $node | ||
*/ | ||
public function refactor(Node $node): ?Node | ||
{ | ||
$nullableObjectType = $this->returnNullableObjectType($node->left); | ||
|
||
if ($nullableObjectType instanceof ObjectType) { | ||
$node->left = $this->createExprInstanceof($node->left, $nullableObjectType); | ||
|
||
return $node; | ||
} | ||
|
||
$nullableObjectType = $this->returnNullableObjectType($node->right); | ||
|
||
if ($nullableObjectType instanceof ObjectType) { | ||
$node->right = $this->createExprInstanceof($node->right, $nullableObjectType); | ||
|
||
return $node; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
private function returnNullableObjectType(Expr $expr): ObjectType|null | ||
{ | ||
$exprType = $this->getType($expr); | ||
|
||
$baseType = TypeCombinator::removeNull($exprType); | ||
if (! $baseType instanceof ObjectType) { | ||
return null; | ||
} | ||
|
||
return $baseType; | ||
} | ||
|
||
private function createExprInstanceof(Expr $expr, ObjectType $objectType): Instanceof_ | ||
{ | ||
$fullyQualified = new FullyQualified($objectType->getClassName()); | ||
return new Instanceof_($expr, $fullyQualified); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters