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
8 changes: 8 additions & 0 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -3619,6 +3619,14 @@ static function (): void {
$exprType = $scope->getType($expr->expr);
$toStringMethod = $scope->getMethodReflection($exprType, '__toString');
if ($toStringMethod !== null) {
if ($this->phpVersion->throwsOnStringCast()) {
if ($toStringMethod->getThrowType() !== null) {
$throwPoints[] = InternalThrowPoint::createExplicit($scope, $toStringMethod->getThrowType(), $expr, false);
} else {
$throwPoints[] = InternalThrowPoint::createImplicit($scope, $expr);
}
}

if (!$toStringMethod->hasSideEffects()->no()) {
$impurePoints[] = new ImpurePoint(
$scope,
Expand Down
5 changes: 5 additions & 0 deletions src/Php/PhpVersion.php
Original file line number Diff line number Diff line change
Expand Up @@ -479,4 +479,9 @@ public function deprecatesIncOnNonNumericString(): bool
return $this->versionId >= 80500;
}

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

}
Original file line number Diff line number Diff line change
Expand Up @@ -643,4 +643,14 @@ public function testPropertyHooks(): void
]);
}

public function testBug13806(): void
{
$this->analyse([__DIR__ . '/data/bug-13806.php'], [
[
'Dead catch - InvalidArgumentException is never thrown in the try block.',
16,
],
]);
}

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

namespace Bug13806;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this lack of test,

It should add a test for

function doFoo(Stringable $myVariable): void

to check the implicit throw tag

and a test for

class MyStringVoid {
	/** @throws void */
	public function __toString() {
		throw new \InvalidArgumentException();
	}
}

to check in this case the catch is reported as dead catch


function doFoo(MyString $myVariable, MyStringVoid $string, $mixed): void
{
try {
(string) $myVariable;
} catch (\InvalidArgumentException $e) {
// Reported as dead catch, even though the `__toString()` method
// in `$myVariable` might throw an exception.
}

try {
(string) $string;
} catch (\InvalidArgumentException $e) {
}

try {
(string) $mixed;
} catch (\InvalidArgumentException $e) {
}
}

class MyString {
/** @throws \InvalidArgumentException */
public function __toString() {
throw new \InvalidArgumentException();
}
}

class MyStringVoid {
/** @throws void */
public function __toString()
{
throw new \InvalidArgumentException();
}
}
Loading