Skip to content

Instantly share code, notes, and snippets.

@voku
Last active January 30, 2022 23:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save voku/f6a78e6f86de69a3802033ee37b81063 to your computer and use it in GitHub Desktop.
Save voku/f6a78e6f86de69a3802033ee37b81063 to your computer and use it in GitHub Desktop.
<?php
declare(strict_types=1);
namespace vdmg\App\scripts\githooks\StandardVdmg\PHPStan;
use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
final class VdmgNoDuplicateNegativIfConditionRule implements Rule {
public function getNodeType(): string {
return \PhpParser\Node\Stmt::class;
}
/**
* @param \PhpParser\Node\Stmt $node
*
* @return string[] errors
*/
public function processNode(Node $node, Scope $scope): array {
if (
!($node instanceof \PhpParser\Node\Stmt\If_)
&&
!($node instanceof \PhpParser\Node\Stmt\ElseIf_)
) {
return [];
}
// init
$errors = [];
$cond = $node->cond;
if (!property_exists($cond, 'left')) {
return [];
}
if (!property_exists($cond, 'right')) {
return [];
}
$condType = $scope->getType($cond);
if ($condType instanceof \PHPStan\Type\MixedType) {
return [];
}
$leftType = $scope->getType($cond->left);
$rightType = $scope->getType($cond->right);
// DEBUG
//var_dump(get_class($cond));
if (
$cond instanceof \PhpParser\Node\Expr\BinaryOp\BooleanOr
||
$cond instanceof \PhpParser\Node\Expr\BinaryOp\BooleanAnd
) {
// TODO: check also multiple conditions
}
if ($cond instanceof \PhpParser\Node\Expr\BinaryOp\NotEqual) {
// DEBUG
//var_dump(get_class($leftType));
if (
$rightType instanceof \PHPStan\Type\Constant\ConstantStringType
&&
$rightType->getValue() === ''
&&
(
$leftType instanceof \PHPStan\Type\StringType
||
(
$leftType instanceof \PHPStan\Type\UnionType
&&
$leftType->getTypes()[0] instanceof \PHPStan\Type\StringType
&&
$leftType->getTypes()[1] instanceof \PHPStan\Type\NullType
)
)
) {
$errors[] = \PHPStan\Rules\RuleErrorBuilder::message(
'Please do not use duplicate negativ string conditions.'
)->line($cond->getAttribute('startLine'))->build();
}
if (
$rightType instanceof \PHPStan\Type\Constant\ConstantIntegerType
&&
$rightType->getValue() === 0
&&
(
$leftType instanceof \PHPStan\Type\IntegerType
||
(
$leftType instanceof \PHPStan\Type\UnionType
&&
$leftType->getTypes()[0] instanceof \PHPStan\Type\IntegerType
&&
$leftType->getTypes()[1] instanceof \PHPStan\Type\NullType
)
)
) {
$errors[] = \PHPStan\Rules\RuleErrorBuilder::message(
'Please do not use duplicate negativ integer conditions. Use "!==" instead if needed.'
)->line($cond->getAttribute('startLine'))->build();
}
if (
$rightType instanceof \PHPStan\Type\Constant\ConstantBooleanType
&&
$rightType->getValue() === false
&&
(
$leftType instanceof \PHPStan\Type\BooleanType
||
(
$leftType instanceof \PHPStan\Type\UnionType
&&
$leftType->getTypes()[0] instanceof \PHPStan\Type\BooleanType
&&
$leftType->getTypes()[1] instanceof \PHPStan\Type\NullType
)
)
) {
$errors[] = \PHPStan\Rules\RuleErrorBuilder::message(
'Please do not use duplicate negativ boolean conditions.'
)->line($cond->getAttribute('startLine'))->build();
}
if (
$rightType instanceof \PHPStan\Type\ConstantScalarType
&&
$rightType->getValue() === null
&&
(
$leftType instanceof \PHPStan\Type\IntegerType
||
$leftType instanceof \PHPStan\Type\StringType
||
(
$leftType instanceof \PHPStan\Type\UnionType
&&
$leftType->getTypes()[0] instanceof \PHPStan\Type\IntegerType
&&
$leftType->getTypes()[1] instanceof \PHPStan\Type\NullType
)
||
(
$leftType instanceof \PHPStan\Type\UnionType
&&
$leftType->getTypes()[0] instanceof \PHPStan\Type\StringType
&&
$leftType->getTypes()[1] instanceof \PHPStan\Type\NullType
)
)
) {
$errors[] = \PHPStan\Rules\RuleErrorBuilder::message(
'Please do not use duplicate negativ null conditions. Use "!==" instead if needed.'
)->line($cond->getAttribute('startLine'))->build();
}
}
if ($cond instanceof \PhpParser\Node\Expr\BinaryOp\NotIdentical) {
if (
$rightType instanceof \PHPStan\Type\Constant\ConstantStringType
&&
$rightType->getValue() === ''
&&
$leftType instanceof \PHPStan\Type\StringType
) {
$errors[] = \PHPStan\Rules\RuleErrorBuilder::message(
'Please do not use duplicate negativ string conditions.'
)->line($cond->getAttribute('startLine'))->build();
}
if (
$rightType instanceof \PHPStan\Type\Constant\ConstantBooleanType
&&
$rightType->getValue() === false
&&
$leftType instanceof \PHPStan\Type\BooleanType
) {
$errors[] = \PHPStan\Rules\RuleErrorBuilder::message(
'Please do not use duplicate negativ boolean conditions.'
)->line($cond->getAttribute('startLine'))->build();
}
}
return $errors;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment