mirror of
https://github.com/rectorphp/rector.git
synced 2025-02-24 11:44:14 +01:00
decouple ClassLikeType analyzing logic to AbstractClassLikeTypeResolver
This commit is contained in:
parent
c311ee4436
commit
d6ffcb8434
@ -0,0 +1,104 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\NodeTypeResolver\PerNodeTypeResolver;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\Interface_;
|
||||
use PhpParser\Node\Stmt\Trait_;
|
||||
use PhpParser\Node\Stmt\TraitUse;
|
||||
use Rector\BetterReflection\Reflector\SmartClassReflector;
|
||||
use Rector\Node\Attribute;
|
||||
|
||||
abstract class AbstractClassLikeTypeResolver
|
||||
{
|
||||
/**
|
||||
* @var SmartClassReflector
|
||||
*/
|
||||
private $smartClassReflector;
|
||||
|
||||
/**
|
||||
* @required
|
||||
*/
|
||||
public function setSmartClassReflector(SmartClassReflector $smartClassReflector): void
|
||||
{
|
||||
$this->smartClassReflector = $smartClassReflector;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Name|ClassLike $node
|
||||
*/
|
||||
protected function resolveNameNode(Node $node): string
|
||||
{
|
||||
$name = (string) $node->getAttribute(Attribute::CLASS_NAME);
|
||||
if ($name) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
$namespacedName = $node->getAttribute(Attribute::NAMESPACED_NAME);
|
||||
if ($namespacedName instanceof FullyQualified) {
|
||||
return $namespacedName->toString();
|
||||
}
|
||||
|
||||
$nameNode = $node->getAttribute(Attribute::RESOLVED_NAME);
|
||||
if ($nameNode instanceof Name) {
|
||||
return $nameNode->toString();
|
||||
}
|
||||
|
||||
if ($node instanceof Name) {
|
||||
return $node->toString();
|
||||
}
|
||||
|
||||
return (string) $node->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Class_|Interface_ $classLikeNode
|
||||
* @return string[]
|
||||
*/
|
||||
protected function resolveExtendsTypes(ClassLike $classLikeNode, ?string $className = null): array
|
||||
{
|
||||
if (! $classLikeNode->extends) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->smartClassReflector->getClassParents($className, $classLikeNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Class_|Trait_ $classOrTraitNode
|
||||
* @return string[]
|
||||
*/
|
||||
protected function resolveUsedTraitTypes(ClassLike $classOrTraitNode): array
|
||||
{
|
||||
$usedTraits = [];
|
||||
|
||||
foreach ($classOrTraitNode->stmts as $stmt) {
|
||||
if (! $stmt instanceof TraitUse) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($stmt->traits as $trait) {
|
||||
if ($trait->hasAttribute(Attribute::RESOLVED_NAME)) {
|
||||
$usedTraits[] = (string) $trait->getAttribute(Attribute::RESOLVED_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $usedTraits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
protected function resolveImplementsTypes(Class_ $classNode): array
|
||||
{
|
||||
return array_map(function (Name $interface): string {
|
||||
/** @var FullyQualified $interface */
|
||||
return $interface->toString();
|
||||
}, $classNode->implements);
|
||||
}
|
||||
}
|
@ -4,22 +4,10 @@ namespace Rector\NodeTypeResolver\PerNodeTypeResolver;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use Rector\NodeAnalyzer\ClassLikeAnalyzer;
|
||||
use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface;
|
||||
|
||||
final class ClassTypeResolver implements PerNodeTypeResolverInterface
|
||||
final class ClassTypeResolver extends AbstractClassLikeTypeResolver implements PerNodeTypeResolverInterface
|
||||
{
|
||||
/**
|
||||
* @var ClassLikeAnalyzer
|
||||
*/
|
||||
private $classLikeAnalyzer;
|
||||
|
||||
public function __construct(ClassLikeAnalyzer $classLikeAnalyzer)
|
||||
{
|
||||
$this->classLikeAnalyzer = $classLikeAnalyzer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
@ -29,11 +17,18 @@ final class ClassTypeResolver implements PerNodeTypeResolverInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassLike $classLikeNode
|
||||
* @param Class_ $classNode
|
||||
* @return string[]
|
||||
*/
|
||||
public function resolve(Node $classLikeNode): array
|
||||
public function resolve(Node $classNode): array
|
||||
{
|
||||
return $this->classLikeAnalyzer->resolveTypeAndParentTypes($classLikeNode);
|
||||
$className = $this->resolveNameNode($classNode);
|
||||
$types[] = $className;
|
||||
|
||||
$types = array_merge($types, $this->resolveExtendsTypes($classNode, $className));
|
||||
$types = array_merge($types, $this->resolveImplementsTypes($classNode));
|
||||
$types = array_merge($types, $this->resolveUsedTraitTypes($classNode));
|
||||
|
||||
return $types;
|
||||
}
|
||||
}
|
||||
|
@ -4,21 +4,10 @@ namespace Rector\NodeTypeResolver\PerNodeTypeResolver;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Interface_;
|
||||
use Rector\NodeAnalyzer\ClassLikeAnalyzer;
|
||||
use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface;
|
||||
|
||||
final class InterfaceTypeResolver implements PerNodeTypeResolverInterface
|
||||
final class InterfaceTypeResolver extends AbstractClassLikeTypeResolver implements PerNodeTypeResolverInterface
|
||||
{
|
||||
/**
|
||||
* @var ClassLikeAnalyzer
|
||||
*/
|
||||
private $classLikeAnalyzer;
|
||||
|
||||
public function __construct(ClassLikeAnalyzer $classLikeAnalyzer)
|
||||
{
|
||||
$this->classLikeAnalyzer = $classLikeAnalyzer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
@ -33,8 +22,8 @@ final class InterfaceTypeResolver implements PerNodeTypeResolverInterface
|
||||
*/
|
||||
public function resolve(Node $interfaceNode): array
|
||||
{
|
||||
$className = $this->classLikeAnalyzer->resolveNameNode($interfaceNode);
|
||||
$className = $this->resolveNameNode($interfaceNode);
|
||||
|
||||
return array_merge([$className], $this->classLikeAnalyzer->resolveExtendsTypes($interfaceNode, $className));
|
||||
return array_merge([$className], $this->resolveExtendsTypes($interfaceNode, $className));
|
||||
}
|
||||
}
|
||||
|
@ -4,21 +4,10 @@ namespace Rector\NodeTypeResolver\PerNodeTypeResolver;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\Trait_;
|
||||
use Rector\NodeAnalyzer\ClassLikeAnalyzer;
|
||||
use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface;
|
||||
|
||||
final class TraitTypeResolver implements PerNodeTypeResolverInterface
|
||||
final class TraitTypeResolver extends AbstractClassLikeTypeResolver implements PerNodeTypeResolverInterface
|
||||
{
|
||||
/**
|
||||
* @var ClassLikeAnalyzer
|
||||
*/
|
||||
private $classLikeAnalyzer;
|
||||
|
||||
public function __construct(ClassLikeAnalyzer $classLikeAnalyzer)
|
||||
{
|
||||
$this->classLikeAnalyzer = $classLikeAnalyzer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
@ -33,8 +22,8 @@ final class TraitTypeResolver implements PerNodeTypeResolverInterface
|
||||
*/
|
||||
public function resolve(Node $traitNode): array
|
||||
{
|
||||
$types[] = $this->classLikeAnalyzer->resolveNameNode($traitNode);
|
||||
$types = array_merge($types, $this->classLikeAnalyzer->resolveUsedTraitTypes($traitNode));
|
||||
$types[] = $this->resolveNameNode($traitNode);
|
||||
$types = array_merge($types, $this->resolveUsedTraitTypes($traitNode));
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ final class Attribute
|
||||
public const TYPES = 'types';
|
||||
|
||||
/**
|
||||
* System name.
|
||||
* Internal php-parser name.
|
||||
* Do not change this even if you want!
|
||||
*
|
||||
* @var string
|
||||
@ -25,7 +25,7 @@ final class Attribute
|
||||
public const ORIGINAL_NODE = 'origNode';
|
||||
|
||||
/**
|
||||
* System name to be found in @see \PhpParser\NodeVisitor\NameResolver
|
||||
* Internal php-parser name. @see \PhpParser\NodeVisitor\NameResolver
|
||||
* Do not change this even if you want!
|
||||
*
|
||||
* @var string
|
||||
@ -106,4 +106,12 @@ final class Attribute
|
||||
* @var string
|
||||
*/
|
||||
public const COMMENTS = 'comments';
|
||||
|
||||
/**
|
||||
* Internal php-parser name.
|
||||
* Do not change this even if you want!
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public const NAMESPACED_NAME = 'namespacedName';
|
||||
}
|
||||
|
@ -3,35 +3,14 @@
|
||||
namespace Rector\NodeAnalyzer;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\Interface_;
|
||||
use PhpParser\Node\Stmt\Trait_;
|
||||
use PhpParser\Node\Stmt\TraitUse;
|
||||
use Rector\BetterReflection\Reflector\SmartClassReflector;
|
||||
use Rector\Node\Attribute;
|
||||
|
||||
/**
|
||||
* Read-only utils for ClassLike|Class_|Trait_|Interface_ Node:
|
||||
* "class" SomeClass, "interface" Interface, "trait" Trait
|
||||
*
|
||||
* @todo decouple to Class_|Trait_|Interface_ TypeResolvers and remove this class
|
||||
* This is used nowhere else
|
||||
*/
|
||||
final class ClassLikeAnalyzer
|
||||
{
|
||||
/**
|
||||
* @var SmartClassReflector
|
||||
*/
|
||||
private $smartClassReflector;
|
||||
|
||||
public function __construct(SmartClassReflector $smartClassReflector)
|
||||
{
|
||||
$this->smartClassReflector = $smartClassReflector;
|
||||
}
|
||||
|
||||
public function isAnonymousClassNode(Node $node): bool
|
||||
{
|
||||
return $node instanceof Class_ && $node->isAnonymous();
|
||||
@ -41,104 +20,4 @@ final class ClassLikeAnalyzer
|
||||
{
|
||||
return $node instanceof Class_ && ! $node->isAnonymous();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function resolveTypeAndParentTypes(ClassLike $classLikeNode): array
|
||||
{
|
||||
$types = [];
|
||||
|
||||
if (! $this->isAnonymousClassNode($classLikeNode)) {
|
||||
$className = $this->resolveNameNode($classLikeNode);
|
||||
$types[] = $className;
|
||||
|
||||
if ($classLikeNode instanceof Class_ || $classLikeNode instanceof Interface_) {
|
||||
$types = array_merge($types, $this->resolveExtendsTypes($classLikeNode, $className));
|
||||
}
|
||||
} else {
|
||||
$types = array_merge($types, $this->resolveExtendsTypes($classLikeNode));
|
||||
}
|
||||
|
||||
if ($classLikeNode instanceof Class_) {
|
||||
$types = array_merge($types, $this->resolveImplementsTypes($classLikeNode));
|
||||
$types = array_merge($types, $this->resolveUsedTraitTypes($classLikeNode));
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Name|ClassLike $node
|
||||
*/
|
||||
public function resolveNameNode(Node $node): string
|
||||
{
|
||||
$name = (string) $node->getAttribute(Attribute::CLASS_NAME);
|
||||
if ($name) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
$namespacedName = $node->getAttribute('namespacedName');
|
||||
if ($namespacedName instanceof FullyQualified) {
|
||||
return $namespacedName->toString();
|
||||
}
|
||||
|
||||
$nameNode = $node->getAttribute(Attribute::RESOLVED_NAME);
|
||||
if ($nameNode instanceof Name) {
|
||||
return $nameNode->toString();
|
||||
}
|
||||
|
||||
if ($node instanceof Name) {
|
||||
return $node->toString();
|
||||
}
|
||||
|
||||
return (string) $node->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Class_|Interface_ $classLikeNode
|
||||
* @return string[]
|
||||
*/
|
||||
public function resolveExtendsTypes(ClassLike $classLikeNode, ?string $className = null): array
|
||||
{
|
||||
if (! $classLikeNode->extends) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->smartClassReflector->getClassParents($className, $classLikeNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Class_|Trait_ $classOrTraitNode
|
||||
* @return string[]
|
||||
*/
|
||||
public function resolveUsedTraitTypes(ClassLike $classOrTraitNode): array
|
||||
{
|
||||
$usedTraits = [];
|
||||
|
||||
foreach ($classOrTraitNode->stmts as $stmt) {
|
||||
if (! $stmt instanceof TraitUse) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($stmt->traits as $trait) {
|
||||
if ($trait->hasAttribute(Attribute::RESOLVED_NAME)) {
|
||||
$usedTraits[] = (string) $trait->getAttribute(Attribute::RESOLVED_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $usedTraits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function resolveImplementsTypes(Class_ $classNode): array
|
||||
{
|
||||
return array_map(function (Name $interface): string {
|
||||
/** @var FullyQualified $interface */
|
||||
return $interface->toString();
|
||||
}, $classNode->implements);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user