Skip to content

Commit c8fc6ca

Browse files
staabmngmy
authored andcommitted
Detect callables in any static array (TomasVotruba#140)
* Detect callables in any static array * more tests * Update CallableTypeCollector.php
1 parent 44f9b16 commit c8fc6ca

File tree

8 files changed

+45
-39
lines changed

8 files changed

+45
-39
lines changed

config/extension.neon

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ services:
101101
- phpstan.collector
102102

103103
-
104-
class: TomasVotruba\UnusedPublic\Collectors\Callable_\CallbackFunctionCollector
104+
class: TomasVotruba\UnusedPublic\Collectors\Callable_\CallableTypeCollector
105105
tags:
106106
- phpstan.collector
107107

src/Collectors/Callable_/CallbackFunctionCollector.php src/Collectors/Callable_/CallableTypeCollector.php

+5-30
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
use TomasVotruba\UnusedPublic\Configuration;
1414

1515
/**
16-
* @implements Collector<FuncCall, non-empty-array<string>|null>
16+
* @implements Collector<Expr\Array_, non-empty-array<string>|null>
1717
*/
18-
final readonly class CallbackFunctionCollector implements Collector
18+
final readonly class CallableTypeCollector implements Collector
1919
{
2020
public function __construct(
2121
private Configuration $configuration,
@@ -24,11 +24,11 @@ public function __construct(
2424

2525
public function getNodeType(): string
2626
{
27-
return FuncCall::class;
27+
return Expr\Array_::class;
2828
}
2929

3030
/**
31-
* @param FuncCall $node
31+
* @param Expr\Array_ $node
3232
* @return string[]|null
3333
*/
3434
public function processNode(Node $node, Scope $scope): ?array
@@ -37,16 +37,7 @@ public function processNode(Node $node, Scope $scope): ?array
3737
return null;
3838
}
3939

40-
if ($this->shouldSkipNode($node)) {
41-
return null;
42-
}
43-
44-
$args = $node->getArgs();
45-
if (count($args) < 1) {
46-
return null;
47-
}
48-
49-
$callableType = $scope->getType($args[0]->value);
40+
$callableType = $scope->getType($node);
5041
if (! $callableType instanceof ConstantArrayType) {
5142
return null;
5243
}
@@ -72,20 +63,4 @@ public function processNode(Node $node, Scope $scope): ?array
7263
return $classMethodReferences;
7364
}
7465

75-
/**
76-
* @param FuncCall $node
77-
*/
78-
private function shouldSkipNode(Node $node): bool
79-
{
80-
// unable to resolve method name
81-
if ($node->name instanceof Expr) {
82-
return true;
83-
}
84-
85-
return !in_array(
86-
strtolower($node->name->toString()),
87-
['call_user_func', 'register_shutdown_function'],
88-
true
89-
);
90-
}
9166
}

src/NodeCollectorExtractor.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use PHPStan\Node\CollectedDataNode;
88
use TomasVotruba\UnusedPublic\CollectorMapper\MethodCallCollectorMapper;
99
use TomasVotruba\UnusedPublic\Collectors\Callable_\AttributeCallableCollector;
10-
use TomasVotruba\UnusedPublic\Collectors\Callable_\CallbackFunctionCollector;
10+
use TomasVotruba\UnusedPublic\Collectors\Callable_\CallableTypeCollector;
1111
use TomasVotruba\UnusedPublic\Collectors\MethodCall\MethodCallableCollector;
1212
use TomasVotruba\UnusedPublic\Collectors\MethodCall\MethodCallCollector;
1313
use TomasVotruba\UnusedPublic\Collectors\StaticCall\StaticMethodCallableCollector;
@@ -49,7 +49,7 @@ private function extractCollectedDatas(CollectedDataNode $collectedDataNode): ar
4949
$collectedDataNode->get(StaticMethodCallCollector::class),
5050
$collectedDataNode->get(StaticMethodCallableCollector::class),
5151
$collectedDataNode->get(AttributeCallableCollector::class),
52-
$collectedDataNode->get(CallbackFunctionCollector::class),
52+
$collectedDataNode->get(CallableTypeCollector::class),
5353
];
5454
}
5555
}

tests/Rules/LocalOnlyPublicClassMethodRule/LocalOnlyPublicClassMethodRuleTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use PHPStan\Testing\RuleTestCase;
1111
use PHPUnit\Framework\Attributes\DataProvider;
1212
use TomasVotruba\UnusedPublic\Collectors\Callable_\AttributeCallableCollector;
13-
use TomasVotruba\UnusedPublic\Collectors\Callable_\CallbackFunctionCollector;
13+
use TomasVotruba\UnusedPublic\Collectors\Callable_\CallableTypeCollector;
1414
use TomasVotruba\UnusedPublic\Collectors\MethodCall\MethodCallCollector;
1515
use TomasVotruba\UnusedPublic\Collectors\PublicClassMethodCollector;
1616
use TomasVotruba\UnusedPublic\Collectors\StaticCall\StaticMethodCallCollector;
@@ -91,7 +91,7 @@ protected function getCollectors(): array
9191
self::getContainer()->getByType(MethodCallCollector::class),
9292
self::getContainer()->getByType(StaticMethodCallCollector::class),
9393
self::getContainer()->getByType(AttributeCallableCollector::class),
94-
self::getContainer()->getByType(CallbackFunctionCollector::class),
94+
self::getContainer()->getByType(CallableTypeCollector::class),
9595
];
9696
}
9797

tests/Rules/RelativeUnusedPublicClassMethodRule/RelativeUnusedPublicClassMethodRuleTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use PHPStan\Testing\RuleTestCase;
1111
use PHPUnit\Framework\Attributes\DataProvider;
1212
use TomasVotruba\UnusedPublic\Collectors\Callable_\AttributeCallableCollector;
13-
use TomasVotruba\UnusedPublic\Collectors\Callable_\CallbackFunctionCollector;
13+
use TomasVotruba\UnusedPublic\Collectors\Callable_\CallableTypeCollector;
1414
use TomasVotruba\UnusedPublic\Collectors\FormTypeClassCollector;
1515
use TomasVotruba\UnusedPublic\Collectors\MethodCall\MethodCallableCollector;
1616
use TomasVotruba\UnusedPublic\Collectors\MethodCall\MethodCallCollector;
@@ -64,7 +64,7 @@ protected function getCollectors(): array
6464
// callables
6565
self::getContainer()->getByType(StaticMethodCallableCollector::class),
6666
self::getContainer()->getByType(AttributeCallableCollector::class),
67-
self::getContainer()->getByType(CallbackFunctionCollector::class),
67+
self::getContainer()->getByType(CallableTypeCollector::class),
6868
];
6969
}
7070

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TomasVotruba\UnusedPublic\Tests\Rules\UnusedPublicClassMethodRule\Fixture;
6+
7+
/**
8+
* @var \TomasVotruba\UnusedPublic\Tests\Rules\UnusedPublicClassMethodRule\Source\Caller1 $caller1
9+
*/
10+
11+
myFunc([$caller1, 'callIt']);
12+
13+
function myFunc(callable $c) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TomasVotruba\UnusedPublic\Tests\Rules\UnusedPublicClassMethodRule\Fixture;
6+
7+
/**
8+
* @var \TomasVotruba\UnusedPublic\Tests\Rules\UnusedPublicClassMethodRule\Source\Caller1 $caller1
9+
*/
10+
11+
$c = new MyClass();
12+
$c->myMethod([$caller1, 'callIt']);
13+
14+
class MyClass {
15+
function myMethod(callable $c) {}
16+
}

tests/Rules/UnusedPublicClassMethodRule/UnusedPublicClassMethodRuleTest.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use PHPStan\Testing\RuleTestCase;
1111
use PHPUnit\Framework\Attributes\DataProvider;
1212
use TomasVotruba\UnusedPublic\Collectors\Callable_\AttributeCallableCollector;
13-
use TomasVotruba\UnusedPublic\Collectors\Callable_\CallbackFunctionCollector;
13+
use TomasVotruba\UnusedPublic\Collectors\Callable_\CallableTypeCollector;
1414
use TomasVotruba\UnusedPublic\Collectors\FormTypeClassCollector;
1515
use TomasVotruba\UnusedPublic\Collectors\MethodCall\MethodCallableCollector;
1616
use TomasVotruba\UnusedPublic\Collectors\MethodCall\MethodCallCollector;
@@ -177,6 +177,8 @@ public static function provideData(): Iterator
177177
yield [[__DIR__ . '/Fixture/plain.php', __DIR__ . '/Source/Caller1.php'], []];
178178
yield [[__DIR__ . '/Fixture/plain-call-user-func.php', __DIR__ . '/Source/Caller1.php'], []];
179179
yield [[__DIR__ . '/Fixture/plain-call-shutdown-function.php', __DIR__ . '/Source/Caller1.php'], []];
180+
yield [[__DIR__ . '/Fixture/plain-call-custom-function.php', __DIR__ . '/Source/Caller1.php'], []];
181+
yield [[__DIR__ . '/Fixture/plain-call-custom-method.php', __DIR__ . '/Source/Caller1.php'], []];
180182
yield [[__DIR__ . '/Fixture/SkipCrashBug89.php.inc'], []];
181183

182184
// internal
@@ -241,7 +243,7 @@ protected function getCollectors(): array
241243
// callables
242244
self::getContainer()->getByType(StaticMethodCallableCollector::class),
243245
self::getContainer()->getByType(AttributeCallableCollector::class),
244-
self::getContainer()->getByType(CallbackFunctionCollector::class),
246+
self::getContainer()->getByType(CallableTypeCollector::class),
245247
];
246248
}
247249

0 commit comments

Comments
 (0)