loadArgumentReplacerRecipes($argumentChangesByMethodAndType); $this->methodCallAnalyzer = $methodCallAnalyzer; $this->classMethodAnalyzer = $classMethodAnalyzer; $this->staticMethodCallAnalyzer = $staticMethodCallAnalyzer; $this->constExprEvaluator = $constExprEvaluator; } public function isCandidate(Node $node): bool { $this->activeArgumentReplacerRecipes = $this->matchArgumentChanges($node); return (bool) $this->activeArgumentReplacerRecipes; } /** * @param MethodCall|StaticCall|ClassMethod $node */ public function refactor(Node $node): Node { $argumentsOrParameters = $this->getNodeArgumentsOrParameters($node); $argumentsOrParameters = $this->processArgumentNodes($argumentsOrParameters); $this->setNodeArgumentsOrParameters($node, $argumentsOrParameters); return $node; } /** * @return ArgumentReplacerRecipe[] */ private function matchArgumentChanges(Node $node): array { if (! $node instanceof ClassMethod && ! $node instanceof MethodCall && ! $node instanceof StaticCall) { return []; } $argumentReplacerRecipes = []; foreach ($this->argumentReplacerRecipes as $argumentReplacerRecipe) { if ($this->isNodeToRecipeMatch($node, $argumentReplacerRecipe)) { $argumentReplacerRecipes[] = $argumentReplacerRecipe; } } return $argumentReplacerRecipes; } /** * @return Arg[]|Param[] */ private function getNodeArgumentsOrParameters(Node $node): array { if ($node instanceof MethodCall || $node instanceof StaticCall) { return $node->args; } if ($node instanceof ClassMethod) { return $node->params; } } /** * @param MethodCall|StaticCall|ClassMethod $node * @param mixed[] $argumentsOrParameters */ private function setNodeArgumentsOrParameters(Node $node, array $argumentsOrParameters): void { if ($node instanceof MethodCall || $node instanceof StaticCall) { $node->args = $argumentsOrParameters; } if ($node instanceof ClassMethod) { $node->params = $argumentsOrParameters; } } private function isNodeToRecipeMatch(Node $node, ArgumentReplacerRecipe $argumentReplacerRecipe): bool { $type = $argumentReplacerRecipe->getClass(); $method = $argumentReplacerRecipe->getMethod(); if ($this->methodCallAnalyzer->isTypeAndMethods($node, $type, [$method])) { return true; } if ($this->staticMethodCallAnalyzer->isTypeAndMethods($node, $type, [$method])) { return true; } return $this->classMethodAnalyzer->isTypeAndMethods($node, $type, [$method]); } /** * @param mixed[] $configurationArrays */ private function loadArgumentReplacerRecipes(array $configurationArrays): void { foreach ($configurationArrays as $configurationArray) { $this->argumentReplacerRecipes[] = ArgumentReplacerRecipe::createFromArray($configurationArray); } } /** * @param mixed[] $argumentNodes * @return mixed[] */ private function processArgumentNodes(array $argumentNodes): array { foreach ($this->activeArgumentReplacerRecipes as $argumentReplacerRecipe) { $type = $argumentReplacerRecipe->getType(); $position = $argumentReplacerRecipe->getPosition(); if ($type === ArgumentReplacerRecipe::TYPE_REMOVED) { unset($argumentNodes[$position]); } elseif ($type === ArgumentReplacerRecipe::TYPE_CHANGED) { $argumentNodes[$position] = BuilderHelpers::normalizeValue( $argumentReplacerRecipe->getDefaultValue() ); } elseif ($type === ArgumentReplacerRecipe::TYPE_REPLACED_DEFAULT_VALUE) { $argumentNodes[$position] = $this->processReplacedDefaultValue( $argumentNodes[$position], $argumentReplacerRecipe ); } } return $argumentNodes; } private function processReplacedDefaultValue(Arg $argNode, ArgumentReplacerRecipe $argumentReplacerRecipe): Arg { $resolvedValue = $this->constExprEvaluator->evaluateDirectly($argNode->value); $replaceMap = $argumentReplacerRecipe->getReplaceMap(); foreach ($replaceMap as $oldValue => $newValue) { if ($resolvedValue === $oldValue) { return new Arg(BuilderHelpers::normalizeValue($newValue)); } } return $argNode; } }