From 1c2b7271ff0468f264837cc7ab32c6a52574658e Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Sun, 1 Nov 2020 13:19:50 +0100 Subject: [PATCH] Fix checking overriden method signature when method-level generics are involved --- src/Rules/Methods/MethodSignatureRule.php | 19 +++++-- .../Rules/Methods/MethodSignatureRuleTest.php | 38 +++++++++++++ tests/PHPStan/Rules/Methods/data/bug-4017.php | 40 +++++++++++++ .../PHPStan/Rules/Methods/data/bug-4017_2.php | 56 +++++++++++++++++++ .../PHPStan/Rules/Methods/data/bug-4017_3.php | 50 +++++++++++++++++ tests/PHPStan/Rules/Methods/data/bug-4023.php | 30 ++++++++++ 6 files changed, 227 insertions(+), 6 deletions(-) create mode 100644 tests/PHPStan/Rules/Methods/data/bug-4017.php create mode 100644 tests/PHPStan/Rules/Methods/data/bug-4017_2.php create mode 100644 tests/PHPStan/Rules/Methods/data/bug-4017_3.php create mode 100644 tests/PHPStan/Rules/Methods/data/bug-4023.php diff --git a/src/Rules/Methods/MethodSignatureRule.php b/src/Rules/Methods/MethodSignatureRule.php index c062a783da..afbc188375 100644 --- a/src/Rules/Methods/MethodSignatureRule.php +++ b/src/Rules/Methods/MethodSignatureRule.php @@ -11,6 +11,7 @@ use PHPStan\Reflection\Php\PhpMethodFromParserNodeReflection; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\TrinaryLogic; +use PHPStan\Type\Generic\TemplateTypeHelper; use PHPStan\Type\MixedType; use PHPStan\Type\Type; use PHPStan\Type\TypehintHelper; @@ -154,11 +155,11 @@ private function checkReturnTypeCompatibility( { $returnType = TypehintHelper::decideType( $currentVariant->getNativeReturnType(), - $currentVariant->getPhpDocReturnType() + TemplateTypeHelper::resolveToBounds($currentVariant->getPhpDocReturnType()) ); $parentReturnType = TypehintHelper::decideType( $parentVariant->getNativeReturnType(), - $parentVariant->getPhpDocReturnType() + TemplateTypeHelper::resolveToBounds($parentVariant->getPhpDocReturnType()) ); // Allow adding `void` return type hints when the parent defines no return type if ($returnType instanceof VoidType && $parentReturnType instanceof MixedType) { @@ -170,7 +171,10 @@ private function checkReturnTypeCompatibility( return [TrinaryLogic::createYes(), $returnType, $parentReturnType]; } - return [$parentReturnType->isSuperTypeOf($returnType), $returnType, $parentReturnType]; + return [$parentReturnType->isSuperTypeOf($returnType), TypehintHelper::decideType( + $currentVariant->getNativeReturnType(), + $currentVariant->getPhpDocReturnType() + ), $parentReturnType]; } /** @@ -192,14 +196,17 @@ private function checkParameterTypeCompatibility( $parameterType = TypehintHelper::decideType( $parameter->getNativeType(), - $parameter->getPhpDocType() + TemplateTypeHelper::resolveToBounds($parameter->getPhpDocType()) ); $parentParameterType = TypehintHelper::decideType( $parentParameter->getNativeType(), - $parentParameter->getPhpDocType() + TemplateTypeHelper::resolveToBounds($parentParameter->getPhpDocType()) ); - $parameterResults[] = [$parameterType->isSuperTypeOf($parentParameterType), $parameterType, $parentParameterType]; + $parameterResults[] = [$parameterType->isSuperTypeOf($parentParameterType), TypehintHelper::decideType( + $parameter->getNativeType(), + $parameter->getPhpDocType() + ), $parentParameterType]; } return $parameterResults; diff --git a/tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php b/tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php index 2697fe9881..d84159da38 100644 --- a/tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php +++ b/tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php @@ -239,4 +239,42 @@ public function testBug4003(): void ]); } + public function testBug4017(): void + { + $this->reportMaybes = true; + $this->reportStatic = true; + $this->analyse([__DIR__ . '/data/bug-4017.php'], []); + } + + public function testBug4017Two(): void + { + $this->reportMaybes = true; + $this->reportStatic = true; + $this->analyse([__DIR__ . '/data/bug-4017_2.php'], [ + [ + 'Parameter #1 $a (Bug4017_2\Foo) of method Bug4017_2\Lorem::doFoo() should be compatible with parameter $a (stdClass) of method Bug4017_2\Bar::doFoo()', + 51, + ], + ]); + } + + public function testBug4017Three(): void + { + $this->reportMaybes = true; + $this->reportStatic = true; + $this->analyse([__DIR__ . '/data/bug-4017_3.php'], [ + [ + 'Parameter #1 $a (T of stdClass) of method Bug4017_3\Lorem::doFoo() should be compatible with parameter $a (Bug4017_3\Foo) of method Bug4017_3\Bar::doFoo()', + 45, + ], + ]); + } + + public function testBug4023(): void + { + $this->reportMaybes = true; + $this->reportStatic = true; + $this->analyse([__DIR__ . '/data/bug-4023.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Methods/data/bug-4017.php b/tests/PHPStan/Rules/Methods/data/bug-4017.php new file mode 100644 index 0000000000..c374328688 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/bug-4017.php @@ -0,0 +1,40 @@ + $className + * @return DoctrineEntityRepository + */ + public function getRepository(string $className): DoctrineEntityRepository; +} + + +/** + * @phpstan-template TEntityClass + * @phpstan-extends DoctrineEntityRepository + */ +interface MyEntityRepositoryInterface extends DoctrineEntityRepository +{ +} + +interface MyEntityManagerInterface extends DoctrineEntityManagerInterface +{ + /** + * @template T + * @param class-string $className + * @return MyEntityRepositoryInterface + */ + public function getRepository(string $className): MyEntityRepositoryInterface; +} diff --git a/tests/PHPStan/Rules/Methods/data/bug-4017_2.php b/tests/PHPStan/Rules/Methods/data/bug-4017_2.php new file mode 100644 index 0000000000..30adaa35ca --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/bug-4017_2.php @@ -0,0 +1,56 @@ + + */ +class Baz extends Bar +{ + + /** + * @param Foo $a + */ + public function doFoo($a) + { + + } + +} + +/** + * @extends Bar<\stdClass> + */ +class Lorem extends Bar +{ + + /** + * @param Foo $a + */ + public function doFoo($a) + { + + } + +} diff --git a/tests/PHPStan/Rules/Methods/data/bug-4017_3.php b/tests/PHPStan/Rules/Methods/data/bug-4017_3.php new file mode 100644 index 0000000000..f458c85bf2 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/bug-4017_3.php @@ -0,0 +1,50 @@ +