2021-01-16 21:45:18 +00:00
|
|
|
<?php
|
|
|
|
|
2021-05-09 20:15:43 +00:00
|
|
|
declare (strict_types=1);
|
2022-06-06 17:12:56 +00:00
|
|
|
namespace Rector\CodeQuality\NodeManipulator;
|
2021-01-16 21:45:18 +00:00
|
|
|
|
2022-06-06 17:12:56 +00:00
|
|
|
use PhpParser\Node\Expr;
|
|
|
|
use PhpParser\Node\Expr\BinaryOp;
|
|
|
|
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
|
|
|
|
use PhpParser\Node\Expr\BooleanNot;
|
|
|
|
use PhpParser\Node\Expr\Cast\Bool_;
|
2023-06-18 14:30:25 +00:00
|
|
|
use PHPStan\Type\Type;
|
|
|
|
use PHPStan\Type\TypeCombinator;
|
2022-06-06 17:12:56 +00:00
|
|
|
use PHPStan\Type\UnionType;
|
|
|
|
use Rector\NodeTypeResolver\NodeTypeResolver;
|
|
|
|
use Rector\NodeTypeResolver\PHPStan\Type\StaticTypeAnalyzer;
|
2024-01-02 02:40:38 +00:00
|
|
|
use Rector\PhpParser\Node\NodeFactory;
|
2022-06-06 17:12:56 +00:00
|
|
|
use Rector\PHPStanStaticTypeMapper\Utils\TypeUnwrapper;
|
2021-01-16 21:45:18 +00:00
|
|
|
final class ExprBoolCaster
|
|
|
|
{
|
|
|
|
/**
|
2023-06-11 23:01:39 +00:00
|
|
|
* @readonly
|
2021-05-10 23:39:21 +00:00
|
|
|
* @var \Rector\NodeTypeResolver\NodeTypeResolver
|
2021-01-16 21:45:18 +00:00
|
|
|
*/
|
|
|
|
private $nodeTypeResolver;
|
|
|
|
/**
|
2023-06-11 23:01:39 +00:00
|
|
|
* @readonly
|
2021-05-10 23:39:21 +00:00
|
|
|
* @var \Rector\PHPStanStaticTypeMapper\Utils\TypeUnwrapper
|
2021-01-16 21:45:18 +00:00
|
|
|
*/
|
|
|
|
private $typeUnwrapper;
|
|
|
|
/**
|
2023-06-11 23:01:39 +00:00
|
|
|
* @readonly
|
2021-05-10 23:39:21 +00:00
|
|
|
* @var \Rector\NodeTypeResolver\PHPStan\Type\StaticTypeAnalyzer
|
2021-01-16 21:45:18 +00:00
|
|
|
*/
|
|
|
|
private $staticTypeAnalyzer;
|
|
|
|
/**
|
2023-06-11 23:01:39 +00:00
|
|
|
* @readonly
|
2024-01-02 02:40:38 +00:00
|
|
|
* @var \Rector\PhpParser\Node\NodeFactory
|
2021-01-16 21:45:18 +00:00
|
|
|
*/
|
|
|
|
private $nodeFactory;
|
2022-06-07 08:22:29 +00:00
|
|
|
public function __construct(NodeTypeResolver $nodeTypeResolver, TypeUnwrapper $typeUnwrapper, StaticTypeAnalyzer $staticTypeAnalyzer, NodeFactory $nodeFactory)
|
2021-05-09 20:15:43 +00:00
|
|
|
{
|
2021-01-16 21:45:18 +00:00
|
|
|
$this->nodeTypeResolver = $nodeTypeResolver;
|
|
|
|
$this->typeUnwrapper = $typeUnwrapper;
|
|
|
|
$this->staticTypeAnalyzer = $staticTypeAnalyzer;
|
|
|
|
$this->nodeFactory = $nodeFactory;
|
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
public function boolCastOrNullCompareIfNeeded(Expr $expr) : Expr
|
2021-01-16 21:45:18 +00:00
|
|
|
{
|
2023-06-18 14:30:25 +00:00
|
|
|
$exprStaticType = $this->nodeTypeResolver->getType($expr);
|
|
|
|
if (!TypeCombinator::containsNull($exprStaticType)) {
|
|
|
|
if (!$this->isBoolCastNeeded($expr, $exprStaticType)) {
|
2021-01-16 21:45:18 +00:00
|
|
|
return $expr;
|
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
return new Bool_($expr);
|
2021-01-16 21:45:18 +00:00
|
|
|
}
|
|
|
|
// if we remove null type, still has to be trueable
|
2022-06-07 08:22:29 +00:00
|
|
|
if ($exprStaticType instanceof UnionType) {
|
2021-01-16 21:45:18 +00:00
|
|
|
$unionTypeWithoutNullType = $this->typeUnwrapper->removeNullTypeFromUnionType($exprStaticType);
|
|
|
|
if ($this->staticTypeAnalyzer->isAlwaysTruableType($unionTypeWithoutNullType)) {
|
2022-06-07 08:22:29 +00:00
|
|
|
return new NotIdentical($expr, $this->nodeFactory->createNull());
|
2021-01-16 21:45:18 +00:00
|
|
|
}
|
|
|
|
} elseif ($this->staticTypeAnalyzer->isAlwaysTruableType($exprStaticType)) {
|
2022-06-07 08:22:29 +00:00
|
|
|
return new NotIdentical($expr, $this->nodeFactory->createNull());
|
2021-01-16 21:45:18 +00:00
|
|
|
}
|
2023-06-18 14:30:25 +00:00
|
|
|
if (!$this->isBoolCastNeeded($expr, $exprStaticType)) {
|
2021-01-16 21:45:18 +00:00
|
|
|
return $expr;
|
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
return new Bool_($expr);
|
2021-01-16 21:45:18 +00:00
|
|
|
}
|
2023-06-18 14:30:25 +00:00
|
|
|
private function isBoolCastNeeded(Expr $expr, Type $exprType) : bool
|
2021-01-16 21:45:18 +00:00
|
|
|
{
|
2022-06-07 08:22:29 +00:00
|
|
|
if ($expr instanceof BooleanNot) {
|
2021-05-09 20:15:43 +00:00
|
|
|
return \false;
|
2021-01-16 21:45:18 +00:00
|
|
|
}
|
2023-04-08 16:37:58 +00:00
|
|
|
if ($exprType->isBoolean()->yes()) {
|
2021-05-09 20:15:43 +00:00
|
|
|
return \false;
|
2021-01-16 21:45:18 +00:00
|
|
|
}
|
2022-06-07 08:22:29 +00:00
|
|
|
return !$expr instanceof BinaryOp;
|
2021-01-16 21:45:18 +00:00
|
|
|
}
|
|
|
|
}
|