Skip to content

Commit 6385006

Browse files
committed
Fix mis-identification of 'readonly' keyword
1 parent ed8e00d commit 6385006

File tree

2 files changed

+35
-43
lines changed

2 files changed

+35
-43
lines changed

src/Tokenizers/PHP.php

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,17 @@ protected function tokenize($string)
566566
$lastNotEmptyToken = ($newStackPtr - 1);
567567
}
568568

569+
// Get the next non-empty token.
570+
$nextNonEmptyToken = null;
571+
for ($i = ($stackPtr + 1); $i < $numTokens; $i++) {
572+
if (is_array($tokens[$i]) === false
573+
|| isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === false
574+
) {
575+
$nextNonEmptyToken = $i;
576+
break;
577+
}
578+
}
579+
569580
/*
570581
If we are using \r\n newline characters, the \r and \n are sometimes
571582
split over two tokens. This normally occurs after comments. We need
@@ -602,14 +613,17 @@ protected function tokenize($string)
602613
}
603614

604615
/*
605-
Tokenize context sensitive keyword as string when it should be string.
616+
Tokenize context-sensitive keyword as string when it should be string.
606617
*/
607618

608619
if ($tokenIsArray === true
609620
&& isset(Util\Tokens::$contextSensitiveKeywords[$token[0]]) === true
610621
&& (isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === true
611-
|| $finalTokens[$lastNotEmptyToken]['content'] === '&')
622+
|| $finalTokens[$lastNotEmptyToken]['content'] === '&'
623+
|| (isset($nextNonEmptyToken) === true && $tokens[$nextNonEmptyToken] === '('))
612624
) {
625+
$preserveKeyword = true;
626+
613627
if (isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === true) {
614628
$preserveKeyword = false;
615629

@@ -649,8 +663,6 @@ protected function tokenize($string)
649663
}//end if
650664

651665
if ($finalTokens[$lastNotEmptyToken]['content'] === '&') {
652-
$preserveKeyword = true;
653-
654666
for ($i = ($lastNotEmptyToken - 1); $i >= 0; $i--) {
655667
if (isset(Util\Tokens::$emptyTokens[$finalTokens[$i]['code']]) === true) {
656668
continue;
@@ -664,6 +676,13 @@ protected function tokenize($string)
664676
}
665677
}
666678

679+
if (isset($nextNonEmptyToken) === true
680+
&& $tokens[$nextNonEmptyToken] === '('
681+
&& $token[0] === T_READONLY
682+
) {
683+
$preserveKeyword = false;
684+
}
685+
667686
if ($preserveKeyword === false) {
668687
if (PHP_CODESNIFFER_VERBOSITY > 1) {
669688
$type = Util\Tokens::tokenName($token[0]);
@@ -1012,18 +1031,9 @@ protected function tokenize($string)
10121031
&& $token[0] === T_STRING
10131032
&& strtolower($token[1]) === 'enum'
10141033
) {
1015-
// Get the next non-empty token.
1016-
for ($i = ($stackPtr + 1); $i < $numTokens; $i++) {
1017-
if (is_array($tokens[$i]) === false
1018-
|| isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === false
1019-
) {
1020-
break;
1021-
}
1022-
}
1023-
1024-
if (isset($tokens[$i]) === true
1025-
&& is_array($tokens[$i]) === true
1026-
&& $tokens[$i][0] === T_STRING
1034+
if (isset($tokens[$nextNonEmptyToken]) === true
1035+
&& is_array($tokens[$nextNonEmptyToken]) === true
1036+
&& $tokens[$nextNonEmptyToken][0] === T_STRING
10271037
) {
10281038
// Modify $tokens directly so we can use it later when converting enum "case".
10291039
$tokens[$stackPtr][0] = T_ENUM;
@@ -1230,18 +1240,9 @@ protected function tokenize($string)
12301240
&& ($token[0] === T_STRING
12311241
|| preg_match('`^[a-zA-Z_\x80-\xff]`', $token[1]) === 1)
12321242
) {
1233-
// Get the next non-empty token.
1234-
for ($i = ($stackPtr + 1); $i < $numTokens; $i++) {
1235-
if (is_array($tokens[$i]) === false
1236-
|| isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === false
1237-
) {
1238-
break;
1239-
}
1240-
}
1241-
1242-
if (isset($tokens[$i]) === true
1243-
&& is_array($tokens[$i]) === false
1244-
&& $tokens[$i] === ':'
1243+
if (isset($tokens[$nextNonEmptyToken]) === true
1244+
&& is_array($tokens[$nextNonEmptyToken]) === false
1245+
&& $tokens[$nextNonEmptyToken] === ':'
12451246
) {
12461247
// Get the previous non-empty token.
12471248
for ($j = ($stackPtr - 1); $j > 0; $j--) {
@@ -1287,17 +1288,8 @@ protected function tokenize($string)
12871288
&& strtolower($token[1]) === 'readonly'
12881289
&& isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === false
12891290
) {
1290-
// Get the next non-whitespace token.
1291-
for ($i = ($stackPtr + 1); $i < $numTokens; $i++) {
1292-
if (is_array($tokens[$i]) === false
1293-
|| $tokens[$i][0] !== T_WHITESPACE
1294-
) {
1295-
break;
1296-
}
1297-
}
1298-
1299-
if (isset($tokens[$i]) === false
1300-
|| $tokens[$i] !== '('
1291+
if (isset($tokens[$nextNonEmptyToken]) === false
1292+
|| $tokens[$nextNonEmptyToken] !== '('
13011293
) {
13021294
$finalTokens[$newStackPtr] = [
13031295
'code' => T_READONLY,

tests/Core/Tokenizer/BackfillReadonlyTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,6 @@ public function dataReadonly()
147147
'/* testReadonlyPropertyInAnonymousClass */',
148148
'readonly',
149149
],
150-
[
151-
'/* testReadonlyUsedAsFunctionCallWithSpaceBetweenKeywordAndParens */',
152-
'readonly',
153-
],
154150
[
155151
'/* testParseErrorLiveCoding */',
156152
'readonly',
@@ -224,6 +220,10 @@ public function dataNotReadonly()
224220
'/* testReadonlyAsFunctionCall */',
225221
'readonly',
226222
],
223+
[
224+
'/* testReadonlyUsedAsFunctionCallWithSpaceBetweenKeywordAndParens */',
225+
'readonly',
226+
],
227227
[
228228
'/* testClassConstantFetchWithReadonlyAsConstantName */',
229229
'READONLY',

0 commit comments

Comments
 (0)