[MagicDisclosure] Add SetterOnSetterMethodCallToStandaloneAssignRector (#3860)

* [MagicDisclosure] Add MethodCallOnSetterMethodCallToStandaloneAssignRector

* merge ChainMethodCallManipulator to ChainMethodCallNodeAnalyzer for better DX

* [MagicDisclosure] Add in arg defluent

* rebase
This commit is contained in:
Tomas Votruba 2020-08-01 13:41:16 +02:00 committed by GitHub
parent ab8d290b14
commit 55acb3578a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
173 changed files with 1129 additions and 383 deletions

View File

@ -4,11 +4,14 @@ declare(strict_types=1);
use Rector\MagicDisclosure\Rector\ClassMethod\ReturnThisRemoveRector;
use Rector\MagicDisclosure\Rector\MethodCall\DefluentMethodCallRector;
use Rector\MagicDisclosure\Rector\MethodCall\InArgChainMethodCallToStandaloneMethodCallRector;
use Rector\MagicDisclosure\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector;
use Rector\MagicDisclosure\Rector\Return_\DefluentReturnMethodCallRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
// @see https://ocramius.github.io/blog/fluent-interfaces-are-evil/
// @see https://www.yegor256.com/2018/03/13/fluent-interfaces.html
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
@ -17,4 +20,8 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services->set(DefluentReturnMethodCallRector::class);
$services->set(DefluentMethodCallRector::class);
$services->set(MethodCallOnSetterMethodCallToStandaloneAssignRector::class);
$services->set(InArgChainMethodCallToStandaloneMethodCallRector::class);
};

View File

@ -1,4 +1,4 @@
# All 545 Rectors Overview
# All 546 Rectors Overview
- [Projects](#projects)
---
@ -25,7 +25,7 @@
- [JMS](#jms) (2)
- [Laravel](#laravel) (6)
- [Legacy](#legacy) (4)
- [MagicDisclosure](#magicdisclosure) (6)
- [MagicDisclosure](#magicdisclosure) (8)
- [MockeryToProphecy](#mockerytoprophecy) (2)
- [MockistaToMockery](#mockistatomockery) (2)
- [MysqlToMysqli](#mysqltomysqli) (4)
@ -668,7 +668,8 @@ Change `array_push()` to direct variable assign
Merges nested if statements
```diff
class SomeClass {
class SomeClass
{
public function run()
{
- if ($cond1) {
@ -4317,7 +4318,8 @@ Change Tree from gedmo/doctrine-extensions to knplabs/doctrine-behaviors
Changes property type definition from type definitions to `@var` annotations.
```diff
class SomeClass {
class SomeClass
{
- private string $property;
+ /**
+ * @var string
@ -6211,6 +6213,60 @@ return function (ContainerConfigurator $containerConfigurator) : void {
<br><br>
### `InArgChainMethodCallToStandaloneMethodCallRector`
- class: [`Rector\MagicDisclosure\Rector\MethodCall\InArgChainMethodCallToStandaloneMethodCallRector`](/../master/rules/magic-disclosure/src/Rector/MethodCall/InArgChainMethodCallToStandaloneMethodCallRector.php)
- [test fixtures](/../master/rules/magic-disclosure/tests/Rector/MethodCall/InArgChainMethodCallToStandaloneMethodCallRector/Fixture)
Turns fluent interface calls to classic ones.
```diff
class UsedAsParameter
{
public function someFunction(FluentClass $someClass)
{
- $this->processFluentClass($someClass->someFunction()->otherFunction());
+ $someClass->someFunction();
+ $someClass->otherFunction();
+ $this->processFluentClass($someClass);
}
public function processFluentClass(FluentClass $someClass)
{
}
-}
+}
```
<br><br>
### `MethodCallOnSetterMethodCallToStandaloneAssignRector`
- class: [`Rector\MagicDisclosure\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector`](/../master/rules/magic-disclosure/src/Rector/MethodCall/MethodCallOnSetterMethodCallToStandaloneAssignRector.php)
- [test fixtures](/../master/rules/magic-disclosure/tests/Rector/MethodCall/MethodCallOnSetterMethodCallToStandaloneAssignRector/Fixture)
Change method call on setter to standalone assign before the setter
```diff
class SomeClass
{
public function some()
{
- $this->anotherMethod(new AnotherClass())
- ->someFunction();
+ $anotherClass = new AnotherClass();
+ $anotherClass->someFunction();
+ $this->anotherMethod($anotherClass);
}
public function anotherMethod(AnotherClass $anotherClass)
{
}
}
```
<br><br>
### `ReturnThisRemoveRector`
- class: [`Rector\MagicDisclosure\Rector\ClassMethod\ReturnThisRemoveRector`](/../master/rules/magic-disclosure/src/Rector/ClassMethod/ReturnThisRemoveRector.php)
@ -6218,21 +6274,6 @@ return function (ContainerConfigurator $containerConfigurator) : void {
Removes "return `$this;"` from *fluent interfaces* for specified classes.
```php
<?php
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Rector\MagicDisclosure\Rector\ClassMethod\ReturnThisRemoveRector;
return function (ContainerConfigurator $containerConfigurator) : void {
$services = $containerConfigurator->services();
$services->set(ReturnThisRemoveRector::class)
->call('configure', [['types_to_match', ['SomeExampleClass']]]);
};
```
```diff
class SomeExampleClass
{
@ -9102,7 +9143,8 @@ Add pre-slash to short named functions to improve performance
Add $_SERVER REQUEST_URI to method call
```diff
class SomeClass {
class SomeClass
{
public function run($di)
{
$application = new \Phalcon\Mvc\Application();
@ -9143,7 +9185,8 @@ Decouple `Phalcon\Mvc\Model::save()` with argument to `assign()`
Add `$cssClasses` in Flash to separated method call
```diff
class SomeClass {
class SomeClass
{
public function run()
{
$cssClasses = [];
@ -10336,7 +10379,8 @@ Add "_" as thousands separator in numbers
Change `array_key_exists()` on property to `property_exists()`
```diff
class SomeClass {
class SomeClass
{
public $value;
}
$someClass = new SomeClass;
@ -10891,7 +10935,8 @@ Complete missing constructor dependency instance by type
Change docs types to union types, where possible (properties are covered by TypedPropertiesRector)
```diff
class SomeClass {
class SomeClass
{
/**
* @param array|int $number
* @return bool|float

View File

@ -36,7 +36,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -40,7 +40,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -63,7 +63,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -52,7 +52,6 @@ PHP
// current PHP: 7.2
return 'is PHP 7.2+';
PHP
),
]);
}

View File

@ -52,7 +52,6 @@ class LocationsFixture extends TestFixture implements Plugin
{
}
PHP
),
]);
}

View File

@ -51,7 +51,6 @@ use Event\NotificationListener;
CakeEventManager::instance()->attach(new NotificationListener());
PHP
),
]);
}

View File

@ -67,7 +67,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -43,7 +43,6 @@ final class SomeClass
}
}
PHP
),
]);
}

View File

@ -50,7 +50,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -55,7 +55,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -58,7 +58,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -46,7 +46,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -37,7 +37,6 @@ PHP
<<<'PHP'
'#' . preg_quote('name', '#') . '#';
PHP
),
]);
}

View File

@ -42,7 +42,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -50,7 +50,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -47,7 +47,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -42,7 +42,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -22,7 +22,8 @@ final class CombineIfRector extends AbstractRector
return new RectorDefinition('Merges nested if statements', [
new CodeSample(
<<<'PHP'
class SomeClass {
class SomeClass
{
public function run()
{
if ($cond1) {
@ -35,7 +36,8 @@ class SomeClass {
PHP
,
<<<'PHP'
class SomeClass {
class SomeClass
{
public function run()
{
if ($cond1 && $cond2) {
@ -44,7 +46,6 @@ class SomeClass {
}
}
PHP
),
]);
}

View File

@ -50,8 +50,7 @@ class SomeClass
}
}
PHP
),
),
]
);
}

View File

@ -65,7 +65,6 @@ final class AnotherClass
{
}
PHP
),
]);
}

View File

@ -43,7 +43,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -2,7 +2,8 @@
namespace Rector\CodeQuality\Tests\Rector\If_\CombineIfRector\ChildElse;
class SomeClass {
class SomeClass
{
public function run()
{
if ($cond1) {

View File

@ -2,7 +2,8 @@
namespace Rector\CodeQuality\Tests\Rector\If_\CombineIfRector\ChildElseIf;
class SomeClass {
class SomeClass
{
public function run()
{
if ($cond1) {

View File

@ -2,7 +2,8 @@
namespace Rector\CodeQuality\Tests\Rector\If_\CombineIfRector\DocBlock;
class SomeClass {
class SomeClass
{
public function run()
{
// condition 1
@ -29,7 +30,8 @@ class SomeClass {
namespace Rector\CodeQuality\Tests\Rector\If_\CombineIfRector\DocBlock;
class SomeClass {
class SomeClass
{
public function run()
{
// condition 1

View File

@ -2,7 +2,8 @@
namespace Rector\CodeQuality\Tests\Rector\If_\CombineIfRector\Fixture;
class SomeClass {
class SomeClass
{
public function run()
{
if ($cond1) {
@ -19,7 +20,8 @@ class SomeClass {
namespace Rector\CodeQuality\Tests\Rector\If_\CombineIfRector\Fixture;
class SomeClass {
class SomeClass
{
public function run()
{
if ($cond1 && $cond2) {

View File

@ -2,7 +2,8 @@
namespace Rector\CodeQuality\Tests\Rector\If_\CombineIfRector\MoreStatements;
class SomeClass {
class SomeClass
{
public function run()
{
if ($cond1) {

View File

@ -2,7 +2,8 @@
namespace Rector\CodeQuality\Tests\Rector\If_\CombineIfRector\ParentElse;
class SomeClass {
class SomeClass
{
public function run()
{
if ($cond1) {

View File

@ -2,7 +2,8 @@
namespace Rector\CodeQuality\Tests\Rector\If_\CombineIfRector\ParentElseIf;
class SomeClass {
class SomeClass
{
public function run()
{
if ($cond1) {

View File

@ -39,7 +39,6 @@ function some_camel_case_function()
some_camel_case_function();
PHP
),
]);
}

View File

@ -48,7 +48,6 @@ final class SomeClass
}
}
PHP
),
]);
}

View File

@ -41,7 +41,6 @@ class SomeClass
use AnotherTrait;
}
PHP
),
]);
}

View File

@ -51,7 +51,6 @@ final class SomeClass
}
}
PHP
),
]);
}

View File

@ -50,7 +50,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -40,7 +40,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -52,7 +52,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -68,7 +68,6 @@ class SomeClass
{
}
PHP
),
]);
}

View File

@ -62,7 +62,6 @@ class SomeClass implements SomeInterface
}
}
PHP
),
]);
}

View File

@ -75,7 +75,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -50,7 +50,6 @@ function useMe()
useMe();
PHP
),
]);
}

View File

@ -75,7 +75,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -50,7 +50,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -45,7 +45,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -68,9 +68,8 @@ class SomeClass
}
}
PHP
),
]);
]);
}
/**

View File

@ -47,8 +47,7 @@ final class SomeClass
}
}
PHP
),
),
]
);
}

View File

@ -89,7 +89,6 @@ class SomeClass implements BlameableInterface
use BlameableTrait;
}
PHP
),
]);
}

View File

@ -73,7 +73,6 @@ class SomeClass implements LoggableInterface
private $title;
}
PHP
),
]);
}

View File

@ -81,7 +81,6 @@ class SomeClass implements SluggableInterface
}
}
PHP
),
]);
}

View File

@ -72,8 +72,7 @@ class SomeClass implements SoftDeletableInterface
use SoftDeletableTrait;
}
PHP
),
),
]
);
}

View File

@ -54,8 +54,7 @@ class SomeClass implements TimestampableInterface
use TimestampableTrait;
}
PHP
),
),
]
);
}

View File

@ -136,7 +136,6 @@ class SomeClassTranslation implements TranslationInterface
private $content;
}
PHP
),
]);
}

View File

@ -120,7 +120,6 @@ class SomeClass implements TreeNodeInterface
use TreeNodeTrait;
}
PHP
),
]);
}

View File

@ -22,20 +22,21 @@ final class DowngradeTypedPropertyRector extends AbstractRector
return new RectorDefinition('Changes property type definition from type definitions to `@var` annotations.', [
new CodeSample(
<<<'PHP'
class SomeClass {
class SomeClass
{
private string $property;
}
PHP
,
<<<'PHP'
class SomeClass {
class SomeClass
{
/**
* @var string
*/
private $property;
}
PHP
),
]);
}

View File

@ -2,7 +2,8 @@
namespace Rector\Downgrade\Tests\Rector\Property\DowngradeTypedPropertyRector\Fixture;
class SomeClass {
class SomeClass
{
private string $property;
}
@ -12,7 +13,8 @@ class SomeClass {
namespace Rector\Downgrade\Tests\Rector\Property\DowngradeTypedPropertyRector\Fixture;
class SomeClass {
class SomeClass
{
/**
* @var string
*/

View File

@ -8,10 +8,10 @@ use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\Variable;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\PhpParser\Node\Manipulator\MethodCallManipulator;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\ConfiguredCodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\MagicDisclosure\NodeAnalyzer\ChainMethodCallNodeAnalyzer;
/**
* @see \Rector\Generic\Tests\Rector\MethodCall\MethodCallRemoverRector\MethodCallRemoverRectorTest
@ -29,13 +29,13 @@ final class MethodCallRemoverRector extends AbstractRector implements Configurab
private $methodCallRemoverArgument = [];
/**
* @var MethodCallManipulator
* @var ChainMethodCallNodeAnalyzer
*/
private $methodCallManipulator;
private $chainMethodCallNodeAnalyzer;
public function __construct(MethodCallManipulator $methodCallManipulator)
public function __construct(ChainMethodCallNodeAnalyzer $chainMethodCallNodeAnalyzer)
{
$this->methodCallManipulator = $methodCallManipulator;
$this->chainMethodCallNodeAnalyzer = $chainMethodCallNodeAnalyzer;
}
public function getDefinition(): RectorDefinition
@ -104,7 +104,7 @@ PHP
private function getRootNodeVariableName(MethodCall $methodCall): ?string
{
$rootNode = $this->methodCallManipulator->resolveRootVariable($methodCall);
$rootNode = $this->chainMethodCallNodeAnalyzer->resolveRootVariable($methodCall);
return $this->getName($rootNode);
}
}

View File

@ -43,7 +43,6 @@ class SomeClass
{
}
PHP
),
]);
}

View File

@ -62,7 +62,6 @@ class SomeUtilsClass
SomeUtilsClass::someFunction('lol');
PHP
),
]);
}

View File

@ -4,18 +4,25 @@ declare(strict_types=1);
namespace Rector\MagicDisclosure\NodeAnalyzer;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\StaticCall;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeWithClassName;
use PHPStan\Type\UnionType;
use Rector\MagicDisclosure\ValueObject\AssignAndRootExpr;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\PHPStanStaticTypeMapper\Utils\TypeUnwrapper;
/**
* Utils for chain of MethodCall Node:
* "$this->methodCall()->chainedMethodCall()"
*/
final class ChainMethodCallNodeAnalyzer
{
/**
@ -28,10 +35,19 @@ final class ChainMethodCallNodeAnalyzer
*/
private $typeUnwrapper;
public function __construct(NodeTypeResolver $nodeTypeResolver, TypeUnwrapper $typeUnwrapper)
{
/**
* @var NodeNameResolver
*/
private $nodeNameResolver;
public function __construct(
NodeNameResolver $nodeNameResolver,
NodeTypeResolver $nodeTypeResolver,
TypeUnwrapper $typeUnwrapper
) {
$this->nodeTypeResolver = $nodeTypeResolver;
$this->typeUnwrapper = $typeUnwrapper;
$this->nodeNameResolver = $nodeNameResolver;
}
/**
@ -139,6 +155,83 @@ final class ChainMethodCallNodeAnalyzer
return $chainMethodCalls;
}
/**
* @return MethodCall[]
*/
public function collectAllMethodCallsInChainWithoutRootOne(MethodCall $methodCall): array
{
$chainMethodCalls = $this->collectAllMethodCallsInChain($methodCall);
foreach ($chainMethodCalls as $key => $chainMethodCall) {
if (! $chainMethodCall->var instanceof MethodCall) {
unset($chainMethodCalls[$key]);
break;
}
}
return array_values($chainMethodCalls);
}
/**
* Checks "$this->someMethod()->anotherMethod()"
*
* @param string[] $methods
*/
public function isTypeAndChainCalls(Node $node, Type $type, array $methods): bool
{
if (! $node instanceof MethodCall) {
return false;
}
// node chaining is in reverse order than code
$methods = array_reverse($methods);
foreach ($methods as $method) {
$activeMethodName = $this->nodeNameResolver->getName($node->name);
if ($activeMethodName !== $method) {
return false;
}
$node = $node->var;
if ($node instanceof MethodCall) {
continue;
}
}
$variableType = $this->nodeTypeResolver->resolve($node);
if ($variableType instanceof MixedType) {
return false;
}
return $variableType->isSuperTypeOf($type)->yes();
}
public function resolveRootVariable(MethodCall $methodCall): Node
{
$callerNode = $methodCall->var;
while ($callerNode instanceof MethodCall || $callerNode instanceof StaticCall) {
$callerNode = $callerNode instanceof StaticCall ? $callerNode->class : $callerNode->var;
}
return $callerNode;
}
public function resolveRootMethodCall(MethodCall $methodCall): ?MethodCall
{
$callerNode = $methodCall->var;
while ($callerNode instanceof MethodCall && $callerNode->var instanceof MethodCall) {
$callerNode = $callerNode->var;
}
if ($callerNode instanceof MethodCall) {
return $callerNode;
}
return null;
}
private function resolveStringTypeFromExpr(Expr $expr): ?string
{
$rootStaticType = $this->nodeTypeResolver->getStaticType($expr);

View File

@ -19,7 +19,6 @@ use Rector\MagicDisclosure\NodeManipulator\ChainMethodCallRootExtractor;
use Rector\MagicDisclosure\Rector\AbstractRector\AbstractConfigurableMatchTypeRector;
use Rector\MagicDisclosure\ValueObject\AssignAndRootExpr;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
/**
* @see https://ocramius.github.io/blog/fluent-interfaces-are-evil/
@ -87,7 +86,13 @@ PHP
return null;
}
if ($this->isHandledByReturn($node)) {
// is handled by @see \Rector\MagicDisclosure\Rector\Return_\DefluentReturnMethodCallRector
if ($this->hasParentType($node, Return_::class)) {
return null;
}
// is handled by @see InArgChainMethodCallToStandaloneMethodCallRector
if ($this->hasParentType($node, Arg::class)) {
return null;
}
@ -147,22 +152,6 @@ PHP
return $node;
}
/**
* @param MethodCall|Return_ $node
*/
private function isHandledByReturn(Node $node): bool
{
if ($node instanceof MethodCall) {
$parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
// handled ty Return_ node
if ($parentNode instanceof Return_) {
return true;
}
}
return false;
}
/**
* @param MethodCall[] $chainMethodCalls
*/

View File

@ -0,0 +1,249 @@
<?php
declare(strict_types=1);
namespace Rector\MagicDisclosure\Rector\MethodCall;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\MagicDisclosure\NodeAnalyzer\ChainMethodCallNodeAnalyzer;
use Rector\MagicDisclosure\NodeFactory\NonFluentMethodCallFactory;
use Rector\MagicDisclosure\NodeManipulator\ChainMethodCallRootExtractor;
use Rector\MagicDisclosure\Rector\AbstractRector\AbstractConfigurableMatchTypeRector;
use Rector\MagicDisclosure\ValueObject\AssignAndRootExpr;
use Rector\NodeTypeResolver\Node\AttributeKey;
/**
* @sponsor Thanks https://amateri.com for sponsoring this rule - visit them on https://www.startupjobs.cz/startup/scrumworks-s-r-o
*
* @see \Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainMethodCallToStandaloneMethodCallRector\InArgChainMethodCallToStandaloneMethodCallRectorTest
*/
final class InArgChainMethodCallToStandaloneMethodCallRector extends AbstractConfigurableMatchTypeRector implements ConfigurableRectorInterface
{
/**
* @var ChainMethodCallNodeAnalyzer
*/
private $chainMethodCallNodeAnalyzer;
/**
* @var ChainMethodCallRootExtractor
*/
private $chainMethodCallRootExtractor;
/**
* @var NonFluentMethodCallFactory
*/
private $nonFluentMethodCallFactory;
public function __construct(
ChainMethodCallNodeAnalyzer $chainMethodCallNodeAnalyzer,
ChainMethodCallRootExtractor $chainMethodCallRootExtractor,
NonFluentMethodCallFactory $nonFluentMethodCallFactory
) {
$this->chainMethodCallNodeAnalyzer = $chainMethodCallNodeAnalyzer;
$this->chainMethodCallRootExtractor = $chainMethodCallRootExtractor;
$this->nonFluentMethodCallFactory = $nonFluentMethodCallFactory;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Turns fluent interface calls to classic ones.', [new CodeSample(<<<'PHP'
class UsedAsParameter
{
public function someFunction(FluentClass $someClass)
{
$this->processFluentClass($someClass->someFunction()->otherFunction());
}
public function processFluentClass(FluentClass $someClass)
{
}
}
PHP
, <<<'PHP'
class UsedAsParameter
{
public function someFunction(FluentClass $someClass)
{
$someClass->someFunction();
$someClass->otherFunction();
$this->processFluentClass($someClass);
}
public function processFluentClass(FluentClass $someClass)
{
}
}
PHP
)]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [MethodCall::class];
}
/**
* @param MethodCall $node
*/
public function refactor(Node $node): ?Node
{
$methodCall = $this->matchMethodCall($node);
if ($methodCall === null) {
return null;
}
if (! $this->hasParentType($node, Arg::class)) {
return null;
}
if (! $this->chainMethodCallNodeAnalyzer->isLastChainMethodCall($methodCall)) {
return null;
}
if ($this->isGetterMethodCall($methodCall)) {
return null;
}
$chainMethodCalls = $this->chainMethodCallNodeAnalyzer->collectAllMethodCallsInChain($methodCall);
$assignAndRootExpr = $this->chainMethodCallRootExtractor->extractFromMethodCalls($chainMethodCalls);
if ($assignAndRootExpr === null) {
return null;
}
if ($this->shouldSkip($assignAndRootExpr, $chainMethodCalls)) {
return null;
}
$nodesToAdd = $this->nonFluentMethodCallFactory->createFromAssignObjectAndMethodCalls(
$assignAndRootExpr,
$chainMethodCalls
);
$nodesToAdd = $this->addFluentAsArg($node, $assignAndRootExpr, $nodesToAdd);
$this->removeCurrentNode($node);
foreach ($nodesToAdd as $nodeToAdd) {
// needed to remove weird spacing
$nodeToAdd->setAttribute(AttributeKey::ORIGINAL_NODE, null);
$this->addNodeAfterNode($nodeToAdd, $node);
}
return $node;
}
/**
* @param MethodCall|Return_ $node
*/
private function matchMethodCall(Node $node): ?MethodCall
{
if ($node instanceof Return_) {
if ($node->expr === null) {
return null;
}
if ($node->expr instanceof MethodCall) {
return $node->expr;
}
return null;
}
return $node;
}
/**
* @param MethodCall[] $chainMethodCalls
*/
private function shouldSkip(AssignAndRootExpr $assignAndRootExpr, array $chainMethodCalls): bool
{
$calleeUniqueTypes = $this->chainMethodCallNodeAnalyzer->resolveCalleeUniqueTypes(
$assignAndRootExpr,
$chainMethodCalls
);
if (count($calleeUniqueTypes) !== 1) {
return true;
}
$calleeUniqueType = $calleeUniqueTypes[0];
// skip query and builder
// @see https://ocramius.github.io/blog/fluent-interfaces-are-evil/ "When does a fluent interface make sense?"
if ((bool) Strings::match($calleeUniqueType, '#(Query|Builder)$#')) {
return true;
}
return ! $this->isMatchedType($calleeUniqueType);
}
/**
* @param MethodCall|Return_ $node
*/
private function removeCurrentNode(Node $node): void
{
$parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
if ($parentNode instanceof Assign) {
$this->removeNode($parentNode);
return;
}
// part of method call
if ($parentNode instanceof Arg) {
$parentParent = $parentNode->getAttribute(AttributeKey::PARENT_NODE);
if ($parentParent instanceof MethodCall) {
$this->removeNode($parentParent);
}
return;
}
$this->removeNode($node);
}
/**
* @param Return_|MethodCall $node
* @param Node[] $nodesToAdd
* @return Node[]
*/
private function addFluentAsArg(Node $node, AssignAndRootExpr $assignAndRootExpr, array $nodesToAdd): array
{
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
if (! $parent instanceof Arg) {
return $nodesToAdd;
}
$parentParent = $parent->getAttribute(AttributeKey::PARENT_NODE);
if (! $parentParent instanceof MethodCall) {
return $nodesToAdd;
}
$lastMethodCall = new MethodCall($parentParent->var, $parentParent->name);
$lastMethodCall->args[] = new Arg($assignAndRootExpr->getRootExpr());
$nodesToAdd[] = $lastMethodCall;
return $nodesToAdd;
}
private function isGetterMethodCall(MethodCall $methodCall): bool
{
if ($methodCall->var instanceof MethodCall) {
return false;
}
$methodCallStaticType = $this->getStaticType($methodCall);
$methodCallVarStaticType = $this->getStaticType($methodCall->var);
// getter short call type
return ! $methodCallStaticType->equals($methodCallVarStaticType);
}
}

View File

@ -0,0 +1,176 @@
<?php
declare(strict_types=1);
namespace Rector\MagicDisclosure\Rector\MethodCall;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Expression;
use PHPStan\Type\MixedType;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\MagicDisclosure\NodeAnalyzer\ChainMethodCallNodeAnalyzer;
use Rector\NetteKdyby\Naming\VariableNaming;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
/**
* @sponsor Thanks https://amateri.com for sponsoring this rule - visit them on https://www.startupjobs.cz/startup/scrumworks-s-r-o
*
* @see \Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\MethodCallOnSetterMethodCallToStandaloneAssignRectorTest
*/
final class MethodCallOnSetterMethodCallToStandaloneAssignRector extends AbstractRector
{
/**
* @var VariableNaming
*/
private $variableNaming;
/**
* @var ChainMethodCallNodeAnalyzer
*/
private $chainMethodCallNodeAnalyzer;
public function __construct(
VariableNaming $variableNaming,
ChainMethodCallNodeAnalyzer $chainMethodCallNodeAnalyzer
) {
$this->variableNaming = $variableNaming;
$this->chainMethodCallNodeAnalyzer = $chainMethodCallNodeAnalyzer;
}
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Change method call on setter to standalone assign before the setter', [
new CodeSample(
<<<'PHP'
class SomeClass
{
public function some()
{
$this->anotherMethod(new AnotherClass())
->someFunction();
}
public function anotherMethod(AnotherClass $anotherClass)
{
}
}
PHP
,
<<<'PHP'
class SomeClass
{
public function some()
{
$anotherClass = new AnotherClass();
$anotherClass->someFunction();
$this->anotherMethod($anotherClass);
}
public function anotherMethod(AnotherClass $anotherClass)
{
}
}
PHP
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [MethodCall::class];
}
/**
* @param MethodCall $node
*/
public function refactor(Node $node): ?Node
{
if ($this->shouldSkip($node)) {
return null;
}
$rootMethodCall = $this->chainMethodCallNodeAnalyzer->resolveRootMethodCall($node);
if ($rootMethodCall === null) {
return null;
}
$new = $this->matchNewInFluentSetterMethodCall($rootMethodCall);
if ($new === null) {
return null;
}
$variableName = $this->variableNaming->resolveFromNode($new);
$newVariable = new Variable($variableName);
$assignExpression = $this->createAssignExpression($newVariable, $new);
$this->addNodeBeforeNode($assignExpression, $node);
// resolve chain calls
$chainMethodCalls = $this->chainMethodCallNodeAnalyzer->collectAllMethodCallsInChainWithoutRootOne($node);
$chainMethodCalls = array_reverse($chainMethodCalls);
foreach ($chainMethodCalls as $chainMethodCall) {
$currentMethodCall = new MethodCall($newVariable, $chainMethodCall->name, $chainMethodCall->args);
$this->addNodeBeforeNode($currentMethodCall, $node);
}
// change new arg to root variable
$rootMethodCall->args = [new Arg($newVariable)];
return $rootMethodCall;
}
/**
* Method call with "new X", that returns "X"?
* e.g.
*
* $this->setItem(new Item) // → returns "Item"
*/
private function matchNewInFluentSetterMethodCall(MethodCall $methodCall): ?New_
{
if (count($methodCall->args) !== 1) {
return null;
}
$onlyArgValue = $methodCall->args[0]->value;
if (! $onlyArgValue instanceof New_) {
return null;
}
$newType = $this->getObjectType($onlyArgValue);
if ($newType instanceof MixedType) {
return null;
}
$parentMethodCallReturnType = $this->getObjectType($methodCall);
if (! $newType->equals($parentMethodCallReturnType)) {
return null;
}
return $onlyArgValue;
}
private function createAssignExpression(Variable $newVariable, New_ $new): Expression
{
$assign = new Assign($newVariable, $new);
return new Expression($assign);
}
private function shouldSkip(MethodCall $methodCall): bool
{
if (! $methodCall->var instanceof MethodCall) {
return true;
}
return ! $this->chainMethodCallNodeAnalyzer->isLastChainMethodCall($methodCall);
}
}

View File

@ -3,9 +3,8 @@
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\DefluentMethodCallRector\Fixture;
use DateTime;
use Symfony\Component\Console\Command\Command;
class SkipDateTimeModifyCommand extends Command
class SkipDateTimeModifyCommand
{
public function go()
{

View File

@ -0,0 +1,17 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\DefluentMethodCallRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\DefluentMethodCallRector\Source\FluentInterfaceClass;
class UsedAsParameter
{
public function someFunction(FluentInterfaceClass $someClass)
{
$this->processMoreFluentInterface($someClass->someFunction()->otherFunction());
}
public function processMoreFluentInterface(FluentInterfaceClass $someClass)
{
}
}

View File

@ -1,41 +0,0 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\DefluentMethodCallRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\DefluentMethodCallRector\Source\FluentInterfaceClass;
class UsedAsParameter
{
public function someFunction(FluentInterfaceClass $someClass)
{
$this->processMoreFluentInterface($someClass->someFunction()->otherFunction());
}
public function processMoreFluentInterface(FluentInterfaceClass $someClass)
{
}
}
?>
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\DefluentMethodCallRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\DefluentMethodCallRector\Source\FluentInterfaceClass;
class UsedAsParameter
{
public function someFunction(FluentInterfaceClass $someClass)
{
$someClass->someFunction();
$someClass->otherFunction();
$this->processMoreFluentInterface($someClass);
}
public function processMoreFluentInterface(FluentInterfaceClass $someClass)
{
}
}
?>

View File

@ -0,0 +1,17 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainMethodCallToStandaloneMethodCallRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainMethodCallToStandaloneMethodCallRector\Source\FluentClass;
class SkipSingleClass
{
public function someFunction(FluentClass $someClass)
{
$this->processFluentClass($someClass->someFunction());
}
public function processFluentClass(FluentClass $someClass)
{
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainMethodCallToStandaloneMethodCallRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainMethodCallToStandaloneMethodCallRector\Source\FluentClass;
class UsedAsParameter
{
public function someFunction(FluentClass $someClass)
{
$this->processFluentClass($someClass->someFunction()->otherFunction());
}
public function processFluentClass(FluentClass $someClass)
{
}
}
?>
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainMethodCallToStandaloneMethodCallRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainMethodCallToStandaloneMethodCallRector\Source\FluentClass;
class UsedAsParameter
{
public function someFunction(FluentClass $someClass)
{
$someClass->someFunction();
$someClass->otherFunction();
$this->processFluentClass($someClass);
}
public function processFluentClass(FluentClass $someClass)
{
}
}
?>

View File

@ -0,0 +1,41 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainMethodCallToStandaloneMethodCallRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainMethodCallToStandaloneMethodCallRector\Source\FluentClass;
class WithArgs
{
public function someFunction(FluentClass $someClass)
{
$this->processFluentClass($someClass->someFunction(100)->otherFunction([1, 2, 3]));
}
public function processFluentClass(FluentClass $someClass)
{
}
}
?>
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainMethodCallToStandaloneMethodCallRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainMethodCallToStandaloneMethodCallRector\Source\FluentClass;
class WithArgs
{
public function someFunction(FluentClass $someClass)
{
$someClass->someFunction(100);
$someClass->otherFunction([1, 2, 3]);
$this->processFluentClass($someClass);
}
public function processFluentClass(FluentClass $someClass)
{
}
}
?>

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainMethodCallToStandaloneMethodCallRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\MagicDisclosure\Rector\MethodCall\InArgChainMethodCallToStandaloneMethodCallRector;
use Symplify\SmartFileSystem\SmartFileInfo;
final class InArgChainMethodCallToStandaloneMethodCallRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
protected function getRectorClass(): string
{
return InArgChainMethodCallToStandaloneMethodCallRector::class;
}
}

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\InArgChainMethodCallToStandaloneMethodCallRector\Source;
final class FluentClass
{
public function someFunction(): self
{
return $this;
}
public function otherFunction(): self
{
return $this;
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
class SomeClass
{
public function some()
{
$this->anotherMethod(new AnotherClass())
->someFunction();
}
public function anotherMethod(AnotherClass $anotherClass): AnotherClass
{
return $anotherClass;
}
}
?>
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
class SomeClass
{
public function some()
{
$anotherClass = new AnotherClass();
$anotherClass->someFunction();
$this->anotherMethod($anotherClass);
}
public function anotherMethod(AnotherClass $anotherClass): AnotherClass
{
return $anotherClass;
}
}
?>

View File

@ -0,0 +1,46 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
class MultiChain
{
public function some()
{
$this->anotherMethod(new AnotherClass())
->someFunction()
->anotherFunction();
}
public function anotherMethod(AnotherClass $anotherClass): AnotherClass
{
return $anotherClass;
}
}
?>
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
class MultiChain
{
public function some()
{
$anotherClass = new AnotherClass();
$anotherClass->someFunction();
$anotherClass->anotherFunction();
$this->anotherMethod($anotherClass);
}
public function anotherMethod(AnotherClass $anotherClass): AnotherClass
{
return $anotherClass;
}
}
?>

View File

@ -0,0 +1,46 @@
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
class WithArguments
{
public function some()
{
$this->anotherMethod(new AnotherClass([1, 2, 3]))
->someFunction(4)
->anotherFunction(5);
}
public function anotherMethod(AnotherClass $anotherClass): AnotherClass
{
return $anotherClass;
}
}
?>
-----
<?php
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Fixture;
use Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source\AnotherClass;
class WithArguments
{
public function some()
{
$anotherClass = new AnotherClass([1, 2, 3]);
$anotherClass->someFunction(4);
$anotherClass->anotherFunction(5);
$this->anotherMethod($anotherClass);
}
public function anotherMethod(AnotherClass $anotherClass): AnotherClass
{
return $anotherClass;
}
}
?>

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector;
use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Rector\MagicDisclosure\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector;
use Symplify\SmartFileSystem\SmartFileInfo;
final class MethodCallOnSetterMethodCallToStandaloneAssignRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
protected function getRectorClass(): string
{
return MethodCallOnSetterMethodCallToStandaloneAssignRector::class;
}
}

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace Rector\MagicDisclosure\Tests\Rector\MethodCall\MethodCallOnSetterMethodCallToStandaloneAssignRector\Source;
final class AnotherClass
{
public function someFunction(): AnotherClass
{
return $this;
}
public function anotherFunction(): AnotherClass
{
return $this;
}
}

View File

@ -62,7 +62,6 @@ class SomeTest extends TestCase
}
}
PHP
),
]);
}

View File

@ -65,7 +65,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -71,7 +71,6 @@ final class SomeClass
}
}
PHP
),
]);
}

View File

@ -104,7 +104,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -60,8 +60,7 @@ class SomePresenter extends Presenter
}
}
PHP
),
),
]
);
}

View File

@ -88,7 +88,6 @@ final class SomePresenter extends Presenter
}
}
PHP
),
]);
}

View File

@ -95,7 +95,6 @@ final class AnotherControl extends Control
{
}
PHP
),
]);
}

View File

@ -76,7 +76,6 @@ final class SomeClass
}
}
PHP
),
]);
}

View File

@ -49,7 +49,7 @@ final class VariableWithTypesFactory
foreach ($args as $arg) {
$staticType = $this->nodeTypeResolver->getStaticType($arg->value);
$variableName = $this->variableNaming->resolveFromNode($arg, $staticType);
$variableName = $this->variableNaming->resolveFromNodeAndType($arg, $staticType);
// compensate for static
if ($staticType instanceof StaticType) {

View File

@ -172,7 +172,7 @@ final class ContributeEventClassResolver
private function createGetterFromParamAndStaticType(Param $param, Type $type): string
{
$variableName = $this->variableNaming->resolveFromNode($param, $type);
$variableName = $this->variableNaming->resolveFromNodeAndType($param, $type);
return 'get' . ucfirst($variableName);
}
}

View File

@ -9,6 +9,7 @@ use PhpParser\Node\Arg;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\Cast;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Ternary;
use PhpParser\Node\Scalar;
@ -17,9 +18,11 @@ use PHPStan\Type\ThisType;
use PHPStan\Type\Type;
use Rector\CodingStyle\Naming\ClassNaming;
use Rector\Core\Exception\NotImplementedException;
use Rector\Core\Exception\NotImplementedYetException;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
use Rector\Core\Util\StaticRectorStrings;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\NodeTypeResolver;
final class VariableNaming
{
@ -38,17 +41,31 @@ final class VariableNaming
*/
private $classNaming;
/**
* @var NodeTypeResolver
*/
private $nodeTypeResolver;
public function __construct(
ClassNaming $classNaming,
NodeNameResolver $nodeNameResolver,
ValueResolver $valueResolver
ValueResolver $valueResolver,
NodeTypeResolver $nodeTypeResolver
) {
$this->nodeNameResolver = $nodeNameResolver;
$this->valueResolver = $valueResolver;
$this->classNaming = $classNaming;
$this->nodeTypeResolver = $nodeTypeResolver;
}
public function resolveFromNode(Node $node, Type $type): string
public function resolveFromNode(Node $node): string
{
$nodeType = $this->nodeTypeResolver->getStaticType($node);
return $this->resolveFromNodeAndType($node, $nodeType);
}
public function resolveFromNodeAndType(Node $node, Type $type): string
{
$variableName = $this->resolveBareFromNode($node);
@ -111,17 +128,7 @@ final class VariableNaming
private function resolveBareFromNode(Node $node): string
{
if ($node instanceof Arg) {
$node = $node->value;
}
if ($node instanceof Cast) {
$node = $node->expr;
}
if ($node instanceof Ternary) {
$node = $node->if;
}
$node = $this->unwrapNode($node);
if ($node instanceof ArrayDimFetch) {
return $this->resolveParamNameFromArrayDimFetch($node);
@ -135,6 +142,10 @@ final class VariableNaming
return $this->resolveFromMethodCall($node);
}
if ($node instanceof New_) {
return $this->resolveFromNew($node);
}
if ($node === null) {
throw new NotImplementedException();
}
@ -150,4 +161,31 @@ final class VariableNaming
throw new NotImplementedException();
}
private function resolveFromNew(New_ $new): string
{
if ($new->class instanceof Node\Name) {
$className = $this->nodeNameResolver->getName($new->class);
return $this->classNaming->getShortName($className);
}
throw new NotImplementedYetException();
}
private function unwrapNode(Node $node): ?Node
{
if ($node instanceof Arg) {
return $node->value;
}
if ($node instanceof Cast) {
return $node->expr;
}
if ($node instanceof Ternary) {
return $node->if;
}
return $node;
}
}

View File

@ -94,7 +94,6 @@ final class SomeClass
}
}
PHP
),
]);
}

View File

@ -53,7 +53,6 @@ final class SomeClass
}
}
PHP
),
]);
}

View File

@ -66,7 +66,6 @@ class SomeControl extends Control
}
}
PHP
),
]);
}

View File

@ -60,7 +60,6 @@ final class SomeClass implements ITranslator
}
}
PHP
),
]);
}

View File

@ -42,7 +42,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -54,7 +54,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -64,8 +64,7 @@ class SomeClass
}
}
PHP
),
),
]
);
}

View File

@ -51,7 +51,6 @@ final class SomeExtension extends CompilerExtension
}
}
PHP
),
]);
}

View File

@ -47,7 +47,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -63,7 +63,6 @@ class SomeClass
}
}
PHP
),
]);
}

View File

@ -55,7 +55,6 @@ class SomeClass
const MODE_OFF = 2;
}
PHP
),
]);
}

View File

@ -69,7 +69,6 @@ class SomeClass
}
}
PHP
),
]);
}

Some files were not shown because too many files have changed in this diff Show More