Skip to content

Commit

Permalink
Introduce LocalIgnoresProcessor
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Apr 20, 2024
1 parent 38e2c96 commit d026655
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 63 deletions.
3 changes: 3 additions & 0 deletions conf/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,9 @@ services:
parser: @defaultAnalysisParser
reportUnmatchedIgnoredErrors: %reportUnmatchedIgnoredErrors%

-
class: PHPStan\Analyser\LocalIgnoresProcessor

-
class: PHPStan\Analyser\RuleErrorTransformer

Expand Down
76 changes: 13 additions & 63 deletions src/Analyser/FileAnalyser.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@
use PHPStan\Parser\Parser;
use PHPStan\Parser\ParserErrorsException;
use PHPStan\Rules\Registry as RuleRegistry;
use function array_key_exists;
use function array_keys;
use function array_merge;
use function array_unique;
use function array_values;
use function count;
use function error_reporting;
use function get_class;
use function is_array;
use function is_dir;
use function is_file;
use function restore_error_handler;
Expand All @@ -43,6 +41,7 @@ public function __construct(
private Parser $parser,
private DependencyResolver $dependencyResolver,
private RuleErrorTransformer $ruleErrorTransformer,
private LocalIgnoresProcessor $localIgnoresProcessor,
private bool $reportUnmatchedIgnoredErrors,
)
{
Expand Down Expand Up @@ -176,69 +175,20 @@ public function analyseFile(
$scope,
$nodeCallback,
);
foreach ($temporaryFileErrors as $tmpFileError) {
$line = $tmpFileError->getLine();
if (
$line !== null
&& $tmpFileError->canBeIgnored()
&& array_key_exists($tmpFileError->getFile(), $linesToIgnore)
&& array_key_exists($line, $linesToIgnore[$tmpFileError->getFile()])
) {
$identifiers = $linesToIgnore[$tmpFileError->getFile()][$line];
if ($identifiers === null) {
$locallyIgnoredErrors[] = $tmpFileError;
unset($unmatchedLineIgnores[$tmpFileError->getFile()][$line]);
continue;
}

if ($tmpFileError->getIdentifier() === null) {
$fileErrors[] = $tmpFileError;
continue;
}

foreach ($identifiers as $i => $ignoredIdentifier) {
if ($ignoredIdentifier !== $tmpFileError->getIdentifier()) {
continue;
}

unset($identifiers[$i]);

if (count($identifiers) > 0) {
$linesToIgnore[$tmpFileError->getFile()][$line] = array_values($identifiers);
} else {
unset($linesToIgnore[$tmpFileError->getFile()][$line]);
}

if (
array_key_exists($tmpFileError->getFile(), $unmatchedLineIgnores)
&& array_key_exists($line, $unmatchedLineIgnores[$tmpFileError->getFile()])
) {
$unmatchedIgnoredIdentifiers = $unmatchedLineIgnores[$tmpFileError->getFile()][$line];
if (is_array($unmatchedIgnoredIdentifiers)) {
foreach ($unmatchedIgnoredIdentifiers as $j => $unmatchedIgnoredIdentifier) {
if ($ignoredIdentifier !== $unmatchedIgnoredIdentifier) {
continue;
}

unset($unmatchedIgnoredIdentifiers[$j]);

if (count($unmatchedIgnoredIdentifiers) > 0) {
$unmatchedLineIgnores[$tmpFileError->getFile()][$line] = array_values($unmatchedIgnoredIdentifiers);
} else {
unset($unmatchedLineIgnores[$tmpFileError->getFile()][$line]);
}
break;
}
}
}

$locallyIgnoredErrors[] = $tmpFileError;
continue 2;
}
}

$fileErrors[] = $tmpFileError;
$localIgnoresProcessorResult = $this->localIgnoresProcessor->process(
$temporaryFileErrors,
$linesToIgnore,
$unmatchedLineIgnores,
);
foreach ($localIgnoresProcessorResult->getFileErrors() as $fileError) {
$fileErrors[] = $fileError;
}
foreach ($localIgnoresProcessorResult->getLocallyIgnoredErrors() as $locallyIgnoredError) {
$locallyIgnoredErrors[] = $locallyIgnoredError;
}
$linesToIgnore = $localIgnoresProcessorResult->getLinesToIgnore();
$unmatchedLineIgnores = $localIgnoresProcessorResult->getUnmatchedLineIgnores();

if ($this->reportUnmatchedIgnoredErrors) {
foreach ($unmatchedLineIgnores as $ignoredFile => $lines) {
Expand Down
101 changes: 101 additions & 0 deletions src/Analyser/LocalIgnoresProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php declare(strict_types = 1);

namespace PHPStan\Analyser;

use function array_key_exists;
use function array_values;
use function count;
use function is_array;

/**
* @phpstan-import-type LinesToIgnore from FileAnalyserResult
*/
class LocalIgnoresProcessor
{

/**
* @param list<Error> $temporaryFileErrors
* @param LinesToIgnore $linesToIgnore
* @param LinesToIgnore $unmatchedLineIgnores
*/
public function process(
array $temporaryFileErrors,
array $linesToIgnore,
array $unmatchedLineIgnores,
): LocalIgnoresProcessorResult
{
$fileErrors = [];
$locallyIgnoredErrors = [];
foreach ($temporaryFileErrors as $tmpFileError) {
$line = $tmpFileError->getLine();
if (
$line !== null
&& $tmpFileError->canBeIgnored()
&& array_key_exists($tmpFileError->getFile(), $linesToIgnore)
&& array_key_exists($line, $linesToIgnore[$tmpFileError->getFile()])
) {
$identifiers = $linesToIgnore[$tmpFileError->getFile()][$line];
if ($identifiers === null) {
$locallyIgnoredErrors[] = $tmpFileError;
unset($unmatchedLineIgnores[$tmpFileError->getFile()][$line]);
continue;
}

if ($tmpFileError->getIdentifier() === null) {
$fileErrors[] = $tmpFileError;
continue;
}

foreach ($identifiers as $i => $ignoredIdentifier) {
if ($ignoredIdentifier !== $tmpFileError->getIdentifier()) {
continue;
}

unset($identifiers[$i]);

if (count($identifiers) > 0) {
$linesToIgnore[$tmpFileError->getFile()][$line] = array_values($identifiers);
} else {
unset($linesToIgnore[$tmpFileError->getFile()][$line]);
}

if (
array_key_exists($tmpFileError->getFile(), $unmatchedLineIgnores)
&& array_key_exists($line, $unmatchedLineIgnores[$tmpFileError->getFile()])
) {
$unmatchedIgnoredIdentifiers = $unmatchedLineIgnores[$tmpFileError->getFile()][$line];
if (is_array($unmatchedIgnoredIdentifiers)) {
foreach ($unmatchedIgnoredIdentifiers as $j => $unmatchedIgnoredIdentifier) {
if ($ignoredIdentifier !== $unmatchedIgnoredIdentifier) {
continue;
}

unset($unmatchedIgnoredIdentifiers[$j]);

if (count($unmatchedIgnoredIdentifiers) > 0) {
$unmatchedLineIgnores[$tmpFileError->getFile()][$line] = array_values($unmatchedIgnoredIdentifiers);
} else {
unset($unmatchedLineIgnores[$tmpFileError->getFile()][$line]);
}
break;
}
}
}

$locallyIgnoredErrors[] = $tmpFileError;
continue 2;
}
}

$fileErrors[] = $tmpFileError;
}

return new LocalIgnoresProcessorResult(
$fileErrors,
$locallyIgnoredErrors,
$linesToIgnore,
$unmatchedLineIgnores,
);
}

}
58 changes: 58 additions & 0 deletions src/Analyser/LocalIgnoresProcessorResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php declare(strict_types = 1);

namespace PHPStan\Analyser;

/**
* @phpstan-import-type LinesToIgnore from FileAnalyserResult
*/
class LocalIgnoresProcessorResult
{

/**
* @param list<Error> $fileErrors
* @param list<Error> $locallyIgnoredErrors
* @param LinesToIgnore $linesToIgnore
* @param LinesToIgnore $unmatchedLineIgnores
*/
public function __construct(
private array $fileErrors,
private array $locallyIgnoredErrors,
private array $linesToIgnore,
private array $unmatchedLineIgnores,
)
{
}

/**
* @return list<Error>
*/
public function getFileErrors(): array
{
return $this->fileErrors;
}

/**
* @return list<Error>
*/
public function getLocallyIgnoredErrors(): array
{
return $this->locallyIgnoredErrors;
}

/**
* @return LinesToIgnore
*/
public function getLinesToIgnore(): array
{
return $this->linesToIgnore;
}

/**
* @return LinesToIgnore
*/
public function getUnmatchedLineIgnores(): array
{
return $this->unmatchedLineIgnores;
}

}
2 changes: 2 additions & 0 deletions src/Testing/RuleTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PHPStan\Analyser\AnalyserResultFinalizer;
use PHPStan\Analyser\Error;
use PHPStan\Analyser\FileAnalyser;
use PHPStan\Analyser\LocalIgnoresProcessor;
use PHPStan\Analyser\NodeScopeResolver;
use PHPStan\Analyser\RuleErrorTransformer;
use PHPStan\Analyser\TypeSpecifier;
Expand Down Expand Up @@ -110,6 +111,7 @@ private function getAnalyser(): Analyser
$this->getParser(),
self::getContainer()->getByType(DependencyResolver::class),
new RuleErrorTransformer(),
new LocalIgnoresProcessor(),
true,
);
$this->analyser = new Analyser(
Expand Down
1 change: 1 addition & 0 deletions tests/PHPStan/Analyser/AnalyserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,7 @@ private function createAnalyser(bool $reportUnmatchedIgnoredErrors, bool $enable
),
new DependencyResolver($fileHelper, $reflectionProvider, new ExportedNodeResolver($fileTypeMapper, new ExprPrinter(new Printer())), $fileTypeMapper),
new RuleErrorTransformer(),
new LocalIgnoresProcessor(),
$reportUnmatchedIgnoredErrors,
);

Expand Down

0 comments on commit d026655

Please sign in to comment.