"""AST-level resource leak injection for Java using javalang.""" from typing import Optional import javalang from app.dataset.rules.base import Mutation, MutationRule class JavaResourceLeakRule(MutationRule): """Replace try-with-resources with a plain try block, leaking the resource. Uses `javalang` to locate a try-with-resources statement and removes the resource specification, leaving the stream unclosed. """ name = "java_resource_leak" language = "java" defect_type = "resource_not_closed" def detect_and_mutate(self, source: str, filename: str = "") -> Optional[Mutation]: try: tree = javalang.parse.parse(source) except Exception: return None for path, node in tree: if not isinstance(node, javalang.tree.TryStatement): continue if not node.resources: continue pos = node.position if not pos: continue lines = source.splitlines(keepends=True) start = pos.line # Find the resource clause line e.g. try (BufferedReader br = ...) resource_line = lines[start - 1] new_header = resource_line.split("(", 1)[0].rstrip() + " {\n" mutated = "".join(lines[: start - 1] + [new_header] + lines[start:]) return Mutation( defect_type=self.defect_type, language=self.language, line_start=start, line_end=start, mutated_source=mutated, reference_fix="Use try-with-resources or explicitly close the stream in finally.", description="Removed try-with-resources, leaking the acquired resource.", ) return None