Skip to content

Commit f7021e9

Browse files
committed
IgnoreErrorExtension
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.
1 parent 46b9819 commit f7021e9

File tree

4 files changed

+86
-1
lines changed

4 files changed

+86
-1
lines changed

src/Analyser/AnalyserResultFinalizer.php

+11
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ final class AnalyserResultFinalizer
1919

2020
public function __construct(
2121
private RuleRegistry $ruleRegistry,
22+
private IgnoreErrorExtensionProvider $ignoreErrorExtensionProvider,
2223
private RuleErrorTransformer $ruleErrorTransformer,
2324
private ScopeFactory $scopeFactory,
2425
private LocalIgnoresProcessor $localIgnoresProcessor,
@@ -92,6 +93,16 @@ public function finalize(AnalyserResult $analyserResult, bool $onlyFiles, bool $
9293
}
9394
}
9495

96+
$tempCollectorErrors = array_filter($tempCollectorErrors, function (string $error) use ($scope, $node) : bool {
97+
foreach ($this->ignoreErrorExtensionProvider->getExtensions() as $ignoreErrorExtension) {
98+
if ($ignoreErrorExtension->ignore($error, $node, $scope)) {
99+
return false;
100+
}
101+
}
102+
103+
return true;
104+
});
105+
95106
$errors = $analyserResult->getUnorderedErrors();
96107
$locallyIgnoredErrors = $analyserResult->getLocallyIgnoredErrors();
97108
$allLinesToIgnore = $analyserResult->getLinesToIgnore();

src/Analyser/FileAnalyser.php

+21-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public function __construct(
5151
private NodeScopeResolver $nodeScopeResolver,
5252
private Parser $parser,
5353
private DependencyResolver $dependencyResolver,
54+
private IgnoreErrorExtensionProvider $ignoreErrorExtensionProvider,
5455
private RuleErrorTransformer $ruleErrorTransformer,
5556
private LocalIgnoresProcessor $localIgnoresProcessor,
5657
)
@@ -142,7 +143,15 @@ public function analyseFile(
142143
}
143144

144145
foreach ($ruleErrors as $ruleError) {
145-
$temporaryFileErrors[] = $this->ruleErrorTransformer->transform($ruleError, $scope, $nodeType, $node->getStartLine());
146+
$error = $this->ruleErrorTransformer->transform($ruleError, $scope, $nodeType, $node->getStartLine());
147+
148+
foreach ($this->ignoreErrorExtensionProvider->getExtensions() as $ignoreErrorExtension) {
149+
if ($ignoreErrorExtension->ignore($error, $node, $scope)) {
150+
continue 2;
151+
}
152+
}
153+
154+
$temporaryFileErrors[] = $error;
146155
}
147156
}
148157

@@ -281,6 +290,17 @@ public function analyseFile(
281290
unset($unmatchedLineIgnores[$fileKey]);
282291
}
283292

293+
$fileErrors = array_filter($fileErrors, function (Error $error) use ($scope) : bool {
294+
foreach ($this->ignoreErrorExtensionProvider->getExtensions() as $ignoreErrorExtension) {
295+
if ($ignoreErrorExtension->ignore($error, null, $scope)) {
296+
return false;
297+
}
298+
}
299+
300+
return true;
301+
});
302+
303+
284304
return new FileAnalyserResult(
285305
$fileErrors,
286306
$this->filteredPhpErrors,

src/Analyser/IgnoreErrorExtension.php

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser;
4+
5+
use PhpParser\Node;
6+
7+
/**
8+
* This is the extension interface to implement if you want to ignore errors
9+
* based on the node and scope.
10+
*
11+
* To register it in the configuration file use the `phpstan.ignoreErrorExtension` service tag:
12+
*
13+
* ```
14+
* services:
15+
* -
16+
* class: App\PHPStan\MyExtension
17+
* tags:
18+
* - phpstan.ignoreErrorExtension
19+
* ```
20+
*
21+
* Learn more: https://phpstan.org
22+
*
23+
* @api
24+
*/
25+
interface IgnoreErrorExtension
26+
{
27+
28+
public const EXTENSION_TAG = 'phpstan.ignoreErrorExtension';
29+
30+
public function ignore(Error $error, ?Node $node, Scope $scope): bool;
31+
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Analyser;
4+
5+
use PHPStan\DependencyInjection\Container;
6+
7+
final class IgnoreErrorExtensionProvider
8+
{
9+
10+
public function __construct(private Container $container)
11+
{
12+
}
13+
14+
/**
15+
* @return IgnoreErrorExtension[]
16+
*/
17+
public function getExtensions(): array
18+
{
19+
return $this->container->getServicesByTag(IgnoreErrorExtension::EXTENSION_TAG);
20+
}
21+
22+
}

0 commit comments

Comments
 (0)