Turn InterfaceTypeResolver to PHPStan reflection

This commit is contained in:
Tomas Votruba 2018-08-05 18:12:11 +02:00
parent 13e2ed9fac
commit 915fec0ff8
4 changed files with 33 additions and 126 deletions

View File

@ -4,6 +4,7 @@ namespace Rector\NodeTypeResolver;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\NodeVisitor\NameResolver;
use PHPStan\Analyser\NodeScopeResolver;
use PHPStan\Analyser\Scope;
@ -103,7 +104,7 @@ final class PHPStanNodeScopeResolver
function (Node $node, Scope $scope): void {
// the class reflection is resolved AFTER entering to class node
// so we need to get it from the first after this one
if ($node instanceof Class_) {
if ($node instanceof Class_ || $node instanceof Interface_) {
if (isset($node->namespacedName)) {
$scope = $scope->enterClass($this->phpstanBroker->getClass((string) $node->namespacedName));
} else {

View File

@ -1,121 +0,0 @@
<?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 [];
}
if ($classLikeNode instanceof Interface_ && $className) {
return $this->smartClassReflector->getInterfaceParents($className);
}
return $this->smartClassReflector->getClassParents($className, $classLikeNode);
}
/**
* @param Class_|Trait_ $classOrTraitNode
* @return string[]
*/
protected function resolveUsedTraitTypes(ClassLike $classOrTraitNode): array
{
foreach ($classOrTraitNode->stmts as $stmt) {
if (! $stmt instanceof TraitUse) {
continue;
}
return $this->resolveTraitNamesFromTraitUse($stmt);
}
return [];
}
/**
* @return string[]
*/
protected function resolveImplementsTypes(Class_ $classNode): array
{
return array_map(function (Name $interface): string {
if ($interface->hasAttribute(Attribute::RESOLVED_NAME)) {
return (string) $interface->getAttribute(Attribute::RESOLVED_NAME);
}
return $interface->toString();
}, $classNode->implements);
}
/**
* @return string[]
*/
private function resolveTraitNamesFromTraitUse(TraitUse $traitUse): array
{
$usedTraits = [];
foreach ($traitUse->traits as $trait) {
if ($trait->hasAttribute(Attribute::RESOLVED_NAME)) {
$usedTraits[] = (string) $trait->getAttribute(Attribute::RESOLVED_NAME);
}
}
return $usedTraits;
}
}

View File

@ -4,9 +4,12 @@ namespace Rector\NodeTypeResolver\PerNodeTypeResolver;
use PhpParser\Node;
use PhpParser\Node\Stmt\Interface_;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use Rector\Node\Attribute;
use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface;
final class InterfaceTypeResolver extends AbstractClassLikeTypeResolver implements PerNodeTypeResolverInterface
final class InterfaceTypeResolver implements PerNodeTypeResolverInterface
{
/**
* @return string[]
@ -22,8 +25,20 @@ final class InterfaceTypeResolver extends AbstractClassLikeTypeResolver implemen
*/
public function resolve(Node $interfaceNode): array
{
$interfaceName = $this->resolveNameNode($interfaceNode);
/** @var Scope $interfaceNodeScope */
$interfaceNodeScope = $interfaceNode->getAttribute(Attribute::SCOPE);
return array_merge([$interfaceName], $this->resolveExtendsTypes($interfaceNode, $interfaceName));
/** @var ClassReflection $classReflection */
$classReflection = $interfaceNodeScope->getClassReflection();
$types = [];
$types[] = $classReflection->getName();
// interfaces
foreach ($classReflection->getInterfaces() as $classReflection) {
$types[] = $classReflection->getName();
}
return $types;
}
}

View File

@ -4,9 +4,12 @@ namespace Rector\NodeTypeResolver\PerNodeTypeResolver;
use PhpParser\Node;
use PhpParser\Node\Stmt\Trait_;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use Rector\Node\Attribute;
use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface;
final class TraitTypeResolver extends AbstractClassLikeTypeResolver implements PerNodeTypeResolverInterface
final class TraitTypeResolver implements PerNodeTypeResolverInterface
{
/**
* @return string[]
@ -22,6 +25,15 @@ final class TraitTypeResolver extends AbstractClassLikeTypeResolver implements P
*/
public function resolve(Node $traitNode): array
{
/** @var Scope $traitNodeScope */
$traitNodeScope = $traitNode->getAttribute(Attribute::SCOPE);
/** @var ClassReflection $classReflection */
$classReflection = $traitNodeScope->getClassReflection();
dump($classReflection);
die;
$types[] = $this->resolveNameNode($traitNode);
return array_merge($types, $this->resolveUsedTraitTypes($traitNode));
}