From 8ebc0999021dbaefc265045574633a083d7ff66b Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 22 Oct 2022 17:06:44 +0200 Subject: [PATCH 1/6] implement FunctionReflection/ExtendedMethodReflection returnsByReference() --- src/Analyser/MutatingScope.php | 2 + .../AnnotationMethodReflection.php | 5 ++ .../BetterReflectionProvider.php | 1 + .../Dummy/ChangedTypeMethodReflection.php | 5 ++ .../Dummy/DummyMethodReflection.php | 5 ++ src/Reflection/ExtendedMethodReflection.php | 2 + src/Reflection/FunctionReflection.php | 2 + src/Reflection/FunctionReflectionFactory.php | 1 + .../Native/NativeFunctionReflection.php | 6 +++ .../Native/NativeMethodReflection.php | 6 +++ .../Php/ClosureCallMethodReflection.php | 5 ++ .../Php/EnumCasesMethodReflection.php | 5 ++ .../Php/PhpClassReflectionExtension.php | 7 +++ .../PhpFunctionFromParserNodeReflection.php | 6 +++ src/Reflection/Php/PhpFunctionReflection.php | 6 +++ .../Php/PhpMethodFromParserNodeReflection.php | 2 + src/Reflection/Php/PhpMethodReflection.php | 6 +++ .../Php/PhpMethodReflectionFactory.php | 1 + src/Reflection/ResolvedMethodReflection.php | 5 ++ .../NativeFunctionReflectionProvider.php | 3 ++ .../Type/IntersectionTypeMethodReflection.php | 5 ++ .../Type/UnionTypeMethodReflection.php | 5 ++ .../WrappedExtendedMethodReflection.php | 5 ++ .../Reflection/FunctionReflectionTest.php | 46 +++++++++++++++++++ .../Reflection/data/returns-by-reference.php | 18 ++++++++ 25 files changed, 160 insertions(+) create mode 100644 tests/PHPStan/Reflection/data/returns-by-reference.php diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index bcf9bf024d..5730d405f4 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -2567,6 +2567,7 @@ public function enterClassMethod( $selfOutType, $phpDocComment, array_map(static fn (Type $type): Type => TemplateTypeHelper::toArgument($type), $parameterOutTypes), + null, ), !$classMethod->isStatic(), ); @@ -2672,6 +2673,7 @@ public function enterFunction( $asserts ?? Assertions::createEmpty(), $phpDocComment, array_map(static fn (Type $type): Type => TemplateTypeHelper::toArgument($type), $parameterOutTypes), + null, ), false, ); diff --git a/src/Reflection/Annotations/AnnotationMethodReflection.php b/src/Reflection/Annotations/AnnotationMethodReflection.php index c9d3b79cdb..1203792812 100644 --- a/src/Reflection/Annotations/AnnotationMethodReflection.php +++ b/src/Reflection/Annotations/AnnotationMethodReflection.php @@ -127,4 +127,9 @@ public function getSelfOutType(): ?Type return null; } + public function returnsByReference(): ?bool + { + return null; + } + } diff --git a/src/Reflection/BetterReflection/BetterReflectionProvider.php b/src/Reflection/BetterReflection/BetterReflectionProvider.php index 0766abd21a..344b458b97 100644 --- a/src/Reflection/BetterReflection/BetterReflectionProvider.php +++ b/src/Reflection/BetterReflection/BetterReflectionProvider.php @@ -307,6 +307,7 @@ private function getCustomFunction(string $functionName): PhpFunctionReflection $asserts, $phpDocComment, array_map(static fn (ParamOutTag $paramOutTag): Type => $paramOutTag->getType(), $phpDocParameterOutTags), + $reflectionFunction->returnsReference(), ); } diff --git a/src/Reflection/Dummy/ChangedTypeMethodReflection.php b/src/Reflection/Dummy/ChangedTypeMethodReflection.php index 9c2434d60d..bd4625677f 100644 --- a/src/Reflection/Dummy/ChangedTypeMethodReflection.php +++ b/src/Reflection/Dummy/ChangedTypeMethodReflection.php @@ -100,4 +100,9 @@ public function getSelfOutType(): ?Type return $this->reflection->getSelfOutType(); } + public function returnsByReference(): ?bool + { + return $this->reflection->returnsByReference(); + } + } diff --git a/src/Reflection/Dummy/DummyMethodReflection.php b/src/Reflection/Dummy/DummyMethodReflection.php index 19a6d690ac..130b92cc3e 100644 --- a/src/Reflection/Dummy/DummyMethodReflection.php +++ b/src/Reflection/Dummy/DummyMethodReflection.php @@ -107,4 +107,9 @@ public function getSelfOutType(): ?Type return null; } + public function returnsByReference(): ?bool + { + return null; + } + } diff --git a/src/Reflection/ExtendedMethodReflection.php b/src/Reflection/ExtendedMethodReflection.php index ec16f3d29c..5619731b3d 100644 --- a/src/Reflection/ExtendedMethodReflection.php +++ b/src/Reflection/ExtendedMethodReflection.php @@ -25,4 +25,6 @@ public function getAsserts(): Assertions; public function getSelfOutType(): ?Type; + public function returnsByReference(): ?bool; + } diff --git a/src/Reflection/FunctionReflection.php b/src/Reflection/FunctionReflection.php index 3827d5cdff..d7801c79a0 100644 --- a/src/Reflection/FunctionReflection.php +++ b/src/Reflection/FunctionReflection.php @@ -36,4 +36,6 @@ public function getAsserts(): Assertions; public function getDocComment(): ?string; + public function returnsByReference(): ?bool; + } diff --git a/src/Reflection/FunctionReflectionFactory.php b/src/Reflection/FunctionReflectionFactory.php index 28382fd315..82144ae6da 100644 --- a/src/Reflection/FunctionReflectionFactory.php +++ b/src/Reflection/FunctionReflectionFactory.php @@ -29,6 +29,7 @@ public function create( Assertions $asserts, ?string $phpDocComment, array $phpDocParameterOutTypes, + ?bool $returnsByReference, ): PhpFunctionReflection; } diff --git a/src/Reflection/Native/NativeFunctionReflection.php b/src/Reflection/Native/NativeFunctionReflection.php index 440a41b0a4..982a059cc7 100644 --- a/src/Reflection/Native/NativeFunctionReflection.php +++ b/src/Reflection/Native/NativeFunctionReflection.php @@ -25,6 +25,7 @@ public function __construct( private bool $isDeprecated, ?Assertions $assertions = null, private ?string $phpDocComment = null, + private ?bool $returnsByReference = null, ) { $this->assertions = $assertions ?? Assertions::createEmpty(); @@ -108,4 +109,9 @@ public function getDocComment(): ?string return $this->phpDocComment; } + public function returnsByReference(): ?bool + { + return $this->returnsByReference; + } + } diff --git a/src/Reflection/Native/NativeMethodReflection.php b/src/Reflection/Native/NativeMethodReflection.php index 951cde3382..4b5f4b8e30 100644 --- a/src/Reflection/Native/NativeMethodReflection.php +++ b/src/Reflection/Native/NativeMethodReflection.php @@ -33,6 +33,7 @@ public function __construct( private Assertions $assertions, private ?Type $selfOutType, private ?string $phpDocComment, + private ?bool $returnsByReference, ) { } @@ -167,4 +168,9 @@ public function getSelfOutType(): ?Type return $this->selfOutType; } + public function returnsByReference(): ?bool + { + return $this->returnsByReference; + } + } diff --git a/src/Reflection/Php/ClosureCallMethodReflection.php b/src/Reflection/Php/ClosureCallMethodReflection.php index e5dda920c6..0e5f7a2712 100644 --- a/src/Reflection/Php/ClosureCallMethodReflection.php +++ b/src/Reflection/Php/ClosureCallMethodReflection.php @@ -129,4 +129,9 @@ public function getSelfOutType(): ?Type return $this->nativeMethodReflection->getSelfOutType(); } + public function returnsByReference(): ?bool + { + return $this->nativeMethodReflection->returnsByReference(); + } + } diff --git a/src/Reflection/Php/EnumCasesMethodReflection.php b/src/Reflection/Php/EnumCasesMethodReflection.php index 733bb69f79..a5cd069e7d 100644 --- a/src/Reflection/Php/EnumCasesMethodReflection.php +++ b/src/Reflection/Php/EnumCasesMethodReflection.php @@ -116,4 +116,9 @@ public function getSelfOutType(): ?Type return null; } + public function returnsByReference(): ?bool + { + return null; + } + } diff --git a/src/Reflection/Php/PhpClassReflectionExtension.php b/src/Reflection/Php/PhpClassReflectionExtension.php index f7ab2e78bf..49fafe4d78 100644 --- a/src/Reflection/Php/PhpClassReflectionExtension.php +++ b/src/Reflection/Php/PhpClassReflectionExtension.php @@ -496,6 +496,11 @@ private function createMethod( return new EnumCasesMethodReflection($declaringClass, $arrayBuilder->getArray()); } + $returnsByReference = null; + if ($methodReflection->getReflection() !== null) { + $returnsByReference = $methodReflection->getReflection()->returnsReference(); + } + if ($this->signatureMapProvider->hasMethodSignature($declaringClassName, $methodReflection->getName())) { $variants = []; $reflectionMethod = null; @@ -629,6 +634,7 @@ private function createMethod( $asserts, $selfOutType, $phpDocComment, + $returnsByReference, ); } @@ -782,6 +788,7 @@ private function createMethod( $selfOutType, $phpDocComment, $phpDocParameterOutTypes, + $returnsByReference, ); } diff --git a/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php b/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php index 2e3ffec0d0..a4f0e82886 100644 --- a/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php +++ b/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php @@ -59,6 +59,7 @@ public function __construct( private Assertions $assertions, private ?string $phpDocComment, private array $parameterOutTypes, + private ?bool $returnsByReference, ) { $this->functionLike = $functionLike; @@ -260,4 +261,9 @@ public function getDocComment(): ?string return $this->phpDocComment; } + public function returnsByReference(): ?bool + { + return $this->returnsByReference; + } + } diff --git a/src/Reflection/Php/PhpFunctionReflection.php b/src/Reflection/Php/PhpFunctionReflection.php index bbd1cb62c2..46d41860ea 100644 --- a/src/Reflection/Php/PhpFunctionReflection.php +++ b/src/Reflection/Php/PhpFunctionReflection.php @@ -60,6 +60,7 @@ public function __construct( private Assertions $asserts, private ?string $phpDocComment, private array $phpDocParameterOutTypes, + private ?bool $returnsByReference, ) { } @@ -265,4 +266,9 @@ public function getDocComment(): ?string return $this->phpDocComment; } + public function returnsByReference(): ?bool + { + return $this->returnsByReference; + } + } diff --git a/src/Reflection/Php/PhpMethodFromParserNodeReflection.php b/src/Reflection/Php/PhpMethodFromParserNodeReflection.php index b27632580e..5932a62ffb 100644 --- a/src/Reflection/Php/PhpMethodFromParserNodeReflection.php +++ b/src/Reflection/Php/PhpMethodFromParserNodeReflection.php @@ -49,6 +49,7 @@ public function __construct( private ?Type $selfOutType, ?string $phpDocComment, array $parameterOutTypes, + ?bool $returnsByReference, ) { $name = strtolower($classMethod->name->name); @@ -93,6 +94,7 @@ public function __construct( $assertions, $phpDocComment, $parameterOutTypes, + $returnsByReference, ); } diff --git a/src/Reflection/Php/PhpMethodReflection.php b/src/Reflection/Php/PhpMethodReflection.php index aee826370c..9d5315e9f2 100644 --- a/src/Reflection/Php/PhpMethodReflection.php +++ b/src/Reflection/Php/PhpMethodReflection.php @@ -84,6 +84,7 @@ public function __construct( private ?Type $selfOutType, private ?string $phpDocComment, private array $phpDocParameterOutTypes, + private ?bool $returnsByReference, ) { } @@ -436,4 +437,9 @@ public function getDocComment(): ?string return $this->phpDocComment; } + public function returnsByReference(): ?bool + { + return $this->returnsByReference; + } + } diff --git a/src/Reflection/Php/PhpMethodReflectionFactory.php b/src/Reflection/Php/PhpMethodReflectionFactory.php index a73c617df0..c968db9cc0 100644 --- a/src/Reflection/Php/PhpMethodReflectionFactory.php +++ b/src/Reflection/Php/PhpMethodReflectionFactory.php @@ -31,6 +31,7 @@ public function create( ?Type $selfOutType, ?string $phpDocComment, array $phpDocParameterOutTypes, + ?bool $returnsByReference, ): PhpMethodReflection; } diff --git a/src/Reflection/ResolvedMethodReflection.php b/src/Reflection/ResolvedMethodReflection.php index b4225cd2ad..644fa6ca7a 100644 --- a/src/Reflection/ResolvedMethodReflection.php +++ b/src/Reflection/ResolvedMethodReflection.php @@ -139,4 +139,9 @@ public function getSelfOutType(): ?Type return $this->selfOutType; } + public function returnsByReference(): ?bool + { + return $this->reflection->returnsByReference(); + } + } diff --git a/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php b/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php index 12ae34d53e..de2858b810 100644 --- a/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php +++ b/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php @@ -57,9 +57,11 @@ public function findFunctionReflection(string $functionName): ?NativeFunctionRef $phpDocReturnType = null; $asserts = Assertions::createEmpty(); $docComment = null; + $returnsByReference = null; try { $reflectionFunction = $this->reflector->reflectFunction($functionName); $reflectionFunctionAdapter = new ReflectionFunction($reflectionFunction); + $returnsByReference = $reflectionFunctionAdapter->returnsReference(); if ($reflectionFunction->getFileName() !== null) { $fileName = $reflectionFunction->getFileName(); $docComment = $reflectionFunction->getDocComment(); @@ -174,6 +176,7 @@ public function findFunctionReflection(string $functionName): ?NativeFunctionRef $isDeprecated, $asserts, $docComment, + $returnsByReference, ); $this->functionMap[$lowerCasedFunctionName] = $functionReflection; diff --git a/src/Reflection/Type/IntersectionTypeMethodReflection.php b/src/Reflection/Type/IntersectionTypeMethodReflection.php index 3b48ba80fc..0e4cdcc746 100644 --- a/src/Reflection/Type/IntersectionTypeMethodReflection.php +++ b/src/Reflection/Type/IntersectionTypeMethodReflection.php @@ -170,4 +170,9 @@ public function getSelfOutType(): ?Type return null; } + public function returnsByReference(): ?bool + { + return null; + } + } diff --git a/src/Reflection/Type/UnionTypeMethodReflection.php b/src/Reflection/Type/UnionTypeMethodReflection.php index f72d36090f..855e845bbe 100644 --- a/src/Reflection/Type/UnionTypeMethodReflection.php +++ b/src/Reflection/Type/UnionTypeMethodReflection.php @@ -158,4 +158,9 @@ public function getSelfOutType(): ?Type return null; } + public function returnsByReference(): ?bool + { + return null; + } + } diff --git a/src/Reflection/WrappedExtendedMethodReflection.php b/src/Reflection/WrappedExtendedMethodReflection.php index 38774b738c..426800db2d 100644 --- a/src/Reflection/WrappedExtendedMethodReflection.php +++ b/src/Reflection/WrappedExtendedMethodReflection.php @@ -92,4 +92,9 @@ public function getSelfOutType(): ?Type return null; } + public function returnsByReference(): ?bool + { + return null; + } + } diff --git a/tests/PHPStan/Reflection/FunctionReflectionTest.php b/tests/PHPStan/Reflection/FunctionReflectionTest.php index 5309be7074..a8e863b660 100644 --- a/tests/PHPStan/Reflection/FunctionReflectionTest.php +++ b/tests/PHPStan/Reflection/FunctionReflectionTest.php @@ -127,6 +127,52 @@ public function testMethodHasPhpdoc(string $className, string $methodName, ?stri $this->assertSame($expectedDocComment, $methodReflection->getDocComment()); } + public function dataFunctionReturnsByReference(): iterable + { + yield ['ReturnsByReference\\foo', false]; + yield ['ReturnsByReference\\refFoo', true]; + } + + /** + * @dataProvider dataFunctionReturnsByReference + */ + public function testFunctionReturnsByReference(string $functionName, bool $expectedReturnsByRef): void + { + require_once __DIR__ . '/data/returns-by-reference.php'; + + $reflectionProvider = $this->createReflectionProvider(); + + $functionReflection = $reflectionProvider->getFunction(new Node\Name($functionName), null); + $this->assertSame($expectedReturnsByRef, $functionReflection->returnsByReference()); + } + + public function dataMethodReturnsByReference(): iterable + { + yield ['ReturnsByReference\\X', 'foo', false]; + yield ['ReturnsByReference\\X', 'refFoo', true]; + + yield ['ReturnsByReference\\SubX', 'foo', false]; + yield ['ReturnsByReference\\SubX', 'refFoo', true]; + yield ['ReturnsByReference\\SubX', 'subRefFoo', true]; + } + + /** + * @dataProvider dataMethodReturnsByReference + */ + public function testMethodReturnsByReference(string $className, string $methodName, bool $expectedReturnsByRef): void + { + $reflectionProvider = $this->createReflectionProvider(); + $class = $reflectionProvider->getClass($className); + $scope = $this->createMock(Scope::class); + $scope->method('isInClass')->willReturn(true); + $scope->method('getClassReflection')->willReturn($class); + $scope->method('canAccessProperty')->willReturn(true); + $classReflection = $reflectionProvider->getClass($className); + + $methodReflection = $classReflection->getMethod($methodName, $scope); + $this->assertSame($expectedReturnsByRef, $methodReflection->returnsByReference()); + } + /** * @return string[] */ diff --git a/tests/PHPStan/Reflection/data/returns-by-reference.php b/tests/PHPStan/Reflection/data/returns-by-reference.php new file mode 100644 index 0000000000..3cf7645fea --- /dev/null +++ b/tests/PHPStan/Reflection/data/returns-by-reference.php @@ -0,0 +1,18 @@ + Date: Sat, 22 Oct 2022 17:17:52 +0200 Subject: [PATCH 2/6] test php-src native function --- tests/PHPStan/Reflection/FunctionReflectionTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/PHPStan/Reflection/FunctionReflectionTest.php b/tests/PHPStan/Reflection/FunctionReflectionTest.php index a8e863b660..8b0ffffbd2 100644 --- a/tests/PHPStan/Reflection/FunctionReflectionTest.php +++ b/tests/PHPStan/Reflection/FunctionReflectionTest.php @@ -129,6 +129,8 @@ public function testMethodHasPhpdoc(string $className, string $methodName, ?stri public function dataFunctionReturnsByReference(): iterable { + yield ['\\implode', false]; + yield ['ReturnsByReference\\foo', false]; yield ['ReturnsByReference\\refFoo', true]; } From 433bd9fc135e41dd4ca2adc5aac4dd1a96fc6d23 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 22 Oct 2022 18:16:04 +0200 Subject: [PATCH 3/6] test traits and enums --- tests/PHPStan/Reflection/FunctionReflectionTest.php | 11 +++++++++++ .../Reflection/data/returns-by-reference-enum.php | 11 +++++++++++ .../PHPStan/Reflection/data/returns-by-reference.php | 10 ++++++++++ 3 files changed, 32 insertions(+) create mode 100644 tests/PHPStan/Reflection/data/returns-by-reference-enum.php diff --git a/tests/PHPStan/Reflection/FunctionReflectionTest.php b/tests/PHPStan/Reflection/FunctionReflectionTest.php index 8b0ffffbd2..e27a274deb 100644 --- a/tests/PHPStan/Reflection/FunctionReflectionTest.php +++ b/tests/PHPStan/Reflection/FunctionReflectionTest.php @@ -5,6 +5,7 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Testing\PHPStanTestCase; +use const PHP_VERSION_ID; class FunctionReflectionTest extends PHPStanTestCase { @@ -156,6 +157,16 @@ public function dataMethodReturnsByReference(): iterable yield ['ReturnsByReference\\SubX', 'foo', false]; yield ['ReturnsByReference\\SubX', 'refFoo', true]; yield ['ReturnsByReference\\SubX', 'subRefFoo', true]; + + yield ['ReturnsByReference\\TraitX', 'traitFoo', false]; + yield ['ReturnsByReference\\TraitX', 'refTraitFoo', true]; + + if (PHP_VERSION_ID < 80100) { + return; + } + + yield ['ReturnsByReference\\E', 'enumFoo', false]; + yield ['ReturnsByReference\\E', 'refEnumFoo', true]; } /** diff --git a/tests/PHPStan/Reflection/data/returns-by-reference-enum.php b/tests/PHPStan/Reflection/data/returns-by-reference-enum.php new file mode 100644 index 0000000000..02e0c40704 --- /dev/null +++ b/tests/PHPStan/Reflection/data/returns-by-reference-enum.php @@ -0,0 +1,11 @@ += 8.1 + +namespace ReturnsByReference; + +enum E { + case E1; + + function enumFoo() {} + + function &refEnumFoo() {} +} diff --git a/tests/PHPStan/Reflection/data/returns-by-reference.php b/tests/PHPStan/Reflection/data/returns-by-reference.php index 3cf7645fea..26fb1051b3 100644 --- a/tests/PHPStan/Reflection/data/returns-by-reference.php +++ b/tests/PHPStan/Reflection/data/returns-by-reference.php @@ -16,3 +16,13 @@ class SubX extends X { function &subRefFoo() {} } + +class TraitX { + use T; +} + +trait T { + function traitFoo() {} + + function &refTraitFoo() {} +} From 17f268d87f839ce4c20dd8b0aa2cd8973e03834b Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 26 Oct 2022 11:16:00 +0200 Subject: [PATCH 4/6] make returnsByReference() return TrinaryLogic --- src/Analyser/MutatingScope.php | 4 +-- .../AnnotationMethodReflection.php | 4 +-- .../BetterReflectionProvider.php | 3 +- .../Dummy/ChangedTypeMethodReflection.php | 2 +- .../Dummy/DummyMethodReflection.php | 4 +-- src/Reflection/ExtendedMethodReflection.php | 3 +- src/Reflection/FunctionReflection.php | 2 +- src/Reflection/FunctionReflectionFactory.php | 3 +- .../Native/NativeFunctionReflection.php | 7 +++-- .../Native/NativeMethodReflection.php | 4 +-- .../Php/ClosureCallMethodReflection.php | 2 +- .../Php/EnumCasesMethodReflection.php | 4 +-- .../Php/PhpClassReflectionExtension.php | 4 +-- .../PhpFunctionFromParserNodeReflection.php | 4 +-- src/Reflection/Php/PhpFunctionReflection.php | 4 +-- .../Php/PhpMethodFromParserNodeReflection.php | 3 +- src/Reflection/Php/PhpMethodReflection.php | 4 +-- .../Php/PhpMethodReflectionFactory.php | 3 +- src/Reflection/ResolvedMethodReflection.php | 2 +- .../NativeFunctionReflectionProvider.php | 4 +-- .../Type/IntersectionTypeMethodReflection.php | 4 +-- .../Type/UnionTypeMethodReflection.php | 4 +-- .../WrappedExtendedMethodReflection.php | 4 +-- .../Reflection/FunctionReflectionTest.php | 29 ++++++++++--------- 24 files changed, 60 insertions(+), 51 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 5730d405f4..405df1587f 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -2567,7 +2567,7 @@ public function enterClassMethod( $selfOutType, $phpDocComment, array_map(static fn (Type $type): Type => TemplateTypeHelper::toArgument($type), $parameterOutTypes), - null, + TrinaryLogic::createMaybe(), ), !$classMethod->isStatic(), ); @@ -2673,7 +2673,7 @@ public function enterFunction( $asserts ?? Assertions::createEmpty(), $phpDocComment, array_map(static fn (Type $type): Type => TemplateTypeHelper::toArgument($type), $parameterOutTypes), - null, + TrinaryLogic::createMaybe(), ), false, ); diff --git a/src/Reflection/Annotations/AnnotationMethodReflection.php b/src/Reflection/Annotations/AnnotationMethodReflection.php index 1203792812..b93316270c 100644 --- a/src/Reflection/Annotations/AnnotationMethodReflection.php +++ b/src/Reflection/Annotations/AnnotationMethodReflection.php @@ -127,9 +127,9 @@ public function getSelfOutType(): ?Type return null; } - public function returnsByReference(): ?bool + public function returnsByReference(): TrinaryLogic { - return null; + return TrinaryLogic::createMaybe(); } } diff --git a/src/Reflection/BetterReflection/BetterReflectionProvider.php b/src/Reflection/BetterReflection/BetterReflectionProvider.php index 344b458b97..a255ce4c9c 100644 --- a/src/Reflection/BetterReflection/BetterReflectionProvider.php +++ b/src/Reflection/BetterReflection/BetterReflectionProvider.php @@ -44,6 +44,7 @@ use PHPStan\Reflection\ReflectionProvider; use PHPStan\Reflection\SignatureMap\NativeFunctionReflectionProvider; use PHPStan\ShouldNotHappenException; +use PHPStan\TrinaryLogic; use PHPStan\Type\FileTypeMapper; use PHPStan\Type\Generic\TemplateTypeMap; use PHPStan\Type\Type; @@ -307,7 +308,7 @@ private function getCustomFunction(string $functionName): PhpFunctionReflection $asserts, $phpDocComment, array_map(static fn (ParamOutTag $paramOutTag): Type => $paramOutTag->getType(), $phpDocParameterOutTags), - $reflectionFunction->returnsReference(), + TrinaryLogic::createFromBoolean($reflectionFunction->returnsReference()), ); } diff --git a/src/Reflection/Dummy/ChangedTypeMethodReflection.php b/src/Reflection/Dummy/ChangedTypeMethodReflection.php index bd4625677f..f682ae11a4 100644 --- a/src/Reflection/Dummy/ChangedTypeMethodReflection.php +++ b/src/Reflection/Dummy/ChangedTypeMethodReflection.php @@ -100,7 +100,7 @@ public function getSelfOutType(): ?Type return $this->reflection->getSelfOutType(); } - public function returnsByReference(): ?bool + public function returnsByReference(): TrinaryLogic { return $this->reflection->returnsByReference(); } diff --git a/src/Reflection/Dummy/DummyMethodReflection.php b/src/Reflection/Dummy/DummyMethodReflection.php index 130b92cc3e..6d7e59369b 100644 --- a/src/Reflection/Dummy/DummyMethodReflection.php +++ b/src/Reflection/Dummy/DummyMethodReflection.php @@ -107,9 +107,9 @@ public function getSelfOutType(): ?Type return null; } - public function returnsByReference(): ?bool + public function returnsByReference(): TrinaryLogic { - return null; + return TrinaryLogic::createMaybe(); } } diff --git a/src/Reflection/ExtendedMethodReflection.php b/src/Reflection/ExtendedMethodReflection.php index 5619731b3d..8be932654b 100644 --- a/src/Reflection/ExtendedMethodReflection.php +++ b/src/Reflection/ExtendedMethodReflection.php @@ -2,6 +2,7 @@ namespace PHPStan\Reflection; +use PHPStan\TrinaryLogic; use PHPStan\Type\Type; /** @@ -25,6 +26,6 @@ public function getAsserts(): Assertions; public function getSelfOutType(): ?Type; - public function returnsByReference(): ?bool; + public function returnsByReference(): TrinaryLogic; } diff --git a/src/Reflection/FunctionReflection.php b/src/Reflection/FunctionReflection.php index d7801c79a0..79c2526a30 100644 --- a/src/Reflection/FunctionReflection.php +++ b/src/Reflection/FunctionReflection.php @@ -36,6 +36,6 @@ public function getAsserts(): Assertions; public function getDocComment(): ?string; - public function returnsByReference(): ?bool; + public function returnsByReference(): TrinaryLogic; } diff --git a/src/Reflection/FunctionReflectionFactory.php b/src/Reflection/FunctionReflectionFactory.php index 82144ae6da..124289a739 100644 --- a/src/Reflection/FunctionReflectionFactory.php +++ b/src/Reflection/FunctionReflectionFactory.php @@ -4,6 +4,7 @@ use PHPStan\BetterReflection\Reflection\Adapter\ReflectionFunction; use PHPStan\Reflection\Php\PhpFunctionReflection; +use PHPStan\TrinaryLogic; use PHPStan\Type\Generic\TemplateTypeMap; use PHPStan\Type\Type; @@ -29,7 +30,7 @@ public function create( Assertions $asserts, ?string $phpDocComment, array $phpDocParameterOutTypes, - ?bool $returnsByReference, + TrinaryLogic $returnsByReference, ): PhpFunctionReflection; } diff --git a/src/Reflection/Native/NativeFunctionReflection.php b/src/Reflection/Native/NativeFunctionReflection.php index 982a059cc7..106b9717a8 100644 --- a/src/Reflection/Native/NativeFunctionReflection.php +++ b/src/Reflection/Native/NativeFunctionReflection.php @@ -14,6 +14,8 @@ class NativeFunctionReflection implements FunctionReflection private Assertions $assertions; + private TrinaryLogic $returnsByReference; + /** * @param ParametersAcceptorWithPhpDocs[] $variants */ @@ -25,10 +27,11 @@ public function __construct( private bool $isDeprecated, ?Assertions $assertions = null, private ?string $phpDocComment = null, - private ?bool $returnsByReference = null, + ?TrinaryLogic $returnsByReference = null, ) { $this->assertions = $assertions ?? Assertions::createEmpty(); + $this->returnsByReference = $returnsByReference ?? TrinaryLogic::createMaybe(); } public function getName(): string @@ -109,7 +112,7 @@ public function getDocComment(): ?string return $this->phpDocComment; } - public function returnsByReference(): ?bool + public function returnsByReference(): TrinaryLogic { return $this->returnsByReference; } diff --git a/src/Reflection/Native/NativeMethodReflection.php b/src/Reflection/Native/NativeMethodReflection.php index 4b5f4b8e30..ce7498cfd3 100644 --- a/src/Reflection/Native/NativeMethodReflection.php +++ b/src/Reflection/Native/NativeMethodReflection.php @@ -33,7 +33,7 @@ public function __construct( private Assertions $assertions, private ?Type $selfOutType, private ?string $phpDocComment, - private ?bool $returnsByReference, + private TrinaryLogic $returnsByReference, ) { } @@ -168,7 +168,7 @@ public function getSelfOutType(): ?Type return $this->selfOutType; } - public function returnsByReference(): ?bool + public function returnsByReference(): TrinaryLogic { return $this->returnsByReference; } diff --git a/src/Reflection/Php/ClosureCallMethodReflection.php b/src/Reflection/Php/ClosureCallMethodReflection.php index 0e5f7a2712..6906479cce 100644 --- a/src/Reflection/Php/ClosureCallMethodReflection.php +++ b/src/Reflection/Php/ClosureCallMethodReflection.php @@ -129,7 +129,7 @@ public function getSelfOutType(): ?Type return $this->nativeMethodReflection->getSelfOutType(); } - public function returnsByReference(): ?bool + public function returnsByReference(): TrinaryLogic { return $this->nativeMethodReflection->returnsByReference(); } diff --git a/src/Reflection/Php/EnumCasesMethodReflection.php b/src/Reflection/Php/EnumCasesMethodReflection.php index a5cd069e7d..e947377eae 100644 --- a/src/Reflection/Php/EnumCasesMethodReflection.php +++ b/src/Reflection/Php/EnumCasesMethodReflection.php @@ -116,9 +116,9 @@ public function getSelfOutType(): ?Type return null; } - public function returnsByReference(): ?bool + public function returnsByReference(): TrinaryLogic { - return null; + return TrinaryLogic::createMaybe(); } } diff --git a/src/Reflection/Php/PhpClassReflectionExtension.php b/src/Reflection/Php/PhpClassReflectionExtension.php index 49fafe4d78..3ccae86b15 100644 --- a/src/Reflection/Php/PhpClassReflectionExtension.php +++ b/src/Reflection/Php/PhpClassReflectionExtension.php @@ -496,9 +496,9 @@ private function createMethod( return new EnumCasesMethodReflection($declaringClass, $arrayBuilder->getArray()); } - $returnsByReference = null; + $returnsByReference = TrinaryLogic::createMaybe(); if ($methodReflection->getReflection() !== null) { - $returnsByReference = $methodReflection->getReflection()->returnsReference(); + $returnsByReference = TrinaryLogic::createFromBoolean($methodReflection->getReflection()->returnsReference()); } if ($this->signatureMapProvider->hasMethodSignature($declaringClassName, $methodReflection->getName())) { diff --git a/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php b/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php index a4f0e82886..59b1c2794e 100644 --- a/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php +++ b/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php @@ -59,7 +59,7 @@ public function __construct( private Assertions $assertions, private ?string $phpDocComment, private array $parameterOutTypes, - private ?bool $returnsByReference, + private TrinaryLogic $returnsByReference, ) { $this->functionLike = $functionLike; @@ -261,7 +261,7 @@ public function getDocComment(): ?string return $this->phpDocComment; } - public function returnsByReference(): ?bool + public function returnsByReference(): TrinaryLogic { return $this->returnsByReference; } diff --git a/src/Reflection/Php/PhpFunctionReflection.php b/src/Reflection/Php/PhpFunctionReflection.php index 46d41860ea..ed66938474 100644 --- a/src/Reflection/Php/PhpFunctionReflection.php +++ b/src/Reflection/Php/PhpFunctionReflection.php @@ -60,7 +60,7 @@ public function __construct( private Assertions $asserts, private ?string $phpDocComment, private array $phpDocParameterOutTypes, - private ?bool $returnsByReference, + private TrinaryLogic $returnsByReference, ) { } @@ -266,7 +266,7 @@ public function getDocComment(): ?string return $this->phpDocComment; } - public function returnsByReference(): ?bool + public function returnsByReference(): TrinaryLogic { return $this->returnsByReference; } diff --git a/src/Reflection/Php/PhpMethodFromParserNodeReflection.php b/src/Reflection/Php/PhpMethodFromParserNodeReflection.php index 5932a62ffb..4f4d69a092 100644 --- a/src/Reflection/Php/PhpMethodFromParserNodeReflection.php +++ b/src/Reflection/Php/PhpMethodFromParserNodeReflection.php @@ -9,6 +9,7 @@ use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedMethodReflection; use PHPStan\Reflection\MissingMethodFromReflectionException; +use PHPStan\TrinaryLogic; use PHPStan\Type\ArrayType; use PHPStan\Type\BooleanType; use PHPStan\Type\Generic\TemplateTypeMap; @@ -49,7 +50,7 @@ public function __construct( private ?Type $selfOutType, ?string $phpDocComment, array $parameterOutTypes, - ?bool $returnsByReference, + TrinaryLogic $returnsByReference, ) { $name = strtolower($classMethod->name->name); diff --git a/src/Reflection/Php/PhpMethodReflection.php b/src/Reflection/Php/PhpMethodReflection.php index 9d5315e9f2..53dead8da2 100644 --- a/src/Reflection/Php/PhpMethodReflection.php +++ b/src/Reflection/Php/PhpMethodReflection.php @@ -84,7 +84,7 @@ public function __construct( private ?Type $selfOutType, private ?string $phpDocComment, private array $phpDocParameterOutTypes, - private ?bool $returnsByReference, + private TrinaryLogic $returnsByReference, ) { } @@ -437,7 +437,7 @@ public function getDocComment(): ?string return $this->phpDocComment; } - public function returnsByReference(): ?bool + public function returnsByReference(): TrinaryLogic { return $this->returnsByReference; } diff --git a/src/Reflection/Php/PhpMethodReflectionFactory.php b/src/Reflection/Php/PhpMethodReflectionFactory.php index c968db9cc0..d329953237 100644 --- a/src/Reflection/Php/PhpMethodReflectionFactory.php +++ b/src/Reflection/Php/PhpMethodReflectionFactory.php @@ -4,6 +4,7 @@ use PHPStan\Reflection\Assertions; use PHPStan\Reflection\ClassReflection; +use PHPStan\TrinaryLogic; use PHPStan\Type\Generic\TemplateTypeMap; use PHPStan\Type\Type; @@ -31,7 +32,7 @@ public function create( ?Type $selfOutType, ?string $phpDocComment, array $phpDocParameterOutTypes, - ?bool $returnsByReference, + TrinaryLogic $returnsByReference, ): PhpMethodReflection; } diff --git a/src/Reflection/ResolvedMethodReflection.php b/src/Reflection/ResolvedMethodReflection.php index 644fa6ca7a..9691cc15cc 100644 --- a/src/Reflection/ResolvedMethodReflection.php +++ b/src/Reflection/ResolvedMethodReflection.php @@ -139,7 +139,7 @@ public function getSelfOutType(): ?Type return $this->selfOutType; } - public function returnsByReference(): ?bool + public function returnsByReference(): TrinaryLogic { return $this->reflection->returnsByReference(); } diff --git a/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php b/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php index de2858b810..56f3a6bcc5 100644 --- a/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php +++ b/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php @@ -57,11 +57,11 @@ public function findFunctionReflection(string $functionName): ?NativeFunctionRef $phpDocReturnType = null; $asserts = Assertions::createEmpty(); $docComment = null; - $returnsByReference = null; + $returnsByReference = TrinaryLogic::createMaybe(); try { $reflectionFunction = $this->reflector->reflectFunction($functionName); $reflectionFunctionAdapter = new ReflectionFunction($reflectionFunction); - $returnsByReference = $reflectionFunctionAdapter->returnsReference(); + $returnsByReference = TrinaryLogic::createFromBoolean($reflectionFunctionAdapter->returnsReference()); if ($reflectionFunction->getFileName() !== null) { $fileName = $reflectionFunction->getFileName(); $docComment = $reflectionFunction->getDocComment(); diff --git a/src/Reflection/Type/IntersectionTypeMethodReflection.php b/src/Reflection/Type/IntersectionTypeMethodReflection.php index 0e4cdcc746..914af93e2c 100644 --- a/src/Reflection/Type/IntersectionTypeMethodReflection.php +++ b/src/Reflection/Type/IntersectionTypeMethodReflection.php @@ -170,9 +170,9 @@ public function getSelfOutType(): ?Type return null; } - public function returnsByReference(): ?bool + public function returnsByReference(): TrinaryLogic { - return null; + return TrinaryLogic::createMaybe(); } } diff --git a/src/Reflection/Type/UnionTypeMethodReflection.php b/src/Reflection/Type/UnionTypeMethodReflection.php index 855e845bbe..20159cf16e 100644 --- a/src/Reflection/Type/UnionTypeMethodReflection.php +++ b/src/Reflection/Type/UnionTypeMethodReflection.php @@ -158,9 +158,9 @@ public function getSelfOutType(): ?Type return null; } - public function returnsByReference(): ?bool + public function returnsByReference(): TrinaryLogic { - return null; + return TrinaryLogic::createMaybe(); } } diff --git a/src/Reflection/WrappedExtendedMethodReflection.php b/src/Reflection/WrappedExtendedMethodReflection.php index 426800db2d..984f3bcac5 100644 --- a/src/Reflection/WrappedExtendedMethodReflection.php +++ b/src/Reflection/WrappedExtendedMethodReflection.php @@ -92,9 +92,9 @@ public function getSelfOutType(): ?Type return null; } - public function returnsByReference(): ?bool + public function returnsByReference(): TrinaryLogic { - return null; + return TrinaryLogic::createMaybe(); } } diff --git a/tests/PHPStan/Reflection/FunctionReflectionTest.php b/tests/PHPStan/Reflection/FunctionReflectionTest.php index e27a274deb..6c23ca4027 100644 --- a/tests/PHPStan/Reflection/FunctionReflectionTest.php +++ b/tests/PHPStan/Reflection/FunctionReflectionTest.php @@ -5,6 +5,7 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Testing\PHPStanTestCase; +use PHPStan\TrinaryLogic; use const PHP_VERSION_ID; class FunctionReflectionTest extends PHPStanTestCase @@ -130,16 +131,16 @@ public function testMethodHasPhpdoc(string $className, string $methodName, ?stri public function dataFunctionReturnsByReference(): iterable { - yield ['\\implode', false]; + yield ['\\implode', TrinaryLogic::createNo()]; - yield ['ReturnsByReference\\foo', false]; - yield ['ReturnsByReference\\refFoo', true]; + yield ['ReturnsByReference\\foo', TrinaryLogic::createNo()]; + yield ['ReturnsByReference\\refFoo', TrinaryLogic::createYes()]; } /** * @dataProvider dataFunctionReturnsByReference */ - public function testFunctionReturnsByReference(string $functionName, bool $expectedReturnsByRef): void + public function testFunctionReturnsByReference(string $functionName, TrinaryLogic $expectedReturnsByRef): void { require_once __DIR__ . '/data/returns-by-reference.php'; @@ -151,28 +152,28 @@ public function testFunctionReturnsByReference(string $functionName, bool $expec public function dataMethodReturnsByReference(): iterable { - yield ['ReturnsByReference\\X', 'foo', false]; - yield ['ReturnsByReference\\X', 'refFoo', true]; + yield ['ReturnsByReference\\X', 'foo', TrinaryLogic::createNo()]; + yield ['ReturnsByReference\\X', 'refFoo', TrinaryLogic::createYes()]; - yield ['ReturnsByReference\\SubX', 'foo', false]; - yield ['ReturnsByReference\\SubX', 'refFoo', true]; - yield ['ReturnsByReference\\SubX', 'subRefFoo', true]; + yield ['ReturnsByReference\\SubX', 'foo', TrinaryLogic::createNo()]; + yield ['ReturnsByReference\\SubX', 'refFoo', TrinaryLogic::createYes()]; + yield ['ReturnsByReference\\SubX', 'subRefFoo', TrinaryLogic::createYes()]; - yield ['ReturnsByReference\\TraitX', 'traitFoo', false]; - yield ['ReturnsByReference\\TraitX', 'refTraitFoo', true]; + yield ['ReturnsByReference\\TraitX', 'traitFoo', TrinaryLogic::createNo()]; + yield ['ReturnsByReference\\TraitX', 'refTraitFoo', TrinaryLogic::createYes()]; if (PHP_VERSION_ID < 80100) { return; } - yield ['ReturnsByReference\\E', 'enumFoo', false]; - yield ['ReturnsByReference\\E', 'refEnumFoo', true]; + yield ['ReturnsByReference\\E', 'enumFoo', TrinaryLogic::createNo()]; + yield ['ReturnsByReference\\E', 'refEnumFoo', TrinaryLogic::createYes()]; } /** * @dataProvider dataMethodReturnsByReference */ - public function testMethodReturnsByReference(string $className, string $methodName, bool $expectedReturnsByRef): void + public function testMethodReturnsByReference(string $className, string $methodName, TrinaryLogic $expectedReturnsByRef): void { $reflectionProvider = $this->createReflectionProvider(); $class = $reflectionProvider->getClass($className); From ae76ed0ce5aa9c8f2efbed87ba88f997982bfb20 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 26 Oct 2022 14:19:58 +0200 Subject: [PATCH 5/6] implement review feedback --- src/Reflection/FunctionReflectionFactory.php | 2 -- src/Reflection/Native/NativeMethodReflection.php | 3 +-- src/Reflection/Php/BuiltinMethodReflection.php | 2 ++ src/Reflection/Php/EnumCasesMethodReflection.php | 2 +- src/Reflection/Php/FakeBuiltinMethodReflection.php | 5 +++++ src/Reflection/Php/NativeBuiltinMethodReflection.php | 5 +++++ src/Reflection/Php/PhpClassReflectionExtension.php | 7 +------ src/Reflection/Php/PhpFunctionFromParserNodeReflection.php | 3 +-- src/Reflection/Php/PhpFunctionReflection.php | 3 +-- src/Reflection/Php/PhpMethodFromParserNodeReflection.php | 7 +++++-- src/Reflection/Php/PhpMethodReflection.php | 3 +-- src/Reflection/Php/PhpMethodReflectionFactory.php | 2 -- src/Reflection/Type/IntersectionTypeMethodReflection.php | 2 +- src/Reflection/Type/UnionTypeMethodReflection.php | 2 +- 14 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/Reflection/FunctionReflectionFactory.php b/src/Reflection/FunctionReflectionFactory.php index 124289a739..28382fd315 100644 --- a/src/Reflection/FunctionReflectionFactory.php +++ b/src/Reflection/FunctionReflectionFactory.php @@ -4,7 +4,6 @@ use PHPStan\BetterReflection\Reflection\Adapter\ReflectionFunction; use PHPStan\Reflection\Php\PhpFunctionReflection; -use PHPStan\TrinaryLogic; use PHPStan\Type\Generic\TemplateTypeMap; use PHPStan\Type\Type; @@ -30,7 +29,6 @@ public function create( Assertions $asserts, ?string $phpDocComment, array $phpDocParameterOutTypes, - TrinaryLogic $returnsByReference, ): PhpFunctionReflection; } diff --git a/src/Reflection/Native/NativeMethodReflection.php b/src/Reflection/Native/NativeMethodReflection.php index ce7498cfd3..cfe14ff771 100644 --- a/src/Reflection/Native/NativeMethodReflection.php +++ b/src/Reflection/Native/NativeMethodReflection.php @@ -33,7 +33,6 @@ public function __construct( private Assertions $assertions, private ?Type $selfOutType, private ?string $phpDocComment, - private TrinaryLogic $returnsByReference, ) { } @@ -170,7 +169,7 @@ public function getSelfOutType(): ?Type public function returnsByReference(): TrinaryLogic { - return $this->returnsByReference; + return $this->reflection->returnsByReference(); } } diff --git a/src/Reflection/Php/BuiltinMethodReflection.php b/src/Reflection/Php/BuiltinMethodReflection.php index 51f90c87b9..d2d55336aa 100644 --- a/src/Reflection/Php/BuiltinMethodReflection.php +++ b/src/Reflection/Php/BuiltinMethodReflection.php @@ -55,4 +55,6 @@ public function isInternal(): bool; public function isAbstract(): bool; + public function returnsByReference(): TrinaryLogic; + } diff --git a/src/Reflection/Php/EnumCasesMethodReflection.php b/src/Reflection/Php/EnumCasesMethodReflection.php index e947377eae..67cf694313 100644 --- a/src/Reflection/Php/EnumCasesMethodReflection.php +++ b/src/Reflection/Php/EnumCasesMethodReflection.php @@ -118,7 +118,7 @@ public function getSelfOutType(): ?Type public function returnsByReference(): TrinaryLogic { - return TrinaryLogic::createMaybe(); + return TrinaryLogic::createNo(); } } diff --git a/src/Reflection/Php/FakeBuiltinMethodReflection.php b/src/Reflection/Php/FakeBuiltinMethodReflection.php index 96e3bf18b6..de3bfae927 100644 --- a/src/Reflection/Php/FakeBuiltinMethodReflection.php +++ b/src/Reflection/Php/FakeBuiltinMethodReflection.php @@ -120,4 +120,9 @@ public function getParameters(): array return []; } + public function returnsByReference(): TrinaryLogic + { + return TrinaryLogic::createMaybe(); + } + } diff --git a/src/Reflection/Php/NativeBuiltinMethodReflection.php b/src/Reflection/Php/NativeBuiltinMethodReflection.php index 992219233e..2f10d431c5 100644 --- a/src/Reflection/Php/NativeBuiltinMethodReflection.php +++ b/src/Reflection/Php/NativeBuiltinMethodReflection.php @@ -141,4 +141,9 @@ public function getParameters(): array return $this->reflection->getParameters(); } + public function returnsByReference(): TrinaryLogic + { + return TrinaryLogic::createFromBoolean($this->reflection->returnsReference()); + } + } diff --git a/src/Reflection/Php/PhpClassReflectionExtension.php b/src/Reflection/Php/PhpClassReflectionExtension.php index 3ccae86b15..db8f220b7e 100644 --- a/src/Reflection/Php/PhpClassReflectionExtension.php +++ b/src/Reflection/Php/PhpClassReflectionExtension.php @@ -496,11 +496,6 @@ private function createMethod( return new EnumCasesMethodReflection($declaringClass, $arrayBuilder->getArray()); } - $returnsByReference = TrinaryLogic::createMaybe(); - if ($methodReflection->getReflection() !== null) { - $returnsByReference = TrinaryLogic::createFromBoolean($methodReflection->getReflection()->returnsReference()); - } - if ($this->signatureMapProvider->hasMethodSignature($declaringClassName, $methodReflection->getName())) { $variants = []; $reflectionMethod = null; @@ -634,7 +629,6 @@ private function createMethod( $asserts, $selfOutType, $phpDocComment, - $returnsByReference, ); } @@ -757,6 +751,7 @@ private function createMethod( null, $declaringClass->getName(), ); + $returnsByReference = $methodReflection->returnsByReference(); $phpDocReturnType = $this->getPhpDocReturnType($phpDocBlockClassReflection, $resolvedPhpDoc, $nativeReturnType); $phpDocThrowType = $resolvedPhpDoc->getThrowsTag() !== null ? $resolvedPhpDoc->getThrowsTag()->getType() : null; $deprecatedDescription = $resolvedPhpDoc->getDeprecatedTag() !== null ? $resolvedPhpDoc->getDeprecatedTag()->getMessage() : null; diff --git a/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php b/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php index 59b1c2794e..f360036264 100644 --- a/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php +++ b/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php @@ -59,7 +59,6 @@ public function __construct( private Assertions $assertions, private ?string $phpDocComment, private array $parameterOutTypes, - private TrinaryLogic $returnsByReference, ) { $this->functionLike = $functionLike; @@ -263,7 +262,7 @@ public function getDocComment(): ?string public function returnsByReference(): TrinaryLogic { - return $this->returnsByReference; + return TrinaryLogic::createFromBoolean($this->functionLike->returnsByRef()); } } diff --git a/src/Reflection/Php/PhpFunctionReflection.php b/src/Reflection/Php/PhpFunctionReflection.php index ed66938474..4b5428d4fd 100644 --- a/src/Reflection/Php/PhpFunctionReflection.php +++ b/src/Reflection/Php/PhpFunctionReflection.php @@ -60,7 +60,6 @@ public function __construct( private Assertions $asserts, private ?string $phpDocComment, private array $phpDocParameterOutTypes, - private TrinaryLogic $returnsByReference, ) { } @@ -268,7 +267,7 @@ public function getDocComment(): ?string public function returnsByReference(): TrinaryLogic { - return $this->returnsByReference; + return TrinaryLogic::createFromBoolean($this->reflection->returnsReference()); } } diff --git a/src/Reflection/Php/PhpMethodFromParserNodeReflection.php b/src/Reflection/Php/PhpMethodFromParserNodeReflection.php index 4f4d69a092..8c985d54be 100644 --- a/src/Reflection/Php/PhpMethodFromParserNodeReflection.php +++ b/src/Reflection/Php/PhpMethodFromParserNodeReflection.php @@ -50,7 +50,6 @@ public function __construct( private ?Type $selfOutType, ?string $phpDocComment, array $parameterOutTypes, - TrinaryLogic $returnsByReference, ) { $name = strtolower($classMethod->name->name); @@ -95,7 +94,6 @@ public function __construct( $assertions, $phpDocComment, $parameterOutTypes, - $returnsByReference, ); } @@ -145,4 +143,9 @@ public function getSelfOutType(): ?Type return $this->selfOutType; } + public function returnsByReference(): TrinaryLogic + { + return TrinaryLogic::createFromBoolean($this->getClassMethod()->returnsByRef()); + } + } diff --git a/src/Reflection/Php/PhpMethodReflection.php b/src/Reflection/Php/PhpMethodReflection.php index 53dead8da2..e4f26e5dea 100644 --- a/src/Reflection/Php/PhpMethodReflection.php +++ b/src/Reflection/Php/PhpMethodReflection.php @@ -84,7 +84,6 @@ public function __construct( private ?Type $selfOutType, private ?string $phpDocComment, private array $phpDocParameterOutTypes, - private TrinaryLogic $returnsByReference, ) { } @@ -439,7 +438,7 @@ public function getDocComment(): ?string public function returnsByReference(): TrinaryLogic { - return $this->returnsByReference; + return $this->reflection->returnsByReference(); } } diff --git a/src/Reflection/Php/PhpMethodReflectionFactory.php b/src/Reflection/Php/PhpMethodReflectionFactory.php index d329953237..a73c617df0 100644 --- a/src/Reflection/Php/PhpMethodReflectionFactory.php +++ b/src/Reflection/Php/PhpMethodReflectionFactory.php @@ -4,7 +4,6 @@ use PHPStan\Reflection\Assertions; use PHPStan\Reflection\ClassReflection; -use PHPStan\TrinaryLogic; use PHPStan\Type\Generic\TemplateTypeMap; use PHPStan\Type\Type; @@ -32,7 +31,6 @@ public function create( ?Type $selfOutType, ?string $phpDocComment, array $phpDocParameterOutTypes, - TrinaryLogic $returnsByReference, ): PhpMethodReflection; } diff --git a/src/Reflection/Type/IntersectionTypeMethodReflection.php b/src/Reflection/Type/IntersectionTypeMethodReflection.php index 914af93e2c..806e5bdb4b 100644 --- a/src/Reflection/Type/IntersectionTypeMethodReflection.php +++ b/src/Reflection/Type/IntersectionTypeMethodReflection.php @@ -172,7 +172,7 @@ public function getSelfOutType(): ?Type public function returnsByReference(): TrinaryLogic { - return TrinaryLogic::createMaybe(); + return TrinaryLogic::lazyMaxMin($this->methods, static fn (ExtendedMethodReflection $method): TrinaryLogic => $method->returnsByReference()); } } diff --git a/src/Reflection/Type/UnionTypeMethodReflection.php b/src/Reflection/Type/UnionTypeMethodReflection.php index 20159cf16e..0168a315b2 100644 --- a/src/Reflection/Type/UnionTypeMethodReflection.php +++ b/src/Reflection/Type/UnionTypeMethodReflection.php @@ -160,7 +160,7 @@ public function getSelfOutType(): ?Type public function returnsByReference(): TrinaryLogic { - return TrinaryLogic::createMaybe(); + return TrinaryLogic::lazyExtremeIdentity($this->methods, static fn (ExtendedMethodReflection $method): TrinaryLogic => $method->returnsByReference()); } } From 509b5b8f21c90df92e5e4d69322035ffce7eb291 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 26 Oct 2022 14:22:25 +0200 Subject: [PATCH 6/6] test EnumX::cases() special case --- src/Analyser/MutatingScope.php | 2 -- src/Reflection/BetterReflection/BetterReflectionProvider.php | 2 -- src/Reflection/Php/PhpClassReflectionExtension.php | 2 -- tests/PHPStan/Reflection/FunctionReflectionTest.php | 2 ++ 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 405df1587f..bcf9bf024d 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -2567,7 +2567,6 @@ public function enterClassMethod( $selfOutType, $phpDocComment, array_map(static fn (Type $type): Type => TemplateTypeHelper::toArgument($type), $parameterOutTypes), - TrinaryLogic::createMaybe(), ), !$classMethod->isStatic(), ); @@ -2673,7 +2672,6 @@ public function enterFunction( $asserts ?? Assertions::createEmpty(), $phpDocComment, array_map(static fn (Type $type): Type => TemplateTypeHelper::toArgument($type), $parameterOutTypes), - TrinaryLogic::createMaybe(), ), false, ); diff --git a/src/Reflection/BetterReflection/BetterReflectionProvider.php b/src/Reflection/BetterReflection/BetterReflectionProvider.php index a255ce4c9c..0766abd21a 100644 --- a/src/Reflection/BetterReflection/BetterReflectionProvider.php +++ b/src/Reflection/BetterReflection/BetterReflectionProvider.php @@ -44,7 +44,6 @@ use PHPStan\Reflection\ReflectionProvider; use PHPStan\Reflection\SignatureMap\NativeFunctionReflectionProvider; use PHPStan\ShouldNotHappenException; -use PHPStan\TrinaryLogic; use PHPStan\Type\FileTypeMapper; use PHPStan\Type\Generic\TemplateTypeMap; use PHPStan\Type\Type; @@ -308,7 +307,6 @@ private function getCustomFunction(string $functionName): PhpFunctionReflection $asserts, $phpDocComment, array_map(static fn (ParamOutTag $paramOutTag): Type => $paramOutTag->getType(), $phpDocParameterOutTags), - TrinaryLogic::createFromBoolean($reflectionFunction->returnsReference()), ); } diff --git a/src/Reflection/Php/PhpClassReflectionExtension.php b/src/Reflection/Php/PhpClassReflectionExtension.php index db8f220b7e..f7ab2e78bf 100644 --- a/src/Reflection/Php/PhpClassReflectionExtension.php +++ b/src/Reflection/Php/PhpClassReflectionExtension.php @@ -751,7 +751,6 @@ private function createMethod( null, $declaringClass->getName(), ); - $returnsByReference = $methodReflection->returnsByReference(); $phpDocReturnType = $this->getPhpDocReturnType($phpDocBlockClassReflection, $resolvedPhpDoc, $nativeReturnType); $phpDocThrowType = $resolvedPhpDoc->getThrowsTag() !== null ? $resolvedPhpDoc->getThrowsTag()->getType() : null; $deprecatedDescription = $resolvedPhpDoc->getDeprecatedTag() !== null ? $resolvedPhpDoc->getDeprecatedTag()->getMessage() : null; @@ -783,7 +782,6 @@ private function createMethod( $selfOutType, $phpDocComment, $phpDocParameterOutTypes, - $returnsByReference, ); } diff --git a/tests/PHPStan/Reflection/FunctionReflectionTest.php b/tests/PHPStan/Reflection/FunctionReflectionTest.php index 6c23ca4027..4299b2755c 100644 --- a/tests/PHPStan/Reflection/FunctionReflectionTest.php +++ b/tests/PHPStan/Reflection/FunctionReflectionTest.php @@ -168,6 +168,8 @@ public function dataMethodReturnsByReference(): iterable yield ['ReturnsByReference\\E', 'enumFoo', TrinaryLogic::createNo()]; yield ['ReturnsByReference\\E', 'refEnumFoo', TrinaryLogic::createYes()]; + // cases() method cannot be overridden; https://3v4l.org/ebm83 + yield ['ReturnsByReference\\E', 'cases', TrinaryLogic::createNo()]; } /**