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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
//! Cross-language `Loc` helper functions shared by the per-language
//! submodules.
//!
//! The public metric `Stats` (and `Sloc` / `Ploc` / `Cloc` / `Lloc`),
//! the `Loc` trait, and `min_or_zero` stay in the parent module; only
//! the cross-language line-counting helpers live here so the parent
//! clears the 800-SLOC self-scan limit (#976).
//!
//! # The `Loc` catch-all arm is fail-*open*, unlike every sibling metric
//!
//! `Cognitive`, `Cyclomatic`, and `Abc` end their per-language matches
//! with `_ => {}`, so a token the author never considered costs
//! nothing. Every `Loc` implementation instead ends with
//!
//! ```ignore
//! _ => {
//! check_comment_ends_on_code_line(stats, start);
//! stats.ploc.lines.insert(start);
//! }
//! ```
//!
//! which asserts *this row is code*. The default is inverted from the
//! one the neighbouring metric modules train you to expect: an
//! unrecognised token does not fall through harmlessly, it adds a
//! physical line of code — and via [`check_comment_ends_on_code_line`]
//! can reclassify a comment-only row as code-and-comment.
//!
//! Two shipped defects came from exactly this. Tcl and iRules are the
//! only grammars that surface the row terminator as a token child of
//! the root; its start row is the row it *terminates*, so every
//! comment-only and whitespace-only row was credited to PLOC — a
//! realistic fourteen-row Tcl file reported `ploc 13` against a true
//! `7` (#1135). Perl's `#` sits *inside* its `comments` node and did
//! the same to every Perl file carrying a comment row (#1137).
//!
//! When adding a language, enumerate the tokens its grammar emits that
//! are not code — row terminators, comment punctuation, string-internal
//! tokens — and give them an explicit no-op arm. `bca dump` over a
//! small fixture is the fastest way to see them. The parent module's
//! `a_comment_row_is_never_counted_as_code` and
//! `whitespace_only_input_is_the_documented_carve_out` sweep every
//! language for both shapes.
use *;
pub
// Discriminates among the comments that are *after* a code line and
// the ones that are on an independent line.
// This difference is necessary in order to avoid having
// a wrong count for the blank metric.
//
// Requires `end >= start`. Every caller passes the row span returned by
// `init`, and tree-sitter guarantees a node's end row is never before its
// start row — so the only way to violate this is for a caller to adjust
// `end` downwards itself, as Rust's `LineComment` arm does for doc
// comments (#1051).
//
// Scope of the assert, deliberately narrow: it fires only for
// `end < start`, and only in debug — the release profile disables both
// `debug-assertions` and `overflow-checks`. It cannot catch a caller
// whose own arithmetic already wrapped, because `(0, usize::MAX)`
// satisfies `end >= start`. The real guard against that is refusing to
// underflow in the first place, at the site that adjusts the span.
pub
// Detects the comments that are on a code line but *before* the code part.
// This difference is necessary in order to avoid having
// a wrong count for the blank metric.
pub
// Records a physical line carrying both code and comment. Backed by a
// per-line set so several inline block comments on one code line
// (`f(int /*a*/, int /*b*/)`) yield a single comment line, not one per
// comment node (issue #461). Mirrors `Ploc`'s per-line de-duplication.
pub
// Records the inclusive row range `start..=end` as comment-only lines.
// Backed by a per-line set so two standalone block comments on one
// physical line (`/*a*/ /*b*/`) count once, while each distinct row of
// a genuine multi-line block comment still counts (issue #461).
pub
// Adds every physical row spanned by a multi-line string literal to PLOC.
//
// Interior rows of a multi-line string hold real source text, not blank
// lines: classifying them as blank (which happens whenever a language
// no-ops its string nodes, so the rows reach neither PLOC nor CLOC and
// `blank = sloc - ploc - cloc` mislabels them) diverges from Python's
// established behaviour, where a non-docstring multi-line string credits
// all of its rows to PLOC (#415). This helper makes every other language
// agree with that decision (#778).
//
// Mirrors Python's `String` arm exactly: the opening row is inserted only
// when the enclosing statement begins on an earlier row — otherwise that
// row is already attributed to the parent — and rows `start + 1..=end`
// (the interior and closing rows) are always inserted.
pub