diff --git a/src/Analyser/AnalyserResultFinalizer.php b/src/Analyser/AnalyserResultFinalizer.php index 14589f78c8..8bfaa6ee40 100644 --- a/src/Analyser/AnalyserResultFinalizer.php +++ b/src/Analyser/AnalyserResultFinalizer.php @@ -18,6 +18,7 @@ public function __construct( private RuleRegistry $ruleRegistry, private RuleErrorTransformer $ruleErrorTransformer, private ScopeFactory $scopeFactory, + private LocalIgnoresProcessor $localIgnoresProcessor, private bool $reportUnmatchedIgnoredErrors, ) { @@ -39,31 +40,54 @@ public function finalize(AnalyserResult $analyserResult, bool $onlyFiles): Analy $file = 'N/A'; $scope = $this->scopeFactory->create(ScopeContext::create($file)); - $errors = $analyserResult->getUnorderedErrors(); + $collectorErrors = []; foreach ($this->ruleRegistry->getRules($nodeType) as $rule) { try { $ruleErrors = $rule->processNode($node, $scope); } catch (AnalysedCodeException $e) { - $errors[] = (new Error($e->getMessage(), $file, $node->getStartLine(), $e, null, null, $e->getTip()))->withIdentifier('phpstan.internal'); + $collectorErrors[] = (new Error($e->getMessage(), $file, $node->getStartLine(), $e, null, null, $e->getTip()))->withIdentifier('phpstan.internal'); continue; } catch (IdentifierNotFound $e) { - $errors[] = (new Error(sprintf('Reflection error: %s not found.', $e->getIdentifier()->getName()), $file, $node->getStartLine(), $e, null, null, 'Learn more at https://phpstan.org/user-guide/discovering-symbols'))->withIdentifier('phpstan.reflection'); + $collectorErrors[] = (new Error(sprintf('Reflection error: %s not found.', $e->getIdentifier()->getName()), $file, $node->getStartLine(), $e, null, null, 'Learn more at https://phpstan.org/user-guide/discovering-symbols'))->withIdentifier('phpstan.reflection'); continue; } catch (UnableToCompileNode | CircularReference $e) { - $errors[] = (new Error(sprintf('Reflection error: %s', $e->getMessage()), $file, $node->getStartLine(), $e))->withIdentifier('phpstan.reflection'); + $collectorErrors[] = (new Error(sprintf('Reflection error: %s', $e->getMessage()), $file, $node->getStartLine(), $e))->withIdentifier('phpstan.reflection'); continue; } foreach ($ruleErrors as $ruleError) { - $errors[] = $this->ruleErrorTransformer->transform($ruleError, $scope, $nodeType, $node->getStartLine()); + $collectorErrors[] = $this->ruleErrorTransformer->transform($ruleError, $scope, $nodeType, $node->getStartLine()); } } + $errors = $analyserResult->getUnorderedErrors(); + $locallyIgnoredErrors = $analyserResult->getLocallyIgnoredErrors(); + $allLinesToIgnore = $analyserResult->getLinesToIgnore(); + $allUnmatchedLineIgnores = $analyserResult->getUnmatchedLineIgnores(); + foreach ($collectorErrors as $collectorError) { + $file = $collectorError->getFilePath(); + $linesToIgnore = $allLinesToIgnore[$file] ?? []; + $unmatchedLineIgnores = $allUnmatchedLineIgnores[$file] ?? []; + $localIgnoresProcessorResult = $this->localIgnoresProcessor->process( + [$collectorError], + $linesToIgnore, + $unmatchedLineIgnores, + ); + foreach ($localIgnoresProcessorResult->getFileErrors() as $error) { + $errors[] = $error; + } + foreach ($localIgnoresProcessorResult->getLocallyIgnoredErrors() as $locallyIgnoredError) { + $locallyIgnoredErrors[] = $locallyIgnoredError; + } + $allLinesToIgnore[$file] = $localIgnoresProcessorResult->getLinesToIgnore(); + $allUnmatchedLineIgnores[$file] = $localIgnoresProcessorResult->getUnmatchedLineIgnores(); + } + return $this->addUnmatchedIgnoredErrors(new AnalyserResult( $errors, - $analyserResult->getLocallyIgnoredErrors(), - $analyserResult->getLinesToIgnore(), - $analyserResult->getUnmatchedLineIgnores(), + $locallyIgnoredErrors, + $allLinesToIgnore, + $allUnmatchedLineIgnores, $analyserResult->getInternalErrors(), $analyserResult->getCollectedData(), $analyserResult->getDependencies(), diff --git a/src/Testing/RuleTestCase.php b/src/Testing/RuleTestCase.php index 0bcb252576..0a6aa2cc26 100644 --- a/src/Testing/RuleTestCase.php +++ b/src/Testing/RuleTestCase.php @@ -183,6 +183,7 @@ public function gatherAnalyserErrors(array $files): array ]), new RuleErrorTransformer(), $this->createScopeFactory($this->createReflectionProvider(), $this->getTypeSpecifier()), + new LocalIgnoresProcessor(), true, ); diff --git a/tests/PHPStan/Analyser/AnalyserTest.php b/tests/PHPStan/Analyser/AnalyserTest.php index 07172be85f..29fb96bec4 100644 --- a/tests/PHPStan/Analyser/AnalyserTest.php +++ b/tests/PHPStan/Analyser/AnalyserTest.php @@ -655,6 +655,7 @@ private function runAnalyser( $this->createReflectionProvider(), self::getContainer()->getService('typeSpecifier'), ), + new LocalIgnoresProcessor(), $reportUnmatchedIgnoredErrors, ); $analyserResult = $finalizer->finalize($analyserResult, $onlyFiles); diff --git a/tests/PHPStan/Rules/DeadCode/data/call-to-method-without-impure-points.php b/tests/PHPStan/Rules/DeadCode/data/call-to-method-without-impure-points.php index bff8f4f351..e9f82b1476 100644 --- a/tests/PHPStan/Rules/DeadCode/data/call-to-method-without-impure-points.php +++ b/tests/PHPStan/Rules/DeadCode/data/call-to-method-without-impure-points.php @@ -133,3 +133,18 @@ private function doBar(): int } } + +class TestIgnoring +{ + + public function doFoo(): void + { + $this->doBar(); // @phpstan-ignore method.resultUnused + } + + private function doBar(): int + { + return 1; + } + +}