diff --git a/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Fixture/promoted_property.php.inc b/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Fixture/promoted_property.php.inc new file mode 100644 index 00000000000..95c5efc2d92 --- /dev/null +++ b/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Fixture/promoted_property.php.inc @@ -0,0 +1,40 @@ +userRepository instanceof UserRepository); + } +} + +?> +----- + diff --git a/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Fixture/skip_nullable_property.php.inc b/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Fixture/skip_nullable_property.php.inc new file mode 100644 index 00000000000..ec606b9a798 --- /dev/null +++ b/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Fixture/skip_nullable_property.php.inc @@ -0,0 +1,18 @@ +userRepository instanceof UserRepository); + } +} diff --git a/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Fixture/skip_untyped_property.php.inc b/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Fixture/skip_untyped_property.php.inc new file mode 100644 index 00000000000..7b65fe5bc09 --- /dev/null +++ b/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Fixture/skip_untyped_property.php.inc @@ -0,0 +1,15 @@ +userRepository instanceof UserRepository); + } +} diff --git a/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Fixture/skip_with_message.php.inc b/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Fixture/skip_with_message.php.inc new file mode 100644 index 00000000000..75921880d68 --- /dev/null +++ b/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Fixture/skip_with_message.php.inc @@ -0,0 +1,18 @@ +userRepository instanceof UserRepository, 'must be set'); + } +} diff --git a/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Fixture/typed_variable.php.inc b/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Fixture/typed_variable.php.inc new file mode 100644 index 00000000000..9d952946bbd --- /dev/null +++ b/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Fixture/typed_variable.php.inc @@ -0,0 +1,24 @@ + +----- + diff --git a/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/RemoveDeadInstanceOfAssertRectorTest.php b/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/RemoveDeadInstanceOfAssertRectorTest.php new file mode 100644 index 00000000000..1aa9c1678e8 --- /dev/null +++ b/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/RemoveDeadInstanceOfAssertRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Source/UserRepository.php b/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Source/UserRepository.php new file mode 100644 index 00000000000..aa051b11cc9 --- /dev/null +++ b/rules-tests/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector/Source/UserRepository.php @@ -0,0 +1,9 @@ +withRules([RemoveDeadInstanceOfAssertRector::class]); diff --git a/rules/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector.php b/rules/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector.php new file mode 100644 index 00000000000..16e56bc89f7 --- /dev/null +++ b/rules/DeadCode/Rector/StmtsAwareInterface/RemoveDeadInstanceOfAssertRector.php @@ -0,0 +1,155 @@ +userRepository instanceof UserRepository); + } +} +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +final class SomeClass +{ + public function __construct( + private UserRepository $userRepository + ) { + } + + public function run(): void + { + } +} +CODE_SAMPLE + ), + ] + ); + } + + public function getNodeTypes(): array + { + return NodeGroup::STMTS_AWARE; + } + + /** + * @param StmtsAware $node + */ + public function refactor(Node $node): ?Node + { + if ($node->stmts === null) { + return null; + } + + $hasChanged = false; + + foreach ($node->stmts as $key => $stmt) { + if (! $stmt instanceof Expression) { + continue; + } + + if (! $this->isDeadInstanceOfAssert($stmt->expr)) { + continue; + } + + $docComment = $stmt->getDocComment(); + if ($docComment instanceof Doc) { + $nop = new Nop(); + $nop->setDocComment($docComment); + $node->stmts[$key] = $nop; + } else { + unset($node->stmts[$key]); + } + + $hasChanged = true; + } + + if (! $hasChanged) { + return null; + } + + $node->stmts = array_values($node->stmts); + + return $node; + } + + private function isDeadInstanceOfAssert(Expr $expr): bool + { + if (! $expr instanceof FuncCall) { + return false; + } + + if ($expr->isFirstClassCallable()) { + return false; + } + + if (! $this->isName($expr, 'assert')) { + return false; + } + + // single-arg assert only; keep asserts that carry a description message + if (count($expr->getArgs()) !== 1) { + return false; + } + + $instanceof = $expr->getArgs()[0] + ->value; + if (! $instanceof instanceof Instanceof_) { + return false; + } + + // only property fetch or variable value + if (! $instanceof->expr instanceof PropertyFetch && ! $instanceof->expr instanceof Variable) { + return false; + } + + if (! $instanceof->class instanceof Name) { + return false; + } + + $classType = $this->nodeTypeResolver->getType($instanceof->class); + $exprType = $this->nodeTypeResolver->getType($instanceof->expr); + if ($classType->equals($exprType)) { + return true; + } + + return $classType->isSuperTypeOf($exprType) + ->yes(); + } +} diff --git a/rules/Privatization/Guard/ParentPropertyLookupGuard.php b/rules/Privatization/Guard/ParentPropertyLookupGuard.php index c6279f68fee..7f104ba7cbc 100644 --- a/rules/Privatization/Guard/ParentPropertyLookupGuard.php +++ b/rules/Privatization/Guard/ParentPropertyLookupGuard.php @@ -28,7 +28,7 @@ * * @var string[] */ - private const SYMFONY_COMMAND_RESERVED_PROPERTY_NAMES = ['defaultName', 'defaultDescription']; + private const array SYMFONY_COMMAND_RESERVED_PROPERTY_NAMES = ['defaultName', 'defaultDescription']; public function __construct( private BetterNodeFinder $betterNodeFinder, diff --git a/src/Config/Level/DeadCodeLevel.php b/src/Config/Level/DeadCodeLevel.php index 230770622c6..7beacae376f 100644 --- a/src/Config/Level/DeadCodeLevel.php +++ b/src/Config/Level/DeadCodeLevel.php @@ -64,6 +64,7 @@ use Rector\DeadCode\Rector\Stmt\RemoveConditionExactReturnRector; use Rector\DeadCode\Rector\Stmt\RemoveNextSameValueConditionRector; use Rector\DeadCode\Rector\Stmt\RemoveUnreachableStatementRector; +use Rector\DeadCode\Rector\StmtsAwareInterface\RemoveDeadInstanceOfAssertRector; use Rector\DeadCode\Rector\Switch_\RemoveDuplicatedCaseInSwitchRector; use Rector\DeadCode\Rector\Ternary\RemoveUselessTernaryRector; use Rector\DeadCode\Rector\Ternary\TernaryToBooleanOrFalseToBooleanAndRector; @@ -104,6 +105,7 @@ final class DeadCodeLevel RemoveFilterVarOnExactTypeRector::class, RemoveTypedPropertyDeadInstanceOfRector::class, + RemoveDeadInstanceOfAssertRector::class, TernaryToBooleanOrFalseToBooleanAndRector::class, RemoveUselessTernaryRector::class, RemoveDoubleAssignRector::class,