phpstan: added a custom rule to disallow strict equality operators on enum members

comparing enums with equality operators is unreliable because there is no guarantee that the enum objects won't be somehow duplicated, through serialization, cloning or ext-parallel dumb object copying. This means that two equal enum objects may not be thw same object.
This commit is contained in:
Dylan K. Taylor 2020-01-08 19:45:05 +00:00
parent e76cc8eb33
commit a733f094ac
3 changed files with 70 additions and 1 deletions

View File

@ -54,7 +54,8 @@
},
"autoload-dev": {
"psr-4": {
"pocketmine\\": "tests/phpunit/"
"pocketmine\\": "tests/phpunit/",
"pocketmine\\phpstan\\rules\\": "tests/phpstan/rules"
}
},
"repositories": [

View File

@ -13,6 +13,7 @@ parameters:
- build/server-phar.php
paths:
- src
- tests/phpstan/rules
- build/server-phar.php
dynamicConstantNames:
- pocketmine\IS_DEVELOPMENT_BUILD

View File

@ -0,0 +1,67 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\phpstan\rules;
use PhpParser\Node;
use PhpParser\Node\Expr\BinaryOp;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\ObjectType;
use PHPStan\Type\VerbosityLevel;
use pocketmine\utils\EnumTrait;
use function sprintf;
class DisallowEnumComparisonRule implements Rule{
public function getNodeType() : string{
return BinaryOp::class;
}
public function processNode(Node $node, Scope $scope) : array{
if(!($node instanceof Identical) and !($node instanceof NotIdentical)){
return [];
}
$result = [];
foreach([$node->left, $node->right] as $n){
$type = $scope->getType($n);
if(!($type instanceof ObjectType)){
continue;
}
$class = $type->getClassReflection();
if($class === null or !$class->hasTraitUse(EnumTrait::class)){
continue;
}
$result[] = RuleErrorBuilder::message(sprintf(
'Strict comparison using %s involving enum %s is not reliable.',
$node instanceof Identical ? '===' : '!==',
$type->describe(VerbosityLevel::value())
))->build();
}
return $result;
}
}