diff --git a/analyzer/codechecker_analyzer/cli/parse.py b/analyzer/codechecker_analyzer/cli/parse.py index bf702f24de..523426172c 100644 --- a/analyzer/codechecker_analyzer/cli/parse.py +++ b/analyzer/codechecker_analyzer/cli/parse.py @@ -299,7 +299,6 @@ def get_report_dir_status(compile_commands: List[dict[str, str]], for c in compile_commands: for analyzer in supported_analyzers: file, directory, cmd = c["file"], c["directory"], c["command"] - file = os.path.abspath(file) filename = os.path.basename(file) action_hash = analyzer_action_hash(file, directory, cmd) @@ -407,10 +406,25 @@ def print_status(report_dir: str, compile_cmd_path) sys.exit(1) + # Convert all relative compile_cmd.json file paths to absolute + for c in compile_commands: + if not os.path.isabs(c["file"]): + c["file"] = os.path.abspath( + os.path.join(c["directory"], c["file"])) + if files: - files_filter = [os.path.abspath(fp) for fp in files] + file_filter = [os.path.abspath(fp) for fp in files] + + invalid_file_filter = [fp for fp in file_filter + if not os.path.isfile(fp)] + + if invalid_file_filter: + LOG.error("File filter (--file) contains nonexistent files:") + LOG.error(invalid_file_filter) + sys.exit(1) + compile_commands = list( - filter(lambda c: c["file"] in files_filter, compile_commands)) + filter(lambda c: c["file"] in file_filter, compile_commands)) if not compile_commands and not export: LOG.warning("File not found in the compilation database!") @@ -704,7 +718,7 @@ def get_output_file_path(default_file_name: str) -> Optional[str]: if os.path.isdir(input_dir) and os.path.isfile(compile_cmd_json): print_status(input_dir, False, - getattr(args, 'files', None)) + None) if statistics.num_of_reports: sys.exit(2) diff --git a/analyzer/tests/functional/parse_status/test_parse_status.py b/analyzer/tests/functional/parse_status/test_parse_status.py index d51018e33b..8af9e0f319 100644 --- a/analyzer/tests/functional/parse_status/test_parse_status.py +++ b/analyzer/tests/functional/parse_status/test_parse_status.py @@ -72,6 +72,9 @@ def __run_cmd(self, cmd): print(out) print(err) + if process.returncode != 0: + return err + output = out.splitlines(True) processed_output = [] for line in output: @@ -107,6 +110,10 @@ def __log_and_analyze(self): self.__run_cmd(analyze_cmd) + def __get_file_list(self, parsed_json, analyzer, list_type): + return list(map(os.path.basename, + parsed_json["analyzers"][analyzer][list_type])) + def test_parse_status_summary(self): self.__log_and_analyze() @@ -156,14 +163,69 @@ def test_parse_status_detailed_json(self): parsed_json = json.loads(out) - def get_file_list(analyzer, list_type): - return list(map( - os.path.basename, - parsed_json["analyzers"][analyzer][list_type])) - - self.assertListEqual(get_file_list("clangsa", "up-to-date"), + self.assertListEqual(self.__get_file_list(parsed_json, + "clangsa", "up-to-date"), ["a.cpp", "b.cpp"]) - self.assertListEqual(get_file_list("clang-tidy", "up-to-date"), + self.assertListEqual(self.__get_file_list(parsed_json, + "clang-tidy", "up-to-date"), []) - self.assertListEqual(get_file_list("clang-tidy", "missing"), + self.assertListEqual(self.__get_file_list(parsed_json, + "clang-tidy", "missing"), ["a.cpp", "b.cpp"]) + + def test_parse_status_filter(self): + self.__log_and_analyze() + + file_filter = str(os.path.abspath( + os.path.join(self.test_dir, "a.cpp"))) + + parse_status_cmd = [self._codechecker_cmd, "parse", + "--status", "-e", "json", "--detailed", + self.report_dir, "--file", file_filter] + out = self.__run_cmd(parse_status_cmd) + + parsed_json = json.loads(out) + + self.assertListEqual(self.__get_file_list(parsed_json, + "clangsa", "up-to-date"), + ["a.cpp"]) + self.assertListEqual(self.__get_file_list(parsed_json, + "clang-tidy", "up-to-date"), + []) + self.assertListEqual(self.__get_file_list(parsed_json, + "clang-tidy", "missing"), + ["a.cpp"]) + + def test_parse_status_relative_filter(self): + self.__log_and_analyze() + + file_filter = "a.cpp" + + parse_status_cmd = [self._codechecker_cmd, "parse", + "--status", "-e", "json", "--detailed", + self.report_dir, "--file", file_filter] + out = self.__run_cmd(parse_status_cmd) + + parsed_json = json.loads(out) + + self.assertListEqual(self.__get_file_list(parsed_json, + "clangsa", "up-to-date"), + ["a.cpp"]) + self.assertListEqual(self.__get_file_list(parsed_json, + "clang-tidy", "up-to-date"), + []) + self.assertListEqual(self.__get_file_list(parsed_json, + "clang-tidy", "missing"), + ["a.cpp"]) + + def test_parse_status_invalid_filter(self): + self.__log_and_analyze() + + file_filter = "nonexistent_file.cpp" + + parse_status_cmd = [self._codechecker_cmd, "parse", + "--status", "-e", "json", "--detailed", + self.report_dir, "--file", file_filter] + out = self.__run_cmd(parse_status_cmd) + + self.assertIn("File filter (--file) contains nonexistent files", out)