Skip to content

Commit 0b5f64c

Browse files
committed
Merge branch 'feature/tokenizer-anonymous-class-parenthesis-owner' of https://github.com/jrfnl/PHP_CodeSniffer
2 parents b73f463 + baaf896 commit 0b5f64c

File tree

6 files changed

+204
-14
lines changed

6 files changed

+204
-14
lines changed

package.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,12 @@ http://pear.php.net/dtd/package-2.0.xsd">
219219
<file baseinstalldir="" name="AcceptTest.php" role="test" />
220220
</dir>
221221
</dir>
222+
<dir name="Tokenizer">
223+
<dir name="PHP">
224+
<file baseinstalldir="" name="T_AnonClassParenthesisOwnerTest.inc" role="test" />
225+
<file baseinstalldir="" name="T_AnonClassParenthesisOwnerTest.php" role="test" />
226+
</dir>
227+
</dir>
222228
<file baseinstalldir="" name="AbstractMethodUnitTest.php" role="test" />
223229
<file baseinstalldir="" name="AllTests.php" role="test" />
224230
<file baseinstalldir="" name="ErrorSuppressionTest.php" role="test" />
@@ -2029,6 +2035,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
20292035
<install as="CodeSniffer/Core/File/IsReferenceTest.inc" name="tests/Core/File/IsReferenceTest.inc" />
20302036
<install as="CodeSniffer/Core/Filters/Filter/AcceptTest.php" name="tests/Core/Filters/Filter/AcceptTest.php" />
20312037
<install as="CodeSniffer/Core/Filters/Filter/AcceptTest.xml" name="tests/Core/Filters/Filter/AcceptTest.xml" />
2038+
<install as="CodeSniffer/Core/Tokenizer/PHP/T_AnonClassParenthesisOwnerTest.php" name="tests/Core/Tokenizer/PHP/T_AnonClassParenthesisOwnerTest.php" />
2039+
<install as="CodeSniffer/Core/Tokenizer/PHP/T_AnonClassParenthesisOwnerTest.inc" name="tests/Core/Tokenizer/PHP/T_AnonClassParenthesisOwnerTest.inc" />
20322040
<install as="CodeSniffer/Standards/AllSniffs.php" name="tests/Standards/AllSniffs.php" />
20332041
<install as="CodeSniffer/Standards/AbstractSniffUnitTest.php" name="tests/Standards/AbstractSniffUnitTest.php" />
20342042
</filelist>
@@ -2066,6 +2074,8 @@ http://pear.php.net/dtd/package-2.0.xsd">
20662074
<install as="CodeSniffer/Core/File/IsReferenceTest.inc" name="tests/Core/File/IsReferenceTest.inc" />
20672075
<install as="CodeSniffer/Core/Filters/Filter/AcceptTest.php" name="tests/Core/Filters/Filter/AcceptTest.php" />
20682076
<install as="CodeSniffer/Core/Filters/Filter/AcceptTest.xml" name="tests/Core/Filters/Filter/AcceptTest.xml" />
2077+
<install as="CodeSniffer/Core/Tokenizer/PHP/T_AnonClassParenthesisOwnerTest.php" name="tests/Core/Tokenizer/PHP/T_AnonClassParenthesisOwnerTest.php" />
2078+
<install as="CodeSniffer/Core/Tokenizer/PHP/T_AnonClassParenthesisOwnerTest.inc" name="tests/Core/Tokenizer/PHP/T_AnonClassParenthesisOwnerTest.inc" />
20692079
<install as="CodeSniffer/Standards/AllSniffs.php" name="tests/Standards/AllSniffs.php" />
20702080
<install as="CodeSniffer/Standards/AbstractSniffUnitTest.php" name="tests/Standards/AbstractSniffUnitTest.php" />
20712081
<ignore name="bin/phpcs.bat" />

src/Standards/Generic/Sniffs/WhiteSpace/ArbitraryParenthesesSpacingSniff.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ public function register()
5757
$this->ignoreTokens[T_CLOSE_SQUARE_BRACKET] = T_CLOSE_SQUARE_BRACKET;
5858
$this->ignoreTokens[T_CLOSE_SHORT_ARRAY] = T_CLOSE_SHORT_ARRAY;
5959

60-
$this->ignoreTokens[T_ANON_CLASS] = T_ANON_CLASS;
6160
$this->ignoreTokens[T_USE] = T_USE;
6261
$this->ignoreTokens[T_DECLARE] = T_DECLARE;
6362
$this->ignoreTokens[T_THROW] = T_THROW;

src/Tokenizers/PHP.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1559,6 +1559,23 @@ protected function processAdditional()
15591559
echo "\t* token $i on line $line changed from T_CLASS to T_ANON_CLASS".PHP_EOL;
15601560
}
15611561

1562+
if ($this->tokens[$x]['code'] === T_OPEN_PARENTHESIS
1563+
&& isset($this->tokens[$x]['parenthesis_closer']) === true
1564+
) {
1565+
$closer = $this->tokens[$x]['parenthesis_closer'];
1566+
1567+
$this->tokens[$i]['parenthesis_opener'] = $x;
1568+
$this->tokens[$i]['parenthesis_closer'] = $closer;
1569+
$this->tokens[$i]['parenthesis_owner'] = $i;
1570+
$this->tokens[$x]['parenthesis_owner'] = $i;
1571+
$this->tokens[$closer]['parenthesis_owner'] = $i;
1572+
1573+
if (PHP_CODESNIFFER_VERBOSITY > 1) {
1574+
$line = $this->tokens[$i]['line'];
1575+
echo "\t\t* added parenthesis keys to T_ANON_CLASS token $i on line $line".PHP_EOL;
1576+
}
1577+
}
1578+
15621579
for ($x = ($this->tokens[$i]['scope_opener'] + 1); $x < $this->tokens[$i]['scope_closer']; $x++) {
15631580
if (isset($this->tokens[$x]['conditions'][$i]) === false) {
15641581
continue;
@@ -1570,7 +1587,7 @@ protected function processAdditional()
15701587
echo "\t\t* cleaned $x ($type) *".PHP_EOL;
15711588
}
15721589
}
1573-
}
1590+
}//end if
15741591

15751592
continue;
15761593
} else if ($this->tokens[$i]['code'] === T_OPEN_SQUARE_BRACKET) {

src/Util/Tokens.php

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -344,18 +344,19 @@ final class Tokens
344344
* @var array<int, int>
345345
*/
346346
public static $parenthesisOpeners = [
347-
T_ARRAY => T_ARRAY,
348-
T_LIST => T_LIST,
349-
T_FUNCTION => T_FUNCTION,
350-
T_CLOSURE => T_CLOSURE,
351-
T_WHILE => T_WHILE,
352-
T_FOR => T_FOR,
353-
T_FOREACH => T_FOREACH,
354-
T_SWITCH => T_SWITCH,
355-
T_IF => T_IF,
356-
T_ELSEIF => T_ELSEIF,
357-
T_CATCH => T_CATCH,
358-
T_DECLARE => T_DECLARE,
347+
T_ARRAY => T_ARRAY,
348+
T_LIST => T_LIST,
349+
T_FUNCTION => T_FUNCTION,
350+
T_CLOSURE => T_CLOSURE,
351+
T_ANON_CLASS => T_ANON_CLASS,
352+
T_WHILE => T_WHILE,
353+
T_FOR => T_FOR,
354+
T_FOREACH => T_FOREACH,
355+
T_SWITCH => T_SWITCH,
356+
T_IF => T_IF,
357+
T_ELSEIF => T_ELSEIF,
358+
T_CATCH => T_CATCH,
359+
T_DECLARE => T_DECLARE,
359360
];
360361

361362
/**
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
/* testNoParentheses */
4+
$anonClass = new class {
5+
function __construct() {}
6+
};
7+
8+
/* testNoParenthesesAndEmptyTokens */
9+
$anonClass = new class // phpcs:ignore Standard.Cat
10+
{
11+
function __construct() {}
12+
};
13+
14+
/* testWithParentheses */
15+
$anonClass = new class() {};
16+
17+
/* testWithParenthesesAndEmptyTokens */
18+
$anonClass = new class /*comment */
19+
() {};
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
<?php
2+
/**
3+
* Tests the adding of the "parenthesis" keys to an anonymous class token.
4+
*
5+
* @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
6+
* @copyright 2019 Squiz Pty Ltd (ABN 77 084 670 600)
7+
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
8+
*/
9+
10+
namespace PHP_CodeSniffer\Tests\Core\Tokenizer\PHP;
11+
12+
use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest;
13+
14+
class T_AnonClassParenthesisOwnerTest extends AbstractMethodUnitTest
15+
{
16+
17+
18+
/**
19+
* Test that anonymous class tokens without parenthesis do not get assigned a parenthesis owner.
20+
*
21+
* @param string $testMarker The comment which prefaces the target token in the test file.
22+
*
23+
* @dataProvider dataAnonClassNoParentheses
24+
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
25+
*
26+
* @return void
27+
*/
28+
public function testAnonClassNoParentheses($testMarker)
29+
{
30+
$tokens = self::$phpcsFile->getTokens();
31+
32+
$anonClass = $this->getTargetToken($testMarker, T_ANON_CLASS);
33+
$this->assertFalse(array_key_exists('parenthesis_owner', $tokens[$anonClass]));
34+
$this->assertFalse(array_key_exists('parenthesis_opener', $tokens[$anonClass]));
35+
$this->assertFalse(array_key_exists('parenthesis_closer', $tokens[$anonClass]));
36+
37+
}//end testAnonClassNoParentheses()
38+
39+
40+
/**
41+
* Test that the next open/close parenthesis after an anonymous class without parenthesis
42+
* do not get assigned the anonymous class as a parenthesis owner.
43+
*
44+
* @param string $testMarker The comment which prefaces the target token in the test file.
45+
*
46+
* @dataProvider dataAnonClassNoParentheses
47+
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
48+
*
49+
* @return void
50+
*/
51+
public function testAnonClassNoParenthesesNextOpenClose($testMarker)
52+
{
53+
$tokens = self::$phpcsFile->getTokens();
54+
$function = $this->getTargetToken($testMarker, T_FUNCTION);
55+
56+
$opener = $this->getTargetToken($testMarker, T_OPEN_PARENTHESIS);
57+
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$opener]));
58+
$this->assertSame($function, $tokens[$opener]['parenthesis_owner']);
59+
60+
$closer = $this->getTargetToken($testMarker, T_CLOSE_PARENTHESIS);
61+
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$closer]));
62+
$this->assertSame($function, $tokens[$closer]['parenthesis_owner']);
63+
64+
}//end testAnonClassNoParenthesesNextOpenClose()
65+
66+
67+
/**
68+
* Data provider.
69+
*
70+
* @see testAnonClassNoParentheses()
71+
* @see testAnonClassNoParenthesesNextOpenClose()
72+
*
73+
* @return array
74+
*/
75+
public function dataAnonClassNoParentheses()
76+
{
77+
return [
78+
['/* testNoParentheses */'],
79+
['/* testNoParenthesesAndEmptyTokens */'],
80+
];
81+
82+
}//end dataAnonClassNoParentheses()
83+
84+
85+
/**
86+
* Test that anonymous class tokens with parenthesis get assigned a parenthesis owner,
87+
* opener and closer; and that the opener/closer get the anonymous class assigned as owner.
88+
*
89+
* @param string $testMarker The comment which prefaces the target token in the test file.
90+
*
91+
* @dataProvider dataAnonClassWithParentheses
92+
* @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional
93+
*
94+
* @return void
95+
*/
96+
public function testAnonClassWithParentheses($testMarker)
97+
{
98+
$tokens = self::$phpcsFile->getTokens();
99+
$anonClass = $this->getTargetToken($testMarker, T_ANON_CLASS);
100+
$opener = $this->getTargetToken($testMarker, T_OPEN_PARENTHESIS);
101+
$closer = $this->getTargetToken($testMarker, T_CLOSE_PARENTHESIS);
102+
103+
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$anonClass]));
104+
$this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$anonClass]));
105+
$this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$anonClass]));
106+
$this->assertSame($anonClass, $tokens[$anonClass]['parenthesis_owner']);
107+
$this->assertSame($opener, $tokens[$anonClass]['parenthesis_opener']);
108+
$this->assertSame($closer, $tokens[$anonClass]['parenthesis_closer']);
109+
110+
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$opener]));
111+
$this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$opener]));
112+
$this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$opener]));
113+
$this->assertSame($anonClass, $tokens[$opener]['parenthesis_owner']);
114+
$this->assertSame($opener, $tokens[$opener]['parenthesis_opener']);
115+
$this->assertSame($closer, $tokens[$opener]['parenthesis_closer']);
116+
117+
$this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$closer]));
118+
$this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$closer]));
119+
$this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$closer]));
120+
$this->assertSame($anonClass, $tokens[$closer]['parenthesis_owner']);
121+
$this->assertSame($opener, $tokens[$closer]['parenthesis_opener']);
122+
$this->assertSame($closer, $tokens[$closer]['parenthesis_closer']);
123+
124+
}//end testAnonClassWithParentheses()
125+
126+
127+
/**
128+
* Data provider.
129+
*
130+
* @see testAnonClassWithParentheses()
131+
*
132+
* @return array
133+
*/
134+
public function dataAnonClassWithParentheses()
135+
{
136+
return [
137+
['/* testWithParentheses */'],
138+
['/* testWithParenthesesAndEmptyTokens */'],
139+
];
140+
141+
}//end dataAnonClassWithParentheses()
142+
143+
144+
}//end class

0 commit comments

Comments
 (0)