Skip to content

Commit

Permalink
Feature/match expression throws tag
Browse files Browse the repository at this point in the history
  • Loading branch information
rajyan committed Mar 23, 2022
1 parent 0175bc8 commit 2b9d212
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 48 deletions.
21 changes: 20 additions & 1 deletion src/Rules/Comparison/MatchExpressionRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,11 @@ public function processNode(Node $node, Scope $scope): array

if (!$hasDefault && !$nextArmIsDead) {
$remainingType = $node->getEndScope()->getType($matchCondition);
if (!$remainingType instanceof NeverType && !$this->isUnhandledMatchErrorCaught($node)) {
if (
!$remainingType instanceof NeverType
&& !$this->isUnhandledMatchErrorCaught($node)
&& !$this->hasUnhandledMatchErrorThrowsTag($scope)
) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Match expression does not handle remaining %s: %s',
$remainingType instanceof UnionType ? 'values' : 'value',
Expand Down Expand Up @@ -122,4 +126,19 @@ private function isUnhandledMatchErrorCaught(Node $node): bool
return $this->isUnhandledMatchErrorCaught($tryCatchNode);
}

private function hasUnhandledMatchErrorThrowsTag(Scope $scope): bool
{
$function = $scope->getFunction();
if ($function === null) {
return false;
}

$throwsType = $function->getThrowType();
if ($throwsType === null) {
return false;
}

return $throwsType->isSuperTypeOf(new ObjectType(UnhandledMatchError::class))->yes();
}

}
6 changes: 5 additions & 1 deletion tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ public function testRule(): void
'Match expression does not handle remaining value: true',
90,
],
[
'Match expression does not handle remaining values: int<min, 0>|int<2, max>',
168,
],
]);
}

Expand Down Expand Up @@ -176,7 +180,7 @@ public function testBug6115(): void
$this->analyse([__DIR__ . '/data/bug-6115.php'], [
[
'Match expression does not handle remaining value: 3',
28,
32,
],
]);
}
Expand Down
99 changes: 53 additions & 46 deletions tests/PHPStan/Rules/Comparison/data/bug-6115.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,63 @@

namespace Bug6115;

$array = [1, 2, 3];
try {
foreach ($array as $value) {
$b = match ($value) {
1 => 0,
2 => 1,
};
}
} catch (\UnhandledMatchError $e) {
}
class Foo
{
public function bar()
{
$array = [1, 2, 3];
try {
foreach ($array as $value) {
$b = match ($value) {
1 => 0,
2 => 1,
};
}
} catch (\UnhandledMatchError $e) {
}

try {
foreach ($array as $value) {
$b = match ($value) {
1 => 0,
2 => 1,
};
}
} catch (\Error $e) {
}
try {
foreach ($array as $value) {
$b = match ($value) {
1 => 0,
2 => 1,
};
}
} catch (\Error $e) {
}

try {
foreach ($array as $value) {
$b = match ($value) {
1 => 0,
2 => 1,
};
}
} catch (\Exception $e) {
}
try {
foreach ($array as $value) {
$b = match ($value) {
1 => 0,
2 => 1,
};
}
} catch (\Exception $e) {
}

try {
foreach ($array as $value) {
$b = match ($value) {
1 => 0,
2 => 1,
};
}
} catch (\UnhandledMatchError|\Exception $e) {
}
try {
foreach ($array as $value) {
$b = match ($value) {
1 => 0,
2 => 1,
};
}
} catch (\UnhandledMatchError|\Exception $e) {
}

try {
try {
foreach ($array as $value) {
$b = match ($value) {
1 => 0,
2 => 1,
};
try {
try {
foreach ($array as $value) {
$b = match ($value) {
1 => 0,
2 => 1,
};
}
} catch (\Exception $e) {
}
} catch (\UnhandledMatchError $e) {
}
} catch (\Exception $e) {
}
} catch (\UnhandledMatchError $e) {}
}

32 changes: 32 additions & 0 deletions tests/PHPStan/Rules/Comparison/data/match-expr.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,35 @@ public function doBar(int $i): void {


}

class ThrowsTag {
/**
* @throws \UnhandledMatchError
*/
public function foo(int $bar): void
{
$str = match($bar) {
1 => 'test'
};
}

/**
* @throws \Error
*/
public function bar(int $bar): void
{
$str = match($bar) {
1 => 'test'
};
}

/**
* @throws \Exception
*/
public function baz(int $bar): void
{
$str = match($bar) {
1 => 'test'
};
}
}

0 comments on commit 2b9d212

Please sign in to comment.