Skip to content

Commit 4c28423

Browse files
committed
Add basic support for new-in-initializer
1 parent 536889f commit 4c28423

File tree

4 files changed

+123
-2
lines changed

4 files changed

+123
-2
lines changed
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\PhpDocParser\Ast\ConstExpr;
4+
5+
use PHPStan\PhpDocParser\Ast\NodeAttributes;
6+
use function implode;
7+
8+
class ConstExprNewNode implements ConstExprNode
9+
{
10+
11+
use NodeAttributes;
12+
13+
/** @var string */
14+
public $class;
15+
16+
/** @var ConstExprNode[] */
17+
public $arguments;
18+
19+
/**
20+
* @param ConstExprNode[] $arguments
21+
*/
22+
public function __construct(string $class, array $arguments)
23+
{
24+
$this->class = $class;
25+
$this->arguments = $arguments;
26+
}
27+
28+
29+
public function __toString(): string
30+
{
31+
return 'new ' . $this->class . '(' . implode(', ', $this->arguments) . ')';
32+
}
33+
34+
}

src/Parser/ConstExprParser.php

+26
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\Con
183183
case 'array':
184184
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);
185185
return $this->parseArray($tokens, Lexer::TOKEN_CLOSE_PARENTHESES, $startIndex);
186+
case 'new':
187+
return $this->parseNew($tokens, $startIndex);
186188
}
187189

188190
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
@@ -269,6 +271,30 @@ private function parseArray(TokenIterator $tokens, int $endToken, int $startInde
269271
}
270272

271273

274+
private function parseNew(TokenIterator $tokens, int $startIndex): Ast\ConstExpr\ConstExprNewNode
275+
{
276+
$startLine = $tokens->currentTokenLine();
277+
278+
$class = $tokens->currentTokenValue();
279+
$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
280+
281+
$arguments = [];
282+
if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
283+
do {
284+
$arguments[] = $this->parse($tokens);
285+
} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA) && !$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES));
286+
$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
287+
}
288+
289+
return $this->enrichWithAttributes(
290+
$tokens,
291+
new Ast\ConstExpr\ConstExprNewNode($class, $arguments),
292+
$startLine,
293+
$startIndex
294+
);
295+
}
296+
297+
272298
/**
273299
* This method is supposed to be called with TokenIterator after reading TOKEN_DOUBLE_QUOTED_STRING and shifting
274300
* to the next token.

src/Parser/TypeParser.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
221221

222222
try {
223223
$constExpr = $this->constExprParser->parse($tokens, true);
224-
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
224+
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode || $constExpr instanceof Ast\ConstExpr\ConstExprNewNode) {
225225
throw new ParserException(
226226
$currentTokenValue,
227227
$currentTokenType,
@@ -732,7 +732,7 @@ private function parseCallableReturnType(TokenIterator $tokens): Ast\Type\TypeNo
732732

733733
try {
734734
$constExpr = $this->constExprParser->parse($tokens, true);
735-
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
735+
if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode || $constExpr instanceof Ast\ConstExpr\ConstExprNewNode) {
736736
throw new ParserException(
737737
$currentTokenValue,
738738
$currentTokenType,

tests/PHPStan/Parser/PhpDocParserTest.php

+61
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprArrayItemNode;
99
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprArrayNode;
1010
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode;
11+
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNewNode;
1112
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
1213
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
1314
use PHPStan\PhpDocParser\Ast\ConstExpr\DoctrineConstExprStringNode;
@@ -2762,6 +2763,66 @@ public function provideMethodTagsData(): Iterator
27622763
),
27632764
]),
27642765
];
2766+
2767+
yield [
2768+
'OK static with parameter using new in initializer',
2769+
'/** @method static void myFunction(DateInterval $date = new DateInterval("P1Y")) */',
2770+
new PhpDocNode([
2771+
new PhpDocTagNode(
2772+
'@method',
2773+
new MethodTagValueNode(
2774+
true,
2775+
new IdentifierTypeNode('void'),
2776+
'myFunction',
2777+
[
2778+
new MethodTagValueParameterNode(
2779+
new IdentifierTypeNode('DateInterval'),
2780+
false,
2781+
false,
2782+
'$date',
2783+
new ConstExprNewNode(
2784+
'DateInterval',
2785+
[
2786+
new ConstExprStringNode('"P1Y"'),
2787+
]
2788+
)
2789+
),
2790+
],
2791+
''
2792+
)
2793+
),
2794+
]),
2795+
];
2796+
2797+
yield [
2798+
'OK static with parameter using new in initializer with nested new',
2799+
'/** @method static void myFunction(SomeClass $object = new SomeClass(new SomeClass)) */',
2800+
new PhpDocNode([
2801+
new PhpDocTagNode(
2802+
'@method',
2803+
new MethodTagValueNode(
2804+
true,
2805+
new IdentifierTypeNode('void'),
2806+
'myFunction',
2807+
[
2808+
new MethodTagValueParameterNode(
2809+
new IdentifierTypeNode('SomeClass'),
2810+
false,
2811+
false,
2812+
'$object',
2813+
new ConstExprNewNode(
2814+
'SomeClass',
2815+
[
2816+
new ConstExprNewNode('SomeClass', []),
2817+
]
2818+
)
2819+
),
2820+
],
2821+
''
2822+
)
2823+
),
2824+
]),
2825+
];
27652826
}
27662827

27672828

0 commit comments

Comments
 (0)