Skip to content

Commit

Permalink
Detect callables in any static array (#140)
Browse files Browse the repository at this point in the history
* Detect callables in any static array

* more tests

* Update CallableTypeCollector.php
  • Loading branch information
staabm authored Dec 6, 2024
1 parent 177f344 commit 3051615
Show file tree
Hide file tree
Showing 8 changed files with 45 additions and 39 deletions.
2 changes: 1 addition & 1 deletion config/extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ services:
- phpstan.collector

-
class: TomasVotruba\UnusedPublic\Collectors\Callable_\CallbackFunctionCollector
class: TomasVotruba\UnusedPublic\Collectors\Callable_\CallableTypeCollector
tags:
- phpstan.collector

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
use TomasVotruba\UnusedPublic\Configuration;

/**
* @implements Collector<FuncCall, non-empty-array<string>|null>
* @implements Collector<Expr\Array_, non-empty-array<string>|null>
*/
final readonly class CallbackFunctionCollector implements Collector
final readonly class CallableTypeCollector implements Collector
{
public function __construct(
private Configuration $configuration,
Expand All @@ -27,11 +27,11 @@ public function __construct(

public function getNodeType(): string
{
return FuncCall::class;
return Expr\Array_::class;
}

/**
* @param FuncCall $node
* @param Expr\Array_ $node
* @return string[]|null
*/
public function processNode(Node $node, Scope $scope): ?array
Expand All @@ -40,23 +40,14 @@ public function processNode(Node $node, Scope $scope): ?array
return null;
}

if ($this->shouldSkipNode($node)) {
return null;
}

$args = $node->getArgs();
if (count($args) < 1) {
return null;
}

// skip calls in tests, as they are not used in production
$classReflection = $scope->getClassReflection();
if ($classReflection instanceof ClassReflection
&& $this->classTypeDetector->isTestClass($classReflection)) {
return null;
}

$callableType = $scope->getType($args[0]->value);
$callableType = $scope->getType($node);
if (! $callableType instanceof ConstantArrayType) {
return null;
}
Expand All @@ -82,20 +73,4 @@ public function processNode(Node $node, Scope $scope): ?array
return $classMethodReferences;
}

/**
* @param FuncCall $node
*/
private function shouldSkipNode(Node $node): bool
{
// unable to resolve method name
if ($node->name instanceof Expr) {
return true;
}

return !in_array(
strtolower($node->name->toString()),
['call_user_func', 'register_shutdown_function'],
true
);
}
}
4 changes: 2 additions & 2 deletions src/NodeCollectorExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use PHPStan\Node\CollectedDataNode;
use TomasVotruba\UnusedPublic\CollectorMapper\MethodCallCollectorMapper;
use TomasVotruba\UnusedPublic\Collectors\Callable_\AttributeCallableCollector;
use TomasVotruba\UnusedPublic\Collectors\Callable_\CallbackFunctionCollector;
use TomasVotruba\UnusedPublic\Collectors\Callable_\CallableTypeCollector;
use TomasVotruba\UnusedPublic\Collectors\MethodCall\MethodCallableCollector;
use TomasVotruba\UnusedPublic\Collectors\MethodCall\MethodCallCollector;
use TomasVotruba\UnusedPublic\Collectors\StaticCall\StaticMethodCallableCollector;
Expand Down Expand Up @@ -48,7 +48,7 @@ private function extractCollectedDatas(CollectedDataNode $collectedDataNode): ar
$collectedDataNode->get(StaticMethodCallCollector::class),
$collectedDataNode->get(StaticMethodCallableCollector::class),
$collectedDataNode->get(AttributeCallableCollector::class),
$collectedDataNode->get(CallbackFunctionCollector::class),
$collectedDataNode->get(CallableTypeCollector::class),
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use PHPStan\Testing\RuleTestCase;
use PHPUnit\Framework\Attributes\DataProvider;
use TomasVotruba\UnusedPublic\Collectors\Callable_\AttributeCallableCollector;
use TomasVotruba\UnusedPublic\Collectors\Callable_\CallbackFunctionCollector;
use TomasVotruba\UnusedPublic\Collectors\Callable_\CallableTypeCollector;
use TomasVotruba\UnusedPublic\Collectors\MethodCall\MethodCallCollector;
use TomasVotruba\UnusedPublic\Collectors\PublicClassMethodCollector;
use TomasVotruba\UnusedPublic\Collectors\StaticCall\StaticMethodCallCollector;
Expand Down Expand Up @@ -80,7 +80,7 @@ protected function getCollectors(): array
self::getContainer()->getByType(MethodCallCollector::class),
self::getContainer()->getByType(StaticMethodCallCollector::class),
self::getContainer()->getByType(AttributeCallableCollector::class),
self::getContainer()->getByType(CallbackFunctionCollector::class),
self::getContainer()->getByType(CallableTypeCollector::class),
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use PHPStan\Testing\RuleTestCase;
use PHPUnit\Framework\Attributes\DataProvider;
use TomasVotruba\UnusedPublic\Collectors\Callable_\AttributeCallableCollector;
use TomasVotruba\UnusedPublic\Collectors\Callable_\CallbackFunctionCollector;
use TomasVotruba\UnusedPublic\Collectors\Callable_\CallableTypeCollector;
use TomasVotruba\UnusedPublic\Collectors\FormTypeClassCollector;
use TomasVotruba\UnusedPublic\Collectors\MethodCall\MethodCallableCollector;
use TomasVotruba\UnusedPublic\Collectors\MethodCall\MethodCallCollector;
Expand Down Expand Up @@ -64,7 +64,7 @@ protected function getCollectors(): array
// callables
self::getContainer()->getByType(StaticMethodCallableCollector::class),
self::getContainer()->getByType(AttributeCallableCollector::class),
self::getContainer()->getByType(CallbackFunctionCollector::class),
self::getContainer()->getByType(CallableTypeCollector::class),
];
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace TomasVotruba\UnusedPublic\Tests\Rules\UnusedPublicClassMethodRule\Fixture;

/**
* @var \TomasVotruba\UnusedPublic\Tests\Rules\UnusedPublicClassMethodRule\Source\Caller1 $caller1
*/

myFunc([$caller1, 'callIt']);

function myFunc(callable $c) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace TomasVotruba\UnusedPublic\Tests\Rules\UnusedPublicClassMethodRule\Fixture;

/**
* @var \TomasVotruba\UnusedPublic\Tests\Rules\UnusedPublicClassMethodRule\Source\Caller1 $caller1
*/

$c = new MyClass();
$c->myMethod([$caller1, 'callIt']);

class MyClass {
function myMethod(callable $c) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use PHPStan\Testing\RuleTestCase;
use PHPUnit\Framework\Attributes\DataProvider;
use TomasVotruba\UnusedPublic\Collectors\Callable_\AttributeCallableCollector;
use TomasVotruba\UnusedPublic\Collectors\Callable_\CallbackFunctionCollector;
use TomasVotruba\UnusedPublic\Collectors\Callable_\CallableTypeCollector;
use TomasVotruba\UnusedPublic\Collectors\FormTypeClassCollector;
use TomasVotruba\UnusedPublic\Collectors\MethodCall\MethodCallableCollector;
use TomasVotruba\UnusedPublic\Collectors\MethodCall\MethodCallCollector;
Expand Down Expand Up @@ -175,6 +175,8 @@ public static function provideData(): Iterator
yield [[__DIR__ . '/Fixture/plain.php', __DIR__ . '/Source/Caller1.php'], []];
yield [[__DIR__ . '/Fixture/plain-call-user-func.php', __DIR__ . '/Source/Caller1.php'], []];
yield [[__DIR__ . '/Fixture/plain-call-shutdown-function.php', __DIR__ . '/Source/Caller1.php'], []];
yield [[__DIR__ . '/Fixture/plain-call-custom-function.php', __DIR__ . '/Source/Caller1.php'], []];
yield [[__DIR__ . '/Fixture/plain-call-custom-method.php', __DIR__ . '/Source/Caller1.php'], []];
yield [[__DIR__ . '/Fixture/SkipCrashBug89.php.inc'], []];

yield [[__DIR__ . '/Fixture/SkipJsonSerialize.php'], []];
Expand Down Expand Up @@ -204,7 +206,7 @@ protected function getCollectors(): array
// callables
self::getContainer()->getByType(StaticMethodCallableCollector::class),
self::getContainer()->getByType(AttributeCallableCollector::class),
self::getContainer()->getByType(CallbackFunctionCollector::class),
self::getContainer()->getByType(CallableTypeCollector::class),
];
}

Expand Down

0 comments on commit 3051615

Please sign in to comment.