Skip to content

Commit 1fff686

Browse files
committed
Resolve T_READONLY earlier
1 parent d009ba6 commit 1fff686

9 files changed

+88
-60
lines changed

src/Tokenizers/PHP.php

Lines changed: 32 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,6 +1241,38 @@ protected function tokenize($string)
12411241
}//end if
12421242
}//end if
12431243

1244+
/*
1245+
"readonly" keyword for PHP < 8.1
1246+
*/
1247+
1248+
if (PHP_VERSION_ID < 80100
1249+
&& $tokenIsArray === true
1250+
&& strtolower($token[1]) === 'readonly'
1251+
&& isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === false
1252+
) {
1253+
// Get the next non-whitespace token.
1254+
for ($i = ($stackPtr + 1); $i < $numTokens; $i++) {
1255+
if (is_array($tokens[$i]) === false
1256+
|| $tokens[$i][0] !== T_WHITESPACE
1257+
) {
1258+
break;
1259+
}
1260+
}
1261+
1262+
if (isset($tokens[$i]) === false
1263+
|| $tokens[$i] !== '('
1264+
) {
1265+
$finalTokens[$newStackPtr] = [
1266+
'code' => T_READONLY,
1267+
'type' => 'T_READONLY',
1268+
'content' => $token[1],
1269+
];
1270+
$newStackPtr++;
1271+
1272+
continue;
1273+
}
1274+
}//end if
1275+
12441276
/*
12451277
Before PHP 7.0, the "yield from" was tokenized as
12461278
T_YIELD, T_WHITESPACE and T_STRING. So look for
@@ -2924,65 +2956,6 @@ protected function processAdditional()
29242956
$this->tokens[$i]['code'] = T_STRING;
29252957
$this->tokens[$i]['type'] = 'T_STRING';
29262958
}
2927-
} else if ($this->tokens[$i]['code'] === T_STRING
2928-
&& strtolower($this->tokens[$i]['content']) === 'readonly'
2929-
) {
2930-
/*
2931-
Adds "readonly" keyword support for PHP < 8.1.
2932-
*/
2933-
2934-
$allowedAfter = [
2935-
T_STRING => T_STRING,
2936-
T_NS_SEPARATOR => T_NS_SEPARATOR,
2937-
T_NAME_FULLY_QUALIFIED => T_NAME_FULLY_QUALIFIED,
2938-
T_NAME_RELATIVE => T_NAME_RELATIVE,
2939-
T_NAME_QUALIFIED => T_NAME_QUALIFIED,
2940-
T_TYPE_UNION => T_TYPE_UNION,
2941-
T_BITWISE_OR => T_BITWISE_OR,
2942-
T_BITWISE_AND => T_BITWISE_AND,
2943-
T_ARRAY => T_ARRAY,
2944-
T_CALLABLE => T_CALLABLE,
2945-
T_SELF => T_SELF,
2946-
T_PARENT => T_PARENT,
2947-
T_NULL => T_FALSE,
2948-
T_NULLABLE => T_NULLABLE,
2949-
T_STATIC => T_STATIC,
2950-
T_PUBLIC => T_PUBLIC,
2951-
T_PROTECTED => T_PROTECTED,
2952-
T_PRIVATE => T_PRIVATE,
2953-
T_VAR => T_VAR,
2954-
];
2955-
2956-
$shouldBeReadonly = true;
2957-
2958-
for ($x = ($i + 1); $x < $numTokens; $x++) {
2959-
if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) {
2960-
continue;
2961-
}
2962-
2963-
if ($this->tokens[$x]['code'] === T_VARIABLE
2964-
|| $this->tokens[$x]['code'] === T_CONST
2965-
) {
2966-
break;
2967-
}
2968-
2969-
if (isset($allowedAfter[$this->tokens[$x]['code']]) === false) {
2970-
$shouldBeReadonly = false;
2971-
break;
2972-
}
2973-
}
2974-
2975-
if ($shouldBeReadonly === true) {
2976-
if (PHP_CODESNIFFER_VERBOSITY > 1) {
2977-
$line = $this->tokens[$i]['line'];
2978-
echo "\t* token $i on line $line changed from T_STRING to T_READONLY".PHP_EOL;
2979-
}
2980-
2981-
$this->tokens[$i]['code'] = T_READONLY;
2982-
$this->tokens[$i]['type'] = 'T_READONLY';
2983-
}
2984-
2985-
continue;
29862959
}//end if
29872960

29882961
if (($this->tokens[$i]['code'] !== T_CASE

tests/Core/File/GetMemberPropertiesTest.inc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,13 @@ $anon = class() {
247247
public readonly ?array $array;
248248

249249
/* testPHP81ReadonlyWithUnionType */
250-
protected ReadOnly string|null $array;
250+
public readonly string|int $readonlyWithUnionType;
251+
252+
/* testPHP81ReadonlyWithUnionTypeWithNull */
253+
protected ReadOnly string|null $readonlyWithUnionTypeWithNull;
254+
255+
/* testPHP81OnlyReadonlyWithUnionType */
256+
readonly string|int $onlyReadonly;
251257
};
252258

253259
$anon = class {

tests/Core/File/GetMemberPropertiesTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,17 @@ public function dataGetMemberProperties()
690690
],
691691
[
692692
'/* testPHP81ReadonlyWithUnionType */',
693+
[
694+
'scope' => 'public',
695+
'scope_specified' => true,
696+
'is_static' => false,
697+
'is_readonly' => true,
698+
'type' => 'string|int',
699+
'nullable_type' => false,
700+
],
701+
],
702+
[
703+
'/* testPHP81ReadonlyWithUnionTypeWithNull */',
693704
[
694705
'scope' => 'protected',
695706
'scope_specified' => true,
@@ -699,6 +710,17 @@ public function dataGetMemberProperties()
699710
'nullable_type' => false,
700711
],
701712
],
713+
[
714+
'/* testPHP81OnlyReadonlyWithUnionType */',
715+
[
716+
'scope' => 'public',
717+
'scope_specified' => false,
718+
'is_static' => false,
719+
'is_readonly' => true,
720+
'type' => 'string|int',
721+
'nullable_type' => false,
722+
],
723+
],
702724
[
703725
'/* testPHP8PropertySingleAttribute */',
704726
[

tests/Core/Tokenizer/BackfillReadonlyTest.inc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ $var = readonly($a, $b);
9292
/* testClassConstantFetchWithReadonlyAsConstantName */
9393
echo ClassName::READONLY;
9494

95+
/* testReadonlyUsedAsFunctionCallWithSpaceBetweenKeywordAndParens */
96+
$var = readonly /* comment */ ();
97+
9598
/* testParseErrorLiveCoding */
9699
// This must be the last test in the file.
97100
readonly

tests/Core/Tokenizer/BackfillReadonlyTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ public function dataReadonly()
147147
'/* testReadonlyPropertyInAnonymousClass */',
148148
'readonly',
149149
],
150+
[
151+
'/* testReadonlyUsedAsFunctionCallWithSpaceBetweenKeywordAndParens */',
152+
'readonly',
153+
],
150154
[
151155
'/* testParseErrorLiveCoding */',
152156
'readonly',

tests/Core/Tokenizer/BitwiseOrTest.inc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,18 @@ class TypeUnion
3636
/* testTypeUnionPropertyWithReadOnlyKeyword */
3737
protected readonly string|null $array;
3838

39+
/* testTypeUnionPropertyWithStaticAndReadOnlyKeywords */
40+
static readonly string|null $array;
41+
42+
/* testTypeUnionPropertyWithVarAndReadOnlyKeywords */
43+
var readonly string|null $array;
44+
45+
/* testTypeUnionPropertyWithReadOnlyKeywordFirst */
46+
readonly protected string|null $array;
47+
48+
/* testTypeUnionPropertyWithOnlyReadOnlyKeyword */
49+
readonly string|null $nullableString;
50+
3951
public function paramTypes(
4052
/* testTypeUnionParam1 */
4153
int|float $paramA /* testBitwiseOrParamDefaultValue */ = CONSTANT_A | CONSTANT_B,

tests/Core/Tokenizer/BitwiseOrTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ public function dataTypeUnion()
106106
['/* testTypeUnionPropertyPartiallyQualified */'],
107107
['/* testTypeUnionPropertyFullyQualified */'],
108108
['/* testTypeUnionPropertyWithReadOnlyKeyword */'],
109+
['/* testTypeUnionPropertyWithReadOnlyKeywordFirst */'],
110+
['/* testTypeUnionPropertyWithStaticAndReadOnlyKeywords */'],
111+
['/* testTypeUnionPropertyWithVarAndReadOnlyKeywords */'],
112+
['/* testTypeUnionPropertyWithOnlyReadOnlyKeyword */'],
109113
['/* testTypeUnionParam1 */'],
110114
['/* testTypeUnionParam2 */'],
111115
['/* testTypeUnionParam3 */'],

tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.inc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,9 @@ foobar(protected: $value, /* testReservedKeywordProtected2 */ protected: $value)
310310
/* testReservedKeywordPublic1 */
311311
foobar(public: $value, /* testReservedKeywordPublic2 */ public: $value);
312312

313+
/* testReservedKeywordReadonly1 */
314+
foobar(readonly: $value, /* testReservedKeywordReadonly2 */ readonly: $value);
315+
313316
/* testReservedKeywordRequire1 */
314317
foobar(require: $value, /* testReservedKeywordRequire2 */ require: $value);
315318

tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,7 @@ public function dataReservedKeywordsAsName()
804804
'private',
805805
'protected',
806806
'public',
807+
'readonly',
807808
'require',
808809
'require_once',
809810
'return',

0 commit comments

Comments
 (0)