Skip to content

Commit 649f964

Browse files
committed
Merge branch 'master' into 4.x
2 parents d5a9218 + 3b615f2 commit 649f964

File tree

3 files changed

+71
-26
lines changed

3 files changed

+71
-26
lines changed

src/Tokenizers/PHP.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3036,6 +3036,29 @@ protected function processAdditional()
30363036
$allowed += Tokens::MAGIC_CONSTANTS;
30373037

30383038
for ($x = ($i - 1); $x >= 0; $x--) {
3039+
// Allow for PHP 8.4 anon class dereferencing without wrapping parentheses.
3040+
// Note: the T_CLASS token has not yet been retokenized to T_ANON_CLASS!
3041+
if ($this->tokens[$x]['code'] === T_CLOSE_CURLY_BRACKET
3042+
&& isset($this->tokens[$x]['scope_condition']) === true
3043+
&& $this->tokens[$this->tokens[$x]['scope_condition']]['code'] === T_CLASS
3044+
) {
3045+
// Now, make sure it is an anonymous class and not a normal class.
3046+
for ($y = ($this->tokens[$x]['scope_condition'] + 1); $y < $numTokens; $y++) {
3047+
if (isset(Tokens::$emptyTokens[$this->tokens[$y]['code']]) === false) {
3048+
break;
3049+
}
3050+
}
3051+
3052+
// Use the same check as used for the anon class retokenization.
3053+
if ($this->tokens[$y]['code'] === T_OPEN_PARENTHESIS
3054+
|| $this->tokens[$y]['code'] === T_OPEN_CURLY_BRACKET
3055+
|| $this->tokens[$y]['code'] === T_EXTENDS
3056+
|| $this->tokens[$y]['code'] === T_IMPLEMENTS
3057+
) {
3058+
break;
3059+
}
3060+
}
3061+
30393062
// If we hit a scope opener, the statement has ended
30403063
// without finding anything, so it's probably an array
30413064
// using PHP 7.1 short list syntax.

tests/Core/Tokenizers/PHP/ShortArrayTest.inc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,19 @@ $var = $obj?->function_call()[$x];
7777
/* testInterpolatedStringDereferencing */
7878
$var = "PHP{$rocks}"[1];
7979

80+
/* testNewAnonClassNoParenthesesExpressionDereferencing */
81+
$a = new class {}[0];
82+
83+
$a = new class (['value'])
84+
/* testNewAnonClassParenthesesExpressionDereferencing */
85+
{}[0];
86+
87+
/* testNewAnonClassExtendsExpressionDereferencing */
88+
$a = new readonly class extends ArrayObject {}[0];
89+
90+
/* testNewAnonClassImplementsExpressionDereferencing */
91+
$a = new class implements ArrayAccess {}[0];
92+
8093
/*
8194
* Short array brackets.
8295
*/
@@ -115,6 +128,10 @@ if ( true ) :
115128
[ $a ] = [ 'hi' ];
116129
endif;
117130

131+
class Foo extends ArrayObject {}
132+
/* testShortListDeclarationAfterClassDeclaration */
133+
[$a] = ['hi'];
134+
118135
/* testLiveCoding */
119136
// Intentional parse error. This has to be the last test in the file.
120137
$array = [

tests/Core/Tokenizers/PHP/ShortArrayTest.php

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -55,32 +55,36 @@ public function testSquareBrackets($testMarker)
5555
public static function dataSquareBrackets()
5656
{
5757
return [
58-
'array access 1' => ['/* testArrayAccess1 */'],
59-
'array access 2' => ['/* testArrayAccess2 */'],
60-
'array assignment' => ['/* testArrayAssignment */'],
61-
'function call dereferencing' => ['/* testFunctionCallDereferencing */'],
62-
'method call dereferencing' => ['/* testMethodCallDereferencing */'],
63-
'static method call dereferencing' => ['/* testStaticMethodCallDereferencing */'],
64-
'property dereferencing' => ['/* testPropertyDereferencing */'],
65-
'property dereferencing with inaccessable name' => ['/* testPropertyDereferencingWithInaccessibleName */'],
66-
'static property dereferencing' => ['/* testStaticPropertyDereferencing */'],
67-
'string dereferencing single quotes' => ['/* testStringDereferencing */'],
68-
'string dereferencing double quotes' => ['/* testStringDereferencingDoubleQuoted */'],
69-
'global constant dereferencing' => ['/* testConstantDereferencing */'],
70-
'class constant dereferencing' => ['/* testClassConstantDereferencing */'],
71-
'magic constant dereferencing' => ['/* testMagicConstantDereferencing */'],
72-
'partially qualified constant dereferencing' => ['/* testPartiallyQualifiedConstantDereferencing */'],
73-
'fully qualified constant dereferencing' => ['/* testFQNConstantDereferencing */'],
74-
'namespace relative constant dereferencing' => ['/* testNamespaceRelativeConstantDereferencing */'],
75-
'array access with curly braces' => ['/* testArrayAccessCurlyBraces */'],
76-
'array literal dereferencing' => ['/* testArrayLiteralDereferencing */'],
77-
'short array literal dereferencing' => ['/* testShortArrayLiteralDereferencing */'],
78-
'class member dereferencing on instantiation 1' => ['/* testClassMemberDereferencingOnInstantiation1 */'],
79-
'class member dereferencing on instantiation 2' => ['/* testClassMemberDereferencingOnInstantiation2 */'],
80-
'class member dereferencing on clone' => ['/* testClassMemberDereferencingOnClone */'],
81-
'nullsafe method call dereferencing' => ['/* testNullsafeMethodCallDereferencing */'],
82-
'interpolated string dereferencing' => ['/* testInterpolatedStringDereferencing */'],
83-
'live coding' => ['/* testLiveCoding */'],
58+
'array access 1' => ['/* testArrayAccess1 */'],
59+
'array access 2' => ['/* testArrayAccess2 */'],
60+
'array assignment' => ['/* testArrayAssignment */'],
61+
'function call dereferencing' => ['/* testFunctionCallDereferencing */'],
62+
'method call dereferencing' => ['/* testMethodCallDereferencing */'],
63+
'static method call dereferencing' => ['/* testStaticMethodCallDereferencing */'],
64+
'property dereferencing' => ['/* testPropertyDereferencing */'],
65+
'property dereferencing with inaccessable name' => ['/* testPropertyDereferencingWithInaccessibleName */'],
66+
'static property dereferencing' => ['/* testStaticPropertyDereferencing */'],
67+
'string dereferencing single quotes' => ['/* testStringDereferencing */'],
68+
'string dereferencing double quotes' => ['/* testStringDereferencingDoubleQuoted */'],
69+
'global constant dereferencing' => ['/* testConstantDereferencing */'],
70+
'class constant dereferencing' => ['/* testClassConstantDereferencing */'],
71+
'magic constant dereferencing' => ['/* testMagicConstantDereferencing */'],
72+
'partially qualified constant dereferencing' => ['/* testPartiallyQualifiedConstantDereferencing */'],
73+
'fully qualified constant dereferencing' => ['/* testFQNConstantDereferencing */'],
74+
'namespace relative constant dereferencing' => ['/* testNamespaceRelativeConstantDereferencing */'],
75+
'array access with curly braces' => ['/* testArrayAccessCurlyBraces */'],
76+
'array literal dereferencing' => ['/* testArrayLiteralDereferencing */'],
77+
'short array literal dereferencing' => ['/* testShortArrayLiteralDereferencing */'],
78+
'class member dereferencing on instantiation 1' => ['/* testClassMemberDereferencingOnInstantiation1 */'],
79+
'class member dereferencing on instantiation 2' => ['/* testClassMemberDereferencingOnInstantiation2 */'],
80+
'class member dereferencing on clone' => ['/* testClassMemberDereferencingOnClone */'],
81+
'nullsafe method call dereferencing' => ['/* testNullsafeMethodCallDereferencing */'],
82+
'interpolated string dereferencing' => ['/* testInterpolatedStringDereferencing */'],
83+
'new anonymous class expression dereferencing 1' => ['/* testNewAnonClassNoParenthesesExpressionDereferencing */'],
84+
'new anonymous class expression dereferencing 2' => ['/* testNewAnonClassParenthesesExpressionDereferencing */'],
85+
'new anonymous class expression dereferencing 3' => ['/* testNewAnonClassExtendsExpressionDereferencing */'],
86+
'new anonymous class expression dereferencing 4' => ['/* testNewAnonClassImplementsExpressionDereferencing */'],
87+
'live coding' => ['/* testLiveCoding */'],
8488
];
8589

8690
}//end dataSquareBrackets()
@@ -136,6 +140,7 @@ public static function dataShortArrays()
136140
'short list after braced control structure' => ['/* testShortListDeclarationAfterBracedControlStructure */'],
137141
'short list after non-braced control structure' => ['/* testShortListDeclarationAfterNonBracedControlStructure */'],
138142
'short list after alternative control structure' => ['/* testShortListDeclarationAfterAlternativeControlStructure */'],
143+
'short list after class declaration' => ['/* testShortListDeclarationAfterClassDeclaration */'],
139144
];
140145

141146
}//end dataShortArrays()

0 commit comments

Comments
 (0)