2020-07-13 21:13:40 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
namespace Rector\Naming\Rector\Assign;
|
|
|
|
|
|
|
|
use PhpParser\Node;
|
2020-07-19 13:39:13 +00:00
|
|
|
use PhpParser\Node\Expr;
|
2020-07-13 21:13:40 +00:00
|
|
|
use PhpParser\Node\Expr\Assign;
|
|
|
|
use PhpParser\Node\Expr\Closure;
|
2020-07-19 12:30:07 +00:00
|
|
|
use PhpParser\Node\Expr\FuncCall;
|
|
|
|
use PhpParser\Node\Expr\MethodCall;
|
|
|
|
use PhpParser\Node\Expr\StaticCall;
|
2020-07-13 21:13:40 +00:00
|
|
|
use PhpParser\Node\Expr\Variable;
|
|
|
|
use PhpParser\Node\FunctionLike;
|
2020-07-19 10:16:20 +00:00
|
|
|
use PhpParser\Node\Stmt\ClassMethod;
|
|
|
|
use PhpParser\Node\Stmt\Function_;
|
2020-07-19 09:53:35 +00:00
|
|
|
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
|
2020-07-19 16:02:11 +00:00
|
|
|
use PHPStan\Type\TypeWithClassName;
|
2020-07-19 09:53:35 +00:00
|
|
|
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
2020-07-13 21:13:40 +00:00
|
|
|
use Rector\Core\Rector\AbstractRector;
|
|
|
|
use Rector\Core\RectorDefinition\CodeSample;
|
|
|
|
use Rector\Core\RectorDefinition\RectorDefinition;
|
2020-07-19 16:02:11 +00:00
|
|
|
use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer;
|
2020-07-19 10:25:24 +00:00
|
|
|
use Rector\Naming\Guard\BreakingVariableRenameGuard;
|
2020-07-19 16:11:59 +00:00
|
|
|
use Rector\Naming\Matcher\VariableAndCallAssignMatcher;
|
2020-07-13 21:13:40 +00:00
|
|
|
use Rector\Naming\Naming\ExpectedNameResolver;
|
2020-07-19 17:24:46 +00:00
|
|
|
use Rector\Naming\NamingConvention\NamingConventionAnalyzer;
|
2020-07-19 10:16:20 +00:00
|
|
|
use Rector\Naming\VariableRenamer;
|
2020-07-19 09:53:35 +00:00
|
|
|
use Rector\NodeTypeResolver\Node\AttributeKey;
|
2020-07-13 21:13:40 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @see \Rector\Naming\Tests\Rector\Assign\RenameVariableToMatchGetMethodNameRector\RenameVariableToMatchGetMethodNameRectorTest
|
|
|
|
*/
|
|
|
|
final class RenameVariableToMatchGetMethodNameRector extends AbstractRector
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @var ExpectedNameResolver
|
|
|
|
*/
|
|
|
|
private $expectedNameResolver;
|
|
|
|
|
2020-07-19 10:16:20 +00:00
|
|
|
/**
|
|
|
|
* @var VariableRenamer
|
|
|
|
*/
|
|
|
|
private $variableRenamer;
|
|
|
|
|
2020-07-19 10:25:24 +00:00
|
|
|
/**
|
|
|
|
* @var BreakingVariableRenameGuard
|
|
|
|
*/
|
|
|
|
private $breakingVariableRenameGuard;
|
|
|
|
|
2020-07-19 16:02:11 +00:00
|
|
|
/**
|
|
|
|
* @var FamilyRelationsAnalyzer
|
|
|
|
*/
|
|
|
|
private $familyRelationsAnalyzer;
|
|
|
|
|
2020-07-19 16:11:59 +00:00
|
|
|
/**
|
|
|
|
* @var VariableAndCallAssignMatcher
|
|
|
|
*/
|
|
|
|
private $variableAndCallAssignMatcher;
|
|
|
|
|
2020-07-19 17:24:46 +00:00
|
|
|
/**
|
|
|
|
* @var NamingConventionAnalyzer
|
|
|
|
*/
|
|
|
|
private $namingConventionAnalyzer;
|
|
|
|
|
2020-07-19 10:25:24 +00:00
|
|
|
public function __construct(
|
|
|
|
ExpectedNameResolver $expectedNameResolver,
|
|
|
|
VariableRenamer $variableRenamer,
|
2020-07-19 16:02:11 +00:00
|
|
|
BreakingVariableRenameGuard $breakingVariableRenameGuard,
|
2020-07-19 16:11:59 +00:00
|
|
|
FamilyRelationsAnalyzer $familyRelationsAnalyzer,
|
2020-07-19 17:24:46 +00:00
|
|
|
VariableAndCallAssignMatcher $variableAndCallAssignMatcher,
|
|
|
|
NamingConventionAnalyzer $namingConventionAnalyzer
|
2020-07-19 10:25:24 +00:00
|
|
|
) {
|
2020-07-13 21:13:40 +00:00
|
|
|
$this->expectedNameResolver = $expectedNameResolver;
|
2020-07-19 10:16:20 +00:00
|
|
|
$this->variableRenamer = $variableRenamer;
|
2020-07-19 10:25:24 +00:00
|
|
|
$this->breakingVariableRenameGuard = $breakingVariableRenameGuard;
|
2020-07-19 16:02:11 +00:00
|
|
|
$this->familyRelationsAnalyzer = $familyRelationsAnalyzer;
|
2020-07-19 16:11:59 +00:00
|
|
|
$this->variableAndCallAssignMatcher = $variableAndCallAssignMatcher;
|
2020-07-19 17:24:46 +00:00
|
|
|
$this->namingConventionAnalyzer = $namingConventionAnalyzer;
|
2020-07-13 21:13:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function getDefinition(): RectorDefinition
|
|
|
|
{
|
|
|
|
return new RectorDefinition('Rename variable to match get method name', [
|
|
|
|
new CodeSample(
|
|
|
|
<<<'PHP'
|
2020-07-19 11:52:01 +00:00
|
|
|
class SomeClass
|
|
|
|
{
|
2020-07-13 21:13:40 +00:00
|
|
|
public function run()
|
|
|
|
{
|
|
|
|
$a = $this->getRunner();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PHP
|
|
|
|
,
|
|
|
|
<<<'PHP'
|
2020-07-19 11:52:01 +00:00
|
|
|
class SomeClass
|
|
|
|
{
|
2020-07-13 21:13:40 +00:00
|
|
|
public function run()
|
|
|
|
{
|
|
|
|
$runner = $this->getRunner();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PHP
|
|
|
|
),
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string[]
|
|
|
|
*/
|
|
|
|
public function getNodeTypes(): array
|
|
|
|
{
|
|
|
|
return [Assign::class];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Assign $node
|
|
|
|
*/
|
|
|
|
public function refactor(Node $node): ?Node
|
|
|
|
{
|
2020-07-19 16:11:59 +00:00
|
|
|
$variableAndCallAssign = $this->variableAndCallAssignMatcher->match($node);
|
|
|
|
if ($variableAndCallAssign === null) {
|
2020-07-13 21:13:40 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2020-07-19 17:24:46 +00:00
|
|
|
$expectedName = $this->expectedNameResolver->resolveForGetCallExpr($variableAndCallAssign->getCall());
|
|
|
|
if ($expectedName === null || $this->isName($node, $expectedName)) {
|
2020-07-13 21:13:40 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2020-07-19 17:24:46 +00:00
|
|
|
if ($this->namingConventionAnalyzer->isCallMatchingVariableName(
|
2020-07-19 16:11:59 +00:00
|
|
|
$variableAndCallAssign->getCall(),
|
|
|
|
$variableAndCallAssign->getVariableName(),
|
2020-07-19 17:24:46 +00:00
|
|
|
$expectedName
|
2020-07-19 16:11:59 +00:00
|
|
|
)) {
|
2020-07-19 12:30:07 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2020-07-19 17:24:46 +00:00
|
|
|
if ($this->isClassTypeWithChildren($variableAndCallAssign->getCall())) {
|
2020-07-19 10:25:24 +00:00
|
|
|
return null;
|
|
|
|
}
|
2020-07-13 21:13:40 +00:00
|
|
|
|
2020-07-19 10:25:24 +00:00
|
|
|
if ($this->breakingVariableRenameGuard->shouldSkipVariable(
|
2020-07-19 16:11:59 +00:00
|
|
|
$variableAndCallAssign->getVariableName(),
|
2020-07-19 17:24:46 +00:00
|
|
|
$expectedName,
|
2020-07-19 16:11:59 +00:00
|
|
|
$variableAndCallAssign->getFunctionLike(),
|
|
|
|
$variableAndCallAssign->getVariable()
|
2020-07-19 10:25:24 +00:00
|
|
|
)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2020-07-19 17:24:46 +00:00
|
|
|
return $this->renameVariable($node, $expectedName, $variableAndCallAssign->getFunctionLike());
|
2020-07-13 21:13:40 +00:00
|
|
|
}
|
|
|
|
|
2020-07-19 16:11:59 +00:00
|
|
|
/**
|
|
|
|
* @param ClassMethod|Function_|Closure $functionLike
|
|
|
|
*/
|
|
|
|
private function renameVariable(Assign $assign, string $newName, FunctionLike $functionLike): Assign
|
2020-07-13 21:13:40 +00:00
|
|
|
{
|
|
|
|
/** @var Variable $variableNode */
|
2020-07-19 09:53:35 +00:00
|
|
|
$variableNode = $assign->var;
|
2020-07-13 21:13:40 +00:00
|
|
|
|
|
|
|
/** @var string $originalName */
|
|
|
|
$originalName = $variableNode->name;
|
|
|
|
|
2020-07-19 10:16:20 +00:00
|
|
|
$this->renameInDocComment($assign, $originalName, $newName);
|
2020-07-13 21:13:40 +00:00
|
|
|
|
2020-07-19 11:22:55 +00:00
|
|
|
$this->variableRenamer->renameVariableInFunctionLike($functionLike, $assign, $originalName, $newName);
|
2020-07-19 10:25:24 +00:00
|
|
|
|
|
|
|
return $assign;
|
2020-07-13 21:13:40 +00:00
|
|
|
}
|
|
|
|
|
2020-07-19 11:52:01 +00:00
|
|
|
/**
|
|
|
|
* @note variable rename is correct, but node printer doesn't see it as a changed text for some reason
|
|
|
|
*/
|
2020-07-19 10:16:20 +00:00
|
|
|
private function renameInDocComment(Node $node, string $originalName, string $newName): void
|
2020-07-13 21:13:40 +00:00
|
|
|
{
|
2020-07-19 09:53:35 +00:00
|
|
|
/** @var PhpDocInfo|null $phpDocInfo */
|
2020-07-19 10:16:20 +00:00
|
|
|
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
|
2020-07-19 09:53:35 +00:00
|
|
|
if ($phpDocInfo === null) {
|
2020-07-19 09:41:35 +00:00
|
|
|
return;
|
2020-07-13 21:13:40 +00:00
|
|
|
}
|
2020-07-19 09:41:35 +00:00
|
|
|
|
2020-07-19 09:53:35 +00:00
|
|
|
$varTagValueNode = $phpDocInfo->getByType(VarTagValueNode::class);
|
|
|
|
if ($varTagValueNode === null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($varTagValueNode->variableName !== '$' . $originalName) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$varTagValueNode->variableName = '$' . $newName;
|
2020-07-13 21:13:40 +00:00
|
|
|
}
|
2020-07-19 13:39:13 +00:00
|
|
|
|
|
|
|
/**
|
2020-07-19 17:24:46 +00:00
|
|
|
* @param StaticCall|MethodCall|FuncCall $expr
|
2020-07-19 13:39:13 +00:00
|
|
|
*/
|
2020-07-19 17:24:46 +00:00
|
|
|
private function isClassTypeWithChildren(Expr $expr): bool
|
2020-07-19 13:39:13 +00:00
|
|
|
{
|
2020-07-19 17:24:46 +00:00
|
|
|
$callStaticType = $this->getStaticType($expr);
|
|
|
|
if (! $callStaticType instanceof TypeWithClassName) {
|
|
|
|
return false;
|
2020-07-19 13:39:13 +00:00
|
|
|
}
|
|
|
|
|
2020-07-19 17:24:46 +00:00
|
|
|
return $this->familyRelationsAnalyzer->isParentClass($callStaticType->getClassName());
|
2020-07-19 13:39:13 +00:00
|
|
|
}
|
2020-07-13 21:13:40 +00:00
|
|
|
}
|