From 4f26c0e13754cad265f41f7eb8d0e8af64760570 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 6 Oct 2026 20:09:21 +0700 Subject: [PATCH] [CodingStyle] Handle strings with accented chars on SimplifyQuoteEscapeRector --- .../Fixture/accented_chars.php.inc | 29 ++++++++++++++ .../skip_escaped_multibyte_chars.php.inc | 12 ++++++ .../Fixture/skip_invalid_utf8.php.inc | 11 ++++++ .../String_/SimplifyQuoteEscapeRector.php | 38 ++++++++++++++++++- 4 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 rules-tests/CodingStyle/Rector/String_/SimplifyQuoteEscapeRector/Fixture/accented_chars.php.inc create mode 100644 rules-tests/CodingStyle/Rector/String_/SimplifyQuoteEscapeRector/Fixture/skip_escaped_multibyte_chars.php.inc create mode 100644 rules-tests/CodingStyle/Rector/String_/SimplifyQuoteEscapeRector/Fixture/skip_invalid_utf8.php.inc diff --git a/rules-tests/CodingStyle/Rector/String_/SimplifyQuoteEscapeRector/Fixture/accented_chars.php.inc b/rules-tests/CodingStyle/Rector/String_/SimplifyQuoteEscapeRector/Fixture/accented_chars.php.inc new file mode 100644 index 00000000000..1358251dae6 --- /dev/null +++ b/rules-tests/CodingStyle/Rector/String_/SimplifyQuoteEscapeRector/Fixture/accented_chars.php.inc @@ -0,0 +1,29 @@ + +----- + diff --git a/rules-tests/CodingStyle/Rector/String_/SimplifyQuoteEscapeRector/Fixture/skip_escaped_multibyte_chars.php.inc b/rules-tests/CodingStyle/Rector/String_/SimplifyQuoteEscapeRector/Fixture/skip_escaped_multibyte_chars.php.inc new file mode 100644 index 00000000000..31ad2a10311 --- /dev/null +++ b/rules-tests/CodingStyle/Rector/String_/SimplifyQuoteEscapeRector/Fixture/skip_escaped_multibyte_chars.php.inc @@ -0,0 +1,12 @@ +hasChanged = false; - if (StringUtils::isMatch($node->value, self::HAS_NON_PRINTABLE_CHARS)) { + if ($this->hasNonPrintableChars($node->value)) { return null; } @@ -125,6 +131,11 @@ private function processDoubleQuoted(String_ $string, int $singleQuoteCount, int return; } + // contains escape sequence that will be printed as raw char, e.g. "\u{00A0}" + if ($this->hasEscapeSequence($string)) { + return; + } + $string->setAttribute(AttributeKey::KIND, String_::KIND_SINGLE_QUOTED); // invoke override $string->setAttribute(AttributeKey::ORIGINAL_NODE, null); @@ -137,4 +148,29 @@ private function isMatchEscapedChars(string $string): bool { return StringUtils::isMatch($string, self::ESCAPED_CHAR_REGEX); } + + private function hasEscapeSequence(String_ $string): bool + { + $rawValue = $string->getAttribute(AttributeKey::RAW_VALUE); + if (! is_string($rawValue)) { + return false; + } + + // any escape sequence other than \" makes the written content differ from the value + return str_replace('\\"', '"', substr($rawValue, 1, -1)) !== $string->value; + } + + private function hasNonPrintableChars(string $value): bool + { + if (! StringUtils::isMatch($value, self::HAS_NON_PRINTABLE_CHARS)) { + return false; + } + + if (StringUtils::isMatch($value, self::CONTROL_CHARS_REGEX)) { + return true; + } + + // bytes above ASCII are printable as part of valid UTF-8 text, e.g. "é" + return ! Validators::isUnicode($value); + } }