Skip to content

Commit bc14bda

Browse files
Resolve static type in method @throws
1 parent f9a2208 commit bc14bda

File tree

7 files changed

+111
-3
lines changed

7 files changed

+111
-3
lines changed

src/Analyser/MutatingScope.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3127,7 +3127,7 @@ public function enterClassMethod(
31273127
$this->getParameterAttributes($classMethod),
31283128
$this->transformStaticType($this->getFunctionType($classMethod->returnType, false, false)),
31293129
$phpDocReturnType !== null ? $this->transformStaticType(TemplateTypeHelper::toArgument($phpDocReturnType)) : null,
3130-
$throwType,
3130+
$throwType !== null ? $this->transformStaticType(TemplateTypeHelper::toArgument($throwType)) : null,
31313131
$deprecatedDescription,
31323132
$isDeprecated,
31333133
$isInternal,
@@ -3214,7 +3214,7 @@ public function enterPropertyHook(
32143214
$this->getParameterAttributes($hook),
32153215
$realReturnType,
32163216
$phpDocReturnType,
3217-
$throwType,
3217+
$throwType !== null ? $this->transformStaticType(TemplateTypeHelper::toArgument($throwType)) : null,
32183218
$deprecatedDescription,
32193219
$isDeprecated,
32203220
false,

src/Reflection/Dummy/ChangedTypeMethodReflection.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public function __construct(
2626
private array $variants,
2727
private ?array $namedArgumentsVariants,
2828
private ?Type $selfOutType,
29+
private ?Type $throwType,
2930
)
3031
{
3132
}
@@ -122,7 +123,7 @@ public function isBuiltin(): TrinaryLogic
122123

123124
public function getThrowType(): ?Type
124125
{
125-
return $this->reflection->getThrowType();
126+
return $this->throwType;
126127
}
127128

128129
public function hasSideEffects(): TrinaryLogic

src/Reflection/Type/CallbackUnresolvedMethodPrototypeReflection.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,18 @@ private function transformMethodWithStaticType(ClassReflection $declaringClass,
125125
$namedArgumentVariants = $namedArgumentVariants !== null
126126
? array_map($variantFn, $namedArgumentVariants)
127127
: null;
128+
$throwType = $method->getThrowType();
129+
$throwType = $throwType !== null
130+
? $this->transformStaticType($throwType)
131+
: null;
128132

129133
return new ChangedTypeMethodReflection(
130134
$declaringClass,
131135
$method,
132136
$variants,
133137
$namedArgumentVariants,
134138
$selfOutType,
139+
$throwType,
135140
);
136141
}
137142

src/Reflection/Type/CalledOnTypeUnresolvedMethodPrototypeReflection.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,18 @@ private function transformMethodWithStaticType(ClassReflection $declaringClass,
120120
$namedArgumentsVariants = $namedArgumentsVariants !== null
121121
? array_map($variantFn, $namedArgumentsVariants)
122122
: null;
123+
$throwType = $method->getThrowType();
124+
$throwType = $throwType !== null
125+
? $this->transformStaticType($throwType)
126+
: null;
123127

124128
return new ChangedTypeMethodReflection(
125129
$declaringClass,
126130
$method,
127131
$variants,
128132
$namedArgumentsVariants,
129133
$selfOutType,
134+
$throwType,
130135
);
131136
}
132137

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Exceptions;
4+
5+
use PHPStan\Rules\Rule;
6+
use PHPStan\Testing\RuleTestCase;
7+
use PHPUnit\Framework\Attributes\RequiresPhp;
8+
9+
/**
10+
* @extends RuleTestCase<MissingCheckedExceptionInMethodThrowsRule>
11+
*/
12+
class Bug11900Test extends RuleTestCase
13+
{
14+
15+
protected function getRule(): Rule
16+
{
17+
return new MissingCheckedExceptionInMethodThrowsRule(
18+
new MissingCheckedExceptionInThrowsCheck(new DefaultExceptionTypeResolver(
19+
self::createReflectionProvider(),
20+
[],
21+
[],
22+
[],
23+
[],
24+
)),
25+
);
26+
}
27+
28+
#[RequiresPhp('>= 8.4')]
29+
public function testRule(): void
30+
{
31+
$this->analyse([__DIR__ . '/data/bug-11900.php'], []);
32+
}
33+
34+
public static function getAdditionalConfigFiles(): array
35+
{
36+
return [
37+
__DIR__ . '/bug-11900.neon',
38+
];
39+
}
40+
41+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
parameters:
2+
exceptions:
3+
implicitThrows: false
4+
check:
5+
missingCheckedExceptionInThrows: true
6+
tooWideThrowType: true
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php // lint >= 8.4
2+
3+
namespace Bug11900;
4+
5+
use Exception;
6+
use Throwable;
7+
8+
abstract class ADataException extends Exception
9+
{
10+
/**
11+
* @return void
12+
* @throws static
13+
*/
14+
public function throw1(): void
15+
{
16+
throw $this;
17+
}
18+
19+
/**
20+
* @return void
21+
* @throws static
22+
*/
23+
public static function throw2(): void
24+
{
25+
throw new static();
26+
}
27+
}
28+
29+
final class TestDataException extends ADataException
30+
{
31+
}
32+
33+
class TestPhpStan
34+
{
35+
/**
36+
* @throws TestDataException
37+
*/
38+
public function validate(TestDataException $e): void
39+
{
40+
$e->throw1();
41+
}
42+
43+
/**
44+
* @throws TestDataException
45+
*/
46+
public function validate2(): void
47+
{
48+
TestDataException::throw2();
49+
}
50+
}

0 commit comments

Comments
 (0)