diff --git a/src/Node/ClassStatementsGatherer.php b/src/Node/ClassStatementsGatherer.php index 71a56858423..b2cc1632a7c 100644 --- a/src/Node/ClassStatementsGatherer.php +++ b/src/Node/ClassStatementsGatherer.php @@ -11,6 +11,7 @@ use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Expr\StaticPropertyFetch; use PhpParser\Node\Identifier; +use PhpParser\Node\Name; use PHPStan\Analyser\Scope; use PHPStan\Node\Constant\ClassConstantFetch; use PHPStan\Node\Expr\SetExistingOffsetValueTypeExpr; @@ -200,7 +201,35 @@ private function gatherNodes(Node $node, Scope $scope): void return; } if ($node instanceof Array_ && count($node->items) === 2) { - $this->methodCalls[] = new \PHPStan\Node\Method\MethodCall($node, $scope); + $firstItem = $node->items[0]; + if (!$firstItem->unpack) { + $firstExpr = $firstItem->value; + if ($firstExpr instanceof Expr\Variable && $firstExpr->name === 'this') { + $this->methodCalls[] = new \PHPStan\Node\Method\MethodCall($node, $scope); + return; + } + + if ( + $firstExpr instanceof Expr\ClassConstFetch + && $firstExpr->name instanceof Identifier + && $firstExpr->name->toLowerString() === 'class' + ) { + if ($firstExpr->class instanceof Name) { + $className = $firstExpr->class->toLowerString(); + if ( + $className === 'self' + || $className === 'static' + || $className === strtolower($this->classReflection->getName()) + ) { + $this->methodCalls[] = new \PHPStan\Node\Method\MethodCall($node, $scope); + return; + } + } elseif ($firstExpr->class instanceof Expr\Variable && $firstExpr->class->name === 'this') { + $this->methodCalls[] = new \PHPStan\Node\Method\MethodCall($node, $scope); + return; + } + } + } return; } if ($node instanceof Expr\ClassConstFetch) { diff --git a/tests/PHPStan/Node/ClassStatementsGathererTest.php b/tests/PHPStan/Node/ClassStatementsGathererTest.php new file mode 100644 index 00000000000..4c3ae884c34 --- /dev/null +++ b/tests/PHPStan/Node/ClassStatementsGathererTest.php @@ -0,0 +1,80 @@ +> + */ +class ClassStatementsGathererTest extends RuleTestCase +{ + + /** + * @return Rule + */ + protected function getRule(): Rule + { + return new /** @implements Rule */ class implements Rule { + + public function getNodeType(): string + { + return ClassMethodsNode::class; + } + + /** + * @param ClassMethodsNode $node + * @return list + */ + public function processNode(Node $node, Scope $scope): array + { + $errors = []; + foreach ($node->getMethodCalls() as $methodCall) { + $callNode = $methodCall->getNode(); + if (!$callNode instanceof Array_) { + continue; + } + + $errors[] = RuleErrorBuilder::message( + sprintf('Gathered callable array on line %d.', $callNode->getStartLine()), + )->line($callNode->getStartLine()) + ->identifier('tests.gatheredCallableArray') + ->build(); + } + + return $errors; + } + + }; + } + + public function testGatherCallableArrays(): void + { + $this->analyse([__DIR__ . '/data/class-statements-gatherer-callable-array.php'], [ + [ + 'Gathered callable array on line 10.', + 10, + ], + [ + 'Gathered callable array on line 11.', + 11, + ], + [ + 'Gathered callable array on line 12.', + 12, + ], + [ + 'Gathered callable array on line 13.', + 13, + ], + ]); + } + +} diff --git a/tests/PHPStan/Node/data/class-statements-gatherer-callable-array.php b/tests/PHPStan/Node/data/class-statements-gatherer-callable-array.php new file mode 100644 index 00000000000..b89dc7ee1bc --- /dev/null +++ b/tests/PHPStan/Node/data/class-statements-gatherer-callable-array.php @@ -0,0 +1,22 @@ +analyse([__DIR__ . '/data/bug-14880.php'], []); } + public function testCallableArrays(): void + { + $this->analyse([__DIR__ . '/data/unused-private-method-callable-arrays.php'], [ + [ + 'Static method UnusedPrivateMethodCallableArrays\Foo::statusKey() is unused.', + 29, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/DeadCode/data/unused-private-method-callable-arrays.php b/tests/PHPStan/Rules/DeadCode/data/unused-private-method-callable-arrays.php new file mode 100644 index 00000000000..b6977fddf50 --- /dev/null +++ b/tests/PHPStan/Rules/DeadCode/data/unused-private-method-callable-arrays.php @@ -0,0 +1,43 @@ +