mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-17 21:38:22 +01:00
[Php70] add a rector to pass only variables as arguments by reference
This commit is contained in:
parent
a21b805655
commit
85e73f9827
@ -23,3 +23,4 @@ services:
|
||||
|
||||
Rector\Php70\Rector\Break_\BreakNotInLoopOrSwitchToReturnRector: null
|
||||
Rector\Php70\Rector\FuncCall\RenameMktimeWithoutArgsToTimeRector: null
|
||||
Rector\Php70\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector: null
|
||||
|
@ -1,4 +1,4 @@
|
||||
# All 425 Rectors Overview
|
||||
# All 426 Rectors Overview
|
||||
|
||||
- [Projects](#projects)
|
||||
- [General](#general)
|
||||
@ -5275,6 +5275,19 @@ Changes multiple dirname() calls to one with nesting level
|
||||
|
||||
<br>
|
||||
|
||||
### `NonVariableToVariableOnFunctionCallRector`
|
||||
|
||||
- class: `Rector\Php70\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector`
|
||||
|
||||
Transform non variable like arguments to variable where a function or method expects an argument passed by reference
|
||||
|
||||
```diff
|
||||
-reset(a());
|
||||
+$a = a(); reset($a);
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
### `Php4ConstructorRector`
|
||||
|
||||
- class: `Rector\Php70\Rector\FunctionLike\Php4ConstructorRector`
|
||||
|
@ -90,7 +90,7 @@ PHP
|
||||
|
||||
$countInCond = $node;
|
||||
$valueName = $this->getName($node->args[0]->value);
|
||||
$countedValueName = $this->createCountedValueName($valueName, $for);
|
||||
$countedValueName = $this->createCountedValueName($valueName, $for->getAttribute(AttributeKey::SCOPE));
|
||||
|
||||
return new Variable($countedValueName);
|
||||
});
|
||||
@ -105,7 +105,7 @@ PHP
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function createCountedValueName(?string $valueName, For_ $for): string
|
||||
protected function createCountedValueName(?string $valueName, ?Scope $scope): string
|
||||
{
|
||||
if ($valueName === null) {
|
||||
$countedValueName = self::DEFAULT_VARIABLE_COUNT_NAME;
|
||||
@ -113,25 +113,6 @@ PHP
|
||||
$countedValueName = $valueName . 'Count';
|
||||
}
|
||||
|
||||
/** @var Scope|null $forScope */
|
||||
$forScope = $for->getAttribute(AttributeKey::SCOPE);
|
||||
if ($forScope === null) {
|
||||
return $countedValueName;
|
||||
}
|
||||
|
||||
// make sure variable name is unique
|
||||
if (! $forScope->hasVariableType($countedValueName)->yes()) {
|
||||
return $countedValueName;
|
||||
}
|
||||
|
||||
// we need to add number suffix until the variable is unique
|
||||
$i = 2;
|
||||
$countedValueNamePart = $countedValueName;
|
||||
while ($forScope->hasVariableType($countedValueName)->yes()) {
|
||||
$countedValueName = $countedValueNamePart . $i;
|
||||
++$i;
|
||||
}
|
||||
|
||||
return $countedValueName;
|
||||
return parent::createCountedValueName($countedValueName, $scope);
|
||||
}
|
||||
}
|
||||
|
@ -8,3 +8,4 @@ services:
|
||||
exclude:
|
||||
- '../src/Rector/**/*Rector.php'
|
||||
- '../src/Exception/*'
|
||||
- '../src/ValueObject/*'
|
||||
|
@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php70\Rector\FuncCall;
|
||||
|
||||
use function lcfirst;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\ArrayDimFetch;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\AssignOp;
|
||||
use PhpParser\Node\Expr\AssignRef;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Expr\StaticPropertyFetch;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use PHPStan\Analyser\MutatingScope;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\ParameterReflection;
|
||||
use Rector\CodingStyle\Naming\ClassNaming;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Php70\Reflection\CallReflection;
|
||||
use Rector\Php70\ValueObject\VariableAssignPair;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
|
||||
/**
|
||||
* @see https://www.php.net/manual/en/migration70.incompatible.php
|
||||
*
|
||||
* @see \Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\NonVariableToVariableOnFunctionCallRectorTest
|
||||
*/
|
||||
final class NonVariableToVariableOnFunctionCallRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const DEFAULT_VARIABLE_NAME = 'tmp';
|
||||
|
||||
/**
|
||||
* @var CallReflection
|
||||
*/
|
||||
private $callReflection;
|
||||
|
||||
/**
|
||||
* @var ClassNaming
|
||||
*/
|
||||
private $classNaming;
|
||||
|
||||
public function __construct(CallReflection $callReflection, ClassNaming $classNaming)
|
||||
{
|
||||
$this->callReflection = $callReflection;
|
||||
$this->classNaming = $classNaming;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition(
|
||||
'Transform non variable like arguments to variable where a function or method expects an argument passed by reference',
|
||||
[new CodeSample('reset(a());', '$a = a(); reset($a);')]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [FuncCall::class, MethodCall::class, StaticCall::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FuncCall|MethodCall|StaticCall $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$scope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
if (! $scope instanceof MutatingScope) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$arguments = $this->getNonVariableArguments($node, $scope);
|
||||
|
||||
if ($arguments === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach ($arguments as $key => $argument) {
|
||||
$replacements = $this->getReplacementsFor($argument, $scope);
|
||||
|
||||
$current = $node->getAttribute(AttributeKey::CURRENT_STATEMENT);
|
||||
$this->addNodeBeforeNode($replacements->assign(), $current instanceof Return_ ? $current : $node);
|
||||
$node->args[$key]->value = $replacements->variable();
|
||||
|
||||
$scope = $scope->assignExpression($replacements->variable(), $scope->getType($replacements->variable()));
|
||||
}
|
||||
|
||||
$node->setAttribute(AttributeKey::SCOPE, $scope);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FuncCall|MethodCall|StaticCall $node
|
||||
*
|
||||
* @return array<int, Expr>
|
||||
*/
|
||||
private function getNonVariableArguments(Node $node, Scope $scope): array
|
||||
{
|
||||
$arguments = [];
|
||||
|
||||
/** @var ParameterReflection $parameter */
|
||||
foreach ($this->callReflection->getParameterReflections($node, $scope) as $key => $parameter) {
|
||||
// omitted optional parameter
|
||||
if (! isset($node->args[$key])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($parameter->passedByReference()->no()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$argument = $node->args[$key]->value;
|
||||
|
||||
if ($this->isVariableLikeNode($argument)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$arguments[$key] = $argument;
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
private function getReplacementsFor(Expr $expr, Scope $scope): VariableAssignPair
|
||||
{
|
||||
if (
|
||||
(
|
||||
$expr instanceof Assign
|
||||
|| $expr instanceof AssignRef
|
||||
|| $expr instanceof AssignOp
|
||||
)
|
||||
&& $this->isVariableLikeNode($expr->var)
|
||||
) {
|
||||
return new VariableAssignPair($expr->var, $expr);
|
||||
}
|
||||
|
||||
$variable = new Variable($this->getVariableNameFor($expr, $scope));
|
||||
|
||||
return new VariableAssignPair($variable, new Assign($variable, $expr));
|
||||
}
|
||||
|
||||
private function isVariableLikeNode(Node $node): bool
|
||||
{
|
||||
return $node instanceof Variable
|
||||
|| $node instanceof ArrayDimFetch
|
||||
|| $node instanceof PropertyFetch
|
||||
|| $node instanceof StaticPropertyFetch;
|
||||
}
|
||||
|
||||
private function getVariableNameFor(Expr $expr, Scope $scope): string
|
||||
{
|
||||
if ($expr instanceof New_ && $expr->class instanceof Name) {
|
||||
$name = $this->classNaming->getShortName($expr->class);
|
||||
} else {
|
||||
$name = $this->getName($expr);
|
||||
}
|
||||
|
||||
return lcfirst($this->createCountedValueName($name ?? self::DEFAULT_VARIABLE_NAME, $scope));
|
||||
}
|
||||
}
|
107
packages/Php70/src/Reflection/CallReflection.php
Normal file
107
packages/Php70/src/Reflection/CallReflection.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php70\Reflection;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Name;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Broker\Broker;
|
||||
use PHPStan\Broker\FunctionNotFoundException;
|
||||
use PHPStan\Reflection\ParameterReflection;
|
||||
use PHPStan\Reflection\ParametersAcceptor;
|
||||
use PHPStan\Reflection\ParametersAcceptorSelector;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
use Rector\PhpParser\Node\Resolver\NameResolver;
|
||||
|
||||
final class CallReflection
|
||||
{
|
||||
/**
|
||||
* @var Broker
|
||||
*/
|
||||
private $broker;
|
||||
|
||||
/**
|
||||
* @var NodeTypeResolver
|
||||
*/
|
||||
private $nodeTypeResolver;
|
||||
|
||||
/**
|
||||
* @var NameResolver
|
||||
*/
|
||||
private $nameResolver;
|
||||
|
||||
public function __construct(Broker $broker, NodeTypeResolver $nodeTypeResolver, NameResolver $nameResolver)
|
||||
{
|
||||
$this->broker = $broker;
|
||||
$this->nodeTypeResolver = $nodeTypeResolver;
|
||||
$this->nameResolver = $nameResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FuncCall|MethodCall|StaticCall $node
|
||||
*
|
||||
* @return array<int, ParameterReflection>
|
||||
*/
|
||||
public function getParameterReflections(Node $node, Scope $scope): array
|
||||
{
|
||||
if ($node instanceof MethodCall || $node instanceof StaticCall) {
|
||||
$classType = $this->nodeTypeResolver->getObjectType(
|
||||
$node instanceof MethodCall ? $node->var : $node->class
|
||||
);
|
||||
$methodName = $this->nameResolver->getName($node->name);
|
||||
|
||||
if ($methodName === null || ! $classType->hasMethod($methodName)->yes()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return ParametersAcceptorSelector::selectSingle(
|
||||
$classType->getMethod($methodName, $scope)->getVariants()
|
||||
)->getParameters();
|
||||
}
|
||||
|
||||
if ($node->name instanceof Expr) {
|
||||
return $this->getParametersForExpr($node->name, $scope);
|
||||
}
|
||||
|
||||
return $this->getParametersForName($node->name, $node->args, $scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, ParameterReflection>
|
||||
*/
|
||||
private function getParametersForExpr(Expr $expr, Scope $scope): array
|
||||
{
|
||||
$type = $scope->getType($expr);
|
||||
|
||||
if (! $type instanceof ParametersAcceptor) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $type->getParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Arg[] $args
|
||||
*
|
||||
* @return array<int, ParameterReflection>
|
||||
*/
|
||||
private function getParametersForName(Name $name, array $args, Scope $scope): array
|
||||
{
|
||||
try {
|
||||
return ParametersAcceptorSelector::selectFromArgs(
|
||||
$scope,
|
||||
$args,
|
||||
$this->broker->getFunction($name, $scope)->getVariants()
|
||||
)->getParameters();
|
||||
} catch (FunctionNotFoundException $functionNotFoundException) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
53
packages/Php70/src/ValueObject/VariableAssignPair.php
Normal file
53
packages/Php70/src/ValueObject/VariableAssignPair.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php70\ValueObject;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\ArrayDimFetch;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\AssignOp;
|
||||
use PhpParser\Node\Expr\AssignRef;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\StaticPropertyFetch;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
|
||||
final class VariableAssignPair
|
||||
{
|
||||
/**
|
||||
* @var Variable|ArrayDimFetch|PropertyFetch|StaticPropertyFetch
|
||||
*/
|
||||
private $variable;
|
||||
|
||||
/**
|
||||
* @var Assign|AssignOp|AssignRef
|
||||
*/
|
||||
private $assign;
|
||||
|
||||
/**
|
||||
* @param Variable|ArrayDimFetch|PropertyFetch|StaticPropertyFetch $variable
|
||||
* @param Assign|AssignOp|AssignRef $node
|
||||
*/
|
||||
public function __construct(Node $variable, Node $node)
|
||||
{
|
||||
$this->variable = $variable;
|
||||
$this->assign = $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Variable|ArrayDimFetch|PropertyFetch|StaticPropertyFetch
|
||||
*/
|
||||
public function variable(): Node
|
||||
{
|
||||
return $this->variable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Assign|AssignOp|AssignRef
|
||||
*/
|
||||
public function assign(): Node
|
||||
{
|
||||
return $this->assign;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture;
|
||||
|
||||
function assignment()
|
||||
{
|
||||
reset($var = []);
|
||||
reset($var = [0][0]);
|
||||
reset($var = (new \stdClass())->bar);
|
||||
reset($var = \stdClass::$bar);
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture;
|
||||
|
||||
function assignment()
|
||||
{
|
||||
$var = [];
|
||||
reset($var);
|
||||
$var = [0][0];
|
||||
reset($var);
|
||||
$var = (new \stdClass())->bar;
|
||||
reset($var);
|
||||
$var = \stdClass::$bar;
|
||||
reset($var);
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture;
|
||||
|
||||
function binaryOp()
|
||||
{
|
||||
reset(1 + 1);
|
||||
reset(2 + $var);
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture;
|
||||
|
||||
function binaryOp()
|
||||
{
|
||||
$tmp = 1 + 1;
|
||||
reset($tmp);
|
||||
$tmp = 2 + $var;
|
||||
reset($tmp);
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture;
|
||||
|
||||
function byRef($bar, &$baz) {}
|
||||
|
||||
function allByRef(&$bar, &$baz) {}
|
||||
|
||||
function funcCalls()
|
||||
{
|
||||
reset(bar());
|
||||
byRef(bar(), baz());
|
||||
allByRef(bar(), baz());
|
||||
allByRef(1, 2);
|
||||
|
||||
$anonymousFunction = function (&$bar) {};
|
||||
$staticAnonymousFunction = static function (&$bar) {};
|
||||
$anonymousFunction(bar());
|
||||
$staticAnonymousFunction(bar());
|
||||
|
||||
return byRef(1, bar());
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture;
|
||||
|
||||
function byRef($bar, &$baz) {}
|
||||
|
||||
function allByRef(&$bar, &$baz) {}
|
||||
|
||||
function funcCalls()
|
||||
{
|
||||
$bar = bar();
|
||||
reset($bar);
|
||||
$baz = baz();
|
||||
byRef(bar(), $baz);
|
||||
$bar = bar();
|
||||
$baz = baz();
|
||||
allByRef($bar, $baz);
|
||||
$tmp = 1;
|
||||
$tmp2 = 2;
|
||||
allByRef($tmp, $tmp2);
|
||||
|
||||
$anonymousFunction = function (&$bar) {};
|
||||
$staticAnonymousFunction = static function (&$bar) {};
|
||||
$bar = bar();
|
||||
$anonymousFunction($bar);
|
||||
$bar = bar();
|
||||
$staticAnonymousFunction($bar);
|
||||
$bar = bar();
|
||||
|
||||
return byRef(1, $bar);
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture;
|
||||
|
||||
function arrayDimFetch()
|
||||
{
|
||||
reset([1][0]);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture;
|
||||
|
||||
function propertyFetch()
|
||||
{
|
||||
reset((new \stdClass())->dummy);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture;
|
||||
|
||||
function staticPropertyFetch()
|
||||
{
|
||||
reset(\stdClass::$dummy);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture;
|
||||
|
||||
function variable()
|
||||
{
|
||||
reset($var);
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture;
|
||||
|
||||
function methodCallAsArgument()
|
||||
{
|
||||
reset((new \stdClass())->bar());
|
||||
reset((new \stdClass())->bar()->baz());
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture;
|
||||
|
||||
function methodCallAsArgument()
|
||||
{
|
||||
$bar = (new \stdClass())->bar();
|
||||
reset($bar);
|
||||
$baz = (new \stdClass())->bar()->baz();
|
||||
reset($baz);
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture;
|
||||
|
||||
class Child
|
||||
{
|
||||
public function bar(&$bar) {}
|
||||
}
|
||||
|
||||
class AClass
|
||||
{
|
||||
public static function staticMethod(&$bar) {}
|
||||
|
||||
public function baz(&$bar) {}
|
||||
|
||||
public function child(): Child
|
||||
{
|
||||
return new Child();
|
||||
}
|
||||
}
|
||||
|
||||
function methodCalls()
|
||||
{
|
||||
AClass::staticMethod(bar());
|
||||
$aClass = new AClass();
|
||||
$aClass->baz(baz());
|
||||
$aClass->child()->bar(bar());
|
||||
|
||||
$anonymousClass = new class {
|
||||
public function bar(&$baz) {}
|
||||
};
|
||||
$anonymousClass->bar(baz());
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture;
|
||||
|
||||
class Child
|
||||
{
|
||||
public function bar(&$bar) {}
|
||||
}
|
||||
|
||||
class AClass
|
||||
{
|
||||
public static function staticMethod(&$bar) {}
|
||||
|
||||
public function baz(&$bar) {}
|
||||
|
||||
public function child(): Child
|
||||
{
|
||||
return new Child();
|
||||
}
|
||||
}
|
||||
|
||||
function methodCalls()
|
||||
{
|
||||
$bar = bar();
|
||||
AClass::staticMethod($bar);
|
||||
$aClass = new AClass();
|
||||
$baz = baz();
|
||||
$aClass->baz($baz);
|
||||
$bar = bar();
|
||||
$aClass->child()->bar($bar);
|
||||
|
||||
$anonymousClass = new class {
|
||||
public function bar(&$baz) {}
|
||||
};
|
||||
$baz = baz();
|
||||
$anonymousClass->bar($baz);
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture;
|
||||
|
||||
class Bar {}
|
||||
|
||||
function new_()
|
||||
{
|
||||
reset(new \stdClass());
|
||||
reset(new Bar());
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture;
|
||||
|
||||
class Bar {}
|
||||
|
||||
function new_()
|
||||
{
|
||||
$stdClass = new \stdClass();
|
||||
reset($stdClass);
|
||||
$bar = new Bar();
|
||||
reset($bar);
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector\Fixture;
|
||||
|
||||
function withOptionalParameter(&$a = null) {}
|
||||
|
||||
function optionalParameter()
|
||||
{
|
||||
baz();
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php70\Tests\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Php70\Rector\FuncCall\NonVariableToVariableOnFunctionCallRector;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
final class NonVariableToVariableOnFunctionCallRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideDataForTest()
|
||||
*/
|
||||
public function test(string $file): void
|
||||
{
|
||||
$this->doTestFile($file);
|
||||
}
|
||||
|
||||
public function provideDataForTest(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return NonVariableToVariableOnFunctionCallRector::class;
|
||||
}
|
||||
}
|
@ -256,3 +256,6 @@ parameters:
|
||||
- '#Method (.*?) returns bool type, so the name should start with is/has/was#'
|
||||
|
||||
- '#Property Rector\\BetterPhpDocParser\\PhpDocNode\\Gedmo\\BlameableTagValueNode\:\:\$value has no typehint specified#'
|
||||
|
||||
# known value
|
||||
- "#^Parameter \\#1 \\$variable of class Rector\\\\Php70\\\\ValueObject\\\\VariableAssignPair constructor expects PhpParser\\\\Node\\\\Expr\\\\ArrayDimFetch\\|PhpParser\\\\Node\\\\Expr\\\\PropertyFetch\\|PhpParser\\\\Node\\\\Expr\\\\StaticPropertyFetch\\|PhpParser\\\\Node\\\\Expr\\\\Variable, PhpParser\\\\Node\\\\Expr given\\.$#"
|
||||
|
@ -13,6 +13,7 @@ use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\NodeVisitorAbstract;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use Rector\Commander\CommanderCollector;
|
||||
use Rector\Contract\PhpParser\Node\CommanderInterface;
|
||||
use Rector\Contract\Rector\PhpRectorInterface;
|
||||
@ -276,4 +277,26 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
|
||||
{
|
||||
return ! $this->areNodesEqual($originalNode, $node);
|
||||
}
|
||||
|
||||
protected function createCountedValueName(string $countedValueName, ?Scope $scope): string
|
||||
{
|
||||
if ($scope === null) {
|
||||
return $countedValueName;
|
||||
}
|
||||
|
||||
// make sure variable name is unique
|
||||
if (! $scope->hasVariableType($countedValueName)->yes()) {
|
||||
return $countedValueName;
|
||||
}
|
||||
|
||||
// we need to add number suffix until the variable is unique
|
||||
$i = 2;
|
||||
$countedValueNamePart = $countedValueName;
|
||||
while ($scope->hasVariableType($countedValueName)->yes()) {
|
||||
$countedValueName = $countedValueNamePart . $i;
|
||||
++$i;
|
||||
}
|
||||
|
||||
return $countedValueName;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user