Skip to content

Commit

Permalink
bug #4519 Fix unary operator precedence change (fabpot)
Browse files Browse the repository at this point in the history
This PR was merged into the 3.x branch.

Discussion
----------

Fix unary operator precedence change

Closes #4503

Commits
-------

2cf1939 Fix unary operator precedence change
  • Loading branch information
fabpot committed Dec 28, 2024
2 parents c7be388 + 2cf1939 commit 2e13a83
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 2 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# 3.18.0 (2024-XX-XX)

* Fix unary operator precedence change
* Ignore `SyntaxError` exceptions from undefined handlers when using the `guard` tag
* Add a way to stream template rendering (`TemplateWrapper::stream()` and `TemplateWrapper::streamBlock()` )
* Add a way to stream template rendering (`TemplateWrapper::stream()` and `TemplateWrapper::streamBlock()`)

# 3.17.1 (2024-12-12)

Expand Down
2 changes: 1 addition & 1 deletion src/ExpressionParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,14 @@ private function triggerPrecedenceDeprecations(AbstractExpression $expr): void
return;
}
$target = explode('_', $unaryOp)[1];
$change = $this->unaryOperators[$target]['precedence_change'];
/** @var AbstractExpression $node */
$node = $expr->getNode('node');
foreach ($this->precedenceChanges as $operatorName => $changes) {
if (!\in_array($unaryOp, $changes)) {
continue;
}
if ($node->hasAttribute('operator') && $operatorName === $node->getAttribute('operator')) {
$change = $this->unaryOperators[$target]['precedence_change'];
trigger_deprecation($change->getPackage(), $change->getVersion(), \sprintf('Add explicit parentheses around the "%s" unary operator to avoid behavior change in the next major version as its precedence will change in "%s" at line %d.', $target, $this->parser->getStream()->getSourceContext()->getName(), $node->getTemplateLine()));
}
}
Expand Down
24 changes: 24 additions & 0 deletions tests/ExpressionParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
use Twig\Attribute\FirstClassTwigCallableReady;
use Twig\Compiler;
use Twig\Environment;
use Twig\Error\SyntaxError;
use Twig\Extension\AbstractExtension;
Expand All @@ -24,6 +25,7 @@
use Twig\Node\Expression\FilterExpression;
use Twig\Node\Expression\FunctionExpression;
use Twig\Node\Expression\TestExpression;
use Twig\Node\Expression\Unary\AbstractUnary;
use Twig\Node\Expression\Variable\ContextVariable;
use Twig\Node\Node;
use Twig\Parser;
Expand Down Expand Up @@ -564,6 +566,28 @@ public function testTwoWordTestPrecedence()
$this->expectNotToPerformAssertions();
}

public function testUnaryPrecedenceChange()
{
$env = new Environment(new ArrayLoader(), ['cache' => false, 'autoescape' => false]);
$env->addExtension(new class () extends AbstractExtension {
public function getOperators()
{
$class = new class (new ConstantExpression('foo', 1), 1) extends AbstractUnary {
public function operator(Compiler $compiler): Compiler
{
return $compiler->raw('!');
}
};

return [['!' => ['precedence' => 50, 'class' => $class::class]], []];
}
});
$parser = new Parser($env);

$parser->parse($env->tokenize(new Source('{{ !false ? "OK" : "KO" }}', 'index')));
$this->expectNotToPerformAssertions();
}

private static function createContextVariable(string $name, array $attributes): ContextVariable
{
$expression = new ContextVariable($name, 1);
Expand Down

0 comments on commit 2e13a83

Please sign in to comment.