mirror of
https://github.com/rectorphp/rector.git
synced 2025-03-14 04:19:44 +01:00
decouple VariableTypeResolver and TypeToStringResolver
This commit is contained in:
parent
023270a1b3
commit
85aea7d8f8
@ -7,17 +7,9 @@ use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Param;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Broker\Broker;
|
||||
use PHPStan\TrinaryLogic;
|
||||
use PHPStan\Type\IntersectionType;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\ThisType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\UnionType;
|
||||
use Rector\BetterPhpDocParser\NodeAnalyzer\DocBlockAnalyzer;
|
||||
use Rector\Node\Attribute;
|
||||
use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface;
|
||||
use Rector\NodeTypeResolver\Reflection\ClassReflectionTypesResolver;
|
||||
use Rector\NodeTypeResolver\PHPStan\Type\TypeToStringResolver;
|
||||
|
||||
final class NodeTypeResolver
|
||||
{
|
||||
@ -27,28 +19,13 @@ final class NodeTypeResolver
|
||||
private $perNodeTypeResolvers = [];
|
||||
|
||||
/**
|
||||
* @var ClassReflectionTypesResolver
|
||||
* @var TypeToStringResolver
|
||||
*/
|
||||
private $classReflectionTypesResolver;
|
||||
private $typeToStringResolver;
|
||||
|
||||
/**
|
||||
* @var DocBlockAnalyzer
|
||||
*/
|
||||
private $docBlockAnalyzer;
|
||||
|
||||
/**
|
||||
* @var Broker
|
||||
*/
|
||||
private $broker;
|
||||
|
||||
public function __construct(
|
||||
ClassReflectionTypesResolver $classReflectionTypesResolver,
|
||||
DocBlockAnalyzer $docBlockAnalyzer,
|
||||
Broker $broker
|
||||
) {
|
||||
$this->classReflectionTypesResolver = $classReflectionTypesResolver;
|
||||
$this->docBlockAnalyzer = $docBlockAnalyzer;
|
||||
$this->broker = $broker;
|
||||
public function __construct(TypeToStringResolver $typeToStringResolver)
|
||||
{
|
||||
$this->typeToStringResolver = $typeToStringResolver;
|
||||
}
|
||||
|
||||
public function addPerNodeTypeResolver(PerNodeTypeResolverInterface $perNodeTypeResolver): void
|
||||
@ -74,11 +51,7 @@ final class NodeTypeResolver
|
||||
return [$node->type->toString()];
|
||||
}
|
||||
|
||||
if ($node instanceof Variable) {
|
||||
return $this->resolveVariableNode($node, $nodeScope);
|
||||
}
|
||||
|
||||
if ($node instanceof Expr) {
|
||||
if ($node instanceof Expr && ! $node instanceof Variable) {
|
||||
return $this->resolveExprNode($node);
|
||||
}
|
||||
|
||||
@ -100,81 +73,6 @@ final class NodeTypeResolver
|
||||
|
||||
$type = $nodeScope->getType($exprNode);
|
||||
|
||||
return $this->resolveObjectTypesToStrings($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo make use of recursion
|
||||
* @return string[]
|
||||
*/
|
||||
private function resolveObjectTypesToStrings(Type $type): array
|
||||
{
|
||||
$types = [];
|
||||
|
||||
if ($type instanceof ObjectType) {
|
||||
$types[] = $type->getClassName();
|
||||
}
|
||||
|
||||
if ($type instanceof UnionType) {
|
||||
foreach ($type->getTypes() as $type) {
|
||||
if ($type instanceof ObjectType) {
|
||||
$types[] = $type->getClassName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($type instanceof IntersectionType) {
|
||||
foreach ($type->getTypes() as $type) {
|
||||
if ($type instanceof ObjectType) {
|
||||
$types[] = $type->getClassName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function resolveVariableNode(Variable $variableNode, Scope $nodeScope): array
|
||||
{
|
||||
$variableName = (string) $variableNode->name;
|
||||
|
||||
if ($nodeScope->hasVariableType($variableName) === TrinaryLogic::createYes()) {
|
||||
$type = $nodeScope->getVariableType($variableName);
|
||||
|
||||
// this
|
||||
if ($type instanceof ThisType) {
|
||||
return $this->classReflectionTypesResolver->resolve($nodeScope->getClassReflection());
|
||||
}
|
||||
|
||||
$types = $this->resolveObjectTypesToStrings($type);
|
||||
|
||||
// complete parents
|
||||
foreach ($types as $type) {
|
||||
$propertyClassReflection = $this->broker->getClass($type);
|
||||
$types = array_merge($types, $this->classReflectionTypesResolver->resolve($propertyClassReflection));
|
||||
}
|
||||
|
||||
return array_unique($types);
|
||||
}
|
||||
|
||||
// get from annotation
|
||||
$variableTypes = $this->docBlockAnalyzer->getVarTypes($variableNode);
|
||||
|
||||
foreach ($variableTypes as $i => $type) {
|
||||
if (! class_exists($type)) {
|
||||
unset($variableTypes[$i]);
|
||||
continue;
|
||||
}
|
||||
$propertyClassReflection = $this->broker->getClass($type);
|
||||
$variableTypes = array_merge(
|
||||
$variableTypes,
|
||||
$this->classReflectionTypesResolver->resolve($propertyClassReflection)
|
||||
);
|
||||
}
|
||||
|
||||
return array_unique($variableTypes);
|
||||
return $this->typeToStringResolver->resolve($type);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\NodeTypeResolver\PHPStan\Type;
|
||||
|
||||
use PHPStan\Type\IntersectionType;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\Type;
|
||||
use PHPStan\Type\UnionType;
|
||||
|
||||
final class TypeToStringResolver
|
||||
{
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function resolve(Type $type): array
|
||||
{
|
||||
$types = [];
|
||||
|
||||
if ($type instanceof ObjectType) {
|
||||
$types[] = $type->getClassName();
|
||||
}
|
||||
|
||||
if ($type instanceof UnionType || $type instanceof IntersectionType) {
|
||||
foreach ($type->getTypes() as $type) {
|
||||
if ($type instanceof ObjectType) {
|
||||
$types[] = $type->getClassName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\NodeTypeResolver\PerNodeTypeResolver;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PHPStan\Broker\Broker;
|
||||
use PHPStan\TrinaryLogic;
|
||||
use PHPStan\Type\ThisType;
|
||||
use Rector\BetterPhpDocParser\NodeAnalyzer\DocBlockAnalyzer;
|
||||
use Rector\Node\Attribute;
|
||||
use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface;
|
||||
use Rector\NodeTypeResolver\PHPStan\Type\TypeToStringResolver;
|
||||
use Rector\NodeTypeResolver\Reflection\ClassReflectionTypesResolver;
|
||||
|
||||
final class VariableTypeResolver implements PerNodeTypeResolverInterface
|
||||
{
|
||||
/**
|
||||
* @var ClassReflectionTypesResolver
|
||||
*/
|
||||
private $classReflectionTypesResolver;
|
||||
|
||||
/**
|
||||
* @var DocBlockAnalyzer
|
||||
*/
|
||||
private $docBlockAnalyzer;
|
||||
|
||||
/**
|
||||
* @var Broker
|
||||
*/
|
||||
private $broker;
|
||||
|
||||
/**
|
||||
* @var TypeToStringResolver
|
||||
*/
|
||||
private $typeToStringResolver;
|
||||
|
||||
public function __construct(
|
||||
ClassReflectionTypesResolver $classReflectionTypesResolver,
|
||||
DocBlockAnalyzer $docBlockAnalyzer,
|
||||
Broker $broker,
|
||||
TypeToStringResolver $typeToStringResolver
|
||||
) {
|
||||
$this->classReflectionTypesResolver = $classReflectionTypesResolver;
|
||||
$this->docBlockAnalyzer = $docBlockAnalyzer;
|
||||
$this->broker = $broker;
|
||||
$this->typeToStringResolver = $typeToStringResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeClasses(): array
|
||||
{
|
||||
return [Variable::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Variable $variableNode
|
||||
* @return string[]
|
||||
*/
|
||||
public function resolve(Node $variableNode): array
|
||||
{
|
||||
$nodeScope = $variableNode->getAttribute(Attribute::SCOPE);
|
||||
|
||||
$variableName = (string) $variableNode->name;
|
||||
|
||||
if ($nodeScope->hasVariableType($variableName) === TrinaryLogic::createYes()) {
|
||||
$type = $nodeScope->getVariableType($variableName);
|
||||
|
||||
// this
|
||||
if ($type instanceof ThisType) {
|
||||
return $this->classReflectionTypesResolver->resolve($nodeScope->getClassReflection());
|
||||
}
|
||||
|
||||
$types = $this->typeToStringResolver->resolve($type);
|
||||
|
||||
// complete parents
|
||||
foreach ($types as $type) {
|
||||
$propertyClassReflection = $this->broker->getClass($type);
|
||||
$types = array_merge($types, $this->classReflectionTypesResolver->resolve($propertyClassReflection));
|
||||
}
|
||||
|
||||
return array_unique($types);
|
||||
}
|
||||
|
||||
// get from annotation
|
||||
$variableTypes = $this->docBlockAnalyzer->getVarTypes($variableNode);
|
||||
|
||||
foreach ($variableTypes as $i => $type) {
|
||||
if (! class_exists($type)) {
|
||||
unset($variableTypes[$i]);
|
||||
continue;
|
||||
}
|
||||
$propertyClassReflection = $this->broker->getClass($type);
|
||||
$variableTypes = array_merge(
|
||||
$variableTypes,
|
||||
$this->classReflectionTypesResolver->resolve($propertyClassReflection)
|
||||
);
|
||||
}
|
||||
|
||||
return array_unique($variableTypes);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user