[PHPStan 1.0] Remove sorted union types, now handled by default (#1112)

This commit is contained in:
Tomas Votruba 2021-10-30 15:59:31 +02:00 committed by GitHub
parent 95ad690d94
commit 6a894b4939
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 68 additions and 129 deletions

View File

@ -9,8 +9,8 @@ use PhpParser\Node\Stmt\Property;
use PHPStan\Type\NullType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use PHPStan\Type\VerbosityLevel;
use Rector\StaticTypeMapper\TypeFactory\UnionTypeFactory;
use Rector\Tests\NodeTypeResolver\PerNodeTypeResolver\AbstractNodeTypeResolverTest;
use Rector\Tests\NodeTypeResolver\PerNodeTypeResolver\PropertyTypeResolver\Source\ClassThatExtendsHtml;
use Rector\Tests\NodeTypeResolver\PerNodeTypeResolver\PropertyTypeResolver\Source\Html;
@ -42,14 +42,11 @@ final class PropertyTypeResolverTest extends AbstractNodeTypeResolverTest
public function provideData(): Iterator
{
$unionTypeFactory = new UnionTypeFactory();
yield [__DIR__ . '/Source/MethodParamDocBlock.php', 0, new ObjectType(Html::class)];
yield [__DIR__ . '/Source/MethodParamDocBlock.php', 1, new ObjectType(ClassThatExtendsHtml::class)];
// mimics failing test from DomainDrivenDesign set
$unionType = $unionTypeFactory->createUnionObjectType([SomeChild::class, new NullType()]);
$unionType = new UnionType([new ObjectType(SomeChild::class), new NullType()]);
yield [__DIR__ . '/Source/ActionClass.php', 0, $unionType];
}

View File

@ -4,11 +4,9 @@ declare(strict_types=1);
namespace Rector\Tests\NodeTypeResolver\PerNodeTypeResolver\TraitTypeResolver;
use Iterator;
use PhpParser\Node\Stmt\Trait_;
use PHPStan\Type\Type;
use PHPStan\Type\ObjectType;
use PHPStan\Type\UnionType;
use Rector\StaticTypeMapper\TypeFactory\UnionTypeFactory;
use Rector\Tests\NodeTypeResolver\PerNodeTypeResolver\AbstractNodeTypeResolverTest;
use Rector\Tests\NodeTypeResolver\PerNodeTypeResolver\TraitTypeResolver\Source\AnotherTrait;
use Rector\Tests\NodeTypeResolver\PerNodeTypeResolver\TraitTypeResolver\Source\TraitWithTrait;
@ -18,28 +16,21 @@ use Rector\Tests\NodeTypeResolver\PerNodeTypeResolver\TraitTypeResolver\Source\T
*/
final class TraitTypeResolverTest extends AbstractNodeTypeResolverTest
{
/**
* @dataProvider provideData()
*/
public function test(string $file, int $nodePosition, Type $expectedType): void
public function test(): void
{
$variableNodes = $this->getNodesForFileOfType($file, Trait_::class);
$variableNodes = $this->getNodesForFileOfType(__DIR__ . '/Source/TraitWithTrait.php', Trait_::class);
$resolvedType = $this->nodeTypeResolver->getType($variableNodes[$nodePosition]);
$this->assertEquals($expectedType, $resolvedType);
$resolvedType = $this->nodeTypeResolver->getType($variableNodes[0]);
$expectedUnionType = $this->createExpectedType();
$this->assertEquals($expectedUnionType, $resolvedType);
}
/**
* @return Iterator<int[]|string[]|UnionType[]>
*/
public function provideData(): Iterator
private function createExpectedType(): UnionType
{
$unionTypeFactory = new UnionTypeFactory();
$anotherTraitObjectType = new ObjectType(AnotherTrait::class);
$traitWithTraitObjectType = new ObjectType(TraitWithTrait::class);
yield [
__DIR__ . '/Source/TraitWithTrait.php',
0,
$unionTypeFactory->createUnionObjectType([AnotherTrait::class, TraitWithTrait::class]),
];
return new UnionType([$anotherTraitObjectType, $traitWithTraitObjectType]);
}
}

View File

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace Rector\Tests\NodeTypeResolver\TypeComparator;
use Iterator;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\ArrayType;
use PHPStan\Type\ClassStringType;
use PHPStan\Type\Constant\ConstantArrayType;
@ -13,8 +13,8 @@ use PHPStan\Type\Generic\GenericClassStringType;
use PHPStan\Type\MixedType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\StringType;
use PHPStan\Type\UnionType;
use Rector\NodeTypeResolver\TypeComparator\ArrayTypeComparator;
use Rector\StaticTypeMapper\TypeFactory\UnionTypeFactory;
use Rector\Testing\PHPUnit\AbstractTestCase;
use Rector\Tests\NodeTypeResolver\TypeComparator\Source\SomeGenericTypeObject;
@ -22,38 +22,38 @@ final class ArrayTypeComparatorTest extends AbstractTestCase
{
private ArrayTypeComparator $arrayTypeComparator;
private ReflectionProvider $reflectionProvider;
protected function setUp(): void
{
$this->boot();
$this->arrayTypeComparator = $this->getService(ArrayTypeComparator::class);
$this->reflectionProvider = $this->getService(ReflectionProvider::class);
}
/**
* @dataProvider provideData()
*/
public function test(ArrayType $firstArrayType, ArrayType $secondArrayType, bool $areExpectedEqual): void
public function testClassStringSubtype(): void
{
$areEqual = $this->arrayTypeComparator->isSubtype($firstArrayType, $secondArrayType);
$this->assertSame($areExpectedEqual, $areEqual);
}
/**
* @return Iterator<ArrayType[]|bool[]>
*/
public function provideData(): Iterator
{
$unionTypeFactory = new UnionTypeFactory();
$classStringKeysArrayType = new ArrayType(new StringType(), new ClassStringType());
$stringArrayType = new ArrayType(new StringType(), new MixedType());
yield [$stringArrayType, $classStringKeysArrayType, false];
$genericClassStringType = new GenericClassStringType(new ObjectType(SomeGenericTypeObject::class));
$isSubtypeActual = $this->arrayTypeComparator->isSubtype($classStringKeysArrayType, $stringArrayType);
$this->assertTrue($isSubtypeActual);
}
public function testGenericObjectType(): void
{
$someGenericTypeObjectClassReflection = $this->reflectionProvider->getClass(SomeGenericTypeObject::class);
$objectType = new ObjectType(SomeGenericTypeObject::class, null, $someGenericTypeObjectClassReflection);
$genericClassStringType = new GenericClassStringType($objectType);
$constantArrayType = new ConstantArrayType(
[new ConstantIntegerType(0)],
[$unionTypeFactory->createUnionObjectType([$genericClassStringType, $genericClassStringType])]
[new UnionType([$genericClassStringType, $genericClassStringType])]
);
yield [$constantArrayType, $stringArrayType, false];
$stringArrayType = new ArrayType(new StringType(), new MixedType());
$isSubtypeActual = $this->arrayTypeComparator->isSubtype($constantArrayType, $stringArrayType);
$this->assertFalse($isSubtypeActual);
}
}

View File

@ -13,12 +13,12 @@ use PHPStan\Type\MixedType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use Rector\Core\Enum\ObjectReference;
use Rector\Core\NodeAnalyzer\ClassAnalyzer;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\StaticTypeMapper\TypeFactory\UnionTypeFactory;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
final class NewTypeResolver implements NodeTypeResolverInterface
@ -26,7 +26,6 @@ final class NewTypeResolver implements NodeTypeResolverInterface
public function __construct(
private NodeNameResolver $nodeNameResolver,
private ClassAnalyzer $classAnalyzer,
private UnionTypeFactory $unionTypeFactory
) {
}
@ -89,7 +88,7 @@ final class NewTypeResolver implements NodeTypeResolverInterface
}
if (count($types) > 1) {
$unionType = $this->unionTypeFactory->createUnionObjectType($types);
$unionType = new UnionType($types);
return new ObjectWithoutClassType($unionType);
}

View File

@ -18,13 +18,12 @@ use PHPStan\Type\ObjectType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeUtils;
use PHPStan\Type\UnionType;
use Rector\NodeTypeResolver\PHPStan\TypeHasher;
use Rector\StaticTypeMapper\TypeFactory\UnionTypeFactory;
final class TypeFactory
{
public function __construct(
private UnionTypeFactory $unionTypeFactory,
private TypeHasher $typeHasher,
) {
}
@ -122,7 +121,7 @@ final class TypeFactory
return $types[0];
}
return $this->unionTypeFactory->createUnionObjectType($types);
return new UnionType($types);
}
private function removeValueFromConstantType(Type $type): Type

View File

@ -15,7 +15,6 @@ use PHPStan\Type\Type;
use PHPStan\Type\TypeTraverser;
use PHPStan\Type\TypeWithClassName;
use PHPStan\Type\UnionType;
use PHPStan\Type\UnionTypeHelper;
use PHPStan\Type\VerbosityLevel;
use Rector\StaticTypeMapper\ValueObject\Type\AliasedObjectType;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
@ -87,15 +86,12 @@ final class TypeHasher
private function createUnionTypeHash(UnionType $unionType): string
{
$sortedTypes = UnionTypeHelper::sortTypes($unionType->getTypes());
$sortedUnionType = new UnionType($sortedTypes);
$booleanType = new BooleanType();
if ($booleanType->isSuperTypeOf($unionType)->yes()) {
return $booleanType->describe(VerbosityLevel::precise());
}
$normalizedUnionType = clone $sortedUnionType;
$normalizedUnionType = clone $unionType;
// change alias to non-alias
$normalizedUnionType = TypeTraverser::map(

View File

@ -8,15 +8,9 @@ use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use PHPStan\Type\TypeWithClassName;
use PHPStan\Type\UnionType;
use Rector\StaticTypeMapper\TypeFactory\UnionTypeFactory;
final class TypeUnwrapper
{
public function __construct(
private UnionTypeFactory $unionTypeFactory
) {
}
/**
* E.g. null|ClassType ClassType
*/
@ -54,6 +48,6 @@ final class TypeUnwrapper
$unionedTypesWithoutNullType[] = $type;
}
return $this->unionTypeFactory->createUnionObjectType($unionedTypesWithoutNullType);
return new UnionType($unionedTypesWithoutNullType);
}
}

View File

@ -1,36 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\StaticTypeMapper\TypeFactory;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use ReflectionClass;
use Symplify\PackageBuilder\Reflection\PrivatesAccessor;
final class UnionTypeFactory
{
/**
* @param string[]|Type[] $types
*/
public function createUnionObjectType(array $types): UnionType
{
$objectTypes = [];
foreach ($types as $type) {
$objectTypes[] = $type instanceof Type ? $type : new ObjectType($type);
}
// this is needed to prevent missing broker static fatal error, for tests with missing class
$reflectionClass = new ReflectionClass(UnionType::class);
/** @var UnionType $unionType */
$unionType = $reflectionClass->newInstanceWithoutConstructor();
$privatesAccessor = new PrivatesAccessor();
$privatesAccessor->setPrivateProperty($unionType, 'types', $objectTypes);
return $unionType;
}
}

View File

@ -22,7 +22,7 @@ namespace Rector\Tests\CodeQuality\Rector\Class_\CompleteDynamicPropertiesRector
class MultipleTypes
{
public int|string|bool $value;
public bool|int|string $value;
public function set()
{
$this->value = 5;

View File

@ -20,7 +20,7 @@ use PhpParser\Node\Name;
if (! function_exists('some_helper')) {
/**
* @param \PhpParser\Node\Name|mixed[] $item
* @param mixed[]|\PhpParser\Node\Name $item
*/
function some_helper($item)
{

View File

@ -24,7 +24,7 @@ namespace Rector\Tests\Php74\Rector\Property\TypedPropertyRector\FixtureUnionTyp
class SetIfElse
{
public string|int $stringOrInteger = 'hi';
public int|string $stringOrInteger = 'hi';
public function setNumber()
{

View File

@ -21,7 +21,7 @@ namespace Rector\Tests\Php80\Rector\FunctionLike\UnionTypesRector\Fixture;
final class RemoveDocArrayTyped
{
public function normalizeNodeValue($value): bool|float|int|string|array
public function normalizeNodeValue($value): array|bool|float|int|string
{
return $value;
}

View File

@ -21,7 +21,7 @@ namespace Rector\Tests\Php80\Rector\FunctionLike\UnionTypesRector\Fixture;
final class RemoveDocArrayTyped2
{
public function normalizeNodeValue(bool|float|int|string|array $value)
public function normalizeNodeValue(array|bool|float|int|string $value)
{
return $value;
}

View File

@ -21,7 +21,7 @@ namespace Rector\Tests\Php80\Rector\FunctionLike\UnionTypesRector\Fixture;
final class FalsePseudoType
{
public function go($value): false|int
public function go($value): int|false
{
return (int) $value ?? false;
}

View File

@ -32,7 +32,7 @@ use PhpParser\Node\Stmt\Property;
final class ParamDoc
{
public function addAsFirstMethod(Class_ $class, \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Property|\PhpParser\Node\Stmt\ClassConst $stmt): void
public function addAsFirstMethod(Class_ $class, \PhpParser\Node\Stmt\ClassConst|\PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Property $stmt): void
{
}
}

View File

@ -27,7 +27,7 @@ namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeR
final class HasOffset
{
/**
* @return mixed|mixed[]
* @return mixed[]|mixed
*/
private function convertArguments($service)
{

View File

@ -36,7 +36,7 @@ final class RespectArrayReturnType
private $items = [];
/**
* @return mixed[]|array<string, mixed[]>|array<string, int>
* @return array<string, mixed[]>
*/
public function process($message): array
{

View File

@ -24,7 +24,7 @@ final class DoNotDuplicateArrayReturn
/**
* @return bool|mixed[]|float|string[]
*/
public function go($number): bool|array|float
public function go($number): array|bool|float
{
return execute();
}

View File

@ -21,4 +21,4 @@ class PrivateVarNullUnused
private $config = null;
}
?>
?>

View File

@ -25,7 +25,7 @@ use stdClass;
class PublicVarNullUsed
{
/**
* @var null|stdClass
* @var stdClass|null
*/
public $config = null;

View File

@ -41,7 +41,7 @@ class FactoryC {}
final class RecursiveMultipleClassStringArray
{
/**
* @var array<string, mixed[]>
* @var array<string, array<class-string<\Rector\Tests\TypeDeclaration\Rector\Property\CompleteVarDocTypePropertyRector\Fixture\FactoryA>|class-string<\Rector\Tests\TypeDeclaration\Rector\Property\CompleteVarDocTypePropertyRector\Fixture\FactoryB>|class-string<\Rector\Tests\TypeDeclaration\Rector\Property\CompleteVarDocTypePropertyRector\Fixture\FactoryC>|class-string<\Rector\Tests\TypeDeclaration\Rector\Property\CompleteVarDocTypePropertyRector\Fixture\InvokableA>|class-string<\Rector\Tests\TypeDeclaration\Rector\Property\CompleteVarDocTypePropertyRector\Fixture\InvokableB>|class-string<\Rector\Tests\TypeDeclaration\Rector\Property\CompleteVarDocTypePropertyRector\Fixture\InvokableC>>>
*/
public $services = [
'invokables' => [

View File

@ -21,4 +21,4 @@ class PrivateVarNullUnused
private $config = null;
}
?>
?>

View File

@ -25,7 +25,7 @@ use stdClass;
class PublicVarNullUsed
{
/**
* @var null|stdClass
* @var stdClass|null
*/
public $config = null;

View File

@ -34,11 +34,11 @@ namespace Rector\Tests\TypeDeclaration\Rector\Property\PropertyTypeDeclarationRe
final class StaticPropertyWithDefaultNull
{
/**
* @var null|string
* @var string|null
*/
private $cacheFile = null;
/**
* @var null|string[]
* @var string[]|null
*/
private $cacheFiles = null;

View File

@ -133,9 +133,12 @@ CODE_SAMPLE
if ($varType instanceof UnionType) {
$types = $varType->getTypes();
if (count($types) === 2 && $types[0] instanceof TemplateType) {
if (count($types) === 2 && $types[1] instanceof TemplateType) {
$templateType = $types[1];
$node->type = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode(
$types[0]->getBound(),
$templateType->getBound(),
TypeKind::PROPERTY()
);

View File

@ -15,10 +15,8 @@ use PHPStan\Type\Type;
use PHPStan\Type\TypeTraverser;
use PHPStan\Type\UnionType;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
use Rector\StaticTypeMapper\TypeFactory\UnionTypeFactory;
use Rector\TypeDeclaration\ValueObject\NestedArrayType;
use Symplify\PackageBuilder\Reflection\PrivatesAccessor;
use Symplify\SimplePhpDocParser\PhpDocNodeTraverser;
/**
* @see \Rector\Tests\TypeDeclaration\TypeNormalizerTest
@ -32,8 +30,6 @@ final class TypeNormalizer
public function __construct(
private TypeFactory $typeFactory,
private UnionTypeFactory $unionTypeFactory,
// private PhpDocNodeTraverser $phpDocNodeTraverser,
private PrivatesAccessor $privatesAccessor
) {
}
@ -175,7 +171,7 @@ final class TypeNormalizer
{
$nonConstantValueTypes = array_values($nonConstantValueTypes);
if (count($nonConstantValueTypes) > 1) {
$nonConstantValueType = $this->unionTypeFactory->createUnionObjectType($nonConstantValueTypes);
$nonConstantValueType = new UnionType($nonConstantValueTypes);
} else {
$nonConstantValueType = $nonConstantValueTypes[0];
}
@ -212,7 +208,7 @@ final class TypeNormalizer
}
if (count($unionedTypes) > 1) {
return $this->unionTypeFactory->createUnionObjectType($unionedTypes);
return new UnionType($unionedTypes);
}
return $unionedTypes[0];

View File

@ -40,7 +40,7 @@ use PhpParser\Node\Expr\BooleanNot;
final class ComplexReturn
{
public function run(Expr $expr, Expr $expr2): BooleanAnd|BooleanOr|BooleanNot|Identical
public function run(Expr $expr, Expr $expr2): BooleanAnd|BooleanOr|Identical|BooleanNot
{
if (true) {
return rand(0, 1) !== 0

View File

@ -42,4 +42,4 @@ final class ElseTernaryUnion
}
}
?>
?>

View File

@ -27,7 +27,7 @@ namespace Rector\Core\Tests\Issues\IssueEarlyReturnAndOrNarrow\Fixture;
class AndNextOrReturnVoid
{
/**
* @return null|void
* @return void|null
*/
public function run($a, $b, $c, $d)
{