handle cases where strlen arg is a Stringable object (#981)

* handle cases where strlen arg is a Stringable object

* handle in processLeftIdentical as well

* fix to use getNativeType

* add test fixtures

* stick on strict comparison by using string cast

* fix return type

* refactor processIdentical

* refactor processEqual

* fix

* separate expr to variable
This commit is contained in:
rajyan 2021-10-12 08:08:52 +09:00 committed by GitHub
parent 65c3a44c63
commit 5f915d861b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 134 additions and 30 deletions

View File

@ -2,9 +2,9 @@
namespace Rector\Tests\CodeQuality\Rector\Identical\StrlenZeroToIdenticalEmptyStringRector\Fixture;
class Fixture
class DefinitelyString
{
public function run($value)
public function run(string $value)
{
$empty = strlen($value) === 0;
@ -18,9 +18,9 @@ class Fixture
namespace Rector\Tests\CodeQuality\Rector\Identical\StrlenZeroToIdenticalEmptyStringRector\Fixture;
class Fixture
class DefinitelyString
{
public function run($value)
public function run(string $value)
{
$empty = $value === '';

View File

@ -0,0 +1,31 @@
<?php
namespace Rector\Tests\CodeQuality\Rector\Identical\StrlenZeroToIdenticalEmptyStringRector\Fixture;
class MightNotBeString
{
public function run($value)
{
$empty = strlen($value) === 0;
$empty = 0 === strlen($value);
}
}
?>
-----
<?php
namespace Rector\Tests\CodeQuality\Rector\Identical\StrlenZeroToIdenticalEmptyStringRector\Fixture;
class MightNotBeString
{
public function run($value)
{
$empty = (string) $value === '';
$empty = (string) $value === '';
}
}
?>

View File

@ -0,0 +1,35 @@
<?php
namespace Rector\Tests\CodeQuality\Rector\Identical\StrlenZeroToIdenticalEmptyStringRector\Fixture;
class NonStringValue
{
public function run()
{
$value = null;
$empty = strlen($value) === 0;
$empty = 0 === strlen($value);
}
}
?>
-----
<?php
namespace Rector\Tests\CodeQuality\Rector\Identical\StrlenZeroToIdenticalEmptyStringRector\Fixture;
class NonStringValue
{
public function run()
{
$value = null;
$empty = (string) $value === '';
$empty = (string) $value === '';
}
}
?>

View File

@ -0,0 +1,51 @@
<?php
namespace Rector\Tests\CodeQuality\Rector\Identical\StrlenZeroToIdenticalEmptyStringRector\Fixture;
class Stringable {
private string $string = '';
public function __toString() : string {
return $this->string;
}
}
class StringableObject
{
public function run()
{
$value = new Stringable();
$empty = strlen($value) === 0;
$empty = 0 === strlen($value);
}
}
?>
-----
<?php
namespace Rector\Tests\CodeQuality\Rector\Identical\StrlenZeroToIdenticalEmptyStringRector\Fixture;
class Stringable {
private string $string = '';
public function __toString() : string {
return $this->string;
}
}
class StringableObject
{
public function run()
{
$value = new Stringable();
$empty = (string) $value === '';
$empty = (string) $value === '';
}
}
?>

View File

@ -11,6 +11,8 @@ use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Scalar\String_;
use Rector\Core\NodeAnalyzer\ArgsAnalyzer;
use PhpParser\Node\Expr\BinaryOp\Equal;
use PHPStan\Type\StringType;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -34,7 +36,7 @@ final class StrlenZeroToIdenticalEmptyStringRector extends AbstractRector
<<<'CODE_SAMPLE'
class SomeClass
{
public function run($value)
public function run(string $value)
{
$empty = strlen($value) === 0;
}
@ -44,7 +46,7 @@ CODE_SAMPLE
<<<'CODE_SAMPLE'
class SomeClass
{
public function run($value)
public function run(string $value)
{
$empty = $value === '';
}
@ -69,23 +71,23 @@ CODE_SAMPLE
public function refactor(Node $node): ?Node
{
if ($node->left instanceof FuncCall) {
return $this->processLeftIdentical($node, $node->left);
return $this->processIdentical($node->right, $node->left);
}
if ($node->right instanceof FuncCall) {
return $this->processRightIdentical($node, $node->right);
return $this->processIdentical($node->left, $node->right);
}
return null;
}
private function processLeftIdentical(Identical $identical, FuncCall $funcCall): ?Identical
private function processIdentical(Expr $value, FuncCall $funcCall): ?Identical
{
if (! $this->isName($funcCall, 'strlen')) {
return null;
}
if (! $this->valueResolver->isValue($identical->right, 0)) {
if (! $this->valueResolver->isValue($value, 0)) {
return null;
}
@ -98,28 +100,13 @@ CODE_SAMPLE
/** @var Expr $variable */
$variable = $firstArg->value;
return new Identical($variable, new String_(''));
}
private function processRightIdentical(Identical $identical, FuncCall $funcCall): ?Identical
{
if (! $this->isName($funcCall, 'strlen')) {
return null;
// Needs string cast if variable type is not string
// see https://github.com/rectorphp/rector/issues/6700
$isStringType = $this->nodeTypeResolver->getNativeType($variable) instanceof StringType;
if (!$isStringType) {
return new Identical(new Expr\Cast\String_($variable), new String_(''));
}
if (! $this->valueResolver->isValue($identical->left, 0)) {
return null;
}
if (! $this->argsAnalyzer->isArgInstanceInArgsPosition($funcCall->args, 0)) {
return null;
}
/** @var Arg $firstArg */
$firstArg = $funcCall->args[0];
/** @var Expr $variable */
$variable = $firstArg->value;
return new Identical($variable, new String_(''));
}
}