Coverage for analyzers / common.py: 100%
53 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-08 15:04 -0800
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-08 15:04 -0800
1"""Shared analysis logic for all language analyzers."""
3from __future__ import annotations
5from pathlib import Path
7from models import FunctionComplexity, FileComplexity
8from common import (
9 _compute_loc,
10 _compute_sloc,
11 compute_maintainability_index,
12 compute_ldi,
13)
14from metrics.duplication.core import (
15 compute_type1_hash,
16 compute_type2_hash,
17 count_statements,
18)
21def analyze_source_generic(
22 code,
23 parse_fn,
24 collect_functions_fn,
25 func_name_fn,
26 compute_cognitive_fn,
27 compute_halstead_fn,
28 compute_npath_fn,
29 compute_dtd_fn,
30 compute_cyclomatic_fn,
31 count_lloc_fn,
32 dup_config,
33 check_patterns_fn=None,
34 timing_manager=None,
35) -> FileComplexity:
36 """Shared analysis loop: parse, collect functions, compute all metrics."""
37 import perf
39 if timing_manager is None:
40 timing_manager = perf.create_timing_manager()
42 with perf.time_block() as t:
43 root = parse_fn(code)
44 functions = collect_functions_fn(root)
45 timing_manager["parse"].append(t[0])
47 with perf.time_block() as t:
48 result = FileComplexity(path="<string>")
49 result.loc = _compute_loc(code)
50 result.lloc = count_lloc_fn(root)
51 result.sloc = _compute_sloc(code, root)
53 if check_patterns_fn is not None:
54 result.pattern_violations = check_patterns_fn(root)
55 timing_manager["lloc"].append(t[0])
57 for func_node in functions:
58 name = func_name_fn(func_node)
59 line = func_node.start_point[0] + 1
61 with perf.time_block() as t:
62 complexity = compute_cognitive_fn(func_node, name)
63 timing_manager["cognitive"].append(t[0])
65 with perf.time_block() as t:
66 halstead = compute_halstead_fn(func_node)
67 timing_manager["halstead"].append(t[0])
69 with perf.time_block() as t:
70 npath = compute_npath_fn(func_node)
71 timing_manager["npath"].append(t[0])
73 with perf.time_block() as t:
74 dtd = compute_dtd_fn(func_node)
75 timing_manager["dtd"].append(t[0])
77 with perf.time_block() as t:
78 cyclomatic = compute_cyclomatic_fn(func_node)
79 timing_manager["cyclomatic"].append(t[0])
81 func_loc = func_node.end_point[0] - func_node.start_point[0] + 1
83 with perf.time_block() as t:
84 mi = compute_maintainability_index(halstead.volume, cyclomatic, func_loc)
85 timing_manager["mi"].append(t[0])
87 with perf.time_block() as t:
88 ldi = compute_ldi(
89 halstead.volume, halstead.vocabulary, halstead.n2, halstead.difficulty
90 )
91 timing_manager["ldi"].append(t[0])
93 with perf.time_block() as t:
94 t1 = compute_type1_hash(func_node, dup_config)
95 t2 = compute_type2_hash(func_node, dup_config)
96 stmts = count_statements(func_node)
97 timing_manager["duplication"].append(t[0])
99 result.functions.append(
100 FunctionComplexity(
101 name=name,
102 line=line,
103 complexity=complexity,
104 halstead=halstead,
105 npath=npath,
106 dtd=dtd,
107 mi=mi,
108 ldi=ldi,
109 cyclomatic=cyclomatic,
110 type1_hash=t1,
111 type2_hash=t2,
112 func_loc=func_loc,
113 stmt_count=stmts,
114 )
115 )
116 return result