From 03d8312e3ea62bb2c6a3ed89a88a6d86101a5594 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Fri, 27 Aug 2021 09:46:14 +0200 Subject: [PATCH] Fixed missing return rule for native mixed type --- src/Rules/Missing/MissingReturnRule.php | 1 + .../Analyser/NodeScopeResolverTest.php | 4 +++ tests/PHPStan/Analyser/data/model-mixin.php | 30 +++++++++++++++++ .../Rules/Missing/MissingReturnRuleTest.php | 32 +++++++++++++++++++ 4 files changed, 67 insertions(+) create mode 100644 tests/PHPStan/Analyser/data/model-mixin.php diff --git a/src/Rules/Missing/MissingReturnRule.php b/src/Rules/Missing/MissingReturnRule.php index ffa7b2759a..641352b3e6 100644 --- a/src/Rules/Missing/MissingReturnRule.php +++ b/src/Rules/Missing/MissingReturnRule.php @@ -114,6 +114,7 @@ public function processNode(Node $node, Scope $scope): array if ( $returnType instanceof MixedType && !$returnType instanceof TemplateMixedType + && !$node->hasNativeReturnTypehint() && ( !$returnType->isExplicitMixed() || !$this->checkExplicitMixedMissingReturn diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index d3a4cecc38..2e1d412e3d 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -482,6 +482,10 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/data/filter-var-returns-non-empty-string.php'); + if (PHP_VERSION_ID >= 80000 || self::$useStaticReflectionProvider) { + yield from $this->gatherAssertTypes(__DIR__ . '/data/model-mixin.php'); + } + yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-5529.php'); } diff --git a/tests/PHPStan/Analyser/data/model-mixin.php b/tests/PHPStan/Analyser/data/model-mixin.php new file mode 100644 index 0000000000..69bd29565a --- /dev/null +++ b/tests/PHPStan/Analyser/data/model-mixin.php @@ -0,0 +1,30 @@ += 8.0 + +namespace ModelMixin; + +use function PHPStan\Testing\assertType; + +/** @mixin Builder */ +class Model +{ + /** @param array $args */ + public static function __callStatic(string $method, array $args): mixed + { + (new self)->$method(...$args); + } +} + +/** @template TModel as Model */ +class Builder +{ + /** @return array */ + public function all() { return []; } +} + +class User extends Model +{ +} + +function (): void { + assertType('array', User::all()); +}; diff --git a/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php b/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php index aaa8cf8cc6..2b2640ee7b 100644 --- a/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php +++ b/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php @@ -250,4 +250,36 @@ public function testCheckPhpDocMissingReturn(bool $checkPhpDocMissingReturn, arr $this->analyse([__DIR__ . '/data/check-phpdoc-missing-return.php'], $errors); } + public function dataModelMixin(): array + { + return [ + [ + true, + ], + [ + false, + ], + ]; + } + + /** + * @dataProvider dataModelMixin + * @param bool $checkExplicitMixedMissingReturn + */ + public function testModelMixin(bool $checkExplicitMixedMissingReturn): void + { + if (PHP_VERSION_ID < 80000 && !self::$useStaticReflectionProvider) { + $this->markTestSkipped('Test requires PHP 8.0.'); + } + + $this->checkExplicitMixedMissingReturn = $checkExplicitMixedMissingReturn; + $this->checkPhpDocMissingReturn = true; + $this->analyse([__DIR__ . '/../../Analyser/data/model-mixin.php'], [ + [ + 'Method ModelMixin\Model::__callStatic() should return mixed but return statement is missing.', + 13, + ], + ]); + } + }