From e0c3a4f36a0f8eb30b0024623c672fa554713457 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sat, 3 May 2025 03:46:42 +0700 Subject: [PATCH 1/6] Revert "Useful PhpMethodReflection native type refactoring from #3966" This reverts commit 3854cbc5748a7cb51ee0b86ceffe29bd0564bc98. --- src/Reflection/Php/PhpMethodReflection.php | 47 +++++++++++----------- src/Type/TypehintHelper.php | 5 +-- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/Reflection/Php/PhpMethodReflection.php b/src/Reflection/Php/PhpMethodReflection.php index b141bcec7e..432fd69350 100644 --- a/src/Reflection/Php/PhpMethodReflection.php +++ b/src/Reflection/Php/PhpMethodReflection.php @@ -302,9 +302,30 @@ public function isPublic(): bool private function getReturnType(): Type { if ($this->returnType === null) { - $this->returnType = TypehintHelper::decideType( - $this->getNativeReturnType(), + $name = strtolower($this->getName()); + $returnType = $this->reflection->getReturnType(); + if ($returnType === null) { + if (in_array($name, ['__construct', '__destruct', '__unset', '__wakeup', '__clone'], true)) { + return $this->returnType = TypehintHelper::decideType(new VoidType(), $this->phpDocReturnType); + } + if ($name === '__tostring') { + return $this->returnType = TypehintHelper::decideType(new StringType(), $this->phpDocReturnType); + } + if ($name === '__isset') { + return $this->returnType = TypehintHelper::decideType(new BooleanType(), $this->phpDocReturnType); + } + if ($name === '__sleep') { + return $this->returnType = TypehintHelper::decideType(new ArrayType(new IntegerType(), new StringType()), $this->phpDocReturnType); + } + if ($name === '__set_state') { + return $this->returnType = TypehintHelper::decideType(new ObjectWithoutClassType(), $this->phpDocReturnType); + } + } + + $this->returnType = TypehintHelper::decideTypeFromReflection( + $returnType, $this->phpDocReturnType, + $this->declaringClass, ); } @@ -323,28 +344,8 @@ private function getPhpDocReturnType(): Type private function getNativeReturnType(): Type { if ($this->nativeReturnType === null) { - $returnType = $this->reflection->getReturnType(); - if ($returnType === null) { - $name = strtolower($this->getName()); - if (in_array($this->getName(), ['__construct', '__destruct', '__unset', '__wakeup', '__clone'], true)) { - return $this->nativeReturnType = new VoidType(); - } - if ($name === '__tostring') { - return $this->nativeReturnType = new StringType(); - } - if ($name === '__isset') { - return $this->nativeReturnType = new BooleanType(); - } - if ($name === '__sleep') { - return $this->nativeReturnType = new ArrayType(new IntegerType(), new StringType()); - } - if ($name === '__set_state') { - return $this->nativeReturnType = new ObjectWithoutClassType(); - } - } - $this->nativeReturnType = TypehintHelper::decideTypeFromReflection( - $returnType, + $this->reflection->getReturnType(), null, $this->declaringClass, ); diff --git a/src/Type/TypehintHelper.php b/src/Type/TypehintHelper.php index df89b763b1..5ae08aac5d 100644 --- a/src/Type/TypehintHelper.php +++ b/src/Type/TypehintHelper.php @@ -68,6 +68,8 @@ public static function decideTypeFromReflection( $type = ParserNodeTypeToPHPStanType::resolve($typeNode, $selfClass); if ($reflectionType->allowsNull()) { $type = TypeCombinator::addNull($type); + } elseif ($phpDocType !== null) { + $phpDocType = TypeCombinator::removeNull($phpDocType); } return self::decideType($type, $phpDocType); @@ -78,9 +80,6 @@ public static function decideType( ?Type $phpDocType, ): Type { - if ($phpDocType !== null && $type->isNull()->no()) { - $phpDocType = TypeCombinator::removeNull($phpDocType); - } if ($type instanceof BenevolentUnionType) { return $type; } From 2247c699ac7de6f9cdd475f7cabe960065f7ea9e Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sat, 3 May 2025 03:51:01 +0700 Subject: [PATCH 2/6] add test for mixed __toString() --- .../Analyser/nsrt/bug-to-string-type.php | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tests/PHPStan/Analyser/nsrt/bug-to-string-type.php diff --git a/tests/PHPStan/Analyser/nsrt/bug-to-string-type.php b/tests/PHPStan/Analyser/nsrt/bug-to-string-type.php new file mode 100644 index 0000000000..a9c49e80f8 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-to-string-type.php @@ -0,0 +1,32 @@ +__toString()); +} From 40f9920d56456d9b1d117a7ce1cf15f04abf0450 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sat, 3 May 2025 03:54:46 +0700 Subject: [PATCH 3/6] add missing use statement --- tests/PHPStan/Analyser/nsrt/bug-to-string-type.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/PHPStan/Analyser/nsrt/bug-to-string-type.php b/tests/PHPStan/Analyser/nsrt/bug-to-string-type.php index a9c49e80f8..bb64f421a7 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-to-string-type.php +++ b/tests/PHPStan/Analyser/nsrt/bug-to-string-type.php @@ -2,6 +2,8 @@ namespace BugToStringType; +use function PHPStan\Testing\assertType; + class ParentClassWithToStringMixedReturn { public function __toString() From 993bfbd1b66b02afc9dc26dc9154ec1065c379c3 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sat, 3 May 2025 03:58:52 +0700 Subject: [PATCH 4/6] test native and non-native --- tests/PHPStan/Analyser/nsrt/bug-to-string-type.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/PHPStan/Analyser/nsrt/bug-to-string-type.php b/tests/PHPStan/Analyser/nsrt/bug-to-string-type.php index bb64f421a7..31e1b97281 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-to-string-type.php +++ b/tests/PHPStan/Analyser/nsrt/bug-to-string-type.php @@ -2,6 +2,7 @@ namespace BugToStringType; +use function PHPStan\Testing\assertNativeType; use function PHPStan\Testing\assertType; class ParentClassWithToStringMixedReturn @@ -30,5 +31,6 @@ public function __toString() function test(Consumer $test): void { - assertType('mixed', $test->__toString()); + assertType('string', $test->__toString()); + assertNativeType('mixed', $test->__toString()); } From 4e820816ad78608d7f2ef8bbb9f322a878d45fa5 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sat, 3 May 2025 16:24:12 +0700 Subject: [PATCH 5/6] keep TypehintHelper remove null --- src/Type/TypehintHelper.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Type/TypehintHelper.php b/src/Type/TypehintHelper.php index 5ae08aac5d..c5e338ebad 100644 --- a/src/Type/TypehintHelper.php +++ b/src/Type/TypehintHelper.php @@ -68,8 +68,6 @@ public static function decideTypeFromReflection( $type = ParserNodeTypeToPHPStanType::resolve($typeNode, $selfClass); if ($reflectionType->allowsNull()) { $type = TypeCombinator::addNull($type); - } elseif ($phpDocType !== null) { - $phpDocType = TypeCombinator::removeNull($phpDocType); } return self::decideType($type, $phpDocType); @@ -80,6 +78,10 @@ public static function decideType( ?Type $phpDocType, ): Type { + if ($phpDocType !== null && $type->isNull()->no()) { + $phpDocType = TypeCombinator::removeNull($phpDocType); + } + if ($type instanceof BenevolentUnionType) { return $type; } From 213967850f702cbf2d87d3b2bc39883c55b8e348 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sat, 3 May 2025 16:25:39 +0700 Subject: [PATCH 6/6] remove space as it was before --- src/Type/TypehintHelper.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Type/TypehintHelper.php b/src/Type/TypehintHelper.php index c5e338ebad..df89b763b1 100644 --- a/src/Type/TypehintHelper.php +++ b/src/Type/TypehintHelper.php @@ -81,7 +81,6 @@ public static function decideType( if ($phpDocType !== null && $type->isNull()->no()) { $phpDocType = TypeCombinator::removeNull($phpDocType); } - if ($type instanceof BenevolentUnionType) { return $type; }