import json
import re
import sys
from collections import defaultdict
MARKER = "cov:unreachable"
FN_SIG = re.compile(
r"^\s*(pub\s*(\([^)]*\)\s*)?)?(default\s+)?(const\s+)?(async\s+)?(unsafe\s+)?"
r"(extern\s+\"[^\"]*\"\s+)?fn\s"
)
def in_scope(file: str) -> bool:
return "/src/" in file and "/tests/" not in file and not file.endswith("/main.rs")
class Source:
def __init__(self) -> None:
self.cache: dict[str, list[str]] = {}
def lines(self, file: str) -> list[str]:
if file not in self.cache:
try:
self.cache[file] = open(file, encoding="utf-8").read().splitlines()
except OSError:
self.cache[file] = []
return self.cache[file]
def text(self, file: str, line: int) -> str:
lines = self.lines(file)
return lines[line - 1] if 0 <= line - 1 < len(lines) else ""
def marked_at(self, file: str, line: int) -> bool:
return MARKER in self.text(file, line)
def load_lines(lcov_path: str) -> dict[str, dict[int, int]]:
per_file: dict[str, dict[int, int]] = defaultdict(dict)
current = None
with open(lcov_path, encoding="utf-8") as fh:
for raw in fh:
if raw.startswith("SF:"):
current = raw[3:].strip()
elif raw.startswith("DA:") and current is not None:
fields = raw[3:].strip().split(",")
line, count = int(fields[0]), int(fields[1])
per_file[current][line] = max(per_file[current].get(line, 0), count)
return per_file
def gate_functions(cov_path: str, src: Source) -> tuple[list[str], list[str]]:
data = json.load(open(cov_path, encoding="utf-8"))
export = data["data"][0]
if "functions" not in export:
raise SystemExit(
f"FAIL: {cov_path!r} has no per-function data (keys: {sorted(export)}). "
"Generate it WITHOUT `--summary-only`."
)
funcs = export["functions"]
merged: dict[tuple[str, int, int], int] = defaultdict(int)
for f in funcs:
regions = f.get("regions", [])
if not regions:
continue
file = (f.get("filenames") or ["?"])[0]
start = min(regions, key=lambda r: (r[0], r[1]))
merged[(file, start[0], start[1])] += f["count"]
failing, exempted = [], []
for (file, line, _col), count in merged.items():
if count > 0 or not in_scope(file):
continue
short = f"{file.split('/src/')[-1]}:{line}"
if any(src.marked_at(file, ln) for ln in (line - 2, line - 1, line)):
exempted.append(short)
else:
failing.append(short)
return failing, exempted
def gate_lines(lcov_path: str, src: Source) -> tuple[list[str], list[str]]:
failing, exempted = [], []
for file, hits in load_lines(lcov_path).items():
if not in_scope(file):
continue
mapped = set(hits)
covered = {ln for ln, c in hits.items() if c > 0}
for line in sorted(ln for ln, c in hits.items() if c == 0):
found = False
for probe in range(line, 0, -1):
if src.marked_at(file, probe):
found = True
break
text = src.text(file, probe).strip()
if FN_SIG.match(text):
break in_region = probe in mapped and probe not in covered
filler = probe not in mapped and (not text or text.startswith("//"))
if not (in_region or filler):
break short = f"{file.split('/src/')[-1]}:{line}"
(exempted if found else failing).append(short)
return failing, exempted
def report(kind: str, failing: list[str], exempted: list[str]) -> None:
if exempted:
print(f"cov:unreachable {kind} exemptions ({len(exempted)}):")
for e in sorted(exempted):
print(f" - {e}")
if failing:
print(f"\nUNCOVERED {kind} without a `// cov:unreachable` marker ({len(failing)}):")
for x in sorted(failing):
print(f" x {x}")
def main() -> int:
cov_path = sys.argv[1] if len(sys.argv) > 1 else "cov.json"
lcov_path = sys.argv[2] if len(sys.argv) > 2 else "lcov.info"
for path, what in ((cov_path, "llvm-cov JSON"), (lcov_path, "LCOV report")):
try:
open(path, encoding="utf-8").close()
except OSError as exc:
print(f"FAIL: cannot read the {what} at {path!r}: {exc}")
return 2
src = Source()
fn_fail, fn_exempt = gate_functions(cov_path, src)
ln_fail, ln_exempt = gate_lines(lcov_path, src)
report("functions", fn_fail, fn_exempt)
print()
report("lines", ln_fail, ln_exempt)
if fn_fail or ln_fail:
print(
"\nFAIL: cover these, or annotate provably-dead defensive arms with "
"`// cov:unreachable: <the dominating invariant>`.\n"
"Never delete or restructure a defensive guard to turn a line green (ADR-0008)."
)
return 1
print("\nOK: 100% line + function coverage, modulo annotated provably-unreachable arms.")
return 0
if __name__ == "__main__":
sys.exit(main())