From d8bc1da00446e8c332eeecdc913d422bc7db0e91 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Mon, 30 Dec 2019 15:19:37 +0100 Subject: [PATCH 1/5] [PHP 7.4] Add @var removal to TypedPropertyRector --- .../Rector/Property/TypedPropertyRector.php | 28 ++++++++++++++-- .../Fixture/bool_property.php.inc | 1 - .../Fixture/class_property.php.inc | 3 -- .../Fixture/default_values.php.inc | 33 ------------------- ...ault_values_for_nullable_iterables.php.inc | 9 ----- .../Fixture/match_types.php.inc | 27 --------------- .../Fixture/match_types_parent.php.inc | 3 -- .../Fixture/nullable_property.php.inc | 6 ---- .../Fixture/nullable_property_scalar.php.inc | 3 -- .../Fixture/property.php.inc | 3 -- .../Fixture/static_property.php.inc | 3 -- .../parent_has_untyped_property.php.inc | 2 -- ...ent_of_parent_has_untyped_property.php.inc | 2 -- .../FixtureUnionTypes/two_types.php.inc | 3 -- 14 files changed, 25 insertions(+), 101 deletions(-) diff --git a/packages/Php74/src/Rector/Property/TypedPropertyRector.php b/packages/Php74/src/Rector/Property/TypedPropertyRector.php index dbc03697c434..bccdb5fd5579 100644 --- a/packages/Php74/src/Rector/Property/TypedPropertyRector.php +++ b/packages/Php74/src/Rector/Property/TypedPropertyRector.php @@ -6,6 +6,7 @@ use PhpParser\Node; use PhpParser\Node\Stmt\Property; +use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode; use PHPStan\Type\MixedType; use Rector\Rector\AbstractRector; use Rector\RectorDefinition\CodeSample; @@ -56,9 +57,6 @@ final class SomeClass <<<'PHP' final class SomeClass { - /** - * @var int - */ private int count; } PHP @@ -103,8 +101,32 @@ public function refactor(Node $node): ?Node return null; } + $this->removeVarPhpTagValueNodeIfNotComment($node); + $node->type = $propertyTypeNode; return $node; } + + private function removeVarPhpTagValueNodeIfNotComment(Property $property): void + { + $propertyPhpDocInfo = $this->getPhpDocInfo($property); + // nothing to remove + if ($propertyPhpDocInfo === null) { + return; + } + + $varTagValueNode = $propertyPhpDocInfo->getByType(VarTagValueNode::class); + if ($varTagValueNode === null) { + return; + } + + // has description? keep it + if ($varTagValueNode->description !== '') { + return; + } + + $propertyPhpDocInfo->removeByType(VarTagValueNode::class); + $this->docBlockManipulator->updateNodeWithPhpDocInfo($property, $propertyPhpDocInfo); + } } diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/bool_property.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/bool_property.php.inc index 5c30e3a9ed07..f295fe383c8b 100644 --- a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/bool_property.php.inc +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/bool_property.php.inc @@ -20,7 +20,6 @@ namespace Rector\Php74\Tests\Rector\Property\TypedPropertyRector\Fixture; final class BoolProperty { /** - * @var bool * another comment */ private bool $isTrue = false; diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/class_property.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/class_property.php.inc index 07211d748b47..cda76080b34e 100644 --- a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/class_property.php.inc +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/class_property.php.inc @@ -22,9 +22,6 @@ use Rector\TypeDeclaration\Tests\Rector\Property\TypedPropertyRector\Source\Anot final class ClassWithClassProperty { - /** - * @var AnotherClass - */ private \Rector\TypeDeclaration\Tests\Rector\Property\TypedPropertyRector\Source\AnotherClass $anotherClass; } diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/default_values.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/default_values.php.inc index c619b20460cb..62d814a43179 100644 --- a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/default_values.php.inc +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/default_values.php.inc @@ -68,59 +68,26 @@ namespace Rector\Php74\Tests\Rector\Property\TypedPropertyRector\Fixture; final class DefaultValues { - /** - * @var bool - */ private string $name = 'not_a_bool'; - /** - * @var bool - */ private bool $isItRealName = false; - /** - * @var bool - */ private ?bool $isItRealNameNull = null; - /** - * @var string - */ private bool $size = false; - /** - * @var float - */ private float $a = 42.42; - /** - * @var float - */ private int $b = 42; - /** - * @var float - */ private string $c = 'hey'; - /** - * @var int - */ private float $e = 42.42; - /** - * @var int - */ private int $f = 42; - /** - * @var array - */ private array $g = [1, 2, 3]; - /** - * @var iterable - */ private array $h = [1, 2, 3]; } diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/default_values_for_nullable_iterables.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/default_values_for_nullable_iterables.php.inc index 52cc5a275cf4..84750fceb9fb 100644 --- a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/default_values_for_nullable_iterables.php.inc +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/default_values_for_nullable_iterables.php.inc @@ -28,19 +28,10 @@ namespace Rector\Php74\Tests\Rector\Property\TypedPropertyRector\Fixture; final class DefaultValuesForNullableIterables { - /** - * @var array - */ private ?array $items = null; - /** - * @var iterable - */ private ?iterable $itemsB = null; - /** - * @var array|null - */ private ?array $nullableItems = null; } diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/match_types.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/match_types.php.inc index 93cfbddeffa6..f81874418694 100644 --- a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/match_types.php.inc +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/match_types.php.inc @@ -58,49 +58,22 @@ namespace Rector\Php74\Tests\Rector\Property\TypedPropertyRector\Fixture; final class MatchTypes { - /** - * @var bool - */ private bool $a; - /** - * @var boolean - */ private bool $b; - /** - * @var int - */ private int $c; - /** - * @var integer - */ private int $d; - /** - * @var float - */ private float $e; - /** - * @var string - */ private string $f; - /** - * @var object - */ private object $g; - /** - * @var iterable - */ private iterable $h; - /** - * @var self - */ private self $i; } diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/match_types_parent.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/match_types_parent.php.inc index c19ce68afc5d..caaf4b122f15 100644 --- a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/match_types_parent.php.inc +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/match_types_parent.php.inc @@ -28,9 +28,6 @@ class PropperParent final class MatchTypesParent extends PropperParent { - /** - * @var parent - */ private parent $j; } diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/nullable_property.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/nullable_property.php.inc index 4767dc38e8be..d2c736513a0f 100644 --- a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/nullable_property.php.inc +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/nullable_property.php.inc @@ -27,14 +27,8 @@ use Rector\TypeDeclaration\Tests\Rector\Property\TypedPropertyRector\Source\Anot final class ClassWithNullableProperty { - /** - * @var AnotherClass|null - */ private ?\Rector\TypeDeclaration\Tests\Rector\Property\TypedPropertyRector\Source\AnotherClass $nullableClassWithDefaultNull = null; - /** - * @var null|AnotherClass - */ private ?\Rector\TypeDeclaration\Tests\Rector\Property\TypedPropertyRector\Source\AnotherClass $yetAnotherClass; } diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/nullable_property_scalar.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/nullable_property_scalar.php.inc index 1344f90fa16a..880fbeb3bd39 100644 --- a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/nullable_property_scalar.php.inc +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/nullable_property_scalar.php.inc @@ -23,9 +23,6 @@ namespace Rector\Php74\Tests\Rector\Property\TypedPropertyRector\Fixture; final class NullablePropertyScalar { - /** - * @var int|null - */ private ?int $countOrNull; public function countOrNull(): ?int diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/property.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/property.php.inc index 62086b44a835..5eaa5d187a11 100644 --- a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/property.php.inc +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/property.php.inc @@ -33,9 +33,6 @@ namespace Rector\Php74\Tests\Rector\Property\TypedPropertyRector\Fixture; final class ClassWithProperty { - /** - * @var int - */ private int $count; /** diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/static_property.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/static_property.php.inc index 687f82cc1a3a..5cb49765b3e6 100644 --- a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/static_property.php.inc +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/static_property.php.inc @@ -22,9 +22,6 @@ use Rector\TypeDeclaration\Tests\Rector\Property\TypedPropertyRector\Source\Anot final class ClassWithStaticProperty { - /** - * @var iterable - */ private static iterable $iterable; } diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/FixturePhp74/parent_has_untyped_property.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/FixturePhp74/parent_has_untyped_property.php.inc index 826e7f5841fb..9e62e82314af 100644 --- a/packages/Php74/tests/Rector/Property/TypedPropertyRector/FixturePhp74/parent_has_untyped_property.php.inc +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/FixturePhp74/parent_has_untyped_property.php.inc @@ -16,5 +16,3 @@ final class Child extends SomeParent */ protected string $typedName = 'child'; } - -?> diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/FixturePhp74/parent_of_parent_has_untyped_property.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/FixturePhp74/parent_of_parent_has_untyped_property.php.inc index 8d23050a212f..c26bcca05066 100644 --- a/packages/Php74/tests/Rector/Property/TypedPropertyRector/FixturePhp74/parent_of_parent_has_untyped_property.php.inc +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/FixturePhp74/parent_of_parent_has_untyped_property.php.inc @@ -20,5 +20,3 @@ final class Child2 extends Middle */ protected string $typedName = 'child'; } - -?> diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/FixtureUnionTypes/two_types.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/FixtureUnionTypes/two_types.php.inc index f735ed6d5d41..df6d9672f11d 100644 --- a/packages/Php74/tests/Rector/Property/TypedPropertyRector/FixtureUnionTypes/two_types.php.inc +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/FixtureUnionTypes/two_types.php.inc @@ -18,9 +18,6 @@ namespace Rector\Php74\Tests\Rector\Property\TypedPropertyRector\FixtureUnionTyp final class TwoTypes { - /** - * @var bool|string - */ private bool|string $unionValue; } From 8e4e386c9111f8d46afeb1fef8d15f0dd98a4f62 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Mon, 30 Dec 2019 17:53:28 +0100 Subject: [PATCH 2/5] simplify PHP 7.4 test --- .../parent_has_untyped_property.php.inc | 2 +- .../parent_of_parent_has_untyped_property.php.inc | 2 +- .../TypedPropertyRector/Source/SomeParent.php | 2 +- .../TypedPropertyRectorTest.php | 14 -------------- 4 files changed, 3 insertions(+), 17 deletions(-) rename packages/Php74/tests/Rector/Property/TypedPropertyRector/{FixturePhp74 => Fixture}/parent_has_untyped_property.php.inc (87%) rename packages/Php74/tests/Rector/Property/TypedPropertyRector/{FixturePhp74 => Fixture}/parent_of_parent_has_untyped_property.php.inc (88%) diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/FixturePhp74/parent_has_untyped_property.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/parent_has_untyped_property.php.inc similarity index 87% rename from packages/Php74/tests/Rector/Property/TypedPropertyRector/FixturePhp74/parent_has_untyped_property.php.inc rename to packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/parent_has_untyped_property.php.inc index 9e62e82314af..4bcadce659ea 100644 --- a/packages/Php74/tests/Rector/Property/TypedPropertyRector/FixturePhp74/parent_has_untyped_property.php.inc +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/parent_has_untyped_property.php.inc @@ -14,5 +14,5 @@ final class Child extends SomeParent /** * @var string */ - protected string $typedName = 'child'; + protected $typedName = 'child'; } diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/FixturePhp74/parent_of_parent_has_untyped_property.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/parent_of_parent_has_untyped_property.php.inc similarity index 88% rename from packages/Php74/tests/Rector/Property/TypedPropertyRector/FixturePhp74/parent_of_parent_has_untyped_property.php.inc rename to packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/parent_of_parent_has_untyped_property.php.inc index c26bcca05066..c0e282d8dcb2 100644 --- a/packages/Php74/tests/Rector/Property/TypedPropertyRector/FixturePhp74/parent_of_parent_has_untyped_property.php.inc +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/parent_of_parent_has_untyped_property.php.inc @@ -18,5 +18,5 @@ final class Child2 extends Middle /** * @var string */ - protected string $typedName = 'child'; + protected $typedName = 'child'; } diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Source/SomeParent.php b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Source/SomeParent.php index 17cdd0b32989..78cb426c3e0f 100644 --- a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Source/SomeParent.php +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Source/SomeParent.php @@ -14,5 +14,5 @@ abstract class SomeParent /** * @var string */ - protected string $typedName; + protected $typedName; } diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/TypedPropertyRectorTest.php b/packages/Php74/tests/Rector/Property/TypedPropertyRector/TypedPropertyRectorTest.php index 071b02982158..97f26ebd420d 100644 --- a/packages/Php74/tests/Rector/Property/TypedPropertyRector/TypedPropertyRectorTest.php +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/TypedPropertyRectorTest.php @@ -23,20 +23,6 @@ public function provideDataForTest(): Iterator return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture'); } - /** - * @requires PHP >= 7.4 - * @dataProvider provideDataForTest() - */ - public function testPhp74(string $file): void - { - $this->doTestFile($file); - } - - public function provideDataForTestPhp74(): Iterator - { - return $this->yieldFilesFromDirectory(__DIR__ . '/FixturePhp74'); - } - protected function getRectorClass(): string { return TypedPropertyRector::class; From 38a6bbdcfc47edc1d6cdacaef4c889cdfde2dd75 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Mon, 30 Dec 2019 18:03:48 +0100 Subject: [PATCH 3/5] keep non-simple array types for typed properties --- .../NodeTypeResolver/src/StaticTypeMapper.php | 7 ++++ .../Rector/Property/TypedPropertyRector.php | 40 ++++++++++++++++++ .../Fixture/complex_array.php.inc | 41 +++++++++++++++++++ .../Fixture/simple_array.php.inc | 24 +++++++++++ 4 files changed, 112 insertions(+) create mode 100644 packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/complex_array.php.inc create mode 100644 packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/simple_array.php.inc diff --git a/packages/NodeTypeResolver/src/StaticTypeMapper.php b/packages/NodeTypeResolver/src/StaticTypeMapper.php index ea59e51f7f2e..df7720cd8894 100644 --- a/packages/NodeTypeResolver/src/StaticTypeMapper.php +++ b/packages/NodeTypeResolver/src/StaticTypeMapper.php @@ -554,6 +554,13 @@ public function mapStringToPhpParserNode(string $type): ?Node throw new NotImplementedException(sprintf('%s for "%s"', __METHOD__, $type)); } + public function mapPHPStanPhpDocTypeNodeToPhpDocString(TypeNode $typeNode, Node $node): string + { + $phpStanType = $this->mapPHPStanPhpDocTypeNodeToPHPStanType($typeNode, $node); + + return $this->mapPHPStanTypeToDocString($phpStanType); + } + public function mapPHPStanPhpDocTypeNodeToPHPStanType(TypeNode $typeNode, Node $node): Type { if ($typeNode instanceof IdentifierTypeNode) { diff --git a/packages/Php74/src/Rector/Property/TypedPropertyRector.php b/packages/Php74/src/Rector/Property/TypedPropertyRector.php index bccdb5fd5579..5875c2e68af5 100644 --- a/packages/Php74/src/Rector/Property/TypedPropertyRector.php +++ b/packages/Php74/src/Rector/Property/TypedPropertyRector.php @@ -7,6 +7,9 @@ use PhpParser\Node; use PhpParser\Node\Stmt\Property; use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode; +use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode; +use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; +use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\Type\MixedType; use Rector\Rector\AbstractRector; use Rector\RectorDefinition\CodeSample; @@ -126,7 +129,44 @@ private function removeVarPhpTagValueNodeIfNotComment(Property $property): void return; } + // keep string[] etc. + if ($this->isNonBasicArrayType($property, $varTagValueNode)) { + return; + } + $propertyPhpDocInfo->removeByType(VarTagValueNode::class); $this->docBlockManipulator->updateNodeWithPhpDocInfo($property, $propertyPhpDocInfo); } + + private function isNonBasicArrayType(Property $property, VarTagValueNode $varTagValueNode): bool + { + if (! $this->isArrayGenericTypeNode($varTagValueNode) && ! $this->isArrayTypeNode($varTagValueNode)) { + return false; + } + + $varTypeDocString = $this->staticTypeMapper->mapPHPStanPhpDocTypeNodeToPhpDocString( + $varTagValueNode->type, + $property + ); + + return $varTypeDocString !== 'array'; + } + + private function isArrayGenericTypeNode(VarTagValueNode $varTagValueNode): bool + { + if (! $varTagValueNode->type instanceof GenericTypeNode) { + return false; + } + + if (! $varTagValueNode->type->type instanceof IdentifierTypeNode) { + return false; + } + + return $varTagValueNode->type->type->name === 'array'; + } + + private function isArrayTypeNode(VarTagValueNode $varTagValueNode): bool + { + return $varTagValueNode->type instanceof ArrayTypeNode; + } } diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/complex_array.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/complex_array.php.inc new file mode 100644 index 000000000000..c71d098ea4be --- /dev/null +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/complex_array.php.inc @@ -0,0 +1,41 @@ + + */ + private $foo; + + /** + * @var int[] + */ + private $foos; +} + +?> +----- + + */ + private array $foo; + + /** + * @var int[] + */ + private array $foos; +} + +?> diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/simple_array.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/simple_array.php.inc new file mode 100644 index 000000000000..f844f75e65c0 --- /dev/null +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/simple_array.php.inc @@ -0,0 +1,24 @@ + +----- + From 52014ab27769ed3764a7b76699d93a6a28438ed5 Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Mon, 30 Dec 2019 18:53:50 +0100 Subject: [PATCH 4/5] handle generics --- .../NodeTypeResolver/src/StaticTypeMapper.php | 21 +++++++- .../Fixture/non_array_generic_types.php.inc | 53 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/non_array_generic_types.php.inc diff --git a/packages/NodeTypeResolver/src/StaticTypeMapper.php b/packages/NodeTypeResolver/src/StaticTypeMapper.php index df7720cd8894..16467d30425f 100644 --- a/packages/NodeTypeResolver/src/StaticTypeMapper.php +++ b/packages/NodeTypeResolver/src/StaticTypeMapper.php @@ -31,6 +31,7 @@ use PHPStan\Type\ClosureType; use PHPStan\Type\ConstantType; use PHPStan\Type\FloatType; +use PHPStan\Type\Generic\GenericObjectType; use PHPStan\Type\IntegerType; use PHPStan\Type\IntersectionType; use PHPStan\Type\IterableType; @@ -645,7 +646,11 @@ public function mapPHPStanPhpDocTypeNodeToPHPStanType(TypeNode $typeNode, Node $ if ($typeNode instanceof GenericTypeNode) { if ($typeNode->type instanceof IdentifierTypeNode) { $typeName = $typeNode->type->name; - if (in_array($typeName, ['array', 'iterable'], true)) { + + // remove extra prefix + $typeName = ltrim($typeName, '\\'); + + if (in_array($typeName, ['array', 'iterable', 'Traversable'], true)) { $genericTypes = []; foreach ($typeNode->genericTypes as $genericTypeNode) { $genericTypes[] = $this->mapPHPStanPhpDocTypeNodeToPHPStanType($genericTypeNode, $node); @@ -660,6 +665,20 @@ public function mapPHPStanPhpDocTypeNodeToPHPStanType(TypeNode $typeNode, Node $ return new IterableType(new MixedType(), $genericType); } } + + $mainType = $this->mapPHPStanPhpDocTypeNodeToPHPStanType($typeNode->type, $node); + if ($mainType instanceof TypeWithClassName) { + $className = $mainType->getClassName(); + } else { + throw new NotImplementedException(); + } + + $genericTypes = []; + foreach ($typeNode->genericTypes as $genericType) { + $genericTypes[] = $this->mapPHPStanPhpDocTypeNodeToPHPStanType($genericType, $node); + } + + return new GenericObjectType($className, $genericTypes); } throw new NotImplementedException(__METHOD__ . ' for ' . get_class($typeNode)); diff --git a/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/non_array_generic_types.php.inc b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/non_array_generic_types.php.inc new file mode 100644 index 000000000000..caa305f4694b --- /dev/null +++ b/packages/Php74/tests/Rector/Property/TypedPropertyRector/Fixture/non_array_generic_types.php.inc @@ -0,0 +1,53 @@ + + */ + private $foo; + + /** + * @var Promise + */ + private $bar; +} + +?> +----- + + */ + private \Traversable $foo; + + /** + * @var Promise + */ + private \Rector\Php74\Tests\Rector\Property\TypedPropertyRector\Fixture\Promise $bar; +} + +?> From b40a1514bdaea975ee03041be97939275aee69dd Mon Sep 17 00:00:00 2001 From: TomasVotruba Date: Mon, 30 Dec 2019 19:00:15 +0100 Subject: [PATCH 5/5] skip generic types --- .../NodeTypeResolver/src/StaticTypeMapper.php | 4 ++++ .../Rector/Property/TypedPropertyRector.php | 21 ++++++------------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/packages/NodeTypeResolver/src/StaticTypeMapper.php b/packages/NodeTypeResolver/src/StaticTypeMapper.php index 16467d30425f..d88882f7b4fb 100644 --- a/packages/NodeTypeResolver/src/StaticTypeMapper.php +++ b/packages/NodeTypeResolver/src/StaticTypeMapper.php @@ -662,6 +662,10 @@ public function mapPHPStanPhpDocTypeNodeToPHPStanType(TypeNode $typeNode, Node $ return new ArrayType(new MixedType(), $genericType); } + if ($typeName === 'Traversable') { + return new ObjectType('Traversable'); + } + return new IterableType(new MixedType(), $genericType); } } diff --git a/packages/Php74/src/Rector/Property/TypedPropertyRector.php b/packages/Php74/src/Rector/Property/TypedPropertyRector.php index 5875c2e68af5..02b4a9815cd0 100644 --- a/packages/Php74/src/Rector/Property/TypedPropertyRector.php +++ b/packages/Php74/src/Rector/Property/TypedPropertyRector.php @@ -9,7 +9,6 @@ use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode; use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode; use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; -use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\Type\MixedType; use Rector\Rector\AbstractRector; use Rector\RectorDefinition\CodeSample; @@ -129,6 +128,11 @@ private function removeVarPhpTagValueNodeIfNotComment(Property $property): void return; } + // keep generic types + if ($varTagValueNode->type instanceof GenericTypeNode) { + return; + } + // keep string[] etc. if ($this->isNonBasicArrayType($property, $varTagValueNode)) { return; @@ -140,7 +144,7 @@ private function removeVarPhpTagValueNodeIfNotComment(Property $property): void private function isNonBasicArrayType(Property $property, VarTagValueNode $varTagValueNode): bool { - if (! $this->isArrayGenericTypeNode($varTagValueNode) && ! $this->isArrayTypeNode($varTagValueNode)) { + if (! $this->isArrayTypeNode($varTagValueNode)) { return false; } @@ -152,19 +156,6 @@ private function isNonBasicArrayType(Property $property, VarTagValueNode $varTag return $varTypeDocString !== 'array'; } - private function isArrayGenericTypeNode(VarTagValueNode $varTagValueNode): bool - { - if (! $varTagValueNode->type instanceof GenericTypeNode) { - return false; - } - - if (! $varTagValueNode->type->type instanceof IdentifierTypeNode) { - return false; - } - - return $varTagValueNode->type->type->name === 'array'; - } - private function isArrayTypeNode(VarTagValueNode $varTagValueNode): bool { return $varTagValueNode->type instanceof ArrayTypeNode;