Skip to content

Commit 4e890a3

Browse files
committed
Use scope by method name
1 parent b1f4ec6 commit 4e890a3

File tree

5 files changed

+83
-17
lines changed

5 files changed

+83
-17
lines changed

Diff for: src/Rules/Methods/CallMethodsRule.php

+14-5
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33
namespace PHPStan\Rules\Methods;
44

55
use PhpParser\Node;
6+
use PhpParser\Node\Expr\BinaryOp\Identical;
67
use PhpParser\Node\Expr\MethodCall;
8+
use PhpParser\Node\Scalar\String_;
79
use PHPStan\Analyser\Scope;
810
use PHPStan\Internal\SprintfHelper;
911
use PHPStan\Reflection\ParametersAcceptorSelector;
1012
use PHPStan\Rules\FunctionCallParametersCheck;
1113
use PHPStan\Rules\IdentifierRuleError;
1214
use PHPStan\Rules\Rule;
1315
use PHPStan\Type\Constant\ConstantStringType;
16+
use function array_column;
1417
use function array_map;
1518
use function array_merge;
1619

@@ -36,14 +39,20 @@ public function processNode(Node $node, Scope $scope): array
3639
{
3740
$errors = [];
3841
if ($node->name instanceof Node\Identifier) {
39-
$methodNames = [$node->name->name];
42+
$methodNameScopes = [$node->name->name => $scope];
4043
} else {
41-
$callType = $scope->getType($node->name);
42-
$methodNames = array_map(static fn (ConstantStringType $type): string => $type->getValue(), $callType->getConstantStrings());
44+
$nameType = $scope->getType($node->name);
45+
$methodNameScopes = array_column(array_map(
46+
static fn (ConstantStringType $constantString) => [
47+
$name = $constantString->getValue(),
48+
$scope->filterByTruthyValue(new Identical($node->name, new String_($name))),
49+
],
50+
$nameType->getConstantStrings(),
51+
), 1, 0);
4352
}
4453

45-
foreach ($methodNames as $methodName) {
46-
$errors = array_merge($errors, $this->processSingleMethodCall($scope, $node, $methodName));
54+
foreach ($methodNameScopes as $methodName => $methodScope) {
55+
$errors = array_merge($errors, $this->processSingleMethodCall($methodScope, $node, $methodName));
4756
}
4857

4958
return $errors;

Diff for: src/Rules/Methods/CallStaticMethodsRule.php

+14-5
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33
namespace PHPStan\Rules\Methods;
44

55
use PhpParser\Node;
6+
use PhpParser\Node\Expr\BinaryOp\Identical;
67
use PhpParser\Node\Expr\StaticCall;
8+
use PhpParser\Node\Scalar\String_;
79
use PHPStan\Analyser\Scope;
810
use PHPStan\Internal\SprintfHelper;
911
use PHPStan\Reflection\ParametersAcceptorSelector;
1012
use PHPStan\Rules\FunctionCallParametersCheck;
1113
use PHPStan\Rules\IdentifierRuleError;
1214
use PHPStan\Rules\Rule;
1315
use PHPStan\Type\Constant\ConstantStringType;
16+
use function array_column;
1417
use function array_map;
1518
use function array_merge;
1619
use function sprintf;
@@ -37,14 +40,20 @@ public function processNode(Node $node, Scope $scope): array
3740
{
3841
$errors = [];
3942
if ($node->name instanceof Node\Identifier) {
40-
$methodNames = [$node->name->name];
43+
$methodNameScopes = [$node->name->name => $scope];
4144
} else {
42-
$callType = $scope->getType($node->name);
43-
$methodNames = array_map(static fn (ConstantStringType $type): string => $type->getValue(), $callType->getConstantStrings());
45+
$nameType = $scope->getType($node->name);
46+
$methodNameScopes = array_column(array_map(
47+
static fn (ConstantStringType $constantString) => [
48+
$name = $constantString->getValue(),
49+
$scope->filterByTruthyValue(new Identical($node->name, new String_($name))),
50+
],
51+
$nameType->getConstantStrings(),
52+
), 1, 0);
4453
}
4554

46-
foreach ($methodNames as $methodName) {
47-
$errors = array_merge($errors, $this->processSingleMethodCall($scope, $node, $methodName));
55+
foreach ($methodNameScopes as $methodName => $methodScope) {
56+
$errors = array_merge($errors, $this->processSingleMethodCall($methodScope, $node, $methodName));
4857
}
4958

5059
return $errors;

Diff for: tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php

+14-2
Original file line numberDiff line numberDiff line change
@@ -3565,13 +3565,25 @@ public function testDynamicCall(): void
35653565
23,
35663566
],
35673567
[
3568-
'Call to an undefined method MethodsDynamicCall\Foo::bar().',
3568+
'Call to an undefined method MethodsDynamicCall\Foo::doBar().',
35693569
26,
35703570
],
35713571
[
3572-
'Call to an undefined method MethodsDynamicCall\Foo::buz().',
3572+
'Call to an undefined method MethodsDynamicCall\Foo::doBuz().',
35733573
26,
35743574
],
3575+
[
3576+
'Parameter #1 $n of method MethodsDynamicCall\Foo::doFoo() expects int, int|string given.',
3577+
53,
3578+
],
3579+
[
3580+
'Parameter #1 $s of method MethodsDynamicCall\Foo::doQux() expects string, int given.',
3581+
54,
3582+
],
3583+
[
3584+
'Parameter #1 $n of method MethodsDynamicCall\Foo::doFoo() expects int, string given.',
3585+
55,
3586+
],
35753587
]);
35763588
}
35773589

Diff for: tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php

+14-2
Original file line numberDiff line numberDiff line change
@@ -874,13 +874,25 @@ public function testDynamicCall(): void
874874
33,
875875
],
876876
[
877-
'Call to an undefined static method MethodsDynamicCall\Foo::bar().',
877+
'Call to an undefined static method MethodsDynamicCall\Foo::doBar().',
878878
36,
879879
],
880880
[
881-
'Call to an undefined static method MethodsDynamicCall\Foo::buz().',
881+
'Call to an undefined static method MethodsDynamicCall\Foo::doBuz().',
882882
36,
883883
],
884+
[
885+
'Parameter #1 $n of method MethodsDynamicCall\Foo::doFoo() expects int, int|string given.',
886+
58,
887+
],
888+
[
889+
'Parameter #1 $s of static method MethodsDynamicCall\Foo::doQux() expects string, int given.',
890+
59,
891+
],
892+
[
893+
'Parameter #1 $n of method MethodsDynamicCall\Foo::doFoo() expects int, string given.',
894+
60,
895+
],
884896
]);
885897
}
886898

Diff for: tests/PHPStan/Rules/Methods/data/dynamic-call.php

+27-3
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
final class Foo
66
{
77

8-
/** @var 'foo'|'bar'|'buz'|'qux' */
8+
/** @var 'doFoo'|'doBar'|'doBuz'|'doQux' */
99
public static $name;
1010

11-
public function foo(): void
11+
public function doFoo(int $n = 0): void
1212
{
1313
}
1414

15-
public static function qux(): void
15+
public static function doQux(string $s = 'default'): void
1616
{
1717
}
1818

@@ -35,4 +35,28 @@ public function testStaticCall(string $string, object $obj): void
3535
echo self::$obj();
3636
echo self::{self::$name}();
3737
}
38+
39+
public function testScope(): void
40+
{
41+
$param1 = 1;
42+
$param2 = 'str';
43+
$name1 = 'doFoo';
44+
if (rand(0, 1)) {
45+
$name = $name1;
46+
$param = $param1;
47+
} else {
48+
$name = 'doQux';
49+
$param = $param2;
50+
}
51+
52+
$this->$name($param); // ok
53+
$this->$name1($param);
54+
$this->$name($param1);
55+
$this->$name($param2);
56+
57+
self::$name($param); // ok
58+
self::$name1($param);
59+
self::$name($param1);
60+
self::$name($param2);
61+
}
3862
}

0 commit comments

Comments
 (0)