| 10 | "data/defects4j/") |
| 11 | |
| 12 | class FaultLocalization(BaseTask): |
| 13 | RANGE_REGEX = "\(line (?P<beginline>\d+),col (?P<begincol>\d+)\)-\(line (?P<endline>\d+),col (?P<endcol>\d+)\)" |
| 14 | def __init__(self, logdir, split, _type="pred", **kwargs): |
| 15 | self.max_repetitions = kwargs.get("max_repetitions", 3) |
| 16 | self.max_num_tests = kwargs.get("max_num_tests", 1) |
| 17 | super().__init__(logdir, split, _type=_type, **kwargs) |
| 18 | self.task_template = """Given following failed test case, localize which method in the codebase is responsible for the failure. |
| 19 | Failed Test: {test} |
| 20 | The test looks like: \n\n```java\n{test_snippets}\n```\n\n |
| 21 | It failed with the following error message and call stack:\n\n```\n{failing_traces}\n```\n\n |
| 22 | <output> provide the method name in the format 'package.ClassName.methodName' that you think is responsible for the failure. No need to call editor to fix the fault.<\output>""" |
| 23 | |
| 24 | self._max_repetition_in_stack = 5 |
| 25 | self.defects4j_path = kwargs.get("defects4j_path") |
| 26 | self.java_home = kwargs.get("java_home", "/usr") |
| 27 | self.llm = LocalLLM({"model": "mistralai/Mixtral-8x7B-Instruct-v0.1", "system_prompt": "Given following answer and true buggy methods, output True or False whether the predicted method is matched with buggy methods or not.", "max_tokens": 25000}) |
| 28 | |
| 29 | def failing_test_signatures(self, _fail_info): |
| 30 | return list(_fail_info.keys()) |
| 31 | |
| 32 | def report(self, results): |
| 33 | correct = sum(r.kwargs["correct"] for r in results) |
| 34 | total = len(results) |
| 35 | return {"correct": correct, "total": total} |
| 36 | |
| 37 | def setup(self): |
| 38 | self.bug_names = os.listdir(BUG_INFO_DIR) |
| 39 | |
| 40 | def construct_prompt(self, idx): |
| 41 | bug_name = self.bug_names[idx] |
| 42 | fail_info = self._load_fail_info(bug_name) |
| 43 | fail_test_signatures = [ |
| 44 | signature for signature in self.failing_test_signatures(fail_info) |
| 45 | if self.get_test_snippet(signature, bug_name) is not None |
| 46 | ] |
| 47 | fail_test_signatures = fail_test_signatures[:self.max_num_tests] |
| 48 | test_snippets = "\n\n".join(self.get_test_snippet(signature, bug_name).rstrip() for signature in fail_test_signatures) |
| 49 | failing_traces = "\n\n".join(self.get_fail_info(signature, bug_name, minimize=False).rstrip() for signature in fail_test_signatures) |
| 50 | |
| 51 | prompt = self.task_template.format(test=fail_test_signatures, test_snippets=test_snippets, failing_traces=failing_traces) |
| 52 | return prompt |
| 53 | |
| 54 | def load_data(self, idx): |
| 55 | bug_name = self.bug_names[idx] |
| 56 | with open(os.path.join(BUG_INFO_DIR, bug_name, "snippet.json")) as f: |
| 57 | data = json.load(f) |
| 58 | return data |
| 59 | |
| 60 | def __len__(self): |
| 61 | return len(self.bug_names) |
| 62 | |
| 63 | def __getitem__(self, idx): |
| 64 | bug_name = self.bug_names[idx] |
| 65 | project = bug_name.split("_")[0] |
| 66 | bug_id = bug_name.split("_")[1] |
| 67 | self.run_bash("checkout_bug", project, bug_id) |
| 68 | repo_dir = f"data/repos/{project}-{bug_id}" |
| 69 | return repo_dir |