Skip to content

Commit 7ba01c8

Browse files
committed
Enhancement: Implement Files\NoPhpstanIgnoreRule
1 parent 32ae316 commit 7ba01c8

File tree

9 files changed

+282
-0
lines changed

9 files changed

+282
-0
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
88

99
For a full diff see [`2.12.0...main`][2.12.0...main].
1010

11+
### Added
12+
13+
- Added `PHPStan\NoIgnoreRule`, which reports an error when a `@phpstan-ignore`, `@phpstan-ignore-line`, or `@phpstan-ignore-next-line` tag is used to suppress an error ([#1009]), by [@localheinz]
14+
1115
### Changed
1216

1317
- Required `phpstan/phpstan:^2.1.35` ([#1010]), by [@localheinz]
@@ -740,6 +744,7 @@ For a full diff see [`362c7ea...0.1.0`][362c7ea...0.1.0].
740744
[#958]: https://github.com/ergebnis/phpstan-rules/pull/958
741745
[#972]: https://github.com/ergebnis/phpstan-rules/pull/972
742746
[#977]: https://github.com/ergebnis/phpstan-rules/pull/977
747+
[#1009]: https://github.com/ergebnis/phpstan-rules/pull/1009
743748
[#1010]: https://github.com/ergebnis/phpstan-rules/pull/1010
744749

745750
[@cosmastech]: https://github.com/cosmastech

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ This package provides the following rules for use with [`phpstan/phpstan`](https
5858
- [`Ergebnis\PHPStan\Rules\Expressions\NoEvalRule`](https://github.com/ergebnis/phpstan-rules#expressionsnoevalrule)
5959
- [`Ergebnis\PHPStan\Rules\Expressions\NoIssetRule`](https://github.com/ergebnis/phpstan-rules#expressionsnoissetrule)
6060
- [`Ergebnis\PHPStan\Rules\Files\DeclareStrictTypesRule`](https://github.com/ergebnis/phpstan-rules#filesdeclarestricttypesrule)
61+
- [`Ergebnis\PHPStan\Rules\Files\NoPhpstanIgnoreRule`](https://github.com/ergebnis/phpstan-rules#filesnophpstanignorerule)
6162
- [`Ergebnis\PHPStan\Rules\Functions\NoNullableReturnTypeDeclarationRule`](https://github.com/ergebnis/phpstan-rules#functionsnonullablereturntypedeclarationrule)
6263
- [`Ergebnis\PHPStan\Rules\Functions\NoParameterPassedByReferenceRule`](https://github.com/ergebnis/phpstan-rules#functionsnoparameterpassedbyreferencerule)
6364
- [`Ergebnis\PHPStan\Rules\Functions\NoParameterWithNullableTypeDeclarationRule`](https://github.com/ergebnis/phpstan-rules#functionsnoparameterwithnullabletypedeclarationrule)
@@ -348,6 +349,21 @@ parameters:
348349
enabled: false
349350
```
350351

352+
#### `Files\NoPhpstanIgnoreRule`
353+
354+
This rule reports an error when a `@phpstan-ignore`, `@phpstan-ignore-line`, or `@phpstan-ignore-next-line` tag is used to [ignore errors reported by `phpstan/phpstan`](https://phpstan.org/user-guide/ignoring-errors#ignoring-in-code-using-phpdocs).
355+
356+
##### Disabling the rule
357+
358+
You can set the `enabled` parameter to `false` to disable this rule.
359+
360+
```neon
361+
parameters:
362+
ergebnis:
363+
noPhpstanIgnore:
364+
enabled: false
365+
```
366+
351367
### Functions
352368

353369
#### `Functions\NoNullableReturnTypeDeclarationRule`

rules.neon

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ conditionalTags:
2525
phpstan.rules.rule: %ergebnis.noIsset.enabled%
2626
Ergebnis\PHPStan\Rules\Files\DeclareStrictTypesRule:
2727
phpstan.rules.rule: %ergebnis.declareStrictTypes.enabled%
28+
Ergebnis\PHPStan\Rules\Files\NoPhpstanIgnoreRule:
29+
phpstan.rules.rule: %ergebnis.noPhpstanIgnore.enabled%
2830
Ergebnis\PHPStan\Rules\Functions\NoNullableReturnTypeDeclarationRule:
2931
phpstan.rules.rule: %ergebnis.noNullableReturnTypeDeclaration.enabled%
3032
Ergebnis\PHPStan\Rules\Functions\NoParameterPassedByReferenceRule:
@@ -102,6 +104,8 @@ parameters:
102104
enabled: %ergebnis.allRules%
103105
noParameterWithNullDefaultValue:
104106
enabled: %ergebnis.allRules%
107+
noPhpstanIgnore:
108+
enabled: %ergebnis.allRules%
105109
noReturnByReference:
106110
enabled: %ergebnis.allRules%
107111
noSwitch:
@@ -176,6 +180,9 @@ parametersSchema:
176180
noParameterWithNullDefaultValue: structure([
177181
enabled: bool(),
178182
])
183+
noPhpstanIgnore: structure([
184+
enabled: bool(),
185+
])
179186
noReturnByReference: structure([
180187
enabled: bool(),
181188
])
@@ -238,6 +245,9 @@ services:
238245
-
239246
class: Ergebnis\PHPStan\Rules\Files\DeclareStrictTypesRule
240247

248+
-
249+
class: Ergebnis\PHPStan\Rules\Files\NoPhpstanIgnoreRule
250+
241251
-
242252
class: Ergebnis\PHPStan\Rules\Functions\NoNullableReturnTypeDeclarationRule
243253

src/ErrorIdentifier.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ public static function noNullableReturnTypeDeclaration(): self
110110
return new self('noNullableReturnTypeDeclaration');
111111
}
112112

113+
public static function noPhpstanIgnore(): self
114+
{
115+
return new self('noPhpstanIgnore');
116+
}
117+
113118
public static function noReturnByReference(): self
114119
{
115120
return new self('noReturnByReference');

src/Files/NoPhpstanIgnoreRule.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Copyright (c) 2018-2026 Andreas Möller
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE.md file that was distributed with this source code.
10+
*
11+
* @see https://github.com/ergebnis/phpstan-rules
12+
*/
13+
14+
namespace Ergebnis\PHPStan\Rules\Files;
15+
16+
use Ergebnis\PHPStan\Rules\ErrorIdentifier;
17+
use PhpParser\Node;
18+
use PHPStan\Analyser;
19+
use PHPStan\Node\FileNode;
20+
use PHPStan\Rules;
21+
22+
/**
23+
* @implements Rules\Rule<FileNode>
24+
*/
25+
final class NoPhpstanIgnoreRule implements Rules\Rule
26+
{
27+
public function getNodeType(): string
28+
{
29+
return FileNode::class;
30+
}
31+
32+
public function processNode(
33+
Node $node,
34+
Analyser\Scope $scope
35+
): array {
36+
$errors = [];
37+
38+
foreach ($node->getNodes() as $nodeInFile) {
39+
foreach ($nodeInFile->getComments() as $comment) {
40+
$text = $comment->getText();
41+
$commentStartLine = $comment->getStartLine();
42+
43+
foreach (\explode("\n", $text) as $index => $line) {
44+
if (0 === \preg_match('/@phpstan-ignore(-line|-next-line)?(?=\s|$|,)/', $line, $matches)) {
45+
continue;
46+
}
47+
48+
$tag = $matches[0];
49+
50+
$message = \sprintf(
51+
'Errors reported by phpstan/phpstan should not be ignored via "%s", fix the error or use the baseline instead.',
52+
$tag,
53+
);
54+
55+
$errors[] = Rules\RuleErrorBuilder::message($message)
56+
->identifier(ErrorIdentifier::noPhpstanIgnore()->toString())
57+
->line($commentStartLine + $index)
58+
->nonIgnorable()
59+
->build();
60+
}
61+
}
62+
}
63+
64+
return $errors;
65+
}
66+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
// @phpstan-ignore variable.undefined
6+
echo $undefined;
7+
8+
/* @phpstan-ignore variable.undefined */
9+
echo $undefined;
10+
11+
/** @phpstan-ignore variable.undefined */
12+
echo $undefined;
13+
14+
/*
15+
* @phpstan-ignore variable.undefined
16+
*/
17+
echo $undefined;
18+
19+
echo $undefined; // @phpstan-ignore-line
20+
21+
echo $undefined; /* @phpstan-ignore-line */
22+
23+
echo $undefined;
24+
25+
/** @phpstan-ignore-line */
26+
27+
// @phpstan-ignore-next-line
28+
echo $undefined;
29+
30+
/* @phpstan-ignore-next-line */
31+
echo $undefined;
32+
33+
/** @phpstan-ignore-next-line */
34+
echo $undefined;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
// a normal comment
6+
/* a normal block comment */
7+
8+
/** a normal doc comment */
9+
echo 'Hello!';
10+
11+
// @phpstan-type Foo = int
12+
/* @phpstan-param int $x */
13+
14+
/** @phpstan-return int */
15+
echo 'World!';
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Copyright (c) 2018-2026 Andreas Möller
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE.md file that was distributed with this source code.
10+
*
11+
* @see https://github.com/ergebnis/phpstan-rules
12+
*/
13+
14+
namespace Ergebnis\PHPStan\Rules\Test\Integration\Files;
15+
16+
use Ergebnis\PHPStan\Rules\Test;
17+
use PHPStan\Rules;
18+
use PHPStan\Testing;
19+
20+
/**
21+
* @covers \Ergebnis\PHPStan\Rules\Files\NoPhpstanIgnoreRule
22+
*
23+
* @uses \Ergebnis\PHPStan\Rules\ErrorIdentifier
24+
*
25+
* @extends Testing\RuleTestCase<\Ergebnis\PHPStan\Rules\Files\NoPhpstanIgnoreRule>
26+
*/
27+
final class NoPhpStanIgnoreRuleTest extends Testing\RuleTestCase
28+
{
29+
use Test\Util\Helper;
30+
31+
public function testNoIgnoreRule(): void
32+
{
33+
$this->analyse(
34+
self::phpFilesIn(__DIR__ . '/../../Fixture/Files/NoPhpstanIgnoreRule'),
35+
[
36+
[
37+
'Errors reported by phpstan/phpstan should not be ignored via "@phpstan-ignore", fix the error or use the baseline instead.',
38+
5,
39+
],
40+
[
41+
'No error with identifier variable.undefined is reported on line 6.',
42+
6,
43+
],
44+
[
45+
'Errors reported by phpstan/phpstan should not be ignored via "@phpstan-ignore", fix the error or use the baseline instead.',
46+
8,
47+
],
48+
[
49+
'No error with identifier variable.undefined is reported on line 9.',
50+
9,
51+
],
52+
[
53+
'Errors reported by phpstan/phpstan should not be ignored via "@phpstan-ignore", fix the error or use the baseline instead.',
54+
11,
55+
],
56+
[
57+
'No error with identifier variable.undefined is reported on line 12.',
58+
12,
59+
],
60+
[
61+
'Errors reported by phpstan/phpstan should not be ignored via "@phpstan-ignore", fix the error or use the baseline instead.',
62+
15,
63+
],
64+
[
65+
'No error with identifier variable.undefined is reported on line 17.',
66+
17,
67+
],
68+
[
69+
'Errors reported by phpstan/phpstan should not be ignored via "@phpstan-ignore-line", fix the error or use the baseline instead.',
70+
19,
71+
],
72+
[
73+
'No error to ignore is reported on line 19.',
74+
19,
75+
],
76+
[
77+
'Errors reported by phpstan/phpstan should not be ignored via "@phpstan-ignore-line", fix the error or use the baseline instead.',
78+
21,
79+
],
80+
[
81+
'No error to ignore is reported on line 21.',
82+
21,
83+
],
84+
[
85+
'Errors reported by phpstan/phpstan should not be ignored via "@phpstan-ignore-line", fix the error or use the baseline instead.',
86+
25,
87+
],
88+
[
89+
'No error to ignore is reported on line 25.',
90+
25,
91+
],
92+
[
93+
'Errors reported by phpstan/phpstan should not be ignored via "@phpstan-ignore-next-line", fix the error or use the baseline instead.',
94+
27,
95+
],
96+
[
97+
'No error to ignore is reported on line 28.',
98+
28,
99+
],
100+
[
101+
'Errors reported by phpstan/phpstan should not be ignored via "@phpstan-ignore-next-line", fix the error or use the baseline instead.',
102+
30,
103+
],
104+
[
105+
'No error to ignore is reported on line 31.',
106+
31,
107+
],
108+
[
109+
'Errors reported by phpstan/phpstan should not be ignored via "@phpstan-ignore-next-line", fix the error or use the baseline instead.',
110+
33,
111+
],
112+
[
113+
'No error to ignore is reported on line 34.',
114+
34,
115+
],
116+
],
117+
);
118+
}
119+
120+
protected function getRule(): Rules\Rule
121+
{
122+
return new \Ergebnis\PHPStan\Rules\Files\NoPhpstanIgnoreRule();
123+
}
124+
}

test/Unit/ErrorIdentifierTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,13 @@ public function testNoParameterWithNullableTypeDeclarationReturnsErrorIdentifier
140140
self::assertSame('ergebnis.noParameterWithNullableTypeDeclaration', $errorIdentifier->toString());
141141
}
142142

143+
public function testNoPhpstanIgnoreReturnsErrorIdentifier(): void
144+
{
145+
$errorIdentifier = ErrorIdentifier::noPhpstanIgnore();
146+
147+
self::assertSame('ergebnis.noPhpstanIgnore', $errorIdentifier->toString());
148+
}
149+
143150
public function testNoReturnByReferenceReturnsErrorIdentifier(): void
144151
{
145152
$errorIdentifier = ErrorIdentifier::noReturnByReference();

0 commit comments

Comments
 (0)