[Nette] Remove AbstractWithFunctionToNetteUtilsStringsRector (#5742)

Co-authored-by: kaizen-ci <info@kaizen-ci.org>
This commit is contained in:
Tomas Votruba 2021-03-03 10:40:03 +01:00 committed by GitHub
parent abdc91606d
commit 92f2c5b3a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 411 additions and 280 deletions

View File

@ -392,6 +392,15 @@ final class NodeNameResolver
return $this->classNaming->getShortName($name);
}
/**
* @param array<string, string> $renameMap
*/
public function matchNameFromMap(Node $node, array $renameMap): ?string
{
$name = $this->getName($node);
return $renameMap[$name] ?? null;
}
private function isCallOrIdentifier(Node $node): bool
{
return StaticInstanceOf::isOneOf($node, [MethodCall::class, StaticCall::class, Identifier::class]);

View File

@ -1,19 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Nette\Contract;
use PhpParser\Node;
use PhpParser\Node\Expr\Variable;
use Rector\Nette\ValueObject\ContentExprAndNeedleExpr;
interface WithFunctionToNetteUtilsStringsRectorInterface
{
public function getMethodName(): string;
public function matchContentAndNeedleOfSubstrOfVariableLength(
Node $node,
Variable $variable
): ?ContentExprAndNeedleExpr;
}

View File

@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace Rector\Nette\NodeAnalyzer;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\BinaryOp\Minus;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\LNumber;
final class PregMatchAllAnalyzer
{
/**
* Compensate enforced flag https://github.com/nette/utils/blob/e3dd1853f56ee9a68bfbb2e011691283c2ed420d/src/Utils/Strings.php#L487
* See https://stackoverflow.com/a/61424319/1348344
*
* @param Arg[] $args
* @return Arg[]
*/
public function compensateEnforcedFlag(string $methodName, FuncCall $funcCall, array $args): array
{
if ($methodName !== 'matchAll') {
return $args;
}
if (count($funcCall->args) !== 3) {
return $args;
}
$constFetch = new ConstFetch(new Name('PREG_SET_ORDER'));
$minus = new Minus($constFetch, new LNumber(1));
$args[] = new Arg($minus);
return $args;
}
}

View File

@ -0,0 +1,79 @@
<?php
declare(strict_types=1);
namespace Rector\Nette\NodeAnalyzer;
use PhpParser\Node;
use PhpParser\Node\Expr\BinaryOp;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\UnaryMinus;
use PhpParser\Node\Expr\Variable;
use Rector\Core\PhpParser\Comparing\NodeComparator;
use Rector\Nette\ValueObject\ContentExprAndNeedleExpr;
use Rector\NodeNameResolver\NodeNameResolver;
final class StrlenEndsWithResolver
{
/**
* @var NodeNameResolver
*/
private $nodeNameResolver;
/**
* @var NodeComparator
*/
private $nodeComparator;
public function __construct(NodeNameResolver $nodeNameResolver, NodeComparator $nodeComparator)
{
$this->nodeNameResolver = $nodeNameResolver;
$this->nodeComparator = $nodeComparator;
}
/**
* @param Identical|NotIdentical $binaryOp
*/
public function resolveBinaryOpForFunction(BinaryOp $binaryOp): ?ContentExprAndNeedleExpr
{
if ($binaryOp->left instanceof Variable) {
return $this->matchContentExprAndNeedleExpr($binaryOp->right, $binaryOp->left);
}
if ($binaryOp->right instanceof Variable) {
return $this->matchContentExprAndNeedleExpr($binaryOp->left, $binaryOp->right);
}
return null;
}
public function matchContentExprAndNeedleExpr(Node $node, Variable $variable): ?ContentExprAndNeedleExpr
{
if (! $this->nodeNameResolver->isFuncCallName($node, 'substr')) {
return null;
}
/** @var FuncCall $node */
if (! $node->args[1]->value instanceof UnaryMinus) {
return null;
}
/** @var UnaryMinus $unaryMinus */
$unaryMinus = $node->args[1]->value;
if (! $this->nodeNameResolver->isFuncCallName($unaryMinus->expr, 'strlen')) {
return null;
}
/** @var FuncCall $strlenFuncCall */
$strlenFuncCall = $unaryMinus->expr;
if ($this->nodeComparator->areNodesEqual($strlenFuncCall->args[0]->value, $variable)) {
return new ContentExprAndNeedleExpr($node->args[0]->value, $strlenFuncCall->args[0]->value);
}
return null;
}
}

View File

@ -0,0 +1,97 @@
<?php
declare(strict_types=1);
namespace Rector\Nette\NodeAnalyzer;
use PhpParser\Node;
use PhpParser\Node\Expr\BinaryOp;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\Variable;
use Rector\Core\PhpParser\Comparing\NodeComparator;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
use Rector\Nette\ValueObject\ContentExprAndNeedleExpr;
use Rector\NodeNameResolver\NodeNameResolver;
final class StrlenStartsWithResolver
{
/**
* @var NodeNameResolver
*/
private $nodeNameResolver;
/**
* @var ValueResolver
*/
private $valueResolver;
/**
* @var NodeComparator
*/
private $nodeComparator;
public function __construct(
NodeNameResolver $nodeNameResolver,
ValueResolver $valueResolver,
NodeComparator $nodeComparator
) {
$this->nodeNameResolver = $nodeNameResolver;
$this->valueResolver = $valueResolver;
$this->nodeComparator = $nodeComparator;
}
/**
* @param Identical|NotIdentical $binaryOp
*/
public function resolveBinaryOpForFunction(BinaryOp $binaryOp, string $functionName): ?ContentExprAndNeedleExpr
{
if ($binaryOp->left instanceof Variable) {
return $this->matchContentExprAndNeedleExpr($binaryOp->right, $binaryOp->left, $functionName);
}
if ($binaryOp->right instanceof Variable) {
return $this->matchContentExprAndNeedleExpr($binaryOp->left, $binaryOp->right, $functionName);
}
return null;
}
private function matchContentExprAndNeedleExpr(
Node $node, Variable $variable, string $functionName
): ?ContentExprAndNeedleExpr {
if (! $node instanceof FuncCall) {
return null;
}
if (! $this->nodeNameResolver->isName($node, $functionName)) {
return null;
}
/** @var FuncCall $node */
if (! $this->valueResolver->isValue($node->args[1]->value, 0)) {
return null;
}
if (! isset($node->args[2])) {
return null;
}
if (! $node->args[2]->value instanceof FuncCall) {
return null;
}
if (! $this->nodeNameResolver->isName($node->args[2]->value, 'strlen')) {
return null;
}
/** @var FuncCall $strlenFuncCall */
$strlenFuncCall = $node->args[2]->value;
if ($this->nodeComparator->areNodesEqual($strlenFuncCall->args[0]->value, $variable)) {
return new ContentExprAndNeedleExpr($node->args[0]->value, $strlenFuncCall->args[0]->value);
}
return null;
}
}

View File

@ -1,69 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Nette\Rector\FuncCall;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\Cast\Bool_;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\Rector\AbstractRector;
use Rector\Nette\Contract\PregToNetteUtilsStringInterface;
/**
* @see https://tomasvotruba.com/blog/2019/02/07/what-i-learned-by-using-thecodingmachine-safe/#is-there-a-better-way
*
* @see \Rector\Nette\Tests\Rector\FuncCall\PregMatchFunctionToNetteUtilsStringsRector\PregMatchFunctionToNetteUtilsStringsRectorTest
*/
abstract class AbstractPregToNetteUtilsStringsRector extends AbstractRector implements PregToNetteUtilsStringInterface
{
/**
* @param FuncCall|Identical $node
*/
public function refactor(Node $node): ?Node
{
if ($node instanceof Identical) {
return $this->refactorIdentical($node);
}
return $this->refactorFuncCall($node);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [FuncCall::class, Identical::class];
}
/**
* @param array<string, string> $functionRenameMap
*/
protected function matchFuncCallRenameToMethod(FuncCall $funcCall, array $functionRenameMap): ?string
{
$oldFunctionNames = array_keys($functionRenameMap);
if (! $this->isNames($funcCall, $oldFunctionNames)) {
return null;
}
$currentFunctionName = $this->getName($funcCall);
return $functionRenameMap[$currentFunctionName];
}
/**
* @param Expr $expr
*/
protected function createBoolCast(?Node $node, Node $expr): Bool_
{
if ($node instanceof Return_ && $expr instanceof Assign) {
$expr = $expr->expr;
}
return new Bool_($expr);
}
}

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Rector\Nette\Rector\FuncCall;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
@ -17,6 +18,8 @@ use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\Rector\AbstractRector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -26,7 +29,7 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
*
* @see \Rector\Nette\Tests\Rector\FuncCall\PregFunctionToNetteUtilsStringsRector\PregFunctionToNetteUtilsStringsRectorTest
*/
final class PregFunctionToNetteUtilsStringsRector extends AbstractPregToNetteUtilsStringsRector
final class PregFunctionToNetteUtilsStringsRector extends AbstractRector
{
/**
* @var array<string, string>
@ -76,6 +79,26 @@ CODE_SAMPLE
]);
}
/**
* @param FuncCall|Identical $node
*/
public function refactor(Node $node): ?Node
{
if ($node instanceof Identical) {
return $this->refactorIdentical($node);
}
return $this->refactorFuncCall($node);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [FuncCall::class, Identical::class];
}
public function refactorIdentical(Identical $identical): ?Bool_
{
$parentNode = $identical->getAttribute(AttributeKey::PARENT_NODE);
@ -102,7 +125,7 @@ CODE_SAMPLE
*/
public function refactorFuncCall(FuncCall $funcCall): ?Expr
{
$methodName = $this->matchFuncCallRenameToMethod($funcCall, self::FUNCTION_NAME_TO_METHOD_NAME);
$methodName = $this->nodeNameResolver->matchNameFromMap($funcCall, self::FUNCTION_NAME_TO_METHOD_NAME);
if ($methodName === null) {
return null;
}
@ -134,6 +157,18 @@ CODE_SAMPLE
return $matchStaticCall;
}
/**
* @param Expr $expr
*/
private function createBoolCast(?Node $node, Node $expr): Bool_
{
if ($node instanceof Return_ && $expr instanceof Assign) {
$expr = $expr->expr;
}
return new Bool_($expr);
}
private function createMatchStaticCall(FuncCall $funcCall, string $methodName): StaticCall
{
$args = [];

View File

@ -4,18 +4,18 @@ declare(strict_types=1);
namespace Rector\Nette\Rector\FuncCall;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\BinaryOp\Minus;
use PhpParser\Node\Expr\Cast\Bool_;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\Rector\AbstractRector;
use Rector\Nette\NodeAnalyzer\PregMatchAllAnalyzer;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -25,7 +25,7 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
*
* @see \Rector\Nette\Tests\Rector\FuncCall\PregMatchFunctionToNetteUtilsStringsRector\PregMatchFunctionToNetteUtilsStringsRectorTest
*/
final class PregMatchFunctionToNetteUtilsStringsRector extends AbstractPregToNetteUtilsStringsRector
final class PregMatchFunctionToNetteUtilsStringsRector extends AbstractRector
{
/**
* @var array<string, string>
@ -35,6 +35,16 @@ final class PregMatchFunctionToNetteUtilsStringsRector extends AbstractPregToNet
'preg_match_all' => 'matchAll',
];
/**
* @var PregMatchAllAnalyzer
*/
private $pregMatchAllAnalyzer;
public function __construct(PregMatchAllAnalyzer $pregMatchAllAnalyzer)
{
$this->pregMatchAllAnalyzer = $pregMatchAllAnalyzer;
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
@ -68,6 +78,26 @@ CODE_SAMPLE
]);
}
/**
* @param FuncCall|Identical $node
*/
public function refactor(Node $node): ?Node
{
if ($node instanceof Identical) {
return $this->refactorIdentical($node);
}
return $this->refactorFuncCall($node);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [FuncCall::class, Identical::class];
}
public function refactorIdentical(Identical $identical): ?Bool_
{
$parentNode = $identical->getAttribute(AttributeKey::PARENT_NODE);
@ -94,7 +124,7 @@ CODE_SAMPLE
*/
public function refactorFuncCall(FuncCall $funcCall): ?Expr
{
$methodName = $this->matchFuncCallRenameToMethod($funcCall, self::FUNCTION_NAME_TO_METHOD_NAME);
$methodName = $this->nodeNameResolver->matchNameFromMap($funcCall, self::FUNCTION_NAME_TO_METHOD_NAME);
if ($methodName === null) {
return null;
}
@ -120,38 +150,25 @@ CODE_SAMPLE
return $matchStaticCall;
}
/**
* @param Expr $expr
*/
private function createBoolCast(?Node $node, Node $expr): Bool_
{
if ($node instanceof Return_ && $expr instanceof Assign) {
$expr = $expr->expr;
}
return new Bool_($expr);
}
private function createMatchStaticCall(FuncCall $funcCall, string $methodName): StaticCall
{
$args = [];
$args[] = $funcCall->args[1];
$args[] = $funcCall->args[0];
$args = $this->compensateMatchAllEnforcedFlag($methodName, $funcCall, $args);
$args = $this->pregMatchAllAnalyzer->compensateEnforcedFlag($methodName, $funcCall, $args);
return $this->nodeFactory->createStaticCall('Nette\Utils\Strings', $methodName, $args);
}
/**
* Compensate enforced flag https://github.com/nette/utils/blob/e3dd1853f56ee9a68bfbb2e011691283c2ed420d/src/Utils/Strings.php#L487
* See https://stackoverflow.com/a/61424319/1348344
*
* @param Arg[] $args
* @return Arg[]
*/
private function compensateMatchAllEnforcedFlag(string $methodName, FuncCall $funcCall, array $args): array
{
if ($methodName !== 'matchAll') {
return $args;
}
if (count($funcCall->args) !== 3) {
return $args;
}
$constFetch = new ConstFetch(new Name('PREG_SET_ORDER'));
$minus = new Minus($constFetch, new LNumber(1));
$args[] = new Arg($minus);
return $args;
}
}

View File

@ -1,64 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Nette\Rector\Identical;
use PhpParser\Node;
use PhpParser\Node\Expr\BinaryOp;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
use PhpParser\Node\Expr\BooleanNot;
use PhpParser\Node\Expr\Variable;
use Rector\Core\Rector\AbstractRector;
use Rector\Nette\Contract\WithFunctionToNetteUtilsStringsRectorInterface;
use Rector\Nette\ValueObject\ContentExprAndNeedleExpr;
abstract class AbstractWithFunctionToNetteUtilsStringsRector extends AbstractRector implements WithFunctionToNetteUtilsStringsRectorInterface
{
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Identical::class, NotIdentical::class];
}
/**
* @param Identical|NotIdentical $node
*/
public function refactor(Node $node): ?Node
{
$contentExprAndNeedleExpr = $this->resolveContentExprAndNeedleExpr($node);
if (! $contentExprAndNeedleExpr instanceof ContentExprAndNeedleExpr) {
return null;
}
$staticCall = $this->nodeFactory->createStaticCall('Nette\Utils\Strings', $this->getMethodName(), [
$contentExprAndNeedleExpr->getContentExpr(),
$contentExprAndNeedleExpr->getNeedleExpr(),
]);
if ($node instanceof NotIdentical) {
return new BooleanNot($staticCall);
}
return $staticCall;
}
/**
* @param Identical|NotIdentical $binaryOp
*/
private function resolveContentExprAndNeedleExpr(BinaryOp $binaryOp): ?ContentExprAndNeedleExpr
{
if ($binaryOp->left instanceof Variable) {
return $this->matchContentAndNeedleOfSubstrOfVariableLength($binaryOp->right, $binaryOp->left);
}
if ($binaryOp->right instanceof Variable) {
return $this->matchContentAndNeedleOfSubstrOfVariableLength($binaryOp->left, $binaryOp->right);
}
return null;
}
}

View File

@ -5,9 +5,11 @@ declare(strict_types=1);
namespace Rector\Nette\Rector\Identical;
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\UnaryMinus;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
use PhpParser\Node\Expr\BooleanNot;
use Rector\Core\Rector\AbstractRector;
use Rector\Nette\NodeAnalyzer\StrlenEndsWithResolver;
use Rector\Nette\ValueObject\ContentExprAndNeedleExpr;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -16,8 +18,26 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
* @see https://github.com/nette/utils/blob/master/src/Utils/Strings.php
* @see \Rector\Nette\Tests\Rector\Identical\EndsWithFunctionToNetteUtilsStringsRector\EndsWithFunctionToNetteUtilsStringsRectorTest
*/
final class EndsWithFunctionToNetteUtilsStringsRector extends AbstractWithFunctionToNetteUtilsStringsRector
final class EndsWithFunctionToNetteUtilsStringsRector extends AbstractRector
{
/**
* @var StrlenEndsWithResolver
*/
private $strlenEndsWithResolver;
public function __construct(StrlenEndsWithResolver $strlenEndsWithResolver)
{
$this->strlenEndsWithResolver = $strlenEndsWithResolver;
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Identical::class, NotIdentical::class];
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
@ -37,13 +57,14 @@ class SomeClass
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
use Nette\Utils\Strings;
class SomeClass
{
public function end($needle)
{
$content = 'Hi, my name is Tom';
$yes = \Nette\Utils\Strings::endsWith($content, $needle);
$yes = Strings::endsWith($content, $needle);
}
}
CODE_SAMPLE
@ -51,38 +72,25 @@ CODE_SAMPLE
]);
}
public function getMethodName(): string
/**
* @param Identical|NotIdentical $node
*/
public function refactor(Node $node): ?Node
{
return 'endsWith';
}
public function matchContentAndNeedleOfSubstrOfVariableLength(
Node $node,
Variable $variable
): ?ContentExprAndNeedleExpr {
if (! $this->nodeNameResolver->isFuncCallName($node, 'substr')) {
$contentExprAndNeedleExpr = $this->strlenEndsWithResolver->resolveBinaryOpForFunction($node);
if (! $contentExprAndNeedleExpr instanceof ContentExprAndNeedleExpr) {
return null;
}
/** @var FuncCall $node */
if (! $node->args[1]->value instanceof UnaryMinus) {
return null;
$staticCall = $this->nodeFactory->createStaticCall('Nette\Utils\Strings', 'endsWith', [
$contentExprAndNeedleExpr->getContentExpr(),
$contentExprAndNeedleExpr->getNeedleExpr(),
]);
if ($node instanceof NotIdentical) {
return new BooleanNot($staticCall);
}
/** @var UnaryMinus $unaryMinus */
$unaryMinus = $node->args[1]->value;
if (! $this->nodeNameResolver->isFuncCallName($unaryMinus->expr, 'strlen')) {
return null;
}
/** @var FuncCall $strlenFuncCall */
$strlenFuncCall = $unaryMinus->expr;
if ($this->nodeComparator->areNodesEqual($strlenFuncCall->args[0]->value, $variable)) {
return new ContentExprAndNeedleExpr($node->args[0]->value, $strlenFuncCall->args[0]->value);
}
return null;
return $staticCall;
}
}

View File

@ -5,8 +5,11 @@ declare(strict_types=1);
namespace Rector\Nette\Rector\Identical;
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Expr\BinaryOp\Identical;
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
use PhpParser\Node\Expr\BooleanNot;
use Rector\Core\Rector\AbstractRector;
use Rector\Nette\NodeAnalyzer\StrlenStartsWithResolver;
use Rector\Nette\ValueObject\ContentExprAndNeedleExpr;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -16,77 +19,77 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
*
* @see \Rector\Nette\Tests\Rector\Identical\StartsWithFunctionToNetteUtilsStringsRector\StartsWithFunctionToNetteUtilsStringsRectorTest
*/
final class StartsWithFunctionToNetteUtilsStringsRector extends AbstractWithFunctionToNetteUtilsStringsRector
final class StartsWithFunctionToNetteUtilsStringsRector extends AbstractRector
{
/**
* @var StrlenStartsWithResolver
*/
private $strlenStartsWithResolver;
public function __construct(StrlenStartsWithResolver $strlenStartsWithResolver)
{
$this->strlenStartsWithResolver = $strlenStartsWithResolver;
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Identical::class, NotIdentical::class];
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Use Nette\Utils\Strings::startsWith() over bare string-functions',
[
new CodeSample(
<<<'CODE_SAMPLE'
return new RuleDefinition('Use Nette\Utils\Strings::startsWith() over bare string-functions', [
new CodeSample(
<<<'CODE_SAMPLE'
class SomeClass
{
public function start($needle)
{
$content = 'Hi, my name is Tom';
$yes = substr($content, 0, strlen($needle)) === $needle;
}
public function start($needle)
{
$content = 'Hi, my name is Tom';
$yes = substr($content, 0, strlen($needle)) === $needle;
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
,
<<<'CODE_SAMPLE'
use Nette\Utils\Strings;
class SomeClass
{
public function start($needle)
{
$content = 'Hi, my name is Tom';
$yes = \Nette\Utils\Strings::startsWith($content, $needle);
}
public function start($needle)
{
$content = 'Hi, my name is Tom';
$yes = Strings::startsWith($content, $needle);
}
}
CODE_SAMPLE
),
]);
]);
}
public function getMethodName(): string
/**
* @param Identical|NotIdentical $node
*/
public function refactor(Node $node): ?Node
{
return 'startsWith';
}
$contentExprAndNeedleExpr = $this->strlenStartsWithResolver->resolveBinaryOpForFunction($node, 'substr');
public function matchContentAndNeedleOfSubstrOfVariableLength(
Node $node,
Variable $variable
): ?ContentExprAndNeedleExpr {
if (! $this->nodeNameResolver->isFuncCallName($node, 'substr')) {
if (! $contentExprAndNeedleExpr instanceof ContentExprAndNeedleExpr) {
return null;
}
/** @var FuncCall $node */
if (! $this->valueResolver->isValue($node->args[1]->value, 0)) {
return null;
$staticCall = $this->nodeFactory->createStaticCall('Nette\Utils\Strings', 'startsWith', [
$contentExprAndNeedleExpr->getContentExpr(),
$contentExprAndNeedleExpr->getNeedleExpr(),
]);
if ($node instanceof NotIdentical) {
return new BooleanNot($staticCall);
}
if (! isset($node->args[2])) {
return null;
}
if (! $node->args[2]->value instanceof FuncCall) {
return null;
}
if (! $this->isName($node->args[2]->value, 'strlen')) {
return null;
}
/** @var FuncCall $strlenFuncCall */
$strlenFuncCall = $node->args[2]->value;
if ($this->nodeComparator->areNodesEqual($strlenFuncCall->args[0]->value, $variable)) {
return new ContentExprAndNeedleExpr($node->args[0]->value, $strlenFuncCall->args[0]->value);
}
return null;
return $staticCall;
}
}

View File

@ -40,9 +40,9 @@ final class AnonymousFunctionFactory
/**
* @param Param[] $params
* @param Stmt[] $stmts
* @param Identifier|Name|NullableType|UnionType|null $node
* @param Identifier|Name|NullableType|UnionType|null $returnTypeNode
*/
public function create(array $params, array $stmts, ?Node $node): Closure
public function create(array $params, array $stmts, ?Node $returnTypeNode): Closure
{
$useVariables = $this->createUseVariablesFromParams($stmts, $params);
@ -53,8 +53,8 @@ final class AnonymousFunctionFactory
$anonymousFunctionNode->uses[] = new ClosureUse($useVariable);
}
if ($node instanceof Node) {
$anonymousFunctionNode->returnType = $node;
if ($returnTypeNode instanceof Node) {
$anonymousFunctionNode->returnType = $returnTypeNode;
}
$anonymousFunctionNode->stmts = $stmts;

View File

@ -6,7 +6,6 @@ namespace Rector\Privatization\Rector\ClassMethod;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Type\ObjectType;

View File

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace Rector\Privatization\Tests\Rector\ClassMethod\PrivatizeLocalOnlyMethodRector;
use Iterator;
use Rector\Privatization\Rector\ClassMethod\PrivatizeLocalOnlyMethodRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;

View File

@ -19,8 +19,6 @@ services:
- Rector\Core\Rector\AbstractTemporaryRector
- Rector\PhpSpecToPHPUnit\Rector\AbstractPhpSpecToPHPUnitRector
# solve later
- Rector\Nette\Rector\FuncCall\AbstractPregToNetteUtilsStringsRector
- Rector\Nette\Rector\Identical\AbstractWithFunctionToNetteUtilsStringsRector
- Rector\TypeDeclaration\Rector\FunctionLike\AbstractTypeDeclarationRector
- Rector\Symfony\Rector\MethodCall\AbstractToConstructorInjectionRector
- Rector\NetteCodeQuality\Rector\ArrayDimFetch\AbstractArrayDimFetchToAnnotatedControlVariableRector