1from __future__ import annotations 2 3from typing import NamedTuple 4 5 6class LlvmCoverageSegment(NamedTuple): 7 line: int 8 col: int 9 segment_count: int 10 has_count: int 11 is_region_entry: int 12 is_gap_entry: int | None 13 14 @property 15 def has_coverage(self) -> bool: 16 return self.segment_count > 0 17 18 @property 19 def is_executable(self) -> bool: 20 return self.has_count > 0 21 22 def get_coverage( 23 self, prev_segment: LlvmCoverageSegment 24 ) -> tuple[list[int], list[int]]: 25 # Code adapted from testpilot.testinfra.runners.gtestcoveragerunner.py 26 if not prev_segment.is_executable: 27 return [], [] 28 29 # this segment ends at the line if col == 1 30 # (so segment effectively ends on the line) and 31 # line+1 if col is > 1 (so it touches at least some part of last line). 32 end_of_segment = self.line if self.col == 1 else self.line + 1 33 lines_range = list(range(prev_segment.line, end_of_segment)) 34 return (lines_range, []) if prev_segment.has_coverage else ([], lines_range) 35 36 37def parse_segments(raw_segments: list[list[int]]) -> list[LlvmCoverageSegment]: 38 """ 39 Creates LlvmCoverageSegment from a list of lists in llvm export json. 40 each segment is represented by 5-element array. 41 """ 42 ret: list[LlvmCoverageSegment] = [] 43 for raw_segment in raw_segments: 44 assert ( 45 len(raw_segment) == 5 or len(raw_segment) == 6 46 ), "list is not compatible with llvmcom export:" 47 " Expected to have 5 or 6 elements" 48 if len(raw_segment) == 5: 49 ret.append( 50 LlvmCoverageSegment( 51 raw_segment[0], 52 raw_segment[1], 53 raw_segment[2], 54 raw_segment[3], 55 raw_segment[4], 56 None, 57 ) 58 ) 59 else: 60 ret.append(LlvmCoverageSegment(*raw_segment)) 61 62 return ret 63