From 58d5780ef38fcf087bbad6e7ecae9f43d5b8de27 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 26 Aug 2024 15:04:26 +0200 Subject: [PATCH] Fix two-word tests precedence over one-word tests --- CHANGELOG | 1 + src/ExpressionParser.php | 14 +++++++------- tests/ExpressionParserTest.php | 11 +++++++++++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ee6f4d87a..8d27a072d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ # 3.12.0 (2024-XX-XX) + * Fix precedence of two-word tests when the first word is a valid test * Deprecate the `spaceless` filter * Deprecate some internal methods from `Parser`: `getBlockStack()`, `hasBlock()`, `getBlock()`, `hasMacro()`, `hasTraits()`, `getParent()` * Deprecate passing `null` to `Twig\Parser::setParent()` diff --git a/src/ExpressionParser.php b/src/ExpressionParser.php index 28b556ccc..e6bd3b48c 100644 --- a/src/ExpressionParser.php +++ b/src/ExpressionParser.php @@ -750,15 +750,15 @@ class ExpressionParser $stream = $this->parser->getStream(); $name = $stream->expect(Token::NAME_TYPE)->getValue(); - if (!$test = $this->env->getTest($name)) { - if ($stream->test(Token::NAME_TYPE)) { - // try 2-words tests - $name = $name.' '.$this->parser->getCurrentToken()->getValue(); + if ($stream->test(Token::NAME_TYPE)) { + // try 2-words tests + $name = $name.' '.$this->parser->getCurrentToken()->getValue(); - if ($test = $this->env->getTest($name)) { - $stream->next(); - } + if ($test = $this->env->getTest($name)) { + $stream->next(); } + } else { + $test = $this->env->getTest($name); } if (!$test) { diff --git a/tests/ExpressionParserTest.php b/tests/ExpressionParserTest.php index fe780be33..49e42dcec 100644 --- a/tests/ExpressionParserTest.php +++ b/tests/ExpressionParserTest.php @@ -573,6 +573,17 @@ class ExpressionParserTest extends TestCase $this->doesNotPerformAssertions(); } + public function testTwoWordTestPrecedence() + { + // a "empty element" test must have precedence over "empty" + $env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false]); + $env->addTest(new TwigTest('empty element', 'foo')); + $parser = new Parser($env); + + $parser->parse($env->tokenize(new Source('{{ 1 is empty element }}', 'index'))); + $this->doesNotPerformAssertions(); + } + private function createNameExpression(string $name, array $attributes) { $expression = new NameExpression($name, 1);