diff --git a/CHANGELOG b/CHANGELOG index ef31a1c58..39a4b7886 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,3 +7,4 @@ * Change the compilation of `for` loops to throw an exception when a `loop.*` variable is not defined * Make `Environment::getGlobals()` private * Drop support for PHP < 8.2 + * Escape characters are no longer ignored diff --git a/src/Lexer.php b/src/Lexer.php index ff056f99d..b4fde986c 100644 --- a/src/Lexer.php +++ b/src/Lexer.php @@ -428,12 +428,7 @@ class Lexer if (isset(self::SPECIAL_CHARS[$nextChar])) { $result .= self::SPECIAL_CHARS[$nextChar]; - } elseif ('\\' === $nextChar) { - $result .= $nextChar; - } elseif ("'" === $nextChar || '"' === $nextChar) { - if ($nextChar !== $quoteType) { - trigger_deprecation('twig/twig', '3.12', 'Character "%s" at position %d should not be escaped; the "\" character is ignored in Twig v3 but will not be in v4. Please remove the extra "\" character.', $nextChar, $i + 1); - } + } elseif ($nextChar === '\\' || $nextChar === $quoteType) { $result .= $nextChar; } elseif ('#' === $nextChar && $i + 1 < $length && '{' === $str[$i + 1]) { $result .= '#{'; @@ -451,8 +446,7 @@ class Lexer } $result .= \chr(octdec($octal)); } else { - trigger_deprecation('twig/twig', '3.12', 'Character "%s" at position %d should not be escaped; the "\" character is ignored in Twig v3 but will not be in v4. Please remove the extra "\" character.', $nextChar, $i + 1); - $result .= $nextChar; + $result .= '\\'.$nextChar; } ++$i; diff --git a/tests/Fixtures/escape_characters.test b/tests/Fixtures/escape_characters.test new file mode 100644 index 000000000..8f2d3d2c6 --- /dev/null +++ b/tests/Fixtures/escape_characters.test @@ -0,0 +1,14 @@ +--TEST-- +Exception with bad line number +--TEMPLATE-- +{{ 'Foo\Bar' }} +{{ 'Foo\\Bar' }} +{{ 'Foo\\\Bar' }} +{{ 'Foo\\\\Bar' }} +--DATA-- +return [] +--EXPECT-- +Foo\Bar +Foo\Bar +Foo\\Bar +Foo\\Bar diff --git a/tests/Fixtures/functions/enum_cases/invalid_enum_escaping.test b/tests/Fixtures/functions/enum_cases/invalid_enum_escaping.test deleted file mode 100644 index 1d5828fbc..000000000 --- a/tests/Fixtures/functions/enum_cases/invalid_enum_escaping.test +++ /dev/null @@ -1,10 +0,0 @@ ---TEST-- -"enum_cases" function with missing \ escaping ---CONDITION-- -\PHP_VERSION_ID >= 80100 ---TEMPLATE-- -{% for c in enum_cases('Twig\Tests\DummyBackedEnum') %} - {{~ c.name }} -{% endfor %} ---EXCEPTION-- -Twig\Error\SyntaxError: The first argument of the "enum_cases" function must be the name of an enum, "TwigTestsDummyBackedEnum" given in "index.twig" at line 2. diff --git a/tests/Fixtures/functions/enum_cases/valid.test b/tests/Fixtures/functions/enum_cases/valid.test index 011d64786..a4ba3d3a5 100644 --- a/tests/Fixtures/functions/enum_cases/valid.test +++ b/tests/Fixtures/functions/enum_cases/valid.test @@ -6,10 +6,13 @@ {% for c in enum_cases('Twig\\Tests\\DummyBackedEnum') %} {{~ c.name }}: {{ c.value }} {% endfor %} -{% for c in enum_cases('Twig\\Tests\\DummyUnitEnum') %} +{% for c in enum_cases('Twig\Tests\DummyBackedEnum') %} + {{~ c.name }}: {{ c.value }} +{% endfor %} +{% for c in enum_cases('Twig\Tests\DummyUnitEnum') %} {{~ c.name }} {% endfor %} -{% set from_variable='Twig\\Tests\\DummyUnitEnum' %} +{% set from_variable='Twig\Tests\DummyUnitEnum' %} {% for c in enum_cases(from_variable) %} {{~ c.name }} {% endfor %} @@ -18,6 +21,8 @@ return [] --EXPECT-- FOO: foo BAR: bar +FOO: foo +BAR: bar BAR BAZ BAR diff --git a/tests/LexerTest.php b/tests/LexerTest.php index f07a08684..a2a2794a0 100644 --- a/tests/LexerTest.php +++ b/tests/LexerTest.php @@ -12,7 +12,6 @@ namespace Twig\Tests; */ use PHPUnit\Framework\TestCase; -use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; use Twig\Environment; use Twig\Error\SyntaxError; use Twig\Lexer; @@ -22,8 +21,6 @@ use Twig\Token; class LexerTest extends TestCase { - use ExpectDeprecationTrait; - public function testNameLabelForTag() { $template = '{% ยง %}'; @@ -195,6 +192,18 @@ class LexerTest extends TestCase public function getStringWithEscapedDelimiter() { + yield '{{ \'App\Test\' }} => App\Test' => [ + '{{ \'App\\Test\' }}', + 'App\Test', + ]; + yield '{{ "foo \\\' bar" }} => foo \' bar' => [ + '{{ "foo \\\' bar" }}', + "foo \' bar", + ]; + yield '{{ \'foo \" bar\' }} => foo \" bar' => [ + '{{ \'foo \\" bar\' }}', + 'foo \" bar', + ]; yield '{{ \'\x6\' }} => \x6' => [ '{{ \'\x6\' }}', "\x6", @@ -229,43 +238,6 @@ class LexerTest extends TestCase ]; } - /** - * @group legacy - * @dataProvider getStringWithEscapedDelimiterProducingDeprecation - */ - public function testStringWithEscapedDelimiterProducingDeprecation(string $template, string $expected, string $expectedDeprecation) - { - $this->expectDeprecation($expectedDeprecation); - - $lexer = new Lexer(new Environment(new ArrayLoader())); - $stream = $lexer->tokenize(new Source($template, 'index')); - $stream->expect(Token::VAR_START_TYPE); - $stream->expect(Token::STRING_TYPE, $expected); - - // add a dummy assertion here to satisfy PHPUnit, the only thing we want to test is that the code above - // can be executed without throwing any exceptions - $this->addToAssertionCount(1); - } - - public function getStringWithEscapedDelimiterProducingDeprecation() - { - yield '{{ \'App\Test\' }} => AppTest' => [ - '{{ \'App\\Test\' }}', - 'AppTest', - 'Since twig/twig 3.12: Character "T" at position 5 should not be escaped; the "\" character is ignored in Twig v3 but will not be in v4. Please remove the extra "\" character.', - ]; - yield '{{ "foo \\\' bar" }} => foo \' bar' => [ - '{{ "foo \\\' bar" }}', - 'foo \' bar', - 'Since twig/twig 3.12: Character "\'" at position 6 should not be escaped; the "\" character is ignored in Twig v3 but will not be in v4. Please remove the extra "\" character.', - ]; - yield '{{ \'foo \" bar\' }} => foo " bar' => [ - '{{ \'foo \\" bar\' }}', - 'foo " bar', - 'Since twig/twig 3.12: Character """ at position 6 should not be escaped; the "\" character is ignored in Twig v3 but will not be in v4. Please remove the extra "\" character.', - ]; - } - public function testStringWithInterpolation() { $template = 'foo {{ "bar #{ baz + 1 }" }}';