Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions src/Testing/RuleTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace PHPStan\Testing;

use LogicException;
use PhpParser\Node;
use PHPStan\Analyser\Analyser;
use PHPStan\Analyser\AnalyserResultFinalizer;
Expand Down Expand Up @@ -40,7 +41,9 @@
use function array_map;
use function array_merge;
use function count;
use function file;
use function implode;
use function preg_match;
use function sprintf;
use function str_replace;

Expand Down Expand Up @@ -142,10 +145,26 @@ private function getAnalyser(DirectRuleRegistry $ruleRegistry): Analyser

/**
* @param string[] $files
* @param list<array{0: string, 1: int, 2?: string|null}> $expectedErrors
* @param ?list<array{0: string, 1: int, 2?: string|null}> $expectedErrors
*/
public function analyse(array $files, array $expectedErrors): void
public function analyse(array $files, ?array $expectedErrors): void
{
if ($expectedErrors === null) {
$expectedErrors = [];
foreach ($files as $file) {
$lines = file($file);
if ($lines === false) {
throw new LogicException('Error while reading data from ' . $file);
}
foreach ($lines as $n => $line) {
if (preg_match('~// error: (.+?)(?:, tip: (.+))?$~m', $line, $match) !== 1) {
continue;
}
$expectedErrors[] = [$match[1], $n + 1, $match[2] ?? null];
}
}
}

[$actualErrors, $delayedErrors] = $this->gatherAnalyserErrorsWithDelayedErrors($files);
$strictlyTypedSprintf = static function (int $line, string $message, ?string $tip): string {
$message = sprintf('%02d: %s', $line, $message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,20 +346,14 @@ public function testBug5743(): void
public static function dataBug4969(): iterable
{
yield [false, []];
yield [true, [
[
'Result of && is always false.',
15,
'Because the type is coming from a PHPDoc, you can turn off this check by setting <fg=cyan>treatPhpDocTypesAsCertain: false</> in your <fg=cyan>%configurationFile%</>.',
],
]];
yield [true, null];
}

/**
* @param list<array{0: string, 1: int, 2?: string}> $expectedErrors
* @param ?list<array{0: string, 1: int, 2?: string}> $expectedErrors
*/
#[DataProvider('dataBug4969')]
public function testBug4969(bool $treatPhpDocTypesAsCertain, array $expectedErrors): void
public function testBug4969(bool $treatPhpDocTypesAsCertain, ?array $expectedErrors): void
{
$this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain;
$this->analyse([__DIR__ . '/data/bug-4969.php'], $expectedErrors);
Expand Down
52 changes: 1 addition & 51 deletions tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,57 +37,7 @@ protected function shouldTreatPhpDocTypesAsCertain(): bool

public function testRule(): void
{
$tipText = 'Remove remaining cases below this one and this error will disappear too.';
$this->analyse([__DIR__ . '/data/match-expr.php'], [
[
'Match arm comparison between 1|2|3 and \'foo\' is always false.',
14,
],
[
'Match arm comparison between 1|2|3 and 0 is always false.',
19,
],
[
'Match arm comparison between 3 and 3 is always true.',
28,
$tipText,
],
[
'Match arm comparison between 3 and 3 is always true.',
35,
$tipText,
],
[
'Match arm comparison between 1 and 1 is always true.',
40,
$tipText,
],
[
'Match arm comparison between 1 and 1 is always true.',
46,
$tipText,
],
[
'Match expression does not handle remaining value: 3',
50,
],
[
'Match arm comparison between 1|2 and 3 is always false.',
61,
],
[
'Match expression does not handle remaining values: 1|2|3',
78,
],
[
'Match expression does not handle remaining value: true',
90,
],
[
'Match expression does not handle remaining values: int<min, 0>|int<2, max>',
168,
],
]);
$this->analyse([__DIR__ . '/data/match-expr.php'], null);
}

public function testBug5161(): void
Expand Down
2 changes: 1 addition & 1 deletion tests/PHPStan/Rules/Comparison/data/bug-4969.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public function set(array $config): void
if (!is_string($config['host'])) {
throw new \InvalidArgumentException('error');
}
if (isset($config['port']) && !is_int($config['port'])) {
if (isset($config['port']) && !is_int($config['port'])) { // error: Result of && is always false., tip: Because the type is coming from a PHPDoc, you can turn off this check by setting <fg=cyan>treatPhpDocTypesAsCertain: false</> in your <fg=cyan>%configurationFile%</>.
throw new \InvalidArgumentException('error');
}
}
Expand Down
22 changes: 11 additions & 11 deletions tests/PHPStan/Rules/Comparison/data/match-expr.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ class Foo
public function doFoo(int $i): void
{
match ($i) {
'foo' => null, // always false
'foo' => null, // always false // error: Match arm comparison between 1|2|3 and 'foo' is always false.
default => null,
};

match ($i) {
0 => null,
0 => null, // error: Match arm comparison between 1|2|3 and 0 is always false.
1 => null,
2 => null,
3 => null, // always true, but do not report (it's the last one)
Expand All @@ -25,29 +25,29 @@ public function doFoo(int $i): void
match ($i) {
1 => null,
2 => null,
3 => null, // always true - report with strict-rules
3 => null, // always true - report with strict-rules // error: Match arm comparison between 3 and 3 is always true., tip: Remove remaining cases below this one and this error will disappear too.
4 => null, // unreachable
};

match ($i) {
1 => null,
2 => null,
3 => null, // always true - report with strict-rules
3 => null, // always true - report with strict-rules // error: Match arm comparison between 3 and 3 is always true., tip: Remove remaining cases below this one and this error will disappear too.
default => null, // unreachable
};

match (1) {
1 => null, // always true - report with strict-rules
1 => null, // always true - report with strict-rules // error: Match arm comparison between 1 and 1 is always true., tip: Remove remaining cases below this one and this error will disappear too.
2 => null, // unreachable
3 => null, // unreachable
};

match (1) {
1 => null, // always true - report with strict-rules
1 => null, // always true - report with strict-rules // error: Match arm comparison between 1 and 1 is always true., tip: Remove remaining cases below this one and this error will disappear too.
default => null, // unreachable
};

match ($i) {
match ($i) { // error: Match expression does not handle remaining value: 3
1, 2 => null,
// unhandled
};
Expand All @@ -58,7 +58,7 @@ public function doFoo(int $i): void
};

match ($i) {
3, 3 => null, // second 3 is always false
3, 3 => null, // second 3 is always false // error: Match arm comparison between 1|2 and 3 is always false.
default => null,
};

Expand All @@ -75,7 +75,7 @@ public function doFoo(int $i): void
1 => 2,
};

match ($i) {
match ($i) { // error: Match expression does not handle remaining values: 1|2|3
// unhandled
};
}
Expand All @@ -87,7 +87,7 @@ public function doBar(\Exception $e): void
default => null,
};

match (true) {
match (true) { // error: Match expression does not handle remaining value: true
$e instanceof \InvalidArgumentException => true,
$e instanceof \InvalidArgumentException => true, // reported by ImpossibleInstanceOfRule
};
Expand Down Expand Up @@ -165,7 +165,7 @@ public function bar(int $bar): void
*/
public function baz(int $bar): void
{
$str = match($bar) {
$str = match($bar) { // error: Match expression does not handle remaining values: int<min, 0>|int<2, max>
1 => 'test'
};
}
Expand Down
Loading