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
189
190
191
192
193
194
195
196
197
198
199
200
//! Per-metric implementations.
//!
//! Each submodule defines one maintainability metric, its per-language
//! traits, and its `Stats` accumulator. See the crate-level docs for an
//! overview of the metric suite.
use crate::;
/// Assignment / Branch / Condition counts.
/// Cognitive complexity.
/// Cyclomatic complexity.
/// Halstead suite (operators, operands, volume, difficulty, effort).
/// Lines-of-code variants (SLOC, PLOC, LLOC, CLOC, blank).
/// Maintainability Index.
/// Number of arguments per function.
/// Exit-point counting.
/// Number of methods (functions + closures).
/// Number of public attributes.
/// Number of public methods.
/// Token count.
/// Weighted Methods per Class.
// Gated on the union of every feature any test in the module names —
// the `FIXTURES` rows plus the `bash` / `lua` / `c` row set that
// `a_language_with_no_member_construct_emits_neither_block` uses. The
// narrower `FIXTURES` union belongs on the four tests that read
// `FIXTURES`, not here: a module gate is an outer `cfg`, so naming only
// the `FIXTURES` features would delete that Bash/Lua/C test from a build
// enabling exactly the languages it exists to cover
// (`.claude/rules/testing.md`, #1286).
/// Divides a metric sum by a count, guarding the divisor with `.max(1)`.
///
/// Every "average over a count" metric routes through this helper so the
/// divide-by-zero guard added for [#428] is applied uniformly rather than
/// per call site. A `count` of `0` degrades to `sum / 1` (the sum itself)
/// instead of producing `inf`/`NaN`, so a never-observed or count-less
/// space still serializes a finite number.
///
/// The *meaning* of `count` is the caller's choice of denominator
/// convention; the project uses two:
///
/// - **Per-function** averages (`cognitive`, `cyclomatic`, `exit`,
/// `nargs`) divide by the function/closure count of the subtree, so the
/// value reads as "average complexity per function". `cognitive`/
/// `exit`/`nargs` source this count from `Nom`; `cyclomatic` counts its
/// own function/closure *spaces* (equal in the common case, but
/// independent of whether `Nom` is selected — see
/// `cyclomatic::Stats::function_spaces`).
/// - **Per-space** averages (`nom`, `loc`, `abc`, `tokens`) divide by the
/// total number of spaces (functions, closures, classes, the file unit,
/// …). These measure a property of each space rather than of each
/// function, so a per-function denominator would not match their
/// meaning (and for `nom` it would be circular — it *is* the function
/// count).
///
/// [#428]: https://github.com/dekobon/big-code-analysis/issues/428
// `count as f64` is exact for any realistic space count; the cast mirrors
// the per-metric modules' module-level allowance for count-to-float casts.
pub
/// How far the C++ `requires` clause or `requires` expression the walk
/// is inside reaches, so `cyclomatic`, `cognitive` and `abc` can leave
/// it unscored in `O(1)` per node.
///
/// A constraint is checked at compile time, and a requires-expression's
/// requirements are never evaluated at all, so neither branches. The
/// grammar parses `requires A<T> && B<T>` as a `constraint_conjunction`,
/// which no metric arm matches, but `requires (A<T> && B<T>)` as an
/// ordinary `binary_expression`. Asking each operator whether it sits in
/// a clause by climbing to one made a long `&&` chain quadratic (#1533),
/// so the answer is carried down the walk instead.
///
/// It is exact because the walk is pre-order: a clause is visited before
/// its descendants, and every node visited after the clause starts
/// before the clause's end byte if and only if it is a descendant. A
/// nested clause ends within the outer one, so the outer reach already
/// covers it. Each space keeps its own reach in its metric `Stats`;
/// C++ lambdas open no space, so a lambda written in a constraint
/// scores nothing either. Never serialized or merged: it is walk state.
pub
/// Whether the object-oriented member metrics — `wmc`, `npm`, `npa` —
/// are meaningful on a space of a given [`SpaceKind`].
///
/// An extension trait rather than an inherent method because
/// `SpaceKind` is defined in `big-code-analysis-ast`, which knows
/// nothing about metrics: "does `wmc` apply here" is a question only
/// this crate can ask, so it is answered here (#1376).
pub