Load the stored info on the source files, and prepares the source contexts for use. Args: files_config (dict): the files configuration part of the overall JSON config
(self, files_config)
| 163 | |
| 164 | # Overridden base function |
| 165 | def loadAndPrepareSource(self, files_config): |
| 166 | """Load the stored info on the source files, and prepares the source contexts for use. |
| 167 | |
| 168 | Args: |
| 169 | files_config (dict): the files configuration part of the overall JSON config |
| 170 | """ |
| 171 | # Prepare & load the stats from each file (using the functions file) |
| 172 | src_file_names = [] |
| 173 | self.logger.info("Loading the information regarding the compiled source files") |
| 174 | self.logger.addIndent() |
| 175 | for full_file_path in files_config: |
| 176 | self.logger.debug(f"Parsing the canonical representation of file: {full_file_path.split(os.path.sep)[-1]}") |
| 177 | src_file_names.append(full_file_path) |
| 178 | parseFileStats(full_file_path, files_config[full_file_path]) |
| 179 | self.logger.removeIndent() |
| 180 | |
| 181 | # get the variables from the utils file |
| 182 | self._src_functions_list, self.src_functions_ctx, self._src_file_mappings = getSourceFunctions() |
| 183 | |
| 184 | # prepare a possible collision mapping |
| 185 | collision_map = defaultdict(list) |
| 186 | |
| 187 | # pre-processed list indices (efficiency improvement) |
| 188 | func_indices = defaultdict(list) |
| 189 | for func_idx, func_name in enumerate(self._src_functions_list): |
| 190 | func_indices[func_name].append(func_idx) |
| 191 | |
| 192 | # Convert all function calls to contexts instead of names |
| 193 | self.logger.info("Converting all function references to use the built contexts (instead of string names)") |
| 194 | self._src_external_functions = {} |
| 195 | for src_index, src_func_ctx in enumerate(self.src_functions_ctx): |
| 196 | call_name_to_ctx = {} |
| 197 | # don't forget the file hint string |
| 198 | str_file_hint = src_func_ctx.checkFileHint() |
| 199 | if str_file_hint is not None: |
| 200 | self._str_file_hints.add(str_file_hint) |
| 201 | # split the functions to internal and external |
| 202 | src_internal_calls = [] |
| 203 | src_external_calls = [] |
| 204 | src_func_ctx.index = src_index |
| 205 | for call in src_func_ctx.calls: |
| 206 | # should make sure to prioritize the call from the same file (duplicates are a nasty edge case) |
| 207 | if len(func_indices[call]) == 1: |
| 208 | call_src_ctx = self.src_functions_ctx[func_indices[call][0]] |
| 209 | else: |
| 210 | candidates = list(filter(lambda idx: self.src_functions_ctx[idx].file == src_func_ctx.file, func_indices[call])) |
| 211 | # duplicate symbol in *other* files, we won't know what to pick up :( |
| 212 | if len(candidates) == 0: |
| 213 | self.logger.error("Found duplicate implementations of function \"%s\" in files: %s, can't pick one to use :(", |
| 214 | call, ', '.join(self.src_functions_ctx[idx].file for idx in func_indices[call])) |
| 215 | raise KartaException() |
| 216 | call_src_ctx = self.src_functions_ctx[candidates[0]] |
| 217 | call_name_to_ctx[call] = call_src_ctx |
| 218 | src_internal_calls.append(call_src_ctx) |
| 219 | for call in src_func_ctx.unknown_funcs: |
| 220 | if call in libc.skip_function_names or len(call) == 0: |
| 221 | continue |
| 222 | if call not in self._src_external_functions: |
no test coverage detected