Skip to content

Commit

Permalink
Union mapper cleanup (#6094)
Browse files Browse the repository at this point in the history
* instnance check

* union mapper cleanup
  • Loading branch information
TomasVotruba authored Jul 1, 2024
1 parent ef33350 commit 3c2100b
Show file tree
Hide file tree
Showing 4 changed files with 10 additions and 148 deletions.
32 changes: 0 additions & 32 deletions src/PHPStanStaticTypeMapper/TypeAnalyzer/UnionTypeAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,11 @@

namespace Rector\PHPStanStaticTypeMapper\TypeAnalyzer;

use PHPStan\Type\ArrayType;
use PHPStan\Type\IterableType;
use PHPStan\Type\NullType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\UnionType;
use Rector\PHPStanStaticTypeMapper\ValueObject\UnionTypeAnalysis;
use Traversable;

final class UnionTypeAnalyzer
{
public function analyseForArrayAndIterable(UnionType $unionType): ?UnionTypeAnalysis
{
$hasIterable = false;
$hasArray = false;

foreach ($unionType->getTypes() as $unionedType) {
if ($unionedType instanceof IterableType) {
$hasIterable = true;
continue;
}

if ($unionedType instanceof ArrayType) {
$hasArray = true;
continue;
}

if ($unionedType instanceof ObjectType && $unionedType->getClassName() === Traversable::class) {
$hasIterable = true;
continue;
}

return null;
}

return new UnionTypeAnalysis($hasIterable, $hasArray);
}

public function isNullable(UnionType $unionType, bool $checkTwoTypes = false): bool
{
$types = $unionType->getTypes();
Expand Down
88 changes: 3 additions & 85 deletions src/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,16 @@
use PhpParser\Node\UnionType as PhpParserUnionType;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\IterableType;
use PHPStan\Type\MixedType;
use PHPStan\Type\NullType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use PHPStan\Type\VoidType;
use Rector\BetterPhpDocParser\ValueObject\Type\BracketsAwareUnionTypeNode;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\Php\PhpVersionProvider;
use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface;
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeAnalyzer\UnionTypeAnalyzer;
use Rector\PHPStanStaticTypeMapper\ValueObject\UnionTypeAnalysis;
use Rector\ValueObject\PhpVersionFeature;
use Webmozart\Assert\Assert;
use Webmozart\Assert\InvalidArgumentException;
Expand All @@ -41,8 +37,6 @@ final class UnionTypeMapper implements TypeMapperInterface

public function __construct(
private readonly PhpVersionProvider $phpVersionProvider,
private readonly UnionTypeAnalyzer $unionTypeAnalyzer,
private readonly NodeNameResolver $nodeNameResolver
) {
}

Expand All @@ -61,19 +55,11 @@ public function getNodeClass(): string
*/
public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode
{
// note: cannot be handled by PHPStan as uses no-space around |
$unionTypesNodes = [];
$skipIterable = $this->shouldSkipIterable($type);

foreach ($type->getTypes() as $unionedType) {
if ($unionedType instanceof IterableType && $skipIterable) {
continue;
}

$unionTypesNodes[] = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($unionedType);
}

$unionTypesNodes = array_unique($unionTypesNodes);
return new BracketsAwareUnionTypeNode($unionTypesNodes);
}

Expand All @@ -83,15 +69,10 @@ public function mapToPHPStanPhpDocTypeNode(Type $type): TypeNode
public function mapToPhpParserNode(Type $type, string $typeKind): ?Node
{
// special case for nullable
$nullabledType = $this->matchTypeForNullableUnionType($type);
if (! $nullabledType instanceof Type) {
return $this->matchTypeForUnionedTypes($type, $typeKind);
}

return $this->mapNullabledType($nullabledType, $typeKind);
return $this->matchTypeForUnionedTypes($type, $typeKind);
}

public function resolveTypeWithNullablePHPParserUnionType(
private function resolveTypeWithNullablePHPParserUnionType(
PhpParserUnionType $phpParserUnionType
): PhpParserUnionType|NullableType|null {
$totalTypes = count($phpParserUnionType->types);
Expand Down Expand Up @@ -138,7 +119,7 @@ private function resolveNullableType(NullableType $nullableType): null|NullableT
return $nullableType;
}

if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::INTERSECTION_TYPES)) {
if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::UNION_TYPES)) {
return null;
}

Expand All @@ -148,49 +129,6 @@ private function resolveNullableType(NullableType $nullableType): null|NullableT
return new PhpParserUnionType($types);
}

/**
* @param TypeKind::* $typeKind
*/
private function mapNullabledType(
Type $nullabledType,
string $typeKind
): NullableType|ComplexType|PhpParserUnionType|null {
// void cannot be nullable
if ($nullabledType->isVoid()->yes()) {
return null;
}

$nullabledTypeNode = $this->phpStanStaticTypeMapper->mapToPhpParserNode($nullabledType, $typeKind);
if (! $nullabledTypeNode instanceof Node) {
return null;
}

if (in_array($nullabledTypeNode::class, [NullableType::class, ComplexType::class], true)) {
return $nullabledTypeNode;
}

/** @var Name $nullabledTypeNode */
if (! $this->nodeNameResolver->isNames($nullabledTypeNode, ['false', 'mixed'])) {
return $this->resolveNullableType(new NullableType($nullabledTypeNode));
}

return null;
}

private function shouldSkipIterable(UnionType $unionType): bool
{
$unionTypeAnalysis = $this->unionTypeAnalyzer->analyseForArrayAndIterable($unionType);
if (! $unionTypeAnalysis instanceof UnionTypeAnalysis) {
return false;
}

if (! $unionTypeAnalysis->hasIterable()) {
return false;
}

return $unionTypeAnalysis->hasArray();
}

private function resolveUnionTypes(PhpParserUnionType $phpParserUnionType): ?PhpParserUnionType
{
if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::UNION_TYPES)) {
Expand All @@ -200,26 +138,6 @@ private function resolveUnionTypes(PhpParserUnionType $phpParserUnionType): ?Php
return $phpParserUnionType;
}

private function matchTypeForNullableUnionType(UnionType $unionType): ?Type
{
if (count($unionType->getTypes()) !== 2) {
return null;
}

$firstType = $unionType->getTypes()[0];
$secondType = $unionType->getTypes()[1];

if ($firstType instanceof NullType) {
return $secondType;
}

if ($secondType instanceof NullType) {
return $firstType;
}

return null;
}

private function hasObjectAndStaticType(PhpParserUnionType $phpParserUnionType): bool
{
$hasAnonymousObjectType = false;
Expand Down
24 changes: 0 additions & 24 deletions src/PHPStanStaticTypeMapper/ValueObject/UnionTypeAnalysis.php

This file was deleted.

14 changes: 7 additions & 7 deletions src/StaticTypeMapper/Naming/NameScopeFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,18 @@ public function __construct(
public function createNameScopeFromNodeWithoutTemplateTypes(Node $node): NameScope
{
$scope = $node->getAttribute(AttributeKey::SCOPE);
$namespace = $scope instanceof Scope ? $scope->getNamespace() : null;

$uses = $this->useImportsResolver->resolve();
$usesAliasesToNames = $this->resolveUseNamesByAlias($uses);

if ($scope instanceof Scope && $scope->getClassReflection() instanceof ClassReflection) {
if ($scope instanceof Scope) {
$namespace = $scope->getNamespace();
$classReflection = $scope->getClassReflection();
$className = $classReflection->getName();
$className = $classReflection instanceof ClassReflection ? $classReflection->getName() : null;
} else {
$namespace = null;
$className = null;
}

$uses = $this->useImportsResolver->resolve();
$usesAliasesToNames = $this->resolveUseNamesByAlias($uses);

return new NameScope($namespace, $usesAliasesToNames, $className);
}

Expand Down

0 comments on commit 3c2100b

Please sign in to comment.