1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//! Doc-comment attachment (B0.6b, `docs/decision-log.md` 2026-07-20):
//! promotes `///`/`//!` from trivia to a first-class `DOC_COMMENT` CST node,
//! attached structurally by the parser rather than re-derived later by a
//! trivia walk.
//!
//! Two independent attachment sites:
//!
//! - **Leading (outer, `///`).** [`maybe_consume_leading_run`] is called by
//! `block::item` before its declaration-head dispatch. It always consumes
//! a `DOC_COMMENT_OUTER` run it finds (as bare tokens, no node yet — see
//! below) and returns a [`rowan::Checkpoint`] marking where the run
//! started. The caller then either wraps that checkpoint into a
//! `DOC_COMMENT` node as the declaration's leading child (via
//! [`open_with_doc`], when a declaration head actually follows), or — the
//! B0.6b judgment call for an *unattached* leading doc (nothing
//! declaration-shaped follows) — does nothing further. In the unattached
//! case the run's tokens are already sitting bare in the tree exactly
//! where ordinary trivia would, with no diagnostic: a deliberate
//! trivia-fallback, not an error, flagged in the issue for a later ruling
//! on whether an `unused_doc_comment`-style warning belongs here instead.
//!
//! - **Inner (`//!`).** [`maybe_consume_inner_run`] is called right after a
//! `BLOCK`'s opening `{` (and at the very start of `SOURCE_FILE`) — since
//! the enclosing container node is already open at that point, no
//! checkpoint trick is needed: the run is wrapped in a `DOC_COMMENT` node
//! directly, becoming the container's leading child unconditionally
//! (there is no "unattached" case for the inner form — it always
//! documents whatever container it opens).
use crate;
use Parser;
/// If the current token is a leading (`///`) doc-comment token, consume the
/// full contiguous run (see [`consume_doc_run`] for what "contiguous"
/// means) as bare tokens and return a checkpoint marking where the run
/// started, for the caller to retroactively wrap (via [`open_with_doc`])
/// if — and only if — a declaration head turns out to follow. Returns
/// `None` without consuming anything if the current token isn't
/// `DOC_COMMENT_OUTER`.
pub
/// If the current token is an inner (`//!`) doc-comment token, consume the
/// run and wrap it in a `DOC_COMMENT` node as the next child of whatever
/// node is currently open (a `BLOCK` right after its `{`, or `SOURCE_FILE`
/// at its very start — both callers hold the enclosing node open already,
/// so the wrap is unconditional). No-op if the current token isn't
/// `DOC_COMMENT_INNER`.
pub
/// Open a declaration node, attaching a previously-consumed leading doc run
/// (see [`maybe_consume_leading_run`]) as its leading `DOC_COMMENT` child
/// when `doc` is `Some`. Every native decl-parsing function
/// (`parser::decl`) calls this in place of a bare `p.start_node(kind)`.
pub
/// Consume a contiguous run of `doc_kind` comment lines, starting at the
/// current position (the caller has already confirmed the first token is
/// `doc_kind`). "Contiguous": each line may be indented (leading
/// `WHITESPACE`, bumped bare) and is separated from the next by exactly one
/// `NEWLINE`; a blank line — a `NEWLINE` followed (past any `WHITESPACE`)
/// by another `NEWLINE` — ends the run, and that second `NEWLINE` is left
/// unconsumed for normal dispatch to handle. A plain (non-doc) comment, a
/// different-kind doc comment, or any other token also ends the run without
/// being consumed. Every token that IS consumed is bumped bare (no node) —
/// callers decide afterward whether to retroactively wrap the run in a
/// `DOC_COMMENT` node.