Skip to main content

big_code_analysis/metrics/
mod.rs

1//! Per-metric implementations.
2//!
3//! Each submodule defines one maintainability metric, its per-language
4//! traits, and its `Stats` accumulator. See the crate-level docs for an
5//! overview of the metric suite.
6
7/// Assignment / Branch / Condition counts.
8pub mod abc;
9/// Cognitive complexity.
10pub mod cognitive;
11/// Cyclomatic complexity.
12pub mod cyclomatic;
13/// Halstead suite (operators, operands, volume, difficulty, effort).
14pub mod halstead;
15/// Lines-of-code variants (SLOC, PLOC, LLOC, CLOC, blank).
16pub mod loc;
17/// Maintainability Index.
18pub mod mi;
19/// Number of arguments per function.
20pub mod nargs;
21/// Exit-point counting.
22pub mod nexits;
23/// Number of methods (functions + closures).
24pub mod nom;
25/// Number of public attributes.
26pub mod npa;
27/// Number of public methods.
28pub mod npm;
29/// Token count.
30pub mod tokens;
31/// Weighted Methods per Class.
32pub mod wmc;
33
34#[cfg(test)]
35#[path = "container_scope_tests.rs"]
36mod container_scope_tests;
37
38/// Divides a metric sum by a count, guarding the divisor with `.max(1)`.
39///
40/// Every "average over a count" metric routes through this helper so the
41/// divide-by-zero guard added for [#428] is applied uniformly rather than
42/// per call site. A `count` of `0` degrades to `sum / 1` (the sum itself)
43/// instead of producing `inf`/`NaN`, so a never-observed or count-less
44/// space still serializes a finite number.
45///
46/// The *meaning* of `count` is the caller's choice of denominator
47/// convention; the project uses two:
48///
49/// - **Per-function** averages (`cognitive`, `cyclomatic`, `exit`,
50///   `nargs`) divide by the function/closure count of the subtree, so the
51///   value reads as "average complexity per function". `cognitive`/
52///   `exit`/`nargs` source this count from `Nom`; `cyclomatic` counts its
53///   own function/closure *spaces* (equal in the common case, but
54///   independent of whether `Nom` is selected — see
55///   `cyclomatic::Stats::function_spaces`).
56/// - **Per-space** averages (`nom`, `loc`, `abc`, `tokens`) divide by the
57///   total number of spaces (functions, closures, classes, the file unit,
58///   …). These measure a property of each space rather than of each
59///   function, so a per-function denominator would not match their
60///   meaning (and for `nom` it would be circular — it *is* the function
61///   count).
62///
63/// [#428]: https://github.com/dekobon/big-code-analysis/issues/428
64#[inline]
65#[must_use]
66// `count as f64` is exact for any realistic space count; the cast mirrors
67// the per-metric modules' module-level allowance for count-to-float casts.
68#[allow(clippy::cast_precision_loss)]
69pub(crate) fn average(sum: f64, count: usize) -> f64 {
70    sum / count.max(1) as f64
71}