Skip to content

Commit

Permalink
IgnoreErrorExtension
Browse files Browse the repository at this point in the history
This allows for more flexibility in ignoring errors.

Some use cases:

* Ignore `missingType.iterableValue` on controller actions:
  Rule: when the method is public and it has `#[Route]` attribute or the
        class has `#[AsController]` attribute.
* Ignore `should return int but returns int|null` on `getId` for entities.
  Rule: class needs to have `#[Entity]` attribute.
* Ignore `never returns null so it can be removed from the return type`
  Rule: method needs to have `#[GraphQL\Field]` attribute.
* Enforce missingCheckedExceptionInThrows partially, only for specific classes.
  • Loading branch information
ruudk committed Jan 24, 2025
1 parent 46b9819 commit f7021e9
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 1 deletion.
11 changes: 11 additions & 0 deletions src/Analyser/AnalyserResultFinalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ final class AnalyserResultFinalizer

public function __construct(
private RuleRegistry $ruleRegistry,
private IgnoreErrorExtensionProvider $ignoreErrorExtensionProvider,
private RuleErrorTransformer $ruleErrorTransformer,
private ScopeFactory $scopeFactory,
private LocalIgnoresProcessor $localIgnoresProcessor,
Expand Down Expand Up @@ -92,6 +93,16 @@ public function finalize(AnalyserResult $analyserResult, bool $onlyFiles, bool $
}
}

$tempCollectorErrors = array_filter($tempCollectorErrors, function (string $error) use ($scope, $node) : bool {
foreach ($this->ignoreErrorExtensionProvider->getExtensions() as $ignoreErrorExtension) {
if ($ignoreErrorExtension->ignore($error, $node, $scope)) {
return false;
}
}

return true;
});

$errors = $analyserResult->getUnorderedErrors();
$locallyIgnoredErrors = $analyserResult->getLocallyIgnoredErrors();
$allLinesToIgnore = $analyserResult->getLinesToIgnore();
Expand Down
22 changes: 21 additions & 1 deletion src/Analyser/FileAnalyser.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public function __construct(
private NodeScopeResolver $nodeScopeResolver,
private Parser $parser,
private DependencyResolver $dependencyResolver,
private IgnoreErrorExtensionProvider $ignoreErrorExtensionProvider,
private RuleErrorTransformer $ruleErrorTransformer,
private LocalIgnoresProcessor $localIgnoresProcessor,
)
Expand Down Expand Up @@ -142,7 +143,15 @@ public function analyseFile(
}

foreach ($ruleErrors as $ruleError) {
$temporaryFileErrors[] = $this->ruleErrorTransformer->transform($ruleError, $scope, $nodeType, $node->getStartLine());
$error = $this->ruleErrorTransformer->transform($ruleError, $scope, $nodeType, $node->getStartLine());

foreach ($this->ignoreErrorExtensionProvider->getExtensions() as $ignoreErrorExtension) {
if ($ignoreErrorExtension->ignore($error, $node, $scope)) {
continue 2;
}
}

$temporaryFileErrors[] = $error;
}
}

Expand Down Expand Up @@ -281,6 +290,17 @@ public function analyseFile(
unset($unmatchedLineIgnores[$fileKey]);
}

$fileErrors = array_filter($fileErrors, function (Error $error) use ($scope) : bool {
foreach ($this->ignoreErrorExtensionProvider->getExtensions() as $ignoreErrorExtension) {
if ($ignoreErrorExtension->ignore($error, null, $scope)) {
return false;
}
}

return true;
});


return new FileAnalyserResult(
$fileErrors,
$this->filteredPhpErrors,
Expand Down
32 changes: 32 additions & 0 deletions src/Analyser/IgnoreErrorExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php declare(strict_types = 1);

namespace PHPStan\Analyser;

use PhpParser\Node;

/**
* This is the extension interface to implement if you want to ignore errors
* based on the node and scope.
*
* To register it in the configuration file use the `phpstan.ignoreErrorExtension` service tag:
*
* ```
* services:
* -
* class: App\PHPStan\MyExtension
* tags:
* - phpstan.ignoreErrorExtension
* ```
*
* Learn more: https://phpstan.org
*
* @api
*/
interface IgnoreErrorExtension
{

public const EXTENSION_TAG = 'phpstan.ignoreErrorExtension';

public function ignore(Error $error, ?Node $node, Scope $scope): bool;

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

namespace PHPStan\Analyser;

use PHPStan\DependencyInjection\Container;

final class IgnoreErrorExtensionProvider
{

public function __construct(private Container $container)
{
}

/**
* @return IgnoreErrorExtension[]
*/
public function getExtensions(): array
{
return $this->container->getServicesByTag(IgnoreErrorExtension::EXTENSION_TAG);
}

}

0 comments on commit f7021e9

Please sign in to comment.