Skip to content

Commit

Permalink
extracted ClassTypeDetector to ease re-use (#64)
Browse files Browse the repository at this point in the history
  • Loading branch information
staabm authored Jun 26, 2023
1 parent 2172ea4 commit 46d3aab
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 17 deletions.
1 change: 1 addition & 0 deletions config/extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ parameters:

services:
- TomasVotruba\UnusedPublic\PublicClassMethodMatcher
- TomasVotruba\UnusedPublic\ClassTypeDetector
- TomasVotruba\UnusedPublic\ApiDocStmtAnalyzer
- TomasVotruba\UnusedPublic\ClassMethodCallReferenceResolver
- TomasVotruba\UnusedPublic\CollectorMapper\MethodCallCollectorMapper
Expand Down
23 changes: 23 additions & 0 deletions src/ClassTypeDetector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace TomasVotruba\UnusedPublic;

use PhpParser\Comment\Doc;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\Php\PhpMethodReflection;
use PHPStan\Reflection\ResolvedMethodReflection;

final class ClassTypeDetector
{
public function isTestClass(ClassReflection $classReflection): bool
{
return $classReflection->isSubclassOf('PHPUnit\Framework\TestCase') || $classReflection->isSubclassOf(
'PHPUnit_Framework_TestCase'
);
}

}
12 changes: 7 additions & 5 deletions src/Collectors/CallUserFuncCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use PHPStan\Collectors\Collector;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Type\Constant\ConstantArrayType;
use TomasVotruba\UnusedPublic\ClassTypeDetector;
use TomasVotruba\UnusedPublic\Configuration;

/**
Expand All @@ -20,6 +21,7 @@ final class CallUserFuncCollector implements Collector
{
public function __construct(
private readonly Configuration $configuration,
private readonly ClassTypeDetector $classTypeDetector,
) {
}

Expand All @@ -38,12 +40,12 @@ public function processNode(Node $node, Scope $scope): ?array
return null;
}

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

// unable to resolve method name
Expand Down
20 changes: 9 additions & 11 deletions src/Collectors/MethodCallCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
use PHPStan\Collectors\Collector;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\ReflectionProvider;
use TomasVotruba\UnusedPublic\ClassMethodCallReferenceResolver;
use TomasVotruba\UnusedPublic\ClassTypeDetector;
use TomasVotruba\UnusedPublic\Configuration;
use TomasVotruba\UnusedPublic\Enum\ReferenceMarker;

Expand All @@ -23,6 +25,7 @@ public function __construct(
private readonly ReflectionProvider $reflectionProvider,
private readonly ClassMethodCallReferenceResolver $classMethodCallReferenceResolver,
private readonly Configuration $configuration,
private readonly ClassTypeDetector $classTypeDetector,
) {
}

Expand All @@ -41,8 +44,13 @@ public function processNode(Node $node, Scope $scope): ?array
return null;
}

$classReflection = $scope->getClassReflection();
if (!$classReflection instanceof ClassReflection) {
return null;
}

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

Expand Down Expand Up @@ -95,15 +103,5 @@ private function findParentClassMethodReferences(string $className, string $meth
return $classMethodReferences;
}

private function isPHPUnitTestCase(Scope $scope): bool
{
if (! $scope->isInClass()) {
return false;
}

$classReflection = $scope->getClassReflection();
return $classReflection->isSubclassOf('PHPUnit\Framework\TestCase') || $classReflection->isSubclassOf(
'PHPUnit_Framework_TestCase'
);
}
}
9 changes: 8 additions & 1 deletion src/PublicClassMethodMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,24 @@ final class PublicClassMethodMatcher
* @var string[]
*/
private const SKIPPED_TYPES = [
'PHPUnit\Framework\TestCase',
'Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator',
];

public function __construct(
private readonly ClassTypeDetector $classTypeDetector,
) {}

public function shouldSkipClassReflection(ClassReflection $classReflection): bool
{
// skip interface as required, traits as unable to detect for sure
if ($classReflection->isInterface() || $classReflection->isTrait()) {
return true;
}

if ($this->classTypeDetector->isTestClass($classReflection)) {
return true;
}

foreach (self::SKIPPED_TYPES as $skippedType) {
if ($classReflection->isSubclassOf($skippedType)) {
return true;
Expand Down

0 comments on commit 46d3aab

Please sign in to comment.