Skip to content

Commit 57acc0a

Browse files
committed
Limit documentation comments to direct declarations
1 parent f6c6828 commit 57acc0a

17 files changed

Lines changed: 50 additions & 282 deletions

‎doc/documentation_comments.rst‎

Lines changed: 14 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ closing marker or the symmetric ``##}`` marker:
4848
Documenting Variable Bindings
4949
-----------------------------
5050

51-
Inside a tag or expression, an inline documentation comment starts with ``##``
52-
and continues until the end of the line. It describes the variable binding that
53-
starts on the next line.
51+
Inside a tag, an inline documentation comment starts with ``##`` and continues
52+
until the end of the line. It describes the variable binding that starts on the
53+
next line.
5454

5555
Type Declarations
5656
~~~~~~~~~~~~~~~~~
@@ -93,28 +93,6 @@ Each target in a multiple assignment can have its own documentation:
9393
= user.first_name, user.last_name
9494
%}
9595
96-
The same syntax works with the assignment operator, including sequence and
97-
object destructuring:
98-
99-
.. code-block:: twig
100-
101-
{{ (## The normalized result.
102-
result = normalize(value)) }}
103-
104-
{{ ([
105-
## The first coordinate.
106-
x,
107-
## The second coordinate.
108-
y,
109-
] = coordinates) }}
110-
111-
{{ ({
112-
name: ## The user's display name.
113-
display_name,
114-
## The user's email address.
115-
email,
116-
} = user) }}
117-
11896
Loop Targets
11997
~~~~~~~~~~~~
12098

@@ -145,32 +123,16 @@ Documentation comments can describe individual macro arguments:
145123
name,
146124
## The initial field value.
147125
value = null,
148-
## Extra HTML attributes.
149-
...attributes,
150126
) %}
151127
...
152128
{% endmacro %}
153129
154-
Arrow Function Arguments
155-
~~~~~~~~~~~~~~~~~~~~~~~~
156-
157-
Documentation comments can also describe arrow function arguments:
158-
159-
.. code-block:: twig
160-
161-
{% set formatter = (
162-
## The value to format.
163-
value,
164-
## The requested locale.
165-
locale
166-
) => value|format(locale) %}
167-
168130
Attachment Rules
169131
----------------
170132

171-
A documentation comment applies to the next supported construct or variable
172-
binding. Consecutive documentation comments are combined and separated by
173-
newlines:
133+
A documentation comment is considered for the construct or variable binding
134+
that immediately follows it and attaches only when that position is supported.
135+
Consecutive documentation comments are combined and separated by newlines:
174136

175137
.. code-block:: twig
176138
@@ -189,9 +151,12 @@ construct or variable must therefore start on a later line:
189151
page = 1
190152
%}
191153
192-
Documentation comments in unsupported positions remain comments and do not
193-
attach metadata. In particular, they do not document ordinary variable reads,
194-
mapping keys, function arguments or named call arguments.
154+
Documentation comments are attached on a best-effort basis where Twig can
155+
associate them directly with a construct or declaration. Comments in other
156+
positions remain regular comments and expose no metadata. In particular, they
157+
do not document ordinary variable reads, mapping keys, function arguments,
158+
named call arguments, assignment operators, destructuring assignments, arrow
159+
function arguments or variadic macro arguments.
195160

196161
Reading Documentation from Nodes
197162
--------------------------------
@@ -207,5 +172,5 @@ metadata is stored on the semantic node represented by the source:
207172
* variable-binding documentation is stored on the node representing its
208173
assignment target.
209174

210-
Documentation is discarded when an optimization or a node visitor replaces a
211-
supported node with an unsupported node.
175+
Documentation metadata belongs to its node and is not preserved when an
176+
optimization or a node visitor replaces that node.

‎src/ExpressionParser.php‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
use Twig\Node\Expression\Variable\AssignContextVariable;
2525
use Twig\Node\Expression\Variable\ContextVariable;
2626
use Twig\Node\Node;
27-
use Twig\Node\NodeDocumentation;
2827
use Twig\Node\Nodes;
2928

3029
/**
@@ -311,9 +310,7 @@ public function parseAssignmentExpression()
311310
} else {
312311
$stream->expect(Token::NAME_TYPE, null, 'Only variables can be assigned to');
313312
}
314-
$target = new AssignContextVariable($token->getValue(), $token->getLine());
315-
NodeDocumentation::set($target, $token);
316-
$targets[] = $target;
313+
$targets[] = new AssignContextVariable($token->getValue(), $token->getLine());
317314

318315
if (!$stream->nextIf(Token::PUNCTUATION_TYPE, ',')) {
319316
break;

‎src/ExpressionParser/Infix/AssignmentExpressionParser.php‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
use Twig\Node\Expression\Binary\SetBinary;
2222
use Twig\Node\Expression\Variable\AssignContextVariable;
2323
use Twig\Node\Expression\Variable\ContextVariable;
24-
use Twig\Node\NodeDocumentation;
2524
use Twig\Parser;
2625
use Twig\Token;
2726

@@ -53,9 +52,7 @@ public function parse(Parser $parser, AbstractExpression $left, Token $token): A
5352
if ($left instanceof ArrayExpression) {
5453
foreach ($left->getKeyValuePairs() as $i => $pair) {
5554
if ($pair['value'] instanceof ContextVariable && !$pair['value'] instanceof AssignContextVariable) {
56-
$target = new AssignContextVariable($pair['value']->getAttribute('name'), $pair['value']->getTemplateLine());
57-
NodeDocumentation::copy($pair['value'], $target);
58-
$left->setNode(2 * $i + 1, $target);
55+
$left->setNode(2 * $i + 1, new AssignContextVariable($pair['value']->getAttribute('name'), $pair['value']->getTemplateLine()));
5956
}
6057
}
6158

‎src/ExpressionParser/Prefix/GroupingExpressionParser.php‎

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
use Twig\Node\Expression\ListExpression;
2020
use Twig\Node\Expression\Variable\AssignContextVariable;
2121
use Twig\Node\Expression\Variable\ContextVariable;
22-
use Twig\Node\NodeDocumentation;
2322
use Twig\Parser;
2423
use Twig\Token;
2524

@@ -38,7 +37,7 @@ public function parse(Parser $parser, Token $token): AbstractExpression
3837
return $expr->setExplicitParentheses();
3938
}
4039

41-
return new ListExpression([$this->toAssignContextVariable($expr)], $token->getLine());
40+
return new ListExpression([self::toAssignContextVariable($expr)], $token->getLine());
4241
}
4342

4443
// determine if we are parsing an arrow function arguments
@@ -53,32 +52,23 @@ public function parse(Parser $parser, Token $token): AbstractExpression
5352
}
5453
$stream->expect(Token::PUNCTUATION_TYPE, ',');
5554
$token = $stream->expect(Token::NAME_TYPE);
56-
$name = new AssignContextVariable($token->getValue(), $token->getLine());
57-
NodeDocumentation::set($name, $token);
58-
$names[] = $name;
55+
$names[] = new ContextVariable($token->getValue(), $token->getLine());
5956
}
6057

6158
if (!$stream->test(Token::OPERATOR_TYPE, '=>')) {
6259
throw new SyntaxError('A list of variables must be followed by an arrow.', $stream->getCurrent()->getLine(), $stream->getSourceContext());
6360
}
6461

65-
return new ListExpression(array_map($this->toAssignContextVariable(...), $names), $token->getLine());
62+
return new ListExpression(array_map(self::toAssignContextVariable(...), $names), $token->getLine());
6663
}
6764

68-
private function toAssignContextVariable(AbstractExpression $expr): AssignContextVariable
65+
private static function toAssignContextVariable(AbstractExpression $expr): AssignContextVariable
6966
{
7067
if (!$expr instanceof ContextVariable) {
7168
throw new SyntaxError('A list must only contain variables.', $expr->getTemplateLine(), $expr->getSourceContext());
7269
}
7370

74-
if ($expr instanceof AssignContextVariable) {
75-
return $expr;
76-
}
77-
78-
$target = new AssignContextVariable($expr->getAttribute('name'), $expr->getTemplateLine());
79-
NodeDocumentation::copy($expr, $target);
80-
81-
return $target;
71+
return $expr instanceof AssignContextVariable ? $expr : new AssignContextVariable($expr->getAttribute('name'), $expr->getTemplateLine());
8272
}
8373

8474
public function getName(): string

‎src/ExpressionParser/Prefix/LiteralExpressionParser.php‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
use Twig\Node\Expression\ConstantExpression;
2323
use Twig\Node\Expression\EmptyExpression;
2424
use Twig\Node\Expression\Variable\ContextVariable;
25-
use Twig\Node\NodeDocumentation;
2625
use Twig\Parser;
2726
use Twig\Token;
2827

@@ -209,7 +208,6 @@ private function parseMappingExpression(Parser $parser)
209208
// {a} is a shortcut for {a:a}
210209
if ($stream->test(Token::PUNCTUATION_TYPE, [',', '}'])) {
211210
$value = new ContextVariable($key->getAttribute('value'), $key->getTemplateLine());
212-
NodeDocumentation::set($value, $token);
213211
$node->addElement($value, $key);
214212
continue;
215213
}

‎src/Node/Expression/ArrowFunctionExpression.php‎

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
use Twig\Node\Expression\Variable\AssignContextVariable;
1717
use Twig\Node\Expression\Variable\ContextVariable;
1818
use Twig\Node\Node;
19-
use Twig\Node\NodeDocumentation;
2019

2120
/**
2221
* Represents an arrow function.
@@ -28,13 +27,7 @@ class ArrowFunctionExpression extends AbstractExpression
2827
public function __construct(AbstractExpression $expr, Node $names, $lineno)
2928
{
3029
if ($names instanceof ContextVariable) {
31-
if (!$names instanceof AssignContextVariable) {
32-
$target = new AssignContextVariable($names->getAttribute('name'), $names->getTemplateLine());
33-
NodeDocumentation::copy($names, $target);
34-
$names = $target;
35-
}
36-
37-
$names = new ListExpression([$names], $lineno);
30+
$names = new ListExpression([new AssignContextVariable($names->getAttribute('name'), $names->getTemplateLine())], $lineno);
3831
}
3932

4033
if (!$names instanceof ListExpression) {

‎src/Node/Expression/Binary/SetBinary.php‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
use Twig\Node\Expression\Variable\AssignContextVariable;
1717
use Twig\Node\Expression\Variable\ContextVariable;
1818
use Twig\Node\Node;
19-
use Twig\Node\NodeDocumentation;
2019

2120
/**
2221
* @author Fabien Potencier <fabien@symfony.com>
@@ -33,11 +32,7 @@ public function __construct(Node $left, Node $right, int $lineno)
3332
if (!\is_string($name)) {
3433
throw new \LogicException('The "name" attribute must be a string.');
3534
}
36-
if (!$left instanceof AssignContextVariable) {
37-
$target = new AssignContextVariable($name, $left->getTemplateLine());
38-
NodeDocumentation::copy($left, $target);
39-
$left = $target;
40-
}
35+
$left = new AssignContextVariable($name, $left->getTemplateLine());
4136

4237
parent::__construct($left, $right, $lineno);
4338
}

‎src/Node/MacroNode.php‎

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class MacroNode extends Node
4242
* @param BodyNode $body
4343
* @param ArrayExpression $arguments
4444
*/
45-
public function __construct(string $name, Node $body, Node $arguments, int $lineno, ?LocalVariable $variadic = null)
45+
public function __construct(string $name, Node $body, Node $arguments, int $lineno, ?string $variadicName = null)
4646
{
4747
if (!$body instanceof BodyNode) {
4848
trigger_deprecation('twig/twig', '3.12', \sprintf('Not passing a "%s" instance as the "body" argument of the "%s" constructor is deprecated ("%s" given).', BodyNode::class, static::class, $body::class));
@@ -58,7 +58,6 @@ public function __construct(string $name, Node $body, Node $arguments, int $line
5858
$arguments = $args;
5959
}
6060

61-
$variadicName = null === $variadic ? null : $this->stripReservedPrefix($variadic->getAttribute('name'));
6261
$seen = [];
6362
foreach ($arguments->getKeyValuePairs() as $pair) {
6463
$argName = $pair['key']->getAttribute('name');
@@ -74,12 +73,7 @@ public function __construct(string $name, Node $body, Node $arguments, int $line
7473
$seen[$argName] = true;
7574
}
7675

77-
$nodes = ['body' => $body, 'arguments' => $arguments];
78-
if (null !== $variadic) {
79-
$nodes['variadic'] = $variadic;
80-
}
81-
82-
parent::__construct($nodes, ['name' => $name], $lineno);
76+
parent::__construct(['body' => $body, 'arguments' => $arguments], ['name' => $name, 'variadic_name' => $variadicName], $lineno);
8377
}
8478

8579
public function compile(Compiler $compiler): void
@@ -99,14 +93,14 @@ public function compileMacroFactory(Compiler $compiler): void
9993
// "...$bucket" parameter and a context entry; a non-variadic macro must NOT emit
10094
// "...$varargs" anymore (so extra arguments raise an error), and the implicit
10195
// "varargs" context entry and VARARGS_NAME handling below go away.
102-
$variadic = $this->hasNode('variadic') ? $this->getNode('variadic') : null;
103-
if (null === $variadic) {
96+
$variadicName = $this->getAttribute('variadic_name');
97+
if (null === $variadicName) {
10498
// Legacy implicit "varargs" bucket: to be removed in 4.0.
10599
$bucketName = self::VARARGS_NAME;
106100
$bucketVar = self::VARARGS_NAME;
107101
} else {
108-
$bucketVar = $variadic->getAttribute('name');
109-
$bucketName = $this->stripReservedPrefix($bucketVar);
102+
$bucketName = $variadicName;
103+
$bucketVar = \in_array($variadicName, TempNameExpression::RESERVED_NAMES, true) ? TempNameExpression::RESERVED_NAME_PREFIX.$variadicName : $variadicName;
110104
}
111105

112106
/** @var ArrayExpression $arguments */
@@ -173,7 +167,7 @@ public function compileMacroFactory(Compiler $compiler): void
173167

174168
$compiler
175169
->repr($signature)
176-
->raw(', '.(null !== $variadic ? 'true' : 'false').')')
170+
->raw(', '.(null !== $variadicName ? 'true' : 'false').')')
177171
;
178172
}
179173

‎src/Node/Node.php‎

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -142,19 +142,11 @@ public function getDocumentation(): ?string
142142
/**
143143
* @internal
144144
*/
145-
public function setDocumentation(string $documentation): void
145+
public function setDocumentation(?string $documentation): void
146146
{
147147
$this->documentation = $documentation;
148148
}
149149

150-
/**
151-
* @internal
152-
*/
153-
public function removeDocumentation(): void
154-
{
155-
$this->documentation = null;
156-
}
157-
158150
/**
159151
* @internal
160152
*/

‎src/Node/NodeDocumentation.php‎

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,11 @@ public static function set(Node $node, Token ...$tokens): void
3535
}
3636
}
3737

38-
public static function copy(Node $source, Node $target): void
39-
{
40-
if (null !== $documentation = $source->getDocumentation()) {
41-
self::prepend($target, $documentation);
42-
}
43-
}
44-
4538
public static function move(Node $source, Node $target): void
4639
{
4740
if (null !== $documentation = $source->getDocumentation()) {
4841
self::prepend($target, $documentation);
49-
$source->removeDocumentation();
42+
$source->setDocumentation(null);
5043
}
5144
}
5245

0 commit comments

Comments
 (0)