diff --git a/composer.json b/composer.json index d24d79dad..04d120d0d 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "description": "Rector upgrades rules for Laravel Framework", "require": { "php": ">=8.3", - "rector/rector": "^2.2.7", + "rector/rector": "^2.2.13", "webmozart/assert": "^1.11", "symplify/rule-doc-generator-contracts": "^11.2" }, diff --git a/src/NodeAnalyzer/ExpectedClassMethodAnalyzer.php b/src/NodeAnalyzer/ExpectedClassMethodAnalyzer.php index c01eca3ae..d431467a4 100644 --- a/src/NodeAnalyzer/ExpectedClassMethodAnalyzer.php +++ b/src/NodeAnalyzer/ExpectedClassMethodAnalyzer.php @@ -18,7 +18,6 @@ final readonly class ExpectedClassMethodAnalyzer { public function __construct( - private SimpleCallableNodeTraverser $simpleCallableNodeTraverser, private NodeNameResolver $nodeNameResolver, private NodeTypeResolver $nodeTypeResolver, ) {} @@ -31,7 +30,7 @@ public function findExpectedJobCallsWithClassMethod(ClassMethod $classMethod): ? $notExpectedMethodCalls = []; $reasonsToNotContinue = false; - $this->simpleCallableNodeTraverser->traverseNodesWithCallable($classMethod, function (Node $node) use ( + SimpleCallableNodeTraverser::traverseNodesWithCallable($classMethod, function (Node $node) use ( &$expectedMethodCalls, &$notExpectedMethodCalls, &$reasonsToNotContinue, @@ -87,7 +86,7 @@ public function findExpectedEventCallsWithClassMethod(ClassMethod $classMethod): $notExpectedMethodCalls = []; $reasonsToNotContinue = false; - $this->simpleCallableNodeTraverser->traverseNodesWithCallable($classMethod, function (Node $node) use ( + SimpleCallableNodeTraverser::traverseNodesWithCallable($classMethod, function (Node $node) use ( &$expectedMethodCalls, &$notExpectedMethodCalls, &$reasonsToNotContinue, diff --git a/src/NodeFactory/ModelFactoryNodeFactory.php b/src/NodeFactory/ModelFactoryNodeFactory.php index 50238dc68..7ab733ec1 100644 --- a/src/NodeFactory/ModelFactoryNodeFactory.php +++ b/src/NodeFactory/ModelFactoryNodeFactory.php @@ -34,7 +34,6 @@ public function __construct( private NodeNameResolver $nodeNameResolver, private NodeFactory $nodeFactory, private ValueResolver $valueResolver, - private SimpleCallableNodeTraverser $simpleCallableNodeTraverser ) {} public function createEmptyFactory(string $name, Expr $expr): Class_ @@ -116,7 +115,7 @@ public function createEmptyConfigure(): ClassMethod public function appendConfigure(ClassMethod $classMethod, string $name, Closure|ArrowFunction $callable): void { - $this->simpleCallableNodeTraverser->traverseNodesWithCallable( + SimpleCallableNodeTraverser::traverseNodesWithCallable( (array) $classMethod->stmts, function (Node $node) use ($callable, $name): ?Return_ { if (! $node instanceof Return_) { @@ -145,7 +144,7 @@ function (Node $node) use ($callable, $name): ?Return_ { */ private function fakerVariableToPropertyFetch(array $stmts, Param $param): void { - $this->simpleCallableNodeTraverser->traverseNodesWithCallable($stmts, function (Node $node) use ( + SimpleCallableNodeTraverser::traverseNodesWithCallable($stmts, function (Node $node) use ( $param ): ?PropertyFetch { if (! $node instanceof Variable) { diff --git a/src/Rector/ArrayDimFetch/RequestVariablesToRequestFacadeRector.php b/src/Rector/ArrayDimFetch/RequestVariablesToRequestFacadeRector.php index ecdd6820f..b582d5081 100644 --- a/src/Rector/ArrayDimFetch/RequestVariablesToRequestFacadeRector.php +++ b/src/Rector/ArrayDimFetch/RequestVariablesToRequestFacadeRector.php @@ -2,7 +2,6 @@ namespace RectorLaravel\Rector\ArrayDimFetch; -use Override; use PhpParser\Node; use PhpParser\Node\Arg; use PhpParser\Node\Expr; @@ -13,6 +12,8 @@ use PhpParser\Node\Expr\Variable; use PhpParser\Node\Scalar; use PhpParser\Node\Scalar\String_; +use PHPStan\Analyser\Scope; +use Rector\NodeTypeResolver\Node\AttributeKey; use RectorLaravel\AbstractRector; use RectorLaravel\ValueObject\ReplaceRequestKeyAndMethodValue; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; @@ -58,44 +59,39 @@ public function getRuleDefinition(): RuleDefinition ); } - #[Override] - public function beforeTraverse(array $nodes): array + public function getNodeTypes(): array + { + return [Node::class, ArrayDimFetch::class, Variable::class, Isset_::class]; + } + + public function refactor(Node $node): StaticCall|NotIdentical|null { - parent::beforeTraverse($nodes); + if (! $node instanceof ArrayDimFetch && ! $node instanceof Variable && ! $node instanceof Isset_) { + $scope = $node->getAttribute(AttributeKey::SCOPE); + if ($scope instanceof Scope && $scope->isInFirstLevelStatement()) { + $this->traverseNodesWithCallable($node, function (Node $subNode) { + if ($subNode instanceof ArrayDimFetch) { - $this->traverseNodesWithCallable($nodes, function (Node $node) { - if ($node instanceof ArrayDimFetch) { + if ($subNode->dim instanceof Scalar) { + return null; + } - if ($node->dim instanceof Scalar) { - return null; - } + $this->traverseNodesWithCallable($subNode, function (Node $subSubNode) { + if ($subSubNode instanceof Variable) { + $subSubNode->setAttribute(self::IS_INSIDE_ARRAY_DIM_FETCH_WITH_DIM_NOT_SCALAR, true); - $this->traverseNodesWithCallable($node, function (Node $subNode) { - if ($subNode instanceof Variable) { - $subNode->setAttribute(self::IS_INSIDE_ARRAY_DIM_FETCH_WITH_DIM_NOT_SCALAR, true); + return $subSubNode; + } - return $subNode; + return null; + }); } - - return null; }); } - }); - return $nodes; - } - - public function getNodeTypes(): array - { - return [ArrayDimFetch::class, Variable::class, Isset_::class]; - } + return null; + } - /** - * @param ArrayDimFetch|Variable $node - * @return StaticCall|NotIdentical|1|null - */ - public function refactor(Node $node): StaticCall|NotIdentical|int|null - { if ($node instanceof Variable) { if ($node->getAttribute(self::IS_INSIDE_ARRAY_DIM_FETCH_WITH_DIM_NOT_SCALAR) === true) { return null; @@ -121,10 +117,7 @@ public function refactor(Node $node): StaticCall|NotIdentical|int|null return $replaceValue; } - /** - * @return ReplaceRequestKeyAndMethodValue|1|null - */ - public function findAllKeys(ArrayDimFetch $arrayDimFetch): ReplaceRequestKeyAndMethodValue|int|null + public function findAllKeys(ArrayDimFetch $arrayDimFetch): ?ReplaceRequestKeyAndMethodValue { if (! $arrayDimFetch->dim instanceof Scalar) { return null; @@ -177,10 +170,7 @@ private function getGetterMethodName(Variable $variable): ?string }; } - /** - * @return StaticCall|NotIdentical|1|null - */ - private function processIsset(Isset_ $isset): StaticCall|NotIdentical|int|null + private function processIsset(Isset_ $isset): StaticCall|NotIdentical|null { if (count($isset->vars) < 1) { return null; diff --git a/src/Rector/ArrayDimFetch/ServerVariableToRequestFacadeRector.php b/src/Rector/ArrayDimFetch/ServerVariableToRequestFacadeRector.php index c54729ff4..23f5fc539 100644 --- a/src/Rector/ArrayDimFetch/ServerVariableToRequestFacadeRector.php +++ b/src/Rector/ArrayDimFetch/ServerVariableToRequestFacadeRector.php @@ -2,7 +2,6 @@ namespace RectorLaravel\Rector\ArrayDimFetch; -use Override; use PhpParser\Node; use PhpParser\Node\Arg; use PhpParser\Node\Expr; @@ -12,6 +11,8 @@ use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Scalar\InterpolatedString; use PhpParser\Node\Stmt\Unset_; +use PHPStan\Analyser\Scope; +use Rector\NodeTypeResolver\Node\AttributeKey; use RectorLaravel\AbstractRector; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -40,41 +41,37 @@ public function getRuleDefinition(): RuleDefinition public function getNodeTypes(): array { - return [ArrayDimFetch::class]; + return [Node::class, ArrayDimFetch::class]; } - #[Override] - public function beforeTraverse(array $nodes): array + public function refactor(Node $node): ?StaticCall { - parent::beforeTraverse($nodes); - - $this->traverseNodesWithCallable($nodes, function (Node $node) { - if (in_array($node::class, [Assign::class, Isset_::class, Unset_::class, InterpolatedString::class], true) - && (! $node instanceof Assign || $node->var instanceof ArrayDimFetch && $this->isName($node->var->var, '_SERVER'))) { + if (! $node instanceof ArrayDimFetch) { + $scope = $node->getAttribute(AttributeKey::SCOPE); + if ($scope instanceof Scope && $scope->isInFirstLevelStatement()) { $this->traverseNodesWithCallable($node, function (Node $subNode) { - if (! $subNode instanceof ArrayDimFetch) { - return null; - } + if (in_array($subNode::class, [Assign::class, Isset_::class, Unset_::class, InterpolatedString::class], true) + && (! $subNode instanceof Assign || $subNode->var instanceof ArrayDimFetch && $this->isName($subNode->var->var, '_SERVER'))) { + $this->traverseNodesWithCallable($subNode, function (Node $subSubNode) { + if (! $subSubNode instanceof ArrayDimFetch) { + return null; + } - $subNode->setAttribute(self::IS_IN_SERVER_VARIABLE, true); + $subSubNode->setAttribute(self::IS_IN_SERVER_VARIABLE, true); - return $subNode; - }); + return $subSubNode; + }); + + return $subNode; + } - return $node; + return null; + }); } return null; - }); - - return $nodes; - } + } - /** - * @param ArrayDimFetch $node - */ - public function refactor(Node $node): ?StaticCall - { if (! $this->isName($node->var, '_SERVER')) { return null; } diff --git a/src/Rector/ArrayDimFetch/SessionVariableToSessionFacadeRector.php b/src/Rector/ArrayDimFetch/SessionVariableToSessionFacadeRector.php index a7ec69ac1..7a2dd3b20 100644 --- a/src/Rector/ArrayDimFetch/SessionVariableToSessionFacadeRector.php +++ b/src/Rector/ArrayDimFetch/SessionVariableToSessionFacadeRector.php @@ -2,7 +2,6 @@ namespace RectorLaravel\Rector\ArrayDimFetch; -use Override; use PhpParser\Node; use PhpParser\Node\Arg; use PhpParser\Node\Expr; @@ -14,6 +13,8 @@ use PhpParser\Node\Expr\Variable; use PhpParser\Node\Stmt\Expression; use PhpParser\Node\Stmt\Unset_; +use PHPStan\Analyser\Scope; +use Rector\NodeTypeResolver\Node\AttributeKey; use RectorLaravel\AbstractRector; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -56,40 +57,10 @@ public function getRuleDefinition(): RuleDefinition ); } - #[Override] - public function beforeTraverse(array $nodes): array - { - parent::beforeTraverse($nodes); - - $this->traverseNodesWithCallable($nodes, function (Node $node) { - if (! $node instanceof ArrayDimFetch) { - return null; - } - - if (! $node->dim instanceof Expr) { - $node->setAttribute(self::IS_INSIDE_ARRAY_DIM_FETCH_WITH_DIM_NOT_EXPR, true); - $this->traverseNodesWithCallable($node, function (Node $subNode) { - if (! $subNode instanceof Variable) { - return null; - } - - $subNode->setAttribute(self::IS_INSIDE_ARRAY_DIM_FETCH_WITH_DIM_NOT_EXPR, true); - - return $subNode; - }); - - return $node; - } - - return null; - }); - - return $nodes; - } - public function getNodeTypes(): array { return [ + Node::class, Isset_::class, Unset_::class, ArrayDimFetch::class, @@ -104,6 +75,36 @@ public function getNodeTypes(): array */ public function refactor(Node $node): StaticCall|Expression|null { + $scope = $node->getAttribute(AttributeKey::SCOPE); + if ($scope instanceof Scope && $scope->isInFirstLevelStatement()) { + $this->traverseNodesWithCallable($node, function (Node $subNode) { + if (! $subNode instanceof ArrayDimFetch) { + return null; + } + + if (! $subNode->dim instanceof Expr) { + $subNode->setAttribute(self::IS_INSIDE_ARRAY_DIM_FETCH_WITH_DIM_NOT_EXPR, true); + $this->traverseNodesWithCallable($subNode, function (Node $subSubNode) { + if (! $subSubNode instanceof Variable) { + return null; + } + + $subSubNode->setAttribute(self::IS_INSIDE_ARRAY_DIM_FETCH_WITH_DIM_NOT_EXPR, true); + + return $subSubNode; + }); + + return $subNode; + } + + return null; + }); + } + + if (! $node instanceof Isset_ && ! $node instanceof Unset_ && ! $node instanceof ArrayDimFetch && ! $node instanceof Assign && ! $node instanceof FuncCall && ! $node instanceof Variable) { + return null; + } + if ($node instanceof ArrayDimFetch) { return $this->processDimFetch($node); } diff --git a/src/Rector/PropertyFetch/ReplaceFakerInstanceWithHelperRector.php b/src/Rector/PropertyFetch/ReplaceFakerInstanceWithHelperRector.php index a4564eaae..77d2aabe2 100644 --- a/src/Rector/PropertyFetch/ReplaceFakerInstanceWithHelperRector.php +++ b/src/Rector/PropertyFetch/ReplaceFakerInstanceWithHelperRector.php @@ -4,7 +4,6 @@ namespace RectorLaravel\Rector\PropertyFetch; -use Override; use PhpParser\Node; use PhpParser\Node\Expr; use PhpParser\Node\Expr\BinaryOp\Concat; @@ -12,8 +11,10 @@ use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Scalar\InterpolatedString; +use PHPStan\Analyser\Scope; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ReflectionProvider; +use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\Reflection\ReflectionResolver; use RectorLaravel\AbstractRector; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; @@ -72,47 +73,44 @@ public function definition() */ public function getNodeTypes(): array { - return [PropertyFetch::class, MethodCall::class, InterpolatedString::class]; + return [Node::class, PropertyFetch::class, MethodCall::class, InterpolatedString::class]; } - #[Override] - public function beforeTraverse(array $nodes): array + public function refactor(Node $node): ?Node { - parent::beforeTraverse($nodes); - - $this->traverseNodesWithCallable($nodes, function (Node $node) { - if (! $node instanceof MethodCall) { - return null; - } + if (! $node instanceof PropertyFetch && ! $node instanceof MethodCall && ! $node instanceof InterpolatedString) { + $scope = $node->getAttribute(AttributeKey::SCOPE); + if ($scope instanceof Scope && $scope->isInFirstLevelStatement()) { - // The randomEnum() method is a special case where the faker instance is used - // see https://github.com/spatie/laravel-enum#faker-provider - if ($this->isName($node->name, 'randomEnum')) { - $node->setAttribute(self::IS_IN_RANDOM_ENUM, true); $this->traverseNodesWithCallable($node, function (Node $subNode) { - if (! $subNode instanceof PropertyFetch && ! $subNode instanceof InterpolatedString) { + if (! $subNode instanceof MethodCall) { return null; } - $subNode->setAttribute(self::IS_IN_RANDOM_ENUM, true); + // The randomEnum() method is a special case where the faker instance is used + // see https://github.com/spatie/laravel-enum#faker-provider + if ($this->isName($subNode->name, 'randomEnum')) { + $subNode->setAttribute(self::IS_IN_RANDOM_ENUM, true); + $this->traverseNodesWithCallable($subNode, function (Node $subSubNode) { + if (! $subSubNode instanceof PropertyFetch && ! $subSubNode instanceof InterpolatedString) { + return null; + } - return $subNode; - }); + $subSubNode->setAttribute(self::IS_IN_RANDOM_ENUM, true); - return $node; + return $subSubNode; + }); + + return $subNode; + } + + return null; + }); } return null; - }); - - return $nodes; - } + } - /** - * @param PropertyFetch|MethodCall|InterpolatedString $node - */ - public function refactor(Node $node): ?Node - { $classReflection = $this->reflectionResolver->resolveClassReflection($node); if (! $classReflection instanceof ClassReflection) {