def test_new_intercept_build(self): """ Test log file parsing escapes with upstream (GitHub) intercept-build. """ logfile = os.path.join(self.__test_files, "intercept-new.json") # Upstream scan-build-py creates an argument vector, as opposed to a # command string. This argument vector contains the define as it's # element in the following format: # -DVARIABLE=\"some value\" # and the target triplet, e.g.: # --target=x86_64-linux-gnu # # The define is passed to the analyzer properly. build_actions, _ = log_parser.\ parse_unique_log(load_json_or_empty(logfile), self.__this_dir) build_action = build_actions[0] self.assertEqual(build_action.source, r'/tmp/a.cpp') self.assertEqual(len(build_action.analyzer_options), 1) self.assertTrue(len(build_action.target) > 0) self.assertEqual(build_action.analyzer_options[0], r'-DVARIABLE="some value"') # Test source file with spaces. logfile = os.path.join(self.__test_files, "intercept-new-space.json") build_actions, _ = log_parser.\ parse_unique_log(load_json_or_empty(logfile), self.__this_dir) build_action = build_actions[0] self.assertEqual(build_action.source, '/tmp/a b.cpp') self.assertEqual(build_action.lang, 'c++')
def test_new_ldlogger(self): """ Test log file parsing escape behaviour with after-#631 LD-LOGGER. """ logfile = os.path.join(self.__test_files, "ldlogger-new.json") # LD-LOGGERS after http://github.com/Ericsson/codechecker/pull/631 # now properly log the multiword arguments. When these are parsed by # the log_parser, the define's value will be passed to the analyzer. # # Logfile contains -DVARIABLE="some value" # and --target=x86_64-linux-gnu. build_actions, _ = log_parser.\ parse_unique_log(load_json_or_empty(logfile), self.__this_dir) build_action = build_actions[0] self.assertEqual(build_action.source, r'/tmp/a.cpp') self.assertEqual(len(build_action.analyzer_options), 1) self.assertTrue(len(build_action.target) > 0) self.assertEqual(build_action.analyzer_options[0], r'-DVARIABLE=some value') # Test source file with spaces. logfile = os.path.join(self.__test_files, "ldlogger-new-space.json") build_actions, _ = log_parser.\ parse_unique_log(load_json_or_empty(logfile), self.__this_dir) build_action = build_actions[0] self.assertEqual(build_action.source, r'/tmp/a b.cpp') self.assertEqual(build_action.lang, 'c++')
def test_old_intercept_build(self): """ Test log file parsing escape behaviour with clang-5.0 intercept-build. """ logfile = os.path.join(self.__test_files, "intercept-old.json") # Scan-build-py shipping with clang-5.0 makes a logfile that contains: # -DVARIABLE=\"some value\" and --target=x86_64-linux-gnu # # The define is passed to the analyzer properly. build_actions, _ = log_parser.\ parse_unique_log(load_json_or_empty(logfile), self.__this_dir) build_action = build_actions[0] self.assertEqual(build_action.source, r'/tmp/a.cpp') self.assertEqual(len(build_action.analyzer_options), 1) self.assertTrue(len(build_action.target) > 0) self.assertEqual(build_action.analyzer_options[0], r'-DVARIABLE="some') # Test source file with spaces. logfile = os.path.join(self.__test_files, "intercept-old-space.json") build_actions, _ = log_parser.\ parse_unique_log(load_json_or_empty(logfile), self.__this_dir) build_action = build_actions[0] self.assertEqual(build_action.source, '/tmp/a b.cpp') self.assertEqual(build_action.lang, 'c++')
def test_old_ldlogger(self): """ Test log file parsing escape behaviour with pre-2017 Q2 LD-LOGGER. """ logfile = os.path.join(self.__test_files, "ldlogger-old.json") # LD-LOGGER before http://github.com/Ericsson/codechecker/pull/631 # used an escape mechanism that, when parsed by the log parser via # shlex, made CodeChecker parse arguments with multiword string # literals in them be considered as "file" (instead of compile option), # eventually ignored by the command builder, thus lessening analysis # accuracy, as defines were lost. # # Logfile contains "-DVARIABLE="some value"". # # There is no good way to back-and-forth convert in log_parser or # option_parser, so here we aim for a non-failing stalemate of the # define being considered a file and ignored, for now. build_actions, _ = log_parser.\ parse_unique_log(load_json_or_empty(logfile), self.__this_dir) build_action = build_actions[0] self.assertEqual(build_action.source, r'/tmp/a.cpp') self.assertEqual(len(build_action.analyzer_options), 1)
def test_response_file_contains_source_file(self): """ Test response file where the source file comes from the response file. """ with open(self.compile_command_file_path, "w", encoding="utf-8", errors="ignore") as build_json: build_json.write( json.dumps([ dict(directory=self.tmp_dir, command="g++ @{0}".format(self.rsp_file_path), file="@{0}".format(self.rsp_file_path)) ])) with open(self.rsp_file_path, "w", encoding="utf-8", errors="ignore") as rsp_file: rsp_file.write("""-DVARIABLE="some value" {0}""".format( self.src_file_path)) logfile = os.path.join(self.compile_command_file_path) build_actions, _ = log_parser. \ parse_unique_log(load_json_or_empty(logfile), self.__this_dir) build_action = build_actions[0] self.assertEqual(len(build_action.analyzer_options), 1) self.assertEqual(build_action.source, self.src_file_path) self.assertEqual(build_action.analyzer_options[0], '-DVARIABLE=some')
def test_include_rel_to_abs(self): """ Test working directory prepending to relative include paths. """ logfile = os.path.join(self.__test_files, "include.json") build_actions, _ = log_parser.\ parse_unique_log(load_json_or_empty(logfile), self.__this_dir) build_action = build_actions[0] self.assertEqual(len(build_action.analyzer_options), 4) self.assertEqual(build_action.analyzer_options[0], '-I') self.assertEqual(build_action.analyzer_options[1], '/include') self.assertEqual(build_action.analyzer_options[2], '-I/include') self.assertEqual(build_action.analyzer_options[3], '-I/tmp')
def test_response_file_contains_multiple_source_files(self): """ Test response file where multiple source files come from the response file. """ with open(self.compile_command_file_path, "w", encoding="utf-8", errors="ignore") as build_json: build_json.write( json.dumps([ dict(directory=self.tmp_dir, command="g++ @{0}".format(self.rsp_file_path), file="@{0}".format(self.rsp_file_path)) ])) a_file_path = os.path.join(self.tmp_dir, "a.cpp") with open(a_file_path, "w", encoding="utf-8", errors="ignore") as src_file: src_file.write("int main() { return 0; }") b_file_path = os.path.join(self.tmp_dir, "b.cpp") with open(b_file_path, "w", encoding="utf-8", errors="ignore") as src_file: src_file.write("void foo() {}") with open(self.rsp_file_path, "w", encoding="utf-8", errors="ignore") as rsp_file: rsp_file.write("""-DVARIABLE="some value" {0} {1}""".format( a_file_path, b_file_path)) logfile = os.path.join(self.compile_command_file_path) build_actions, _ = log_parser. \ parse_unique_log(load_json_or_empty(logfile), self.__this_dir) self.assertEqual(len(build_actions), 2) a_build_action = [b for b in build_actions if b.source == a_file_path][0] self.assertEqual(len(a_build_action.analyzer_options), 1) self.assertEqual(a_build_action.analyzer_options[0], '-DVARIABLE=some') b_build_action = [b for b in build_actions if b.source == b_file_path][0] self.assertEqual(len(b_build_action.analyzer_options), 1) self.assertEqual(b_build_action.analyzer_options[0], '-DVARIABLE=some')
def load_compiler_info(filename, compiler): """Load compiler information from a file.""" contents = load_json_or_empty(filename, {}) compiler_info = contents.get(compiler) if compiler_info is None: LOG.error("Could not find compiler %s in file %s", compiler, filename) return ICI = ImplicitCompilerInfo if not ICI.compiler_info.get(compiler): ICI.compiler_info[compiler] = defaultdict(dict) # Load for language C ICI.compiler_info[compiler][ICI.c()]['compiler_includes'] = [] c_lang_data = compiler_info.get(ICI.c()) if c_lang_data: for element in map(shlex.split, c_lang_data.get("compiler_includes")): element = [x for x in element if x != '-isystem'] ICI.compiler_info[compiler][ICI.c()]['compiler_includes'] \ .extend(element) ICI.compiler_info[compiler][ICI.c()]['compiler_standard'] = \ c_lang_data.get('compiler_standard') ICI.compiler_info[compiler][ICI.c()]['target'] = \ c_lang_data.get('target') # Load for language C++ ICI.compiler_info[compiler][ICI.cpp()]['compiler_includes'] = [] cpp_lang_data = compiler_info.get(ICI.cpp()) if cpp_lang_data: for element in map(shlex.split, cpp_lang_data.get('compiler_includes')): element = [x for x in element if x != '-isystem'] ICI.compiler_info[compiler][ICI.cpp()]['compiler_includes'] \ .extend(element) ICI.compiler_info[compiler][ICI.cpp()]['compiler_standard'] = \ cpp_lang_data.get('compiler_standard') ICI.compiler_info[compiler][ICI.cpp()]['target'] = \ cpp_lang_data.get('target')