Skip to content

Commit

Permalink
File::getMethodParameters(): bug fix for attributes leaking into type…
Browse files Browse the repository at this point in the history
… hint

This commit adds handling of parameter attributes to the `File::getMethodParameters()` method as per option [2] discussed in issue 3298.

In practice this means that:
* [New] A new `attributes` index is introduced into the returned array which will hold a boolean value indicating whether attributes are attached to the parameter.
* [Unchanged] The `content` index in the returned array includes the textual representation of any attributes attached to a parameter.
* [Fixed] The `type_hint` and `type_hint_token` indexes will no longer be polluted (set incorrectly) with information belonging to the attribute(s) instead of to the type declaration.

Includes minor efficiency fix for handling of parenthesis and brackets in default values.

Includes dedicated unit test.

Fixes 3298
  • Loading branch information
jrfnl committed Apr 23, 2021
1 parent e4af9dc commit e3b113f
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 3 deletions.
17 changes: 14 additions & 3 deletions src/Files/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -1283,6 +1283,7 @@ public function getDeclarationName($stackPtr)
* 'name' => '$var', // The variable name.
* 'token' => integer, // The stack pointer to the variable name.
* 'content' => string, // The full content of the variable definition.
* 'attributes' => boolean, // Does the parameter have one or more attributes attached ?
* 'pass_by_reference' => boolean, // Is the variable passed by reference?
* 'reference_token' => integer, // The stack pointer to the reference operator
* // or FALSE if the param is not passed by reference.
Expand Down Expand Up @@ -1355,6 +1356,7 @@ public function getMethodParameters($stackPtr)
$defaultStart = null;
$equalToken = null;
$paramCount = 0;
$attributes = false;
$passByReference = false;
$referenceToken = false;
$variableLength = false;
Expand All @@ -1373,18 +1375,25 @@ public function getMethodParameters($stackPtr)
if (isset($this->tokens[$i]['parenthesis_opener']) === true) {
// Don't do this if it's the close parenthesis for the method.
if ($i !== $this->tokens[$i]['parenthesis_closer']) {
$i = ($this->tokens[$i]['parenthesis_closer'] + 1);
$i = $this->tokens[$i]['parenthesis_closer'];
continue;
}
}

if (isset($this->tokens[$i]['bracket_opener']) === true) {
// Don't do this if it's the close parenthesis for the method.
if ($i !== $this->tokens[$i]['bracket_closer']) {
$i = ($this->tokens[$i]['bracket_closer'] + 1);
$i = $this->tokens[$i]['bracket_closer'];
continue;
}
}

switch ($this->tokens[$i]['code']) {
case T_ATTRIBUTE:
$attributes = true;

// Skip to the end of the attribute.
$i = $this->tokens[$i]['attribute_closer'];
break;
case T_BITWISE_AND:
if ($defaultStart === null) {
$passByReference = true;
Expand Down Expand Up @@ -1501,6 +1510,7 @@ public function getMethodParameters($stackPtr)
$vars[$paramCount]['default_equal_token'] = $equalToken;
}

$vars[$paramCount]['attributes'] = $attributes;
$vars[$paramCount]['pass_by_reference'] = $passByReference;
$vars[$paramCount]['reference_token'] = $referenceToken;
$vars[$paramCount]['variable_length'] = $variableLength;
Expand All @@ -1526,6 +1536,7 @@ public function getMethodParameters($stackPtr)
$paramStart = ($i + 1);
$defaultStart = null;
$equalToken = null;
$attributes = false;
$passByReference = false;
$referenceToken = false;
$variableLength = false;
Expand Down
14 changes: 14 additions & 0 deletions tests/Core/File/GetMethodParametersTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,17 @@ function commentsInParams(
// Leading comment.
?MyClass /*-*/ & /*-*/.../*-*/ $param /*-*/ = /*-*/ 'default value' . /*-*/ 'second part' // Trailing comment.
) {}

/* testParameterAttributesInFunctionDeclaration */
class ParametersWithAttributes(
public function __construct(
#[\MyExample\MyAttribute] private string $constructorPropPromTypedParamSingleAttribute,
#[MyAttr([1, 2])]
Type|false
$typedParamSingleAttribute,
#[MyAttribute(1234), MyAttribute(5678)] ?int $nullableTypedParamMultiAttribute,
#[WithoutArgument] #[SingleArgument(0)] $nonTypedParamTwoAttributes,
#[MyAttribute(array("key" => "value"))]
&...$otherParam,
) {}
}
Loading

0 comments on commit e3b113f

Please sign in to comment.