Cyclomatic Complexity Calculator
Calculate McCabe\'s cyclomatic complexity of your source code. Analyze decision points, risk levels, and per-function breakdown instantly.
About
Cyclomatic complexity, introduced by Thomas McCabe in 1976, quantifies the number of linearly independent paths through a program's control flow graph. The metric is computed as M = E − N + 2P, where E is edge count, N is node count, and P is the number of connected components. In practice, it reduces to counting decision points: each if, while, for, case, catch, &&, ||, and ternary ? adds one to the baseline of 1. Functions exceeding a complexity of 10 become disproportionately harder to test. The SEI recommends keeping values below 10 per function. Ignoring this metric leads to undertested code paths, latent defects, and regression failures that compound with each release cycle.
This tool parses your source code as text. It does not execute it. It strips comments and string literals, then scans for decision keywords and logical operators across JavaScript, TypeScript, Java, C, C++, C#, Go, and Python-like syntax. Results include a total complexity score, per-function breakdown, and risk classification per NIST guidelines. Limitation: the parser uses heuristic pattern matching, not a full AST. Deeply nested template literals, preprocessor macros, or language-specific constructs like Rust's match arms may require manual verification.
Formulas
McCabe's cyclomatic complexity is defined on the control flow graph of a program:
Where E = number of edges in the control flow graph, N = number of nodes, P = number of connected components (typically 1 for a single function).
For a single function, this simplifies to the decision-count method:
Where D = total number of decision points (if, else if, while, for, case, catch, &&, ||, ??, ternary ?).
The minimum number of linearly independent test paths equals M. For a program with multiple functions, total complexity is:
Where k = number of functions and Mi = complexity of function i.
Reference Data
| Complexity Range | Risk Level | Testability | Recommended Action | Min. Test Cases | Defect Probability |
|---|---|---|---|---|---|
| 1 − 5 | Low | Easy to test | No action needed | 1 − 5 | < 5% |
| 6 − 10 | Moderate | Manageable | Review during code review | 6 − 10 | 5 − 15% |
| 11 − 20 | High | Difficult | Refactor recommended | 11 − 20 | 15 − 40% |
| 21 − 50 | Very High | Nearly untestable | Must refactor / split | 21 − 50 | 40 − 65% |
| > 50 | Critical | Untestable | Rewrite from scratch | > 50 | > 65% |
| Common Language Constructs & Their Complexity Contribution | |||||
if | +1 per occurrence (each branch creates a new path) | ||||
else if | +1 per occurrence (additional decision point) | ||||
else | +0 (not a decision; it is the default path) | ||||
while / do-while | +1 per loop (loop condition is a decision) | ||||
for / foreach | +1 per loop | ||||
case (in switch) | +1 per case label (excluding default) | ||||
catch | +1 per catch block | ||||
&& (logical AND) | +1 per operator (short-circuit creates branch) | ||||
|| (logical OR) | +1 per operator (short-circuit creates branch) | ||||
?? (nullish coalescing) | +1 per operator | ||||
? (ternary) | +1 per ternary expression | ||||
return (early) | +0 (does not add complexity in McCabe model) | ||||
Frequently Asked Questions
if (a && b) is semantically equivalent to if (a) { if (b) { ... } }, producing two decision points. McCabe's extended complexity model counts each boolean operator as a separate path. This matters for testing: to achieve full branch coverage, you must test the case where the first operand short-circuits and where it does not.else clause does not add to cyclomatic complexity because it does not introduce a new decision. The decision was already made at the if. The else is the default path. However, else if does add +1 because it introduces a new conditional check.//), multi-line comments (/* ... */), Python-style comments (#), and string literals (single-quoted, double-quoted, backtick template literals). This prevents false positives from keywords appearing inside comments or strings such as "if this works" being counted as a decision point.match arms, and heavily nested template literals. For those cases, supplement with a dedicated linter like ESLint's complexity rule or SonarQube.case label within a switch block adds +1 to complexity. The default label does not add complexity, as it represents the fallback path analogous to else. A switch with 10 case labels contributes 10 to the complexity score. Fall-through cases (without break) still count individually because each case label is a potential entry point.