mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-17 13:28:18 +01:00
[CodingStyle] Add NullableCompareToNullRector + add NodeFactoryTrait + cleanup
This commit is contained in:
parent
01b5ebfdad
commit
c3558f65c4
@ -37,6 +37,7 @@
|
||||
"Rector\\": "src",
|
||||
"Rector\\ContributorTools\\": "packages/ContributorTools/src",
|
||||
"Rector\\ConsoleDiffer\\": "packages/ConsoleDiffer/src",
|
||||
"Rector\\CodingStyle\\": "packages/CodingStyle/src",
|
||||
"Rector\\Guzzle\\": "packages/Guzzle/src",
|
||||
"Rector\\CodeQuality\\": "packages/CodeQuality/src",
|
||||
"Rector\\DomainDrivenDesign\\": "packages/DomainDrivenDesign/src",
|
||||
@ -63,6 +64,7 @@
|
||||
"Rector\\NodeTypeResolver\\Tests\\": "packages/NodeTypeResolver/tests",
|
||||
"Rector\\CakePHP\\Tests\\": "packages/CakePHP/tests",
|
||||
"Rector\\CodeQuality\\Tests\\": "packages/CodeQuality/tests",
|
||||
"Rector\\CodingStyle\\Tests\\": "packages/CodingStyle/tests",
|
||||
"Rector\\DomainDrivenDesign\\Tests\\": "packages/DomainDrivenDesign/tests",
|
||||
"Rector\\Guzzle\\Tests\\": "packages/Guzzle/tests",
|
||||
"Rector\\Php\\Tests\\": "packages/Php/tests",
|
||||
|
2
config/level/coding-style.yml
Normal file
2
config/level/coding-style.yml
Normal file
@ -0,0 +1,2 @@
|
||||
services:
|
||||
Rector\CodingStyle\Rector\If_\NullableCompareToNullRector: ~
|
1
ecs.yml
1
ecs.yml
@ -27,6 +27,7 @@ services:
|
||||
|
||||
Symplify\CodingStandard\Sniffs\DependencyInjection\NoClassInstantiationSniff:
|
||||
extraAllowedClasses:
|
||||
- 'PHPStan\Type\*'
|
||||
- 'PhpParser\Node\*'
|
||||
- 'Symplify\PackageBuilder\*'
|
||||
- 'PhpParser\Comment\Doc'
|
||||
|
@ -8,7 +8,6 @@ use PhpParser\Node\Expr\BinaryOp\Identical;
|
||||
use PhpParser\Node\Expr\BooleanNot;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt\Foreach_;
|
||||
use PhpParser\Node\Stmt\If_;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
@ -31,11 +30,6 @@ final class ForeachToInArrayRector extends AbstractRector
|
||||
*/
|
||||
private $constFetchAnalyzer;
|
||||
|
||||
/**
|
||||
* @var Return_
|
||||
*/
|
||||
private $returnNodeToRemove;
|
||||
|
||||
public function __construct(NodeFactory $nodeFactory, ConstFetchAnalyzer $constFetchAnalyzer)
|
||||
{
|
||||
$this->nodeFactory = $nodeFactory;
|
||||
@ -108,8 +102,8 @@ CODE_SAMPLE
|
||||
|
||||
$inArrayFunctionCall = $this->createInArrayFunction($condition, $ifCondition, $foreachNode);
|
||||
|
||||
$this->returnNodeToRemove = $foreachNode->getAttribute(Attribute::NEXT_NODE);
|
||||
$this->removeNode($this->returnNodeToRemove);
|
||||
$returnNodeToRemove = $foreachNode->getAttribute(Attribute::NEXT_NODE);
|
||||
$this->removeNode($returnNodeToRemove);
|
||||
|
||||
/** @var Return_ $returnNode */
|
||||
$returnNode = $firstNodeInsideForeach->stmts[0];
|
||||
@ -176,9 +170,9 @@ CODE_SAMPLE
|
||||
$arguments = $this->nodeFactory->createArgs([$condition, $foreachNode->expr]);
|
||||
|
||||
if ($ifCondition instanceof Identical) {
|
||||
$arguments[] = $this->nodeFactory->createArg($this->nodeFactory->createTrueConstant());
|
||||
$arguments[] = $this->nodeFactory->createArg($this->createTrue());
|
||||
}
|
||||
|
||||
return new FuncCall(new Name('in_array'), $arguments);
|
||||
return $this->createFunction('in_array', $arguments);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ namespace Rector\CodeQuality\Rector\FuncCall;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Name;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
@ -47,6 +46,6 @@ final class SimplifyFuncGetArgsCountRector extends AbstractRector
|
||||
return $node;
|
||||
}
|
||||
|
||||
return new FuncCall(new Name('func_num_args'));
|
||||
return $this->createFunction('func_num_args');
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ use PhpParser\Node\Expr\BinaryOp\NotIdentical;
|
||||
use PhpParser\Node\Expr\BooleanNot;
|
||||
use PhpParser\Node\Expr\ConstFetch;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Name;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
@ -49,7 +48,7 @@ final class SimplifyArraySearchRector extends AbstractRector
|
||||
|
||||
[$arraySearchFuncCallNode, $boolConstFetchNode] = $match;
|
||||
|
||||
$inArrayFuncCall = new FuncCall(new Name('in_array'), [
|
||||
$inArrayFuncCall = $this->createFunction('in_array', [
|
||||
$arraySearchFuncCallNode->args[0],
|
||||
$arraySearchFuncCallNode->args[1],
|
||||
]);
|
||||
|
@ -0,0 +1,71 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodingStyle\Rector\If_;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\BinaryOp\Identical;
|
||||
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
|
||||
use PhpParser\Node\Expr\BooleanNot;
|
||||
use PhpParser\Node\Stmt\If_;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
||||
final class NullableCompareToNullRector extends AbstractRector
|
||||
{
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition(
|
||||
'Changes negate of empty comparison of nullable value to explicit === or !== compare',
|
||||
[
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
/** @var stdClass|null $value */
|
||||
if ($value) {
|
||||
}
|
||||
|
||||
if (!$value) {
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
/** @var stdClass|null $value */
|
||||
if ($value !== null) {
|
||||
}
|
||||
|
||||
if ($value === null) {
|
||||
}
|
||||
CODE_SAMPLE
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [If_::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param If_ $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if ($this->isNullableType($node->cond)) {
|
||||
$node->cond = new NotIdentical($node->cond, $this->createNull());
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
if ($node->cond instanceof BooleanNot && $this->isNullableType($node->cond->expr)) {
|
||||
$node->cond = new Identical($node->cond->expr, $this->createNull());
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/** @var stdClass|null $value */
|
||||
$value = null;
|
||||
if ($value !== null) {
|
||||
}
|
||||
|
||||
if ($value === null) {
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
/** @var stdClass|null|string $value */
|
||||
$value = null;
|
||||
if ($value !== null) {
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\If_\NullableCompareToNullRector\Wrong;
|
||||
|
||||
use stdClass;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
if ($this->getNullOrObject() !== null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getNullOrObject(): ?stdClass
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\If_\NullableCompareToNullRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
/**
|
||||
* @covers \Rector\CodingStyle\Rector\If_\NullableCompareToNullRector
|
||||
*/
|
||||
final class NullableCompareToNullRectorTest 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'];
|
||||
yield [__DIR__ . '/Wrong/wrong2.php.inc', __DIR__ . '/Correct/correct2.php.inc'];
|
||||
yield [__DIR__ . '/Wrong/wrong3.php.inc', __DIR__ . '/Correct/correct3.php.inc'];
|
||||
}
|
||||
|
||||
protected function provideConfig(): string
|
||||
{
|
||||
return __DIR__ . '/config.yml';
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/** @var stdClass|null $value */
|
||||
$value = null;
|
||||
if ($value) {
|
||||
}
|
||||
|
||||
if (!$value) {
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
/** @var stdClass|null|string $value */
|
||||
$value = null;
|
||||
if ($value) {
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\If_\NullableCompareToNullRector\Wrong;
|
||||
|
||||
use stdClass;
|
||||
|
||||
class SomeClass
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
if ($this->getNullOrObject()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getNullOrObject(): ?stdClass
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
services:
|
||||
Rector\CodingStyle\Rector\If_\NullableCompareToNullRector: ~
|
95
packages/NodeTypeResolver/src/NodeTypeAnalyzer.php
Normal file
95
packages/NodeTypeResolver/src/NodeTypeAnalyzer.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\NodeTypeResolver;
|
||||
|
||||
use Countable;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Type\Accessory\HasOffsetType;
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\BooleanType;
|
||||
use PHPStan\Type\IntersectionType;
|
||||
use PHPStan\Type\NullType;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\StringType;
|
||||
use PHPStan\Type\UnionType;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
|
||||
final class NodeTypeAnalyzer
|
||||
{
|
||||
public function isStringType(Node $node): bool
|
||||
{
|
||||
if (! $node instanceof Expr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var Scope $nodeScope */
|
||||
$nodeScope = $node->getAttribute(Attribute::SCOPE);
|
||||
$nodeType = $nodeScope->getType($node);
|
||||
|
||||
return $nodeType instanceof StringType;
|
||||
}
|
||||
|
||||
/**
|
||||
* e.g. string|null, ObjectNull|null
|
||||
*/
|
||||
public function isNullableType(Node $node): bool
|
||||
{
|
||||
if (! $node instanceof Expr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var Scope $nodeScope */
|
||||
$nodeScope = $node->getAttribute(Attribute::SCOPE);
|
||||
$nodeType = $nodeScope->getType($node);
|
||||
|
||||
if (! $nodeType instanceof UnionType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $nodeType->accepts(new NullType(), true)->yes();
|
||||
}
|
||||
|
||||
public function isBoolType(Node $node): bool
|
||||
{
|
||||
if (! $node instanceof Expr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var Scope $nodeScope */
|
||||
$nodeScope = $node->getAttribute(Attribute::SCOPE);
|
||||
$nodeType = $nodeScope->getType($node);
|
||||
|
||||
return $nodeType instanceof BooleanType;
|
||||
}
|
||||
|
||||
public function isCountableType(Node $node): bool
|
||||
{
|
||||
if (! $node instanceof Expr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var Scope $nodeScope */
|
||||
$nodeScope = $node->getAttribute(Attribute::SCOPE);
|
||||
$nodeType = $nodeScope->getType($node);
|
||||
|
||||
if ($nodeType instanceof ObjectType) {
|
||||
return is_a($nodeType->getClassName(), Countable::class, true);
|
||||
}
|
||||
|
||||
if ($nodeType instanceof IntersectionType) {
|
||||
foreach ($nodeType->getTypes() as $intersectionNodeType) {
|
||||
if ($intersectionNodeType instanceof ArrayType || $intersectionNodeType instanceof HasOffsetType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return $nodeType instanceof ArrayType;
|
||||
}
|
||||
}
|
@ -3,11 +3,9 @@
|
||||
namespace Rector\Php\Rector\Each;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\List_;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt\Do_;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
@ -64,16 +62,16 @@ CODE_SAMPLE
|
||||
|
||||
// only key: list($key, ) = each($values);
|
||||
if ($listNode->items[0] && $listNode->items[1] === null) {
|
||||
$keyFuncCall = $this->createFuncCallWithNameAndArgs('key', $eachFuncCall->args);
|
||||
$keyFuncCall = $this->createFunction('key', $eachFuncCall->args);
|
||||
return new Assign($listNode->items[0]->value, $keyFuncCall);
|
||||
}
|
||||
|
||||
// only value: list(, $value) = each($values);
|
||||
if ($listNode->items[1] && $listNode->items[0] === null) {
|
||||
$nextFuncCall = $this->createFuncCallWithNameAndArgs('next', $eachFuncCall->args);
|
||||
$nextFuncCall = $this->createFunction('next', $eachFuncCall->args);
|
||||
$this->addNodeAfterNode($nextFuncCall, $node);
|
||||
|
||||
$currentFuncCall = $this->createFuncCallWithNameAndArgs('current', $eachFuncCall->args);
|
||||
$currentFuncCall = $this->createFunction('current', $eachFuncCall->args);
|
||||
return new Assign($listNode->items[1]->value, $currentFuncCall);
|
||||
}
|
||||
|
||||
@ -82,16 +80,16 @@ CODE_SAMPLE
|
||||
// $key = key($values);
|
||||
// $value = current($values);
|
||||
// next($values); - only inside a loop
|
||||
$currentFuncCall = $this->createFuncCallWithNameAndArgs('current', $eachFuncCall->args);
|
||||
$currentFuncCall = $this->createFunction('current', $eachFuncCall->args);
|
||||
$assignCurrentNode = new Assign($listNode->items[1]->value, $currentFuncCall);
|
||||
$this->addNodeAfterNode($assignCurrentNode, $node);
|
||||
|
||||
if ($this->isInsideDoWhile($node)) {
|
||||
$nextFuncCall = $this->createFuncCallWithNameAndArgs('next', $eachFuncCall->args);
|
||||
$nextFuncCall = $this->createFunction('next', $eachFuncCall->args);
|
||||
$this->addNodeAfterNode($nextFuncCall, $node);
|
||||
}
|
||||
|
||||
$keyFuncCall = $this->createFuncCallWithNameAndArgs('key', $eachFuncCall->args);
|
||||
$keyFuncCall = $this->createFunction('key', $eachFuncCall->args);
|
||||
return new Assign($listNode->items[0]->value, $keyFuncCall);
|
||||
}
|
||||
|
||||
@ -117,14 +115,6 @@ CODE_SAMPLE
|
||||
return $listNode->items[0] === null && $listNode->items[1] === null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Arg[] $args
|
||||
*/
|
||||
private function createFuncCallWithNameAndArgs(string $name, array $args): FuncCall
|
||||
{
|
||||
return new FuncCall(new Name($name), $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is inside the "do {} while ();" loop → need to add "next()"
|
||||
*/
|
||||
|
@ -7,7 +7,6 @@ use PhpParser\Node\Expr\ArrayItem;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\List_;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt\Foreach_;
|
||||
use PhpParser\Node\Stmt\While_;
|
||||
use Rector\Rector\AbstractRector;
|
||||
@ -85,7 +84,7 @@ CODE_SAMPLE
|
||||
$listNode = $assignNode->var;
|
||||
|
||||
if (count($listNode->items) === 1) { // just one argument - the key
|
||||
$foreachedExpr = new FuncCall(new Name('array_keys'), [$eachFuncCall->args[0]]);
|
||||
$foreachedExpr = $this->createFunction('array_keys', [$eachFuncCall->args[0]]);
|
||||
} else {
|
||||
$foreachedExpr = $eachFuncCall->args[0]->value;
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ use PhpParser\Node\Expr\BinaryOp\BooleanOr;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\Instanceof_;
|
||||
use PhpParser\Node\Expr\Ternary;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PhpParser\Node\Scalar\LNumber;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
@ -73,7 +72,7 @@ CODE_SAMPLE
|
||||
}
|
||||
|
||||
$conditionNode = new BooleanOr(
|
||||
new FuncCall(new Name('is_array'), [new Arg($countedNode)]),
|
||||
$this->createFunction('is_array', [new Arg($countedNode)]),
|
||||
new Instanceof_($countedNode, new FullyQualified('Countable'))
|
||||
);
|
||||
|
||||
|
@ -8,7 +8,6 @@ use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\ArrayDimFetch;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\BinaryOp\Concat;
|
||||
use PhpParser\Node\Expr\ConstFetch;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\Ternary;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
@ -109,7 +108,7 @@ final class EregToPregMatchRector extends AbstractRector
|
||||
|
||||
private function processVariablePattern(FuncCall $funcCallNode, Variable $patternNode, string $functionName): void
|
||||
{
|
||||
$pregQuotePatternNode = new FuncCall(new Name('preg_quote'), [
|
||||
$pregQuotePatternNode = $this->createFunction('preg_quote', [
|
||||
new Arg($patternNode),
|
||||
new Arg(new String_('#')),
|
||||
]);
|
||||
@ -155,9 +154,9 @@ final class EregToPregMatchRector extends AbstractRector
|
||||
private function createTernaryWithStrlenOfFirstMatch(FuncCall $funcCallNode): Ternary
|
||||
{
|
||||
$arrayDimFetch = new ArrayDimFetch($funcCallNode->args[2]->value, new LNumber(0));
|
||||
$strlenFuncCall = new FuncCall(new Name('strlen'), [new Arg($arrayDimFetch)]);
|
||||
$strlenFuncCall = $this->createFunction('strlen', [$arrayDimFetch]);
|
||||
|
||||
return new Ternary($funcCallNode, $strlenFuncCall, new ConstFetch(new Name('false')));
|
||||
return new Ternary($funcCallNode, $strlenFuncCall, $this->createFalse());
|
||||
}
|
||||
|
||||
private function isCaseInsensitiveFunction(string $functionName): bool
|
||||
|
@ -72,7 +72,7 @@ CODE_SAMPLE
|
||||
$node->args[$i] = new Arg($this->createConstFetch('JSON_THROW_ON_ERROR'));
|
||||
} else {
|
||||
// fill in blanks
|
||||
$node->args[$i] = new Arg($this->createConstFetch('null'));
|
||||
$node->args[$i] = new Arg($this->createNull());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ final class RandomFunctionRector extends AbstractRector
|
||||
// special case: random_int(); → random_int(0, getrandmax());
|
||||
if ($newFunctionName === 'random_int' && count($node->args) === 0) {
|
||||
$node->args[0] = new Arg(new LNumber(0));
|
||||
$node->args[1] = new Arg(new FuncCall(new Name('mt_getrandmax')));
|
||||
$node->args[1] = new Arg($this->createFunction('mt_getrandmax'));
|
||||
}
|
||||
|
||||
return $node;
|
||||
|
@ -3,11 +3,8 @@
|
||||
namespace Rector\Php\Rector\List_;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\List_;
|
||||
use PhpParser\Node\Name;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
@ -48,7 +45,7 @@ final class ListSplitStringRector extends AbstractRector
|
||||
return null;
|
||||
}
|
||||
|
||||
$node->expr = new FuncCall(new Name('str_split'), [new Arg($node->expr)]);
|
||||
$node->expr = $this->createFunction('str_split', [$node->expr]);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
@ -3,13 +3,10 @@
|
||||
namespace Rector\Php\Rector\List_;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\ArrayDimFetch;
|
||||
use PhpParser\Node\Expr\ArrayItem;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\List_;
|
||||
use PhpParser\Node\Name;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
@ -61,7 +58,7 @@ final class ListSwapArrayOrderRector extends AbstractRector
|
||||
}
|
||||
|
||||
// wrap with array_reverse, to reflect reverse assign order in left
|
||||
$node->expr = new FuncCall(new Name('array_reverse'), [new Arg($node->expr)]);
|
||||
$node->expr = $this->createFunction('array_reverse', [$node->expr]);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
@ -4,8 +4,6 @@ namespace Rector\Php\Rector\Unset_;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Cast\Unset_;
|
||||
use PhpParser\Node\Expr\ConstFetch;
|
||||
use PhpParser\Node\Name;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
@ -40,6 +38,6 @@ CODE_SAMPLE
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
return new ConstFetch(new Name('null'));
|
||||
return $this->createNull();
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ use PhpParser\Node\Expr\ArrayDimFetch;
|
||||
use PhpParser\Node\Expr\ArrayItem;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
use PhpParser\Node\Expr\ConstFetch;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
@ -186,7 +185,7 @@ CODE_SAMPLE
|
||||
// set default data in between
|
||||
if ($position + 1 !== $optionsPosition) {
|
||||
if (! isset($methodCallNode->args[$position + 1])) {
|
||||
$methodCallNode->args[$position + 1] = new Arg(new ConstFetch(new Name('null')));
|
||||
$methodCallNode->args[$position + 1] = new Arg($this->createNull());
|
||||
}
|
||||
}
|
||||
|
||||
@ -291,11 +290,12 @@ CODE_SAMPLE
|
||||
$optionsDefaults = new Array_();
|
||||
|
||||
foreach (array_keys($namesToArgs) as $optionName) {
|
||||
$optionsDefaults->items[] = new ArrayItem(new ConstFetch(new Name('null')), new String_($optionName));
|
||||
$optionsDefaults->items[] = new ArrayItem($this->createNull(), new String_($optionName));
|
||||
}
|
||||
|
||||
$setDefaultsMethodCall = new MethodCall($resolverParamNode->var, new Identifier('setDefaults'));
|
||||
$setDefaultsMethodCall->args[] = new Arg($optionsDefaults);
|
||||
$setDefaultsMethodCall = new MethodCall($resolverParamNode->var, new Identifier('setDefaults'), [
|
||||
new Arg($optionsDefaults),
|
||||
]);
|
||||
|
||||
$configureOptionsClassMethodNode = $this->builderFactory->method('configureOptions')
|
||||
->makePublic()
|
||||
|
@ -75,7 +75,7 @@ final class VarDumperTestTraitMethodArgsRector extends AbstractRector
|
||||
|
||||
if ($node->args[2]->value instanceof String_) {
|
||||
$node->args[3] = $node->args[2];
|
||||
$node->args[2] = $this->nodeFactory->createArg($this->nodeFactory->createNullConstant());
|
||||
$node->args[2] = $this->nodeFactory->createArg($this->createNull());
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
@ -5,9 +5,7 @@ namespace Rector\Symfony\Rector\Yaml;
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Name;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Type\Constant\ConstantStringType;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
@ -51,7 +49,7 @@ final class ParseFileRector extends AbstractRector
|
||||
return null;
|
||||
}
|
||||
|
||||
$fileGetContentsFunCallNode = new FuncCall(new Name('file_get_contents'), [$node->args[0]]);
|
||||
$fileGetContentsFunCallNode = $this->createFunction('file_get_contents', [$node->args[0]]);
|
||||
$node->args[0] = new Arg($fileGetContentsFunCallNode);
|
||||
|
||||
return $node;
|
||||
|
@ -5,4 +5,4 @@ namespace Rector\Symfony\Tests\Rector\New_\StringToArrayArgumentProcessRector\So
|
||||
final class Process
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -5,4 +5,4 @@ namespace Rector\Symfony\Tests\Rector\New_\StringToArrayArgumentProcessRector\So
|
||||
final class ProcessHelper
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Expr\ArrayItem;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
use PhpParser\Node\Expr\ConstFetch;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name;
|
||||
@ -55,22 +54,6 @@ final class NodeFactory
|
||||
$this->typeAnalyzer = $typeAnalyzer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates "null"
|
||||
*/
|
||||
public function createNullConstant(): ConstFetch
|
||||
{
|
||||
return BuilderHelpers::normalizeValue(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates "true"
|
||||
*/
|
||||
public function createTrueConstant(): ConstFetch
|
||||
{
|
||||
return BuilderHelpers::normalizeValue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates "\SomeClass::CONSTANT"
|
||||
*/
|
||||
@ -168,9 +151,7 @@ final class NodeFactory
|
||||
*/
|
||||
public function createArg($argument): Arg
|
||||
{
|
||||
$value = BuilderHelpers::normalizeValue($argument);
|
||||
|
||||
return new Arg($value);
|
||||
return new Arg(BuilderHelpers::normalizeValue($argument));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -179,8 +160,7 @@ final class NodeFactory
|
||||
*/
|
||||
public function createNamespace(string $namespace): Namespace_
|
||||
{
|
||||
return $this->builderFactory->namespace($namespace)
|
||||
->getNode();
|
||||
return new Namespace_(new Name($namespace));
|
||||
}
|
||||
|
||||
public function createParam(string $name, string $type): Param
|
||||
|
@ -17,6 +17,7 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
|
||||
use BetterStandardPrinterTrait;
|
||||
use ClassPropertyCollectorTrait;
|
||||
use RemovingTrait;
|
||||
use NodeFactoryTrait;
|
||||
|
||||
/**
|
||||
* @var ExpressionAdder
|
||||
|
37
src/Rector/NodeFactoryTrait.php
Normal file
37
src/Rector/NodeFactoryTrait.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\Rector;
|
||||
|
||||
use PhpParser\Node\Expr\ConstFetch;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Name;
|
||||
|
||||
/**
|
||||
* This could be part of @see AbstractRector, but decopuling to trait
|
||||
* makes clear what code has 1 purpose.
|
||||
*/
|
||||
trait NodeFactoryTrait
|
||||
{
|
||||
protected function createNull(): ConstFetch
|
||||
{
|
||||
return new ConstFetch(new Name('null'));
|
||||
}
|
||||
|
||||
protected function createFalse(): ConstFetch
|
||||
{
|
||||
return new ConstFetch(new Name('false'));
|
||||
}
|
||||
|
||||
protected function createTrue(): ConstFetch
|
||||
{
|
||||
return new ConstFetch(new Name('true'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $arguments
|
||||
*/
|
||||
protected function createFunction(string $name, array $arguments = []): FuncCall
|
||||
{
|
||||
return new FuncCall(new Name($name), $arguments);
|
||||
}
|
||||
}
|
@ -2,9 +2,7 @@
|
||||
|
||||
namespace Rector\Rector;
|
||||
|
||||
use Countable;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\ArrayDimFetch;
|
||||
use PhpParser\Node\Expr\Cast;
|
||||
use PhpParser\Node\Expr\ClassConstFetch;
|
||||
@ -13,14 +11,8 @@ use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Stmt\ClassConst;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Type\Accessory\HasOffsetType;
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\BooleanType;
|
||||
use PHPStan\Type\IntersectionType;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\StringType;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\NodeTypeResolver\NodeTypeAnalyzer;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
|
||||
/**
|
||||
@ -34,6 +26,11 @@ trait TypeAnalyzerTrait
|
||||
*/
|
||||
private $nodeTypeResolver;
|
||||
|
||||
/**
|
||||
* @var NodeTypeAnalyzer
|
||||
*/
|
||||
private $nodeTypeAnalyzer;
|
||||
|
||||
/**
|
||||
* @required
|
||||
*/
|
||||
@ -42,6 +39,14 @@ trait TypeAnalyzerTrait
|
||||
$this->nodeTypeResolver = $nodeTypeResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* @required
|
||||
*/
|
||||
public function setNodeTypeAnalyzer(NodeTypeAnalyzer $nodeTypeAnalyzer): void
|
||||
{
|
||||
$this->nodeTypeAnalyzer = $nodeTypeAnalyzer;
|
||||
}
|
||||
|
||||
public function isType(Node $node, string $type): bool
|
||||
{
|
||||
$nodeTypes = $this->getTypes($node);
|
||||
@ -68,57 +73,22 @@ trait TypeAnalyzerTrait
|
||||
|
||||
public function isStringType(Node $node): bool
|
||||
{
|
||||
if (! $node instanceof Expr) {
|
||||
return false;
|
||||
}
|
||||
return $this->nodeTypeAnalyzer->isStringType($node);
|
||||
}
|
||||
|
||||
/** @var Scope $nodeScope */
|
||||
$nodeScope = $node->getAttribute(Attribute::SCOPE);
|
||||
$nodeType = $nodeScope->getType($node);
|
||||
|
||||
return $nodeType instanceof StringType;
|
||||
public function isNullableType(Node $node): bool
|
||||
{
|
||||
return $this->nodeTypeAnalyzer->isNullableType($node);
|
||||
}
|
||||
|
||||
public function isBoolType(Node $node): bool
|
||||
{
|
||||
if (! $node instanceof Expr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var Scope $nodeScope */
|
||||
$nodeScope = $node->getAttribute(Attribute::SCOPE);
|
||||
$nodeType = $nodeScope->getType($node);
|
||||
|
||||
return $nodeType instanceof BooleanType;
|
||||
return $this->nodeTypeAnalyzer->isBoolType($node);
|
||||
}
|
||||
|
||||
public function isCountableType(Node $node): bool
|
||||
{
|
||||
if (! $node instanceof Expr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var Scope $nodeScope */
|
||||
$nodeScope = $node->getAttribute(Attribute::SCOPE);
|
||||
$nodeType = $nodeScope->getType($node);
|
||||
|
||||
if ($nodeType instanceof ObjectType) {
|
||||
return is_a($nodeType->getClassName(), Countable::class, true);
|
||||
}
|
||||
|
||||
if ($nodeType instanceof IntersectionType) {
|
||||
foreach ($nodeType->getTypes() as $intersectionNodeType) {
|
||||
if ($intersectionNodeType instanceof ArrayType || $intersectionNodeType instanceof HasOffsetType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return $nodeType instanceof ArrayType;
|
||||
return $this->nodeTypeAnalyzer->isCountableType($node);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -126,6 +96,7 @@ trait TypeAnalyzerTrait
|
||||
*/
|
||||
public function getTypes(Node $node): array
|
||||
{
|
||||
// @todo should be resolved by NodeTypeResolver internally
|
||||
if ($node instanceof ClassMethod || $node instanceof ClassConst) {
|
||||
return $this->nodeTypeResolver->resolve($node->getAttribute(Attribute::CLASS_NODE));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user