-
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: assign a parenthesis_owner for anonymous classes with pare…
…nthesis Code: ```php $anonClass = new class($arg) {}; ``` As anonymous classes have a distinct token, it makes sense to me to assign that token as the parenthesis owner, along the same lines as is done for anonymous functions. The main difference is that for anonymous classes, the parenthesis are optional. Assigning an owner for them can not be done from within the `Tokenizer::createTokenMap()` as at that point in time the `PHP::processAdditional()` method hasn't run yet, so the token is still a `T_CLASS`. It can however be adjusted from within the `PHP::processAdditional()` method when the `T_CLASS` token is changed to a `T_ANON_CLASS` token. This commit implements this. This means that for the `class` token in the above code snippet will now have a `parenthesis_owner`, `parenthesis_opener` and `parenthesis_closer` in the `$tokens` array. The parenthesis opener and closer will both now also have the `parenthesis_owner` key, in addition to the `parenthesis_opener` and `parenthesis_closer` keys which they already had. Instead of testing this via existing sniffs, I have chosen to add a new set of `Core` tests for specific tokenizer issues, with the tests for this change being the first set of tests added. Includes: * Adding the `T_ANON_CLASS` token to the `Tokens::$parenthesisOpeners` array. * Removing the `T_ANON_CLASS` from the "additional tokens indicating that parenthesis are not arbitrary" list in the `Generic.WhiteSpace.ArbitraryParenthesesSpacing` sniff.
- Loading branch information
Showing
6 changed files
with
204 additions
and
14 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
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
19 changes: 19 additions & 0 deletions
19
tests/Core/Tokenizer/PHP/T_AnonClassParenthesisOwnerTest.inc
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,19 @@ | ||
<?php | ||
|
||
/* testNoParentheses */ | ||
$anonClass = new class { | ||
function __construct() {} | ||
}; | ||
|
||
/* testNoParenthesesAndEmptyTokens */ | ||
$anonClass = new class // phpcs:ignore Standard.Cat | ||
{ | ||
function __construct() {} | ||
}; | ||
|
||
/* testWithParentheses */ | ||
$anonClass = new class() {}; | ||
|
||
/* testWithParenthesesAndEmptyTokens */ | ||
$anonClass = new class /*comment */ | ||
() {}; |
144 changes: 144 additions & 0 deletions
144
tests/Core/Tokenizer/PHP/T_AnonClassParenthesisOwnerTest.php
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,144 @@ | ||
<?php | ||
/** | ||
* Tests the adding of the "parenthesis" keys to an anonymous class token. | ||
* | ||
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl> | ||
* @copyright 2019 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\PHP; | ||
|
||
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; | ||
|
||
class T_AnonClassParenthesisOwnerTest extends AbstractMethodUnitTest | ||
{ | ||
|
||
|
||
/** | ||
* Test that anonymous class tokens without parenthesis do not get assigned a parenthesis owner. | ||
* | ||
* @param string $testMarker The comment which prefaces the target token in the test file. | ||
* | ||
* @dataProvider dataAnonClassNoParentheses | ||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional | ||
* | ||
* @return void | ||
*/ | ||
public function testAnonClassNoParentheses($testMarker) | ||
{ | ||
$tokens = self::$phpcsFile->getTokens(); | ||
|
||
$anonClass = $this->getTargetToken($testMarker, T_ANON_CLASS); | ||
$this->assertFalse(array_key_exists('parenthesis_owner', $tokens[$anonClass])); | ||
$this->assertFalse(array_key_exists('parenthesis_opener', $tokens[$anonClass])); | ||
$this->assertFalse(array_key_exists('parenthesis_closer', $tokens[$anonClass])); | ||
|
||
}//end testAnonClassNoParentheses() | ||
|
||
|
||
/** | ||
* Test that the next open/close parenthesis after an anonymous class without parenthesis | ||
* do not get assigned the anonymous class as a parenthesis owner. | ||
* | ||
* @param string $testMarker The comment which prefaces the target token in the test file. | ||
* | ||
* @dataProvider dataAnonClassNoParentheses | ||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional | ||
* | ||
* @return void | ||
*/ | ||
public function testAnonClassNoParenthesesNextOpenClose($testMarker) | ||
{ | ||
$tokens = self::$phpcsFile->getTokens(); | ||
$function = $this->getTargetToken($testMarker, T_FUNCTION); | ||
|
||
$opener = $this->getTargetToken($testMarker, T_OPEN_PARENTHESIS); | ||
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$opener])); | ||
$this->assertSame($function, $tokens[$opener]['parenthesis_owner']); | ||
|
||
$closer = $this->getTargetToken($testMarker, T_CLOSE_PARENTHESIS); | ||
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$closer])); | ||
$this->assertSame($function, $tokens[$closer]['parenthesis_owner']); | ||
|
||
}//end testAnonClassNoParenthesesNextOpenClose() | ||
|
||
|
||
/** | ||
* Data provider. | ||
* | ||
* @see testAnonClassNoParentheses() | ||
* @see testAnonClassNoParenthesesNextOpenClose() | ||
* | ||
* @return array | ||
*/ | ||
public function dataAnonClassNoParentheses() | ||
{ | ||
return [ | ||
['/* testNoParentheses */'], | ||
['/* testNoParenthesesAndEmptyTokens */'], | ||
]; | ||
|
||
}//end dataAnonClassNoParentheses() | ||
|
||
|
||
/** | ||
* Test that anonymous class tokens with parenthesis get assigned a parenthesis owner, | ||
* opener and closer; and that the opener/closer get the anonymous class assigned as owner. | ||
* | ||
* @param string $testMarker The comment which prefaces the target token in the test file. | ||
* | ||
* @dataProvider dataAnonClassWithParentheses | ||
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional | ||
* | ||
* @return void | ||
*/ | ||
public function testAnonClassWithParentheses($testMarker) | ||
{ | ||
$tokens = self::$phpcsFile->getTokens(); | ||
$anonClass = $this->getTargetToken($testMarker, T_ANON_CLASS); | ||
$opener = $this->getTargetToken($testMarker, T_OPEN_PARENTHESIS); | ||
$closer = $this->getTargetToken($testMarker, T_CLOSE_PARENTHESIS); | ||
|
||
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$anonClass])); | ||
$this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$anonClass])); | ||
$this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$anonClass])); | ||
$this->assertSame($anonClass, $tokens[$anonClass]['parenthesis_owner']); | ||
$this->assertSame($opener, $tokens[$anonClass]['parenthesis_opener']); | ||
$this->assertSame($closer, $tokens[$anonClass]['parenthesis_closer']); | ||
|
||
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$opener])); | ||
$this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$opener])); | ||
$this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$opener])); | ||
$this->assertSame($anonClass, $tokens[$opener]['parenthesis_owner']); | ||
$this->assertSame($opener, $tokens[$opener]['parenthesis_opener']); | ||
$this->assertSame($closer, $tokens[$opener]['parenthesis_closer']); | ||
|
||
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$closer])); | ||
$this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$closer])); | ||
$this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$closer])); | ||
$this->assertSame($anonClass, $tokens[$closer]['parenthesis_owner']); | ||
$this->assertSame($opener, $tokens[$closer]['parenthesis_opener']); | ||
$this->assertSame($closer, $tokens[$closer]['parenthesis_closer']); | ||
|
||
}//end testAnonClassWithParentheses() | ||
|
||
|
||
/** | ||
* Data provider. | ||
* | ||
* @see testAnonClassWithParentheses() | ||
* | ||
* @return array | ||
*/ | ||
public function dataAnonClassWithParentheses() | ||
{ | ||
return [ | ||
['/* testWithParentheses */'], | ||
['/* testWithParenthesesAndEmptyTokens */'], | ||
]; | ||
|
||
}//end dataAnonClassWithParentheses() | ||
|
||
|
||
}//end class |