Skip to content

Commit 94bcb68

Browse files
committed
feat: add option to report ignores without identifiers
1 parent 2ac87fc commit 94bcb68

File tree

7 files changed

+93
-5
lines changed

7 files changed

+93
-5
lines changed

conf/config.neon

+3
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ parameters:
9595
cache:
9696
nodesByStringCountMax: 256
9797
reportUnmatchedIgnoredErrors: true
98+
reportIgnoresWithoutIdentifiers: false
9899
typeAliases: []
99100
universalObjectCratesClasses:
100101
- stdClass
@@ -198,6 +199,7 @@ parameters:
198199
- [parameters, errorFormat]
199200
- [parameters, ignoreErrors]
200201
- [parameters, reportUnmatchedIgnoredErrors]
202+
- [parameters, reportIgnoresWithoutIdentifiers]
201203
- [parameters, tipsOfTheDay]
202204
- [parameters, parallel]
203205
- [parameters, internalErrorsCountLimit]
@@ -461,6 +463,7 @@ services:
461463
class: PHPStan\Analyser\AnalyserResultFinalizer
462464
arguments:
463465
reportUnmatchedIgnoredErrors: %reportUnmatchedIgnoredErrors%
466+
reportIgnoresWithoutIdentifiers: %reportIgnoresWithoutIdentifiers%
464467

465468
-
466469
class: PHPStan\Analyser\FileAnalyser

conf/parametersSchema.neon

+1
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ parametersSchema:
143143
nodesByStringCountMax: int()
144144
])
145145
reportUnmatchedIgnoredErrors: bool()
146+
reportIgnoresWithoutIdentifiers: bool()
146147
typeAliases: arrayOf(string())
147148
universalObjectCratesClasses: listOf(string())
148149
stubFiles: listOf(string())

src/Analyser/AnalyserResultFinalizer.php

+50-4
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,20 @@ public function __construct(
2424
private ScopeFactory $scopeFactory,
2525
private LocalIgnoresProcessor $localIgnoresProcessor,
2626
private bool $reportUnmatchedIgnoredErrors,
27+
private bool $reportIgnoresWithoutIdentifiers,
2728
)
2829
{
2930
}
3031

3132
public function finalize(AnalyserResult $analyserResult, bool $onlyFiles, bool $debug): FinalizerResult
3233
{
3334
if (count($analyserResult->getCollectedData()) === 0) {
34-
return $this->addUnmatchedIgnoredErrors($this->mergeFilteredPhpErrors($analyserResult), [], []);
35+
return $this->addUnmatchedIgnoredErrors($this->addIgnoresWithoutIdentifiersErrors($this->mergeFilteredPhpErrors($analyserResult)), [], []);
3536
}
3637

3738
$hasInternalErrors = count($analyserResult->getInternalErrors()) > 0 || $analyserResult->hasReachedInternalErrorsCountLimit();
3839
if ($hasInternalErrors) {
39-
return $this->addUnmatchedIgnoredErrors($this->mergeFilteredPhpErrors($analyserResult), [], []);
40+
return $this->addUnmatchedIgnoredErrors($this->addIgnoresWithoutIdentifiersErrors($this->mergeFilteredPhpErrors($analyserResult)), [], []);
4041
}
4142

4243
$nodeType = CollectedDataNode::class;
@@ -130,7 +131,7 @@ public function finalize(AnalyserResult $analyserResult, bool $onlyFiles, bool $
130131
$allUnmatchedLineIgnores[$file] = $localIgnoresProcessorResult->getUnmatchedLineIgnores();
131132
}
132133

133-
return $this->addUnmatchedIgnoredErrors(new AnalyserResult(
134+
return $this->addUnmatchedIgnoredErrors($this->addIgnoresWithoutIdentifiersErrors(new AnalyserResult(
134135
array_merge($errors, $analyserResult->getFilteredPhpErrors()),
135136
[],
136137
$analyserResult->getAllPhpErrors(),
@@ -143,7 +144,7 @@ public function finalize(AnalyserResult $analyserResult, bool $onlyFiles, bool $
143144
$analyserResult->getExportedNodes(),
144145
$analyserResult->hasReachedInternalErrorsCountLimit(),
145146
$analyserResult->getPeakMemoryUsageBytes(),
146-
), $collectorErrors, $locallyIgnoredCollectorErrors);
147+
)), $collectorErrors, $locallyIgnoredCollectorErrors);
147148
}
148149

149150
private function mergeFilteredPhpErrors(AnalyserResult $analyserResult): AnalyserResult
@@ -230,4 +231,49 @@ private function addUnmatchedIgnoredErrors(
230231
);
231232
}
232233

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

src/Command/FixerWorkerCommand.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ function (array $errors, array $locallyIgnoredErrors, array $analysedFiles) use
308308
if ($error->getIdentifier() === null) {
309309
continue;
310310
}
311-
if (!in_array($error->getIdentifier(), ['ignore.count', 'ignore.unmatched', 'ignore.unmatchedLine', 'ignore.unmatchedIdentifier'], true)) {
311+
if (!in_array($error->getIdentifier(), ['ignore.count', 'ignore.unmatched', 'ignore.unmatchedLine', 'ignore.unmatchedIdentifier', 'ignore.noIdentifier'], true)) {
312312
continue;
313313
}
314314
$ignoreFileErrors[] = $error;

src/Testing/RuleTestCase.php

+1
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ private function gatherAnalyserErrorsWithDelayedErrors(array $files): array
241241
$this->createScopeFactory($reflectionProvider, $this->getTypeSpecifier()),
242242
new LocalIgnoresProcessor(),
243243
true,
244+
false,
244245
);
245246

246247
return [

tests/PHPStan/Analyser/AnalyserTest.php

+16
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,20 @@ public function testIgnoreNextLineUnmatched(): void
559559
}
560560
}
561561

562+
public function testIgnoresWithoutIdentifiersReported(): void
563+
{
564+
$result = $this->runAnalyser([], false, [
565+
__DIR__ . '/data/ignore-no-identifiers.php',
566+
], true, true);
567+
$this->assertCount(4, $result);
568+
foreach ([10, 12, 15, 18] as $i => $line) {
569+
$this->assertArrayHasKey($i, $result);
570+
$this->assertInstanceOf(Error::class, $result[$i]);
571+
$this->assertStringContainsString('Error is ignored with no identifiers on line', $result[$i]->getMessage());
572+
$this->assertSame($line, $result[$i]->getLine());
573+
}
574+
}
575+
562576
/**
563577
* @dataProvider dataTrueAndFalse
564578
*/
@@ -645,6 +659,7 @@ private function runAnalyser(
645659
bool $reportUnmatchedIgnoredErrors,
646660
$filePaths,
647661
bool $onlyFiles,
662+
bool $reportIgnoresWithoutIdentifiers = false,
648663
): array
649664
{
650665
$analyser = $this->createAnalyser();
@@ -677,6 +692,7 @@ private function runAnalyser(
677692
),
678693
new LocalIgnoresProcessor(),
679694
$reportUnmatchedIgnoredErrors,
695+
$reportIgnoresWithoutIdentifiers,
680696
);
681697
$analyserResult = $finalizer->finalize($analyserResult, $onlyFiles, false)->getAnalyserResult();
682698

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace IgnoreIdentifiers;
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)