diff --git a/src/Rules/Functions/DuplicateFunctionDeclarationRule.php b/src/Rules/Functions/DuplicateFunctionDeclarationRule.php index f9dfa97e90..25006e0b95 100644 --- a/src/Rules/Functions/DuplicateFunctionDeclarationRule.php +++ b/src/Rules/Functions/DuplicateFunctionDeclarationRule.php @@ -23,6 +23,9 @@ final class DuplicateFunctionDeclarationRule implements Rule { + /** @var array>|null */ + private ?array $functionMap = null; + public function __construct(private Reflector $reflector, private RelativePathHelper $relativePathHelper) { } @@ -35,25 +38,32 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { $thisFunction = $node->getFunctionReflection(); - $allFunctions = $this->reflector->reflectAllFunctions(); - $filteredFunctions = []; - foreach ($allFunctions as $reflectionFunction) { - if ($reflectionFunction->getName() !== $thisFunction->getName()) { - continue; - } + $functionName = $thisFunction->getName(); - $filteredFunctions[] = $reflectionFunction; + // this rule runs at the very end of the analysis, + // so all function already have been discovered at this point. + if ($this->functionMap === null) { + $this->functionMap = []; + + $allFunctions = $this->reflector->reflectAllFunctions(); + foreach ($allFunctions as $reflectionFunction) { + $reflectionFunctionName = $reflectionFunction->getName(); + if (!isset($this->functionMap[$reflectionFunctionName])) { + $this->functionMap[$reflectionFunctionName] = []; + } + $this->functionMap[$reflectionFunctionName][] = $reflectionFunction; + } } - if (count($filteredFunctions) < 2) { + if (!isset($this->functionMap[$functionName]) || count($this->functionMap[$functionName]) < 2) { return []; } return [ RuleErrorBuilder::message(sprintf( "Function %s declared multiple times:\n%s", - $thisFunction->getName(), - implode("\n", array_map(fn (ReflectionFunction $function) => sprintf('- %s:%d', $this->relativePathHelper->getRelativePath($function->getFileName() ?? 'unknown'), $function->getStartLine()), $filteredFunctions)), + $functionName, + implode("\n", array_map(fn (ReflectionFunction $function) => sprintf('- %s:%d', $this->relativePathHelper->getRelativePath($function->getFileName() ?? 'unknown'), $function->getStartLine()), $this->functionMap[$functionName])), ))->identifier('function.duplicate')->build(), ]; }