From 3f7abf29a82ec0e81386d7d519133f8fe1f278dd Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 20 Sep 2023 19:42:21 +0100 Subject: [PATCH] Added PHPStan rule to flag usages of legacy enum accessors provided by LegacyEnumShimTrait closes #6061 --- phpstan.neon.dist | 1 + .../rules/DeprecatedLegacyEnumAccessRule.php | 78 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 tests/phpstan/rules/DeprecatedLegacyEnumAccessRule.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 581bf41ec..2fde67d6c 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -10,6 +10,7 @@ includes: - vendor/phpstan/phpstan-strict-rules/rules.neon rules: + - pocketmine\phpstan\rules\DeprecatedLegacyEnumAccessRule - pocketmine\phpstan\rules\DisallowEnumComparisonRule - pocketmine\phpstan\rules\DisallowForeachByReferenceRule - pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule diff --git a/tests/phpstan/rules/DeprecatedLegacyEnumAccessRule.php b/tests/phpstan/rules/DeprecatedLegacyEnumAccessRule.php new file mode 100644 index 000000000..2f17e6914 --- /dev/null +++ b/tests/phpstan/rules/DeprecatedLegacyEnumAccessRule.php @@ -0,0 +1,78 @@ + + */ +final class DeprecatedLegacyEnumAccessRule implements Rule{ + + public function getNodeType() : string{ + return StaticCall::class; + } + + public function processNode(Node $node, Scope $scope) : array{ + /** @var StaticCall $node */ + if(!$node->name instanceof Node\Identifier){ + return []; + } + $caseName = $node->name->name; + $classType = $node->class instanceof Node\Name ? + $scope->resolveTypeByName($node->class) : + $scope->getType($node->class); + + if(!$classType instanceof TypeWithClassName){ + return []; + } + + $reflection = $classType->getClassReflection(); + if($reflection === null || !$reflection->hasTraitUse(LegacyEnumShimTrait::class) || !$reflection->implementsInterface(\UnitEnum::class)){ + return []; + } + + if(!$reflection->hasNativeMethod($caseName)){ + return [ + RuleErrorBuilder::message(sprintf( + 'Use of legacy enum case accessor %s::%s().', + $reflection->getName(), + $caseName + ))->tip(sprintf( + 'Access the enum constant directly instead (remove the brackets), e.g. %s::%s', + $reflection->getName(), + $caseName + ))->build() + ]; + } + + return []; + } +}