-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Tokenizer/PHP: bugfix goto tokenization logic
The logic could get confused when `goto` would be used in a mixed PHP/HTML file. Includes adding a limited set of unit tests for the `T_GOTO_LABEL` tokenization.
- Loading branch information
Showing
4 changed files
with
231 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<?php | ||
|
||
/* testGotoStatement */ | ||
goto marker; | ||
echo 'Foo'; | ||
|
||
/* testGotoDeclaration */ | ||
marker: | ||
echo 'Bar'; | ||
|
||
/* testGotoStatementInLoop */ | ||
for($i=0,$j=50; $i<100; $i++) { | ||
while($j--) { | ||
if($j==17) GOTO end; | ||
} | ||
} | ||
echo "i = $i"; | ||
?> | ||
<div><?php $cond ? TEST_A : TEST_B ?></div> | ||
|
||
<?php | ||
/* testGotoDeclarationOutsideLoop */ | ||
end: | ||
echo 'j hit 17'; | ||
|
||
switch ($x) { | ||
/* testNotGotoDeclarationGlobalConstant */ | ||
case CONSTANT: | ||
// Do something. | ||
break; | ||
|
||
/* testNotGotoDeclarationNamespacedConstant */ | ||
case MyNS\CONSTANT: | ||
// Do something. | ||
break; | ||
|
||
/* testNotGotoDeclarationClassConstant */ | ||
case MyClass::CONSTANT: | ||
// Do something. | ||
break; | ||
|
||
/* testNotGotoDeclarationClassProperty */ | ||
case $obj->property: | ||
// Do something. | ||
break; | ||
} | ||
|
||
switch (true) { | ||
/* testNotGotoDeclarationGlobalConstantInTernary */ | ||
case $x === ($cond) ? CONST_A : CONST_B: | ||
// Do something. | ||
break; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
<?php | ||
/** | ||
* Tests the tokenization of goto declarations and statements. | ||
* | ||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl> | ||
* @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) | ||
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence | ||
*/ | ||
|
||
namespace PHP_CodeSniffer\Tests\Core\Tokenizer; | ||
|
||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; | ||
|
||
class GotoLabelTest extends AbstractMethodUnitTest | ||
{ | ||
|
||
|
||
/** | ||
* Verify that the label in a goto statement is tokenized as T_STRING. | ||
* | ||
* @param string $testMarker The comment prefacing the target token. | ||
* @param string $testContent The token content to expect. | ||
* | ||
* @dataProvider dataGotoStatement | ||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize | ||
* | ||
* @return void | ||
*/ | ||
public function testGotoStatement($testMarker, $testContent) | ||
{ | ||
$tokens = self::$phpcsFile->getTokens(); | ||
|
||
$label = $this->getTargetToken($testMarker, T_STRING); | ||
|
||
$this->assertInternalType('int', $label); | ||
$this->assertSame($testContent, $tokens[$label]['content']); | ||
|
||
}//end testGotoStatement() | ||
|
||
|
||
/** | ||
* Data provider. | ||
* | ||
* @see testGotoStatement() | ||
* | ||
* @return array | ||
*/ | ||
public function dataGotoStatement() | ||
{ | ||
return [ | ||
[ | ||
'/* testGotoStatement */', | ||
'marker', | ||
], | ||
[ | ||
'/* testGotoStatementInLoop */', | ||
'end', | ||
], | ||
]; | ||
|
||
}//end dataGotoStatement() | ||
|
||
|
||
/** | ||
* Verify that the label in a goto declaration is tokenized as T_GOTO_LABEL. | ||
* | ||
* @param string $testMarker The comment prefacing the target token. | ||
* @param string $testContent The token content to expect. | ||
* | ||
* @dataProvider dataGotoDeclaration | ||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize | ||
* | ||
* @return void | ||
*/ | ||
public function testGotoDeclaration($testMarker, $testContent) | ||
{ | ||
$tokens = self::$phpcsFile->getTokens(); | ||
|
||
$label = $this->getTargetToken($testMarker, T_GOTO_LABEL); | ||
|
||
$this->assertInternalType('int', $label); | ||
$this->assertSame($testContent, $tokens[$label]['content']); | ||
|
||
}//end testGotoDeclaration() | ||
|
||
|
||
/** | ||
* Data provider. | ||
* | ||
* @see testGotoDeclaration() | ||
* | ||
* @return array | ||
*/ | ||
public function dataGotoDeclaration() | ||
{ | ||
return [ | ||
[ | ||
'/* testGotoDeclaration */', | ||
'marker:', | ||
], | ||
[ | ||
'/* testGotoDeclarationOutsideLoop */', | ||
'end:', | ||
], | ||
]; | ||
|
||
}//end dataGotoDeclaration() | ||
|
||
|
||
/** | ||
* Verify that the constant used in a switch - case statement is not confused with a goto label. | ||
* | ||
* @param string $testMarker The comment prefacing the target token. | ||
* @param string $testContent The token content to expect. | ||
* | ||
* @dataProvider dataNotAGotoDeclaration | ||
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize | ||
* | ||
* @return void | ||
*/ | ||
public function testNotAGotoDeclaration($testMarker, $testContent) | ||
{ | ||
$tokens = self::$phpcsFile->getTokens(); | ||
$target = $this->getTargetToken($testMarker, [T_GOTO_LABEL, T_STRING], $testContent); | ||
|
||
$this->assertSame(T_STRING, $tokens[$target]['code']); | ||
$this->assertSame('T_STRING', $tokens[$target]['type']); | ||
|
||
}//end testNotAGotoDeclaration() | ||
|
||
|
||
/** | ||
* Data provider. | ||
* | ||
* @see testNotAGotoDeclaration() | ||
* | ||
* @return array | ||
*/ | ||
public function dataNotAGotoDeclaration() | ||
{ | ||
return [ | ||
[ | ||
'/* testNotGotoDeclarationGlobalConstant */', | ||
'CONSTANT', | ||
], | ||
[ | ||
'/* testNotGotoDeclarationNamespacedConstant */', | ||
'CONSTANT', | ||
], | ||
[ | ||
'/* testNotGotoDeclarationClassConstant */', | ||
'CONSTANT', | ||
], | ||
[ | ||
'/* testNotGotoDeclarationClassProperty */', | ||
'property', | ||
], | ||
[ | ||
'/* testNotGotoDeclarationGlobalConstantInTernary */', | ||
'CONST_A', | ||
], | ||
[ | ||
'/* testNotGotoDeclarationGlobalConstantInTernary */', | ||
'CONST_B', | ||
], | ||
]; | ||
|
||
}//end dataNotAGotoDeclaration() | ||
|
||
|
||
}//end class |