Coverage for metrics / dtd / go.py: 85%
39 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"""Data Transformation Density (DTD) for Go."""
3from __future__ import annotations
5from parsers.go import is_named_func_literal
7_GO_DTD_MAP_NAMES = {"Map", "Filter", "Reduce"}
10def compute_dtd_go(func_node) -> int:
11 """Compute Data Transformation Density for a Go function node."""
12 body = func_node.child_by_field_name("body")
13 if body and body.type == "block":
14 return _dtd_walk_go(body, depth=0, top_func=func_node)
15 for child in func_node.children:
16 if child.type == "block":
17 return _dtd_walk_go(child, depth=0, top_func=func_node)
18 return 0
21def _is_map_call_go(node) -> bool:
22 """Check if a call_expression is a Map/Filter/Reduce call."""
23 if node.type != "call_expression":
24 return False
25 func = node.child_by_field_name("function")
26 if func and func.type == "selector_expression":
27 field = func.child_by_field_name("field")
28 if field and field.text.decode() in _GO_DTD_MAP_NAMES:
29 return True
30 return False
33_GO_DTD_NESTED_FUNCS = {"function_declaration", "method_declaration"}
34_GO_DTD_LITERAL_ELEMENTS = {"keyed_element", "literal_element"}
37def _dtd_walk_go(node, depth: int, top_func) -> int:
38 """Walk AST and accumulate DTD score."""
39 total = 0
40 is_literal = node.type == "literal_value"
41 for child in node.children:
42 if child.type in _GO_DTD_NESTED_FUNCS and child is not top_func:
43 continue
44 if child.type == "func_literal" and child is not top_func:
45 if not is_named_func_literal(child):
46 total += _dtd_walk_go(child, depth, top_func)
47 continue
49 if child.type == "literal_value" or _is_map_call_go(child):
50 total += _dtd_walk_go(child, depth + 1, top_func)
51 continue
53 if is_literal and child.type in _GO_DTD_LITERAL_ELEMENTS:
54 total += depth
56 total += _dtd_walk_go(child, depth, top_func)
58 return total