From 09d34887f805437a216a388aadce4bd83aaaab51 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Fri, 23 Apr 2021 16:15:09 +0200 Subject: [PATCH] Built-in PHP functions without required parameters and no arguments passed do not have implicit throw point --- src/Analyser/NodeScopeResolver.php | 24 ++++++++++++++++--- .../Analyser/NodeScopeResolverTest.php | 1 + tests/PHPStan/Analyser/data/bug-4838.php | 24 +++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 tests/PHPStan/Analyser/data/bug-4838.php diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 4a12206fab..423641eca1 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -1786,9 +1786,27 @@ function (MutatingScope $scope) use ($expr, $nodeCallback, $context): Expression $throwPoints[] = ThrowPoint::createExplicit($scope, $throwType, true); } } elseif ($this->implicitThrows) { - $functionReturnedType = $scope->getType($expr); - if (!(new ObjectType(\Throwable::class))->isSuperTypeOf($functionReturnedType)->yes()) { - $throwPoints[] = ThrowPoint::createImplicit($scope); + $requiredParameters = null; + if ($parametersAcceptor !== null) { + $requiredParameters = 0; + foreach ($parametersAcceptor->getParameters() as $parameter) { + if ($parameter->isOptional()) { + continue; + } + + $requiredParameters++; + } + } + if ( + !$functionReflection->isBuiltin() + || $requiredParameters === null + || $requiredParameters > 0 + || count($expr->args) > 0 + ) { + $functionReturnedType = $scope->getType($expr); + if (!(new ObjectType(\Throwable::class))->isSuperTypeOf($functionReturnedType)->yes()) { + $throwPoints[] = ThrowPoint::createImplicit($scope); + } } } } else { diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index 4f857b815c..10512cbf3b 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -384,6 +384,7 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/data/DateTimeDynamicReturnTypes.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4821.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4838.php'); } /** diff --git a/tests/PHPStan/Analyser/data/bug-4838.php b/tests/PHPStan/Analyser/data/bug-4838.php new file mode 100644 index 0000000000..19f8022517 --- /dev/null +++ b/tests/PHPStan/Analyser/data/bug-4838.php @@ -0,0 +1,24 @@ + 5) { + throw new \LogicException(); + } + } finally { + assertVariableCertainty(TrinaryLogic::createYes(), $handle); + } + } + +}