Skip to content

Commit 897b598

Browse files
authored
Merge pull request #444 from tmdk/fix/continuation-lines-with-star
Fix parsing of tag descriptions with continuation lines starting with *
2 parents 2309b0c + bc1d9aa commit 897b598

File tree

2 files changed

+52
-12
lines changed

2 files changed

+52
-12
lines changed

src/DocBlock/Tags/Factory/AbstractPHPStanFactory.php

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@
2525
use PHPStan\PhpDocParser\ParserConfig;
2626
use RuntimeException;
2727

28-
use function ltrim;
2928
use function property_exists;
3029
use function rtrim;
30+
use function str_replace;
31+
use function trim;
3132

3233
/**
3334
* Factory class creating tags using phpstan's parser
@@ -61,7 +62,7 @@ public function __construct(PHPStanFactory ...$factories)
6162
public function create(string $tagLine, ?TypeContext $context = null): Tag
6263
{
6364
try {
64-
$tokens = $this->tokenizeLine($tagLine . "\n");
65+
$tokens = $this->tokenizeLine($tagLine);
6566
$ast = $this->parser->parseTag($tokens);
6667
if (property_exists($ast->value, 'description') === true) {
6768
$ast->value->setAttribute(
@@ -104,20 +105,20 @@ public function create(string $tagLine, ?TypeContext $context = null): Tag
104105
*/
105106
private function tokenizeLine(string $tagLine): TokenIterator
106107
{
107-
$tokens = $this->lexer->tokenize($tagLine);
108+
// Prefix continuation lines with "* ", which is consumed by the phpstan parser as TOKEN_PHPDOC_EOL.
109+
$tagLine = str_replace("\n", "\n* ", $tagLine);
110+
$tokens = $this->lexer->tokenize($tagLine . "\n");
108111
$fixed = [];
109112
foreach ($tokens as $token) {
110-
if (($token[1] === Lexer::TOKEN_PHPDOC_EOL) && rtrim($token[0], " \t") !== $token[0]) {
113+
if ($token[Lexer::TYPE_OFFSET] === Lexer::TOKEN_PHPDOC_EOL) {
114+
// Strip "* " prefix (and other horizontal whitespace) again so it doesn't and up in the
115+
// description when we joinUntil() in create().
111116
$fixed[] = [
112-
rtrim($token[Lexer::VALUE_OFFSET], " \t"),
113-
Lexer::TOKEN_PHPDOC_EOL,
114-
$token[2] ?? 0,
115-
];
116-
$fixed[] = [
117-
ltrim($token[Lexer::VALUE_OFFSET], "\n\r"),
118-
Lexer::TOKEN_HORIZONTAL_WS,
119-
($token[2] ?? 0) + 1,
117+
Lexer::VALUE_OFFSET => trim($token[Lexer::VALUE_OFFSET], "* \t"),
118+
Lexer::TYPE_OFFSET => $token[Lexer::TYPE_OFFSET],
119+
Lexer::LINE_OFFSET => $token[Lexer::LINE_OFFSET] ?? 0,
120120
];
121+
121122
continue;
122123
}
123124

tests/integration/InterpretingDocBlocksTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,4 +489,43 @@ public function testParamTagDescriptionIsCorrectly(): void
489489
self::assertSame('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas varius, tellus in cursus
490490
dictum, justo odio sagittis velit, id iaculis mi dui id nisi.', (string) $paramTags->getDescription());
491491
}
492+
493+
public function testParamBlockDescriptionPreservesStarContinuationLines(): void
494+
{
495+
$docComment = <<<DOC
496+
/**
497+
* @param array \$foo {
498+
* Description of foo.
499+
*
500+
* @type string \$bar Description of bar with
501+
* * a list
502+
* * spanning *multiple* lines
503+
* }
504+
*/
505+
DOC;
506+
507+
$factory = DocBlockFactory::createInstance();
508+
$docblock = $factory->create($docComment);
509+
510+
self::assertEquals(
511+
[
512+
new Param(
513+
'foo',
514+
new Array_(),
515+
false,
516+
new Description(<<<'DESCRIPTION'
517+
{
518+
Description of foo.
519+
520+
@type string $bar Description of bar with
521+
* a list
522+
* spanning *multiple* lines
523+
}
524+
DESCRIPTION
525+
),
526+
),
527+
],
528+
$docblock->getTags()
529+
);
530+
}
492531
}

0 commit comments

Comments
 (0)