Skip to content

Commit 85ba225

Browse files
committed
fix(syntax): ignore trivia between docblock and statement
closes #571 Signed-off-by: azjezz <[email protected]>
1 parent a3be66b commit 85ba225

File tree

3 files changed

+85
-20
lines changed

3 files changed

+85
-20
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
interface Column
6+
{
7+
public function name(): string;
8+
}
9+
10+
final class FlatColumn implements Column
11+
{
12+
public function __construct(
13+
private string $name,
14+
) {}
15+
16+
public function name(): string
17+
{
18+
return $this->name;
19+
}
20+
}
21+
22+
final class NestedColumn implements Column
23+
{
24+
public function __construct(
25+
private string $name,
26+
) {}
27+
28+
public function name(): string
29+
{
30+
return $this->name;
31+
}
32+
33+
public function isList(): bool
34+
{
35+
return true;
36+
}
37+
}
38+
39+
function processNestedColumn(NestedColumn $column): void
40+
{
41+
echo 'Processing nested column: ' . $column->name() . "\n";
42+
}
43+
44+
function process(Column $column): void
45+
{
46+
if ($column instanceof FlatColumn) {
47+
echo "Flat column\n";
48+
return;
49+
}
50+
51+
/**
52+
* @var NestedColumn $column
53+
*/
54+
// Comment after docblock should not prevent docblock from being recognized
55+
//
56+
//
57+
// Some comment here
58+
//
59+
/* another */
60+
# and this
61+
processNestedColumn($column);
62+
}

crates/analyzer/tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ test_case!(issue_564);
395395
test_case!(issue_567);
396396
test_case!(issue_568);
397397
test_case!(issue_570);
398+
test_case!(issue_571);
398399
test_case!(issue_573);
399400
test_case!(issue_549);
400401
test_case!(issue_551);

crates/syntax/src/comments/docblock.rs

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -55,32 +55,34 @@ pub fn get_docblock_before_position<'arena>(
5555
return None;
5656
}
5757

58+
// Track the earliest position we've "covered" by trivia.
59+
// Start from node_start_offset and work backwards.
60+
// As we iterate, we verify that each trivia connects to the next (no code gaps).
61+
let mut covered_from = node_start_offset;
62+
5863
for i in (0..candidate_partition_idx).rev() {
5964
let trivia = &trivias[i];
65+
let trivia_end = trivia.span.end_offset();
6066

61-
match trivia.kind {
62-
TriviaKind::DocBlockComment => {
63-
let docblock_end_offset = trivia.span().end.offset;
64-
65-
// Get the slice between docblock end and class start
66-
let code_between_slice = file
67-
.contents
68-
.as_bytes()
69-
.get(docblock_end_offset as usize..node_start_offset as usize)
70-
.unwrap_or(&[]);
67+
// Check if there's a gap between this trivia and our covered region.
68+
// If there's non-whitespace content in the gap, there's actual code between them.
69+
let gap_slice = file.contents.as_bytes().get(trivia_end as usize..covered_from as usize).unwrap_or(&[]);
7170

72-
if code_between_slice.iter().all(u8::is_ascii_whitespace) {
73-
// It's the correct docblock!
74-
return Some(trivia);
75-
}
71+
if !gap_slice.iter().all(u8::is_ascii_whitespace) {
72+
// There's actual code in the gap. No docblock applies.
73+
return None;
74+
}
7675

77-
// There was non-whitespace code between this docblock and the class.
78-
// This docblock doesn't apply. Stop searching.
79-
return None;
76+
match trivia.kind {
77+
TriviaKind::DocBlockComment => {
78+
// Found a docblock with no code between it and the node.
79+
return Some(trivia);
8080
}
81-
TriviaKind::WhiteSpace => {}
82-
_ => {
83-
return None;
81+
TriviaKind::WhiteSpace
82+
| TriviaKind::SingleLineComment
83+
| TriviaKind::MultiLineComment
84+
| TriviaKind::HashComment => {
85+
covered_from = trivia.span.start_offset();
8486
}
8587
}
8688
}

0 commit comments

Comments
 (0)