diff --git a/packages/NodeRemoval/AssignRemover.php b/packages/NodeRemoval/AssignRemover.php deleted file mode 100644 index def2517cc82..00000000000 --- a/packages/NodeRemoval/AssignRemover.php +++ /dev/null @@ -1,51 +0,0 @@ -betterNodeFinder->resolveCurrentStatement($assign); - - if (! $currentStatement instanceof Stmt) { - return; - } - - $this->livingCodeManipulator->addLivingCodeBeforeNode($assign->var, $currentStatement); - - /** @var Assign $assign */ - $parent = $assign->getAttribute(AttributeKey::PARENT_NODE); - if ($parent instanceof Expression) { - $this->nodeRemover->removeNode($assign); - return; - } - - $this->nodesToReplaceCollector->addReplaceNodeWithAnotherNode($assign, $assign->expr); - $this->rectorChangeCollector->notifyNodeFileInfo($assign->expr); - - if ($parent instanceof Assign) { - $this->removeAssignNode($parent); - } - } -} diff --git a/packages/PostRector/Collector/NodesToReplaceCollector.php b/packages/PostRector/Collector/NodesToReplaceCollector.php deleted file mode 100644 index f5813456b85..00000000000 --- a/packages/PostRector/Collector/NodesToReplaceCollector.php +++ /dev/null @@ -1,37 +0,0 @@ - - */ - private array $nodesToReplace = []; - - public function addReplaceNodeWithAnotherNode(Node $node, Node $replaceWith): void - { - $this->nodesToReplace[] = [$node, $replaceWith]; - } - - public function isActive(): bool - { - return $this->nodesToReplace !== []; - } - - /** - * @return array - */ - public function getNodes(): array - { - return $this->nodesToReplace; - } -} diff --git a/packages/PostRector/Rector/NodeToReplacePostRector.php b/packages/PostRector/Rector/NodeToReplacePostRector.php deleted file mode 100644 index 08bd1ad84df..00000000000 --- a/packages/PostRector/Rector/NodeToReplacePostRector.php +++ /dev/null @@ -1,63 +0,0 @@ -nodesToReplaceCollector->getNodes() as [$nodeToFind, $replacement]) { - if ($node === $nodeToFind) { - return $replacement; - } - } - - return null; - } - - public function getRuleDefinition(): RuleDefinition - { - return new RuleDefinition( - 'Replaces nodes on weird positions', - [ - new CodeSample( - <<<'CODE_SAMPLE' -class SomeClass -{ - public function run($value) - { - return 1; - } -} -CODE_SAMPLE - , - <<<'CODE_SAMPLE' -class SomeClass -{ - public function run($value) - { - return $value; - } -} -CODE_SAMPLE - ), ] - ); - } -} diff --git a/packages/ReadWrite/NodeAnalyzer/ReadWritePropertyAnalyzer.php b/packages/ReadWrite/NodeAnalyzer/ReadWritePropertyAnalyzer.php index 2e07d12298a..c3727736fd6 100644 --- a/packages/ReadWrite/NodeAnalyzer/ReadWritePropertyAnalyzer.php +++ b/packages/ReadWrite/NodeAnalyzer/ReadWritePropertyAnalyzer.php @@ -7,6 +7,7 @@ namespace Rector\ReadWrite\NodeAnalyzer; use PhpParser\Node; use PhpParser\Node\Arg; use PhpParser\Node\Expr\ArrayDimFetch; +use PhpParser\Node\Expr\AssignOp; use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\Isset_; use PhpParser\Node\Expr\PostDec; @@ -41,6 +42,26 @@ final class ReadWritePropertyAnalyzer throw new ShouldNotHappenException(); } + if ($parent instanceof PostInc) { + return true; + } + + if ($parent instanceof PreInc) { + return true; + } + + if ($parent instanceof PostDec) { + return true; + } + + if ($parent instanceof PreDec) { + return true; + } + + if ($parent instanceof AssignOp) { + return true; + } + $parent = $this->unwrapPostPreIncDec($parent); if ($parent instanceof Arg) { diff --git a/phpstan.neon b/phpstan.neon index 45e0eb53abb..cfd5b0c138a 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -89,7 +89,6 @@ parameters: - rules/Php70/EregToPcreTransformer.php - packages/NodeTypeResolver/NodeTypeResolver.php - rules/Renaming/NodeManipulator/ClassRenamer.php - - rules/DogFood/Rector/Closure/UpgradeRectorConfigRector.php - "#^Cognitive complexity for \"Rector\\\\Php70\\\\EregToPcreTransformer\\:\\:(.*?)\" is (.*?), keep it under 10$#" - '#Cognitive complexity for "Rector\\Core\\PhpParser\\Node\\Value\\ValueResolver\:\:getValue\(\)" is \d+, keep it under 10#' @@ -150,8 +149,6 @@ parameters: - '#Method Rector\\CodeQuality\\Rector\\Foreach_\\SimplifyForeachToCoalescingRector\:\:matchReturnOrAssignNode\(\) should return PhpParser\\Node\\Expr\\Assign\|PhpParser\\Node\\Stmt\\Return_\|null but returns PhpParser\\Node\|null#' - - '#Instanceof between PhpParser\\Node\\Stmt and Rector\\Core\\PhpParser\\Node\\CustomNode\\FileWithoutNamespace will always evaluate to false#' - - message: '#Unreachable statement \- code above always terminates#' paths: @@ -184,15 +181,12 @@ parameters: paths: - src/Rector/AbstractRector.php - - '#Method Rector\\Core\\PhpParser\\Node\\BetterNodeFinder\:\:findParentType\(\) should return T of PhpParser\\Node\|null but returns class\-string\|T of PhpParser\\Node#' - - '#Property Rector\\Core\\PhpParser\\Node\\AssignAndBinaryMap\:\:\$binaryOpToAssignClasses \(array, class\-string\>\) does not accept array#' - message: '#Function "property_exists\(\)" cannot be used/left in the code#' paths: # on PhpParser Nodes - - packages/NodeTypeResolver/NodeVisitor/StatementNodeVisitor.php - packages/NodeNameResolver/NodeNameResolver.php - packages/NodeNameResolver/NodeNameResolver/ClassNameResolver.php - packages/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php @@ -342,6 +336,7 @@ parameters: message: '#Class cognitive complexity is \d+, keep it under 50#' paths: - src/PhpParser/Node/BetterNodeFinder.php + - rules/Removing/NodeManipulator/ComplexNodeRemover.php - message: '#Parameter \#2 \$length of function str_split expects int<1, max\>, int given#' @@ -579,28 +574,19 @@ parameters: # move later in BC break release - '#Class "(Rector\\DeadCode\\Rector\\(.*?)\\(RemoveUnreachableStatementRector|RemoveDoubleAssignRector))" has invalid namespace category "(.*?)"\. Pick one of\: "(.*?)"#' - # by child generics, this property is always available - - '#Access to an undefined property PhpParser\\Node\\FunctionLike\|PhpParser\\Node\\Stmt\\Else_\|PhpParser\\Node\\Stmt\\Foreach_\|PhpParser\\Node\\Stmt\\If_\:\:\$stmts#' - - '#Access to an undefined property PhpParser\\Node\\FunctionLike\|PhpParser\\Node\\Stmt\\Foreach_\|PhpParser\\Node\\Stmt\\If_\|PhpParser\\Node\\Stmt\\Namespace_\|Rector\\Core\\PhpParser\\Node\\CustomNode\\FileWithoutNamespace\:\:\$stmts#' # stmts refactoring - '#Cognitive complexity for "Rector\\DeadCode\\Rector\\Assign\\RemoveDoubleAssignRector\:\:refactor\(\)" is \d+, keep it under 10#' - # todo add custom stmts aware interface - - - message: '#Access to an undefined property PhpParser\\Node\:\:\$stmts#' - path: src/PhpParser/Node/BetterNodeFinder.php - # empty parent construct - '#Rector\\Core\\PhpParser\\NodeTraverser\\FileWithoutNamespaceNodeTraverser\:\:__construct\(\) does not call parent constructor from PhpParser\\NodeTraverser#' - # resolve later to collector - - - message: '#Class cognitive complexity is \d+, keep it under 50#' - path: rules/TypeDeclaration/PHPStan/ObjectTypeSpecifier.php - - '#Cognitive complexity for "Rector\\TypeDeclaration\\PHPStan\\ObjectTypeSpecifier\:\:matchShortenedObjectType\(\)" is \d+, keep it under 10#' - '#Cognitive complexity for "Rector\\TypeDeclaration\\PHPStan\\ObjectTypeSpecifier\:\:narrowToFullyQualifiedOrAliasedObjectType\(\)" is \d+, keep it under 10#' - '#Class "Rector\\CodeQuality\\Rector\\ClassMethod\\InlineArrayReturnAssignRector" has invalid namespace category "ClassMethod"\. Pick one of\: "NodeTypeGroup"#' - '#Parameter \#1 \$node (.*?) of method Rector\\(.*?)\:\:refactorWithScope\(\) should be contravariant with parameter \$node \(PhpParser\\Node\) of method Rector\\Core\\Contract\\Rector\\ScopeAwarePhpRectorInterface\:\:refactorWithScope\(\)#' - - '#Return type \(array\|null\) of method Rector\\CodeQuality\\Rector\\For_\\ForRepeatedCountToOwnVariableRector\:\:refactorWithScope\(\) should be covariant with return type \(array\|PhpParser\\Node\|null\) of method Rector\\Core\\Contract\\Rector\\ScopeAwarePhpRectorInterface\:\:refactorWithScope\(\)#' + + # cleanup after merge of assing remover refactoring + - '#Cognitive complexity for "Rector\\Removing\\NodeManipulator\\ComplexNodeRemover\:\:removePropertyAndUsages\(\)" is \d+, keep it under 10#' + - '#Class "Rector\\DeadCode\\Rector\\Property\\RemoveUnusedPrivatePropertyRector" has invalid namespace category "Property"\. Pick one of\: "Class_"#' + - '#Cognitive complexity for "Rector\\ReadWrite\\NodeAnalyzer\\ReadWritePropertyAnalyzer\:\:isRead\(\)" is 14, keep it under 10#' diff --git a/rules-tests/CodeQuality/Rector/Expression/InlineIfToExplicitIfRector/Fixture/assign_op.php.inc b/rules-tests/CodeQuality/Rector/Expression/InlineIfToExplicitIfRector/Fixture/inline_assign_op.php.inc similarity index 89% rename from rules-tests/CodeQuality/Rector/Expression/InlineIfToExplicitIfRector/Fixture/assign_op.php.inc rename to rules-tests/CodeQuality/Rector/Expression/InlineIfToExplicitIfRector/Fixture/inline_assign_op.php.inc index 2c71578bca6..d32f1a64cd9 100644 --- a/rules-tests/CodeQuality/Rector/Expression/InlineIfToExplicitIfRector/Fixture/assign_op.php.inc +++ b/rules-tests/CodeQuality/Rector/Expression/InlineIfToExplicitIfRector/Fixture/inline_assign_op.php.inc @@ -2,7 +2,7 @@ namespace Rector\Tests\CodeQuality\Rector\Expression\InlineIfToExplicitIfRector\Fixture; -class AssignOp +final class InlineAssignOp { public function run() { @@ -17,7 +17,7 @@ class AssignOp namespace Rector\Tests\CodeQuality\Rector\Expression\InlineIfToExplicitIfRector\Fixture; -class AssignOp +final class InlineAssignOp { public function run() { diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/function_call.php.inc b/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/function_call.php.inc deleted file mode 100644 index 847390bdf9f..00000000000 --- a/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/function_call.php.inc +++ /dev/null @@ -1,37 +0,0 @@ -prop = foo(); - - $this->prop[bar()] = foo(); - - return $this->prop[bar()] = foo(); - } -} - -?> ------ - diff --git a/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/write_only_dim_fetch_use.php.inc b/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/write_only_dim_fetch_use.php.inc deleted file mode 100644 index 0cfba66dbbf..00000000000 --- a/rules-tests/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector/Fixture/write_only_dim_fetch_use.php.inc +++ /dev/null @@ -1,40 +0,0 @@ -key = $key; - } - - public function buildData(): array - { - $data[$this->key] = 10000; - } -} - -?> ------ - diff --git a/rules-tests/Transform/Rector/New_/NewToConstructorInjectionRector/config/configured_rule.php b/rules-tests/Transform/Rector/New_/NewToConstructorInjectionRector/config/configured_rule.php index 31e58df4e6b..cd357247db1 100644 --- a/rules-tests/Transform/Rector/New_/NewToConstructorInjectionRector/config/configured_rule.php +++ b/rules-tests/Transform/Rector/New_/NewToConstructorInjectionRector/config/configured_rule.php @@ -7,6 +7,5 @@ use Rector\Tests\Transform\Rector\New_\NewToConstructorInjectionRector\Source\Du use Rector\Transform\Rector\New_\NewToConstructorInjectionRector; return static function (RectorConfig $rectorConfig): void { - $rectorConfig - ->ruleWithConfiguration(NewToConstructorInjectionRector::class, [DummyValidator::class]); + $rectorConfig->ruleWithConfiguration(NewToConstructorInjectionRector::class, [DummyValidator::class]); }; diff --git a/rules/DeadCode/NodeManipulator/LivingCodeManipulator.php b/rules/DeadCode/NodeManipulator/LivingCodeManipulator.php index 5479828d75d..dc881752117 100644 --- a/rules/DeadCode/NodeManipulator/LivingCodeManipulator.php +++ b/rules/DeadCode/NodeManipulator/LivingCodeManipulator.php @@ -29,27 +29,16 @@ use PhpParser\Node\Expr\UnaryMinus; use PhpParser\Node\Expr\UnaryPlus; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Scalar; -use PhpParser\Node\Stmt\Expression; use PHPStan\Type\ObjectType; use Rector\NodeTypeResolver\NodeTypeResolver; -use Rector\PostRector\Collector\NodesToAddCollector; final class LivingCodeManipulator { public function __construct( - private readonly NodesToAddCollector $nodesToAddCollector, private readonly NodeTypeResolver $nodeTypeResolver ) { } - public function addLivingCodeBeforeNode(Expr $expr, Node $addBeforeThisNode): void - { - $livinExprs = $this->keepLivingCodeFromExpr($expr); - foreach ($livinExprs as $livinExpr) { - $this->nodesToAddCollector->addNodeBeforeNode(new Expression($livinExpr), $addBeforeThisNode); - } - } - /** * @return Expr[]|mixed[] */ diff --git a/rules/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector.php b/rules/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector.php index 28f8ea32754..9ae819fb289 100644 --- a/rules/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector.php +++ b/rules/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector.php @@ -36,6 +36,9 @@ final class RemoveUnusedPrivatePropertyRector extends AbstractRector implements ) { } + /** + * @param mixed[] $configuration + */ public function configure(array $configuration): void { $this->removeAssignSideEffect = $configuration[self::REMOVE_ASSIGN_SIDE_EFFECT] ?? (bool) current( @@ -72,25 +75,35 @@ CODE_SAMPLE */ public function getNodeTypes(): array { - return [Property::class]; + return [Class_::class]; } /** - * @param Property $node + * @param Class_ $node */ public function refactor(Node $node): ?Node { - if ($this->shouldSkipProperty($node)) { - return null; + $hasChanged = false; + + foreach ($node->getProperties() as $property) { + if ($this->shouldSkipProperty($property)) { + continue; + } + + if ($this->propertyManipulator->isPropertyUsedInReadContext($property)) { + continue; + } + + $this->complexNodeRemover->removePropertyAndUsages($node, $property, $this->removeAssignSideEffect); + + $hasChanged = true; } - if ($this->propertyManipulator->isPropertyUsedInReadContext($node)) { - return null; + if ($hasChanged) { + return $node; } - $this->complexNodeRemover->removePropertyAndUsages($node, $this->removeAssignSideEffect); - - return $node; + return null; } private function shouldSkipProperty(Property $property): bool @@ -99,11 +112,6 @@ CODE_SAMPLE return true; } - if (! $property->isPrivate()) { - return true; - } - - $class = $this->betterNodeFinder->findParentType($property, Class_::class); - return ! $class instanceof Class_; + return ! $property->isPrivate(); } } diff --git a/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php b/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php index ce1bfc2b3d0..ab6e39852d4 100644 --- a/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php +++ b/rules/DowngradePhp74/Rector/Array_/DowngradeArraySpreadRector.php @@ -240,7 +240,10 @@ CODE_SAMPLE // Assign the value to the variable, and replace the element with the variable $newVariable = new Variable($variableName); - $this->nodesToAddCollector->addNodeBeforeNode(new Assign($newVariable, $arrayItem->value), $array); + + $newVariableAssign = new Assign($newVariable, $arrayItem->value); + $this->nodesToAddCollector->addNodeBeforeNode($newVariableAssign, $array); + return $newVariable; } diff --git a/rules/Removing/NodeManipulator/ComplexNodeRemover.php b/rules/Removing/NodeManipulator/ComplexNodeRemover.php index 873a317d96d..cc6f7cc396f 100644 --- a/rules/Removing/NodeManipulator/ComplexNodeRemover.php +++ b/rules/Removing/NodeManipulator/ComplexNodeRemover.php @@ -5,6 +5,8 @@ declare(strict_types=1); namespace Rector\Removing\NodeManipulator; use PhpParser\Node; +use PhpParser\Node\Expr; +use PhpParser\Node\Expr\ArrayDimFetch; use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\StaticPropertyFetch; @@ -13,6 +15,7 @@ use PhpParser\Node\Param; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassLike; use PhpParser\Node\Stmt\ClassMethod; +use PhpParser\Node\Stmt\Expression; use PhpParser\Node\Stmt\Property; use Rector\Core\PhpParser\Comparing\NodeComparator; use Rector\Core\PhpParser\Node\BetterNodeFinder; @@ -20,32 +23,87 @@ use Rector\Core\PhpParser\NodeFinder\PropertyFetchFinder; use Rector\Core\ValueObject\MethodName; use Rector\DeadCode\SideEffect\SideEffectNodeDetector; use Rector\NodeNameResolver\NodeNameResolver; -use Rector\NodeRemoval\AssignRemover; use Rector\NodeRemoval\NodeRemover; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\Removing\NodeAnalyzer\ForbiddenPropertyRemovalAnalyzer; +use Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser; final class ComplexNodeRemover { public function __construct( - private readonly AssignRemover $assignRemover, private readonly PropertyFetchFinder $propertyFetchFinder, private readonly NodeNameResolver $nodeNameResolver, private readonly BetterNodeFinder $betterNodeFinder, private readonly NodeRemover $nodeRemover, private readonly NodeComparator $nodeComparator, private readonly ForbiddenPropertyRemovalAnalyzer $forbiddenPropertyRemovalAnalyzer, - private readonly SideEffectNodeDetector $sideEffectNodeDetector + private readonly SideEffectNodeDetector $sideEffectNodeDetector, + private readonly SimpleCallableNodeTraverser $simpleCallableNodeTraverser, ) { } - public function removePropertyAndUsages(Property $property, bool $removeAssignSideEffect = true): void - { + public function removePropertyAndUsages( + Class_ $class, + Property $property, + bool $removeAssignSideEffect + ): void { + $propertyName = $this->nodeNameResolver->getName($property); + + $hasSideEffect = false; + + $this->simpleCallableNodeTraverser->traverseNodesWithCallable($class->stmts, function (Node $node) use ( + $removeAssignSideEffect, + $propertyName, + &$hasSideEffect + ) { + // here should be checked all expr like stmts that can hold assign, e.f. if, foreach etc. etc. + if ($node instanceof Expression) { + $nodeExpr = $node->expr; + + // remove direct assigns + if ($nodeExpr instanceof Assign) { + $assign = $nodeExpr; + + // skip double assigns + if ($assign->expr instanceof Assign) { + return null; + } + + $propertyFetches = $this->resolvePropertyFetchFromDimFetch($assign->var); + if ($propertyFetches === []) { + return null; + } + + foreach ($propertyFetches as $propertyFetch) { + if (! $this->nodeNameResolver->isName($propertyFetch->var, 'this')) { + continue; + } + + if ($this->nodeNameResolver->isName($propertyFetch->name, $propertyName)) { + if (! $removeAssignSideEffect && $this->sideEffectNodeDetector->detect($assign->expr)) { + $hasSideEffect = true; + return null; + } + + $this->nodeRemover->removeNode($node); + } + } + } + } + + return null; + }); + + // do not remove anyhting in case of side-effect + if ($hasSideEffect) { + return; + } + $propertyFetches = $this->propertyFetchFinder->findPrivatePropertyFetches($property); $assigns = []; foreach ($propertyFetches as $propertyFetch) { - $assign = $this->resolveAssign($propertyFetch); + $assign = $this->resolvePropertyFetchAssign($propertyFetch); if (! $assign instanceof Assign) { return; } @@ -54,10 +112,6 @@ final class ComplexNodeRemover return; } - if (! $removeAssignSideEffect && $this->sideEffectNodeDetector->detect($assign->expr)) { - return; - } - $assigns[] = $assign; } @@ -105,12 +159,11 @@ final class ComplexNodeRemover { foreach ($assigns as $assign) { // remove assigns - $this->assignRemover->removeAssignNode($assign); $this->removeConstructorDependency($assign); } } - private function resolveAssign(PropertyFetch | StaticPropertyFetch $expr): ?Assign + private function resolvePropertyFetchAssign(PropertyFetch | StaticPropertyFetch $expr): ?Assign { $assign = $expr->getAttribute(AttributeKey::PARENT_NODE); @@ -234,4 +287,27 @@ final class ComplexNodeRemover $expressionVariable = $node->getAttribute(AttributeKey::PARENT_NODE); return ! $expressionVariable instanceof Assign; } + + /** + * @return PropertyFetch[] + */ + private function resolvePropertyFetchFromDimFetch(Expr $expr): array + { + // unwrap array dim fetch, till we get to parent too caller node + $propertyFetches = []; + + while ($expr instanceof ArrayDimFetch) { + if ($expr->dim instanceof PropertyFetch) { + $propertyFetches[] = $expr->dim; + } + + $expr = $expr->var; + } + + if ($expr instanceof PropertyFetch) { + $propertyFetches[] = $expr; + } + + return $propertyFetches; + } } diff --git a/rules/Transform/Rector/New_/NewToConstructorInjectionRector.php b/rules/Transform/Rector/New_/NewToConstructorInjectionRector.php index e2bf8d59462..d6b54ad51b3 100644 --- a/rules/Transform/Rector/New_/NewToConstructorInjectionRector.php +++ b/rules/Transform/Rector/New_/NewToConstructorInjectionRector.php @@ -10,12 +10,12 @@ use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\New_; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt\Class_; +use PhpParser\Node\Stmt\Expression; use PHPStan\Type\ObjectType; use Rector\Core\Contract\Rector\ConfigurableRectorInterface; use Rector\Core\Rector\AbstractRector; use Rector\Naming\Naming\PropertyNaming; use Rector\Naming\ValueObject\ExpectedName; -use Rector\NodeRemoval\AssignRemover; use Rector\PostRector\Collector\PropertyToAddCollector; use Rector\PostRector\ValueObject\PropertyMetadata; use Rector\Transform\NodeFactory\PropertyFetchFactory; @@ -37,7 +37,6 @@ final class NewToConstructorInjectionRector extends AbstractRector implements Co private readonly PropertyFetchFactory $propertyFetchFactory, private readonly PropertyNaming $propertyNaming, private readonly PropertyToAddCollector $propertyToAddCollector, - private readonly AssignRemover $assignRemover ) { } @@ -86,11 +85,11 @@ CODE_SAMPLE */ public function getNodeTypes(): array { - return [New_::class, Assign::class, MethodCall::class]; + return [New_::class, Assign::class, MethodCall::class, Expression::class]; } /** - * @param New_|Assign|MethodCall $node + * @param New_|Assign|MethodCall|Expression $node */ public function refactor(Node $node): ?Node { @@ -98,8 +97,11 @@ CODE_SAMPLE return $this->refactorMethodCall($node); } - if ($node instanceof Assign) { - $this->refactorAssign($node); + if ($node instanceof Expression) { + $nodeExpr = $node->expr; + if ($nodeExpr instanceof Assign) { + $this->refactorAssignExpression($node, $nodeExpr); + } } if ($node instanceof New_) { @@ -144,18 +146,19 @@ CODE_SAMPLE return null; } - private function refactorAssign(Assign $assign): void + private function refactorAssignExpression(Expression $expression, Assign $assign): void { - if (! $assign->expr instanceof New_) { + $currentAssign = $assign->expr instanceof Assign ? $assign->expr : $assign; + if (! $currentAssign->expr instanceof New_) { return; } foreach ($this->constructorInjectionObjectTypes as $constructorInjectionObjectType) { - if (! $this->isObjectType($assign->expr, $constructorInjectionObjectType)) { + if (! $this->isObjectType($currentAssign->expr, $constructorInjectionObjectType)) { continue; } - $this->assignRemover->removeAssignNode($assign); + $this->removeNode($expression); } }