Skip to content

Commit f22e90b

Browse files
authored
Merge pull request #1016 from PHPCSStandards/phpcs-4.0/feature/185-tokenizer-php-goto-label-tokenize-colon-separately
Tokenizer/PHP: `T_GOTO_LABEL` no longer contains colon
2 parents 8c0f336 + ebff295 commit f22e90b

File tree

5 files changed

+70
-37
lines changed

5 files changed

+70
-37
lines changed

src/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ public function process(File $phpcsFile, $stackPtr)
156156

157157
if ($tokens[$varToken]['code'] === T_VARIABLE
158158
|| $tokens[$varToken]['code'] === T_OPEN_TAG
159-
|| $tokens[$varToken]['code'] === T_GOTO_LABEL
159+
|| $tokens[$varToken]['code'] === T_GOTO_COLON
160160
|| $tokens[$varToken]['code'] === T_INLINE_THEN
161161
|| $tokens[$varToken]['code'] === T_INLINE_ELSE
162162
|| $tokens[$varToken]['code'] === T_SEMICOLON

src/Tokenizers/PHP.php

Lines changed: 52 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ class PHP extends Tokenizer
364364
T_FUNC_C => 12,
365365
T_GLOBAL => 6,
366366
T_GOTO => 4,
367+
T_GOTO_COLON => 1,
367368
T_HALT_COMPILER => 15,
368369
T_IF => 2,
369370
T_IMPLEMENTS => 10,
@@ -2252,45 +2253,67 @@ function return types. We want to keep the parenthesis map clean,
22522253

22532254
if ($tokenIsArray === true
22542255
&& $token[0] === T_STRING
2255-
&& isset($tokens[($stackPtr + 1)]) === true
2256-
&& $tokens[($stackPtr + 1)] === ':'
22572256
&& (is_array($tokens[($stackPtr - 1)]) === false
22582257
|| $tokens[($stackPtr - 1)][0] !== T_PAAMAYIM_NEKUDOTAYIM)
22592258
) {
2260-
$stopTokens = [
2261-
T_CASE => true,
2262-
T_SEMICOLON => true,
2263-
T_OPEN_TAG => true,
2264-
T_OPEN_CURLY_BRACKET => true,
2265-
T_INLINE_THEN => true,
2266-
T_ENUM => true,
2267-
];
2268-
2269-
for ($x = ($newStackPtr - 1); $x > 0; $x--) {
2270-
if (isset($stopTokens[$finalTokens[$x]['code']]) === true) {
2271-
break;
2259+
// Find next non-empty token.
2260+
for ($i = ($stackPtr + 1); $i < $numTokens; $i++) {
2261+
if (is_array($tokens[$i]) === true
2262+
&& isset(Tokens::$emptyTokens[$tokens[$i][0]]) === true
2263+
) {
2264+
continue;
22722265
}
2266+
2267+
break;
22732268
}
22742269

2275-
if ($finalTokens[$x]['code'] !== T_CASE
2276-
&& $finalTokens[$x]['code'] !== T_INLINE_THEN
2277-
&& $finalTokens[$x]['code'] !== T_ENUM
2278-
) {
2279-
$finalTokens[$newStackPtr] = [
2280-
'content' => $token[1].':',
2281-
'code' => T_GOTO_LABEL,
2282-
'type' => 'T_GOTO_LABEL',
2270+
if (isset($tokens[$i]) === true && $tokens[$i] === ':') {
2271+
// Okay, so we have a colon, now we need to make sure that this is not
2272+
// class constant access, a ternary, enum or switch case.
2273+
$stopTokens = [
2274+
T_CASE => true,
2275+
T_SEMICOLON => true,
2276+
T_OPEN_TAG => true,
2277+
T_OPEN_CURLY_BRACKET => true,
2278+
T_INLINE_THEN => true,
2279+
T_ENUM => true,
22832280
];
22842281

2285-
if (PHP_CODESNIFFER_VERBOSITY > 1) {
2286-
StatusWriter::write("* token $stackPtr changed from T_STRING to T_GOTO_LABEL", 2);
2287-
StatusWriter::write('* skipping T_COLON token '.($stackPtr + 1), 2);
2282+
for ($x = ($newStackPtr - 1); $x > 0; $x--) {
2283+
if (isset($stopTokens[$finalTokens[$x]['code']]) === true) {
2284+
break;
2285+
}
22882286
}
22892287

2290-
$newStackPtr++;
2291-
$stackPtr++;
2292-
continue;
2293-
}
2288+
if ($finalTokens[$x]['code'] !== T_CASE
2289+
&& $finalTokens[$x]['code'] !== T_INLINE_THEN
2290+
&& $finalTokens[$x]['code'] !== T_ENUM
2291+
) {
2292+
$finalTokens[$newStackPtr] = [
2293+
'content' => $token[1],
2294+
'code' => T_GOTO_LABEL,
2295+
'type' => 'T_GOTO_LABEL',
2296+
];
2297+
2298+
if (PHP_CODESNIFFER_VERBOSITY > 1) {
2299+
StatusWriter::write("* token $stackPtr changed from T_STRING to T_GOTO_LABEL", 2);
2300+
}
2301+
2302+
// Modify the original token stack for the colon as potential
2303+
// whitespace/comments between still needs to get the normal treatment.
2304+
$tokens[$i] = [
2305+
0 => T_GOTO_COLON,
2306+
1 => ':',
2307+
];
2308+
2309+
if (PHP_CODESNIFFER_VERBOSITY > 1) {
2310+
StatusWriter::write("* token $i changed from \":\" to T_GOTO_COLON in the original token stack", 2);
2311+
}
2312+
2313+
$newStackPtr++;
2314+
continue;
2315+
}//end if
2316+
}//end if
22942317
}//end if
22952318

22962319
/*

src/Util/Tokens.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
define('T_OPEN_SHORT_ARRAY', 'PHPCS_T_OPEN_SHORT_ARRAY');
5555
define('T_CLOSE_SHORT_ARRAY', 'PHPCS_T_CLOSE_SHORT_ARRAY');
5656
define('T_GOTO_LABEL', 'PHPCS_T_GOTO_LABEL');
57+
define('T_GOTO_COLON', 'PHPCS_T_GOTO_COLON');
5758
define('T_BINARY_CAST', 'PHPCS_T_BINARY_CAST');
5859
define('T_OPEN_USE_GROUP', 'PHPCS_T_OPEN_USE_GROUP');
5960
define('T_CLOSE_USE_GROUP', 'PHPCS_T_CLOSE_USE_GROUP');

tests/Core/Tokenizers/PHP/GotoLabelTest.inc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ echo "i = $i";
2020

2121
<?php
2222
/* testGotoDeclarationOutsideLoop */
23-
end:
23+
end /*comment*/ :
2424
echo 'j hit 17';
2525

2626
switch($x){
@@ -31,7 +31,7 @@ switch($x){
3131
goto def;
3232
default:
3333
/* testGotoDeclarationInSwitch */
34-
def:
34+
def :
3535
print($x);
3636
}
3737

tests/Core/Tokenizers/PHP/GotoLabelTest.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP;
1111

1212
use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase;
13+
use PHP_CodeSniffer\Util\Tokens;
1314

1415
/**
1516
* Tests the tokenization of goto declarations and statements.
@@ -74,7 +75,8 @@ public static function dataGotoStatement()
7475

7576

7677
/**
77-
* Verify that the label in a goto declaration is tokenized as T_GOTO_LABEL.
78+
* Verify that the label in a goto declaration is tokenized as T_GOTO_LABEL
79+
* and that the next non-empty token is always T_GOTO_COLON.
7880
*
7981
* @param string $testMarker The comment prefacing the target token.
8082
* @param string $testContent The token content to expect.
@@ -92,6 +94,13 @@ public function testGotoDeclaration($testMarker, $testContent)
9294
$this->assertIsInt($label);
9395
$this->assertSame($testContent, $tokens[$label]['content']);
9496

97+
$next = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($label + 1), null, true);
98+
99+
$this->assertIsInt($next);
100+
$this->assertSame(T_GOTO_COLON, $tokens[$next]['code']);
101+
$this->assertSame('T_GOTO_COLON', $tokens[$next]['type']);
102+
$this->assertSame(':', $tokens[$next]['content']);
103+
95104
}//end testGotoDeclaration()
96105

97106

@@ -107,19 +116,19 @@ public static function dataGotoDeclaration()
107116
return [
108117
'label in goto declaration - marker' => [
109118
'testMarker' => '/* testGotoDeclaration */',
110-
'testContent' => 'marker:',
119+
'testContent' => 'marker',
111120
],
112121
'label in goto declaration - end' => [
113122
'testMarker' => '/* testGotoDeclarationOutsideLoop */',
114-
'testContent' => 'end:',
123+
'testContent' => 'end',
115124
],
116125
'label in goto declaration - def' => [
117126
'testMarker' => '/* testGotoDeclarationInSwitch */',
118-
'testContent' => 'def:',
127+
'testContent' => 'def',
119128
],
120129
'label in goto declaration - label' => [
121130
'testMarker' => '/* testGotoDeclarationInFunction */',
122-
'testContent' => 'label:',
131+
'testContent' => 'label',
123132
],
124133
];
125134

0 commit comments

Comments
 (0)