Skip to content

Commit

Permalink
MethodCallCollector: emit data once per class (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
janedbal authored Jul 15, 2024
1 parent 6f0b3d1 commit 3fc29fd
Showing 1 changed file with 26 additions and 37 deletions.
63 changes: 26 additions & 37 deletions src/Collector/MethodCallCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use PhpParser\Node\Name;
use PHPStan\Analyser\Scope;
use PHPStan\Collectors\Collector;
use PHPStan\Node\ClassMethodsNode;
use PHPStan\Node\MethodCallableNode;
use PHPStan\Node\StaticMethodCallableNode;
use PHPStan\Reflection\ClassReflection;
Expand All @@ -28,6 +29,11 @@ class MethodCallCollector implements Collector

private ReflectionProvider $reflectionProvider;

/**
* @var list<string>
*/
private array $callsBuffer = [];

public function __construct(ReflectionProvider $reflectionProvider)
{
$this->reflectionProvider = $reflectionProvider;
Expand All @@ -47,66 +53,64 @@ public function processNode(
): ?array
{
if ($node instanceof MethodCallableNode) { // @phpstan-ignore-line ignore BC promise
return $this->registerMethodCall($node->getOriginalNode(), $scope);
$this->registerMethodCall($node->getOriginalNode(), $scope);
}

if ($node instanceof StaticMethodCallableNode) { // @phpstan-ignore-line ignore BC promise
return $this->registerStaticCall($node->getOriginalNode(), $scope);
$this->registerStaticCall($node->getOriginalNode(), $scope);
}

if ($node instanceof MethodCall || $node instanceof NullsafeMethodCall) {
return $this->registerMethodCall($node, $scope);
$this->registerMethodCall($node, $scope);
}

if ($node instanceof StaticCall) {
return $this->registerStaticCall($node, $scope);
$this->registerStaticCall($node, $scope);
}

if ($node instanceof FuncCall) {
return $this->registerFuncCall($node, $scope);
$this->registerFuncCall($node, $scope);
}

if (!$scope->isInClass() || $node instanceof ClassMethodsNode) { // @phpstan-ignore-line ignore BC promise
$data = $this->callsBuffer;
$this->callsBuffer = [];
return $data === [] ? null : $data; // collect data once per class to save memory & resultCache size
}

return null;
}

/**
* @param NullsafeMethodCall|MethodCall $methodCall
* @return list<string>|null
*/
private function registerMethodCall(
CallLike $methodCall,
Scope $scope
): ?array
): void
{
$methodName = $this->getMethodName($methodCall);
$callerType = $scope->getType($methodCall->var);

if ($methodName === null) {
return null;
return;
}

$result = [];

foreach ($this->getReflectionsWithMethod($callerType, $methodName) as $classWithMethod) {
$className = $classWithMethod->getMethod($methodName, $scope)->getDeclaringClass()->getName();
$result[] = DeadCodeHelper::composeMethodKey($className, $methodName);
$this->callsBuffer[] = DeadCodeHelper::composeMethodKey($className, $methodName);
}

return $result !== [] ? $result : null;
}

/**
* @return list<string>|null
*/
private function registerStaticCall(
StaticCall $staticCall,
Scope $scope
): ?array
): void
{
$methodName = $this->getMethodName($staticCall);

if ($methodName === null) {
return null;
return;
}

if ($staticCall->class instanceof Expr) {
Expand All @@ -124,26 +128,19 @@ private function registerStaticCall(
}
}

$result = [];

foreach ($classReflections as $classWithMethod) {
$className = $classWithMethod->getMethod($methodName, $scope)->getDeclaringClass()->getName();
$result[] = DeadCodeHelper::composeMethodKey($className, $methodName);
$this->callsBuffer[] = DeadCodeHelper::composeMethodKey($className, $methodName);
}

return $result !== [] ? $result : null;
}

/**
* @return list<string>|null
*/
private function registerFuncCall(
FuncCall $functionCall,
Scope $scope
): ?array
): void
{
if (!$functionCall->name instanceof Name || $functionCall->name->toString() !== 'array_map') { // we should support all native fns
return null;
return;
}

$callableType = $scope->getType($functionCall->getArgs()[0]->value);
Expand All @@ -152,24 +149,16 @@ private function registerFuncCall(
foreach ($callableType->getConstantArrays() as $constantArray) {
$callableTypeAndNames = $constantArray->findTypeAndMethodNames();

$result = [];

foreach ($callableTypeAndNames as $typeAndName) {
$methodName = $typeAndName->getMethod();

foreach ($this->getReflectionsWithMethod($typeAndName->getType(), $methodName) as $classWithMethod) {
$className = $classWithMethod->getMethod($methodName, $scope)->getDeclaringClass()->getName();
$result[] = DeadCodeHelper::composeMethodKey($className, $methodName);
$this->callsBuffer[] = DeadCodeHelper::composeMethodKey($className, $methodName);
}
}

if ($result !== []) {
return $result;
}
}
}

return null;
}

/**
Expand Down

0 comments on commit 3fc29fd

Please sign in to comment.