From 51bd3a4416e073497e801767b849588be08a75da Mon Sep 17 00:00:00 2001 From: Guillaume Sainthillier Date: Mon, 12 Oct 2026 12:03:33 +0200 Subject: [PATCH] [Php80] Skip non-zero mb_strpos() offset in MbStrContainsRector --- .../Fixture/offset_equal_strpos.php.inc | 25 ---------------- .../offset_expression_equal_strpos.php.inc | 27 ----------------- .../offset_expression_mb_strpos.php.inc | 27 ----------------- .../offset_negative_equal_strpos.php.inc | 25 ---------------- .../Fixture/offset_negative_strpos.php.inc | 25 ---------------- .../Fixture/offset_strpos.php.inc | 25 ---------------- .../offset_variable_equal_strpos.php.inc | 27 ----------------- .../Fixture/offset_variable_strpos.php.inc | 27 ----------------- .../offset_variable_zero_equal_strpos.php.inc | 2 +- .../offset_variable_zero_strpos.php.inc | 2 +- .../Fixture/skip_offset_equal_strpos.php.inc | 12 ++++++++ ...kip_offset_expression_equal_strpos.php.inc | 13 +++++++++ .../skip_offset_expression_mb_strpos.php.inc | 13 +++++++++ .../skip_offset_loop_mb_strpos.php.inc | 15 ++++++++++ .../skip_offset_negative_equal_strpos.php.inc | 12 ++++++++ .../skip_offset_negative_strpos.php.inc | 12 ++++++++ .../Fixture/skip_offset_strpos.php.inc | 12 ++++++++ .../skip_offset_variable_equal_strpos.php.inc | 13 +++++++++ .../skip_offset_variable_strpos.php.inc | 13 +++++++++ .../NotIdentical/MbStrContainsRector.php | 29 +++++-------------- 20 files changed, 125 insertions(+), 231 deletions(-) delete mode 100644 rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_equal_strpos.php.inc delete mode 100644 rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_expression_equal_strpos.php.inc delete mode 100644 rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_expression_mb_strpos.php.inc delete mode 100644 rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_negative_equal_strpos.php.inc delete mode 100644 rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_negative_strpos.php.inc delete mode 100644 rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_strpos.php.inc delete mode 100644 rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_variable_equal_strpos.php.inc delete mode 100644 rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_variable_strpos.php.inc create mode 100644 rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_equal_strpos.php.inc create mode 100644 rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_expression_equal_strpos.php.inc create mode 100644 rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_expression_mb_strpos.php.inc create mode 100644 rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_loop_mb_strpos.php.inc create mode 100644 rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_negative_equal_strpos.php.inc create mode 100644 rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_negative_strpos.php.inc create mode 100644 rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_strpos.php.inc create mode 100644 rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_variable_equal_strpos.php.inc create mode 100644 rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_variable_strpos.php.inc diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_equal_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_equal_strpos.php.inc deleted file mode 100644 index 7a91da6a599..00000000000 --- a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_equal_strpos.php.inc +++ /dev/null @@ -1,25 +0,0 @@ - ------ - diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_expression_equal_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_expression_equal_strpos.php.inc deleted file mode 100644 index b57186ea9d6..00000000000 --- a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_expression_equal_strpos.php.inc +++ /dev/null @@ -1,27 +0,0 @@ - ------ - diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_expression_mb_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_expression_mb_strpos.php.inc deleted file mode 100644 index 5202f15e2d8..00000000000 --- a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_expression_mb_strpos.php.inc +++ /dev/null @@ -1,27 +0,0 @@ - ------ - diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_negative_equal_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_negative_equal_strpos.php.inc deleted file mode 100644 index 22c0564cbd9..00000000000 --- a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_negative_equal_strpos.php.inc +++ /dev/null @@ -1,25 +0,0 @@ - ------ - diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_negative_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_negative_strpos.php.inc deleted file mode 100644 index 5f928270ad7..00000000000 --- a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_negative_strpos.php.inc +++ /dev/null @@ -1,25 +0,0 @@ - ------ - diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_strpos.php.inc deleted file mode 100644 index 6f2aadf4607..00000000000 --- a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_strpos.php.inc +++ /dev/null @@ -1,25 +0,0 @@ - ------ - diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_variable_equal_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_variable_equal_strpos.php.inc deleted file mode 100644 index defaf7f1515..00000000000 --- a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_variable_equal_strpos.php.inc +++ /dev/null @@ -1,27 +0,0 @@ - ------ - diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_variable_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_variable_strpos.php.inc deleted file mode 100644 index 9b4945425dc..00000000000 --- a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_variable_strpos.php.inc +++ /dev/null @@ -1,27 +0,0 @@ - ------ - diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_variable_zero_equal_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_variable_zero_equal_strpos.php.inc index ff3e1bc7e9c..9fe19d399e2 100644 --- a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_variable_zero_equal_strpos.php.inc +++ b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_variable_zero_equal_strpos.php.inc @@ -21,7 +21,7 @@ class OffsetVariableZeroStrpos public function run() { $offset = 0; - $isMatch = str_contains(mb_substr('abc', $offset), 'a'); + $isMatch = str_contains('abc', 'a'); } } ?> diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_variable_zero_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_variable_zero_strpos.php.inc index c7cac64b729..c9d38cb2ae8 100644 --- a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_variable_zero_strpos.php.inc +++ b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/offset_variable_zero_strpos.php.inc @@ -21,7 +21,7 @@ class OffsetVariableZeroStrpos public function run() { $offset = 0; - $isMatch = str_contains(mb_substr('abc', $offset), 'a'); + $isMatch = str_contains('abc', 'a'); } } ?> diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_equal_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_equal_strpos.php.inc new file mode 100644 index 00000000000..7879af22fe2 --- /dev/null +++ b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_equal_strpos.php.inc @@ -0,0 +1,12 @@ + diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_expression_equal_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_expression_equal_strpos.php.inc new file mode 100644 index 00000000000..7801ba6cf08 --- /dev/null +++ b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_expression_equal_strpos.php.inc @@ -0,0 +1,13 @@ + diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_expression_mb_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_expression_mb_strpos.php.inc new file mode 100644 index 00000000000..fe9b1314e16 --- /dev/null +++ b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_expression_mb_strpos.php.inc @@ -0,0 +1,13 @@ + diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_loop_mb_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_loop_mb_strpos.php.inc new file mode 100644 index 00000000000..0729ab6a409 --- /dev/null +++ b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_loop_mb_strpos.php.inc @@ -0,0 +1,15 @@ + diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_negative_equal_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_negative_equal_strpos.php.inc new file mode 100644 index 00000000000..816dbd1e4a3 --- /dev/null +++ b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_negative_equal_strpos.php.inc @@ -0,0 +1,12 @@ + diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_negative_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_negative_strpos.php.inc new file mode 100644 index 00000000000..e8bb151d346 --- /dev/null +++ b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_negative_strpos.php.inc @@ -0,0 +1,12 @@ + diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_strpos.php.inc new file mode 100644 index 00000000000..18cd0f8b511 --- /dev/null +++ b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_strpos.php.inc @@ -0,0 +1,12 @@ + diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_variable_equal_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_variable_equal_strpos.php.inc new file mode 100644 index 00000000000..df1a723e515 --- /dev/null +++ b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_variable_equal_strpos.php.inc @@ -0,0 +1,13 @@ + diff --git a/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_variable_strpos.php.inc b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_variable_strpos.php.inc new file mode 100644 index 00000000000..b97565dba4e --- /dev/null +++ b/rules-tests/Php80/Rector/NotIdentical/MbStrContainsRector/Fixture/skip_offset_variable_strpos.php.inc @@ -0,0 +1,13 @@ + diff --git a/rules/Php80/Rector/NotIdentical/MbStrContainsRector.php b/rules/Php80/Rector/NotIdentical/MbStrContainsRector.php index d39a825261e..453e6f6c2c5 100644 --- a/rules/Php80/Rector/NotIdentical/MbStrContainsRector.php +++ b/rules/Php80/Rector/NotIdentical/MbStrContainsRector.php @@ -5,8 +5,6 @@ namespace Rector\Php80\Rector\NotIdentical; use PhpParser\Node; -use PhpParser\Node\Arg; -use PhpParser\Node\Expr; use PhpParser\Node\Expr\BinaryOp\Equal; use PhpParser\Node\Expr\BinaryOp\Identical; use PhpParser\Node\Expr\BinaryOp\NotEqual; @@ -14,8 +12,8 @@ use PhpParser\Node\Expr\BooleanNot; use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Name; -use PhpParser\Node\Scalar\Int_; use Rector\Php80\NodeResolver\StrFalseComparisonResolver; +use Rector\PhpParser\Node\Value\ValueResolver; use Rector\Rector\AbstractRector; use Rector\RuleDoc\CodeSample\CodeSample; use Rector\RuleDoc\RuleDefinition; @@ -35,7 +33,8 @@ final class MbStrContainsRector extends AbstractRector implements MinPhpVersionI private const array OLD_STR_NAMES = ['mb_strpos', 'mb_strstr']; public function __construct( - private readonly StrFalseComparisonResolver $strFalseComparisonResolver + private readonly StrFalseComparisonResolver $strFalseComparisonResolver, + private readonly ValueResolver $valueResolver ) { } @@ -97,14 +96,11 @@ public function refactor(Node $node): ?Node return null; } - if (isset($funcCall->getArgs()[2])) { - $secondArg = $funcCall->getArgs()[2]; - - if ($this->isName($funcCall->name, 'mb_strpos') && ! $this->isIntegerZero($secondArg->value)) { - $funcCall->args[0] = new Arg($this->nodeFactory->createFuncCall( - 'mb_substr', - [$funcCall->args[0], $secondArg] - )); + $args = $funcCall->getArgs(); + if (isset($args[2])) { + // str_contains() has no offset, and mb_substr() would copy the haystack on every call + if ($this->isName($funcCall->name, 'mb_strpos') && ! $this->valueResolver->isValue($args[2]->value, 0)) { + return null; } unset($funcCall->args[2]); @@ -123,13 +119,4 @@ public function providePolyfillPackage(): string { return PolyfillPackage::PHP_80; } - - private function isIntegerZero(Expr $expr): bool - { - if (! $expr instanceof Int_) { - return false; - } - - return $expr->value === 0; - } }