Coverage for metrics / cyclomatic / shared.py: 100%

18 statements  

« prev     ^ index     » next       coverage.py v7.13.3, created at 2026-02-08 15:04 -0800

1"""Shared cyclomatic complexity logic for all languages.""" 

2 

3from __future__ import annotations 

4 

5 

6def create_cyclomatic_computer(skip_check_fn, decision_types, logical_ops=None): 

7 """Factory to create language-specific cyclomatic complexity computer. 

8 

9 Args: 

10 skip_check_fn: Function(node, top_func) -> bool that returns True to skip recursion into a node 

11 decision_types: Set/SetList of node types that add 1 to complexity 

12 logical_ops: Optional set of token types that count as logical operators (for &&/??) 

13 """ 

14 

15 def _count_decisions(node, top_func) -> int: 

16 """Recursively count decision points in an AST subtree.""" 

17 count = 0 

18 

19 for child in node.children: 

20 if skip_check_fn(child, top_func): 

21 continue 

22 

23 if child.type in decision_types: 

24 count += 1 

25 elif logical_ops and child.type == "binary_expression": 

26 count += sum(1 for sub in child.children if sub.type in logical_ops) 

27 

28 count += _count_decisions(child, top_func) 

29 

30 return count 

31 

32 return _count_decisions 

33 

34 

35def create_cyclomatic_wrapper(count_decisions_fn): 

36 """Create compute_cyclomatic function wrapper.""" 

37 

38 def compute_cyclomatic(func_node) -> int: 

39 """Compute McCabe cyclomatic complexity for a function node. 

40 

41 CC = 1 + number of decision points. 

42 """ 

43 return 1 + count_decisions_fn(func_node, top_func=func_node) 

44 

45 return compute_cyclomatic