Skip to content

Commit

Permalink
Do not report missing implementation abstract method from trait when …
Browse files Browse the repository at this point in the history
…it's implicitly implemented by enum
  • Loading branch information
ondrejmirtes committed Sep 3, 2024
1 parent 1cba4ba commit c50b71f
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 15 deletions.
13 changes: 0 additions & 13 deletions src/Rules/Classes/EnumSanityRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,7 @@ public function processNode(Node $node, Scope $scope): array
$errors = [];

foreach ($enumNode->getMethods() as $methodNode) {
if ($methodNode->isAbstract()) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Enum %s contains abstract method %s().',
$classReflection->getDisplayName(),
$methodNode->name->name,
))
->identifier('enum.abstractMethod')
->line($methodNode->getStartLine())
->nonIgnorable()
->build();
}

$lowercasedMethodName = $methodNode->name->toLowerString();

if ($methodNode->isMagic()) {
if ($lowercasedMethodName === '__construct') {
$errors[] = RuleErrorBuilder::message(sprintf(
Expand Down
13 changes: 13 additions & 0 deletions src/Rules/Methods/AbstractMethodInNonAbstractClassRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\ShouldNotHappenException;
use function in_array;
use function sprintf;

/**
Expand All @@ -29,6 +30,18 @@ public function processNode(Node $node, Scope $scope): array
$class = $scope->getClassReflection();

if (!$class->isAbstract() && $node->isAbstract()) {
if ($class->isEnum()) {
$lowercasedMethodName = $node->name->toLowerString();
if ($lowercasedMethodName === 'cases') {
return [];
}
if ($class->isBackedEnum()) {
if (in_array($lowercasedMethodName, ['from', 'tryfrom'], true)) {
return [];
}
}
}

$description = $class->getClassTypeDescription();
return [
RuleErrorBuilder::message(sprintf(
Expand Down
31 changes: 29 additions & 2 deletions tests/PHPStan/Rules/Classes/EnumSanityRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ public function testRule(): void
}

$expected = [
[
/*[
// reported by AbstractMethodInNonAbstractClassRule
'Enum EnumSanity\EnumWithAbstractMethod contains abstract method foo().',
7,
],
],*/
[
'Enum EnumSanity\EnumWithConstructorAndDestructor contains constructor.',
12,
Expand Down Expand Up @@ -123,4 +124,30 @@ public function testBug9402(): void
]);
}

public function testBug11592(): void
{
if (PHP_VERSION_ID < 80100) {
$this->markTestSkipped('Test requires PHP 8.1');
}

$this->analyse([__DIR__ . '/data/bug-11592.php'], [
[
'Enum Bug11592\Test2 cannot redeclare native method cases().',
22,
],
[
'Enum Bug11592\BackedTest2 cannot redeclare native method cases().',
37,
],
[
'Enum Bug11592\BackedTest2 cannot redeclare native method from().',
39,
],
[
'Enum Bug11592\BackedTest2 cannot redeclare native method tryFrom().',
41,
],
]);
}

}
47 changes: 47 additions & 0 deletions tests/PHPStan/Rules/Classes/data/bug-11592.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php // lint >= 8.1

namespace Bug11592;

trait HelloWorld
{
abstract public static function cases(): array;

abstract public static function from(): self;

abstract public static function tryFrom(): ?self;
}

enum Test
{
use HelloWorld;
}

enum Test2
{

abstract public static function cases(): array;

abstract public static function from(): self;

abstract public static function tryFrom(): ?self;

}

enum BackedTest: int
{
use HelloWorld;
}

enum BackedTest2: int
{
abstract public static function cases(): array;

abstract public static function from(): self;

abstract public static function tryFrom(): ?self;
}

enum EnumWithAbstractMethod
{
abstract function foo();
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,34 @@ public function testEnum(): void
]);
}

public function testBug11592(): void
{
if (PHP_VERSION_ID < 80100) {
$this->markTestSkipped('Test requires PHP 8.1');
}

$this->analyse([__DIR__ . '/../Classes/data/bug-11592.php'], [
[
'Enum Bug11592\Test contains abstract method from().',
9,
],
[
'Enum Bug11592\Test contains abstract method tryFrom().',
11,
],
[
'Enum Bug11592\Test2 contains abstract method from().',
24,
],
[
'Enum Bug11592\Test2 contains abstract method tryFrom().',
26,
],
[
'Enum Bug11592\EnumWithAbstractMethod contains abstract method foo().',
46,
],
]);
}

}

0 comments on commit c50b71f

Please sign in to comment.