diff --git a/rules/Unambiguous/NodeAnalyzer/FluentMethodCallsCollector.php b/rules/Unambiguous/NodeAnalyzer/FluentMethodCallsCollector.php new file mode 100644 index 00000000000..94387aedd78 --- /dev/null +++ b/rules/Unambiguous/NodeAnalyzer/FluentMethodCallsCollector.php @@ -0,0 +1,60 @@ +var instanceof MethodCall) { + return []; + } + + /** @var MethodCall[] $methodCalls */ + $methodCalls = []; + + $currentMethodCall = $firstMethodCall; + $classNameObjectType = null; + while ($currentMethodCall instanceof MethodCall) { + if ($currentMethodCall->isFirstClassCallable()) { + return []; + } + + // must be exactly one argument + if (count($currentMethodCall->getArgs()) !== 1) { + return []; + } + + $objectType = $this->nodeTypeResolver->getType($currentMethodCall->var); + if (! $objectType instanceof ObjectType) { + return []; + } + + if ($classNameObjectType === null) { + $classNameObjectType = $objectType->getClassName(); + } elseif ($classNameObjectType !== $objectType->getClassName()) { + return []; + } + + $methodCalls[] = $currentMethodCall; + $currentMethodCall = $currentMethodCall->var; + } + + return $methodCalls; + } +} diff --git a/rules/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector.php b/rules/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector.php index f9da5bf3e9e..4b94cd32c40 100644 --- a/rules/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector.php +++ b/rules/Unambiguous/Rector/Expression/FluentSettersToStandaloneCallMethodRector.php @@ -19,6 +19,7 @@ use Rector\Naming\Naming\PropertyNaming; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\Rector\AbstractRector; +use Rector\Unambiguous\NodeAnalyzer\FluentMethodCallsCollector; use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; @@ -30,7 +31,8 @@ final class FluentSettersToStandaloneCallMethodRector extends AbstractRector { public function __construct( - private readonly PropertyNaming $propertyNaming + private readonly PropertyNaming $propertyNaming, + private readonly FluentMethodCallsCollector $fluentMethodCallsCollector ) { } @@ -87,54 +89,21 @@ public function refactor(Node $node): ?array return null; } - $firstMethodCall = $node->expr; - - // must be nested method call, so we avoid only single one - if (! $firstMethodCall->var instanceof MethodCall) { - return null; - } - - /** @var MethodCall[] $methodCalls */ - $methodCalls = []; - - $currentMethodCall = $firstMethodCall; - $classNameObjectType = null; - while ($currentMethodCall instanceof MethodCall) { - if ($currentMethodCall->isFirstClassCallable()) { - return null; - } - - // must be exactly one argument - if (count($currentMethodCall->getArgs()) !== 1) { - return null; - } - - $objectType = $this->getType($currentMethodCall->var); - if (! $objectType instanceof ObjectType) { - return null; - } - - if ($classNameObjectType === null) { - $classNameObjectType = $objectType->getClassName(); - } elseif ($classNameObjectType !== $objectType->getClassName()) { - return null; - } - - $methodCalls[] = $currentMethodCall; - $currentMethodCall = $currentMethodCall->var; - } + $methodCalls = $this->fluentMethodCallsCollector->resolve($node->expr); // at least 2 method calls if (count($methodCalls) < 1) { return null; } - $rootExpr = $currentMethodCall; + $lastMethodCall = end($methodCalls); + $rootExpr = $lastMethodCall->var; + if (! $rootExpr instanceof New_) { return null; } - if ($this->shouldSkipForVendorOrInternal($firstMethodCall)) { + if ($this->shouldSkipForVendorOrInternal($node->expr)) { return null; }