Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 12c4e9f

Browse files
Merge remote-tracking branch 'origin/2.0.x' into 2.1.x
2 parents dc7c469 + 51087f8 commit 12c4e9f

File tree

2 files changed

+188
-0
lines changed

2 files changed

+188
-0
lines changed

‎src/Parser/TypeParser.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,14 @@ private function parseUnion(TokenIterator $tokens, Ast\Type\TypeNode $type): Ast
271271

272272
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_UNION)) {
273273
$types[] = $this->parseAtomic($tokens);
274+
$tokens->pushSavePoint();
275+
$tokens->skipNewLineTokens();
276+
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {
277+
$tokens->rollback();
278+
break;
279+
}
280+
281+
$tokens->dropSavePoint();
274282
}
275283

276284
return new Ast\Type\UnionTypeNode($types);
@@ -299,6 +307,14 @@ private function parseIntersection(TokenIterator $tokens, Ast\Type\TypeNode $typ
299307

300308
while ($tokens->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) {
301309
$types[] = $this->parseAtomic($tokens);
310+
$tokens->pushSavePoint();
311+
$tokens->skipNewLineTokens();
312+
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) {
313+
$tokens->rollback();
314+
break;
315+
}
316+
317+
$tokens->dropSavePoint();
302318
}
303319

304320
return new Ast\Type\IntersectionTypeNode($types);

‎tests/PHPStan/Parser/PhpDocParserTest.php

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode;
6161
use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode;
6262
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
63+
use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode;
6364
use PHPStan\PhpDocParser\Ast\Type\InvalidTypeNode;
6465
use PHPStan\PhpDocParser\Ast\Type\NullableTypeNode;
6566
use PHPStan\PhpDocParser\Ast\Type\ObjectShapeItemNode;
@@ -71,6 +72,7 @@
7172
use PHPUnit\Framework\TestCase;
7273
use function count;
7374
use function sprintf;
75+
use const DIRECTORY_SEPARATOR;
7476
use const PHP_EOL;
7577

7678
class PhpDocParserTest extends TestCase
@@ -4211,6 +4213,176 @@ public function provideMultiLinePhpDocData(): iterable
42114213
]),
42124214
];
42134215

4216+
yield [
4217+
'Multiline PHPDoc with multiple new line within union type declaration',
4218+
'/**' . PHP_EOL .
4219+
' * @param array<string, array{' . PHP_EOL .
4220+
' * foo: int,' . PHP_EOL .
4221+
' * bar?: array<string,' . PHP_EOL .
4222+
' * array{foo1: int, bar1?: true}' . PHP_EOL .
4223+
' * | array{foo1: int, foo2: true, bar1?: true}' . PHP_EOL .
4224+
' * | array{foo2: int, foo3: bool, bar2?: true}' . PHP_EOL .
4225+
' * | array{foo1: int, foo3: true, bar3?: false}' . PHP_EOL .
4226+
' * >,' . PHP_EOL .
4227+
' * }> $a' . PHP_EOL .
4228+
' */',
4229+
new PhpDocNode([
4230+
new PhpDocTagNode('@param', new ParamTagValueNode(
4231+
new GenericTypeNode(
4232+
new IdentifierTypeNode('array'),
4233+
[
4234+
new IdentifierTypeNode('string'),
4235+
ArrayShapeNode::createSealed([
4236+
new ArrayShapeItemNode(new IdentifierTypeNode('foo'), false, new IdentifierTypeNode('int')),
4237+
new ArrayShapeItemNode(new IdentifierTypeNode('bar'), true, new GenericTypeNode(
4238+
new IdentifierTypeNode('array'),
4239+
[
4240+
new IdentifierTypeNode('string'),
4241+
new UnionTypeNode([
4242+
ArrayShapeNode::createSealed([
4243+
new ArrayShapeItemNode(new IdentifierTypeNode('foo1'), false, new IdentifierTypeNode('int')),
4244+
new ArrayShapeItemNode(new IdentifierTypeNode('bar1'), true, new IdentifierTypeNode('true')),
4245+
]),
4246+
ArrayShapeNode::createSealed([
4247+
new ArrayShapeItemNode(new IdentifierTypeNode('foo1'), false, new IdentifierTypeNode('int')),
4248+
new ArrayShapeItemNode(new IdentifierTypeNode('foo2'), false, new IdentifierTypeNode('true')),
4249+
new ArrayShapeItemNode(new IdentifierTypeNode('bar1'), true, new IdentifierTypeNode('true')),
4250+
]),
4251+
ArrayShapeNode::createSealed([
4252+
new ArrayShapeItemNode(new IdentifierTypeNode('foo2'), false, new IdentifierTypeNode('int')),
4253+
new ArrayShapeItemNode(new IdentifierTypeNode('foo3'), false, new IdentifierTypeNode('bool')),
4254+
new ArrayShapeItemNode(new IdentifierTypeNode('bar2'), true, new IdentifierTypeNode('true')),
4255+
]),
4256+
ArrayShapeNode::createSealed([
4257+
new ArrayShapeItemNode(new IdentifierTypeNode('foo1'), false, new IdentifierTypeNode('int')),
4258+
new ArrayShapeItemNode(new IdentifierTypeNode('foo3'), false, new IdentifierTypeNode('true')),
4259+
new ArrayShapeItemNode(new IdentifierTypeNode('bar3'), true, new IdentifierTypeNode('false')),
4260+
]),
4261+
]),
4262+
],
4263+
[
4264+
GenericTypeNode::VARIANCE_INVARIANT,
4265+
GenericTypeNode::VARIANCE_INVARIANT,
4266+
],
4267+
)),
4268+
]),
4269+
],
4270+
[
4271+
GenericTypeNode::VARIANCE_INVARIANT,
4272+
GenericTypeNode::VARIANCE_INVARIANT,
4273+
],
4274+
),
4275+
false,
4276+
'$a',
4277+
'',
4278+
false,
4279+
)),
4280+
]),
4281+
];
4282+
4283+
yield [
4284+
'Multiline PHPDoc with multiple new line within intersection type declaration',
4285+
'/**' . PHP_EOL .
4286+
' * @param array<string, array{' . PHP_EOL .
4287+
' * foo: int,' . PHP_EOL .
4288+
' * bar?: array<string,' . PHP_EOL .
4289+
' * array{foo1: int, bar1?: true}' . PHP_EOL .
4290+
' * & array{foo1: int, foo2: true, bar1?: true}' . PHP_EOL .
4291+
' * & array{foo2: int, foo3: bool, bar2?: true}' . PHP_EOL .
4292+
' * & array{foo1: int, foo3: true, bar3?: false}' . PHP_EOL .
4293+
' * >,' . PHP_EOL .
4294+
' * }> $a' . PHP_EOL .
4295+
' */',
4296+
new PhpDocNode([
4297+
new PhpDocTagNode('@param', new ParamTagValueNode(
4298+
new GenericTypeNode(
4299+
new IdentifierTypeNode('array'),
4300+
[
4301+
new IdentifierTypeNode('string'),
4302+
ArrayShapeNode::createSealed([
4303+
new ArrayShapeItemNode(new IdentifierTypeNode('foo'), false, new IdentifierTypeNode('int')),
4304+
new ArrayShapeItemNode(new IdentifierTypeNode('bar'), true, new GenericTypeNode(
4305+
new IdentifierTypeNode('array'),
4306+
[
4307+
new IdentifierTypeNode('string'),
4308+
new IntersectionTypeNode([
4309+
ArrayShapeNode::createSealed([
4310+
new ArrayShapeItemNode(new IdentifierTypeNode('foo1'), false, new IdentifierTypeNode('int')),
4311+
new ArrayShapeItemNode(new IdentifierTypeNode('bar1'), true, new IdentifierTypeNode('true')),
4312+
]),
4313+
ArrayShapeNode::createSealed([
4314+
new ArrayShapeItemNode(new IdentifierTypeNode('foo1'), false, new IdentifierTypeNode('int')),
4315+
new ArrayShapeItemNode(new IdentifierTypeNode('foo2'), false, new IdentifierTypeNode('true')),
4316+
new ArrayShapeItemNode(new IdentifierTypeNode('bar1'), true, new IdentifierTypeNode('true')),
4317+
]),
4318+
ArrayShapeNode::createSealed([
4319+
new ArrayShapeItemNode(new IdentifierTypeNode('foo2'), false, new IdentifierTypeNode('int')),
4320+
new ArrayShapeItemNode(new IdentifierTypeNode('foo3'), false, new IdentifierTypeNode('bool')),
4321+
new ArrayShapeItemNode(new IdentifierTypeNode('bar2'), true, new IdentifierTypeNode('true')),
4322+
]),
4323+
ArrayShapeNode::createSealed([
4324+
new ArrayShapeItemNode(new IdentifierTypeNode('foo1'), false, new IdentifierTypeNode('int')),
4325+
new ArrayShapeItemNode(new IdentifierTypeNode('foo3'), false, new IdentifierTypeNode('true')),
4326+
new ArrayShapeItemNode(new IdentifierTypeNode('bar3'), true, new IdentifierTypeNode('false')),
4327+
]),
4328+
]),
4329+
],
4330+
[
4331+
GenericTypeNode::VARIANCE_INVARIANT,
4332+
GenericTypeNode::VARIANCE_INVARIANT,
4333+
],
4334+
)),
4335+
]),
4336+
],
4337+
[
4338+
GenericTypeNode::VARIANCE_INVARIANT,
4339+
GenericTypeNode::VARIANCE_INVARIANT,
4340+
],
4341+
),
4342+
false,
4343+
'$a',
4344+
'',
4345+
false,
4346+
)),
4347+
]),
4348+
];
4349+
4350+
yield [
4351+
'Multiline PHPDoc with multiple new line being invalid due to union and intersection type declaration',
4352+
'/**' . PHP_EOL .
4353+
' * @param array<string, array{' . PHP_EOL .
4354+
' * foo: int,' . PHP_EOL .
4355+
' * bar?: array<string,' . PHP_EOL .
4356+
' * array{foo1: int, bar1?: true}' . PHP_EOL .
4357+
' * & array{foo1: int, foo2: true, bar1?: true}' . PHP_EOL .
4358+
' * | array{foo2: int, foo3: bool, bar2?: true}' . PHP_EOL .
4359+
' * & array{foo1: int, foo3: true, bar3?: false}' . PHP_EOL .
4360+
' * >,' . PHP_EOL .
4361+
' * }> $a' . PHP_EOL .
4362+
' */',
4363+
new PhpDocNode([
4364+
new PhpDocTagNode('@param', new InvalidTagValueNode(
4365+
'array<string, array{' . PHP_EOL .
4366+
' foo: int,' . PHP_EOL .
4367+
' bar?: array<string,' . PHP_EOL .
4368+
' array{foo1: int, bar1?: true}' . PHP_EOL .
4369+
' & array{foo1: int, foo2: true, bar1?: true}' . PHP_EOL .
4370+
' | array{foo2: int, foo3: bool, bar2?: true}' . PHP_EOL .
4371+
' & array{foo1: int, foo3: true, bar3?: false}' . PHP_EOL .
4372+
' >,' . PHP_EOL .
4373+
'}> $a',
4374+
new ParserException(
4375+
'?',
4376+
Lexer::TOKEN_NULLABLE,
4377+
DIRECTORY_SEPARATOR === '\\' ? 65 : 62,
4378+
Lexer::TOKEN_CLOSE_CURLY_BRACKET,
4379+
null,
4380+
4,
4381+
),
4382+
)),
4383+
]),
4384+
];
4385+
42144386
/**
42154387
* @return object{
42164388
* a: int,

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /