diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/AddArrayReturnDocTypeRector/Fixture/call_reflection_resolver.php.inc b/rules-tests/TypeDeclaration/Rector/ClassMethod/AddArrayReturnDocTypeRector/Fixture/call_reflection_resolver.php.inc deleted file mode 100644 index 126927045db..00000000000 --- a/rules-tests/TypeDeclaration/Rector/ClassMethod/AddArrayReturnDocTypeRector/Fixture/call_reflection_resolver.php.inc +++ /dev/null @@ -1,70 +0,0 @@ -resolveFunctionCall($node); - } - - return $this->resolveMethodCall($node); - } - - /** - * @return FunctionReflection|MethodReflection|null - */ - private function resolveFunctionCall(FuncCall $funcCall) - { - } - - private function resolveMethodCall(Node $node): ?MethodReflection - { - } - -} -?> ------ -resolveFunctionCall($node); - } - - return $this->resolveMethodCall($node); - } - - /** - * @return FunctionReflection|MethodReflection|null - */ - private function resolveFunctionCall(FuncCall $funcCall) - { - } - - private function resolveMethodCall(Node $node): ?MethodReflection - { - } - -} -?> diff --git a/rules-tests/TypeDeclaration/Rector/ClassMethod/AddArrayReturnDocTypeRector/Fixture/has_offset.php.inc b/rules-tests/TypeDeclaration/Rector/ClassMethod/AddArrayReturnDocTypeRector/Fixture/has_offset.php.inc deleted file mode 100644 index 12b45cddc44..00000000000 --- a/rules-tests/TypeDeclaration/Rector/ClassMethod/AddArrayReturnDocTypeRector/Fixture/has_offset.php.inc +++ /dev/null @@ -1,46 +0,0 @@ - ------ - diff --git a/rules/TypeDeclaration/Rector/ClassMethod/AddArrayReturnDocTypeRector.php b/rules/TypeDeclaration/Rector/ClassMethod/AddArrayReturnDocTypeRector.php index ab48bb0f1ce..3b371e61c32 100644 --- a/rules/TypeDeclaration/Rector/ClassMethod/AddArrayReturnDocTypeRector.php +++ b/rules/TypeDeclaration/Rector/ClassMethod/AddArrayReturnDocTypeRector.php @@ -25,6 +25,7 @@ use Rector\Privatization\TypeManipulator\TypeNormalizer; use Rector\TypeDeclaration\NodeTypeAnalyzer\DetailedTypeAnalyzer; use Rector\TypeDeclaration\TypeAnalyzer\AdvancedArrayAnalyzer; +use Rector\TypeDeclaration\TypeAnalyzer\IterableTypeAnalyzer; use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer; use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer\ReturnTypeDeclarationReturnTypeInfererTypeInferer; use Rector\VendorLocker\NodeVendorLocker\ClassMethodReturnTypeOverrideGuard; @@ -45,6 +46,7 @@ public function __construct( private readonly ReturnTagRemover $returnTagRemover, private readonly DetailedTypeAnalyzer $detailedTypeAnalyzer, private readonly TypeNormalizer $typeNormalizer, + private readonly IterableTypeAnalyzer $iterableTypeAnalyzer, ) { } @@ -178,6 +180,10 @@ private function shouldSkipType( ClassMethod $classMethod, PhpDocInfo $phpDocInfo ): bool { + if (! $this->iterableTypeAnalyzer->isIterableType($newType)) { + return true; + } + if ($newType instanceof ArrayType && $this->shouldSkipArrayType($newType, $classMethod, $phpDocInfo)) { return true; } diff --git a/rules/TypeDeclaration/TypeAnalyzer/IterableTypeAnalyzer.php b/rules/TypeDeclaration/TypeAnalyzer/IterableTypeAnalyzer.php new file mode 100644 index 00000000000..13d1a3e5bc1 --- /dev/null +++ b/rules/TypeDeclaration/TypeAnalyzer/IterableTypeAnalyzer.php @@ -0,0 +1,69 @@ +isUnionOfIterableTypes($type)) { + return true; + } + + if ($type instanceof ArrayType) { + return true; + } + + if ($type instanceof IterableType) { + return true; + } + + if ($type instanceof GenericObjectType) { + if (! $this->reflectionProvider->hasClass($type->getClassName())) { + return false; + } + + $genericObjectTypeClassReflection = $this->reflectionProvider->getClass($type->getClassName()); + if ($genericObjectTypeClassReflection->implementsInterface('Traversable')) { + return true; + } + } + + return false; + } + + private function isUnionOfIterableTypes(Type $type): bool + { + if (! $type instanceof UnionType) { + return false; + } + + foreach ($type->getTypes() as $unionedType) { + // nullable union is allowed + if ($unionedType instanceof NullType) { + continue; + } + + if (! $this->isIterableType($unionedType)) { + return false; + } + } + + return true; + } +} diff --git a/src/functions/node_helper.php b/src/functions/node_helper.php index 3971561b5a4..176ff63e216 100644 --- a/src/functions/node_helper.php +++ b/src/functions/node_helper.php @@ -6,6 +6,18 @@ use PhpParser\PrettyPrinter\Standard; use Tracy\Dumper; +if (! function_exists('dump_with_depth')) { + /** + * @param mixed $value + */ + function dump_with_depth($value, int $depth = 2): void + { + Dumper::dump($value, [ + Dumper::DEPTH => $depth, + ]); + } +} + if (! function_exists('dn')) { function dn(Node $node, int $depth = 2): void { diff --git a/tests/Issues/IssueEarlyReturnAndOrNarrow/Fixture/and_next_or.php.inc b/tests/Issues/IssueEarlyReturnAndOrNarrow/Fixture/and_next_or.php.inc deleted file mode 100644 index bc2e2aa5b46..00000000000 --- a/tests/Issues/IssueEarlyReturnAndOrNarrow/Fixture/and_next_or.php.inc +++ /dev/null @@ -1,42 +0,0 @@ - ------ - diff --git a/tests/Issues/IssueEarlyReturnAndOrNarrow/IssueEarlyReturnAndOrNarrowTest.php b/tests/Issues/IssueEarlyReturnAndOrNarrow/IssueEarlyReturnAndOrNarrowTest.php deleted file mode 100644 index a3b40a4e978..00000000000 --- a/tests/Issues/IssueEarlyReturnAndOrNarrow/IssueEarlyReturnAndOrNarrowTest.php +++ /dev/null @@ -1,33 +0,0 @@ -doTestFileInfo($fileInfo); - } - - /** - * @return Iterator - */ - public function provideData(): Iterator - { - return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture'); - } - - public function provideConfigFilePath(): string - { - return __DIR__ . '/config/configured_rule.php'; - } -} diff --git a/tests/Issues/IssueEarlyReturnAndOrNarrow/config/configured_rule.php b/tests/Issues/IssueEarlyReturnAndOrNarrow/config/configured_rule.php deleted file mode 100644 index 75d41be81e2..00000000000 --- a/tests/Issues/IssueEarlyReturnAndOrNarrow/config/configured_rule.php +++ /dev/null @@ -1,17 +0,0 @@ -services(); - $services->set(ChangeOrIfReturnToEarlyReturnRector::class); - $services->set(ChangeAndIfToEarlyReturnRector::class); - $services->set(AddArrayReturnDocTypeRector::class); - $services->set(NarrowUnionTypeDocRector::class); -};