Skip to content

Commit 50a74d8

Browse files
committed
fixed PHPStan errors
1 parent e824be7 commit 50a74d8

22 files changed

Lines changed: 119 additions & 173 deletions

phpstan-baseline.neon

Lines changed: 0 additions & 103 deletions
This file was deleted.

phpstan.neon

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,48 @@
11
parameters:
2-
level: 6
3-
errorFormat: raw
2+
level: 8
43

54
paths:
65
- src
76

87
excludePaths:
98
- src/Framework/FileMutator.php
109

11-
includes:
12-
- phpstan-baseline.neon
10+
ignoreErrors:
11+
- # DomQuery: PHP 8.4 Dom\Element API not in PHPStan stubs
12+
identifier: method.notFound
13+
path: src/Framework/DomQuery.php
14+
- # DomQuery: SimpleXMLElement subclass return types
15+
identifier: return.type
16+
path: src/Framework/DomQuery.php
17+
- # DomQuery: regex match group offsets
18+
identifier: offsetAccess.notFound
19+
path: src/Framework/DomQuery.php
20+
- # DomQuery: simplexml_import_dom accepts Dom\Node in PHP 8.4
21+
identifier: argument.type
22+
path: src/Framework/DomQuery.php
23+
- # DomQuery: regex analysis false positive
24+
identifier: identical.alwaysFalse
25+
path: src/Framework/DomQuery.php
26+
27+
- # Edge case: with a registered onFailure handler exception() may return a Throwable that is not T; the documented contract still holds for the throw-on-failure default behaviour.
28+
message: '#^Method Tester\\Assert\:\:exception\(\) should return \(T of Throwable\)\|null but returns Throwable\|null\.$#'
29+
identifier: return.type
30+
path: src/Framework/Assert.php
31+
32+
- # Intentional: arrow/anonymous fn receives the file path via func_get_arg() so the included file is not given any local variables in scope.
33+
identifier: arguments.count
34+
paths:
35+
- src/Framework/DataProvider.php
36+
- src/Runner/CliTester.php
37+
38+
- # Intentional: $runner is used inside the included --setup script, not in the closure body itself.
39+
identifier: closure.unusedUse
40+
path: src/Runner/CliTester.php
41+
42+
- # Intentional infinite loop for the --watch mode.
43+
identifier: while.alwaysTrue
44+
path: src/Runner/CliTester.php
45+
46+
- # False positive: $interrupted is mutated transitively through $this->testHandler->assess() -> Runner::finishTest(); PHPStan cannot track cross-method property mutation.
47+
identifier: if.alwaysFalse
48+
path: src/Runner/Runner.php

src/CodeCoverage/Collector.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ class Collector
2929
public static function detectEngines(): array
3030
{
3131
return array_filter([
32-
extension_loaded('pcov') ? [self::EnginePcov, phpversion('pcov')] : null,
33-
defined('PHPDBG_VERSION') ? [self::EnginePhpdbg, PHPDBG_VERSION] : null,
34-
extension_loaded('xdebug') ? [self::EngineXdebug, phpversion('xdebug')] : null,
32+
extension_loaded('pcov') ? [self::EnginePcov, (string) phpversion('pcov')] : null,
33+
defined('PHPDBG_VERSION') ? [self::EnginePhpdbg, (string) PHPDBG_VERSION] : null,
34+
extension_loaded('xdebug') ? [self::EngineXdebug, (string) phpversion('xdebug')] : null,
3535
]);
3636
}
3737

@@ -183,7 +183,9 @@ private static function startPhpDbg(): void
183183
*/
184184
private static function collectPhpDbg(): array
185185
{
186+
/** @var array<string, array<int, int>> $positive */
186187
$positive = phpdbg_end_oplog();
188+
/** @var array<string, array<int, int>> $negative */
187189
$negative = phpdbg_get_executable();
188190

189191
foreach ($positive as $file => &$lines) {

src/CodeCoverage/Generators/AbstractGenerator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public function __construct(string $file, array $sources = [])
5757
}
5858
}
5959

60-
$this->sources = array_map('realpath', $sources);
60+
$this->sources = array_map(fn(string $source): string => (string) realpath($source), $sources);
6161
}
6262

6363

src/CodeCoverage/Generators/CloverXMLGenerator.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ protected function renderSelf(): void
8383

8484
if (empty($this->data[$file])) {
8585
$coverageData = null;
86-
$this->totalSum += count(file($file, FILE_SKIP_EMPTY_LINES));
86+
$this->totalSum += count(file($file, FILE_SKIP_EMPTY_LINES) ?: []);
8787
} else {
8888
$coverageData = $this->data[$file];
8989
}
@@ -198,7 +198,7 @@ private static function analyzeMethod(\stdClass $info, ?array $coverageData = nu
198198
$coveredCount = 0;
199199

200200
if ($coverageData === null) { // Never loaded file
201-
$count = max(1, $info->end - $info->start - 2);
201+
$count = (int) max(1, $info->end - $info->start - 2);
202202
} else {
203203
for ($i = $info->start; $i <= $info->end; $i++) {
204204
if (isset($coverageData[$i]) && $coverageData[$i] !== self::LineDead) {
@@ -216,15 +216,15 @@ private static function analyzeMethod(\stdClass $info, ?array $coverageData = nu
216216

217217
private static function appendMetrics(\stdClass $summary, \stdClass $add): void
218218
{
219-
foreach ($add as $name => $value) {
219+
foreach (get_object_vars($add) as $name => $value) {
220220
$summary->{$name} += $value;
221221
}
222222
}
223223

224224

225225
private static function setMetricAttributes(DOMElement $element, \stdClass $metrics): void
226226
{
227-
foreach ($metrics as $name => $value) {
227+
foreach (get_object_vars($metrics) as $name => $value) {
228228
$element->setAttribute(self::$metricAttributesMap[$name], (string) $value);
229229
}
230230
}

src/CodeCoverage/Generators/HtmlGenerator.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,10 @@ private function parse(): void
9393
$this->totalSum += $total;
9494
$this->coveredSum += $covered;
9595
} else {
96-
$this->totalSum += count(file($entry, FILE_SKIP_EMPTY_LINES));
96+
$this->totalSum += count(file($entry, FILE_SKIP_EMPTY_LINES) ?: []);
9797
}
9898

99-
$light = $total ? $total < 5 : count(file($entry)) < 50;
99+
$light = $total ? $total < 5 : count(file($entry) ?: []) < 50;
100100
$this->files[] = (object) [
101101
'name' => str_replace($commonSourcesPath, '', $entry),
102102
'file' => $entry,

src/CodeCoverage/PhpParser.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ public function parse(string $code): \stdClass
5555
{
5656
$tokens = \PhpToken::tokenize($code, TOKEN_PARSE);
5757

58-
$level = $classLevel = $functionLevel = null;
58+
$level = 0;
59+
$classLevel = $functionLevel = null;
5960
$namespace = '';
6061
$line = 1;
6162

src/Framework/Assert.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -557,13 +557,14 @@ public static function isMatching(string $pattern, string $actual, bool $strict
557557
'\x00' => '\x00',
558558
'[\t ]*\r?\n' => '[\t ]*\r?\n', // right trim
559559
];
560-
$pattern = '#^' . preg_replace_callback('#' . implode('|', array_keys($patterns)) . '#U' . $utf8, function ($m) use ($patterns) {
560+
$pattern = '#^' . preg_replace_callback('#' . implode('|', array_keys($patterns)) . '#U' . $utf8, function ($m) use ($patterns): string {
561561
foreach ($patterns as $re => $replacement) {
562562
$s = preg_replace("#^$re$#D", str_replace('\\', '\\\\', $replacement), $m[0], 1, $count);
563563
if ($count) {
564-
return $s;
564+
return $s ?? $m[0];
565565
}
566566
}
567+
return $m[0];
567568
}, rtrim($pattern, " \t\n\r")) . $suffix;
568569
}
569570

src/Framework/DomQuery.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@ public static function fromXml(string $xml): self
7979
public function find(string $selector): array
8080
{
8181
if (PHP_VERSION_ID < 80400) {
82-
return str_starts_with($selector, ':scope')
82+
return (str_starts_with($selector, ':scope')
8383
? $this->xpath('self::' . self::css2xpath(substr($selector, 6)))
84-
: $this->xpath('descendant::' . self::css2xpath($selector));
84+
: $this->xpath('descendant::' . self::css2xpath($selector))) ?: [];
8585
}
8686

8787
return array_map(

src/Framework/Dumper.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ public static function dumpException(\Throwable $e): string
294294
$trace = $e->getTrace();
295295
array_splice($trace, 0, $e instanceof \ErrorException ? 1 : 0, [['file' => $e->getFile(), 'line' => $e->getLine()]]);
296296

297-
$testFile = null;
297+
$testFile = $e->getFile();
298298
foreach (array_reverse($trace) as $item) {
299299
if (isset($item['file'])) { // in case of shutdown handler, we want to skip inner-code blocks and debugging calls
300300
$testFile = $item['file'];
@@ -359,8 +359,8 @@ public static function dumpException(\Throwable $e): string
359359
continue;
360360
}
361361

362-
$line = $item['class'] === Assert::class && method_exists($item['class'], $item['function'])
363-
&& strpos($tmp = file($item['file'])[$item['line'] - 1], "::$item[function](") ? $tmp : null;
362+
$line = $item['class'] === Assert::class && isset($item['function'], $item['file']) && method_exists($item['class'], $item['function'])
363+
&& strpos($tmp = (file($item['file']) ?: [])[$item['line'] - 1] ?? '', "::$item[function](") ? $tmp : null;
364364

365365
$s .= 'in '
366366
. ($item['file']

0 commit comments

Comments
 (0)