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
#![allow(
clippy::enum_glob_use,
clippy::too_many_lines,
clippy::wildcard_imports
)]
#![allow(
clippy::cast_precision_loss,
clippy::cast_possible_truncation,
clippy::cast_sign_loss
)]
use super::{Abc, Stats};
use crate::*;
impl Abc for BashCode {
fn compute<'a>(node: &Node<'a>, code: &'a [u8], stats: &mut Stats) {
match node.kind_id().into() {
// Each `variable_assignment` is one assignment regardless of
// operator (`=`, `+=`, `-=`, …) — counting the parent node
// avoids double-counting `Bash::EQ`, which is also produced
// for the `=` inside `[ a = b ]` test expressions.
Bash::VariableAssignment | Bash::VariableAssignment2 => {
stats.assignments += 1.;
}
// Every command invocation is a branch in the ABC sense
// (function-call / message-pass). `return` and `exit` builtins
// are also `Bash::Command` nodes and count here too.
Bash::Command => {
stats.branches += 1.;
}
// Two condition signals share this arm:
//
// - Comparison operators inside `[[ … ]]` and `(( … ))`, plus
// the prefix test operators `-z`, `-n`, `-eq`, `-lt`, … which
// the grammar emits as `Bash::TestOperator`.
// - Control-flow branches (`if`/`elif`/`while`). A Bash predicate
// is a command, so the branch keyword itself is the only
// condition signal. These branch keywords mirror the matching
// Bash cyclomatic decisions (`if`/`elif`/`while`; not `for`/
// `&&`/`||`), lifting ABC off 0 for `if cmd; then … elif … fi`.
Bash::EQEQ
| Bash::BANGEQ
| Bash::LT
| Bash::GT
| Bash::LTEQ
| Bash::GTEQ
| Bash::EQTILDE
| Bash::TestOperator
| Bash::IfStatement
| Bash::ElifClause
| Bash::WhileStatement => {
stats.conditions += 1.;
}
// Case arms are conditions too, but counted per-arm like
// cyclomatic, excluding the bare-`*)` wildcard (the Bash analogue
// of `default:`) (#696).
Bash::CaseItem | Bash::CaseItem2
if !crate::metrics::cyclomatic::bash_case_item_is_bare_wildcard(node, code) =>
{
stats.conditions += 1.;
}
_ => {}
}
}
}