Skip to content

Commit

Permalink
Filter out implicit throw points from callables when `exceptions.impl…
Browse files Browse the repository at this point in the history
…icitThrows: false`

Co-authored-by: Ondrej Mirtes <ondrej@mirtes.cz>
  • Loading branch information
janedbal and ondrejmirtes authored Apr 19, 2024
1 parent 70a75f6 commit e956fad
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 2 deletions.
12 changes: 10 additions & 2 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -2232,7 +2232,11 @@ static function (): void {
$throwPoints = array_merge($throwPoints, $invokeResult->getThrowPoints());
$impurePoints = array_merge($impurePoints, $invokeResult->getImpurePoints());
} elseif ($parametersAcceptor instanceof CallableParametersAcceptor) {
$throwPoints = array_merge($throwPoints, array_map(static fn (SimpleThrowPoint $throwPoint) => $throwPoint->isExplicit() ? ThrowPoint::createExplicit($scope, $throwPoint->getType(), $expr, $throwPoint->canContainAnyThrowable()) : ThrowPoint::createImplicit($scope, $expr), $parametersAcceptor->getThrowPoints()));
$callableThrowPoints = array_map(static fn (SimpleThrowPoint $throwPoint) => $throwPoint->isExplicit() ? ThrowPoint::createExplicit($scope, $throwPoint->getType(), $expr, $throwPoint->canContainAnyThrowable()) : ThrowPoint::createImplicit($scope, $expr), $parametersAcceptor->getThrowPoints());
if (!$this->implicitThrows) {
$callableThrowPoints = array_values(array_filter($callableThrowPoints, static fn (ThrowPoint $throwPoint) => $throwPoint->isExplicit()));
}
$throwPoints = array_merge($throwPoints, $callableThrowPoints);
$impurePoints = array_merge($impurePoints, array_map(static fn (SimpleImpurePoint $impurePoint) => new ImpurePoint($scope, $expr, $impurePoint->getIdentifier(), $impurePoint->getDescription(), $impurePoint->isCertain()), $parametersAcceptor->getImpurePoints()));

$scope = $this->processImmediatelyCalledCallable($scope, $parametersAcceptor->getInvalidateExpressions(), $parametersAcceptor->getUsedVariables());
Expand Down Expand Up @@ -4404,7 +4408,11 @@ private function processArgs(
if (count($acceptors) === 1) {
$scope = $this->processImmediatelyCalledCallable($scope, $acceptors[0]->getInvalidateExpressions(), $acceptors[0]->getUsedVariables());
if ($callCallbackImmediately) {
$throwPoints = array_merge($throwPoints, array_map(static fn (SimpleThrowPoint $throwPoint) => $throwPoint->isExplicit() ? ThrowPoint::createExplicit($scope, $throwPoint->getType(), $arg->value, $throwPoint->canContainAnyThrowable()) : ThrowPoint::createImplicit($scope, $arg->value), $acceptors[0]->getThrowPoints()));
$callableThrowPoints = array_map(static fn (SimpleThrowPoint $throwPoint) => $throwPoint->isExplicit() ? ThrowPoint::createExplicit($scope, $throwPoint->getType(), $arg->value, $throwPoint->canContainAnyThrowable()) : ThrowPoint::createImplicit($scope, $arg->value), $acceptors[0]->getThrowPoints());
if (!$this->implicitThrows) {
$callableThrowPoints = array_values(array_filter($callableThrowPoints, static fn (ThrowPoint $throwPoint) => $throwPoint->isExplicit()));
}
$throwPoints = array_merge($throwPoints, $callableThrowPoints);
$impurePoints = array_merge($impurePoints, array_map(static fn (SimpleImpurePoint $impurePoint) => new ImpurePoint($scope, $arg->value, $impurePoint->getIdentifier(), $impurePoint->getDescription(), $impurePoint->isCertain()), $acceptors[0]->getImpurePoints()));
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php declare(strict_types = 1);

namespace PHPStan\Analyser;

use PHPStan\Testing\TypeInferenceTestCase;
use function array_merge;

class ImmediatelyCalledFunctionWithoutImplicitThrowTest extends TypeInferenceTestCase
{

public function dataFileAsserts(): iterable
{
yield from $this->gatherAssertTypes(__DIR__ . '/data/immediately-called-function-without-implicit-throw.php');
}

/**
* @dataProvider dataFileAsserts
* @param mixed ...$args
*/
public function testFileAsserts(
string $assertType,
string $file,
...$args,
): void
{
$this->assertFileAsserts($assertType, $file, ...$args);
}

public static function getAdditionalConfigFiles(): array
{
return array_merge(
parent::getAdditionalConfigFiles(),
[__DIR__ . '/data/immediately-called-function-without-implicit-throw.neon'],
);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
parameters:
exceptions:
implicitThrows: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace ImmediatelyCalledFunctionWithoutImplicitThrow;

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

try {
$result = array_map('ucfirst', []);
} finally {
assertVariableCertainty(TrinaryLogic::createYes(), $result);
}

class SomeClass
{

public function noThrow(): void
{
}

public function testFirstClassCallableNoThrow(): void
{
try {
$result = array_map($this->noThrow(...), []);
} finally {
assertVariableCertainty(TrinaryLogic::createYes(), $result);
}
}

}

0 comments on commit e956fad

Please sign in to comment.