mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-17 21:38:22 +01:00
refactoring of variable name counted (#3999)
* fix variable rename scoping * [rector] fix variable rename scoping * [cs] fix variable rename scoping Co-authored-by: rector-bot <tomas@getrector.org>
This commit is contained in:
parent
04597e9685
commit
786095f328
@ -20,7 +20,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
->exclude([
|
||||
__DIR__ . '/../src/Exception/*',
|
||||
__DIR__ . '/../src/ValueObject/*',
|
||||
__DIR__ . '/../src/Rector/*',
|
||||
__DIR__ . '/../src/Rector',
|
||||
]);
|
||||
|
||||
$services->set(AddNewServiceToSymfonyPhpConfigRector::class)
|
||||
|
@ -3,6 +3,7 @@ includes:
|
||||
- vendor/symplify/phpstan-extensions/config/config.neon
|
||||
- vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon
|
||||
- vendor/slam/phpstan-extensions/conf/slam-rules.neon
|
||||
- vendor/phpstan/phpstan/conf/bleedingEdge.neon
|
||||
|
||||
# see https://github.com/symplify/coding-standard
|
||||
- vendor/symplify/coding-standard/config/symplify-rules.neon
|
||||
@ -375,7 +376,6 @@ parameters:
|
||||
# is nested expr
|
||||
- '#Access to an undefined property PhpParser\\Node\\Expr\:\:\$expr#'
|
||||
- '#Cognitive complexity for "Rector\\DeadCode\\NodeManipulator\\LivingCodeManipulator\:\:keepLivingCodeFromExpr\(\)" is \d+, keep it under 9#'
|
||||
- '#Class with base "LexerFactory" name is already used in "PHPStan\\Parser\\LexerFactory", "Rector\\Core\\PhpParser\\Parser\\LexerFactory"\. Use unique name to make classes easy to recognize#'
|
||||
- '#Parameter \#1 \$files of method Symplify\\SmartFileSystem\\Finder\\FinderSanitizer\:\:sanitize\(\) expects \(iterable<SplFileInfo\|string\>&Nette\\Utils\\Finder\)\|Symfony\\Component\\Finder\\Finder, array<string\> given#'
|
||||
- '#Static property Rector\\Core\\Testing\\PHPUnit\\AbstractGenericRectorTestCase\:\:\$allRectorContainer \(Rector\\Naming\\Tests\\Rector\\Class_\\RenamePropertyToMatchTypeRector\\Source\\ContainerInterface\|Symfony\\Component\\DependencyInjection\\Container\|null\) does not accept Psr\\Container\\ContainerInterface#'
|
||||
# stubs
|
||||
|
@ -7,14 +7,12 @@ namespace Rector\CodeQuality\Rector\For_;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\For_;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\NetteKdyby\Naming\VariableNaming;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
||||
/**
|
||||
@ -23,9 +21,14 @@ use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
final class ForRepeatedCountToOwnVariableRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @var VariableNaming
|
||||
*/
|
||||
private const DEFAULT_VARIABLE_COUNT_NAME = 'itemsCount';
|
||||
private $variableNaming;
|
||||
|
||||
public function __construct(VariableNaming $variableNaming)
|
||||
{
|
||||
$this->variableNaming = $variableNaming;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
@ -73,13 +76,14 @@ PHP
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$countInCond = null;
|
||||
$countedValueName = null;
|
||||
$for = $node;
|
||||
$variableName = null;
|
||||
|
||||
$forScope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
|
||||
$this->traverseNodesWithCallable($node->cond, function (Node $node) use (
|
||||
&$countInCond,
|
||||
&$countedValueName,
|
||||
$for
|
||||
&$variableName,
|
||||
$forScope
|
||||
) {
|
||||
if (! $node instanceof FuncCall) {
|
||||
return null;
|
||||
@ -91,36 +95,23 @@ PHP
|
||||
|
||||
$countInCond = $node;
|
||||
|
||||
$valueName = $this->resolveValueName($node);
|
||||
$countedValueName = $this->createCountedValueName($valueName, $for->getAttribute(AttributeKey::SCOPE));
|
||||
$variableName = $this->variableNaming->resolveFromFuncCallFirstArgumentWithSuffix(
|
||||
$node,
|
||||
'Count',
|
||||
'itemsCount',
|
||||
$forScope
|
||||
);
|
||||
|
||||
return new Variable($countedValueName);
|
||||
return new Variable($variableName);
|
||||
});
|
||||
|
||||
if ($countInCond === null || $countedValueName === null) {
|
||||
if ($countInCond === null || $variableName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$countAssign = new Assign(new Variable($countedValueName), $countInCond);
|
||||
$countAssign = new Assign(new Variable($variableName), $countInCond);
|
||||
$this->addNodeBeforeNode($countAssign, $node);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
protected function createCountedValueName(?string $valueName, ?Scope $scope): string
|
||||
{
|
||||
$countedValueName = $valueName === null ? self::DEFAULT_VARIABLE_COUNT_NAME : $valueName . 'Count';
|
||||
|
||||
return parent::createCountedValueName($countedValueName, $scope);
|
||||
}
|
||||
|
||||
private function resolveValueName(FuncCall $funcCall): ?string
|
||||
{
|
||||
$argumentValue = $funcCall->args[0]->value;
|
||||
if ($argumentValue instanceof MethodCall || $argumentValue instanceof StaticCall) {
|
||||
return $this->getName($argumentValue->name);
|
||||
}
|
||||
|
||||
return $this->getName($argumentValue);
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\MagicDisclosure\NodeAnalyzer\FluentChainMethodCallNodeAnalyzer;
|
||||
use Rector\MagicDisclosure\NodeManipulator\FluentChainMethodCallRootExtractor;
|
||||
use Rector\MagicDisclosure\ValueObject\AssignAndRootExpr;
|
||||
@ -42,6 +43,10 @@ final class NonFluentChainMethodCallFactory
|
||||
public function createFromNewAndRootMethodCall(New_ $new, MethodCall $rootMethodCall): array
|
||||
{
|
||||
$variableName = $this->variableNaming->resolveFromNode($new);
|
||||
if ($variableName === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$newVariable = new Variable($variableName);
|
||||
|
||||
$newStmts = [];
|
||||
|
@ -10,6 +10,7 @@ use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\MagicDisclosure\NodeAnalyzer\ExprStringTypeResolver;
|
||||
use Rector\MagicDisclosure\ValueObject\AssignAndRootExpr;
|
||||
@ -79,9 +80,7 @@ final class FluentChainMethodCallRootExtractor
|
||||
if ($methodCall->var instanceof New_) {
|
||||
// direct = no parent
|
||||
if ($kind === self::KIND_IN_ARGS) {
|
||||
$variableName = $this->variableNaming->resolveFromNode($methodCall->var);
|
||||
$silentVariable = new Variable($variableName);
|
||||
return new AssignAndRootExpr($methodCall->var, $methodCall->var, $silentVariable);
|
||||
return $this->resolveKindInArgs($methodCall);
|
||||
}
|
||||
|
||||
return $this->matchMethodCallOnNew($methodCall);
|
||||
@ -119,6 +118,17 @@ final class FluentChainMethodCallRootExtractor
|
||||
return $variableStaticType !== $calledMethodStaticType;
|
||||
}
|
||||
|
||||
private function resolveKindInArgs(MethodCall $methodCall): AssignAndRootExpr
|
||||
{
|
||||
$variableName = $this->variableNaming->resolveFromNode($methodCall->var);
|
||||
if ($variableName === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$silentVariable = new Variable($variableName);
|
||||
return new AssignAndRootExpr($methodCall->var, $methodCall->var, $silentVariable);
|
||||
}
|
||||
|
||||
private function matchMethodCallOnNew(MethodCall $methodCall): ?AssignAndRootExpr
|
||||
{
|
||||
// we need assigned left variable here
|
||||
|
@ -9,6 +9,7 @@ use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\MagicDisclosure\NodeAnalyzer\NewFluentChainMethodCallNodeAnalyzer;
|
||||
@ -140,6 +141,10 @@ PHP
|
||||
private function crateVariableFromNew(New_ $new): Variable
|
||||
{
|
||||
$variableName = $this->variableNaming->resolveFromNode($new);
|
||||
if ($variableName === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
return new Variable($variableName);
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\MagicDisclosure\NodeAnalyzer\NewFluentChainMethodCallNodeAnalyzer;
|
||||
@ -126,6 +127,10 @@ PHP
|
||||
private function crateVariableFromNew(New_ $new): Variable
|
||||
{
|
||||
$variableName = $this->variableNaming->resolveFromNode($new);
|
||||
if ($variableName === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
return new Variable($variableName);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ namespace Rector\NetteKdyby\BlueprintFactory;
|
||||
use PhpParser\Node\Arg;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\StaticType;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\NetteKdyby\Naming\VariableNaming;
|
||||
use Rector\NetteKdyby\ValueObject\VariableWithType;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
@ -50,6 +51,9 @@ final class VariableWithTypesFactory
|
||||
foreach ($args as $arg) {
|
||||
$staticType = $this->nodeTypeResolver->getStaticType($arg->value);
|
||||
$variableName = $this->variableNaming->resolveFromNodeAndType($arg, $staticType);
|
||||
if ($variableName === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
// compensate for static
|
||||
if ($staticType instanceof StaticType) {
|
||||
|
@ -173,6 +173,10 @@ final class ContributeEventClassResolver
|
||||
private function createGetterFromParamAndStaticType(Param $param, Type $type): string
|
||||
{
|
||||
$variableName = $this->variableNaming->resolveFromNodeAndType($param, $type);
|
||||
if ($variableName === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
return 'get' . ucfirst($variableName);
|
||||
}
|
||||
}
|
||||
|
@ -8,13 +8,16 @@ use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\ArrayDimFetch;
|
||||
use PhpParser\Node\Expr\Cast;
|
||||
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\Ternary;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Scalar;
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Type\ThisType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\CodingStyle\Naming\ClassNaming;
|
||||
@ -25,6 +28,9 @@ use Rector\Core\Util\StaticRectorStrings;
|
||||
use Rector\NodeNameResolver\NodeNameResolver;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
|
||||
/**
|
||||
* @todo decouple to collector?
|
||||
*/
|
||||
final class VariableNaming
|
||||
{
|
||||
/**
|
||||
@ -59,16 +65,18 @@ final class VariableNaming
|
||||
$this->nodeTypeResolver = $nodeTypeResolver;
|
||||
}
|
||||
|
||||
public function resolveFromNode(Node $node): 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
|
||||
public function resolveFromNodeAndType(Node $node, Type $type): ?string
|
||||
{
|
||||
$variableName = $this->resolveBareFromNode($node);
|
||||
if ($variableName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// adjust static to specific class
|
||||
if ($variableName === 'this' && $type instanceof ThisType) {
|
||||
@ -79,7 +87,52 @@ final class VariableNaming
|
||||
return StaticRectorStrings::underscoreToPascalCase($variableName);
|
||||
}
|
||||
|
||||
private function resolveBareFromNode(Node $node): string
|
||||
public function resolveFromNodeWithScopeCountAndFallbackName(
|
||||
Node\Expr $expr,
|
||||
Scope $scope,
|
||||
string $fallbackName
|
||||
): string {
|
||||
$name = $this->resolveFromNode($expr);
|
||||
if ($name === null) {
|
||||
$name = $fallbackName;
|
||||
}
|
||||
|
||||
return lcfirst($this->createCountedValueName($name, $scope));
|
||||
}
|
||||
|
||||
public function createCountedValueName(string $valueName, ?Scope $scope): string
|
||||
{
|
||||
if ($scope === null) {
|
||||
return $valueName;
|
||||
}
|
||||
|
||||
// make sure variable name is unique
|
||||
if (! $scope->hasVariableType($valueName)->yes()) {
|
||||
return $valueName;
|
||||
}
|
||||
|
||||
// we need to add number suffix until the variable is unique
|
||||
$i = 2;
|
||||
$countedValueNamePart = $valueName;
|
||||
while ($scope->hasVariableType($valueName)->yes()) {
|
||||
$valueName = $countedValueNamePart . $i;
|
||||
++$i;
|
||||
}
|
||||
|
||||
return $valueName;
|
||||
}
|
||||
|
||||
public function resolveFromFuncCallFirstArgumentWithSuffix(
|
||||
FuncCall $funcCall,
|
||||
string $suffix,
|
||||
string $fallbackName,
|
||||
?Scope $scope
|
||||
): string {
|
||||
$bareName = $this->resolveBareFuncCallArgumentName($funcCall, $fallbackName, $suffix);
|
||||
return $this->createCountedValueName($bareName, $scope);
|
||||
}
|
||||
|
||||
private function resolveBareFromNode(Node $node): ?string
|
||||
{
|
||||
$node = $this->unwrapNode($node);
|
||||
|
||||
@ -99,6 +152,10 @@ final class VariableNaming
|
||||
return $this->resolveFromNew($node);
|
||||
}
|
||||
|
||||
if ($node instanceof FuncCall) {
|
||||
return $this->resolveFromNode($node->name);
|
||||
}
|
||||
|
||||
if ($node === null) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@ -112,7 +169,23 @@ final class VariableNaming
|
||||
return $node->value;
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
return null;
|
||||
}
|
||||
|
||||
private function resolveBareFuncCallArgumentName(FuncCall $funcCall, string $fallbackName, string $suffix): string
|
||||
{
|
||||
$argumentValue = $funcCall->args[0]->value;
|
||||
if ($argumentValue instanceof MethodCall || $argumentValue instanceof StaticCall) {
|
||||
$name = $this->nodeNameResolver->getName($argumentValue->name);
|
||||
} else {
|
||||
$name = $this->nodeNameResolver->getName($argumentValue);
|
||||
}
|
||||
|
||||
if ($name === null) {
|
||||
return $fallbackName;
|
||||
}
|
||||
|
||||
return $name . $suffix;
|
||||
}
|
||||
|
||||
private function unwrapNode(Node $node): ?Node
|
||||
@ -132,7 +205,7 @@ final class VariableNaming
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function resolveParamNameFromArrayDimFetch(ArrayDimFetch $arrayDimFetch): string
|
||||
private function resolveParamNameFromArrayDimFetch(ArrayDimFetch $arrayDimFetch): ?string
|
||||
{
|
||||
while ($arrayDimFetch instanceof ArrayDimFetch) {
|
||||
if ($arrayDimFetch->dim instanceof Scalar) {
|
||||
@ -165,19 +238,18 @@ final class VariableNaming
|
||||
return $varName . ucfirst($propertyName);
|
||||
}
|
||||
|
||||
private function resolveFromMethodCall(MethodCall $methodCall): string
|
||||
private function resolveFromMethodCall(MethodCall $methodCall): ?string
|
||||
{
|
||||
$varName = $this->nodeNameResolver->getName($methodCall->var);
|
||||
if (! is_string($varName)) {
|
||||
throw new NotImplementedException();
|
||||
if ($methodCall->name instanceof MethodCall) {
|
||||
return $this->resolveFromMethodCall($methodCall->name);
|
||||
}
|
||||
|
||||
$methodName = $this->nodeNameResolver->getName($methodCall->name);
|
||||
if (! is_string($methodName)) {
|
||||
throw new NotImplementedException();
|
||||
return null;
|
||||
}
|
||||
|
||||
return $varName . ucfirst($methodName);
|
||||
return $methodName;
|
||||
}
|
||||
|
||||
private function resolveFromNew(New_ $new): string
|
||||
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace Rector\Php70\Rector\FuncCall;
|
||||
|
||||
use function lcfirst;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\ArrayDimFetch;
|
||||
@ -13,20 +12,20 @@ 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 PHPStan\Type\MixedType;
|
||||
use Rector\Core\PHPStan\Reflection\CallReflectionResolver;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\NetteKdyby\Naming\VariableNaming;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\Php70\ValueObject\VariableAssignPair;
|
||||
|
||||
@ -37,19 +36,20 @@ use Rector\Php70\ValueObject\VariableAssignPair;
|
||||
*/
|
||||
final class NonVariableToVariableOnFunctionCallRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const DEFAULT_VARIABLE_NAME = 'tmp';
|
||||
|
||||
/**
|
||||
* @var CallReflectionResolver
|
||||
*/
|
||||
private $callReflectionResolver;
|
||||
|
||||
public function __construct(CallReflectionResolver $callReflectionResolver)
|
||||
/**
|
||||
* @var VariableNaming
|
||||
*/
|
||||
private $variableNaming;
|
||||
|
||||
public function __construct(CallReflectionResolver $callReflectionResolver, VariableNaming $variableNaming)
|
||||
{
|
||||
$this->callReflectionResolver = $callReflectionResolver;
|
||||
$this->variableNaming = $variableNaming;
|
||||
}
|
||||
|
||||
public function getDefinition(): RectorDefinition
|
||||
@ -73,27 +73,32 @@ final class NonVariableToVariableOnFunctionCallRector extends AbstractRector
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$scope = $node->getAttribute(AttributeKey::SCOPE);
|
||||
if (! $scope instanceof MutatingScope) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$arguments = $this->getNonVariableArguments($node);
|
||||
if ($arguments === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$scopeNode = $node->getAttribute(AttributeKey::METHOD_NODE) ?? $node->getAttribute(
|
||||
AttributeKey::FUNCTION_NODE
|
||||
) ?? $node->getAttribute(AttributeKey::CLOSURE_NODE);
|
||||
/** @var Scope $currentScope */
|
||||
$currentScope = $scopeNode->getAttribute(AttributeKey::SCOPE);
|
||||
|
||||
foreach ($arguments as $key => $argument) {
|
||||
$replacements = $this->getReplacementsFor($argument, $scope);
|
||||
$replacements = $this->getReplacementsFor($argument, $currentScope, $scopeNode);
|
||||
|
||||
$current = $node->getAttribute(AttributeKey::CURRENT_STATEMENT);
|
||||
$this->addNodeBeforeNode($replacements->assign(), $current instanceof Return_ ? $current : $node);
|
||||
$node->args[$key]->value = $replacements->variable();
|
||||
$this->addNodeBeforeNode($replacements->getAssign(), $current instanceof Return_ ? $current : $node);
|
||||
$node->args[$key]->value = $replacements->getVariable();
|
||||
|
||||
$scope = $scope->assignExpression($replacements->variable(), $scope->getType($replacements->variable()));
|
||||
// add variable name to scope, so we prevent duplication of new variable of the same name
|
||||
$currentScope = $currentScope->assignExpression(
|
||||
$replacements->getVariable(),
|
||||
$currentScope->getType($replacements->getVariable())
|
||||
);
|
||||
}
|
||||
|
||||
$node->setAttribute(AttributeKey::SCOPE, $scope);
|
||||
$scopeNode->setAttribute(AttributeKey::SCOPE, $currentScope);
|
||||
|
||||
return $node;
|
||||
}
|
||||
@ -139,20 +144,24 @@ final class NonVariableToVariableOnFunctionCallRector extends AbstractRector
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
private function getReplacementsFor(Expr $expr, Scope $scope): VariableAssignPair
|
||||
private function getReplacementsFor(Expr $expr, MutatingScope $mutatingScope, Node $scopeNode): VariableAssignPair
|
||||
{
|
||||
if (
|
||||
(
|
||||
$expr instanceof Assign
|
||||
|| $expr instanceof AssignRef
|
||||
|| $expr instanceof AssignOp
|
||||
)
|
||||
&& $this->isVariableLikeNode($expr->var)
|
||||
) {
|
||||
/** @var Assign|AssignOp|AssignRef $expr */
|
||||
if ($this->isAssign($expr) && $this->isVariableLikeNode($expr->var)) {
|
||||
return new VariableAssignPair($expr->var, $expr);
|
||||
}
|
||||
|
||||
$variable = new Variable($this->getVariableNameFor($expr, $scope));
|
||||
$variableName = $this->variableNaming->resolveFromNodeWithScopeCountAndFallbackName(
|
||||
$expr,
|
||||
$mutatingScope,
|
||||
'tmp'
|
||||
);
|
||||
|
||||
$variable = new Variable($variableName);
|
||||
|
||||
// add a new scope with this variable
|
||||
$newVariableAwareScope = $mutatingScope->assignExpression($variable, new MixedType());
|
||||
$scopeNode->setAttribute(AttributeKey::SCOPE, $newVariableAwareScope);
|
||||
|
||||
return new VariableAssignPair($variable, new Assign($variable, $expr));
|
||||
}
|
||||
@ -165,16 +174,16 @@ final class NonVariableToVariableOnFunctionCallRector extends AbstractRector
|
||||
|| $node instanceof StaticPropertyFetch;
|
||||
}
|
||||
|
||||
private function getVariableNameFor(Expr $expr, Scope $scope): string
|
||||
private function isAssign(Expr $expr): bool
|
||||
{
|
||||
if ($expr instanceof New_ && $expr->class instanceof Name) {
|
||||
$name = $this->getShortName($expr->class);
|
||||
} elseif ($expr instanceof MethodCall || $expr instanceof StaticCall) {
|
||||
$name = $this->getName($expr->name);
|
||||
} else {
|
||||
$name = $this->getName($expr);
|
||||
if ($expr instanceof Assign) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return lcfirst($this->createCountedValueName($name ?? self::DEFAULT_VARIABLE_NAME, $scope));
|
||||
if ($expr instanceof AssignRef) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $expr instanceof AssignOp;
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ final class VariableAssignPair
|
||||
/**
|
||||
* @return Variable|ArrayDimFetch|PropertyFetch|StaticPropertyFetch
|
||||
*/
|
||||
public function variable(): Node
|
||||
public function getVariable(): Node
|
||||
{
|
||||
return $this->variable;
|
||||
}
|
||||
@ -46,7 +46,7 @@ final class VariableAssignPair
|
||||
/**
|
||||
* @return Assign|AssignOp|AssignRef
|
||||
*/
|
||||
public function assign(): Node
|
||||
public function getAssign(): Node
|
||||
{
|
||||
return $this->assign;
|
||||
}
|
||||
|
@ -22,8 +22,8 @@ function anonymousFunction()
|
||||
$bar = bar();
|
||||
$anonymousFunction($bar);
|
||||
$staticAnonymousFunction = static function (&$bar) {};
|
||||
$bar = bar();
|
||||
$staticAnonymousFunction($bar);
|
||||
$bar2 = bar();
|
||||
$staticAnonymousFunction($bar2);
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -37,15 +37,15 @@ function arrayCallable()
|
||||
$bar = bar();
|
||||
[ArrayCallable::class, 'someStaticMethod']($bar);
|
||||
$callable = [ArrayCallable::class, 'someStaticMethod'];
|
||||
$bar = bar();
|
||||
$callable($bar);
|
||||
$bar2 = bar();
|
||||
$callable($bar2);
|
||||
|
||||
$arrayCallable = new ArrayCallable();
|
||||
$bar = bar();
|
||||
[$arrayCallable, 'someMethod']($bar);
|
||||
$bar3 = bar();
|
||||
[$arrayCallable, 'someMethod']($bar3);
|
||||
$callable = [$arrayCallable, 'someMethod'];
|
||||
$bar = bar();
|
||||
$callable($bar);
|
||||
$bar4 = bar();
|
||||
$callable($bar4);
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -18,8 +18,8 @@ function binaryOp()
|
||||
{
|
||||
$tmp = 1 + 1;
|
||||
reset($tmp);
|
||||
$tmp = 2 + $var;
|
||||
reset($tmp);
|
||||
$tmp2 = 2 + $var;
|
||||
reset($tmp2);
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -32,15 +32,15 @@ function funcCalls()
|
||||
reset($bar);
|
||||
$baz = baz();
|
||||
byRef(bar(), $baz);
|
||||
$bar = bar();
|
||||
$baz = baz();
|
||||
allByRef($bar, $baz);
|
||||
$bar2 = bar();
|
||||
$baz2 = baz();
|
||||
allByRef($bar2, $baz2);
|
||||
$tmp = 1;
|
||||
$tmp2 = 2;
|
||||
allByRef($tmp, $tmp2);
|
||||
$bar = bar();
|
||||
$bar3 = bar();
|
||||
|
||||
return byRef(1, $bar);
|
||||
return byRef(1, $bar3);
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -57,8 +57,8 @@ function methodCalls()
|
||||
$aClass = new AClass();
|
||||
$baz = baz();
|
||||
$aClass->baz($baz);
|
||||
$bar = bar();
|
||||
$aClass->child()->bar($bar);
|
||||
$bar2 = bar();
|
||||
$aClass->child()->bar($bar2);
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -35,12 +35,12 @@ function stringyCalls()
|
||||
'reset'($bar);
|
||||
|
||||
$functionName = 'reset';
|
||||
$bar = bar();
|
||||
$functionName($bar);
|
||||
$bar2 = bar();
|
||||
$functionName($bar2);
|
||||
|
||||
$methodName = MyClass::class.'::staticMethod';
|
||||
$bar = bar();
|
||||
$methodName($bar);
|
||||
$bar3 = bar();
|
||||
$methodName($bar3);
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -15,7 +15,6 @@ use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use PhpParser\NodeVisitorAbstract;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use Rector\AnonymousClass\NodeAnalyzer\ClassNodeAnalyzer;
|
||||
use Rector\Core\Configuration\Option;
|
||||
use Rector\Core\Contract\Rector\PhpRectorInterface;
|
||||
@ -251,28 +250,6 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
|
||||
return $this->classNodeAnalyzer->isAnonymousClass($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;
|
||||
}
|
||||
|
||||
protected function mirrorComments(Node $newNode, Node $oldNode): void
|
||||
{
|
||||
$newNode->setAttribute(AttributeKey::PHP_DOC_INFO, $oldNode->getAttribute(AttributeKey::PHP_DOC_INFO));
|
||||
|
Loading…
x
Reference in New Issue
Block a user