From 39d2b7d4f28d4383f0575c6d816d19bcb28da8a4 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 16 Feb 2025 16:44:50 +0100 Subject: [PATCH 01/22] Hooked properties cannot be both final and private --- src/Node/ClassPropertyNode.php | 5 +++ src/Rules/Properties/PropertyInClassRule.php | 26 ++++++++++++++ .../Properties/PropertyInClassRuleTest.php | 18 ++++++++++ .../data/private-final-property-hooks.php | 35 +++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 tests/PHPStan/Rules/Properties/data/private-final-property-hooks.php diff --git a/src/Node/ClassPropertyNode.php b/src/Node/ClassPropertyNode.php index b567aa7f7b..aae4446638 100644 --- a/src/Node/ClassPropertyNode.php +++ b/src/Node/ClassPropertyNode.php @@ -86,6 +86,11 @@ public function isPrivate(): bool return (bool) ($this->flags & Modifiers::PRIVATE); } + public function isFinal(): bool + { + return (bool) ($this->flags & Modifiers::FINAL); + } + public function isStatic(): bool { return (bool) ($this->flags & Modifiers::STATIC); diff --git a/src/Rules/Properties/PropertyInClassRule.php b/src/Rules/Properties/PropertyInClassRule.php index f14c9730a0..04f8e4f98f 100644 --- a/src/Rules/Properties/PropertyInClassRule.php +++ b/src/Rules/Properties/PropertyInClassRule.php @@ -81,6 +81,32 @@ public function processNode(Node $node, Scope $scope): array ]; } + if ($node->isPrivate()) { + if ($node->hasHooks()) { + if ($node->isFinal()) { + return [ + RuleErrorBuilder::message('Hooked properties cannot be both final and private.') + ->nonIgnorable() + ->identifier('property.abstractPrivate') + ->build(), + ]; + } + + foreach ($node->getHooks() as $hook) { + if (!$hook->isFinal()) { + continue; + } + + return [ + RuleErrorBuilder::message('Hooked properties cannot be both final and private.') + ->nonIgnorable() + ->identifier('property.abstractPrivate') + ->build(), + ]; + } + } + } + if ($node->isReadOnly()) { if ($node->hasHooks()) { return [ diff --git a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php index 54e041e694..cfe87c689c 100644 --- a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php @@ -213,4 +213,22 @@ public function testPhp84AndStaticHookedProperties(): void ]); } + public function testPhp84AndPrivateFinalHookedProperties(): void + { + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.4 or later.'); + } + + $this->analyse([__DIR__ . '/data/private-final-property-hooks.php'], [ + [ + 'Hooked properties cannot be both final and private.', + 7, + ], + [ + 'Hooked properties cannot be both final and private.', + 11, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Properties/data/private-final-property-hooks.php b/tests/PHPStan/Rules/Properties/data/private-final-property-hooks.php new file mode 100644 index 0000000000..8ad5e37ad7 --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/private-final-property-hooks.php @@ -0,0 +1,35 @@ += 8.4 + +namespace PrivateFinalHook; + +final class User +{ + final private string $privatePropGet = 'mailto: example.org' { + get => 'private:' . $this->privatePropGet; + } + + private string $privateSet = 'mailto: example.org' { + final set => 'private:' . $this->privateSet; + } + + protected string $protected = 'mailto: example.org' { + final get => 'protected:' . $this->protected; + } + + public string $public = 'mailto: example.org' { + final get => 'public:' . $this->public; + } + + private string $email = 'mailto: example.org' { + get => 'mailto:' . $this->email; + } + + function doFoo(): void + { + $u = new User; + var_dump($u->private); + var_dump($u->protected); + var_dump($u->public); + var_dump($u->email); + } +} From cdbc1c81160fc5c622dfa01560a53423b33e5ab0 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 16 Feb 2025 16:47:40 +0100 Subject: [PATCH 02/22] fix lint --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 47ccd330d4..ab23c75942 100644 --- a/Makefile +++ b/Makefile @@ -101,6 +101,7 @@ lint: --exclude tests/PHPStan/Rules/Properties/data/existing-classes-property-hooks.php \ --exclude tests/PHPStan/Rules/Properties/data/set-property-hook-parameter.php \ --exclude tests/PHPStan/Rules/Properties/data/overriding-final-property.php \ + --exclude tests/PHPStan/Rules/Properties/data/private-final-property-hooks.php \ src tests cs: From 49a9779ceede7699a7cf8be6ba14cc36d88e13b8 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 22 Feb 2025 09:35:19 +0100 Subject: [PATCH 03/22] Properties cannot be final --- src/Php/PhpVersion.php | 5 +++ src/Rules/Properties/PropertyInClassRule.php | 12 ++++++ .../Properties/PropertyInClassRuleTest.php | 39 ++++++++++++++++++- .../Properties/data/final-properties.php | 11 ++++++ 4 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 tests/PHPStan/Rules/Properties/data/final-properties.php diff --git a/src/Php/PhpVersion.php b/src/Php/PhpVersion.php index 651aff5205..272a22ce8d 100644 --- a/src/Php/PhpVersion.php +++ b/src/Php/PhpVersion.php @@ -357,6 +357,11 @@ public function supportsPropertyHooks(): bool return $this->versionId >= 80400; } + public function supportsNonPrivateFinalProperties(): bool + { + return $this->versionId >= 80400; + } + public function supportsAsymmetricVisibility(): bool { return $this->versionId >= 80400; diff --git a/src/Rules/Properties/PropertyInClassRule.php b/src/Rules/Properties/PropertyInClassRule.php index 04f8e4f98f..000bf53dc6 100644 --- a/src/Rules/Properties/PropertyInClassRule.php +++ b/src/Rules/Properties/PropertyInClassRule.php @@ -81,6 +81,18 @@ public function processNode(Node $node, Scope $scope): array ]; } + $node->isFinal() + && !$node->hasHooks() + && (!$this->phpVersion->supportsNonPrivateFinalProperties() || $node->isPrivate()) + ) { + return [ + RuleErrorBuilder::message('Properties cannot be final.') + ->nonIgnorable() + ->identifier('property.final') + ->build(), + ]; + } + if ($node->isPrivate()) { if ($node->hasHooks()) { if ($node->isFinal()) { diff --git a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php index cfe87c689c..580b9023df 100644 --- a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php @@ -221,14 +221,49 @@ public function testPhp84AndPrivateFinalHookedProperties(): void $this->analyse([__DIR__ . '/data/private-final-property-hooks.php'], [ [ - 'Hooked properties cannot be both final and private.', + 'Properties cannot be both final and private.', 7, ], [ - 'Hooked properties cannot be both final and private.', + 'Properties cannot be both final and private.', 11, ], ]); } + public function testPhp84FinalProperties(): void + { + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.4 or later.'); + } + + $this->analyse([__DIR__ . '/data/final-properties.php'], [ + [ + 'Properties cannot be final.', + 7, + ], + ]); + } + public function testBeforePhp84FinalProperties(): void + { + if (PHP_VERSION_ID >= 80400) { + $this->markTestSkipped('Test requires PHP 8.3 or earlier.'); + } + + $this->analyse([__DIR__ . '/data/final-properties.php'], [ + [ + 'Properties cannot be final.', + 7, + ], + [ + 'Properties cannot be final.', + 8, + ], + [ + 'Properties cannot be final.', + 9, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Properties/data/final-properties.php b/tests/PHPStan/Rules/Properties/data/final-properties.php new file mode 100644 index 0000000000..1e04ef49b6 --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/final-properties.php @@ -0,0 +1,11 @@ + Date: Sat, 22 Feb 2025 09:47:14 +0100 Subject: [PATCH 04/22] fix --- src/Rules/Properties/PropertyInClassRule.php | 39 +++++++++---------- .../data/private-final-property-hooks.php | 5 ++- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Rules/Properties/PropertyInClassRule.php b/src/Rules/Properties/PropertyInClassRule.php index 000bf53dc6..03c8eb8b01 100644 --- a/src/Rules/Properties/PropertyInClassRule.php +++ b/src/Rules/Properties/PropertyInClassRule.php @@ -81,6 +81,7 @@ public function processNode(Node $node, Scope $scope): array ]; } + if ( $node->isFinal() && !$node->hasHooks() && (!$this->phpVersion->supportsNonPrivateFinalProperties() || $node->isPrivate()) @@ -94,28 +95,26 @@ public function processNode(Node $node, Scope $scope): array } if ($node->isPrivate()) { - if ($node->hasHooks()) { - if ($node->isFinal()) { - return [ - RuleErrorBuilder::message('Hooked properties cannot be both final and private.') - ->nonIgnorable() - ->identifier('property.abstractPrivate') - ->build(), - ]; - } + if ($node->isFinal()) { + return [ + RuleErrorBuilder::message('Properties cannot be both final and private.') + ->nonIgnorable() + ->identifier('property.finalPrivate') + ->build(), + ]; + } - foreach ($node->getHooks() as $hook) { - if (!$hook->isFinal()) { - continue; - } - - return [ - RuleErrorBuilder::message('Hooked properties cannot be both final and private.') - ->nonIgnorable() - ->identifier('property.abstractPrivate') - ->build(), - ]; + foreach ($node->getHooks() as $hook) { + if (!$hook->isFinal()) { + continue; } + + return [ + RuleErrorBuilder::message('Properties cannot be both final and private.') + ->nonIgnorable() + ->identifier('property.finalPrivate') + ->build(), + ]; } } diff --git a/tests/PHPStan/Rules/Properties/data/private-final-property-hooks.php b/tests/PHPStan/Rules/Properties/data/private-final-property-hooks.php index 8ad5e37ad7..1ce2830a95 100644 --- a/tests/PHPStan/Rules/Properties/data/private-final-property-hooks.php +++ b/tests/PHPStan/Rules/Properties/data/private-final-property-hooks.php @@ -8,8 +8,9 @@ final class User get => 'private:' . $this->privatePropGet; } - private string $privateSet = 'mailto: example.org' { - final set => 'private:' . $this->privateSet; + private string $private = 'mailto: example.org' { + final set => 'private:' . $this->private; + get => 'private:' . $this->private; } protected string $protected = 'mailto: example.org' { From 55dea67e4b420feed3ec7c503f2675e975095de7 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 22 Feb 2025 10:06:20 +0100 Subject: [PATCH 05/22] simplify --- src/Php/PhpVersion.php | 2 +- src/Rules/Properties/PropertyInClassRule.php | 9 ++++----- .../Rules/Properties/PropertyInClassRuleTest.php | 12 ++++++------ 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Php/PhpVersion.php b/src/Php/PhpVersion.php index 272a22ce8d..6f55bdda15 100644 --- a/src/Php/PhpVersion.php +++ b/src/Php/PhpVersion.php @@ -357,7 +357,7 @@ public function supportsPropertyHooks(): bool return $this->versionId >= 80400; } - public function supportsNonPrivateFinalProperties(): bool + public function supportsFinalProperties(): bool { return $this->versionId >= 80400; } diff --git a/src/Rules/Properties/PropertyInClassRule.php b/src/Rules/Properties/PropertyInClassRule.php index 03c8eb8b01..ab1e630cfc 100644 --- a/src/Rules/Properties/PropertyInClassRule.php +++ b/src/Rules/Properties/PropertyInClassRule.php @@ -83,11 +83,10 @@ public function processNode(Node $node, Scope $scope): array if ( $node->isFinal() - && !$node->hasHooks() - && (!$this->phpVersion->supportsNonPrivateFinalProperties() || $node->isPrivate()) + && !$this->phpVersion->supportsFinalProperties() ) { return [ - RuleErrorBuilder::message('Properties cannot be final.') + RuleErrorBuilder::message('Property cannot be final.') ->nonIgnorable() ->identifier('property.final') ->build(), @@ -97,7 +96,7 @@ public function processNode(Node $node, Scope $scope): array if ($node->isPrivate()) { if ($node->isFinal()) { return [ - RuleErrorBuilder::message('Properties cannot be both final and private.') + RuleErrorBuilder::message('Property cannot be both final and private.') ->nonIgnorable() ->identifier('property.finalPrivate') ->build(), @@ -110,7 +109,7 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message('Properties cannot be both final and private.') + RuleErrorBuilder::message('Property cannot be both final and private.') ->nonIgnorable() ->identifier('property.finalPrivate') ->build(), diff --git a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php index 580b9023df..ca7afaf408 100644 --- a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php @@ -221,11 +221,11 @@ public function testPhp84AndPrivateFinalHookedProperties(): void $this->analyse([__DIR__ . '/data/private-final-property-hooks.php'], [ [ - 'Properties cannot be both final and private.', + 'Property cannot be both final and private.', 7, ], [ - 'Properties cannot be both final and private.', + 'Property cannot be both final and private.', 11, ], ]); @@ -239,7 +239,7 @@ public function testPhp84FinalProperties(): void $this->analyse([__DIR__ . '/data/final-properties.php'], [ [ - 'Properties cannot be final.', + 'Property cannot be both final and private.', 7, ], ]); @@ -252,15 +252,15 @@ public function testBeforePhp84FinalProperties(): void $this->analyse([__DIR__ . '/data/final-properties.php'], [ [ - 'Properties cannot be final.', + 'Property cannot be final.', 7, ], [ - 'Properties cannot be final.', + 'Property cannot be final.', 8, ], [ - 'Properties cannot be final.', + 'Property cannot be final.', 9, ], ]); From 230bea3a37947894cc6bbbbf49b38bfbd73be892 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 22 Feb 2025 10:44:46 +0100 Subject: [PATCH 06/22] final hook in abstract class --- src/Rules/Properties/PropertyInClassRule.php | 15 +++++++++++++++ .../Rules/Properties/PropertyInClassRuleTest.php | 14 ++++++++++++++ .../data/abstract-final-property-hook.php | 10 ++++++++++ 3 files changed, 39 insertions(+) create mode 100644 tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php diff --git a/src/Rules/Properties/PropertyInClassRule.php b/src/Rules/Properties/PropertyInClassRule.php index ab1e630cfc..e890e382de 100644 --- a/src/Rules/Properties/PropertyInClassRule.php +++ b/src/Rules/Properties/PropertyInClassRule.php @@ -117,6 +117,21 @@ public function processNode(Node $node, Scope $scope): array } } + if ($classReflection->isAbstract() && $node->isAbstract()) { + foreach ($node->getHooks() as $hook) { + if (!$hook->isFinal()) { + continue; + } + + return [ + RuleErrorBuilder::message('Property cannot be both abstract and final.') + ->nonIgnorable() + ->identifier('property.finalPrivate') + ->build(), + ]; + } + } + if ($node->isReadOnly()) { if ($node->hasHooks()) { return [ diff --git a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php index ca7afaf408..f7144a7576 100644 --- a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php @@ -231,6 +231,20 @@ public function testPhp84AndPrivateFinalHookedProperties(): void ]); } + public function testPhp84AndAbstractFinalHookedProperties(): void + { + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.4 or later.'); + } + + $this->analyse([__DIR__ . '/data/abstract-final-property-hook.php'], [ + [ + 'Property cannot be both abstract and final.', + 7, + ], + ]); + } + public function testPhp84FinalProperties(): void { if (PHP_VERSION_ID < 80400) { diff --git a/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php b/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php new file mode 100644 index 0000000000..380c68eeae --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php @@ -0,0 +1,10 @@ += 8.4 + +namespace AbstractFinalHook; + +abstract class User +{ + abstract public string $foo { + final get; + } +} From dbc7204b1a3a284abbffde518c0e4968aa94dedf Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 22 Feb 2025 10:55:14 +0100 Subject: [PATCH 07/22] lint --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index ab23c75942..b558e89fd2 100644 --- a/Makefile +++ b/Makefile @@ -102,6 +102,8 @@ lint: --exclude tests/PHPStan/Rules/Properties/data/set-property-hook-parameter.php \ --exclude tests/PHPStan/Rules/Properties/data/overriding-final-property.php \ --exclude tests/PHPStan/Rules/Properties/data/private-final-property-hooks.php \ + --exclude tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php \ + --exclude tests/PHPStan/Rules/Properties/data/final-properties.php \ src tests cs: From a7ffd300199e9759e555dc13d60742a42f6f39d3 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 22 Feb 2025 11:01:38 +0100 Subject: [PATCH 08/22] cs --- tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php index f7144a7576..d2fdd388b5 100644 --- a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php @@ -258,6 +258,7 @@ public function testPhp84FinalProperties(): void ], ]); } + public function testBeforePhp84FinalProperties(): void { if (PHP_VERSION_ID >= 80400) { From 8d86a1e7058e908908469d5560edda2096908b8c Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 22 Feb 2025 11:04:11 +0100 Subject: [PATCH 09/22] fix 8.3 --- src/Rules/Properties/PropertyInClassRule.php | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Rules/Properties/PropertyInClassRule.php b/src/Rules/Properties/PropertyInClassRule.php index e890e382de..9c8dbf5041 100644 --- a/src/Rules/Properties/PropertyInClassRule.php +++ b/src/Rules/Properties/PropertyInClassRule.php @@ -32,6 +32,18 @@ public function processNode(Node $node, Scope $scope): array return []; } + if ( + $node->isFinal() + && !$this->phpVersion->supportsFinalProperties() + ) { + return [ + RuleErrorBuilder::message('Property cannot be final.') + ->nonIgnorable() + ->identifier('property.final') + ->build(), + ]; + } + if (!$this->phpVersion->supportsPropertyHooks()) { if ($node->hasHooks()) { return [ @@ -81,18 +93,6 @@ public function processNode(Node $node, Scope $scope): array ]; } - if ( - $node->isFinal() - && !$this->phpVersion->supportsFinalProperties() - ) { - return [ - RuleErrorBuilder::message('Property cannot be final.') - ->nonIgnorable() - ->identifier('property.final') - ->build(), - ]; - } - if ($node->isPrivate()) { if ($node->isFinal()) { return [ From d1e74f490d2f8cb359e0a3fcb0e7ff0fcca19eaa Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Mon, 24 Feb 2025 11:05:25 +0100 Subject: [PATCH 10/22] Interfaces cannot include final properties --- Makefile | 2 ++ .../Properties/PropertiesInInterfaceRule.php | 9 ++++++ .../PropertiesInInterfaceRuleTest.php | 30 +++++++++++++++++++ .../Properties/PropertyInClassRuleTest.php | 14 +++++++++ .../final-property-hooks-in-interface.php | 12 ++++++++ .../Properties/data/final-property-hooks.php | 28 +++++++++++++++++ .../data/properties-in-interface.php | 2 ++ 7 files changed, 97 insertions(+) create mode 100644 tests/PHPStan/Rules/Properties/data/final-property-hooks-in-interface.php create mode 100644 tests/PHPStan/Rules/Properties/data/final-property-hooks.php diff --git a/Makefile b/Makefile index b558e89fd2..79d9409933 100644 --- a/Makefile +++ b/Makefile @@ -103,6 +103,8 @@ lint: --exclude tests/PHPStan/Rules/Properties/data/overriding-final-property.php \ --exclude tests/PHPStan/Rules/Properties/data/private-final-property-hooks.php \ --exclude tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php \ + --exclude tests/PHPStan/Rules/Properties/data/final-property-hooks-in-interface.php \ + --exclude tests/PHPStan/Rules/Properties/data/final-property-hooks.php \ --exclude tests/PHPStan/Rules/Properties/data/final-properties.php \ src tests diff --git a/src/Rules/Properties/PropertiesInInterfaceRule.php b/src/Rules/Properties/PropertiesInInterfaceRule.php index 3ff9546d35..bde989a2d5 100644 --- a/src/Rules/Properties/PropertiesInInterfaceRule.php +++ b/src/Rules/Properties/PropertiesInInterfaceRule.php @@ -75,6 +75,15 @@ public function processNode(Node $node, Scope $scope): array ]; } + if ($node->isFinal()) { + return [ + RuleErrorBuilder::message('Interfaces cannot include final properties.') + ->nonIgnorable() + ->identifier('property.finalInInterface') + ->build(), + ]; + } + if ($this->hasAnyHookBody($node)) { return [ RuleErrorBuilder::message('Interfaces cannot include property hooks with bodies.') diff --git a/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php b/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php index 3d6dffcb8c..48025901e5 100644 --- a/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php @@ -40,6 +40,10 @@ public function testPhp83AndPropertiesInInterface(): void 'Interfaces cannot include properties.', 11, ], + [ + 'Interfaces cannot include properties.', + 13, + ], ]); } @@ -79,6 +83,10 @@ public function testPhp84AndPropertiesInInterface(): void 'Interfaces can only include hooked properties.', 11, ], + [ + 'Interfaces can only include hooked properties.', + 13, + ], ]); } @@ -140,6 +148,28 @@ public function testPhp84AndReadonlyPropertyHooksInInterface(): void ]); } + public function testPhp84AndFinalPropertyHooksInInterface(): void + { + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.4 or later.'); + } + + $this->analyse([__DIR__ . '/data/final-property-hooks-in-interface.php'], [ + [ + 'Interfaces cannot include final properties.', + 7, + ], + [ + 'Interfaces cannot include final properties.', + 9, + ], + [ + 'Interfaces cannot include final properties.', + 11, + ], + ]); + } + public function testPhp84AndStaticHookedPropertyInInterface(): void { if (PHP_VERSION_ID < 80400) { diff --git a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php index d2fdd388b5..d32eebf25b 100644 --- a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php @@ -281,4 +281,18 @@ public function testBeforePhp84FinalProperties(): void ]); } + public function testPhp84FinalPropertyHooks(): void + { + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.4 or later.'); + } + + $this->analyse([__DIR__ . '/data/final-property-hooks.php'], [ + [ + 'Cannot use the final modifier on an abstract class member on line 19', + 19, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Properties/data/final-property-hooks-in-interface.php b/tests/PHPStan/Rules/Properties/data/final-property-hooks-in-interface.php new file mode 100644 index 0000000000..10c6130507 --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/final-property-hooks-in-interface.php @@ -0,0 +1,12 @@ + $this->firstName; + set => $this->firstName; + } + + public final string $middleName { get => $this->middleName; } + + public final string $lastName { set => $this->lastName; } +} + +abstract class HiWorld +{ + public abstract final string $firstName { get { return 'jake'; } set; } +} + +final class GoodMorningWorld +{ + public string $firstName { + get => $this->firstName; + set => $this->firstName; + } +} diff --git a/tests/PHPStan/Rules/Properties/data/properties-in-interface.php b/tests/PHPStan/Rules/Properties/data/properties-in-interface.php index 3d64511f64..4d104487fb 100644 --- a/tests/PHPStan/Rules/Properties/data/properties-in-interface.php +++ b/tests/PHPStan/Rules/Properties/data/properties-in-interface.php @@ -9,4 +9,6 @@ interface HelloWorld public \DateTimeInterface $dateTime; public static \Closure $callable; + + public final \DateTime $finalProperty; } From 53879a802f51ebdf372a946592b8877c54d1542e Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 25 Feb 2025 14:45:29 +0100 Subject: [PATCH 11/22] abstract final --- src/Rules/Properties/PropertyInClassRule.php | 11 ++++++++++- .../Rules/Properties/PropertyInClassRuleTest.php | 4 ++++ .../Properties/data/abstract-final-property-hook.php | 4 ++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Rules/Properties/PropertyInClassRule.php b/src/Rules/Properties/PropertyInClassRule.php index 9c8dbf5041..a26b100da6 100644 --- a/src/Rules/Properties/PropertyInClassRule.php +++ b/src/Rules/Properties/PropertyInClassRule.php @@ -118,6 +118,15 @@ public function processNode(Node $node, Scope $scope): array } if ($classReflection->isAbstract() && $node->isAbstract()) { + if ($node->isFinal()) { + return [ + RuleErrorBuilder::message('Property cannot be both abstract and final.') + ->nonIgnorable() + ->identifier('property.abstractFinal') + ->build(), + ]; + } + foreach ($node->getHooks() as $hook) { if (!$hook->isFinal()) { continue; @@ -126,7 +135,7 @@ public function processNode(Node $node, Scope $scope): array return [ RuleErrorBuilder::message('Property cannot be both abstract and final.') ->nonIgnorable() - ->identifier('property.finalPrivate') + ->identifier('property.abstractFinal') ->build(), ]; } diff --git a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php index d32eebf25b..6bc8502a18 100644 --- a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php @@ -242,6 +242,10 @@ public function testPhp84AndAbstractFinalHookedProperties(): void 'Property cannot be both abstract and final.', 7, ], + [ + 'Property cannot be both abstract and final.', + 11, + ], ]); } diff --git a/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php b/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php index 380c68eeae..2564b55973 100644 --- a/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php +++ b/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php @@ -7,4 +7,8 @@ abstract class User abstract public string $foo { final get; } + + final abstract public string $bar { + get; + } } From eeea42c08ffaf66eda98a484c91d807c789e4c48 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 26 Feb 2025 10:28:22 +0100 Subject: [PATCH 12/22] better error message --- src/Rules/Properties/PropertyInClassRule.php | 2 +- .../Properties/PropertyInClassRuleTest.php | 21 ++++++++++++++----- ...stract-final-property-hook-parse-error.php | 10 +++++++++ .../data/abstract-final-property-hook.php | 4 ---- 4 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 tests/PHPStan/Rules/Properties/data/abstract-final-property-hook-parse-error.php diff --git a/src/Rules/Properties/PropertyInClassRule.php b/src/Rules/Properties/PropertyInClassRule.php index a26b100da6..a37d36b056 100644 --- a/src/Rules/Properties/PropertyInClassRule.php +++ b/src/Rules/Properties/PropertyInClassRule.php @@ -37,7 +37,7 @@ public function processNode(Node $node, Scope $scope): array && !$this->phpVersion->supportsFinalProperties() ) { return [ - RuleErrorBuilder::message('Property cannot be final.') + RuleErrorBuilder::message('Final Properties are supported only on PHP 8.4 and later.') ->nonIgnorable() ->identifier('property.final') ->build(), diff --git a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php index 6bc8502a18..71973f8013 100644 --- a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php @@ -242,9 +242,20 @@ public function testPhp84AndAbstractFinalHookedProperties(): void 'Property cannot be both abstract and final.', 7, ], + ]); + } + + public function testPhp84AndAbstractFinalHookedPropertiesParseError(): void + { + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.4 or later.'); + } + + // errors when parsing with php-parser, see https://github.com/nikic/PHP-Parser/issues/1071 + $this->analyse([__DIR__ . '/data/abstract-final-property-hook-parse-error.php'], [ [ - 'Property cannot be both abstract and final.', - 11, + 'Cannot use the final modifier on an abstract class member on line 7', + 7, ], ]); } @@ -271,15 +282,15 @@ public function testBeforePhp84FinalProperties(): void $this->analyse([__DIR__ . '/data/final-properties.php'], [ [ - 'Property cannot be final.', + 'Final Properties are supported only on PHP 8.4 and later.', 7, ], [ - 'Property cannot be final.', + 'Final Properties are supported only on PHP 8.4 and later.', 8, ], [ - 'Property cannot be final.', + 'Final Properties are supported only on PHP 8.4 and later.', 9, ], ]); diff --git a/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook-parse-error.php b/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook-parse-error.php new file mode 100644 index 0000000000..230de9d816 --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook-parse-error.php @@ -0,0 +1,10 @@ += 8.4 + +namespace AbstractFinalHookParseError; + +abstract class User +{ + final abstract public string $bar { + get; + } +} diff --git a/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php b/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php index 2564b55973..380c68eeae 100644 --- a/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php +++ b/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php @@ -7,8 +7,4 @@ abstract class User abstract public string $foo { final get; } - - final abstract public string $bar { - get; - } } From 104b317f1bb4e8895bbe3fb1ae39faa49a34cb4f Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 26 Feb 2025 10:30:44 +0100 Subject: [PATCH 13/22] typo --- src/Rules/Properties/PropertyInClassRule.php | 2 +- tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Rules/Properties/PropertyInClassRule.php b/src/Rules/Properties/PropertyInClassRule.php index a37d36b056..b3e920d52d 100644 --- a/src/Rules/Properties/PropertyInClassRule.php +++ b/src/Rules/Properties/PropertyInClassRule.php @@ -37,7 +37,7 @@ public function processNode(Node $node, Scope $scope): array && !$this->phpVersion->supportsFinalProperties() ) { return [ - RuleErrorBuilder::message('Final Properties are supported only on PHP 8.4 and later.') + RuleErrorBuilder::message('Final properties are supported only on PHP 8.4 and later.') ->nonIgnorable() ->identifier('property.final') ->build(), diff --git a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php index 71973f8013..74292336e5 100644 --- a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php @@ -282,15 +282,15 @@ public function testBeforePhp84FinalProperties(): void $this->analyse([__DIR__ . '/data/final-properties.php'], [ [ - 'Final Properties are supported only on PHP 8.4 and later.', + 'Final properties are supported only on PHP 8.4 and later.', 7, ], [ - 'Final Properties are supported only on PHP 8.4 and later.', + 'Final properties are supported only on PHP 8.4 and later.', 8, ], [ - 'Final Properties are supported only on PHP 8.4 and later.', + 'Final properties are supported only on PHP 8.4 and later.', 9, ], ]); From 944f86cf91c2f1549bd36c0c4fd8655cd9bd291e Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 26 Feb 2025 11:44:57 +0100 Subject: [PATCH 14/22] improve error messages --- src/Rules/Properties/PropertiesInInterfaceRule.php | 2 +- src/Rules/Properties/PropertyInClassRule.php | 6 +++--- .../Properties/PropertiesInInterfaceRuleTest.php | 12 ++++++------ .../Rules/Properties/PropertyInClassRuleTest.php | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Rules/Properties/PropertiesInInterfaceRule.php b/src/Rules/Properties/PropertiesInInterfaceRule.php index bde989a2d5..bfbe933851 100644 --- a/src/Rules/Properties/PropertiesInInterfaceRule.php +++ b/src/Rules/Properties/PropertiesInInterfaceRule.php @@ -32,7 +32,7 @@ public function processNode(Node $node, Scope $scope): array if (!$this->phpVersion->supportsPropertyHooks()) { return [ - RuleErrorBuilder::message('Interfaces cannot include properties.') + RuleErrorBuilder::message('Interfaces can include properties only on PHP 8.4 and later.') ->nonIgnorable() ->identifier('property.inInterface') ->build(), diff --git a/src/Rules/Properties/PropertyInClassRule.php b/src/Rules/Properties/PropertyInClassRule.php index b3e920d52d..6e51ab282f 100644 --- a/src/Rules/Properties/PropertyInClassRule.php +++ b/src/Rules/Properties/PropertyInClassRule.php @@ -109,15 +109,15 @@ public function processNode(Node $node, Scope $scope): array } return [ - RuleErrorBuilder::message('Property cannot be both final and private.') + RuleErrorBuilder::message('Private property cannot have a final hook.') ->nonIgnorable() - ->identifier('property.finalPrivate') + ->identifier('property.finalPrivateHook') ->build(), ]; } } - if ($classReflection->isAbstract() && $node->isAbstract()) { + if ($node->isAbstract()) { if ($node->isFinal()) { return [ RuleErrorBuilder::message('Property cannot be both abstract and final.') diff --git a/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php b/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php index 48025901e5..cf774371ac 100644 --- a/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php @@ -29,19 +29,19 @@ public function testPhp83AndPropertiesInInterface(): void $this->analyse([__DIR__ . '/data/properties-in-interface.php'], [ [ - 'Interfaces cannot include properties.', + 'Interfaces can include properties only on PHP 8.4 and later.', 7, ], [ - 'Interfaces cannot include properties.', + 'Interfaces can include properties only on PHP 8.4 and later.', 9, ], [ - 'Interfaces cannot include properties.', + 'Interfaces can include properties only on PHP 8.4 and later.', 11, ], [ - 'Interfaces cannot include properties.', + 'Interfaces can include properties only on PHP 8.4 and later.', 13, ], ]); @@ -58,11 +58,11 @@ public function testPhp83AndPropertyHooksInInterface(): void $this->analyse([__DIR__ . '/data/property-hooks-in-interface.php'], [ [ - 'Interfaces cannot include properties.', + 'Interfaces can include properties only on PHP 8.4 and later.', 7, ], [ - 'Interfaces cannot include properties.', + 'Interfaces can include properties only on PHP 8.4 and later.', 9, ], ]); diff --git a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php index 74292336e5..7be86e2089 100644 --- a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php @@ -225,7 +225,7 @@ public function testPhp84AndPrivateFinalHookedProperties(): void 7, ], [ - 'Property cannot be both final and private.', + 'Private property cannot have a final hook.', 11, ], ]); From d95074f7b9ade30be4bb6491c89ba338d8ca7c0f Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 26 Feb 2025 14:10:25 +0100 Subject: [PATCH 15/22] Property hook cannot be both abstract and final --- src/Rules/Properties/PropertiesInInterfaceRule.php | 13 +++++++++++++ .../Properties/PropertiesInInterfaceRuleTest.php | 8 ++++++++ .../data/final-property-hooks-in-interface.php | 8 ++++++++ 3 files changed, 29 insertions(+) diff --git a/src/Rules/Properties/PropertiesInInterfaceRule.php b/src/Rules/Properties/PropertiesInInterfaceRule.php index bfbe933851..174c441174 100644 --- a/src/Rules/Properties/PropertiesInInterfaceRule.php +++ b/src/Rules/Properties/PropertiesInInterfaceRule.php @@ -84,6 +84,19 @@ public function processNode(Node $node, Scope $scope): array ]; } + foreach ($node->getHooks() as $hook) { + if (!$hook->isFinal()) { + continue; + } + + return [ + RuleErrorBuilder::message('Property hook cannot be both abstract and final.') + ->nonIgnorable() + ->identifier('property.abstractFinal') + ->build(), + ]; + } + if ($this->hasAnyHookBody($node)) { return [ RuleErrorBuilder::message('Interfaces cannot include property hooks with bodies.') diff --git a/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php b/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php index cf774371ac..ff4db00173 100644 --- a/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php @@ -167,6 +167,14 @@ public function testPhp84AndFinalPropertyHooksInInterface(): void 'Interfaces cannot include final properties.', 11, ], + [ + 'Property hook cannot be both abstract and final.', + 13, + ], + [ + 'Property hook cannot be both abstract and final.', + 17, + ], ]); } diff --git a/tests/PHPStan/Rules/Properties/data/final-property-hooks-in-interface.php b/tests/PHPStan/Rules/Properties/data/final-property-hooks-in-interface.php index 10c6130507..946e8b96ef 100644 --- a/tests/PHPStan/Rules/Properties/data/final-property-hooks-in-interface.php +++ b/tests/PHPStan/Rules/Properties/data/final-property-hooks-in-interface.php @@ -9,4 +9,12 @@ interface HelloWorld public final string $middleName { get; } public final string $lastName { set; } + + public string $finalGetHook { + final get; + } + + public string $finalSetHook { + final set; + } } From 39a6eddaa628b6ba5d04d41b77736d26430d39f1 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 26 Feb 2025 14:29:24 +0100 Subject: [PATCH 16/22] allow abstract non-final hooks --- src/Rules/Properties/PropertyInClassRule.php | 4 ++++ .../Rules/Properties/data/abstract-final-property-hook.php | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/Rules/Properties/PropertyInClassRule.php b/src/Rules/Properties/PropertyInClassRule.php index 6e51ab282f..607fa30792 100644 --- a/src/Rules/Properties/PropertyInClassRule.php +++ b/src/Rules/Properties/PropertyInClassRule.php @@ -128,6 +128,10 @@ public function processNode(Node $node, Scope $scope): array } foreach ($node->getHooks() as $hook) { + if ($hook->body !== null) { + continue; + } + if (!$hook->isFinal()) { continue; } diff --git a/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php b/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php index 380c68eeae..baba303bf1 100644 --- a/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php +++ b/tests/PHPStan/Rules/Properties/data/abstract-final-property-hook.php @@ -8,3 +8,8 @@ abstract class User final get; } } + +abstract class Foo +{ + abstract public int $i { final get { return 1;} set; } +} From b1310f7dc339e3d72584c2877e8463b4d205901e Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 26 Feb 2025 14:38:00 +0100 Subject: [PATCH 17/22] Property in interface cannot be explicitly abstract --- .../Properties/PropertiesInInterfaceRule.php | 9 +++++++++ .../Properties/PropertiesInInterfaceRuleTest.php | 14 ++++++++++++++ .../property-in-interface-explicit-abstract.php | 15 +++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 tests/PHPStan/Rules/Properties/data/property-in-interface-explicit-abstract.php diff --git a/src/Rules/Properties/PropertiesInInterfaceRule.php b/src/Rules/Properties/PropertiesInInterfaceRule.php index 174c441174..32442a6694 100644 --- a/src/Rules/Properties/PropertiesInInterfaceRule.php +++ b/src/Rules/Properties/PropertiesInInterfaceRule.php @@ -75,6 +75,15 @@ public function processNode(Node $node, Scope $scope): array ]; } + if ($node->isAbstract()) { + return [ + RuleErrorBuilder::message('Property in interface cannot be explicitly abstract.') + ->nonIgnorable() + ->identifier('property.hookedStatic') + ->build(), + ]; + } + if ($node->isFinal()) { return [ RuleErrorBuilder::message('Interfaces cannot include final properties.') diff --git a/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php b/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php index ff4db00173..5cfb5e7b58 100644 --- a/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php @@ -178,6 +178,20 @@ public function testPhp84AndFinalPropertyHooksInInterface(): void ]); } + public function testPhp84AndExplicitAbstractProperty(): void + { + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.4 or later.'); + } + + $this->analyse([__DIR__ . '/data/property-in-interface-explicit-abstract.php'], [ + [ + 'Property in interface cannot be explicitly abstract.', + 8, + ], + ]); + } + public function testPhp84AndStaticHookedPropertyInInterface(): void { if (PHP_VERSION_ID < 80400) { diff --git a/tests/PHPStan/Rules/Properties/data/property-in-interface-explicit-abstract.php b/tests/PHPStan/Rules/Properties/data/property-in-interface-explicit-abstract.php new file mode 100644 index 0000000000..d91986b659 --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/property-in-interface-explicit-abstract.php @@ -0,0 +1,15 @@ + Date: Wed, 26 Feb 2025 14:42:36 +0100 Subject: [PATCH 18/22] fix lint --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 79d9409933..1122b4ab0f 100644 --- a/Makefile +++ b/Makefile @@ -106,6 +106,7 @@ lint: --exclude tests/PHPStan/Rules/Properties/data/final-property-hooks-in-interface.php \ --exclude tests/PHPStan/Rules/Properties/data/final-property-hooks.php \ --exclude tests/PHPStan/Rules/Properties/data/final-properties.php \ + --exclude tests/PHPStan/Rules/Properties/data/property-in-interface-explicit-abstract.php \ src tests cs: From 12271a3f665011441c8e25088c390e9366a230d2 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 26 Feb 2025 14:50:53 +0100 Subject: [PATCH 19/22] Update PropertiesInInterfaceRule.php --- src/Rules/Properties/PropertiesInInterfaceRule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rules/Properties/PropertiesInInterfaceRule.php b/src/Rules/Properties/PropertiesInInterfaceRule.php index 32442a6694..e40f1068e2 100644 --- a/src/Rules/Properties/PropertiesInInterfaceRule.php +++ b/src/Rules/Properties/PropertiesInInterfaceRule.php @@ -101,7 +101,7 @@ public function processNode(Node $node, Scope $scope): array return [ RuleErrorBuilder::message('Property hook cannot be both abstract and final.') ->nonIgnorable() - ->identifier('property.abstractFinal') + ->identifier('property.hookedAbstractFinal') ->build(), ]; } From 9aed13d4712d6f6e9daf17dc485c2dee49fada3e Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 26 Feb 2025 16:19:34 +0100 Subject: [PATCH 20/22] Update PropertiesInInterfaceRule.php --- src/Rules/Properties/PropertiesInInterfaceRule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rules/Properties/PropertiesInInterfaceRule.php b/src/Rules/Properties/PropertiesInInterfaceRule.php index e40f1068e2..5083c3704a 100644 --- a/src/Rules/Properties/PropertiesInInterfaceRule.php +++ b/src/Rules/Properties/PropertiesInInterfaceRule.php @@ -79,7 +79,7 @@ public function processNode(Node $node, Scope $scope): array return [ RuleErrorBuilder::message('Property in interface cannot be explicitly abstract.') ->nonIgnorable() - ->identifier('property.hookedStatic') + ->identifier('property.hookedAbstract') ->build(), ]; } From 7b7672a72f51d1fe27aa860b9aa80d79fbed1636 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Wed, 26 Feb 2025 16:23:54 +0100 Subject: [PATCH 21/22] Update PropertiesInInterfaceRule.php --- src/Rules/Properties/PropertiesInInterfaceRule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rules/Properties/PropertiesInInterfaceRule.php b/src/Rules/Properties/PropertiesInInterfaceRule.php index 5083c3704a..ba882da6b6 100644 --- a/src/Rules/Properties/PropertiesInInterfaceRule.php +++ b/src/Rules/Properties/PropertiesInInterfaceRule.php @@ -79,7 +79,7 @@ public function processNode(Node $node, Scope $scope): array return [ RuleErrorBuilder::message('Property in interface cannot be explicitly abstract.') ->nonIgnorable() - ->identifier('property.hookedAbstract') + ->identifier('property.abstractInInterface') ->build(), ]; } From 2b2f64b83c07286c5f0606889c44848ebc7918bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Mirtes?= Date: Wed, 26 Feb 2025 16:54:00 +0100 Subject: [PATCH 22/22] Update src/Rules/Properties/PropertiesInInterfaceRule.php --- src/Rules/Properties/PropertiesInInterfaceRule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rules/Properties/PropertiesInInterfaceRule.php b/src/Rules/Properties/PropertiesInInterfaceRule.php index ba882da6b6..6126625da6 100644 --- a/src/Rules/Properties/PropertiesInInterfaceRule.php +++ b/src/Rules/Properties/PropertiesInInterfaceRule.php @@ -101,7 +101,7 @@ public function processNode(Node $node, Scope $scope): array return [ RuleErrorBuilder::message('Property hook cannot be both abstract and final.') ->nonIgnorable() - ->identifier('property.hookedAbstractFinal') + ->identifier('property.abstractFinalHook') ->build(), ]; }