Skip to content

Commit e6221c7

Browse files
committed
Merge branch 'feature/file-getmethodparams-add-support-for-readonly' of https://github.com/jrfnl/PHP_CodeSniffer
2 parents 0379bba + ca68016 commit e6221c7

File tree

3 files changed

+63
-0
lines changed

3 files changed

+63
-0
lines changed

src/Files/File.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,6 +1310,8 @@ public function getDeclarationName($stackPtr)
13101310
* Parameters declared using PHP 8 constructor property promotion, have these additional array indexes:
13111311
* 'property_visibility' => string, // The property visibility as declared.
13121312
* 'visibility_token' => integer, // The stack pointer to the visibility modifier token.
1313+
* 'property_readonly' => bool, // TRUE if the readonly keyword was found.
1314+
* 'readonly_token' => integer, // The stack pointer to the readonly modifier token.
13131315
*
13141316
* @param int $stackPtr The position in the stack of the function token
13151317
* to acquire the parameters for.
@@ -1366,6 +1368,7 @@ public function getMethodParameters($stackPtr)
13661368
$typeHintEndToken = false;
13671369
$nullableType = false;
13681370
$visibilityToken = null;
1371+
$readonlyToken = null;
13691372

13701373
for ($i = $paramStart; $i <= $closer; $i++) {
13711374
// Check to see if this token has a parenthesis or bracket opener. If it does
@@ -1491,6 +1494,11 @@ public function getMethodParameters($stackPtr)
14911494
$visibilityToken = $i;
14921495
}
14931496
break;
1497+
case T_READONLY:
1498+
if ($defaultStart === null) {
1499+
$readonlyToken = $i;
1500+
}
1501+
break;
14941502
case T_CLOSE_PARENTHESIS:
14951503
case T_COMMA:
14961504
// If it's null, then there must be no parameters for this
@@ -1523,6 +1531,12 @@ public function getMethodParameters($stackPtr)
15231531
if ($visibilityToken !== null) {
15241532
$vars[$paramCount]['property_visibility'] = $this->tokens[$visibilityToken]['content'];
15251533
$vars[$paramCount]['visibility_token'] = $visibilityToken;
1534+
$vars[$paramCount]['property_readonly'] = false;
1535+
}
1536+
1537+
if ($readonlyToken !== null) {
1538+
$vars[$paramCount]['property_readonly'] = true;
1539+
$vars[$paramCount]['readonly_token'] = $readonlyToken;
15261540
}
15271541

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

15501565
$paramCount++;
15511566
break;

tests/Core/File/GetMethodParametersTest.inc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ class ConstructorPropertyPromotionAndNormalParams {
108108
public function __construct(public int $promotedProp, ?int $normalArg) {}
109109
}
110110

111+
class ConstructorPropertyPromotionWithReadOnly {
112+
/* testPHP81ConstructorPropertyPromotionWithReadOnly */
113+
public function __construct(public readonly ?int $promotedProp, readonly private string|bool &$promotedToo) {}
114+
}
115+
111116
/* testPHP8ConstructorPropertyPromotionGlobalFunction */
112117
// Intentional fatal error. Property promotion not allowed in non-constructor, but that's not the concern of this method.
113118
function globalFunction(private $x) {}

tests/Core/File/GetMethodParametersTest.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,7 @@ public function testPHP8ConstructorPropertyPromotionNoTypes()
696696
'type_hint' => '',
697697
'nullable_type' => false,
698698
'property_visibility' => 'public',
699+
'property_readonly' => false,
699700
];
700701
$expected[1] = [
701702
'name' => '$y',
@@ -707,6 +708,7 @@ public function testPHP8ConstructorPropertyPromotionNoTypes()
707708
'type_hint' => '',
708709
'nullable_type' => false,
709710
'property_visibility' => 'protected',
711+
'property_readonly' => false,
710712
];
711713
$expected[2] = [
712714
'name' => '$z',
@@ -718,6 +720,7 @@ public function testPHP8ConstructorPropertyPromotionNoTypes()
718720
'type_hint' => '',
719721
'nullable_type' => false,
720722
'property_visibility' => 'private',
723+
'property_readonly' => false,
721724
];
722725

723726
$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
@@ -742,6 +745,7 @@ public function testPHP8ConstructorPropertyPromotionWithTypes()
742745
'type_hint' => 'float|int',
743746
'nullable_type' => false,
744747
'property_visibility' => 'protected',
748+
'property_readonly' => false,
745749
];
746750
$expected[1] = [
747751
'name' => '$y',
@@ -753,6 +757,7 @@ public function testPHP8ConstructorPropertyPromotionWithTypes()
753757
'type_hint' => '?string',
754758
'nullable_type' => true,
755759
'property_visibility' => 'public',
760+
'property_readonly' => false,
756761
];
757762
$expected[2] = [
758763
'name' => '$z',
@@ -763,6 +768,7 @@ public function testPHP8ConstructorPropertyPromotionWithTypes()
763768
'type_hint' => 'mixed',
764769
'nullable_type' => false,
765770
'property_visibility' => 'private',
771+
'property_readonly' => false,
766772
];
767773

768774
$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
@@ -787,6 +793,7 @@ public function testPHP8ConstructorPropertyPromotionAndNormalParam()
787793
'type_hint' => 'int',
788794
'nullable_type' => false,
789795
'property_visibility' => 'public',
796+
'property_readonly' => false,
790797
];
791798
$expected[1] = [
792799
'name' => '$normalArg',
@@ -803,6 +810,42 @@ public function testPHP8ConstructorPropertyPromotionAndNormalParam()
803810
}//end testPHP8ConstructorPropertyPromotionAndNormalParam()
804811

805812

813+
/**
814+
* Verify recognition of PHP8 constructor with property promotion using PHP 8.1 readonly keyword.
815+
*
816+
* @return void
817+
*/
818+
public function testPHP81ConstructorPropertyPromotionWithReadOnly()
819+
{
820+
$expected = [];
821+
$expected[0] = [
822+
'name' => '$promotedProp',
823+
'content' => 'public readonly ?int $promotedProp',
824+
'has_attributes' => false,
825+
'pass_by_reference' => false,
826+
'variable_length' => false,
827+
'type_hint' => '?int',
828+
'nullable_type' => true,
829+
'property_visibility' => 'public',
830+
'property_readonly' => true,
831+
];
832+
$expected[1] = [
833+
'name' => '$promotedToo',
834+
'content' => 'readonly private string|bool &$promotedToo',
835+
'has_attributes' => false,
836+
'pass_by_reference' => true,
837+
'variable_length' => false,
838+
'type_hint' => 'string|bool',
839+
'nullable_type' => false,
840+
'property_visibility' => 'private',
841+
'property_readonly' => true,
842+
];
843+
844+
$this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected);
845+
846+
}//end testPHP81ConstructorPropertyPromotionWithReadOnly()
847+
848+
806849
/**
807850
* Verify behaviour when a non-constructor function uses PHP 8 property promotion syntax.
808851
*

0 commit comments

Comments
 (0)