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
//! # Code Complexity Metrics
//!
//! **Cyclomatic complexity**, introduced by Thomas J. `McCabe` in 1976, counts
//! the number of independent paths through a piece of code's control flow:
//! each `if`, loop, and branch adds to the count. Code with more independent
//! paths through it is harder to fully test, harder to reason about, and,
//! in decades of empirical research, measurably more likely to contain
//! defects.
//!
//! ## Formula
//!
//! ```text
//! Cyclomatic complexity = edges - nodes + 2
//!
//! edges = control-flow graph edges
//! nodes = control-flow graph nodes
//! ```
//!
//! ## Why it matters
//!
//! Complexity metrics predict testing and defect difficulty; they do not
//! measure quality directly. For large teams they earn their keep as a
//! triage tool: a way to find, among thousands of files, the small subset
//! most likely to reward a closer look, not as a standalone verdict on code
//! quality.
//!
//! ## Example
//!
//! ```rust
//! use software_engineering::code_complexity::cyclomatic_complexity;
//!
//! // A straight-line function with no branches: 1 node, 0 back-edges
//! // beyond the single entry/exit edge — McCabe's minimum score is 1.
//! // Graph: 2 nodes (entry, exit), 1 edge: 1 - 2 + 2 = 1.
//! assert_eq!(cyclomatic_complexity(1, 2), 1);
//!
//! // A single `if` adds one more independent path: 3 edges, 3 nodes.
//! assert_eq!(cyclomatic_complexity(3, 3), 2);
//! ```
//!
//! ## Pitfalls
//!
//! - **Treating a complexity score as a direct quality verdict** — it
//! measures one specific property, not overall code quality.
//! - **Decomposition gaming**: splitting a function to lower the score
//! without genuinely simplifying anything, sometimes scattering the logic
//! across more files and making it harder to follow.
//! - **Applying a universal threshold without calibrating to your own
//! codebase** — a parser or rules engine may have legitimately higher
//! baseline complexity than a typical CRUD service.
//! - **Using complexity metrics to individually evaluate engineers**
//! invites gaming and misapplies a metric meant for triage, not judgement.
//!
//! ## Sources
//!
//! - Chapter 4.1, Code complexity metrics.
//! - `McCabe`, Thomas J., "A Complexity Measure," *IEEE Transactions on
//! Software Engineering* (1976).
//!
//! Topic doc: software-engineering-metrics/locales/en-001/chapters/04-01-code-complexity-metrics.md
/// `McCabe` cyclomatic complexity: independent paths through control flow.
///
/// `edges - nodes + 2`, computed on the function's control-flow graph. A
/// straight-line function with no branches scores 1 (the minimum); each
/// additional decision point (`if`, loop, `case` arm, and similar) adds one.
///
/// # Arguments
///
/// * `edges` — number of edges in the control-flow graph.
/// * `nodes` — number of nodes in the control-flow graph.
///
/// # Returns
///
/// The cyclomatic complexity score (an integer; can be negative for a
/// malformed or disconnected graph, which the caller should treat as
/// invalid input).
///
/// # Examples
///
/// ```rust
/// use software_engineering::code_complexity::cyclomatic_complexity;
///
/// // Straight-line function: 2 nodes, 1 edge -> complexity 1.
/// assert_eq!(cyclomatic_complexity(1, 2), 1);
/// ```