Skip to content

Commit 3cb62d1

Browse files
rvanvelzenondrejmirtes
authored andcommitted
Make requiring whitespace before description optional
1 parent 1e355a3 commit 3cb62d1

File tree

2 files changed

+91
-9
lines changed

2 files changed

+91
-9
lines changed

src/Parser/PhpDocParser.php

+7-2
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,14 @@ class PhpDocParser
2424
/** @var ConstExprParser */
2525
private $constantExprParser;
2626

27-
public function __construct(TypeParser $typeParser, ConstExprParser $constantExprParser)
27+
/** @var bool */
28+
private $requireWhitespaceBeforeDescription;
29+
30+
public function __construct(TypeParser $typeParser, ConstExprParser $constantExprParser, bool $requireWhitespaceBeforeDescription = false)
2831
{
2932
$this->typeParser = $typeParser;
3033
$this->constantExprParser = $constantExprParser;
34+
$this->requireWhitespaceBeforeDescription = $requireWhitespaceBeforeDescription;
3135
}
3236

3337

@@ -492,7 +496,8 @@ private function parseOptionalDescription(TokenIterator $tokens, bool $limitStar
492496
}
493497

494498
if (
495-
!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END)
499+
$this->requireWhitespaceBeforeDescription
500+
&& !$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END)
496501
&& !$tokens->isPrecededByHorizontalWhitespace()
497502
) {
498503
$tokens->consumeTokenType(Lexer::TOKEN_HORIZONTAL_WS); // will throw exception

tests/PHPStan/Parser/PhpDocParserTest.php

+84-7
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,17 @@ class PhpDocParserTest extends TestCase
5353
/** @var PhpDocParser */
5454
private $phpDocParser;
5555

56+
/** @var PhpDocParser */
57+
private $phpDocParserWithRequiredWhitespaceBeforeDescription;
58+
5659
protected function setUp(): void
5760
{
5861
parent::setUp();
5962
$this->lexer = new Lexer();
6063
$constExprParser = new ConstExprParser();
61-
$this->phpDocParser = new PhpDocParser(new TypeParser($constExprParser), $constExprParser);
64+
$typeParser = new TypeParser($constExprParser);
65+
$this->phpDocParser = new PhpDocParser($typeParser, $constExprParser);
66+
$this->phpDocParserWithRequiredWhitespaceBeforeDescription = new PhpDocParser($typeParser, $constExprParser, true);
6267
}
6368

6469

@@ -83,14 +88,37 @@ protected function setUp(): void
8388
* @dataProvider provideRealWorldExampleData
8489
* @dataProvider provideDescriptionWithOrWithoutHtml
8590
*/
86-
public function testParse(string $label, string $input, PhpDocNode $expectedPhpDocNode, int $nextTokenType = Lexer::TOKEN_END): void
91+
public function testParse(
92+
string $label,
93+
string $input,
94+
PhpDocNode $expectedPhpDocNode,
95+
?PhpDocNode $withRequiredWhitespaceBeforeDescriptionExpectedPhpDocNode = null
96+
): void
97+
{
98+
$this->executeTestParse(
99+
$this->phpDocParser,
100+
$label,
101+
$input,
102+
$expectedPhpDocNode
103+
);
104+
105+
$this->executeTestParse(
106+
$this->phpDocParserWithRequiredWhitespaceBeforeDescription,
107+
$label,
108+
$input,
109+
$withRequiredWhitespaceBeforeDescriptionExpectedPhpDocNode ?? $expectedPhpDocNode
110+
);
111+
}
112+
113+
114+
private function executeTestParse(PhpDocParser $phpDocParser, string $label, string $input, PhpDocNode $expectedPhpDocNode): void
87115
{
88116
$tokens = new TokenIterator($this->lexer->tokenize($input));
89-
$actualPhpDocNode = $this->phpDocParser->parse($tokens);
117+
$actualPhpDocNode = $phpDocParser->parse($tokens);
90118

91119
$this->assertEquals($expectedPhpDocNode, $actualPhpDocNode, $label);
92120
$this->assertSame((string) $expectedPhpDocNode, (string) $actualPhpDocNode);
93-
$this->assertSame($nextTokenType, $tokens->currentTokenType());
121+
$this->assertSame(Lexer::TOKEN_END, $tokens->currentTokenType());
94122
}
95123

96124

@@ -675,6 +703,16 @@ public function provideVarTagsData(): Iterator
675703
)
676704
),
677705
]),
706+
new PhpDocNode([
707+
new PhpDocTagNode(
708+
'@var',
709+
new VarTagValueNode(
710+
new IdentifierTypeNode('Foo'),
711+
'$foo',
712+
'#desc'
713+
)
714+
),
715+
]),
678716
];
679717

680718
yield [
@@ -1459,6 +1497,15 @@ public function provideReturnTagsData(): Iterator
14591497
yield [
14601498
'invalid variadic callable',
14611499
'/** @return \Closure(...int, string): string */',
1500+
new PhpDocNode([
1501+
new PhpDocTagNode(
1502+
'@return',
1503+
new ReturnTagValueNode(
1504+
new IdentifierTypeNode('\Closure'),
1505+
'(...int, string): string'
1506+
)
1507+
),
1508+
]),
14621509
new PhpDocNode([
14631510
new PhpDocTagNode(
14641511
'@return',
@@ -2265,6 +2312,16 @@ public function provideSingleLinePhpDocData(): Iterator
22652312
yield [
22662313
'callable with incomplete signature without return type',
22672314
'/** @var callable(int) */',
2315+
new PhpDocNode([
2316+
new PhpDocTagNode(
2317+
'@var',
2318+
new VarTagValueNode(
2319+
new IdentifierTypeNode('callable'),
2320+
'',
2321+
'(int)'
2322+
)
2323+
),
2324+
]),
22682325
new PhpDocNode([
22692326
new PhpDocTagNode(
22702327
'@var',
@@ -4241,6 +4298,20 @@ public function provideDescriptionWithOrWithoutHtml(): Iterator
42414298
'/**' . PHP_EOL .
42424299
' * @return Foo <strong>Important description' . PHP_EOL .
42434300
' */',
4301+
new PhpDocNode([
4302+
new PhpDocTagNode(
4303+
'@return',
4304+
new ReturnTagValueNode(
4305+
new GenericTypeNode(
4306+
new IdentifierTypeNode('Foo'),
4307+
[
4308+
new IdentifierTypeNode('strong'),
4309+
]
4310+
),
4311+
'Important description'
4312+
)
4313+
),
4314+
]),
42444315
new PhpDocNode([
42454316
new PhpDocTagNode(
42464317
'@return',
@@ -4305,14 +4376,20 @@ public function provideTagsWithNumbers(): Iterator
43054376
* @dataProvider dataParseTagValue
43064377
* @param PhpDocNode $expectedPhpDocNode
43074378
*/
4308-
public function testParseTagValue(string $tag, string $phpDoc, Node $expectedPhpDocNode, int $nextTokenType = Lexer::TOKEN_END): void
4379+
public function testParseTagValue(string $tag, string $phpDoc, Node $expectedPhpDocNode): void
4380+
{
4381+
$this->executeTestParseTagValue($this->phpDocParser, $tag, $phpDoc, $expectedPhpDocNode);
4382+
$this->executeTestParseTagValue($this->phpDocParserWithRequiredWhitespaceBeforeDescription, $tag, $phpDoc, $expectedPhpDocNode);
4383+
}
4384+
4385+
private function executeTestParseTagValue(PhpDocParser $phpDocParser, string $tag, string $phpDoc, Node $expectedPhpDocNode): void
43094386
{
43104387
$tokens = new TokenIterator($this->lexer->tokenize($phpDoc));
4311-
$actualPhpDocNode = $this->phpDocParser->parseTagValue($tokens, $tag);
4388+
$actualPhpDocNode = $phpDocParser->parseTagValue($tokens, $tag);
43124389

43134390
$this->assertEquals($expectedPhpDocNode, $actualPhpDocNode);
43144391
$this->assertSame((string) $expectedPhpDocNode, (string) $actualPhpDocNode);
4315-
$this->assertSame($nextTokenType, $tokens->currentTokenType());
4392+
$this->assertSame(Lexer::TOKEN_END, $tokens->currentTokenType());
43164393
}
43174394

43184395
}

0 commit comments

Comments
 (0)