From 35cac5ad49640e052743686088c5b51705cc99a2 Mon Sep 17 00:00:00 2001 From: Brad <28307684+mad-briller@users.noreply.github.com> Date: Mon, 3 Oct 2022 10:34:16 +0100 Subject: [PATCH] Fixed universal object crate classes not respecting @property annotations. --- ...alObjectCratesClassReflectionExtension.php | 11 ++++- ...jectCratesClassReflectionExtensionTest.php | 44 ++++++++++++++++--- .../universal-object-crates-annotations.php | 12 +++++ 3 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 tests/PHPStan/Reflection/Php/data/universal-object-crates-annotations.php diff --git a/src/Reflection/Php/UniversalObjectCratesClassReflectionExtension.php b/src/Reflection/Php/UniversalObjectCratesClassReflectionExtension.php index 6260882e02..a5aaa8443f 100644 --- a/src/Reflection/Php/UniversalObjectCratesClassReflectionExtension.php +++ b/src/Reflection/Php/UniversalObjectCratesClassReflectionExtension.php @@ -2,6 +2,7 @@ namespace PHPStan\Reflection\Php; +use PHPStan\Reflection\Annotations\AnnotationsPropertiesClassReflectionExtension; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Reflection\PropertiesClassReflectionExtension; @@ -16,7 +17,11 @@ class UniversalObjectCratesClassReflectionExtension /** * @param string[] $classes */ - public function __construct(private ReflectionProvider $reflectionProvider, private array $classes) + public function __construct( + private ReflectionProvider $reflectionProvider, + private array $classes, + private AnnotationsPropertiesClassReflectionExtension $annotationClassReflection, + ) { } @@ -56,6 +61,10 @@ public static function isUniversalObjectCrate( public function getProperty(ClassReflection $classReflection, string $propertyName): PropertyReflection { + if ($this->annotationClassReflection->hasProperty($classReflection, $propertyName)) { + return $this->annotationClassReflection->getProperty($classReflection, $propertyName); + } + if ($classReflection->hasNativeMethod('__get')) { $readableType = ParametersAcceptorSelector::selectSingle($classReflection->getNativeMethod('__get')->getVariants())->getReturnType(); } else { diff --git a/tests/PHPStan/Reflection/Php/UniversalObjectCratesClassReflectionExtensionTest.php b/tests/PHPStan/Reflection/Php/UniversalObjectCratesClassReflectionExtensionTest.php index da08f803b7..dabd3948e0 100644 --- a/tests/PHPStan/Reflection/Php/UniversalObjectCratesClassReflectionExtensionTest.php +++ b/tests/PHPStan/Reflection/Php/UniversalObjectCratesClassReflectionExtensionTest.php @@ -2,6 +2,7 @@ namespace PHPStan\Reflection\Php; +use PHPStan\Reflection\Annotations\AnnotationsPropertiesClassReflectionExtension; use PHPStan\Testing\PHPStanTestCase; use PHPStan\Type\ObjectType; use PHPStan\Type\StringType; @@ -13,10 +14,11 @@ class UniversalObjectCratesClassReflectionExtensionTest extends PHPStanTestCase public function testNonexistentClass(): void { $reflectionProvider = $this->createReflectionProvider(); - $extension = new UniversalObjectCratesClassReflectionExtension($reflectionProvider, [ - 'NonexistentClass', - 'stdClass', - ]); + $extension = new UniversalObjectCratesClassReflectionExtension( + $reflectionProvider, + ['NonexistentClass', 'stdClass'], + new AnnotationsPropertiesClassReflectionExtension(), + ); $this->assertTrue($extension->hasProperty($reflectionProvider->getClass(stdClass::class), 'foo')); } @@ -25,9 +27,11 @@ public function testDifferentGetSetType(): void require_once __DIR__ . '/data/universal-object-crates.php'; $reflectionProvider = $this->createReflectionProvider(); - $extension = new UniversalObjectCratesClassReflectionExtension($reflectionProvider, [ - 'UniversalObjectCreates\DifferentGetSetTypes', - ]); + $extension = new UniversalObjectCratesClassReflectionExtension( + $reflectionProvider, + ['UniversalObjectCreates\DifferentGetSetTypes'], + new AnnotationsPropertiesClassReflectionExtension(), + ); $this->assertEquals( new ObjectType('UniversalObjectCreates\DifferentGetSetTypesValue'), @@ -43,4 +47,30 @@ public function testDifferentGetSetType(): void ); } + public function testAnnotationOverrides(): void + { + require_once __DIR__ . '/data/universal-object-crates-annotations.php'; + $className = 'UniversalObjectCratesAnnotations\Model'; + + $reflectionProvider = $this->createReflectionProvider(); + $extension = new UniversalObjectCratesClassReflectionExtension( + $reflectionProvider, + [$className], + new AnnotationsPropertiesClassReflectionExtension(), + ); + + $this->assertEquals( + new StringType(), + $extension + ->getProperty($reflectionProvider->getClass($className), 'foo') + ->getReadableType(), + ); + $this->assertEquals( + new StringType(), + $extension + ->getProperty($reflectionProvider->getClass($className), 'foo') + ->getWritableType(), + ); + } + } diff --git a/tests/PHPStan/Reflection/Php/data/universal-object-crates-annotations.php b/tests/PHPStan/Reflection/Php/data/universal-object-crates-annotations.php new file mode 100644 index 0000000000..09cf01b20b --- /dev/null +++ b/tests/PHPStan/Reflection/Php/data/universal-object-crates-annotations.php @@ -0,0 +1,12 @@ +