Skip to content
Open
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
4 changes: 3 additions & 1 deletion src/Analyser/StatementsHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,9 @@ public function getOverridingThrowPoints(Node\Stmt $statement, MutatingScope $sc
return [];
}

return [InternalThrowPoint::createExplicit($scope, $throwsType, $statement, false)];
$fromThrowExpr = $statement instanceof Node\Stmt\Expression && $statement->expr instanceof Expr\Throw_;

return [InternalThrowPoint::createExplicit($scope, $throwsType, $statement, false, $fromThrowExpr)];
}
}

Expand Down
6 changes: 1 addition & 5 deletions src/Analyser/StmtHandler/TryCatchHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,7 @@ public function processStmt(
if (!$throwPoint->isExplicit()) {
continue;
}
$throwNode = $throwPoint->getNode();
if (
!$throwNode instanceof Expr\Throw_
&& !($throwNode instanceof Node\Stmt\Expression && $throwNode->expr instanceof Expr\Throw_)
) {
if (!$throwPoint->isFromThrowExpr()) {
$onlyExplicitIsThrow = false;
}

Expand Down
57 changes: 57 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-14990.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php declare(strict_types = 1);

namespace Bug14990;

use PHPStan\TrinaryLogic;
use function PHPStan\Testing\assertType;
use function PHPStan\Testing\assertVariableCertainty;

class Thing {}

class Db
{
// Throws are only INFERRED from the body (no @throws tag).
public static function getThing(): Thing
{
if (rand(0, 1) === 0) {
throw new \Exception('no data');
}
return new Thing();
}
}

class Helper
{
/** @throws \Exception */
public static function mightThrow(): void
{
if (rand(0, 1)) {
throw new \Exception('boom');
}
}
}

function doFoo(): void
{
$thing = null;

try {
$thing = Db::getThing();
Helper::mightThrow();
} catch (\Exception $e) {
assertType('Bug14990\Thing|null', $thing);
if ($thing === null) {
echo 'thing not set';
}
}
}

function doBar(): void
{
try {
$thing = Db::getThing();
Helper::mightThrow();
} catch (\Exception $e) {
assertVariableCertainty(TrinaryLogic::createMaybe(), $thing);
}
}
92 changes: 92 additions & 0 deletions tests/PHPStan/Analyser/nsrt/explicit-throws.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,98 @@ public function doBaz(): void
}
}

public function doThrowInArrowFunctionArg(): void
{
try {
doFoo();
$a = 1;
array_map(static fn (int $i) => throw new \InvalidArgumentException(), [1, 2]);
} catch (\InvalidArgumentException $e) {
assertVariableCertainty(TrinaryLogic::createMaybe(), $a);
}
}

public function doThrowInClosureArg(): void
{
try {
doFoo();
$a = 1;
array_map(static function (int $i): int {
throw new \InvalidArgumentException();
}, [1, 2]);
} catch (\InvalidArgumentException $e) {
assertVariableCertainty(TrinaryLogic::createMaybe(), $a);
}
}

public function doThrowInCalledClosure(): void
{
$callback = static function (): void {
throw new \InvalidArgumentException();
};
try {
doFoo();
$a = 1;
$callback();
} catch (\InvalidArgumentException $e) {
assertVariableCertainty(TrinaryLogic::createMaybe(), $a);
}
}

public function doThrowInImmediatelyInvokedClosure(): void
{
try {
doFoo();
$a = 1;
(static function (): void {
throw new \InvalidArgumentException();
})();
} catch (\InvalidArgumentException $e) {
assertVariableCertainty(TrinaryLogic::createMaybe(), $a);
}
}

public function doThrowInClosureVariablePassedAsCallable(): void
{
$callback = static function (int $i): int {
throw new \InvalidArgumentException();
};
try {
doFoo();
$a = 1;
array_map($callback, [1, 2]);
} catch (\InvalidArgumentException $e) {
assertVariableCertainty(TrinaryLogic::createMaybe(), $a);
}
}

public function doAnnotatedThrowStatement(): void
{
try {
doFoo();
$a = 1;
/** @throws \InvalidArgumentException */
throw new \InvalidArgumentException();
} catch (\InvalidArgumentException $e) {
assertVariableCertainty(TrinaryLogic::createMaybe(), $a);
}
}

public function doDocumentedThrowInClosureArg(): void
{
try {
doFoo();
$a = 1;
array_map(function (int $i): int {
$this->throwInvalidArgument();

return $i;
}, [1, 2]);
} catch (\InvalidArgumentException $e) {
assertVariableCertainty(TrinaryLogic::createYes(), $a);
}
}

/**
* @throws \InvalidArgumentException
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,11 @@ public function testBug14966(): void
$this->analyse([__DIR__ . '/data/bug-14966.php'], []);
}

public function testBug14990(): void
{
$this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-14990.php'], []);
}

public function testBug14847(): void
{
$this->analyse([__DIR__ . '/data/bug-14847.php'], [
Expand Down
Loading