Skip to content

Commit d38792c

Browse files
committed
Fix empty docblocks behaviour and optimize docblock analyze + split logic
1 parent 854074c commit d38792c

6 files changed

Lines changed: 148 additions & 187 deletions

File tree

libs/phpdoc/src/DocBlockParser.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,12 @@ private function createTags(array $segments, string $docblock): array
281281
/**
282282
* @throws PhpDocExceptionInterface
283283
*/
284-
private function tryCreateDescription(Segment $segment, string $docblock): ?DescriptionInterface
284+
private function tryCreateDescription(?Segment $segment, string $docblock): ?DescriptionInterface
285285
{
286+
if ($segment === null) {
287+
return null;
288+
}
289+
286290
try {
287291
return $this->descriptionParser->tryParse($segment->text);
288292
} catch (\Throwable $e) {

libs/phpdoc/src/Parser/DocBlockAnalyzer.php

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
use TypeLang\PhpDoc\Parser\Splitter\SplitterInterface;
99

1010
/**
11-
* Groups the significant segments of a DocBlock comment into sections (a
12-
* description followed by tags) and builds the {@see SourceMap} for them.
11+
* Groups the significant segments of a DocBlock comment into a leading
12+
* description followed by tags, joining each tag with its continuation lines.
1313
*
14-
* It only slices and maps the comment: parsing the description and tag
15-
* contents is left to the caller.
14+
* A line opening with "@" starts a new tag; any line before the first tag
15+
* belongs to the description, and any non-tag line after a tag continues it.
1616
*/
1717
final readonly class DocBlockAnalyzer
1818
{
@@ -22,35 +22,51 @@ public function __construct(
2222

2323
public function analyze(string $docblock): RawDocBlock
2424
{
25-
$buffer = '';
26-
$currentOffset = 0;
27-
$hasOffset = false;
25+
/** @phpstan-ignore-next-line : Pre-allocate (invalid) segment in order to use it as a
26+
* template in the future (speeding up object instantiation) */
27+
$prototype = new Segment('');
28+
29+
/** @var list<Segment> $groups */
30+
$groups = [];
2831

29-
/** @var list<Segment> $computedSegments */
30-
$computedSegments = [];
32+
$buffer = '';
33+
$offset = 0;
3134

3235
foreach ($this->splitter->split($docblock) as $segment) {
33-
$segmentText = $segment->text;
36+
// A tag opens a new group; the previous one is finished first.
37+
if ($buffer !== '' && $segment->text[0] === '@') {
38+
/** @phpstan-ignore-next-line : Allow external mutation */
39+
$prototype->text = $buffer;
40+
/** @phpstan-ignore-next-line : Allow external mutation */
41+
$prototype->offset = $offset;
3442

35-
if ($segmentText[0] === '@') {
36-
$computedSegments[] = new Segment($buffer, $currentOffset);
43+
$groups[] = clone $prototype;
3744
$buffer = '';
38-
$currentOffset = $segment->offset;
39-
$hasOffset = true;
40-
} elseif (!$hasOffset) {
41-
// Anchor the leading description at its first significant line.
42-
$currentOffset = $segment->offset;
43-
$hasOffset = true;
45+
}
46+
47+
if ($buffer === '') {
48+
$offset = $segment->offset;
4449
}
4550

4651
$buffer .= $segment->text;
4752
}
4853

49-
$computedSegments[] = new Segment($buffer, $currentOffset);
54+
if ($buffer !== '') {
55+
/** @phpstan-ignore-next-line : Allow external mutation */
56+
$prototype->text = $buffer;
57+
/** @phpstan-ignore-next-line : Allow external mutation */
58+
$prototype->offset = $offset;
59+
60+
$groups[] = clone $prototype;
61+
}
62+
63+
// The leading group is the description unless it already is a tag.
64+
$description = null;
65+
66+
if ($groups !== [] && $groups[0]->text[0] !== '@') {
67+
$description = \array_shift($groups);
68+
}
5069

51-
return new RawDocBlock(
52-
description: \array_shift($computedSegments),
53-
tags: $computedSegments,
54-
);
70+
return new RawDocBlock($description, $groups);
5571
}
5672
}

libs/phpdoc/src/Parser/RawDocBlock.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
final readonly class RawDocBlock
1010
{
1111
public function __construct(
12-
public Segment $description,
12+
public ?Segment $description,
1313
/**
1414
* @var list<Segment>
1515
*/

libs/phpdoc/src/Parser/Splitter/Segment.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313
final class Segment
1414
{
1515
public function __construct(
16-
public string $text = '',
16+
/**
17+
* @var non-empty-string
18+
*/
19+
public string $text,
1720
/**
1821
* @var int<0, max>
1922
*/

0 commit comments

Comments
 (0)