Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/NodeTypeResolver/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ services:
Rector\NodeTypeResolver\:
resource: '../src'
exclude:
- '../src/Contract'
- '../src/Contract/*'
# "Type" is because the file is needed for PHPStan container only
- '../src/Type'
- '../src/PHPStan/TypeExtension/*'

Rector\Php\TypeAnalyzer: null
Rector\FileSystem\FilesFinder: null
Expand Down
4 changes: 2 additions & 2 deletions packages/NodeTypeResolver/config/phpstan/type-extensions.neon
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
services:
-
class: Rector\NodeTypeResolver\Type\TypeExtension\StaticContainerGetDynamicMethodReturnTypeExtension
class: Rector\NodeTypeResolver\PHPStan\TypeExtension\StaticContainerGetDynamicMethodReturnTypeExtension
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]

-
class: Rector\NodeTypeResolver\Type\TypeExtension\KernelGetContainerAfterBootReturnTypeExtension
class: Rector\NodeTypeResolver\PHPStan\TypeExtension\KernelGetContainerAfterBootReturnTypeExtension
tags: [phpstan.broker.dynamicMethodReturnTypeExtension]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Rector\NodeTypeResolver\Contract\PhpDocParser;

use PhpParser\Node;
use PHPStan\Analyser\NameScope;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\Type\Type;

interface PhpDocTypeMapperInterface
{
public function getNodeType(): string;

public function mapToPHPStanType(TypeNode $typeNode, Node $node, NameScope $nameScope): Type;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Rector\NodeTypeResolver\Contract\PhpParser;

use PhpParser\Node;
use PHPStan\Type\Type;

interface PhpParserNodeMapperInterface
{
public function getNodeType(): string;

public function mapToPHPStan(Node $node): Type;
}
4 changes: 4 additions & 0 deletions packages/NodeTypeResolver/src/NodeTypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ public function isNullableType(Node $node): bool
return $nodeType->isSuperTypeOf(new NullType())->yes();
}

/**
* @deprecated
* Use @see NodeTypeResolver::resolve() instead
*/
public function getStaticType(Node $node): Type
{
if ($this->isArrayExpr($node)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Rector\NodeTypeResolver\Type\TypeExtension;
namespace Rector\NodeTypeResolver\PHPStan\TypeExtension;

use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Rector\NodeTypeResolver\Type\TypeExtension;
namespace Rector\NodeTypeResolver\PHPStan\TypeExtension;

use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
Expand Down
64 changes: 64 additions & 0 deletions packages/NodeTypeResolver/src/PHPStan/TypeHasher.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

declare(strict_types=1);

namespace Rector\NodeTypeResolver\PHPStan;

use PHPStan\ShouldNotHappenException;
use PHPStan\Type\ArrayType;
use PHPStan\Type\ConstantType;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeWithClassName;
use PHPStan\Type\UnionType;
use Rector\PHPStan\Type\ShortenedObjectType;
use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper;

final class TypeHasher
{
/**
* @var PHPStanStaticTypeMapper
*/
private $phpStanStaticTypeMapper;

public function __construct(PHPStanStaticTypeMapper $phpStanStaticTypeMapper)
{
$this->phpStanStaticTypeMapper = $phpStanStaticTypeMapper;
}

public function createTypeHash(Type $type): string
{
if ($type instanceof MixedType) {
return serialize($type);
}

if ($type instanceof ArrayType) {
// @todo sort to make different order identical
return $this->createTypeHash($type->getItemType()) . '[]';
}

if ($type instanceof ShortenedObjectType) {
return $type->getFullyQualifiedName();
}

if ($type instanceof TypeWithClassName) {
return $type->getClassName();
}

if ($type instanceof ConstantType) {
if (method_exists($type, 'getValue')) {
return get_class($type) . $type->getValue();
}

throw new ShouldNotHappenException();
}

if ($type instanceof UnionType) {
$types = $type->getTypes();
sort($types);
$type = new UnionType($types);
}

return $this->phpStanStaticTypeMapper->mapToDocString($type);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Exception\MissingTagException;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PHPStan\TypeHasher;
use Rector\NodeTypeResolver\StaticTypeMapper;
use Rector\PHPStan\Type\AliasedObjectType;
use Rector\PHPStan\Type\ShortenedObjectType;
Expand Down Expand Up @@ -94,14 +95,20 @@ final class DocBlockManipulator
*/
private $docBlockNameImporter;

/**
* @var TypeHasher
*/
private $typeHasher;

public function __construct(
PhpDocInfoFactory $phpDocInfoFactory,
PhpDocInfoPrinter $phpDocInfoPrinter,
AttributeAwareNodeFactory $attributeAwareNodeFactory,
PhpDocNodeTraverser $phpDocNodeTraverser,
StaticTypeMapper $staticTypeMapper,
DocBlockClassRenamer $docBlockClassRenamer,
DocBlockNameImporter $docBlockNameImporter
DocBlockNameImporter $docBlockNameImporter,
TypeHasher $typeHasher
) {
$this->phpDocInfoFactory = $phpDocInfoFactory;
$this->phpDocInfoPrinter = $phpDocInfoPrinter;
Expand All @@ -110,6 +117,7 @@ public function __construct(
$this->staticTypeMapper = $staticTypeMapper;
$this->docBlockClassRenamer = $docBlockClassRenamer;
$this->docBlockNameImporter = $docBlockNameImporter;
$this->typeHasher = $typeHasher;
}

public function hasTag(Node $node, string $name): bool
Expand Down Expand Up @@ -566,8 +574,8 @@ private function areTypesEquals(Type $firstType, Type $secondType): bool
return true;
}

$firstTypeHash = $this->staticTypeMapper->createTypeHash($firstType);
$secondTypeHash = $this->staticTypeMapper->createTypeHash($secondType);
$firstTypeHash = $this->typeHasher->createTypeHash($firstType);
$secondTypeHash = $this->typeHasher->createTypeHash($secondType);

if ($firstTypeHash === $secondTypeHash) {
return true;
Expand Down
41 changes: 41 additions & 0 deletions packages/NodeTypeResolver/src/PhpDoc/PhpDocTypeMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace Rector\NodeTypeResolver\PhpDoc;

use PhpParser\Node;
use PHPStan\Analyser\NameScope;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\Type\Type;
use Rector\Exception\NotImplementedException;
use Rector\NodeTypeResolver\Contract\PhpDocParser\PhpDocTypeMapperInterface;

final class PhpDocTypeMapper
{
/**
* @var PhpDocTypeMapperInterface[]
*/
private $phpDocTypeMappers = [];

/**
* @param PhpDocTypeMapperInterface[] $phpDocTypeMappers
*/
public function __construct(array $phpDocTypeMappers)
{
$this->phpDocTypeMappers = $phpDocTypeMappers;
}

public function mapToPHPStanType(TypeNode $typeNode, Node $node, NameScope $nameScope): Type
{
foreach ($this->phpDocTypeMappers as $phpDocTypeMapper) {
if (! is_a($typeNode, $phpDocTypeMapper->getNodeType())) {
continue;
}

return $phpDocTypeMapper->mapToPHPStanType($typeNode, $node, $nameScope);
}

throw new NotImplementedException(__METHOD__ . ' for ' . get_class($typeNode));
}
}
47 changes: 47 additions & 0 deletions packages/NodeTypeResolver/src/PhpDocParser/ArrayTypeMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace Rector\NodeTypeResolver\PhpDocParser;

use PhpParser\Node;
use PHPStan\Analyser\NameScope;
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\Type\ArrayType;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use Rector\NodeTypeResolver\Contract\PhpDocParser\PhpDocTypeMapperInterface;
use Rector\NodeTypeResolver\PhpDoc\PhpDocTypeMapper;

final class ArrayTypeMapper implements PhpDocTypeMapperInterface
{
/**
* @var PhpDocTypeMapper
*/
private $phpDocTypeMapper;

public function getNodeType(): string
{
return ArrayTypeNode::class;
}

/**
* @required
*/
public function autowireGenericPhpDocTypeMapper(PhpDocTypeMapper $phpDocTypeMapper): void
{
$this->phpDocTypeMapper = $phpDocTypeMapper;
}

/**
* @param ArrayTypeNode $typeNode
*/
public function mapToPHPStanType(TypeNode $typeNode, Node $node, NameScope $nameScope): Type
{
$nestedType = $this->phpDocTypeMapper->mapToPHPStanType($typeNode->type, $node, $nameScope);

// @todo improve for key!
return new ArrayType(new MixedType(), $nestedType);
}
}
36 changes: 36 additions & 0 deletions packages/NodeTypeResolver/src/PhpDocParser/GenericTypeMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Rector\NodeTypeResolver\PhpDocParser;

use PhpParser\Node;
use PHPStan\Analyser\NameScope;
use PHPStan\PhpDoc\TypeNodeResolver;
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\Type\Type;
use Rector\NodeTypeResolver\Contract\PhpDocParser\PhpDocTypeMapperInterface;

final class GenericTypeMapper implements PhpDocTypeMapperInterface
{
/**
* @var TypeNodeResolver
*/
private $typeNodeResolver;

public function __construct(TypeNodeResolver $typeNodeResolver)
{
$this->typeNodeResolver = $typeNodeResolver;
}

public function getNodeType(): string
{
return GenericTypeNode::class;
}

public function mapToPHPStanType(TypeNode $typeNode, Node $node, NameScope $nameScope): Type
{
return $this->typeNodeResolver->resolve($typeNode, $nameScope);
}
}
Loading