diff --git a/src/PhpDoc/StubValidator.php b/src/PhpDoc/StubValidator.php index b8396455d8..190d3e296c 100644 --- a/src/PhpDoc/StubValidator.php +++ b/src/PhpDoc/StubValidator.php @@ -201,7 +201,7 @@ private function getRuleRegistry(Container $container): RuleRegistry $container->getParameter('featureToggles')['invalidPhpDocTagLine'], ), new IncompatibleParamImmediatelyInvokedCallableRule($fileTypeMapper), - new IncompatibleSelfOutTypeRule(), + new IncompatibleSelfOutTypeRule($unresolvableTypeHelper), new IncompatibleClassConstantPhpDocTypeRule($genericObjectTypeCheck, $unresolvableTypeHelper), new InvalidThrowsPhpDocValueRule($fileTypeMapper), diff --git a/src/Rules/PhpDoc/IncompatibleSelfOutTypeRule.php b/src/Rules/PhpDoc/IncompatibleSelfOutTypeRule.php index b3092b7a4a..e81665cf8b 100644 --- a/src/Rules/PhpDoc/IncompatibleSelfOutTypeRule.php +++ b/src/Rules/PhpDoc/IncompatibleSelfOutTypeRule.php @@ -17,6 +17,10 @@ final class IncompatibleSelfOutTypeRule implements Rule { + public function __construct(private UnresolvableTypeHelper $unresolvableTypeHelper) + { + } + public function getNodeType(): string { return InClassMethodNode::class; @@ -39,7 +43,7 @@ public function processNode(Node $node, Scope $scope): array $errors[] = RuleErrorBuilder::message(sprintf( 'Self-out type %s of method %s::%s is not subtype of %s.', $selfOutType->describe(VerbosityLevel::precise()), - $classReflection->getName(), + $classReflection->getDisplayName(), $method->getName(), $classType->describe(VerbosityLevel::precise()), ))->identifier('selfOut.type')->build(); @@ -51,6 +55,14 @@ public function processNode(Node $node, Scope $scope): array ->build(); } + if ($this->unresolvableTypeHelper->containsUnresolvableType($selfOutType)) { + $errors[] = RuleErrorBuilder::message(sprintf( + 'PHPDoc tag @phpstan-self-out for method %s::%s() contains unresolvable type.', + $classReflection->getDisplayName(), + $method->getName(), + ))->identifier('parameter.unresolvableType')->build(); + } + return $errors; } diff --git a/tests/PHPStan/Rules/PhpDoc/IncompatibleSelfOutTypeRuleTest.php b/tests/PHPStan/Rules/PhpDoc/IncompatibleSelfOutTypeRuleTest.php index dae30a1039..efb2481bb6 100644 --- a/tests/PHPStan/Rules/PhpDoc/IncompatibleSelfOutTypeRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/IncompatibleSelfOutTypeRuleTest.php @@ -13,7 +13,7 @@ class IncompatibleSelfOutTypeRuleTest extends RuleTestCase protected function getRule(): Rule { - return new IncompatibleSelfOutTypeRule(); + return new IncompatibleSelfOutTypeRule(new UnresolvableTypeHelper()); } public function testRule(): void @@ -31,6 +31,14 @@ public function testRule(): void 'PHPDoc tag @phpstan-self-out is not supported above static method IncompatibleSelfOutType\Foo::selfOutStatic().', 38, ], + [ + 'PHPDoc tag @phpstan-self-out for method IncompatibleSelfOutType\Foo::doFoo() contains unresolvable type.', + 46, + ], + [ + 'PHPDoc tag @phpstan-self-out for method IncompatibleSelfOutType\Foo::doBar() contains unresolvable type.', + 54, + ], ]); } diff --git a/tests/PHPStan/Rules/PhpDoc/data/incompatible-self-out-type.php b/tests/PHPStan/Rules/PhpDoc/data/incompatible-self-out-type.php index 018b6b1c98..6cf1e7057a 100644 --- a/tests/PHPStan/Rules/PhpDoc/data/incompatible-self-out-type.php +++ b/tests/PHPStan/Rules/PhpDoc/data/incompatible-self-out-type.php @@ -40,4 +40,20 @@ public static function selfOutStatic(): void } + /** + * @phpstan-self-out int&string + */ + public function doFoo(): void + { + + } + + /** + * @phpstan-self-out self + */ + public function doBar(): void + { + + } + }