classManipulator = $classManipulator; $this->reflectionResolver = $reflectionResolver; $this->reflectionProvider = $reflectionProvider; } public function getRuleDefinition() : RuleDefinition { return new RuleDefinition('Turns method names to new ones.', [new ConfiguredCodeSample(<<<'CODE_SAMPLE' $someObject = new SomeExampleClass; $someObject->oldMethod(); CODE_SAMPLE , <<<'CODE_SAMPLE' $someObject = new SomeExampleClass; $someObject->newMethod(); CODE_SAMPLE , [new MethodCallRename('SomeExampleClass', 'oldMethod', 'newMethod')])]); } /** * @return array> */ public function getNodeTypes() : array { return [MethodCall::class, StaticCall::class, ClassMethod::class]; } /** * @param MethodCall|StaticCall|ClassMethod $node */ public function refactorWithScope(Node $node, Scope $scope) : ?Node { $classReflection = $scope->getClassReflection(); foreach ($this->methodCallRenames as $methodCallRename) { if (!$this->isName($node->name, $methodCallRename->getOldMethod())) { continue; } if ($this->shouldKeepForParentInterface($methodCallRename, $node, $classReflection)) { continue; } if (!$this->nodeTypeResolver->isMethodStaticCallOrClassMethodObjectType($node, $methodCallRename->getObjectType())) { continue; } if ($this->shouldSkipClassMethod($node, $methodCallRename)) { continue; } $node->name = new Identifier($methodCallRename->getNewMethod()); if ($methodCallRename instanceof MethodCallRenameWithArrayKey && !$node instanceof ClassMethod) { return new ArrayDimFetch($node, BuilderHelpers::normalizeValue($methodCallRename->getArrayKey())); } return $node; } return null; } /** * @param mixed[] $configuration */ public function configure(array $configuration) : void { Assert::allIsAOf($configuration, MethodCallRenameInterface::class); $this->methodCallRenames = $configuration; } /** * @param \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall|\PhpParser\Node\Stmt\ClassMethod $node */ private function shouldSkipClassMethod($node, MethodCallRenameInterface $methodCallRename) : bool { if (!$node instanceof ClassMethod) { $classReflection = $this->reflectionResolver->resolveClassReflectionSourceObject($node); if (!$classReflection instanceof ClassReflection) { return \false; } $targetClass = $methodCallRename->getClass(); if (!$this->reflectionProvider->hasClass($targetClass)) { return \false; } $targetClassReflection = $this->reflectionProvider->getClass($targetClass); if ($classReflection->getName() === $targetClassReflection->getName()) { return \false; } // different with configured ClassLike source? it is a child, which may has old and new exists if (!$classReflection->hasMethod($methodCallRename->getOldMethod())) { return \false; } return $classReflection->hasMethod($methodCallRename->getNewMethod()); } return $this->shouldSkipForAlreadyExistingClassMethod($node, $methodCallRename); } private function shouldSkipForAlreadyExistingClassMethod(ClassMethod $classMethod, MethodCallRenameInterface $methodCallRename) : bool { $classLike = $this->betterNodeFinder->findParentType($classMethod, ClassLike::class); if (!$classLike instanceof ClassLike) { return \false; } return (bool) $classLike->getMethod($methodCallRename->getNewMethod()); } /** * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Expr\StaticCall|\PhpParser\Node\Expr\MethodCall $node */ private function shouldKeepForParentInterface(MethodCallRenameInterface $methodCallRename, $node, ?ClassReflection $classReflection) : bool { if (!$node instanceof ClassMethod) { return \false; } if (!$classReflection instanceof ClassReflection) { return \false; } // interface can change current method, as parent contract is still valid if (!$classReflection->isInterface()) { return \false; } return $this->classManipulator->hasParentMethodOrInterface($methodCallRename->getObjectType(), $methodCallRename->getOldMethod(), $methodCallRename->getNewMethod()); } }