Skip to content

Commit b0fac99

Browse files
ondrejmirtesstaabm
authored andcommitted
Resolve method reflection for $var::method() static calls
- When $expr->class is an Expr (variable), resolve method reflection and parameters acceptor using getObjectTypeOrClassStringObjectType() so by-reference parameters and other argument analysis work correctly - Guard $this invalidation and constructor property initialization blocks with $expr->class instanceof Name to prevent $other::__construct() from incorrectly affecting $this - New regression test in tests/PHPStan/Analyser/nsrt/bug-5020.php
1 parent 8717c5d commit b0fac99

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

src/Analyser/NodeScopeResolver.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3381,6 +3381,25 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto
33813381
foreach ($additionalThrowPoints as $throwPoint) {
33823382
$throwPoints[] = $throwPoint;
33833383
}
3384+
3385+
if ($expr->name instanceof Identifier && $methodReflection === null) {
3386+
$staticMethodCalledOnType = TypeCombinator::removeNull($scope->getType($expr->class))->getObjectTypeOrClassStringObjectType();
3387+
$methodName = $expr->name->name;
3388+
if ($staticMethodCalledOnType->hasMethod($methodName)->yes()) {
3389+
$methodReflection = $staticMethodCalledOnType->getMethod($methodName, $scope);
3390+
$parametersAcceptor = ParametersAcceptorSelector::selectFromArgs(
3391+
$scope,
3392+
$expr->getArgs(),
3393+
$methodReflection->getVariants(),
3394+
$methodReflection->getNamedArgumentsVariants(),
3395+
);
3396+
3397+
$methodThrowPoint = $this->getStaticMethodThrowPoint($methodReflection, $parametersAcceptor, $expr, $scope);
3398+
if ($methodThrowPoint !== null) {
3399+
$throwPoints[] = $methodThrowPoint;
3400+
}
3401+
}
3402+
}
33843403
}
33853404

33863405
if ($methodReflection !== null) {
@@ -3410,6 +3429,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto
34103429

34113430
if (
34123431
$methodReflection !== null
3432+
&& $expr->class instanceof Name
34133433
&& (
34143434
(
34153435
!$methodReflection->isStatic()
@@ -3425,6 +3445,7 @@ function (MutatingScope $scope) use ($stmt, $expr, $nodeCallback, $context, $sto
34253445

34263446
if (
34273447
$methodReflection !== null
3448+
&& $expr->class instanceof Name
34283449
&& !$methodReflection->isStatic()
34293450
&& $methodReflection->getName() === '__construct'
34303451
&& $scopeFunction instanceof MethodReflection
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
namespace Bug5020;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
interface ITransformer
8+
{
9+
public static function Transform(string $theInput, bool &$theErrorEncountered): string;
10+
}
11+
12+
class Transformer implements ITransformer
13+
{
14+
public static function Transform(string $theInput, bool &$theErrorEncountered): string
15+
{
16+
if ($theInput === 'invalid') {
17+
$theErrorEncountered = true;
18+
return '';
19+
}
20+
return strtoupper(trim($theInput));
21+
}
22+
}
23+
24+
function testConstantStringStaticCall(): void
25+
{
26+
$transformer = 'Bug5020\Transformer';
27+
$input = ' asdasda asdasd ';
28+
$error = false;
29+
$output = $transformer::Transform($input, $error);
30+
assertType('string', $output);
31+
assertType('bool', $error);
32+
}
33+
34+
function testDirectStaticCall(): void
35+
{
36+
$input = ' asdasda asdasd ';
37+
$error = false;
38+
$output = Transformer::Transform($input, $error);
39+
assertType('string', $output);
40+
assertType('bool', $error);
41+
}
42+
43+
function testClassStringStaticCall(): void
44+
{
45+
/** @var class-string<ITransformer> $transformer */
46+
$transformer = 'Bug5020\Transformer';
47+
$input = ' asdasda asdasd ';
48+
$error = false;
49+
$output = $transformer::Transform($input, $error);
50+
assertType('string', $output);
51+
assertType('bool', $error);
52+
}

0 commit comments

Comments
 (0)