Skip to content

Commit c91c8a1

Browse files
authored
Merge pull request microsoft#342 from TysonAndre/anonymous-class-attributes
Also handle attributes in `new #[MyAttr] class {...}`, traits, interfaces
2 parents 917e065 + ba3805b commit c91c8a1

File tree

79 files changed

+910
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+910
-1
lines changed

src/Node/Expression/ObjectCreationExpression.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
namespace Microsoft\PhpParser\Node\Expression;
88

9+
use Microsoft\PhpParser\Node\AttributeGroup;
910
use Microsoft\PhpParser\Node\ClassBaseClause;
1011
use Microsoft\PhpParser\Node\ClassInterfaceClause;
1112
use Microsoft\PhpParser\Node\ClassMembersNode;
@@ -19,6 +20,9 @@ class ObjectCreationExpression extends Expression {
1920
/** @var Token */
2021
public $newKeword;
2122

23+
/** @var AttributeGroup[]|null optional attributes of an anonymous class. */
24+
public $attributes;
25+
2226
/** @var QualifiedName|Variable|Token */
2327
public $classTypeDesignator;
2428

@@ -41,7 +45,8 @@ class ObjectCreationExpression extends Expression {
4145
public $classMembers;
4246

4347
const CHILD_NAMES = [
44-
'newKeword', // TODO
48+
'newKeword',
49+
'attributes',
4550
'classTypeDesignator',
4651
'openParen',
4752
'argumentExpressionList',

src/Node/Statement/InterfaceDeclaration.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Microsoft\PhpParser\ClassLike;
1010
use Microsoft\PhpParser\NamespacedNameInterface;
1111
use Microsoft\PhpParser\NamespacedNameTrait;
12+
use Microsoft\PhpParser\Node\AttributeGroup;
1213
use Microsoft\PhpParser\Node\InterfaceBaseClause;
1314
use Microsoft\PhpParser\Node\InterfaceMembers;
1415
use Microsoft\PhpParser\Node\StatementNode;
@@ -17,6 +18,9 @@
1718
class InterfaceDeclaration extends StatementNode implements NamespacedNameInterface, ClassLike {
1819
use NamespacedNameTrait;
1920

21+
/** @var AttributeGroup[]|null */
22+
public $attributes;
23+
2024
/** @var Token */
2125
public $interfaceKeyword;
2226

@@ -30,6 +34,7 @@ class InterfaceDeclaration extends StatementNode implements NamespacedNameInterf
3034
public $interfaceMembers;
3135

3236
const CHILD_NAMES = [
37+
'attributes',
3338
'interfaceKeyword',
3439
'name',
3540
'interfaceBaseClause',

src/Node/Statement/TraitDeclaration.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,17 @@
99
use Microsoft\PhpParser\ClassLike;
1010
use Microsoft\PhpParser\NamespacedNameInterface;
1111
use Microsoft\PhpParser\NamespacedNameTrait;
12+
use Microsoft\PhpParser\Node\AttributeGroup;
1213
use Microsoft\PhpParser\Node\StatementNode;
1314
use Microsoft\PhpParser\Node\TraitMembers;
1415
use Microsoft\PhpParser\Token;
1516

1617
class TraitDeclaration extends StatementNode implements NamespacedNameInterface, ClassLike {
1718
use NamespacedNameTrait;
1819

20+
/** @var AttributeGroup[]|null */
21+
public $attributes;
22+
1923
/** @var Token */
2024
public $traitKeyword;
2125

@@ -26,6 +30,7 @@ class TraitDeclaration extends StatementNode implements NamespacedNameInterface,
2630
public $traitMembers;
2731

2832
const CHILD_NAMES = [
33+
'attributes',
2934
'traitKeyword',
3035
'name',
3136
'traitMembers'

src/Parser.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,12 @@ private function parseAttributeStatement($parentNode) {
711711
if ($parentNode instanceof ClassMembersNode) {
712712
// Create a class element or a MissingMemberDeclaration
713713
$statement = $this->parseClassElementFn()($parentNode);
714+
} elseif ($parentNode instanceof TraitMembers) {
715+
// Create a trait element or a MissingMemberDeclaration
716+
$statement = $this->parseTraitElementFn()($parentNode);
717+
} elseif ($parentNode instanceof InterfaceMembers) {
718+
// Create an interface element or a MissingMemberDeclaration
719+
$statement = $this->parseInterfaceElementFn()($parentNode);
714720
} else {
715721
// Classlikes, anonymous functions, global functions, and arrow functions can have attributes. Global constants cannot.
716722
if (in_array($this->token->kind, [TokenKind::ClassKeyword, TokenKind::TraitKeyword, TokenKind::InterfaceKeyword, TokenKind::AbstractKeyword, TokenKind::FinalKeyword, TokenKind::FunctionKeyword, TokenKind::FnKeyword], true) ||
@@ -726,6 +732,8 @@ private function parseAttributeStatement($parentNode) {
726732

727733
if ($statement instanceof FunctionLike ||
728734
$statement instanceof ClassDeclaration ||
735+
$statement instanceof TraitDeclaration ||
736+
$statement instanceof InterfaceDeclaration ||
729737
$statement instanceof ClassConstDeclaration ||
730738
$statement instanceof PropertyDeclaration ||
731739
$statement instanceof MissingDeclaration ||
@@ -3088,6 +3096,12 @@ private function parseObjectCreationExpression($parentNode) {
30883096
// TODO - add tests for this scenario
30893097
$oldIsParsingObjectCreationExpression = $this->isParsingObjectCreationExpression;
30903098
$this->isParsingObjectCreationExpression = true;
3099+
3100+
if ($this->getCurrentToken()->kind === TokenKind::AttributeToken) {
3101+
// Attributes such as `new #[MyAttr] class` can only be used with anonymous class declarations.
3102+
// But handle this like $objectCreationExpression->classMembers and leave it up to the applications to detect the invalid combination.
3103+
$objectCreationExpression->attributes = $this->parseAttributeGroups($objectCreationExpression);
3104+
}
30913105
$objectCreationExpression->classTypeDesignator =
30923106
$this->eatOptional1(TokenKind::ClassKeyword) ??
30933107
$this->parseExpression($objectCreationExpression);
@@ -3311,6 +3325,9 @@ private function parseInterfaceElementFn() {
33113325
case TokenKind::FunctionKeyword:
33123326
return $this->parseMethodDeclaration($parentNode, $modifiers);
33133327

3328+
case TokenKind::AttributeToken:
3329+
return $this->parseAttributeStatement($parentNode);
3330+
33143331
default:
33153332
$missingInterfaceMemberDeclaration = new MissingMemberDeclaration();
33163333
$missingInterfaceMemberDeclaration->parent = $parentNode;
@@ -3491,6 +3508,9 @@ private function parseTraitElementFn() {
34913508
case TokenKind::UseKeyword:
34923509
return $this->parseTraitUseClause($parentNode);
34933510

3511+
case TokenKind::AttributeToken:
3512+
return $this->parseAttributeStatement($parentNode);
3513+
34943514
default:
34953515
return $this->parseRemainingPropertyDeclarationOrMissingMemberDeclaration($parentNode, $modifiers);
34963516
}

tests/cases/parser/callExpression14.php.tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"kind": "NewKeyword",
2828
"textLength": 3
2929
},
30+
"attributes": null,
3031
"classTypeDesignator": {
3132
"QualifiedName": {
3233
"globalSpecifier": null,

tests/cases/parser/interfaceDeclaration1.php.tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
},
1414
{
1515
"InterfaceDeclaration": {
16+
"attributes": null,
1617
"interfaceKeyword": {
1718
"kind": "InterfaceKeyword",
1819
"textLength": 9

tests/cases/parser/interfaceDeclaration10.php.tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
},
1414
{
1515
"InterfaceDeclaration": {
16+
"attributes": null,
1617
"interfaceKeyword": {
1718
"kind": "InterfaceKeyword",
1819
"textLength": 9

tests/cases/parser/interfaceDeclaration11.php.tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
},
1414
{
1515
"InterfaceDeclaration": {
16+
"attributes": null,
1617
"interfaceKeyword": {
1718
"kind": "InterfaceKeyword",
1819
"textLength": 9

tests/cases/parser/interfaceDeclaration12.php.tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
},
1414
{
1515
"InterfaceDeclaration": {
16+
"attributes": null,
1617
"interfaceKeyword": {
1718
"kind": "InterfaceKeyword",
1819
"textLength": 9

tests/cases/parser/interfaceDeclaration13.php.tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
},
1414
{
1515
"InterfaceDeclaration": {
16+
"attributes": null,
1617
"interfaceKeyword": {
1718
"kind": "InterfaceKeyword",
1819
"textLength": 9

0 commit comments

Comments
 (0)