Skip to content

Commit

Permalink
Merge branch 'feature/file-getmethodparams-add-support-for-readonly' of
Browse files Browse the repository at this point in the history
  • Loading branch information
gsherwood committed Jan 17, 2022
2 parents 0379bba + ca68016 commit e6221c7
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 0 deletions.
15 changes: 15 additions & 0 deletions src/Files/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -1310,6 +1310,8 @@ public function getDeclarationName($stackPtr)
* Parameters declared using PHP 8 constructor property promotion, have these additional array indexes:
* 'property_visibility' => string, // The property visibility as declared.
* 'visibility_token' => integer, // The stack pointer to the visibility modifier token.
* 'property_readonly' => bool, // TRUE if the readonly keyword was found.
* 'readonly_token' => integer, // The stack pointer to the readonly modifier token.
*
* @param int $stackPtr The position in the stack of the function token
* to acquire the parameters for.
Expand Down Expand Up @@ -1366,6 +1368,7 @@ public function getMethodParameters($stackPtr)
$typeHintEndToken = false;
$nullableType = false;
$visibilityToken = null;
$readonlyToken = null;

for ($i = $paramStart; $i <= $closer; $i++) {
// Check to see if this token has a parenthesis or bracket opener. If it does
Expand Down Expand Up @@ -1491,6 +1494,11 @@ public function getMethodParameters($stackPtr)
$visibilityToken = $i;
}
break;
case T_READONLY:
if ($defaultStart === null) {
$readonlyToken = $i;
}
break;
case T_CLOSE_PARENTHESIS:
case T_COMMA:
// If it's null, then there must be no parameters for this
Expand Down Expand Up @@ -1523,6 +1531,12 @@ public function getMethodParameters($stackPtr)
if ($visibilityToken !== null) {
$vars[$paramCount]['property_visibility'] = $this->tokens[$visibilityToken]['content'];
$vars[$paramCount]['visibility_token'] = $visibilityToken;
$vars[$paramCount]['property_readonly'] = false;
}

if ($readonlyToken !== null) {
$vars[$paramCount]['property_readonly'] = true;
$vars[$paramCount]['readonly_token'] = $readonlyToken;
}

if ($this->tokens[$i]['code'] === T_COMMA) {
Expand All @@ -1546,6 +1560,7 @@ public function getMethodParameters($stackPtr)
$typeHintEndToken = false;
$nullableType = false;
$visibilityToken = null;
$readonlyToken = null;

$paramCount++;
break;
Expand Down
5 changes: 5 additions & 0 deletions tests/Core/File/GetMethodParametersTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ class ConstructorPropertyPromotionAndNormalParams {
public function __construct(public int $promotedProp, ?int $normalArg) {}
}

class ConstructorPropertyPromotionWithReadOnly {
/* testPHP81ConstructorPropertyPromotionWithReadOnly */
public function __construct(public readonly ?int $promotedProp, readonly private string|bool &$promotedToo) {}
}

/* testPHP8ConstructorPropertyPromotionGlobalFunction */
// Intentional fatal error. Property promotion not allowed in non-constructor, but that's not the concern of this method.
function globalFunction(private $x) {}
Expand Down
43 changes: 43 additions & 0 deletions tests/Core/File/GetMethodParametersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,7 @@ public function testPHP8ConstructorPropertyPromotionNoTypes()
'type_hint' => '',
'nullable_type' => false,
'property_visibility' => 'public',
'property_readonly' => false,
];
$expected[1] = [
'name' => '$y',
Expand All @@ -707,6 +708,7 @@ public function testPHP8ConstructorPropertyPromotionNoTypes()
'type_hint' => '',
'nullable_type' => false,
'property_visibility' => 'protected',
'property_readonly' => false,
];
$expected[2] = [
'name' => '$z',
Expand All @@ -718,6 +720,7 @@ public function testPHP8ConstructorPropertyPromotionNoTypes()
'type_hint' => '',
'nullable_type' => false,
'property_visibility' => 'private',
'property_readonly' => false,
];

$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
Expand All @@ -742,6 +745,7 @@ public function testPHP8ConstructorPropertyPromotionWithTypes()
'type_hint' => 'float|int',
'nullable_type' => false,
'property_visibility' => 'protected',
'property_readonly' => false,
];
$expected[1] = [
'name' => '$y',
Expand All @@ -753,6 +757,7 @@ public function testPHP8ConstructorPropertyPromotionWithTypes()
'type_hint' => '?string',
'nullable_type' => true,
'property_visibility' => 'public',
'property_readonly' => false,
];
$expected[2] = [
'name' => '$z',
Expand All @@ -763,6 +768,7 @@ public function testPHP8ConstructorPropertyPromotionWithTypes()
'type_hint' => 'mixed',
'nullable_type' => false,
'property_visibility' => 'private',
'property_readonly' => false,
];

$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
Expand All @@ -787,6 +793,7 @@ public function testPHP8ConstructorPropertyPromotionAndNormalParam()
'type_hint' => 'int',
'nullable_type' => false,
'property_visibility' => 'public',
'property_readonly' => false,
];
$expected[1] = [
'name' => '$normalArg',
Expand All @@ -803,6 +810,42 @@ public function testPHP8ConstructorPropertyPromotionAndNormalParam()
}//end testPHP8ConstructorPropertyPromotionAndNormalParam()


/**
* Verify recognition of PHP8 constructor with property promotion using PHP 8.1 readonly keyword.
*
* @return void
*/
public function testPHP81ConstructorPropertyPromotionWithReadOnly()
{
$expected = [];
$expected[0] = [
'name' => '$promotedProp',
'content' => 'public readonly ?int $promotedProp',
'has_attributes' => false,
'pass_by_reference' => false,
'variable_length' => false,
'type_hint' => '?int',
'nullable_type' => true,
'property_visibility' => 'public',
'property_readonly' => true,
];
$expected[1] = [
'name' => '$promotedToo',
'content' => 'readonly private string|bool &$promotedToo',
'has_attributes' => false,
'pass_by_reference' => true,
'variable_length' => false,
'type_hint' => 'string|bool',
'nullable_type' => false,
'property_visibility' => 'private',
'property_readonly' => true,
];

$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);

}//end testPHP81ConstructorPropertyPromotionWithReadOnly()


/**
* Verify behaviour when a non-constructor function uses PHP 8 property promotion syntax.
*
Expand Down

0 comments on commit e6221c7

Please sign in to comment.