From c648be5b541b315515816bd072699e05ec3f29d2 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 7 Oct 2025 03:45:16 +0700 Subject: [PATCH 1/7] [CodeQuality] Handle property fetch and common nodes crash on InlineArrayReturnAssignRector --- .../Fixture/with_property_fetch.php.inc | 48 +++++++++++++++++++ src/PhpParser/Node/NodeFactory.php | 17 ++++++- 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 rules-tests/CodeQuality/Rector/ClassMethod/InlineArrayReturnAssignRector/Fixture/with_property_fetch.php.inc diff --git a/rules-tests/CodeQuality/Rector/ClassMethod/InlineArrayReturnAssignRector/Fixture/with_property_fetch.php.inc b/rules-tests/CodeQuality/Rector/ClassMethod/InlineArrayReturnAssignRector/Fixture/with_property_fetch.php.inc new file mode 100644 index 00000000000..81fb58cc089 --- /dev/null +++ b/rules-tests/CodeQuality/Rector/ClassMethod/InlineArrayReturnAssignRector/Fixture/with_property_fetch.php.inc @@ -0,0 +1,48 @@ +name; + $event['payload'] = $this->bar(); + $event['data'] = $obj?->data; + $event['item'] = $obj?->getItem(); + $event['list'] = clone $obj; + $event['verify'] = $obj instanceof \stdClass; + + return $event; + } + + private function bar(): array + { + return []; + } +} + +?> +----- + $this->name, 'payload' => $this->bar(), 'data' => $obj?->data, 'item' => $obj?->getItem(), 'list' => clone $obj, 'verify' => $obj instanceof \stdClass]; + } + + private function bar(): array + { + return []; + } +} + +?> \ No newline at end of file diff --git a/src/PhpParser/Node/NodeFactory.php b/src/PhpParser/Node/NodeFactory.php index eba3a7be6a3..5b5c708debf 100644 --- a/src/PhpParser/Node/NodeFactory.php +++ b/src/PhpParser/Node/NodeFactory.php @@ -23,10 +23,14 @@ use PhpParser\Node\Expr\BinaryOp\NotIdentical; use PhpParser\Node\Expr\Cast; use PhpParser\Node\Expr\ClassConstFetch; +use PhpParser\Node\Expr\Clone_; use PhpParser\Node\Expr\ConstFetch; use PhpParser\Node\Expr\FuncCall; +use PhpParser\Node\Expr\Instanceof_; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\New_; +use PhpParser\Node\Expr\NullsafeMethodCall; +use PhpParser\Node\Expr\NullsafePropertyFetch; use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Expr\StaticPropertyFetch; @@ -377,6 +381,12 @@ private function createArrayItem(mixed $item, string | int | null $key = null): || $item instanceof Scalar || $item instanceof Cast || $item instanceof ConstFetch + || $item instanceof PropertyFetch + || $item instanceof StaticPropertyFetch + || $item instanceof NullsafePropertyFetch + || $item instanceof NullsafeMethodCall + || $item instanceof Clone_ + || $item instanceof Instanceof_ ) { $arrayItem = new ArrayItem($item); } elseif ($item instanceof Identifier) { @@ -411,7 +421,12 @@ private function createArrayItem(mixed $item, string | int | null $key = null): return $arrayItem; } - $nodeClass = is_object($item) ? $item::class : $item; + // fallback to other nodes + if (is_object($item)) { + return new ArrayItem($item); + } + + $nodeClass = $item; throw new NotImplementedYetException(sprintf( 'Not implemented yet. Go to "%s()" and add check for "%s" node.', __METHOD__, From 4c6ed0dec9d69ec7a4c00566f81af746b181f4fb Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 7 Oct 2025 03:49:03 +0700 Subject: [PATCH 2/7] [CodeQuality] Handle property fetch and common nodes crash on InlineArrayReturnAssignRector --- src/PhpParser/Node/NodeFactory.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/PhpParser/Node/NodeFactory.php b/src/PhpParser/Node/NodeFactory.php index 5b5c708debf..3c34559daa2 100644 --- a/src/PhpParser/Node/NodeFactory.php +++ b/src/PhpParser/Node/NodeFactory.php @@ -426,12 +426,8 @@ private function createArrayItem(mixed $item, string | int | null $key = null): return new ArrayItem($item); } - $nodeClass = $item; - throw new NotImplementedYetException(sprintf( - 'Not implemented yet. Go to "%s()" and add check for "%s" node.', - __METHOD__, - (string) $nodeClass - )); + $itemValue = BuilderHelpers::normalizeValue($item); + return new ArrayItem($itemValue); } private function decorateArrayItemWithKey(int | string | null $key, ArrayItem $arrayItem): void From 6479ef5bf85580959fa6bee2f9c78fa18d9b794e Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 7 Oct 2025 03:52:19 +0700 Subject: [PATCH 3/7] fix rectify --- .../ClassLikeNameClassNameImportSkipVoter.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/ClassLikeNameClassNameImportSkipVoter.php b/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/ClassLikeNameClassNameImportSkipVoter.php index 035fda21883..acc913efc0f 100644 --- a/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/ClassLikeNameClassNameImportSkipVoter.php +++ b/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/ClassLikeNameClassNameImportSkipVoter.php @@ -46,8 +46,9 @@ public function shouldSkip(File $file, FullyQualifiedObjectType $fullyQualifiedO $namespace = strtolower((string) $namespace); $shortNameLowered = $fullyQualifiedObjectType->getShortNameLowered(); + $fullyQualifiedObjectTypeNamespace = strtolower( - substr($fullyQualifiedObjectType->getClassName(), 0, -strlen($fullyQualifiedObjectType->getShortName()) - 1) ?: '' + (string) substr($fullyQualifiedObjectType->getClassName(), 0, -strlen($fullyQualifiedObjectType->getShortName()) - 1) ); foreach ($classLikeNames as $classLikeName) { From c8dfbf24adf46b61c6a169210a12977b0c98e2fe Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 6 Oct 2025 20:55:04 +0000 Subject: [PATCH 4/7] [ci-review] Rector Rectify --- .../ClassLikeNameClassNameImportSkipVoter.php | 2 +- src/PhpParser/Node/NodeFactory.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/ClassLikeNameClassNameImportSkipVoter.php b/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/ClassLikeNameClassNameImportSkipVoter.php index acc913efc0f..27466a5548e 100644 --- a/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/ClassLikeNameClassNameImportSkipVoter.php +++ b/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/ClassLikeNameClassNameImportSkipVoter.php @@ -48,7 +48,7 @@ public function shouldSkip(File $file, FullyQualifiedObjectType $fullyQualifiedO $shortNameLowered = $fullyQualifiedObjectType->getShortNameLowered(); $fullyQualifiedObjectTypeNamespace = strtolower( - (string) substr($fullyQualifiedObjectType->getClassName(), 0, -strlen($fullyQualifiedObjectType->getShortName()) - 1) + substr($fullyQualifiedObjectType->getClassName(), 0, -strlen($fullyQualifiedObjectType->getShortName()) - 1) ); foreach ($classLikeNames as $classLikeName) { diff --git a/src/PhpParser/Node/NodeFactory.php b/src/PhpParser/Node/NodeFactory.php index 3c34559daa2..4b30ee35f45 100644 --- a/src/PhpParser/Node/NodeFactory.php +++ b/src/PhpParser/Node/NodeFactory.php @@ -48,7 +48,6 @@ use PHPStan\Type\Type; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; use Rector\Enum\ObjectReference; -use Rector\Exception\NotImplementedYetException; use Rector\Exception\ShouldNotHappenException; use Rector\NodeDecorator\PropertyTypeDecorator; use Rector\NodeTypeResolver\Node\AttributeKey; From 65ab663cd641b5ca65db5ccdcbc384077ee8ea0d Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 7 Oct 2025 03:55:09 +0700 Subject: [PATCH 5/7] fix rectify --- src/PhpParser/Node/NodeFactory.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/PhpParser/Node/NodeFactory.php b/src/PhpParser/Node/NodeFactory.php index 3c34559daa2..8d9304b2699 100644 --- a/src/PhpParser/Node/NodeFactory.php +++ b/src/PhpParser/Node/NodeFactory.php @@ -423,11 +423,17 @@ private function createArrayItem(mixed $item, string | int | null $key = null): // fallback to other nodes if (is_object($item)) { - return new ArrayItem($item); + $arrayItem = new ArrayItem($item); + $this->decorateArrayItemWithKey($key, $arrayItem); + + return $arrayItem; } $itemValue = BuilderHelpers::normalizeValue($item); - return new ArrayItem($itemValue); + $arrayItem = new ArrayItem($itemValue); + $this->decorateArrayItemWithKey($key, $arrayItem); + + return $arrayItem; } private function decorateArrayItemWithKey(int | string | null $key, ArrayItem $arrayItem): void From 5460b7d794d98e38b4ae14e7f79d222248f10c65 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 7 Oct 2025 04:03:29 +0700 Subject: [PATCH 6/7] fix --- rector.php | 6 ++++++ .../ClassLikeNameClassNameImportSkipVoter.php | 6 ++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/rector.php b/rector.php index b24f7fe82f0..375966c5c91 100644 --- a/rector.php +++ b/rector.php @@ -4,6 +4,7 @@ use Rector\CodingStyle\Rector\String_\UseClassKeywordForClassNameResolutionRector; use Rector\Config\RectorConfig; +use Rector\DeadCode\Rector\Cast\RecastingRemovalRector; use Rector\DeadCode\Rector\ConstFetch\RemovePhpVersionIdCheckRector; use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector; @@ -52,4 +53,9 @@ __DIR__ . '/src/Configuration/RectorConfigBuilder.php', __DIR__ . '/src/Console/Notifier.php', ], + + // todo: properly handle, substr() can return false on php 7.x + RecastingRemovalRector::class => [ + __DIR__ . '/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/ClassLikeNameClassNameImportSkipVoter.php', + ], ]); diff --git a/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/ClassLikeNameClassNameImportSkipVoter.php b/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/ClassLikeNameClassNameImportSkipVoter.php index 27466a5548e..be8a44e9ce3 100644 --- a/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/ClassLikeNameClassNameImportSkipVoter.php +++ b/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/ClassLikeNameClassNameImportSkipVoter.php @@ -46,10 +46,8 @@ public function shouldSkip(File $file, FullyQualifiedObjectType $fullyQualifiedO $namespace = strtolower((string) $namespace); $shortNameLowered = $fullyQualifiedObjectType->getShortNameLowered(); - - $fullyQualifiedObjectTypeNamespace = strtolower( - substr($fullyQualifiedObjectType->getClassName(), 0, -strlen($fullyQualifiedObjectType->getShortName()) - 1) - ); + $subClassName = substr($fullyQualifiedObjectType->getClassName(), 0, -strlen($fullyQualifiedObjectType->getShortName()) - 1); + $fullyQualifiedObjectTypeNamespace = strtolower((string) $subClassName); foreach ($classLikeNames as $classLikeName) { if (strtolower($classLikeName) !== $shortNameLowered) { From 26daff394f5ecb65c84fcef69c81ad9c85fcb520 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 7 Oct 2025 04:07:01 +0700 Subject: [PATCH 7/7] fix phpstan --- src/PhpParser/Node/NodeFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpParser/Node/NodeFactory.php b/src/PhpParser/Node/NodeFactory.php index 9e329228085..e3744ce7632 100644 --- a/src/PhpParser/Node/NodeFactory.php +++ b/src/PhpParser/Node/NodeFactory.php @@ -421,7 +421,7 @@ private function createArrayItem(mixed $item, string | int | null $key = null): } // fallback to other nodes - if (is_object($item)) { + if ($item instanceof Expr) { $arrayItem = new ArrayItem($item); $this->decorateArrayItemWithKey($key, $arrayItem);