decopule StaticTypeMapper, NameScopeFactory and StirngTypeToPhpParserNodeMapper

This commit is contained in:
TomasVotruba 2020-02-10 10:17:05 +01:00
parent 292c7125b6
commit 2a930f893d
25 changed files with 154 additions and 125 deletions

View File

@ -70,7 +70,6 @@
"Rector\\NetteTesterToPHPUnit\\": "packages/nette-tester-to-phpunit/src",
"Rector\\NetteToSymfony\\": "packages/nette-to-symfony/src",
"Rector\\Nette\\": "packages/nette/src",
"Rector\\NodeTypeMapper\\": "packages/node-type-mapper/src",
"Rector\\NodeCollector\\": "packages/node-collector/src",
"Rector\\NodeTypeResolver\\": "packages/node-type-resolver/src",
"Rector\\NodeNameResolver\\": "packages/node-name-resolver/src",
@ -99,6 +98,7 @@
"Rector\\Sensio\\": "packages/sensio/src",
"Rector\\Shopware\\": "packages/shopware/src",
"Rector\\Silverstripe\\": "packages/silverstripe/src",
"Rector\\StaticTypeMapper\\": "packages/static-type-mapper/src",
"Rector\\Sylius\\": "packages/sylius/src",
"Rector\\SymfonyCodeQuality\\": "packages/symfony-code-quality/src",
"Rector\\SymfonyPHPUnit\\": "packages/symfony-phpunit/src",

View File

@ -31,7 +31,7 @@ use Rector\BetterPhpDocParser\PhpDocNode\AbstractTagValueNode;
use Rector\Core\Exception\NotImplementedException;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\PHPStan\TypeComparator;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\StaticTypeMapper\StaticTypeMapper;
/**
* @see \Rector\BetterPhpDocParser\Tests\PhpDocInfo\PhpDocInfo\PhpDocInfoTest

View File

@ -16,7 +16,7 @@ use Rector\BetterPhpDocParser\ValueObject\StartEndValueObject;
use Rector\Core\Configuration\CurrentNodeProvider;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PHPStan\TypeComparator;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\StaticTypeMapper\StaticTypeMapper;
final class PhpDocInfoFactory
{

View File

@ -15,8 +15,8 @@ use Rector\CodingStyle\Imports\ImportSkipper;
use Rector\Core\Configuration\Option;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\PHPStan\Type\FullyQualifiedObjectType;
use Rector\StaticTypeMapper\StaticTypeMapper;
use Symplify\PackageBuilder\Parameter\ParameterProvider;
final class NameImporter

View File

@ -103,10 +103,6 @@ PHP
// single value → can we add it?
if (count($parameterData) === 1) {
$typeNode = $this->staticTypeMapper->mapStringToPhpParserNode($parameterData[0]);
if ($typeNode === null) {
continue;
}
$param->type = $typeNode;
}
}

View File

@ -19,7 +19,7 @@ use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\StaticTypeMapper\StaticTypeMapper;
use ReflectionProperty;
/**

View File

@ -10,7 +10,7 @@ use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\Type\Type;
use Rector\BetterPhpDocParser\Ast\PhpDocNodeTraverser;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\StaticTypeMapper\StaticTypeMapper;
final class DocBlockClassRenamer
{

View File

@ -18,9 +18,9 @@ use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\ClassExistenceStaticHelper;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\PHPStan\Type\FullyQualifiedObjectType;
use Rector\PHPStan\Type\ShortenedObjectType;
use Rector\StaticTypeMapper\StaticTypeMapper;
use Symplify\PackageBuilder\Parameter\ParameterProvider;
final class DocBlockNameImporter

View File

@ -11,7 +11,7 @@ use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\Type\ObjectType;
use Rector\BetterPhpDocParser\Ast\PhpDocNodeTraverser;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\StaticTypeMapper\StaticTypeMapper;
final class PhpDocTypeRenamer
{

View File

@ -15,7 +15,7 @@ use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\IterableType;
use PHPStan\Type\MixedType;
use Rector\Core\HttpKernel\RectorKernel;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\StaticTypeMapper\StaticTypeMapper;
use Symplify\PackageBuilder\Tests\AbstractKernelTestCase;
final class StaticTypeMapperTest extends AbstractKernelTestCase

View File

@ -24,7 +24,7 @@ use Rector\Core\Naming\PropertyNaming;
use Rector\Core\PhpParser\Node\NodeFactory;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\StaticTypeMapper\StaticTypeMapper;
final class UniqueObjectFactoryFactory
{

View File

@ -3,5 +3,5 @@ services:
public: true
autowire: true
Rector\NodeTypeMapper\:
Rector\StaticTypeMapper\:
resource: '../src'

View File

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace Rector\StaticTypeMapper\Mapper;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\NullableType;
use Rector\Core\Exception\NotImplementedException;
final class StringTypeToPhpParserNodeMapper
{
/**
* @return Identifier|Name|NullableType
*/
public function map(string $type): Node
{
if ($type === 'string') {
return new Identifier('string');
}
if ($type === 'int') {
return new Identifier('int');
}
if ($type === 'array') {
return new Identifier('array');
}
if ($type === 'float') {
return new Identifier('float');
}
if (Strings::contains($type, '\\') || ctype_upper($type[0])) {
return new FullyQualified($type);
}
if (Strings::startsWith($type, '?')) {
$nullableType = ltrim($type, '?');
/** @var Identifier|Name $nameNode */
$nameNode = $this->map($nullableType);
return new NullableType($nameNode);
}
if ($type === 'void') {
return new Identifier('void');
}
throw new NotImplementedException(sprintf('%s for "%s"', __METHOD__, $type));
}
}

View File

@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace Rector\StaticTypeMapper\PHPStan;
use PhpParser\Node;
use PhpParser\Node\Stmt\Use_;
use PhpParser\Node\Stmt\UseUse;
use PHPStan\Analyser\NameScope;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\AttributeKey;
/**
* @see https://github.com/phpstan/phpstan-src/blob/8376548f76e2c845ae047e3010e873015b796818/src/Analyser/NameScope.php#L32
*/
final class NameScopeFactory
{
public function createNameScopeFromNode(Node $node): NameScope
{
$namespace = $node->getAttribute(AttributeKey::NAMESPACE_NAME);
/** @var Use_[] $useNodes */
$useNodes = (array) $node->getAttribute(AttributeKey::USE_NODES);
$uses = $this->resolveUseNamesByAlias($useNodes);
$className = $node->getAttribute(AttributeKey::CLASS_NAME);
return new NameScope($namespace, $uses, $className);
}
/**
* @param Use_[] $useNodes
* @return string[]
*/
private function resolveUseNamesByAlias(array $useNodes): array
{
$useNamesByAlias = [];
foreach ($useNodes as $useNode) {
foreach ($useNode->uses as $useUse) {
/** @var UseUse $useUse */
$aliasName = $useUse->getAlias()->name;
$useName = $useUse->name->toString();
if (! is_string($useName)) {
throw new ShouldNotHappenException();
}
$useNamesByAlias[$aliasName] = $useName;
}
}
return $useNamesByAlias;
}
}

View File

@ -2,18 +2,13 @@
declare(strict_types=1);
namespace Rector\NodeTypeResolver;
namespace Rector\StaticTypeMapper;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\NullableType;
use PhpParser\Node\Stmt\Use_;
use PhpParser\Node\Stmt\UseUse;
use PhpParser\Node\UnionType as PhpParserUnionType;
use PHPStan\Analyser\NameScope;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
@ -21,12 +16,11 @@ use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\Type\Type;
use Rector\Core\Exception\NotImplementedException;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PhpDoc\PhpDocTypeMapper;
use Rector\NodeTypeResolver\TypeMapper\PhpParserNodeMapper;
use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper;
use Rector\StaticTypeMapper\Mapper\StringTypeToPhpParserNodeMapper;
use Rector\StaticTypeMapper\PHPStan\NameScopeFactory;
/**
* Maps PhpParser <=> PHPStan <=> PHPStan doc <=> string type nodes between all possible formats
@ -38,11 +32,6 @@ final class StaticTypeMapper
*/
private $phpStanStaticTypeMapper;
/**
* @var NodeNameResolver
*/
private $nodeNameResolver;
/**
* @var PhpParserNodeMapper
*/
@ -53,16 +42,28 @@ final class StaticTypeMapper
*/
private $phpDocTypeMapper;
/**
* @var StringTypeToPhpParserNodeMapper
*/
private $stringTypeToPhpParserNodeMapper;
/**
* @var NameScopeFactory
*/
private $nameScopeFactory;
public function __construct(
PHPStanStaticTypeMapper $phpStanStaticTypeMapper,
NodeNameResolver $nodeNameResolver,
PhpParserNodeMapper $phpParserNodeMapper,
PhpDocTypeMapper $phpDocTypeMapper
PhpDocTypeMapper $phpDocTypeMapper,
StringTypeToPhpParserNodeMapper $stringTypeToPhpParserNodeMapper,
NameScopeFactory $nameScopeFactory
) {
$this->phpStanStaticTypeMapper = $phpStanStaticTypeMapper;
$this->nodeNameResolver = $nodeNameResolver;
$this->phpParserNodeMapper = $phpParserNodeMapper;
$this->phpDocTypeMapper = $phpDocTypeMapper;
$this->stringTypeToPhpParserNodeMapper = $stringTypeToPhpParserNodeMapper;
$this->nameScopeFactory = $nameScopeFactory;
}
public function mapPHPStanTypeToPHPStanPhpDocTypeNode(Type $phpStanType): TypeNode
@ -101,44 +102,11 @@ final class StaticTypeMapper
}
/**
* @return Identifier|Name|NullableType|null
* @return Identifier|Name|NullableType
*/
public function mapStringToPhpParserNode(string $type): ?Node
public function mapStringToPhpParserNode(string $type): Node
{
if ($type === 'string') {
return new Identifier('string');
}
if ($type === 'int') {
return new Identifier('int');
}
if ($type === 'array') {
return new Identifier('array');
}
if ($type === 'float') {
return new Identifier('float');
}
if (Strings::contains($type, '\\') || ctype_upper($type[0])) {
return new FullyQualified($type);
}
if (Strings::startsWith($type, '?')) {
$nullableType = ltrim($type, '?');
/** @var Identifier|Name $nameNode */
$nameNode = $this->mapStringToPhpParserNode($nullableType);
return new NullableType($nameNode);
}
if ($type === 'void') {
return new Identifier('void');
}
throw new NotImplementedException(sprintf('%s for "%s"', __METHOD__, $type));
return $this->stringTypeToPhpParserNodeMapper->map($type);
}
public function mapPHPStanPhpDocTypeNodeToPhpDocString(TypeNode $typeNode, Node $node): string
@ -150,48 +118,8 @@ final class StaticTypeMapper
public function mapPHPStanPhpDocTypeNodeToPHPStanType(TypeNode $typeNode, Node $node): Type
{
$nameScope = $this->createNameScopeFromNode($node);
$nameScope = $this->nameScopeFactory->createNameScopeFromNode($node);
return $this->phpDocTypeMapper->mapToPHPStanType($typeNode, $node, $nameScope);
}
/**
* @see https://github.com/phpstan/phpstan-src/blob/8376548f76e2c845ae047e3010e873015b796818/src/Analyser/NameScope.php#L32
*/
private function createNameScopeFromNode(Node $node): NameScope
{
$namespace = $node->getAttribute(AttributeKey::NAMESPACE_NAME);
/** @var Use_[] $useNodes */
$useNodes = (array) $node->getAttribute(AttributeKey::USE_NODES);
$uses = $this->resolveUseNamesByAlias($useNodes);
$className = $node->getAttribute(AttributeKey::CLASS_NAME);
return new NameScope($namespace, $uses, $className);
}
/***
* @param Use_[] $useNodes
* @return string[]
*/
private function resolveUseNamesByAlias(array $useNodes): array
{
$useNamesByAlias = [];
foreach ($useNodes as $useNode) {
foreach ($useNode->uses as $useUse) {
/** @var UseUse $useUse */
$aliasName = $useUse->getAlias()->name;
$useName = $this->nodeNameResolver->getName($useUse->name);
if (! is_string($useName)) {
throw new ShouldNotHappenException();
}
$useNamesByAlias[$aliasName] = $useName;
}
}
return $useNamesByAlias;
}
}

View File

@ -8,7 +8,7 @@ use PhpParser\Node\Param;
use PHPStan\Type\Type;
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwareParamTagValueNode;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\StaticTypeMapper\StaticTypeMapper;
final class ParamPhpDocNodeFactory
{

View File

@ -166,10 +166,6 @@ PHP
}
$returnTypeNode = $this->staticTypeMapper->mapStringToPhpParserNode($newType);
if ($returnTypeNode === null) {
return;
}
$param->type = $returnTypeNode;
}
}

View File

@ -7,7 +7,7 @@ namespace Rector\TypeDeclaration;
use PhpParser\Node\FunctionLike;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\StaticTypeMapper\StaticTypeMapper;
final class TypeDeclarationToStringConverter
{

View File

@ -8,7 +8,7 @@ use Rector\Core\PhpParser\NodeTraverser\CallableNodeTraverser;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\StaticTypeMapper\StaticTypeMapper;
abstract class AbstractTypeInferer
{

View File

@ -11,7 +11,7 @@ use PHPStan\Type\MixedType;
use PHPStan\Type\StringType;
use PHPStan\Type\UnionType;
use Rector\Core\HttpKernel\RectorKernel;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\StaticTypeMapper\StaticTypeMapper;
use Rector\TypeDeclaration\TypeNormalizer;
use Symplify\PackageBuilder\Tests\AbstractKernelTestCase;

View File

@ -221,7 +221,7 @@ parameters:
- '#Property PhpParser\\Node\\Stmt\\Expression\:\:\$expr \(PhpParser\\Node\\Expr\) does not accept PhpParser\\Node\\Expr\|null#'
- '#Call to an undefined method PHPStan\\Type\\Type\:\:getClassName\(\)#'
- '#Parameter \#1 \$typeNode of method Rector\\NodeTypeResolver\\StaticTypeMapper\:\:mapPHPStanPhpDocTypeNodeToPHPStanType\(\) expects PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode, PHPStan\\PhpDocParser\\Ast\\Node given#'
- '#Parameter \#1 \$typeNode of method Rector\\StaticTypeMapper\\StaticTypeMapper\:\:mapPHPStanPhpDocTypeNodeToPHPStanType\(\) expects PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode, PHPStan\\PhpDocParser\\Ast\\Node given#'
- '#Parameter \#1 \$str of function preg_quote expects string, int\|string given#'
- '#Parameter \#1 \$node of method Rector\\Core\\PhpParser\\Node\\Commander\\NodeAddingCommander\:\:wrapToExpression\(\) expects PhpParser\\Node\\Expr\|PhpParser\\Node\\Stmt, PhpParser\\Node given#'

View File

@ -25,7 +25,7 @@ use Rector\FileSystemRector\Parser\FileInfoParser;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\StaticTypeMapper\StaticTypeMapper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

View File

@ -33,7 +33,7 @@ use PHPStan\Type\Type;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
use Rector\Core\Exception\NotImplementedException;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\StaticTypeMapper\StaticTypeMapper;
/**
* @see \Rector\Core\Tests\PhpParser\Node\NodeFactoryTest

View File

@ -24,7 +24,7 @@ use Rector\NodeCollector\NodeFinder\FunctionLikeParsedNodesFinder;
use Rector\NodeTypeResolver\FileSystem\CurrentFileInfoProvider;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\StaticTypeMapper\StaticTypeMapper;
use Rector\Core\Php\PhpVersionProvider;
use Rector\Core\Rector\AbstractRector\AbstractRectorTrait;
use Rector\Core\Rector\AbstractRector\NodeCommandersTrait;

View File

@ -111,10 +111,6 @@ PHP
}
$returnTypeNode = $this->staticTypeMapper->mapStringToPhpParserNode($newType);
if ($returnTypeNode === null) {
return;
}
$classMethod->returnType = $returnTypeNode;
}
}