Find all New_
nodes that are not used as a default value for Param
node
#8742
-
I have a Rector rule that converts It works great. I trigger on Except there is a problem. You should not use class Test
{
public function __construct(
private Money $money = new Money(1234, new Currency('EUR'))
) {}
} I know that parent nodes are removed so that cannot help me. Any idea how to solve this? https://getrector.com/ast/f3ec06ef80fd814785009782208afab44854dfde <?php
declare(strict_types=1);
namespace Dev\Rector;
use Money\Currency;
use Money\Money;
use Override;
use PhpParser\Node;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Scalar\LNumber;
use Rector\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
final class StaticMoneyConstructorRector extends AbstractRector
{
#[Override]
public function getRuleDefinition() : RuleDefinition
{
return new RuleDefinition(
'Replace `new Money(10, new Currency("EUR"))` with `Money::EUR(10)`.',
[
new CodeSample(
<<<'CODE_SAMPLE'
new Money(10, new Currency("EUR"));
CODE_SAMPLE,
<<<'CODE_SAMPLE'
Money::EUR(10);
CODE_SAMPLE,
)],
);
}
/**
* @return array<class-string<Node>>
*/
#[Override]
public function getNodeTypes() : array
{
return [New_::class];
}
#[Override]
public function refactor(Node $node) : ?Node
{
if ( ! $node instanceof New_) {
return null;
}
if ( ! $node->class instanceof Node\Name\FullyQualified) {
return null;
}
if ($node->class->toString() !== Money::class) {
return null;
}
if (count($node->args) !== 2) {
return null;
}
[$amountArg, $currencyArg] = $node->args;
if ( ! $amountArg instanceof Node\Arg) {
return null;
}
if ( ! $currencyArg instanceof Node\Arg) {
return null;
}
$amount = $amountArg->value;
if ( ! $amount instanceof LNumber) {
return null;
}
if ( ! $currencyArg->value instanceof New_) {
return null;
}
if ( ! $currencyArg->value->class instanceof Node\Name\FullyQualified) {
return null;
}
if ($currencyArg->value->class->toString() !== Currency::class) {
return null;
}
if (count($currencyArg->value->args) !== 1) {
return null;
}
[$currencyCodeArg] = $currencyArg->value->args;
if ( ! $currencyCodeArg instanceof Node\Arg) {
return null;
}
$currency = $currencyCodeArg->value;
if ( ! $currency instanceof Node\Scalar\String_) {
return null;
}
return new Node\Expr\StaticCall(
$node->class,
$currency->value,
[new Node\Arg($amount)],
);
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
You can define Param::class early before New_::class: use PhpParser\Node\Param;
// ...
public function getNodeTypes() : array
{
return [Param::class, New_::class];
} Then, in refactor method, you can early skip if below use PhpParser\NodeTraverser;
// ...
/**
* @param Param|New_ $node
*/
public function refactor(Node $node): null|int|Node
{
if ($node instanceof Param) {
// below Param won't be processed on current rule
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
}
// process New_ here...
} see https://getrector.com/blog/5-tricks-to-write-better-custom-rules |
Beta Was this translation helpful? Give feedback.
You can define Param::class early before New_::class:
Then, in refactor method, you can early skip if below
Param
:see https://getrector.com/blog/5-tricks-to-write-better-custom-rules