| 296 | |
| 297 | |
| 298 | class CallGraph: |
| 299 | |
| 300 | def __init__(self): |
| 301 | self.funcs = collections.defaultdict(set) |
| 302 | self.current_caller = None |
| 303 | |
| 304 | def parse(self, lines): |
| 305 | for funcname in lines: |
| 306 | if not funcname: |
| 307 | continue |
| 308 | |
| 309 | if funcname[0] != "\t": |
| 310 | # Always inserting the current caller makes the serialized version |
| 311 | # more compact. |
| 312 | self.funcs[funcname] |
| 313 | self.current_caller = funcname |
| 314 | else: |
| 315 | self.funcs[funcname[1:]].add(self.current_caller) |
| 316 | |
| 317 | def to_file(self, file_name): |
| 318 | """Store call graph in file 'file_name'.""" |
| 319 | log(f"Writing serialized callgraph to {file_name}") |
| 320 | with open(file_name, 'wb') as f: |
| 321 | pickle.dump(self, f) |
| 322 | |
| 323 | @staticmethod |
| 324 | def from_file(file_name): |
| 325 | """Restore call graph from file 'file_name'.""" |
| 326 | log(f"Reading serialized callgraph from {file_name}") |
| 327 | with open(file_name, 'rb') as f: |
| 328 | return pickle.load(f) |
| 329 | |
| 330 | @staticmethod |
| 331 | def from_files(*file_names): |
| 332 | """Merge multiple call graphs from a list of files.""" |
| 333 | callgraph = CallGraph() |
| 334 | for file_name in file_names: |
| 335 | funcs = CallGraph.from_file(file_name).funcs |
| 336 | for callee, callers in funcs.items(): |
| 337 | callgraph.funcs[callee].update(callers) |
| 338 | return callgraph |
| 339 | |
| 340 | |
| 341 | class GCSuspectsCollector: |
no outgoing calls
no test coverage detected