diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 9a03c64e..17548ffb 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -25,4 +25,4 @@ jobs: - uses: ramsey/composer-install@v3 - - run: vendor/bin/phpunit tests + - run: vendor/bin/phpunit diff --git a/README.md b/README.md index b94737a5..dddfc22a 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,10 @@ use Rector\Config\RectorConfig; use RectorLaravel\Rector\FuncCall\RemoveDumpDataDeadCodeRector; return RectorConfig::configure() + // include default config + ->withSets([ + __DIR__ . '/vendor/driftingly/rector-laravel/config/config.php' + ]) ->withConfiguredRule(RemoveDumpDataDeadCodeRector::class, [ 'dd', 'dump', 'var_dump' ]); @@ -127,6 +131,10 @@ use Rector\Config\RectorConfig; use RectorLaravel\Rector\MethodCall\ResponseHelperCallToJsonResponseRector; return RectorConfig::configure() + // include default config + ->withSets([ + __DIR__ . '/vendor/driftingly/rector-laravel/config/config.php' + ]) ->withRules([ ResponseHelperCallToJsonResponseRector::class, ]); diff --git a/config/config.php b/config/config.php index b58ec265..01a981ca 100644 --- a/config/config.php +++ b/config/config.php @@ -3,5 +3,17 @@ declare(strict_types=1); use Rector\Config\RectorConfig; +use Rector\Contract\PhpParser\DecoratingNodeVisitorInterface; +use RectorLaravel\NodeVisitor\ArrayDimFetchContextNodeVisitor; +use RectorLaravel\NodeVisitor\RandomEnumContextNodeVisitor; -return static function (RectorConfig $rectorConfig): void {}; +/** + * to be imported, don't use RectorConfigBuilder for safe usage + */ +return static function (RectorConfig $rectorConfig): void { + $rectorConfig->singleton(ArrayDimFetchContextNodeVisitor::class); + $rectorConfig->tag(ArrayDimFetchContextNodeVisitor::class, DecoratingNodeVisitorInterface::class); + + $rectorConfig->singleton(RandomEnumContextNodeVisitor::class); + $rectorConfig->tag(RandomEnumContextNodeVisitor::class, DecoratingNodeVisitorInterface::class); +}; diff --git a/phpunit.xml b/phpunit.xml index 38dc7003..a8ad69ee 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -9,8 +9,21 @@ displayDetailsOnTestsThatTriggerWarnings="true" > - - tests + + tests/Commands + + + tests/Sets + + + tests/Rector + + + + tests/NodeAnalyzer diff --git a/src/NodeVisitor/ArrayDimFetchContextNodeVisitor.php b/src/NodeVisitor/ArrayDimFetchContextNodeVisitor.php new file mode 100644 index 00000000..6ebf79d5 --- /dev/null +++ b/src/NodeVisitor/ArrayDimFetchContextNodeVisitor.php @@ -0,0 +1,78 @@ +var instanceof ArrayDimFetch && $this->nodeNameResolver->isName($node->var->var, '_SERVER'))) { + SimpleCallableNodeTraverser::traverseNodesWithCallable($node, function (Node $subNode) { + if (! $subNode instanceof ArrayDimFetch) { + return null; + } + + $subNode->setAttribute(self::IS_IN_SERVER_VARIABLE, true); + + return $subNode; + }); + } + + return null; + } + + if (! $node->dim instanceof Expr) { + SimpleCallableNodeTraverser::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; + }); + } + + if ($node->dim instanceof Scalar) { + return null; + } + + SimpleCallableNodeTraverser::traverseNodesWithCallable($node, function (Node $subSubNode) { + if ($subSubNode instanceof Variable) { + $subSubNode->setAttribute(self::IS_INSIDE_ARRAY_DIM_FETCH_WITH_DIM_NOT_SCALAR, true); + + return $subSubNode; + } + + return null; + }); + + return null; + } +} diff --git a/src/NodeVisitor/RandomEnumContextNodeVisitor.php b/src/NodeVisitor/RandomEnumContextNodeVisitor.php new file mode 100644 index 00000000..71861321 --- /dev/null +++ b/src/NodeVisitor/RandomEnumContextNodeVisitor.php @@ -0,0 +1,47 @@ +nodeNameResolver->isName($node->name, 'randomEnum')) { + $node->setAttribute(self::IS_IN_RANDOM_ENUM, true); + SimpleCallableNodeTraverser::traverseNodesWithCallable($node, function (Node $subNode) { + if (! $subNode instanceof PropertyFetch && ! $subNode instanceof InterpolatedString) { + return null; + } + + $subNode->setAttribute(self::IS_IN_RANDOM_ENUM, true); + + return $subNode; + }); + } + + return null; + } +} diff --git a/src/Rector/ArrayDimFetch/RequestVariablesToRequestFacadeRector.php b/src/Rector/ArrayDimFetch/RequestVariablesToRequestFacadeRector.php index b582d508..69956926 100644 --- a/src/Rector/ArrayDimFetch/RequestVariablesToRequestFacadeRector.php +++ b/src/Rector/ArrayDimFetch/RequestVariablesToRequestFacadeRector.php @@ -12,9 +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\NodeVisitor\ArrayDimFetchContextNodeVisitor; use RectorLaravel\ValueObject\ReplaceRequestKeyAndMethodValue; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -24,8 +23,6 @@ */ class RequestVariablesToRequestFacadeRector extends AbstractRector { - private const string IS_INSIDE_ARRAY_DIM_FETCH_WITH_DIM_NOT_SCALAR = 'is_inside_array_dim_fetch_with_dim_not_scalar'; - public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( @@ -61,39 +58,16 @@ public function getRuleDefinition(): RuleDefinition public function getNodeTypes(): array { - return [Node::class, ArrayDimFetch::class, Variable::class, Isset_::class]; + return [ArrayDimFetch::class, Variable::class, Isset_::class]; } + /** + * @param ArrayDimFetch|Variable|Isset_ $node + */ public function refactor(Node $node): StaticCall|NotIdentical|null { - 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) { - - if ($subNode->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); - - return $subSubNode; - } - - return null; - }); - } - }); - } - - return null; - } - if ($node instanceof Variable) { - if ($node->getAttribute(self::IS_INSIDE_ARRAY_DIM_FETCH_WITH_DIM_NOT_SCALAR) === true) { + if ($node->getAttribute(ArrayDimFetchContextNodeVisitor::IS_INSIDE_ARRAY_DIM_FETCH_WITH_DIM_NOT_SCALAR) === true) { return null; } diff --git a/src/Rector/ArrayDimFetch/ServerVariableToRequestFacadeRector.php b/src/Rector/ArrayDimFetch/ServerVariableToRequestFacadeRector.php index 23f5fc53..2d49d184 100644 --- a/src/Rector/ArrayDimFetch/ServerVariableToRequestFacadeRector.php +++ b/src/Rector/ArrayDimFetch/ServerVariableToRequestFacadeRector.php @@ -6,14 +6,9 @@ use PhpParser\Node\Arg; use PhpParser\Node\Expr; use PhpParser\Node\Expr\ArrayDimFetch; -use PhpParser\Node\Expr\Assign; -use PhpParser\Node\Expr\Isset_; 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 RectorLaravel\NodeVisitor\ArrayDimFetchContextNodeVisitor; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -22,8 +17,6 @@ */ class ServerVariableToRequestFacadeRector extends AbstractRector { - private const string IS_IN_SERVER_VARIABLE = 'is_in_server_variable'; - public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( @@ -41,37 +34,14 @@ public function getRuleDefinition(): RuleDefinition public function getNodeTypes(): array { - return [Node::class, ArrayDimFetch::class]; + return [ArrayDimFetch::class]; } + /** + * @param ArrayDimFetch $node + */ public function refactor(Node $node): ?StaticCall { - if (! $node instanceof ArrayDimFetch) { - $scope = $node->getAttribute(AttributeKey::SCOPE); - if ($scope instanceof Scope && $scope->isInFirstLevelStatement()) { - $this->traverseNodesWithCallable($node, function (Node $subNode) { - 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; - } - - $subSubNode->setAttribute(self::IS_IN_SERVER_VARIABLE, true); - - return $subSubNode; - }); - - return $subNode; - } - - return null; - }); - } - - return null; - } - if (! $this->isName($node->var, '_SERVER')) { return null; } @@ -80,7 +50,7 @@ public function refactor(Node $node): ?StaticCall return null; } - if ($node->getAttribute(self::IS_IN_SERVER_VARIABLE) === true) { + if ($node->getAttribute(ArrayDimFetchContextNodeVisitor::IS_IN_SERVER_VARIABLE) === true) { return null; } diff --git a/src/Rector/ArrayDimFetch/SessionVariableToSessionFacadeRector.php b/src/Rector/ArrayDimFetch/SessionVariableToSessionFacadeRector.php index 7a2dd3b2..7a9b6056 100644 --- a/src/Rector/ArrayDimFetch/SessionVariableToSessionFacadeRector.php +++ b/src/Rector/ArrayDimFetch/SessionVariableToSessionFacadeRector.php @@ -13,8 +13,6 @@ 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; @@ -60,7 +58,6 @@ public function getRuleDefinition(): RuleDefinition public function getNodeTypes(): array { return [ - Node::class, Isset_::class, Unset_::class, ArrayDimFetch::class, @@ -75,36 +72,6 @@ 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 77d2aabe..58d6d917 100644 --- a/src/Rector/PropertyFetch/ReplaceFakerInstanceWithHelperRector.php +++ b/src/Rector/PropertyFetch/ReplaceFakerInstanceWithHelperRector.php @@ -11,12 +11,11 @@ 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 RectorLaravel\NodeVisitor\RandomEnumContextNodeVisitor; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -25,8 +24,6 @@ */ final class ReplaceFakerInstanceWithHelperRector extends AbstractRector { - private const string IS_IN_RANDOM_ENUM = 'is_in_random_enum'; - public function __construct( private readonly ReflectionResolver $reflectionResolver, private readonly ReflectionProvider $reflectionProvider, @@ -73,44 +70,14 @@ public function definition() */ public function getNodeTypes(): array { - return [Node::class, PropertyFetch::class, MethodCall::class, InterpolatedString::class]; + return [PropertyFetch::class, MethodCall::class, InterpolatedString::class]; } + /** + * @param PropertyFetch|MethodCall|InterpolatedString $node + */ public function refactor(Node $node): ?Node { - if (! $node instanceof PropertyFetch && ! $node instanceof MethodCall && ! $node instanceof InterpolatedString) { - $scope = $node->getAttribute(AttributeKey::SCOPE); - if ($scope instanceof Scope && $scope->isInFirstLevelStatement()) { - - $this->traverseNodesWithCallable($node, function (Node $subNode) { - if (! $subNode instanceof MethodCall) { - return null; - } - - // 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; - } - - $subSubNode->setAttribute(self::IS_IN_RANDOM_ENUM, true); - - return $subSubNode; - }); - - return $subNode; - } - - return null; - }); - } - - return null; - } - $classReflection = $this->reflectionResolver->resolveClassReflection($node); if (! $classReflection instanceof ClassReflection) { @@ -121,7 +88,7 @@ public function refactor(Node $node): ?Node return null; } - if ($node->getAttribute(self::IS_IN_RANDOM_ENUM) === true) { + if ($node->getAttribute(RandomEnumContextNodeVisitor::IS_IN_RANDOM_ENUM) === true) { return null; }