2020-09-15 11:29:25 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
namespace Rector\CodeQuality\Rector\Isset_;
|
|
|
|
|
|
|
|
use PhpParser\Node;
|
|
|
|
use PhpParser\Node\Arg;
|
|
|
|
use PhpParser\Node\Expr;
|
|
|
|
use PhpParser\Node\Expr\BinaryOp\BooleanAnd;
|
|
|
|
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
|
|
|
|
use PhpParser\Node\Expr\Isset_;
|
|
|
|
use PhpParser\Node\Expr\PropertyFetch;
|
|
|
|
use PhpParser\Node\Scalar\String_;
|
2021-02-17 10:51:32 +00:00
|
|
|
use PhpParser\Node\Stmt\Property;
|
|
|
|
use PHPStan\Type\TypeWithClassName;
|
2020-09-15 11:29:25 +00:00
|
|
|
use Rector\Core\Rector\AbstractRector;
|
2020-11-16 17:50:38 +00:00
|
|
|
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
|
|
|
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
2020-09-15 11:29:25 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @see \Rector\CodeQuality\Tests\Rector\Isset_\IssetOnPropertyObjectToPropertyExistsRector\IssetOnPropertyObjectToPropertyExistsRectorTest
|
|
|
|
* @see https://3v4l.org/TI8XL Change isset on property object to property_exists() with not null check
|
|
|
|
*/
|
|
|
|
final class IssetOnPropertyObjectToPropertyExistsRector extends AbstractRector
|
|
|
|
{
|
2020-11-16 17:50:38 +00:00
|
|
|
public function getRuleDefinition(): RuleDefinition
|
2020-09-15 11:29:25 +00:00
|
|
|
{
|
2021-02-17 10:51:32 +00:00
|
|
|
return new RuleDefinition('Change isset on property object to property_exists() and not null check', [
|
|
|
|
new CodeSample(
|
|
|
|
<<<'CODE_SAMPLE'
|
2020-09-15 11:29:25 +00:00
|
|
|
class SomeClass
|
|
|
|
{
|
2021-02-17 10:51:32 +00:00
|
|
|
private $x;
|
2020-09-15 11:29:25 +00:00
|
|
|
|
2021-02-17 10:51:32 +00:00
|
|
|
public function run(): void
|
|
|
|
{
|
|
|
|
isset($this->x);
|
|
|
|
}
|
2020-09-15 11:29:25 +00:00
|
|
|
}
|
|
|
|
CODE_SAMPLE
|
|
|
|
,
|
2021-02-17 10:51:32 +00:00
|
|
|
<<<'CODE_SAMPLE'
|
2020-09-15 11:29:25 +00:00
|
|
|
class SomeClass
|
|
|
|
{
|
2021-02-17 10:51:32 +00:00
|
|
|
private $x;
|
2020-09-15 11:29:25 +00:00
|
|
|
|
2021-02-17 10:51:32 +00:00
|
|
|
public function run(): void
|
|
|
|
{
|
|
|
|
property_exists($this, 'x') && $this->x !== null;
|
|
|
|
}
|
2020-09-15 11:29:25 +00:00
|
|
|
}
|
|
|
|
CODE_SAMPLE
|
|
|
|
),
|
2021-02-17 10:51:32 +00:00
|
|
|
]);
|
2020-09-15 11:29:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string[]
|
|
|
|
*/
|
|
|
|
public function getNodeTypes(): array
|
|
|
|
{
|
|
|
|
return [Isset_::class];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Isset_ $node
|
|
|
|
*/
|
|
|
|
public function refactor(Node $node): ?Node
|
|
|
|
{
|
2020-10-20 10:50:21 +00:00
|
|
|
$newNodes = [];
|
|
|
|
|
2020-09-15 11:29:25 +00:00
|
|
|
foreach ($node->vars as $issetVar) {
|
|
|
|
if (! $issetVar instanceof PropertyFetch) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-02-17 10:51:32 +00:00
|
|
|
$property = $this->nodeRepository->findPropertyByPropertyFetch($issetVar);
|
|
|
|
if ($property instanceof Property && $property->type) {
|
2020-10-20 10:50:21 +00:00
|
|
|
continue;
|
2020-10-18 18:42:49 +00:00
|
|
|
}
|
|
|
|
|
2021-02-17 10:51:32 +00:00
|
|
|
$propertyFetchName = $this->getName($issetVar->name);
|
|
|
|
if ($propertyFetchName === null) {
|
2020-12-22 22:21:12 +00:00
|
|
|
continue;
|
|
|
|
}
|
2020-09-15 11:29:25 +00:00
|
|
|
|
2021-02-17 10:51:32 +00:00
|
|
|
$propertyFetchVarType = $this->getObjectType($issetVar->var);
|
|
|
|
if ($propertyFetchVarType instanceof TypeWithClassName && property_exists(
|
|
|
|
$propertyFetchVarType->getClassName(),
|
|
|
|
$propertyFetchName
|
|
|
|
)) {
|
|
|
|
$newNodes[] = $this->createNotIdenticalToNull($issetVar);
|
|
|
|
continue;
|
2020-10-18 18:42:49 +00:00
|
|
|
}
|
|
|
|
|
2021-02-17 10:51:32 +00:00
|
|
|
$newNodes[] = $this->replaceToPropertyExistsWithNullCheck($issetVar->var, $propertyFetchName, $issetVar);
|
2021-01-05 16:26:39 +00:00
|
|
|
}
|
|
|
|
|
2021-02-17 10:51:32 +00:00
|
|
|
return $this->nodeFactory->createReturnBooleanAnd($newNodes);
|
2021-01-05 16:26:39 +00:00
|
|
|
}
|
|
|
|
|
2020-12-20 12:50:55 +00:00
|
|
|
private function replaceToPropertyExistsWithNullCheck(
|
|
|
|
Expr $expr,
|
|
|
|
string $property,
|
|
|
|
PropertyFetch $propertyFetch
|
|
|
|
): BooleanAnd {
|
2020-10-20 10:50:21 +00:00
|
|
|
$args = [new Arg($expr), new Arg(new String_($property))];
|
2021-02-17 10:51:32 +00:00
|
|
|
$propertyExistsFuncCall = $this->nodeFactory->createFuncCall('property_exists', $args);
|
2020-10-20 10:50:21 +00:00
|
|
|
|
2021-02-17 10:51:32 +00:00
|
|
|
return new BooleanAnd($propertyExistsFuncCall, $this->createNotIdenticalToNull($propertyFetch));
|
2020-09-15 11:29:25 +00:00
|
|
|
}
|
2020-10-18 18:42:49 +00:00
|
|
|
|
2021-02-17 10:51:32 +00:00
|
|
|
private function createNotIdenticalToNull(Expr $expr): NotIdentical
|
2020-10-18 18:42:49 +00:00
|
|
|
{
|
2021-02-17 10:51:32 +00:00
|
|
|
return new NotIdentical($expr, $this->nodeFactory->createNull());
|
2020-10-18 18:42:49 +00:00
|
|
|
}
|
2020-09-15 11:29:25 +00:00
|
|
|
}
|