Skip to content

Commit 329ef95

Browse files
authored
Merge pull request #10 from phan/attributes-on-global-constants
Attributes on global constants
2 parents b708a8c + 1f4bffc commit 329ef95

20 files changed

+1997
-9
lines changed

TOLERANT_TODO.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,14 @@ Monitor RFCs merged into php-src and mirror the token/grammar changes:
7272
- `final readonly string $prop` - With readonly
7373
- `public readonly final string $prop` - All modifiers combined
7474
- Tested in `tests/cases/parser85/final-promotion-*.php` (5 comprehensive tests)
75-
- **Attributes on constants / extended attribute targets**: verify attributes on constants and traits are preserved.
76-
- **Extend `#[\Override]` to properties / `#[\NoDiscard]` / `#[\DelayedTargetValidation]`**: attributes already parse, but add regression coverage to ensure tolerant does not misclassify their targets.
75+
- **Extended attribute targets** (`#[Deprecated] const FOO = 1;`): ✅ **COMPLETE**
76+
- Added support for attributes on global constants (PHP 8.5+)
77+
- Updated Parser.php to include `TokenKind::ConstKeyword` in allowed attribute targets
78+
- Added `attributes` field to `ConstDeclaration` node
79+
- Added `ConstDeclaration` to instanceof check for attaching attributes
80+
- Verified attributes on class constants still work correctly
81+
- Verified `#[Override]` on properties works correctly (PHP 8.5+)
82+
- Tested in `tests/cases/parser85/attributes-*.php` and `tests/cases/parser85/override-on-property.php`
7783
- Track any additional keywords (`with`, operator tokens, etc.) and update `TokenKind.php` / `TokenStringMaps.php` accordingly.
7884

7985
### Diagnostics & Node Mapping
@@ -111,23 +117,22 @@ Recommended sample inputs for AST diffs (update as new fixtures are added):
111117
| Pipe operator | `tests/cases/parser85/pipe-operator-*.php` | 8.5 || `php ~/phan/tools/dump_ast.php --json …` | `php tools/PrintTolerantAst.php …`, `php ~/phan/internal/dump_fallback_ast.php --php-ast …` |
112118
| Clone with modifications | `tests/cases/parser85/clone-*.php` | 8.5 || (run after `sudo newphp 85`) | same as above |
113119
| Final property promotion | `tests/cases/parser85/final-promotion-*.php` | 8.5 || (run after `sudo newphp 85`) | same as above |
120+
| Extended attribute targets | `tests/cases/parser85/attributes-*.php`, `tests/cases/parser85/override-on-property.php` | 8.5 || (run after `sudo newphp 85`) | same as above |
114121

115122
## Completed Work Summary
116123

117124
As of October 2025, the tolerant parser now has full support for:
118125

119126
- **PHP 8.3**: Dynamic class constant fetch, typed class constants (including union types)
120127
- **PHP 8.4**: Property hooks (with modifiers and edge cases), asymmetric visibility, new without parenthesis, deprecation fixes
121-
- **PHP 8.5**: Pipe operator, clone with property modifications, final property promotion
128+
- **PHP 8.5**: Pipe operator, clone with property modifications, final property promotion, extended attribute targets
122129

123-
**Test Coverage**: 31,463 tests passing across all PHP versions (8.1-8.5)
130+
**Test Coverage**: 31,468 tests passing across all PHP versions (8.1-8.5)
124131
**CI Configuration**: Updated to test on PHP 8.1, 8.2, 8.3, 8.4, 8.5.0RC1-cli
125132

126133
## Next Steps
127134

128-
Remaining PHP 8.5 features to implement:
129-
130-
1. **Extended attribute targets** - Verify attributes work on new targets (constants, properties, etc.)
135+
All major PHP 8.3, 8.4, and 8.5 features are now implemented! ✅
131136

132137
Additional tasks:
133138

src/Node/Statement/ConstDeclaration.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
use Microsoft\PhpParser\Token;
1212

1313
class ConstDeclaration extends StatementNode {
14+
/** @var array|null */
15+
public $attributes;
16+
1417
/** @var Token */
1518
public $constKeyword;
1619

@@ -21,6 +24,7 @@ class ConstDeclaration extends StatementNode {
2124
public $semicolon;
2225

2326
const CHILD_NAMES = [
27+
'attributes',
2428
'constKeyword',
2529
'constElements',
2630
'semicolon'

src/Parser.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -758,8 +758,8 @@ private function parseAttributeStatement($parentNode) {
758758
// Create an interface element or a MissingMemberDeclaration
759759
$statement = $this->parseInterfaceElementFn()($parentNode);
760760
} else {
761-
// Classlikes, anonymous functions, global functions, and arrow functions can have attributes. Global constants cannot.
762-
if (in_array($this->token->kind, [TokenKind::ReadonlyKeyword, TokenKind::ClassKeyword, TokenKind::TraitKeyword, TokenKind::InterfaceKeyword, TokenKind::AbstractKeyword, TokenKind::FinalKeyword, TokenKind::FunctionKeyword, TokenKind::FnKeyword, TokenKind::EnumKeyword], true) ||
761+
// Classlikes, anonymous functions, global functions, arrow functions, and global constants (PHP 8.5+) can have attributes.
762+
if (in_array($this->token->kind, [TokenKind::ReadonlyKeyword, TokenKind::ClassKeyword, TokenKind::TraitKeyword, TokenKind::InterfaceKeyword, TokenKind::AbstractKeyword, TokenKind::FinalKeyword, TokenKind::FunctionKeyword, TokenKind::FnKeyword, TokenKind::EnumKeyword, TokenKind::ConstKeyword], true) ||
763763
$this->token->kind === TokenKind::StaticKeyword && $this->lookahead([TokenKind::FunctionKeyword, TokenKind::FnKeyword])) {
764764
$statement = $this->parseStatement($parentNode);
765765
} else {
@@ -778,6 +778,7 @@ private function parseAttributeStatement($parentNode) {
778778
$statement instanceof InterfaceDeclaration ||
779779
$statement instanceof ClassConstDeclaration ||
780780
$statement instanceof PropertyDeclaration ||
781+
$statement instanceof ConstDeclaration ||
781782
$statement instanceof MissingDeclaration ||
782783
$statement instanceof MissingMemberDeclaration) {
783784

tests/cases/parser/constDeclaration1.php.tree

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

tests/cases/parser/constDeclaration10.php.tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
},
1919
{
2020
"ConstDeclaration": {
21+
"attributes": null,
2122
"constKeyword": {
2223
"kind": "ConstKeyword",
2324
"textLength": 5

tests/cases/parser/constDeclaration2.php.tree

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

tests/cases/parser/constDeclaration3.php.tree

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

tests/cases/parser/constDeclaration4.php.tree

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

tests/cases/parser/constDeclaration5.php.tree

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

tests/cases/parser/constDeclaration8.php.tree

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

0 commit comments

Comments
 (0)