Skip to content

Commit

Permalink
Support for throw expression (PHP 8.0)
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Oct 14, 2020
1 parent 7a38424 commit 5f2d42c
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 1 deletion.
1 change: 1 addition & 0 deletions conf/config.level0.neon
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ rules:
- PHPStan\Rules\Classes\ExistingClassInTraitUseRule
- PHPStan\Rules\Classes\InstantiationRule
- PHPStan\Rules\Classes\NewStaticRule
- PHPStan\Rules\Exceptions\ThrowExpressionRule
- PHPStan\Rules\Functions\CallToFunctionParametersRule
- PHPStan\Rules\Functions\ExistingClassesInArrowFunctionTypehintsRule
- PHPStan\Rules\Functions\ExistingClassesInClosureTypehintsRule
Expand Down
2 changes: 1 addition & 1 deletion src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ private function getNodeKey(Expr $node): string

private function resolveType(Expr $node): Type
{
if ($node instanceof Expr\Exit_) {
if ($node instanceof Expr\Exit_ || $node instanceof Expr\Throw_) {
return new NeverType();
}

Expand Down
5 changes: 5 additions & 0 deletions src/Php/PhpVersion.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,9 @@ public function requiresParenthesesForNestedTernaries(): bool
return $this->versionId >= 80000;
}

public function supportsThrowExpression(): bool
{
return $this->versionId >= 80000;
}

}
40 changes: 40 additions & 0 deletions src/Rules/Exceptions/ThrowExpressionRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Exceptions;

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Php\PhpVersion;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;

/**
* @implements Rule<Node\Expr\Throw_>
*/
class ThrowExpressionRule implements Rule
{

private PhpVersion $phpVersion;

public function __construct(PhpVersion $phpVersion)
{
$this->phpVersion = $phpVersion;
}

public function getNodeType(): string
{
return Node\Expr\Throw_::class;
}

public function processNode(Node $node, Scope $scope): array
{
if ($this->phpVersion->supportsThrowExpression()) {
return [];
}

return [
RuleErrorBuilder::message('Throw expression is supported only on PHP 8.0 and later.')->nonIgnorable()->build(),
];
}

}
10 changes: 10 additions & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10146,6 +10146,15 @@ public function dataPow(): array
return $this->gatherAssertTypes(__DIR__ . '/data/pow.php');
}

public function dataThrowExpression(): array
{
if (PHP_VERSION_ID < 80000 && !self::$useStaticReflectionProvider) {
return [];
}

return $this->gatherAssertTypes(__DIR__ . '/data/throw-expr.php');
}

/**
* @dataProvider dataBug2574
* @dataProvider dataBug2577
Expand Down Expand Up @@ -10223,6 +10232,7 @@ public function dataPow(): array
* @dataProvider dataBug1014
* @dataProvider dataBugFromPr339
* @dataProvider dataPow
* @dataProvider dataThrowExpression
* @param string $assertType
* @param string $file
* @param mixed ...$args
Expand Down
21 changes: 21 additions & 0 deletions tests/PHPStan/Analyser/data/throw-expr.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php // lint >= 8.0

namespace ThrowExpr;

use function PHPStan\Analyser\assertType;

class Foo
{

public function doFoo(bool $b): void
{
$result = $b ? true : throw new \Exception();
assertType('true', $result);
}

public function doBar(): void
{
assertType('*NEVER*', throw new \Exception());
}

}
53 changes: 53 additions & 0 deletions tests/PHPStan/Rules/Exceptions/ThrowExpressionRuleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Exceptions;

use PHPStan\Php\PhpVersion;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;

/**
* @extends RuleTestCase<ThrowExpressionRule>
*/
class ThrowExpressionRuleTest extends RuleTestCase
{

/** @var PhpVersion */
private $phpVersion;

protected function getRule(): Rule
{
return new ThrowExpressionRule($this->phpVersion);
}

public function dataRule(): array
{
return [
[
70400,
[
[
'Throw expression is supported only on PHP 8.0 and later.',
10,
],
],
],
[
80000,
[],
],
];
}

/**
* @dataProvider dataRule
* @param int $phpVersion
* @param mixed[] $expectedErrors
*/
public function testRule(int $phpVersion, array $expectedErrors): void
{
$this->phpVersion = new PhpVersion($phpVersion);
$this->analyse([__DIR__ . '/data/throw-expr.php'], $expectedErrors);
}

}
15 changes: 15 additions & 0 deletions tests/PHPStan/Rules/Exceptions/data/throw-expr.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace ThrowExpr;

class Bar
{

public function doFoo(bool $b): void
{
$b ? true : throw new \Exception();

throw new \Exception();
}

}

0 comments on commit 5f2d42c

Please sign in to comment.