From 7e60264d44dd8660de400af5e84578cf378d3b55 Mon Sep 17 00:00:00 2001 From: Dave Liddament Date: Sun, 9 Feb 2025 14:41:03 +0000 Subject: [PATCH] Update check for #[MustUseResult] on method definitions in interfaces and extended classes --- src/Rules/MustUseResultRule.php | 31 +++++-- tests/Rules/MustUseResultTest.php | 10 +++ .../mustUseResultOnExtendedClass.php | 88 +++++++++++++++++++ .../mustUseResultOnInterface.php | 60 +++++++++++++ 4 files changed, 184 insertions(+), 5 deletions(-) create mode 100644 tests/Rules/data/mustUseResult/mustUseResultOnExtendedClass.php create mode 100644 tests/Rules/data/mustUseResult/mustUseResultOnInterface.php diff --git a/src/Rules/MustUseResultRule.php b/src/Rules/MustUseResultRule.php index dbfb31d..30e020e 100644 --- a/src/Rules/MustUseResultRule.php +++ b/src/Rules/MustUseResultRule.php @@ -7,6 +7,7 @@ use DaveLiddament\PhpstanPhpLanguageExtensions\Helpers\Cache; use PhpParser\Node; use PHPStan\Analyser\Scope; +use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; @@ -66,11 +67,8 @@ public function processNode(Node $node, Scope $scope): array if ($this->cache->hasEntry($fullMethodName)) { $mustUseResult = $this->cache->getEntry($fullMethodName); } else { - $mustUseResult = AttributeFinder::hasAttributeOnMethod( - $classReflection->getNativeReflection(), - $methodName, - MustUseResult::class, - ); + $mustUseResult = $this->isMustUseResult($classReflection, $methodName); + $this->cache->addEntry($fullMethodName, $mustUseResult); } @@ -85,4 +83,27 @@ public function processNode(Node $node, Scope $scope): array return []; } + + private function isMustUseResult(ClassReflection $classReflection, string $methodName): bool + { + if (AttributeFinder::hasAttributeOnMethod( + $classReflection->getNativeReflection(), + $methodName, + MustUseResult::class, + )) { + return true; + } + + foreach ($classReflection->getAncestors() as $parentClassReflection) { + if (AttributeFinder::hasAttributeOnMethod( + $parentClassReflection->getNativeReflection(), + $methodName, + MustUseResult::class, + )) { + return true; + } + } + + return false; + } } diff --git a/tests/Rules/MustUseResultTest.php b/tests/Rules/MustUseResultTest.php index fd1585a..9652782 100644 --- a/tests/Rules/MustUseResultTest.php +++ b/tests/Rules/MustUseResultTest.php @@ -35,6 +35,16 @@ public function testMustUseWithParent(): void $this->assertIssuesReported(__DIR__.'/data/mustUseResult/mustUseResultWithParent.php'); } + public function testMustUseResultOnExtendedClass(): void + { + $this->assertIssuesReported(__DIR__.'/data/mustUseResult/mustUseResultOnExtendedClass.php'); + } + + public function testMustUseResultOnInterface(): void + { + $this->assertIssuesReported(__DIR__.'/data/mustUseResult/mustUseResultOnInterface.php'); + } + protected function getErrorFormatter(): string { return 'Result returned by method must be used'; diff --git a/tests/Rules/data/mustUseResult/mustUseResultOnExtendedClass.php b/tests/Rules/data/mustUseResult/mustUseResultOnExtendedClass.php new file mode 100644 index 0000000..b163e0f --- /dev/null +++ b/tests/Rules/data/mustUseResult/mustUseResultOnExtendedClass.php @@ -0,0 +1,88 @@ +dontNeedToUseResult(); // OK + + $extendedOnce->mustUseResult(); // ERROR + + $extendedOnce->abstractMustUseResult(); // ERROR + + $extendedOnce->abstractDontNeedToUseResult(); // OK + + echo $extendedOnce->mustUseResult(); // OK; + + $value = 1 + $extendedOnce->mustUseResult(); // OK + + + + $extendedTwice = new ExtendedTwice(); + + $extendedTwice->dontNeedToUseResult(); // OK + + $extendedTwice->mustUseResult(); // ERROR + + $extendedTwice->abstractMustUseResult(); // ERROR + + $extendedTwice->abstractDontNeedToUseResult(); // OK + + echo $extendedTwice->mustUseResult(); // OK; + + $value = 1 + $extendedTwice->mustUseResult(); // OK +} \ No newline at end of file diff --git a/tests/Rules/data/mustUseResult/mustUseResultOnInterface.php b/tests/Rules/data/mustUseResult/mustUseResultOnInterface.php new file mode 100644 index 0000000..416b784 --- /dev/null +++ b/tests/Rules/data/mustUseResult/mustUseResultOnInterface.php @@ -0,0 +1,60 @@ +dontNeedToUseResult(); // OK + + $extendedOnce->mustUseResult(); // ERROR + + echo $extendedOnce->mustUseResult(); // OK; + + $value = 1 + $extendedOnce->mustUseResult(); // OK + + + + $extendedTwice = new ExtendedTwice(); + + $extendedTwice->dontNeedToUseResult(); // OK + + $extendedTwice->mustUseResult(); // ERROR + + echo $extendedTwice->mustUseResult(); // OK; + + $value = 1 + $extendedTwice->mustUseResult(); // OK +} \ No newline at end of file