mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-31 12:42:05 +01:00
[CodeQuality] Add SimplifyArrayCallableRector
This commit is contained in:
parent
68b3372cc5
commit
3c0873e3b3
@ -0,0 +1,101 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodeQuality\Rector\FuncCall;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\Closure;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
||||
final class SimplifyArrayCallableRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $activeFuncCallName;
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
private $functionsWithCallableArgumentPosition = [
|
||||
'array_filter' => 1,
|
||||
'array_map' => 0,
|
||||
];
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition('Changes redundant anonymous bool functions to simple calls', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
$paths = array_filter($paths, function ($path): bool {
|
||||
return is_dir($path);
|
||||
});
|
||||
CODE_SAMPLE
|
||||
,
|
||||
'array_filter($paths, "is_dir");'
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [FuncCall::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FuncCall $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
foreach ($this->functionsWithCallableArgumentPosition as $function => $callablePosition) {
|
||||
if (! $this->isName($node, $function)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $node->args[$callablePosition]->value instanceof Closure) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var Closure $closureNode */
|
||||
$closureNode = $node->args[$callablePosition]->value;
|
||||
if ($this->isUsefulClosure($closureNode)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$node->args[$callablePosition] = new Arg(new String_($this->activeFuncCallName));
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function isUsefulClosure(Closure $closureNode): bool
|
||||
{
|
||||
// too complicated
|
||||
if (! $closureNode->stmts[0] instanceof Return_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @var Return_ $returnNode */
|
||||
$returnNode = $closureNode->stmts[0];
|
||||
if (! $returnNode->expr instanceof FuncCall) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @var FuncCall $funcCallNode */
|
||||
$funcCallNode = $returnNode->expr;
|
||||
|
||||
$this->activeFuncCallName = $this->getName($funcCallNode);
|
||||
|
||||
return ! $this->areNodesEqual($closureNode->params, $returnNode->expr->args);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
$paths = array_filter($paths, 'is_dir');
|
||||
|
||||
$paths = array_filter($paths, 'strlen');
|
||||
|
||||
$paths = array_filter($paths, function ($path): bool {
|
||||
return ! is_dir($path);
|
||||
});
|
||||
|
||||
$pathLength = array_map('strlen', $paths);
|
@ -0,0 +1,30 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodeQuality\Tests\Rector\FuncCall\SimplifyArrayCallableRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
/**
|
||||
* @covers \Rector\CodeQuality\Rector\FuncCall\SimplifyArrayCallableRector
|
||||
*/
|
||||
final class SimplifyArrayCallableRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideWrongToFixedFiles()
|
||||
*/
|
||||
public function test(string $wrong, string $fixed): void
|
||||
{
|
||||
$this->doTestFileMatchesExpectedContent($wrong, $fixed);
|
||||
}
|
||||
|
||||
public function provideWrongToFixedFiles(): Iterator
|
||||
{
|
||||
yield [__DIR__ . '/Wrong/wrong.php.inc', __DIR__ . '/Correct/correct.php.inc'];
|
||||
}
|
||||
|
||||
protected function provideConfig(): string
|
||||
{
|
||||
return __DIR__ . '/config.yml';
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
$paths = array_filter($paths, function ($path): bool {
|
||||
return is_dir($path);
|
||||
});
|
||||
|
||||
$paths = array_filter($paths, function ($path): bool {
|
||||
return strlen($path);
|
||||
});
|
||||
|
||||
$paths = array_filter($paths, function ($path): bool {
|
||||
return ! is_dir($path);
|
||||
});
|
||||
|
||||
$pathLength = array_map(function ($path) {
|
||||
return strlen($path);
|
||||
}, $paths);
|
@ -0,0 +1,2 @@
|
||||
services:
|
||||
Rector\CodeQuality\Rector\FuncCall\SimplifyArrayCallableRector: ~
|
@ -116,7 +116,9 @@ final class CreateRectorCommand extends Command
|
||||
'_Description_' => $configuration->getDescription(),
|
||||
'_Name_' => $configuration->getName(),
|
||||
'_CodeBefore_' => $configuration->getCodeBefore(),
|
||||
'_CodeBeforeExample_' => $this->prepareCodeForDefinition($configuration->getCodeBefore()),
|
||||
'_CodeAfter_' => $configuration->getCodeAfter(),
|
||||
'_CodeAfterExample_' => $this->prepareCodeForDefinition($configuration->getCodeAfter()),
|
||||
];
|
||||
|
||||
$arrayNodes = [];
|
||||
@ -137,4 +139,15 @@ final class CreateRectorCommand extends Command
|
||||
{
|
||||
return str_replace(array_keys($data), array_values($data), $content);
|
||||
}
|
||||
|
||||
private function prepareCodeForDefinition(string $code): string
|
||||
{
|
||||
if (Strings::contains($code, PHP_EOL)) {
|
||||
// multi lines
|
||||
return sprintf("<<<'CODE_SAMPLE'%s%sCODE_SAMPLE%s", PHP_EOL, $code, PHP_EOL);
|
||||
}
|
||||
|
||||
// single line
|
||||
return "'" . str_replace("'", '"', $code) . "'";
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ final class _Name_ extends AbstractRector
|
||||
{
|
||||
return new RectorDefinition('_Description_', [
|
||||
new CodeSample(
|
||||
'_CodeBefore_',
|
||||
'_CodeAfter_'
|
||||
_CodeBeforeExample_,
|
||||
_CodeAfterExample_
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
@ -60,8 +60,7 @@ final class ReplaceCreateMethodWithoutReviewerRector extends AbstractRector
|
||||
return null;
|
||||
}
|
||||
|
||||
if (
|
||||
$this->methodArgumentAnalyzer->hasMethodNthArgument($node, 2)
|
||||
if ($this->methodArgumentAnalyzer->hasMethodNthArgument($node, 2)
|
||||
&& ! $this->methodArgumentAnalyzer->isMethodNthArgumentNull($node, 2)
|
||||
) {
|
||||
return null;
|
||||
|
Loading…
x
Reference in New Issue
Block a user