Skip to content

Commit 3b84ad4

Browse files
committed
feat: add option to report ignores without identifiers
1 parent c0f2e9e commit 3b84ad4

File tree

7 files changed

+95
-5
lines changed

7 files changed

+95
-5
lines changed

conf/config.neon

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ parameters:
9898
cache:
9999
nodesByStringCountMax: 256
100100
reportUnmatchedIgnoredErrors: true
101+
reportIgnoresWithoutIdentifiers: false
101102
typeAliases: []
102103
universalObjectCratesClasses:
103104
- stdClass
@@ -201,6 +202,7 @@ parameters:
201202
- [parameters, errorFormat]
202203
- [parameters, ignoreErrors]
203204
- [parameters, reportUnmatchedIgnoredErrors]
205+
- [parameters, reportIgnoresWithoutIdentifiers]
204206
- [parameters, tipsOfTheDay]
205207
- [parameters, parallel]
206208
- [parameters, internalErrorsCountLimit]

conf/parametersSchema.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ parametersSchema:
144144
nodesByStringCountMax: int()
145145
])
146146
reportUnmatchedIgnoredErrors: bool()
147+
reportIgnoresWithoutIdentifiers: bool()
147148
typeAliases: arrayOf(string())
148149
universalObjectCratesClasses: listOf(string())
149150
stubFiles: listOf(string())

src/Analyser/AnalyserResultFinalizer.php

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,21 @@ public function __construct(
2828
private LocalIgnoresProcessor $localIgnoresProcessor,
2929
#[AutowiredParameter]
3030
private bool $reportUnmatchedIgnoredErrors,
31+
#[AutowiredParameter]
32+
private bool $reportIgnoresWithoutIdentifiers,
3133
)
3234
{
3335
}
3436

3537
public function finalize(AnalyserResult $analyserResult, bool $onlyFiles, bool $debug): FinalizerResult
3638
{
3739
if (count($analyserResult->getCollectedData()) === 0) {
38-
return $this->addUnmatchedIgnoredErrors($this->mergeFilteredPhpErrors($analyserResult), [], []);
40+
return $this->addUnmatchedIgnoredErrors($this->addIgnoresWithoutIdentifiersErrors($this->mergeFilteredPhpErrors($analyserResult)), [], []);
3941
}
4042

4143
$hasInternalErrors = count($analyserResult->getInternalErrors()) > 0 || $analyserResult->hasReachedInternalErrorsCountLimit();
4244
if ($hasInternalErrors) {
43-
return $this->addUnmatchedIgnoredErrors($this->mergeFilteredPhpErrors($analyserResult), [], []);
45+
return $this->addUnmatchedIgnoredErrors($this->addIgnoresWithoutIdentifiersErrors($this->mergeFilteredPhpErrors($analyserResult)), [], []);
4446
}
4547

4648
$nodeType = CollectedDataNode::class;
@@ -134,7 +136,7 @@ public function finalize(AnalyserResult $analyserResult, bool $onlyFiles, bool $
134136
$allUnmatchedLineIgnores[$file] = $localIgnoresProcessorResult->getUnmatchedLineIgnores();
135137
}
136138

137-
return $this->addUnmatchedIgnoredErrors(new AnalyserResult(
139+
return $this->addUnmatchedIgnoredErrors($this->addIgnoresWithoutIdentifiersErrors(new AnalyserResult(
138140
array_merge($errors, $analyserResult->getFilteredPhpErrors()),
139141
[],
140142
$analyserResult->getAllPhpErrors(),
@@ -148,7 +150,7 @@ public function finalize(AnalyserResult $analyserResult, bool $onlyFiles, bool $
148150
$analyserResult->getExportedNodes(),
149151
$analyserResult->hasReachedInternalErrorsCountLimit(),
150152
$analyserResult->getPeakMemoryUsageBytes(),
151-
), $collectorErrors, $locallyIgnoredCollectorErrors);
153+
)), $collectorErrors, $locallyIgnoredCollectorErrors);
152154
}
153155

154156
private function mergeFilteredPhpErrors(AnalyserResult $analyserResult): AnalyserResult
@@ -237,4 +239,50 @@ private function addUnmatchedIgnoredErrors(
237239
);
238240
}
239241

242+
private function addIgnoresWithoutIdentifiersErrors(AnalyserResult $analyserResult): AnalyserResult
243+
{
244+
if (!$this->reportIgnoresWithoutIdentifiers) {
245+
return $analyserResult;
246+
}
247+
248+
$errors = $analyserResult->getUnorderedErrors();
249+
foreach ($analyserResult->getLinesToIgnore() as $file => $data) {
250+
foreach ($data as $ignoredFile => $lines) {
251+
if ($ignoredFile !== $file) {
252+
continue;
253+
}
254+
255+
foreach ($lines as $line => $identifiers) {
256+
if ($identifiers !== null) {
257+
continue;
258+
}
259+
260+
$errors[] = (new Error(
261+
sprintf('Error is ignored with no identifiers on line %d.', $line),
262+
$file,
263+
$line,
264+
false,
265+
$file,
266+
))->withIdentifier('ignore.noIdentifier');
267+
}
268+
}
269+
}
270+
271+
return new AnalyserResult(
272+
$errors,
273+
$analyserResult->getFilteredPhpErrors(),
274+
$analyserResult->getAllPhpErrors(),
275+
$analyserResult->getLocallyIgnoredErrors(),
276+
$analyserResult->getLinesToIgnore(),
277+
$analyserResult->getUnmatchedLineIgnores(),
278+
$analyserResult->getInternalErrors(),
279+
$analyserResult->getCollectedData(),
280+
$analyserResult->getDependencies(),
281+
$analyserResult->getUsedTraitDependencies(),
282+
$analyserResult->getExportedNodes(),
283+
$analyserResult->hasReachedInternalErrorsCountLimit(),
284+
$analyserResult->getPeakMemoryUsageBytes(),
285+
);
286+
}
287+
240288
}

src/Command/FixerWorkerCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ function (array $errors, array $locallyIgnoredErrors, array $analysedFiles) use
313313
if ($error->getIdentifier() === null) {
314314
continue;
315315
}
316-
if (!in_array($error->getIdentifier(), ['ignore.count', 'ignore.unmatched', 'ignore.unmatchedLine', 'ignore.unmatchedIdentifier'], true)) {
316+
if (!in_array($error->getIdentifier(), ['ignore.count', 'ignore.unmatched', 'ignore.unmatchedLine', 'ignore.unmatchedIdentifier', 'ignore.noIdentifier'], true)) {
317317
continue;
318318
}
319319
$ignoreFileErrors[] = $error;

src/Testing/RuleTestCase.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ private function gatherAnalyserErrorsWithDelayedErrors(array $files): array
268268
$this->createScopeFactory($reflectionProvider, $this->getTypeSpecifier()),
269269
new LocalIgnoresProcessor(),
270270
true,
271+
false,
271272
);
272273

273274
return [

tests/PHPStan/Analyser/AnalyserTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,21 @@ public function testIgnoreNextLineUnmatched(): void
548548
}
549549
}
550550

551+
#[DataProvider('dataTrueAndFalse')]
552+
public function testIgnoresWithoutIdentifiersReported(): void
553+
{
554+
$result = $this->runAnalyser([], false, [
555+
__DIR__ . '/data/ignore-no-identifiers.php',
556+
], true, true);
557+
$this->assertCount(4, $result);
558+
foreach ([10, 12, 15, 18] as $i => $line) {
559+
$this->assertArrayHasKey($i, $result);
560+
$this->assertInstanceOf(Error::class, $result[$i]);
561+
$this->assertStringContainsString('Error is ignored with no identifiers on line', $result[$i]->getMessage());
562+
$this->assertSame($line, $result[$i]->getLine());
563+
}
564+
}
565+
551566
#[DataProvider('dataTrueAndFalse')]
552567
public function testIgnoreLine(bool $reportUnmatchedIgnoredErrors): void
553568
{
@@ -632,6 +647,7 @@ private function runAnalyser(
632647
bool $reportUnmatchedIgnoredErrors,
633648
$filePaths,
634649
bool $onlyFiles,
650+
bool $reportIgnoresWithoutIdentifiers = false,
635651
): array
636652
{
637653
$analyser = $this->createAnalyser();
@@ -664,6 +680,7 @@ private function runAnalyser(
664680
),
665681
new LocalIgnoresProcessor(),
666682
$reportUnmatchedIgnoredErrors,
683+
$reportIgnoresWithoutIdentifiers,
667684
);
668685
$analyserResult = $finalizer->finalize($analyserResult, $onlyFiles, false)->getAnalyserResult();
669686

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace IgnoreNoIdentifiers;
4+
5+
class Foo
6+
{
7+
8+
public function doFoo(): void
9+
{
10+
fail(); // @phpstan-ignore-line
11+
12+
succ(); /** @phpstan-ignore-line reported as unmatched */
13+
14+
// @phpstan-ignore-next-line
15+
fail();
16+
17+
/** @phpstan-ignore-next-line reported as unmatched */
18+
succ();
19+
}
20+
21+
}

0 commit comments

Comments
 (0)