diff --git a/composer.json b/composer.json index 1befb70b..17bc3237 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "description": "Rector upgrades rules for Laravel Framework", "require": { "php": ">=8.1", - "rector/rector": "^0.15.12" + "rector/rector": "^0.17.1" }, "require-dev": { "phpunit/phpunit": "^10.0", diff --git a/config/sets/laravel-static-to-injection.php b/config/sets/laravel-static-to-injection.php index 5a604e62..f291692e 100644 --- a/config/sets/laravel-static-to-injection.php +++ b/config/sets/laravel-static-to-injection.php @@ -7,12 +7,12 @@ use Rector\Renaming\Rector\Name\RenameClassRector; use Rector\Transform\Rector\FuncCall\FuncCallToNewRector; use Rector\Transform\Rector\StaticCall\StaticCallToMethodCallRector; -use Rector\Transform\ValueObject\ArgumentFuncCallToMethodCall; -use Rector\Transform\ValueObject\ArrayFuncCallToMethodCall; use Rector\Transform\ValueObject\StaticCallToMethodCall; use RectorLaravel\Rector\FuncCall\ArgumentFuncCallToMethodCallRector; use RectorLaravel\Rector\FuncCall\HelperFuncCallToFacadeClassRector; use RectorLaravel\Rector\StaticCall\RequestStaticValidateToInjectRector; +use RectorLaravel\ValueObject\ArgumentFuncCallToMethodCall; +use RectorLaravel\ValueObject\ArrayFuncCallToMethodCall; /** * @see https://www.freecodecamp.org/news/moving-away-from-magic-or-why-i-dont-want-to-use-laravel-anymore-2ce098c979bd/ diff --git a/src/NodeFactory/AppAssignFactory.php b/src/NodeFactory/AppAssignFactory.php index 9f5f28d2..726e2467 100644 --- a/src/NodeFactory/AppAssignFactory.php +++ b/src/NodeFactory/AppAssignFactory.php @@ -50,6 +50,5 @@ private function decorateWithVarAnnotation( ); $phpDocInfo->addTagValueNode($varTagValueNode); - $phpDocInfo->makeSingleLined(); } } diff --git a/src/Rector/Assign/CallOnAppArrayAccessToStandaloneAssignRector.php b/src/Rector/Assign/CallOnAppArrayAccessToStandaloneAssignRector.php index bb768620..f335d635 100644 --- a/src/Rector/Assign/CallOnAppArrayAccessToStandaloneAssignRector.php +++ b/src/Rector/Assign/CallOnAppArrayAccessToStandaloneAssignRector.php @@ -10,9 +10,9 @@ use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\Variable; +use PhpParser\Node\Stmt\Expression; use PHPStan\Type\ObjectType; use Rector\Core\Rector\AbstractRector; -use Rector\PostRector\Collector\NodesToAddCollector; use RectorLaravel\NodeFactory\AppAssignFactory; use RectorLaravel\ValueObject\ServiceNameTypeAndVariableName; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; @@ -30,7 +30,6 @@ final class CallOnAppArrayAccessToStandaloneAssignRector extends AbstractRector public function __construct( private readonly AppAssignFactory $appAssignFactory, - private readonly NodesToAddCollector $nodesToAddCollector, ) { $this->serviceNameTypeAndVariableNames[] = new ServiceNameTypeAndVariableName( 'validator', @@ -44,19 +43,23 @@ public function __construct( */ public function getNodeTypes(): array { - return [Assign::class]; + return [Expression::class]; } /** - * @param Assign $node + * @param Expression $node */ - public function refactor(Node $node): ?Node + public function refactor(Node $node): Node|array|int|null { - if (! $node->expr instanceof MethodCall) { + if (! $node->expr instanceof Assign) { return null; } - $methodCall = $node->expr; + if (! $node->expr->expr instanceof MethodCall) { + return null; + } + + $methodCall = $node->expr->expr; if (! $methodCall->var instanceof ArrayDimFetch) { return null; } @@ -85,10 +88,11 @@ public function refactor(Node $node): ?Node $methodCall->var ); - $this->nodesToAddCollector->addNodeBeforeNode($assignExpression, $node); $methodCall->var = new Variable($serviceNameTypeAndVariableName->getVariableName()); - return $node; + // the nop is a workaround because the docs of the first node are somehow stripped away + // this will add a newline but the docs will be preserved + return [new Node\Stmt\Nop(), $assignExpression, $node]; } return null; diff --git a/src/Rector/ClassMethod/MigrateToSimplifiedAttributeRector.php b/src/Rector/ClassMethod/MigrateToSimplifiedAttributeRector.php index 40d997c7..0f3684c3 100644 --- a/src/Rector/ClassMethod/MigrateToSimplifiedAttributeRector.php +++ b/src/Rector/ClassMethod/MigrateToSimplifiedAttributeRector.php @@ -22,6 +22,7 @@ use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Expression; use PhpParser\Node\Stmt\Return_; +use PhpParser\NodeTraverser; use PHPStan\Type\ObjectType; use Rector\Core\Rector\AbstractRector; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; @@ -41,7 +42,7 @@ public function getNodeTypes(): array /** * @param ClassMethod $node */ - public function refactor(Node $node): ?Node + public function refactor(Node $node): Node|array|int|null { if ($this->shouldSkipNode($node)) { return null; @@ -82,8 +83,7 @@ public function refactor(Node $node): ?Node // is placed on the model and remove the mutator, // so we don't run the refactoring twice if ($accessor instanceof ClassMethod && $mutator instanceof ClassMethod && $this->isMutator($nodeName)) { - $this->removeNode($mutator); - return null; + return NodeTraverser::REMOVE_NODE; } if ($accessor instanceof ClassMethod && $mutator instanceof ClassMethod) { diff --git a/src/Rector/Class_/PropertyDeferToDeferrableProviderToRector.php b/src/Rector/Class_/PropertyDeferToDeferrableProviderToRector.php index 21609bee..5a7096a0 100644 --- a/src/Rector/Class_/PropertyDeferToDeferrableProviderToRector.php +++ b/src/Rector/Class_/PropertyDeferToDeferrableProviderToRector.php @@ -74,7 +74,7 @@ public function refactor(Node $node): ?Node return null; } - $this->removeNode($deferProperty); + unset($node->stmts[array_search($deferProperty, $node->stmts, true)]); $node->implements[] = new FullyQualified('Illuminate\Contracts\Support\DeferrableProvider'); diff --git a/src/Rector/Class_/UnifyModelDatesWithCastsRector.php b/src/Rector/Class_/UnifyModelDatesWithCastsRector.php index 0dc26af8..d5c570dd 100644 --- a/src/Rector/Class_/UnifyModelDatesWithCastsRector.php +++ b/src/Rector/Class_/UnifyModelDatesWithCastsRector.php @@ -72,7 +72,7 @@ public function getNodeTypes(): array /** * @param Class_ $node */ - public function refactor(Node $node): ?Node + public function refactor(Node $node) { if (! $this->isObjectType($node, new ObjectType('Illuminate\Database\Eloquent\Model'))) { return null; @@ -123,7 +123,8 @@ public function refactor(Node $node): ?Node ); } - $this->nodeRemover->removeNode($datesProperty); + unset($node->stmts[array_search($datesProperty, $node->stmts, true)]); + return null; } diff --git a/src/Rector/FuncCall/ArgumentFuncCallToMethodCallRector.php b/src/Rector/FuncCall/ArgumentFuncCallToMethodCallRector.php index 640f0663..ffb51503 100644 --- a/src/Rector/FuncCall/ArgumentFuncCallToMethodCallRector.php +++ b/src/Rector/FuncCall/ArgumentFuncCallToMethodCallRector.php @@ -8,17 +8,14 @@ use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\PropertyFetch; +use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt\Class_; -use PhpParser\Node\Stmt\ClassMethod; +use PHPStan\Type\ObjectType; use Rector\Core\Contract\Rector\ConfigurableRectorInterface; use Rector\Core\Exception\ShouldNotHappenException; use Rector\Core\Rector\AbstractRector; -use Rector\Naming\Naming\PropertyNaming; -use Rector\Naming\ValueObject\ExpectedName; use Rector\NodeTypeResolver\TypeAnalyzer\ArrayTypeAnalyzer; -use Rector\PostRector\Collector\PropertyToAddCollector; -use Rector\PostRector\ValueObject\PropertyMetadata; -use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType; +use Rector\Transform\NodeAnalyzer\FuncCallStaticCallToMethodCallAnalyzer; use RectorLaravel\Contract\ValueObject\ArgumentFuncCallToMethodCallInterface; use RectorLaravel\ValueObject\ArgumentFuncCallToMethodCall; use RectorLaravel\ValueObject\ArrayFuncCallToMethodCall; @@ -38,8 +35,7 @@ final class ArgumentFuncCallToMethodCallRector extends AbstractRector implements public function __construct( private readonly ArrayTypeAnalyzer $arrayTypeAnalyzer, - private readonly PropertyNaming $propertyNaming, - private readonly PropertyToAddCollector $propertyToAddCollector + private readonly FuncCallStaticCallToMethodCallAnalyzer $funcCallStaticCallToMethodCallAnalyzer ) { } @@ -89,33 +85,75 @@ public function action() */ public function getNodeTypes(): array { - return [FuncCall::class]; + return [Class_::class]; } /** - * @param FuncCall $node + * @param Class_ $node */ public function refactor(Node $node): ?Node { - if ($this->shouldSkipFuncCall($node)) { - return null; - } + $hasChanged = false; + $class = $node; - /** @var Class_ $classLike */ - $classLike = $this->betterNodeFinder->findParentType($node, Class_::class); - - foreach ($this->argumentFuncCallToMethodCalls as $argumentFuncCallToMethodCall) { - if (! $this->isName($node, $argumentFuncCallToMethodCall->getFunction())) { + foreach ($node->getMethods() as $classMethod) { + if ($classMethod->isStatic()) { continue; } - if ($argumentFuncCallToMethodCall instanceof ArgumentFuncCallToMethodCall) { - return $this->refactorFuncCallToMethodCall($argumentFuncCallToMethodCall, $classLike, $node); + if ($classMethod->isAbstract()) { + continue; } - if ($argumentFuncCallToMethodCall instanceof ArrayFuncCallToMethodCall) { - return $this->refactorArrayFunctionToMethodCall($argumentFuncCallToMethodCall, $node, $classLike); - } + $this->traverseNodesWithCallable($classMethod, function (Node $node) use ( + $class, + $classMethod, + &$hasChanged + ): ?Node { + if (! $node instanceof FuncCall) { + return null; + } + + foreach ($this->argumentFuncCallToMethodCalls as $argumentFuncCallToMethodCall) { + if (! $this->isName($node->name, $argumentFuncCallToMethodCall->getFunction())) { + continue; + } + + if ($argumentFuncCallToMethodCall instanceof ArgumentFuncCallToMethodCall) { + $expr = $this->funcCallStaticCallToMethodCallAnalyzer->matchTypeProvidingExpr( + $class, + $classMethod, + new ObjectType($argumentFuncCallToMethodCall->getClass()), + ); + + $hasChanged = true; + + return $this->refactorFuncCallToMethodCall($node, $argumentFuncCallToMethodCall, $expr); + } + + if ($argumentFuncCallToMethodCall instanceof ArrayFuncCallToMethodCall) { + $expr = $this->funcCallStaticCallToMethodCallAnalyzer->matchTypeProvidingExpr( + $class, + $classMethod, + new ObjectType($argumentFuncCallToMethodCall->getClass()), + ); + + $hasChanged = true; + + return $this->refactorArrayFunctionToMethodCall( + $node, + $argumentFuncCallToMethodCall, + $expr + ); + } + } + + return null; + }); + } + + if ($hasChanged) { + return $node; } return null; @@ -131,124 +169,52 @@ public function configure(array $configuration): void $this->argumentFuncCallToMethodCalls = $configuration; } - private function shouldSkipFuncCall(FuncCall $funcCall): bool - { - // we can inject only in injectable class method context - /** @var ClassMethod|null $classMethod */ - $classMethod = $this->betterNodeFinder->findParentType($funcCall, ClassMethod::class); - if (! $classMethod instanceof ClassMethod) { - return true; - } - - return $classMethod->isStatic(); - } - - /** - * @return MethodCall|PropertyFetch|null - */ - private function refactorFuncCallToMethodCall( + public function refactorFuncCallToMethodCall( + FuncCall $node, ArgumentFuncCallToMethodCall $argumentFuncCallToMethodCall, - Class_ $class, - FuncCall $funcCall - ): ?Node { - $fullyQualifiedObjectType = new FullyQualifiedObjectType($argumentFuncCallToMethodCall->getClass()); - $expectedName = $this->propertyNaming->getExpectedNameFromType($fullyQualifiedObjectType); - - if (! $expectedName instanceof ExpectedName) { - throw new ShouldNotHappenException(); - } - - $propertyMetadata = new PropertyMetadata( - $expectedName->getName(), - $fullyQualifiedObjectType, - Class_::MODIFIER_PRIVATE - ); - $this->propertyToAddCollector->addPropertyToClass($class, $propertyMetadata); - - $propertyFetchNode = $this->nodeFactory->createPropertyFetch('this', $expectedName->getName()); - - if ($funcCall->args === []) { - return $this->refactorEmptyFuncCallArgs($argumentFuncCallToMethodCall, $propertyFetchNode); + MethodCall|PropertyFetch|Variable $expr + ): MethodCall|PropertyFetch|Variable { + if ($node->args === []) { + return $this->refactorEmptyFuncCallArgs($argumentFuncCallToMethodCall, $expr); } - if ($this->isFunctionToMethodCallWithArgs($funcCall, $argumentFuncCallToMethodCall)) { - $methodName = $argumentFuncCallToMethodCall->getMethodIfArgs(); - if (! is_string($methodName)) { - throw new ShouldNotHappenException(); - } + $methodName = $argumentFuncCallToMethodCall->getMethodIfArgs(); - return new MethodCall($propertyFetchNode, $methodName, $funcCall->args); + if (! is_string($methodName)) { + throw new ShouldNotHappenException(); } - return null; + return $this->nodeFactory->createMethodCall($expr, $methodName, $node->args); } - /** - * @return PropertyFetch|MethodCall|null - */ private function refactorArrayFunctionToMethodCall( - ArrayFuncCallToMethodCall $arrayFuncCallToMethodCall, - FuncCall $funcCall, - Class_ $class - ): ?Node { - $propertyName = $this->propertyNaming->fqnToVariableName($arrayFuncCallToMethodCall->getClass()); - $propertyFetch = $this->nodeFactory->createPropertyFetch('this', $propertyName); - - $fullyQualifiedObjectType = new FullyQualifiedObjectType($arrayFuncCallToMethodCall->getClass()); - - $propertyMetadata = new PropertyMetadata($propertyName, $fullyQualifiedObjectType, Class_::MODIFIER_PRIVATE); - $this->propertyToAddCollector->addPropertyToClass($class, $propertyMetadata); - - return $this->createMethodCallArrayFunctionToMethodCall( - $funcCall, - $arrayFuncCallToMethodCall, - $propertyFetch - ); - } - - private function refactorEmptyFuncCallArgs( - ArgumentFuncCallToMethodCall $argumentFuncCallToMethodCall, - PropertyFetch $propertyFetch - ): MethodCall | PropertyFetch { - if ($argumentFuncCallToMethodCall->getMethodIfNoArgs() !== null) { - $methodName = $argumentFuncCallToMethodCall->getMethodIfNoArgs(); - return new MethodCall($propertyFetch, $methodName); - } - - return $propertyFetch; - } - - private function isFunctionToMethodCallWithArgs( - FuncCall $funcCall, - ArgumentFuncCallToMethodCall $argumentFuncCallToMethodCall - ): bool { - if ($argumentFuncCallToMethodCall->getMethodIfArgs() === null) { - return false; - } - - return count($funcCall->args) >= 1; - } - - /** - * @return PropertyFetch|MethodCall|null - */ - private function createMethodCallArrayFunctionToMethodCall( FuncCall $funcCall, ArrayFuncCallToMethodCall $arrayFuncCallToMethodCall, - PropertyFetch $propertyFetch + MethodCall|PropertyFetch|Variable $expr ): ?Node { if ($funcCall->getArgs() === []) { - return $propertyFetch; + return $expr; } if ($this->arrayTypeAnalyzer->isArrayType($funcCall->getArgs()[0]->value)) { - return new MethodCall($propertyFetch, $arrayFuncCallToMethodCall->getArrayMethod(), $funcCall->getArgs()); + return new MethodCall($expr, $arrayFuncCallToMethodCall->getArrayMethod(), $funcCall->getArgs()); } if ($arrayFuncCallToMethodCall->getNonArrayMethod() === '') { return null; } - return new MethodCall($propertyFetch, $arrayFuncCallToMethodCall->getNonArrayMethod(), $funcCall->getArgs()); + return new MethodCall($expr, $arrayFuncCallToMethodCall->getNonArrayMethod(), $funcCall->getArgs()); + } + + private function refactorEmptyFuncCallArgs( + ArgumentFuncCallToMethodCall $argumentFuncCallToMethodCall, + MethodCall|PropertyFetch|Variable $expr + ): MethodCall | PropertyFetch | Variable { + if ($argumentFuncCallToMethodCall->getMethodIfNoArgs() !== null) { + return $this->nodeFactory->createMethodCall($expr, $argumentFuncCallToMethodCall->getMethodIfNoArgs()); + } + + return $expr; } } diff --git a/src/Rector/FuncCall/RemoveDumpDataDeadCodeRector.php b/src/Rector/FuncCall/RemoveDumpDataDeadCodeRector.php index ceca6fb8..25640053 100644 --- a/src/Rector/FuncCall/RemoveDumpDataDeadCodeRector.php +++ b/src/Rector/FuncCall/RemoveDumpDataDeadCodeRector.php @@ -7,8 +7,8 @@ use PhpParser\Node; use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Stmt\Expression; +use PhpParser\NodeTraverser; use Rector\Core\Rector\AbstractRector; -use Rector\NodeTypeResolver\Node\AttributeKey; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -65,25 +65,22 @@ public function update() */ public function getNodeTypes(): array { - return [FuncCall::class]; + return [Expression::class]; } /** - * @param FuncCall $node + * @param Expression $node */ - public function refactor(Node $node): ?Node + public function refactor(Node $node): int|Node|array|null { - if (! $this->isNames($node->name, ['dd', 'dump'])) { + if (! $node->expr instanceof FuncCall) { return null; } - $parentNode = $node->getAttribute(AttributeKey::PARENT_NODE); - if (! $parentNode instanceof Expression) { + if (! $this->isNames($node->expr->name, ['dd', 'dump'])) { return null; } - $this->removeNode($node); - - return null; + return NodeTraverser::REMOVE_NODE; } } diff --git a/src/Rector/MethodCall/ChangeQueryWhereDateValueWithCarbonRector.php b/src/Rector/MethodCall/ChangeQueryWhereDateValueWithCarbonRector.php index 098b98ab..bbb069f8 100644 --- a/src/Rector/MethodCall/ChangeQueryWhereDateValueWithCarbonRector.php +++ b/src/Rector/MethodCall/ChangeQueryWhereDateValueWithCarbonRector.php @@ -12,9 +12,9 @@ use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Scalar\String_; +use PhpParser\Node\Stmt\Expression; use PHPStan\Type\ObjectType; use Rector\Core\Rector\AbstractRector; -use Rector\PostRector\Collector\NodesToAddCollector; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -26,11 +26,6 @@ */ final class ChangeQueryWhereDateValueWithCarbonRector extends AbstractRector { - public function __construct( - private readonly NodesToAddCollector $nodesToAddCollector, - ) { - } - public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( @@ -72,15 +67,19 @@ public function run(Builder $query) */ public function getNodeTypes(): array { - return [MethodCall::class]; + return [Expression::class]; } /** - * @param MethodCall $node + * @param Expression $node */ - public function refactor(Node $node): ?Node + public function refactor(Node $node): Node|array|int|null { - $expr = $this->matchWhereDateThirdArgValue($node); + if (! $node->expr instanceof MethodCall) { + return null; + } + + $expr = $this->matchWhereDateThirdArgValue($node->expr); if (! $expr instanceof Expr) { return null; } @@ -91,35 +90,38 @@ public function refactor(Node $node): ?Node // 1. extract assign $dateTimeVariable = new Variable('dateTime'); $assign = new Assign($dateTimeVariable, $expr); - $this->nodesToAddCollector->addNodeBeforeNode($assign, $node); - if (! $node->args[2] instanceof Arg) { - return null; + $nodes = [new Expression($assign), $node]; + + if (! $node->expr->args[2] instanceof Arg) { + return $nodes; } - $node->args[2]->value = $dateTimeVariable; - if (! $node->args[1] instanceof Arg) { - return null; + $node->expr->args[2]->value = $dateTimeVariable; + if (! $node->expr->args[1] instanceof Arg) { + return $nodes; } // update assign ">" → ">=" - $this->changeCompareSignExpr($node->args[1]); + $this->changeCompareSignExpr($node->expr->args[1]); // 2. add "whereTime()" time call - $whereTimeMethodCall = $this->createWhereTimeMethodCall($node, $dateTimeVariable); - $this->nodesToAddCollector->addNodeAfterNode($whereTimeMethodCall, $node); + $whereTimeMethodCall = $this->createWhereTimeMethodCall($node->expr, $dateTimeVariable); - return $node; + $nodes[] = new Expression($whereTimeMethodCall); + + return $nodes; } - if ($expr instanceof Variable && $node->args[1] instanceof Arg) { + if ($expr instanceof Variable && $node->expr->args[1] instanceof Arg) { $dateTimeVariable = $expr; - $this->changeCompareSignExpr($node->args[1]); + $this->changeCompareSignExpr($node->expr->args[1]); // 2. add "whereTime()" time call - $whereTimeMethodCall = $this->createWhereTimeMethodCall($node, $dateTimeVariable); - $this->nodesToAddCollector->addNodeAfterNode($whereTimeMethodCall, $node); + $whereTimeMethodCall = $this->createWhereTimeMethodCall($node->expr, $dateTimeVariable); + + return [$node, new Expression($whereTimeMethodCall)]; } return null; diff --git a/src/Rector/MethodCall/RedirectBackToBackHelperRector.php b/src/Rector/MethodCall/RedirectBackToBackHelperRector.php index 9ac6586f..de220812 100644 --- a/src/Rector/MethodCall/RedirectBackToBackHelperRector.php +++ b/src/Rector/MethodCall/RedirectBackToBackHelperRector.php @@ -5,12 +5,12 @@ namespace RectorLaravel\Rector\MethodCall; use PhpParser\Node; +use PhpParser\Node\Expr; use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Name; use Rector\Core\Rector\AbstractRector; -use Rector\Defluent\NodeAnalyzer\FluentChainMethodCallNodeAnalyzer; use Rector\NodeTypeResolver\Node\AttributeKey; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -21,11 +21,6 @@ final class RedirectBackToBackHelperRector extends AbstractRector { - public function __construct( - private readonly FluentChainMethodCallNodeAnalyzer $fluentChainMethodCallNodeAnalyzer, - ) { - } - public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( @@ -96,7 +91,7 @@ private function updateRedirectHelperCall(MethodCall $methodCall): MethodCall|Fu return null; } - $rootExpr = $this->fluentChainMethodCallNodeAnalyzer->resolveRootExpr($methodCall); + $rootExpr = $this->resolveRootExpr($methodCall); $parentNode = $rootExpr->getAttribute(AttributeKey::PARENT_NODE); if (! $parentNode instanceof MethodCall) { @@ -118,9 +113,10 @@ private function updateRedirectHelperCall(MethodCall $methodCall): MethodCall|Fu $childElement = $methodCall->getAttribute('parent'); if ($childElement instanceof MethodCall) { - $this->removeNode($methodCall); $parentNode->var->name = new Name('back'); $parentNode->var->args = $methodCall->getArgs(); + unset($childElement->var); + $childElement->var = $parentNode->var; } else { return new FuncCall(new Name('back'), $methodCall->getArgs()); } @@ -140,4 +136,15 @@ private function updateRedirectStaticCall(StaticCall $staticCall): ?FuncCall return new FuncCall(new Name('back'), $staticCall->args); } + + private function resolveRootExpr(MethodCall $methodCall): Expr | Name + { + $callerNode = $methodCall->var; + + while ($callerNode instanceof MethodCall || $callerNode instanceof StaticCall) { + $callerNode = $callerNode instanceof StaticCall ? $callerNode->class : $callerNode->var; + } + + return $callerNode; + } } diff --git a/src/Rector/MethodCall/RedirectRouteToToRouteHelperRector.php b/src/Rector/MethodCall/RedirectRouteToToRouteHelperRector.php index 372991a4..028f1dc8 100644 --- a/src/Rector/MethodCall/RedirectRouteToToRouteHelperRector.php +++ b/src/Rector/MethodCall/RedirectRouteToToRouteHelperRector.php @@ -5,12 +5,12 @@ namespace RectorLaravel\Rector\MethodCall; use PhpParser\Node; +use PhpParser\Node\Expr; use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Name; use Rector\Core\Rector\AbstractRector; -use Rector\Defluent\NodeAnalyzer\FluentChainMethodCallNodeAnalyzer; use Rector\NodeTypeResolver\Node\AttributeKey; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -21,11 +21,6 @@ final class RedirectRouteToToRouteHelperRector extends AbstractRector { - public function __construct( - private readonly FluentChainMethodCallNodeAnalyzer $fluentChainMethodCallNodeAnalyzer, - ) { - } - public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( @@ -96,7 +91,7 @@ private function updateRedirectHelperCall(MethodCall $methodCall): MethodCall|Fu return null; } - $rootExpr = $this->fluentChainMethodCallNodeAnalyzer->resolveRootExpr($methodCall); + $rootExpr = $this->resolveRootExpr($methodCall); $parentNode = $rootExpr->getAttribute(AttributeKey::PARENT_NODE); if (! $parentNode instanceof MethodCall) { @@ -118,9 +113,10 @@ private function updateRedirectHelperCall(MethodCall $methodCall): MethodCall|Fu $childElement = $methodCall->getAttribute('parent'); if ($childElement instanceof MethodCall) { - $this->removeNode($methodCall); $parentNode->var->name = new Name('to_route'); $parentNode->var->args = $methodCall->getArgs(); + unset($childElement->var); + $childElement->var = $parentNode->var; } else { return new FuncCall(new Name('to_route'), $methodCall->getArgs()); } @@ -140,4 +136,15 @@ private function updateRedirectStaticCall(StaticCall $staticCall): ?FuncCall return new FuncCall(new Name('to_route'), $staticCall->args); } + + private function resolveRootExpr(MethodCall $methodCall): Expr | Name + { + $callerNode = $methodCall->var; + + while ($callerNode instanceof MethodCall || $callerNode instanceof StaticCall) { + $callerNode = $callerNode instanceof StaticCall ? $callerNode->class : $callerNode->var; + } + + return $callerNode; + } } diff --git a/src/Rector/New_/AddGuardToLoginEventRector.php b/src/Rector/New_/AddGuardToLoginEventRector.php index 78709800..0fb26883 100644 --- a/src/Rector/New_/AddGuardToLoginEventRector.php +++ b/src/Rector/New_/AddGuardToLoginEventRector.php @@ -10,8 +10,8 @@ use PhpParser\Node\Expr\New_; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Scalar\String_; +use PhpParser\Node\Stmt\Expression; use Rector\Core\Rector\AbstractRector; -use Rector\PostRector\Collector\NodesToAddCollector; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -23,11 +23,6 @@ */ final class AddGuardToLoginEventRector extends AbstractRector { - public function __construct( - private readonly NodesToAddCollector $nodesToAddCollector, - ) { - } - public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( @@ -68,29 +63,34 @@ public function run(): void */ public function getNodeTypes(): array { - return [New_::class]; + return [Expression::class]; } /** - * @param New_ $node + * @param Expression $node */ - public function refactor(Node $node): ?Node + public function refactor(Node $node): Node|array|int|null { - if (! $this->isName($node->class, 'Illuminate\Auth\Events\Login')) { + $newNode = $this->getNewNode($node); + + if (! $newNode instanceof New_) { return null; } - if (count($node->args) === 3) { + if (! $this->isName($newNode->class, 'Illuminate\Auth\Events\Login')) { + return null; + } + + if (count($newNode->args) === 3) { return null; } $guardVariable = new Variable('guard'); $assign = $this->createGuardAssign($guardVariable); - $this->nodesToAddCollector->addNodeBeforeNode($assign, $node); - $node->args = array_merge([new Arg($guardVariable)], $node->args); + $newNode->args = array_merge([new Arg($guardVariable)], $newNode->args); - return $node; + return [new Expression($assign), $node]; } private function createGuardAssign(Variable $guardVariable): Assign @@ -99,4 +99,17 @@ private function createGuardAssign(Variable $guardVariable): Assign return new Assign($guardVariable, $this->nodeFactory->createFuncCall('config', [$string])); } + + private function getNewNode(Expression $node): New_|null + { + if ($node->expr instanceof Assign && $node->expr->expr instanceof New_) { + return $node->expr->expr; + } + + if ($node->expr instanceof New_) { + return $node->expr; + } + + return null; + } } diff --git a/src/Rector/PropertyFetch/OptionalToNullsafeOperatorRector.php b/src/Rector/PropertyFetch/OptionalToNullsafeOperatorRector.php index 00329c81..f4fc2cf1 100644 --- a/src/Rector/PropertyFetch/OptionalToNullsafeOperatorRector.php +++ b/src/Rector/PropertyFetch/OptionalToNullsafeOperatorRector.php @@ -17,7 +17,6 @@ use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Scalar; use Rector\Core\Contract\Rector\AllowEmptyConfigurableRectorInterface; -use Rector\Core\NodeAnalyzer\ArgsAnalyzer; use Rector\Core\Rector\AbstractRector; use Rector\Core\Util\MultiInstanceofChecker; use Rector\Core\ValueObject\PhpVersion; @@ -52,7 +51,6 @@ final class OptionalToNullsafeOperatorRector extends AbstractRector implements M public function __construct( private readonly MultiInstanceofChecker $multiInstanceofChecker, - private readonly ArgsAnalyzer $argsAnalyzer ) { } @@ -110,7 +108,7 @@ public function refactor(Node $node): ?Node return null; } - if (! $this->argsAnalyzer->isArgInstanceInArgsPosition($node->var->args, 0)) { + if (! isset($node->var->args[0])) { return null; } diff --git a/tests/Rector/Assign/CallOnAppArrayAccessToStandaloneAssignRector/Fixture/some_fixture.php.inc b/tests/Rector/Assign/CallOnAppArrayAccessToStandaloneAssignRector/Fixture/some_fixture.php.inc index bcb0d919..5f0f7254 100644 --- a/tests/Rector/Assign/CallOnAppArrayAccessToStandaloneAssignRector/Fixture/some_fixture.php.inc +++ b/tests/Rector/Assign/CallOnAppArrayAccessToStandaloneAssignRector/Fixture/some_fixture.php.inc @@ -34,7 +34,10 @@ class SomeFixture public function run() { - /** @var \Illuminate\Validation\Factory $validationFactory */ + + /** + * @var \Illuminate\Validation\Factory $validationFactory + */ $validationFactory = $this->app['validator']; $validator = $validationFactory->make('...'); } diff --git a/tests/Rector/FuncCall/ArgumentFuncCallToMethodCallRector/Fixture/auth.php.inc b/tests/Rector/FuncCall/ArgumentFuncCallToMethodCallRector/Fixture/auth.php.inc new file mode 100644 index 00000000..664d3af5 --- /dev/null +++ b/tests/Rector/FuncCall/ArgumentFuncCallToMethodCallRector/Fixture/auth.php.inc @@ -0,0 +1,30 @@ + +----- +guard; + } +} + +?> diff --git a/tests/Rector/FuncCall/ArgumentFuncCallToMethodCallRector/config/configured_rule.php b/tests/Rector/FuncCall/ArgumentFuncCallToMethodCallRector/config/configured_rule.php index d379d02a..c324da72 100644 --- a/tests/Rector/FuncCall/ArgumentFuncCallToMethodCallRector/config/configured_rule.php +++ b/tests/Rector/FuncCall/ArgumentFuncCallToMethodCallRector/config/configured_rule.php @@ -10,6 +10,7 @@ return static function (RectorConfig $rectorConfig): void { $rectorConfig ->ruleWithConfiguration(ArgumentFuncCallToMethodCallRector::class, [ + new ArgumentFuncCallToMethodCall('auth', 'Illuminate\Contracts\Auth\Guard'), new ArgumentFuncCallToMethodCall('view', 'Illuminate\Contracts\View\Factory', 'make'), new ArgumentFuncCallToMethodCall('route', 'Illuminate\Routing\UrlGenerator', 'route'), new ArgumentFuncCallToMethodCall('back', 'Illuminate\Routing\Redirector', 'back', 'back'), diff --git a/tests/Rector/New_/AddGuardToLoginEventRector/Fixture/without_assignment.php.inc b/tests/Rector/New_/AddGuardToLoginEventRector/Fixture/without_assignment.php.inc new file mode 100644 index 00000000..e9f832c6 --- /dev/null +++ b/tests/Rector/New_/AddGuardToLoginEventRector/Fixture/without_assignment.php.inc @@ -0,0 +1,32 @@ + +----- +