mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-09 20:52:23 +00:00
f397ad92ed
e68c8d23cb
Fix CallableTypeParameterNode and IdentifierTypeParameterNode crash (#3353)
105 lines
3.8 KiB
PHP
105 lines
3.8 KiB
PHP
<?php
|
|
|
|
declare (strict_types=1);
|
|
namespace Rector\PHPUnit\NodeFinder;
|
|
|
|
use PhpParser\Node\Stmt\Class_;
|
|
use PhpParser\Node\Stmt\ClassMethod;
|
|
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
|
|
use PHPStan\Reflection\ClassReflection;
|
|
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
|
|
use Rector\Core\PhpParser\AstResolver;
|
|
use Rector\Core\Reflection\ReflectionResolver;
|
|
final class DataProviderClassMethodFinder
|
|
{
|
|
/**
|
|
* @readonly
|
|
* @var \Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory
|
|
*/
|
|
private $phpDocInfoFactory;
|
|
/**
|
|
* @readonly
|
|
* @var \Rector\Core\Reflection\ReflectionResolver
|
|
*/
|
|
private $reflectionResolver;
|
|
/**
|
|
* @readonly
|
|
* @var \Rector\Core\PhpParser\AstResolver
|
|
*/
|
|
private $astResolver;
|
|
public function __construct(PhpDocInfoFactory $phpDocInfoFactory, ReflectionResolver $reflectionResolver, AstResolver $astResolver)
|
|
{
|
|
$this->phpDocInfoFactory = $phpDocInfoFactory;
|
|
$this->reflectionResolver = $reflectionResolver;
|
|
$this->astResolver = $astResolver;
|
|
}
|
|
/**
|
|
* @return ClassMethod[]
|
|
*/
|
|
public function find(Class_ $class) : array
|
|
{
|
|
$parentAbstractClasses = $this->resolveParentAbstractClasses($class);
|
|
$targetClasses = \array_merge([$class], $parentAbstractClasses);
|
|
// foreach to find method names
|
|
$dataProviderMethodNames = [];
|
|
foreach ($targetClasses as $targetClass) {
|
|
$dataProviderMethodNames = \array_merge($dataProviderMethodNames, $this->resolverDataProviderClassMethodNames($targetClass));
|
|
}
|
|
$dataProviderClassMethods = [];
|
|
foreach ($dataProviderMethodNames as $dataProviderMethodName) {
|
|
$dataProviderClassMethod = $class->getMethod($dataProviderMethodName);
|
|
if (!$dataProviderClassMethod instanceof ClassMethod) {
|
|
continue;
|
|
}
|
|
$dataProviderClassMethods[] = $dataProviderClassMethod;
|
|
}
|
|
return $dataProviderClassMethods;
|
|
}
|
|
/**
|
|
* @return string[]
|
|
*/
|
|
private function resolverDataProviderClassMethodNames(Class_ $class) : array
|
|
{
|
|
$dataProviderMethodNames = [];
|
|
foreach ($class->getMethods() as $classMethod) {
|
|
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($classMethod);
|
|
$dataProviderTagValueNodes = $phpDocInfo->getTagsByName('dataProvider');
|
|
if ($dataProviderTagValueNodes === []) {
|
|
continue;
|
|
}
|
|
foreach ($dataProviderTagValueNodes as $dataProviderTagValueNode) {
|
|
if (!$dataProviderTagValueNode->value instanceof GenericTagValueNode) {
|
|
continue;
|
|
}
|
|
$dataProviderMethodNames[] = $this->resolveMethodName($dataProviderTagValueNode->value);
|
|
}
|
|
}
|
|
return $dataProviderMethodNames;
|
|
}
|
|
private function resolveMethodName(GenericTagValueNode $genericTagValueNode) : string
|
|
{
|
|
$rawValue = $genericTagValueNode->value;
|
|
return \trim($rawValue, '()');
|
|
}
|
|
/**
|
|
* @return Class_[]
|
|
*/
|
|
private function resolveParentAbstractClasses(Class_ $class) : array
|
|
{
|
|
// resolve from parent one?
|
|
$classReflection = $this->reflectionResolver->resolveClassReflection($class);
|
|
if (!$classReflection instanceof ClassReflection) {
|
|
return [];
|
|
}
|
|
$parentClasses = [];
|
|
foreach ($classReflection->getParents() as $parentClassReflection) {
|
|
// is the top parent class? stop
|
|
if ($parentClassReflection->getName() === 'PHPUnit\\Framework\\TestCase') {
|
|
break;
|
|
}
|
|
$parentClasses[] = $this->astResolver->resolveClassFromClassReflection($parentClassReflection);
|
|
}
|
|
return $parentClasses;
|
|
}
|
|
}
|