Merge branch '3.x' into 4.x

* 3.x:
  Add return type annotations on Twig 3 to prepare Twig 4
This commit is contained in:
Fabien Potencier
2025-01-24 11:38:08 +01:00
16 changed files with 135 additions and 3 deletions
+3
View File
@@ -67,6 +67,9 @@ abstract class AbstractTwigCallable implements TwigCallableInterface
return $this->dynamicName;
}
/**
* @return callable|array{class-string, string}|null
*/
public function getCallable()
{
return $this->callable;
+54
View File
@@ -145,6 +145,8 @@ class Environment
/**
* Enables debugging mode.
*
* @return void
*/
public function enableDebug()
{
@@ -154,6 +156,8 @@ class Environment
/**
* Disables debugging mode.
*
* @return void
*/
public function disableDebug()
{
@@ -173,6 +177,8 @@ class Environment
/**
* Enables the auto_reload option.
*
* @return void
*/
public function enableAutoReload()
{
@@ -181,6 +187,8 @@ class Environment
/**
* Disables the auto_reload option.
*
* @return void
*/
public function disableAutoReload()
{
@@ -199,6 +207,8 @@ class Environment
/**
* Enables the strict_variables option.
*
* @return void
*/
public function enableStrictVariables()
{
@@ -208,6 +218,8 @@ class Environment
/**
* Disables the strict_variables option.
*
* @return void
*/
public function disableStrictVariables()
{
@@ -257,6 +269,8 @@ class Environment
* @param CacheInterface|string|false $cache A Twig\Cache\CacheInterface implementation,
* an absolute path to the compiled templates,
* or false to disable cache
*
* @return void
*/
public function setCache($cache)
{
@@ -483,6 +497,9 @@ class Environment
throw new LoaderError(\sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
}
/**
* @return void
*/
public function setLexer(Lexer $lexer)
{
$this->lexer = $lexer;
@@ -500,6 +517,9 @@ class Environment
return $this->lexer->tokenize($source);
}
/**
* @return void
*/
public function setParser(Parser $parser)
{
$this->parser = $parser;
@@ -519,6 +539,9 @@ class Environment
return $this->parser->parse($stream);
}
/**
* @return void
*/
public function setCompiler(Compiler $compiler)
{
$this->compiler = $compiler;
@@ -553,6 +576,9 @@ class Environment
}
}
/**
* @return void
*/
public function setLoader(LoaderInterface $loader)
{
$this->loader = $loader;
@@ -563,6 +589,9 @@ class Environment
return $this->loader;
}
/**
* @return void
*/
public function setCharset(string $charset)
{
if ('UTF8' === $charset = strtoupper($charset ?: '')) {
@@ -583,6 +612,9 @@ class Environment
return $this->extensionSet->hasExtension($class);
}
/**
* @return void
*/
public function addRuntimeLoader(RuntimeLoaderInterface $loader)
{
$this->runtimeLoaders[] = $loader;
@@ -630,6 +662,9 @@ class Environment
throw new RuntimeError(\sprintf('Unable to load the "%s" runtime.', $class));
}
/**
* @return void
*/
public function addExtension(ExtensionInterface $extension)
{
$this->extensionSet->addExtension($extension);
@@ -638,6 +673,8 @@ class Environment
/**
* @param ExtensionInterface[] $extensions An array of extensions
*
* @return void
*/
public function setExtensions(array $extensions)
{
@@ -653,6 +690,9 @@ class Environment
return $this->extensionSet->getExtensions();
}
/**
* @return void
*/
public function addTokenParser(TokenParserInterface $parser)
{
$this->extensionSet->addTokenParser($parser);
@@ -681,6 +721,9 @@ class Environment
$this->extensionSet->registerUndefinedTokenParserCallback($callable);
}
/**
* @return void
*/
public function addNodeVisitor(NodeVisitorInterface $visitor)
{
$this->extensionSet->addNodeVisitor($visitor);
@@ -696,6 +739,9 @@ class Environment
return $this->extensionSet->getNodeVisitors();
}
/**
* @return void
*/
public function addFilter(TwigFilter $filter)
{
$this->extensionSet->addFilter($filter);
@@ -730,6 +776,9 @@ class Environment
return $this->extensionSet->getFilters();
}
/**
* @return void
*/
public function addTest(TwigTest $test)
{
$this->extensionSet->addTest($test);
@@ -753,6 +802,9 @@ class Environment
return $this->extensionSet->getTest($name);
}
/**
* @return void
*/
public function addFunction(TwigFunction $function)
{
$this->extensionSet->addFunction($function);
@@ -794,6 +846,8 @@ class Environment
* but after, you can only update existing globals.
*
* @param mixed $value The global value
*
* @return void
*/
public function addGlobal(string $name, $value)
{
+2
View File
@@ -97,6 +97,8 @@ final class EscaperExtension extends AbstractExtension
/**
* @internal
*
* @return array<string>
*/
public static function escapeFilterIsSafe(Node $filterArgs)
{
+8 -1
View File
@@ -66,7 +66,7 @@ final class SandboxExtension extends AbstractExtension
return $this->sourcePolicy->enableSandbox($source);
}
public function setSecurityPolicy(SecurityPolicyInterface $policy)
public function setSecurityPolicy(SecurityPolicyInterface $policy): void
{
$this->policy = $policy;
}
@@ -111,6 +111,13 @@ final class SandboxExtension extends AbstractExtension
}
}
/**
* @param mixed $obj
*
* @return mixed
*
* @throws SecurityNotAllowedMethodError
*/
public function ensureToStringAllowed($obj, int $lineno = -1, ?Source $source = null)
{
if (\is_array($obj)) {
+3
View File
@@ -66,6 +66,9 @@ final class ExtensionSet
$this->staging = new StagingExtension();
}
/**
* @return void
*/
public function initRuntime()
{
$this->runtimeInitialized = true;
+6
View File
@@ -78,6 +78,9 @@ class IncludeNode extends Node implements NodeOutputInterface
}
}
/**
* @return void
*/
protected function addGetTemplate(Compiler $compiler/* , string $template = '' */)
{
$compiler
@@ -91,6 +94,9 @@ class IncludeNode extends Node implements NodeOutputInterface
;
}
/**
* @return void
*/
protected function addTemplateArguments(Compiler $compiler)
{
if (!$this->hasNode('variables')) {
+3
View File
@@ -139,6 +139,9 @@ abstract class Node implements \Countable, \IteratorAggregate
return \array_key_exists($name, $this->attributes);
}
/**
* @return mixed
*/
public function getAttribute(string $name)
{
if (!\array_key_exists($name, $this->attributes)) {
+9
View File
@@ -230,6 +230,9 @@ class Parser
return new Nodes($rv, $lineno);
}
/**
* @return string|null
*/
public function peekBlockStack()
{
return $this->blockStack[\count($this->blockStack) - 1] ?? null;
@@ -279,6 +282,9 @@ class Parser
$this->importedSymbols[0][$type][$alias] = ['name' => $name, 'node' => $internalRef];
}
/**
* @return array{name: string, node: AssignTemplateVariable|null}|null
*/
public function getImportedSymbol(string $type, string $alias)
{
// if the symbol does not exist in the current scope (0), try in the main/global scope (last index)
@@ -305,6 +311,9 @@ class Parser
return $this->expressionParser;
}
/**
* @return bool
*/
public function hasInheritance()
{
return $this->parent || 0 < \count($this->traits);
+6
View File
@@ -36,6 +36,8 @@ final class EscaperRuntime implements RuntimeExtensionInterface
*
* @param string $strategy The strategy name that should be used as a strategy in the escape call
* @param callable(string $string, string $charset): string $callable A valid PHP callable
*
* @return void
*/
public function setEscaper($strategy, callable $callable)
{
@@ -54,6 +56,8 @@ final class EscaperRuntime implements RuntimeExtensionInterface
/**
* @param array<class-string<\Stringable>, string[]> $safeClasses
*
* @return void
*/
public function setSafeClasses(array $safeClasses = [])
{
@@ -67,6 +71,8 @@ final class EscaperRuntime implements RuntimeExtensionInterface
/**
* @param class-string<\Stringable> $class
* @param string[] $strategies
*
* @return void
*/
public function addSafeClass(string $class, array $strategies)
{
@@ -33,7 +33,7 @@ final class SecurityNotAllowedMethodError extends SecurityError
return $this->className;
}
public function getMethodName()
public function getMethodName(): string
{
return $this->methodName;
}
@@ -33,7 +33,7 @@ final class SecurityNotAllowedPropertyError extends SecurityError
return $this->className;
}
public function getPropertyName()
public function getPropertyName(): string
{
return $this->propertyName;
}
+6
View File
@@ -51,6 +51,9 @@ final class TemplateWrapper
return $this->template->render($context);
}
/**
* @return void
*/
public function display(array $context = [])
{
// using func_get_args() allows to not expose the blocks argument
@@ -76,6 +79,9 @@ final class TemplateWrapper
return $this->template->renderBlock($name, $context + $this->env->getGlobals());
}
/**
* @return void
*/
public function displayBlock(string $name, array $context = [])
{
$context += $this->env->getGlobals();
+10
View File
@@ -76,6 +76,8 @@ abstract class IntegrationTestCase extends TestCase
/**
* @dataProvider getTests
*
* @return void
*/
#[DataProvider('getTests')]
public function testIntegration($file, $message, $condition, $templates, $exception, $outputs, $deprecation = '')
@@ -87,6 +89,8 @@ abstract class IntegrationTestCase extends TestCase
* @dataProvider getLegacyTests
*
* @group legacy
*
* @return void
*/
#[DataProvider('getLegacyTests'), IgnoreDeprecations]
public function testLegacyIntegration($file, $message, $condition, $templates, $exception, $outputs, $deprecation = '')
@@ -150,6 +154,9 @@ abstract class IntegrationTestCase extends TestCase
return self::assembleTests(true);
}
/**
* @return void
*/
protected function doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs, $deprecation = '')
{
if (!$outputs) {
@@ -259,6 +266,9 @@ abstract class IntegrationTestCase extends TestCase
}
}
/**
* @return array<string, string>
*/
protected static function parseTemplates($test)
{
$templates = [];
+16
View File
@@ -22,6 +22,14 @@ abstract class NodeTestCase extends TestCase
{
private Environment $currentEnv;
/**
* @return iterable<array{0: Node, 1: string, 2?: Environment|null, 3?: bool}>
*/
public function getTests()
{
return [];
}
/**
* @return iterable<array{0: Node, 1: string, 2?: Environment|null, 3?: bool}>
*/
@@ -29,6 +37,8 @@ abstract class NodeTestCase extends TestCase
/**
* @dataProvider provideTests
*
* @return void
*/
#[DataProvider('provideTests')]
public function testCompile($node, $source, $environment = null, $isPattern = false)
@@ -36,6 +46,9 @@ abstract class NodeTestCase extends TestCase
$this->assertNodeCompilation($source, $node, $environment, $isPattern);
}
/**
* @return void
*/
public function assertNodeCompilation($source, Node $node, ?Environment $environment = null, $isPattern = false)
{
$compiler = $this->getCompiler($environment);
@@ -48,6 +61,9 @@ abstract class NodeTestCase extends TestCase
}
}
/**
* @return Compiler
*/
protected function getCompiler(?Environment $environment = null)
{
return new Compiler($environment ?? $this->getEnvironment());
+3
View File
@@ -80,6 +80,9 @@ final class Token
return $this->type;
}
/**
* @return mixed
*/
public function getValue()
{
return $this->value;
+4
View File
@@ -12,6 +12,7 @@
namespace Twig\TokenParser;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\IncludeNode;
use Twig\Node\Node;
use Twig\Token;
@@ -36,6 +37,9 @@ class IncludeTokenParser extends AbstractTokenParser
return new IncludeNode($expr, $variables, $only, $ignoreMissing, $token->getLine());
}
/**
* @return array{0: ?AbstractExpression, 1: bool, 2: bool}
*/
protected function parseArguments()
{
$stream = $this->parser->getStream();