Skip to content

Commit 7380e7d

Browse files
committed
Add class constant masks, class constants and const masks in array keys (compat with phpstan parser v2.3 https://github.com/phpstan/phpdoc-parser/releases/tag/2.3.0)
1 parent b9a8294 commit 7380e7d

File tree

9 files changed

+96
-14
lines changed

9 files changed

+96
-14
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
"phpstan/phpstan": "^2.1",
2727
"phpstan/phpstan-strict-rules": "^2.0",
2828
"phpunit/phpunit": "^10.5|^11.0|^12.0",
29-
"symfony/var-dumper": "^6.4|^7.0"
29+
"symfony/var-dumper": "^6.4|^7.0",
30+
"type-lang/printer": "^1.3"
3031
},
3132
"autoload-dev": {
3233
"psr-4": {

resources/grammar.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@
207207
new \Phplrt\Parser\Grammar\Concatenation([133]),
208208
new \Phplrt\Parser\Grammar\Optional(54),
209209
new \Phplrt\Parser\Grammar\Alternation([127, 128]),
210-
new \Phplrt\Parser\Grammar\Alternation([3, 23, 21]),
210+
new \Phplrt\Parser\Grammar\Alternation([18, 19, 3, 23, 21]),
211211
new \Phplrt\Parser\Grammar\Lexeme('T_QMARK', true),
212212
new \Phplrt\Parser\Grammar\Concatenation([59]),
213213
new \Phplrt\Parser\Grammar\Optional(132),
@@ -558,7 +558,7 @@
558558

559559
foreach ($children as $field) {
560560
if ($field instanceof Node\Stmt\Shape\ExplicitFieldNode) {
561-
$key = $field->getKey();
561+
$key = $field->getHashString();
562562

563563
if (\in_array($key, $explicit, true)) {
564564
throw SemanticException::fromShapeFieldDuplication($key, $field->offset);
@@ -632,6 +632,10 @@
632632
=> new Node\Stmt\Shape\NumericFieldNode($name, $value, $optional),
633633
$name instanceof Node\Literal\StringLiteralNode
634634
=> new Node\Stmt\Shape\StringNamedFieldNode($name, $value, $optional),
635+
$name instanceof Node\Stmt\ClassConstMaskNode
636+
=> new Node\Stmt\Shape\ClassConstMaskFieldNode($name, $value, $optional),
637+
$name instanceof Node\Stmt\ConstMaskNode
638+
=> new Node\Stmt\Shape\ConstMaskFieldNode($name, $value, $optional),
635639
default => new Node\Stmt\Shape\NamedFieldNode($name, $value, $optional),
636640
};
637641
},

resources/grammar/shape-fields.pp2

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ ShapeFieldsList -> {
4343

4444
foreach ($children as $field) {
4545
if ($field instanceof Node\Stmt\Shape\ExplicitFieldNode) {
46-
$key = $field->getKey();
46+
$key = $field->getHashString();
4747

4848
if (\in_array($key, $explicit, true)) {
4949
throw SemanticException::fromShapeFieldDuplication($key, $field->offset);
@@ -97,6 +97,10 @@ ExplicitField -> {
9797
=> new Node\Stmt\Shape\NumericFieldNode($name, $value, $optional),
9898
$name instanceof Node\Literal\StringLiteralNode
9999
=> new Node\Stmt\Shape\StringNamedFieldNode($name, $value, $optional),
100+
$name instanceof Node\Stmt\ClassConstMaskNode
101+
=> new Node\Stmt\Shape\ClassConstMaskFieldNode($name, $value, $optional),
102+
$name instanceof Node\Stmt\ConstMaskNode
103+
=> new Node\Stmt\Shape\ConstMaskFieldNode($name, $value, $optional),
100104
default => new Node\Stmt\Shape\NamedFieldNode($name, $value, $optional),
101105
};
102106
}
@@ -110,7 +114,9 @@ ImplicitField -> {
110114
;
111115

112116
ShapeKey
113-
: Identifier()
117+
: ConstMaskLiteral()
118+
| ClassConstLiteral()
119+
| Identifier()
114120
| IntLiteral()
115121
| StringLiteral()
116122
;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TypeLang\Parser\Node\Stmt\Shape;
6+
7+
use TypeLang\Parser\Node\Stmt\Attribute\AttributeGroupsListNode;
8+
use TypeLang\Parser\Node\Stmt\ClassConstMaskNode;
9+
use TypeLang\Parser\Node\Stmt\TypeStatement;
10+
11+
final class ClassConstMaskFieldNode extends ExplicitFieldNode
12+
{
13+
public function __construct(
14+
public ClassConstMaskNode $key,
15+
TypeStatement $of,
16+
bool $optional = false,
17+
?AttributeGroupsListNode $attributes = null,
18+
) {
19+
parent::__construct($of, $optional, $attributes);
20+
}
21+
22+
public function getHashString(): string
23+
{
24+
$key = $this->key::class . ':'
25+
. $this->key->class->toString()
26+
. '::' . $this->key->constant?->toString();
27+
28+
return \hash('xxh3', $key);
29+
}
30+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace TypeLang\Parser\Node\Stmt\Shape;
6+
7+
use TypeLang\Parser\Node\Stmt\Attribute\AttributeGroupsListNode;
8+
use TypeLang\Parser\Node\Stmt\ConstMaskNode;
9+
use TypeLang\Parser\Node\Stmt\TypeStatement;
10+
11+
final class ConstMaskFieldNode extends ExplicitFieldNode
12+
{
13+
public function __construct(
14+
public ConstMaskNode $key,
15+
TypeStatement $of,
16+
bool $optional = false,
17+
?AttributeGroupsListNode $attributes = null,
18+
) {
19+
parent::__construct($of, $optional, $attributes);
20+
}
21+
22+
public function getHashString(): string
23+
{
24+
$key = $this->key::class . ':'
25+
. $this->key->name->toString();
26+
27+
return \hash('xxh3', $key);
28+
}
29+
}

src/Node/Stmt/Shape/ExplicitFieldNode.php

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

77
abstract class ExplicitFieldNode extends FieldNode
88
{
9-
abstract public function getKey(): int|string;
9+
/**
10+
* @deprecated Please use {@see getHashString()} instead
11+
*/
12+
public function getKey(): int|string
13+
{
14+
return $this->getHashString();
15+
}
16+
17+
/**
18+
* @return non-empty-string
19+
*/
20+
abstract public function getHashString(): string;
1021
}

src/Node/Stmt/Shape/NamedFieldNode.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@ public function __construct(
2626
parent::__construct($of, $optional, $attributes);
2727
}
2828

29-
public function getKey(): string
29+
public function getHashString(): string
3030
{
31-
/** @var non-empty-string */
32-
return $this->key->toString();
31+
return \hash('xxh3', self::class . ':' . $this->key->toString());
3332
}
3433
}

src/Node/Stmt/Shape/NumericFieldNode.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,9 @@ public function getKey(): int
2323
{
2424
return $this->key->getValue();
2525
}
26+
27+
public function getHashString(): string
28+
{
29+
return \hash('xxh3', self::class . ':' . $this->key->getRawValue());
30+
}
2631
}

src/Node/Stmt/Shape/StringNamedFieldNode.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88
use TypeLang\Parser\Node\Stmt\Attribute\AttributeGroupsListNode;
99
use TypeLang\Parser\Node\Stmt\TypeStatement;
1010

11-
/**
12-
* TODO Add name non-emptiness assertion
13-
*/
1411
final class StringNamedFieldNode extends ExplicitFieldNode
1512
{
1613
public function __construct(
@@ -22,8 +19,8 @@ public function __construct(
2219
parent::__construct($of, $optional, $attributes);
2320
}
2421

25-
public function getKey(): string
22+
public function getHashString(): string
2623
{
27-
return $this->key->getValue();
24+
return \hash('xxh3', self::class . ':' . $this->key->getValue());
2825
}
2926
}

0 commit comments

Comments
 (0)