diff --git a/rules-tests/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector/Fixture/skip_return_in_closure_only.php.inc b/rules-tests/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector/Fixture/skip_return_in_closure_only.php.inc new file mode 100644 index 000000000..0a7cf3ff7 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector/Fixture/skip_return_in_closure_only.php.inc @@ -0,0 +1,19 @@ +render('some_template'); + } +} + +?> +----- +render('some_template'); + } +} + +?> diff --git a/rules-tests/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector/FixtureTypeGuarded/non_guarded_controller.php.inc b/rules-tests/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector/FixtureTypeGuarded/non_guarded_controller.php.inc new file mode 100644 index 000000000..6fca15351 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector/FixtureTypeGuarded/non_guarded_controller.php.inc @@ -0,0 +1,35 @@ +render('some_template'); + } +} + +?> +----- +render('some_template'); + } +} + +?> diff --git a/rules-tests/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector/FixtureTypeGuarded/skip_type_guarded_controller.php.inc b/rules-tests/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector/FixtureTypeGuarded/skip_type_guarded_controller.php.inc new file mode 100644 index 000000000..0fd8e7fb0 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector/FixtureTypeGuarded/skip_type_guarded_controller.php.inc @@ -0,0 +1,15 @@ +render('some_template'); + } +} diff --git a/rules-tests/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector/ResponseReturnTypeControllerActionRectorTypeGuardedTest.php b/rules-tests/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector/ResponseReturnTypeControllerActionRectorTypeGuardedTest.php new file mode 100644 index 000000000..a55e9fbaf --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector/ResponseReturnTypeControllerActionRectorTypeGuardedTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/FixtureTypeGuarded'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/type_guarded_rule.php'; + } +} diff --git a/rules-tests/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector/Source/AbstractCustomController.php b/rules-tests/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector/Source/AbstractCustomController.php new file mode 100644 index 000000000..64d193175 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector/Source/AbstractCustomController.php @@ -0,0 +1,11 @@ +withRules([ResponseReturnTypeControllerActionRector::class]) + ->withTypeGuardedClasses([AbstractCustomController::class]); diff --git a/rules/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector.php b/rules/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector.php index f7c14f2cc..8d8a9067d 100644 --- a/rules/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector.php +++ b/rules/CodeQuality/Rector/ClassMethod/ResponseReturnTypeControllerActionRector.php @@ -30,6 +30,7 @@ use Rector\TypeDeclaration\NodeAnalyzer\ReturnAnalyzer; use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer; use Rector\ValueObject\PhpVersionFeature; +use Rector\VendorLocker\ParentClassMethodTypeOverrideGuard; use Rector\VersionBonding\Contract\MinPhpVersionInterface; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -45,7 +46,8 @@ public function __construct( private readonly BetterNodeFinder $betterNodeFinder, private readonly ReturnAnalyzer $returnAnalyzer, private readonly StaticTypeMapper $staticTypeMapper, - private readonly ReturnTypeInferer $returnTypeInferer + private readonly ReturnTypeInferer $returnTypeInferer, + private readonly ParentClassMethodTypeOverrideGuard $parentClassMethodTypeOverrideGuard ) { } @@ -112,6 +114,11 @@ public function refactor(Node $node): ?Node return null; } + // adding a return type would break child classes of user-guarded classes + if ($this->parentClassMethodTypeOverrideGuard->isTypeGuardedClass($node)) { + return null; + } + if (! $this->isActionClassMethod($node)) { return null; } @@ -188,7 +195,7 @@ private function isActionClassMethod(ClassMethod $classMethod): bool private function hasReturn(ClassMethod $classMethod): bool { - return $this->betterNodeFinder->hasInstancesOf($classMethod, [Return_::class]); + return $this->betterNodeFinder->hasInstancesOfInFunctionLikeScoped($classMethod, Return_::class); } private function refactorResponse(ClassMethod $classMethod): ?ClassMethod