From ec2a21edb83aaa851184424bfeb2ccf174aec409 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 6 Nov 2022 12:33:32 +0700 Subject: [PATCH 1/6] [Php55] Handle crash on no quote replace on PregReplaceEModifierRector --- .../Fixture/skip_no_quote.php.inc | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 rules-tests/Php55/Rector/FuncCall/PregReplaceEModifierRector/Fixture/skip_no_quote.php.inc diff --git a/rules-tests/Php55/Rector/FuncCall/PregReplaceEModifierRector/Fixture/skip_no_quote.php.inc b/rules-tests/Php55/Rector/FuncCall/PregReplaceEModifierRector/Fixture/skip_no_quote.php.inc new file mode 100644 index 00000000000..d51d9a77bce --- /dev/null +++ b/rules-tests/Php55/Rector/FuncCall/PregReplaceEModifierRector/Fixture/skip_no_quote.php.inc @@ -0,0 +1,11 @@ + Date: Sun, 6 Nov 2022 12:39:48 +0700 Subject: [PATCH 2/6] Fixed :tada: --- rules/Php72/NodeFactory/AnonymousFunctionFactory.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rules/Php72/NodeFactory/AnonymousFunctionFactory.php b/rules/Php72/NodeFactory/AnonymousFunctionFactory.php index 7d927b4ac54..7f8d779b02a 100644 --- a/rules/Php72/NodeFactory/AnonymousFunctionFactory.php +++ b/rules/Php72/NodeFactory/AnonymousFunctionFactory.php @@ -149,6 +149,10 @@ public function createAnonymousFunctionFromExpr(Expr $expr): ?Closure { $stringValue = $this->inlineCodeParser->stringify($expr); + if (! str_contains($stringValue, '"')) { + return null; + } + $phpCode = 'simplePhpParser->parseString($phpCode); From ef9a4fd71388b8b73ccfe1c9cb98279c76f89e79 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 6 Nov 2022 13:10:07 +0700 Subject: [PATCH 3/6] Fix --- ...kip_no_quote.php.inc => skip_no_modifier.php.inc} | 2 +- rules/Php55/RegexMatcher.php | 12 ++++++++++++ rules/Php72/NodeFactory/AnonymousFunctionFactory.php | 4 ---- 3 files changed, 13 insertions(+), 5 deletions(-) rename rules-tests/Php55/Rector/FuncCall/PregReplaceEModifierRector/Fixture/{skip_no_quote.php.inc => skip_no_modifier.php.inc} (90%) diff --git a/rules-tests/Php55/Rector/FuncCall/PregReplaceEModifierRector/Fixture/skip_no_quote.php.inc b/rules-tests/Php55/Rector/FuncCall/PregReplaceEModifierRector/Fixture/skip_no_modifier.php.inc similarity index 90% rename from rules-tests/Php55/Rector/FuncCall/PregReplaceEModifierRector/Fixture/skip_no_quote.php.inc rename to rules-tests/Php55/Rector/FuncCall/PregReplaceEModifierRector/Fixture/skip_no_modifier.php.inc index d51d9a77bce..c298d30f145 100644 --- a/rules-tests/Php55/Rector/FuncCall/PregReplaceEModifierRector/Fixture/skip_no_quote.php.inc +++ b/rules-tests/Php55/Rector/FuncCall/PregReplaceEModifierRector/Fixture/skip_no_modifier.php.inc @@ -2,7 +2,7 @@ namespace Rector\Tests\Php55\Rector\FuncCall\PregReplaceEModifierRector\Fixture; -class SkipNoQuote +class SkipNoModifier { public function run() { diff --git a/rules/Php55/RegexMatcher.php b/rules/Php55/RegexMatcher.php index 8ac77b9aa2c..2bbf5556c80 100644 --- a/rules/Php55/RegexMatcher.php +++ b/rules/Php55/RegexMatcher.php @@ -24,6 +24,12 @@ final class RegexMatcher */ private const LETTER_SUFFIX_REGEX = '#(?\w+)$#'; + /** + * @var string[] + * @see https://www.php.net/manual/en/reference.pcre.pattern.modifiers.php + */ + private const ALL_MODIFIERS = ['i', 'm', 's', 'x', 'e', 'A', 'D', 'S', 'U', 'X', 'J', 'u']; + public function __construct( private readonly ValueResolver $valueResolver ) { @@ -46,6 +52,12 @@ public function resolvePatternExpressionWithoutEIfFound(Expr $expr): Concat|Stri return null; } + for ($i = 0; $i < strlen($modifiers); ++$i) { + if (! in_array($modifiers[$i], self::ALL_MODIFIERS, true)) { + return null; + } + } + $patternWithoutE = $this->createPatternWithoutE($pattern, $delimiter, $modifiers); return new String_($patternWithoutE); } diff --git a/rules/Php72/NodeFactory/AnonymousFunctionFactory.php b/rules/Php72/NodeFactory/AnonymousFunctionFactory.php index 7f8d779b02a..7d927b4ac54 100644 --- a/rules/Php72/NodeFactory/AnonymousFunctionFactory.php +++ b/rules/Php72/NodeFactory/AnonymousFunctionFactory.php @@ -149,10 +149,6 @@ public function createAnonymousFunctionFromExpr(Expr $expr): ?Closure { $stringValue = $this->inlineCodeParser->stringify($expr); - if (! str_contains($stringValue, '"')) { - return null; - } - $phpCode = 'simplePhpParser->parseString($phpCode); From c465360406a2eb0f07c363e7e1f9bb8e85f83405 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 6 Nov 2022 14:57:56 +0700 Subject: [PATCH 4/6] Final touch: clean up --- rules/Php55/RegexMatcher.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rules/Php55/RegexMatcher.php b/rules/Php55/RegexMatcher.php index 2bbf5556c80..7c4a47f2d0d 100644 --- a/rules/Php55/RegexMatcher.php +++ b/rules/Php55/RegexMatcher.php @@ -52,10 +52,8 @@ public function resolvePatternExpressionWithoutEIfFound(Expr $expr): Concat|Stri return null; } - for ($i = 0; $i < strlen($modifiers); ++$i) { - if (! in_array($modifiers[$i], self::ALL_MODIFIERS, true)) { - return null; - } + if (! in_array($pattern[strlen($pattern) - 1], self::ALL_MODIFIERS, true)) { + return null; } $patternWithoutE = $this->createPatternWithoutE($pattern, $delimiter, $modifiers); From f8cb85c5fa39c2e39388a625f2cf4df205b81ba2 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 6 Nov 2022 15:01:39 +0700 Subject: [PATCH 5/6] Final touch: specify ( delimiter ) only for this specific use case --- rules/Php55/RegexMatcher.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/rules/Php55/RegexMatcher.php b/rules/Php55/RegexMatcher.php index 7c4a47f2d0d..c5ae1be75a0 100644 --- a/rules/Php55/RegexMatcher.php +++ b/rules/Php55/RegexMatcher.php @@ -24,12 +24,6 @@ final class RegexMatcher */ private const LETTER_SUFFIX_REGEX = '#(?\w+)$#'; - /** - * @var string[] - * @see https://www.php.net/manual/en/reference.pcre.pattern.modifiers.php - */ - private const ALL_MODIFIERS = ['i', 'm', 's', 'x', 'e', 'A', 'D', 'S', 'U', 'X', 'J', 'u']; - public function __construct( private readonly ValueResolver $valueResolver ) { @@ -52,7 +46,7 @@ public function resolvePatternExpressionWithoutEIfFound(Expr $expr): Concat|Stri return null; } - if (! in_array($pattern[strlen($pattern) - 1], self::ALL_MODIFIERS, true)) { + if ($delimiter === '(' && $pattern[strlen($pattern) - 1] === ')') { return null; } From 78553617ca114cc3bf311e8e7cd9f92c28d4e033 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 7 Nov 2022 06:31:32 +0700 Subject: [PATCH 6/6] handle other brackets --- .../Fixture/skip_no_modifier.php.inc | 5 +++++ rules/Php55/RegexMatcher.php | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/rules-tests/Php55/Rector/FuncCall/PregReplaceEModifierRector/Fixture/skip_no_modifier.php.inc b/rules-tests/Php55/Rector/FuncCall/PregReplaceEModifierRector/Fixture/skip_no_modifier.php.inc index c298d30f145..1b563355680 100644 --- a/rules-tests/Php55/Rector/FuncCall/PregReplaceEModifierRector/Fixture/skip_no_modifier.php.inc +++ b/rules-tests/Php55/Rector/FuncCall/PregReplaceEModifierRector/Fixture/skip_no_modifier.php.inc @@ -8,4 +8,9 @@ class SkipNoModifier { echo preg_replace('([[:upper:]]+)', '_$0', 'FOO'); } + + public function run2() + { + echo preg_replace('{[[:upper:]]+}', '_$0', 'FOO'); + } } diff --git a/rules/Php55/RegexMatcher.php b/rules/Php55/RegexMatcher.php index c5ae1be75a0..81e3d1cad19 100644 --- a/rules/Php55/RegexMatcher.php +++ b/rules/Php55/RegexMatcher.php @@ -46,7 +46,7 @@ public function resolvePatternExpressionWithoutEIfFound(Expr $expr): Concat|Stri return null; } - if ($delimiter === '(' && $pattern[strlen($pattern) - 1] === ')') { + if (in_array($pattern[strlen($pattern) - 1], [')', '}', ']', '>'], true)) { return null; }