breakingVariableRenameGuard = $breakingVariableRenameGuard; $this->expectedNameResolver = $expectedNameResolver; $this->namingConventionAnalyzer = $namingConventionAnalyzer; $this->varTagValueNodeRenamer = $varTagValueNodeRenamer; $this->variableAndCallAssignMatcher = $variableAndCallAssignMatcher; $this->variableRenamer = $variableRenamer; $this->docBlockUpdater = $docBlockUpdater; $this->phpDocInfoFactory = $phpDocInfoFactory; } public function getRuleDefinition() : RuleDefinition { return new RuleDefinition('Rename variable to match method return type', [new CodeSample(<<<'CODE_SAMPLE' class SomeClass { public function run() { $a = $this->getRunner(); } public function getRunner(): Runner { return new Runner(); } } CODE_SAMPLE , <<<'CODE_SAMPLE' class SomeClass { public function run() { $runner = $this->getRunner(); } public function getRunner(): Runner { return new Runner(); } } CODE_SAMPLE )]); } /** * @return array> */ public function getNodeTypes() : array { return [ClassMethod::class, Closure::class, Function_::class]; } /** * @param ClassMethod|Closure|Function_ $node */ public function refactor(Node $node) : ?Node { if ($node->stmts === null) { return null; } foreach ($node->stmts as $stmt) { if (!$stmt instanceof Expression) { continue; } if (!$stmt->expr instanceof Assign) { continue; } $assign = $stmt->expr; $variableAndCallAssign = $this->variableAndCallAssignMatcher->match($assign, $node); if (!$variableAndCallAssign instanceof VariableAndCallAssign) { return null; } $call = $variableAndCallAssign->getCall(); $expectedName = $this->expectedNameResolver->resolveForCall($call); if ($expectedName === null) { continue; } if ($this->isName($assign->var, $expectedName)) { continue; } if ($this->shouldSkip($variableAndCallAssign, $expectedName)) { continue; } $this->renameVariable($variableAndCallAssign, $expectedName, $stmt); return $node; } return null; } private function shouldSkip(VariableAndCallAssign $variableAndCallAssign, string $expectedName) : bool { if (Strings::match($expectedName, self::VALID_VARIABLE_NAME_REGEX) === null) { return \true; } if ($this->namingConventionAnalyzer->isCallMatchingVariableName($variableAndCallAssign->getCall(), $variableAndCallAssign->getVariableName(), $expectedName)) { return \true; } $isUnionName = Strings::match($variableAndCallAssign->getVariableName(), self::OR_BETWEEN_WORDS_REGEX); if ($isUnionName !== null) { return \true; } return $this->breakingVariableRenameGuard->shouldSkipVariable($variableAndCallAssign->getVariableName(), $expectedName, $variableAndCallAssign->getFunctionLike(), $variableAndCallAssign->getVariable()); } private function renameVariable(VariableAndCallAssign $variableAndCallAssign, string $expectedName, Expression $expression) : void { $this->variableRenamer->renameVariableInFunctionLike($variableAndCallAssign->getFunctionLike(), $variableAndCallAssign->getVariableName(), $expectedName, $variableAndCallAssign->getAssign()); $assignPhpDocInfo = $this->phpDocInfoFactory->createFromNode($expression); if (!$assignPhpDocInfo instanceof PhpDocInfo) { return; } $this->varTagValueNodeRenamer->renameAssignVarTagVariableName($assignPhpDocInfo, $variableAndCallAssign->getVariableName(), $expectedName); $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($expression); } }