def test_collect_path_events(self): """ Test path event collect before store. """ clang50_trunk_plist = os.path.join( self.__plist_test_files, 'clang-5.0-trunk.plist') files, reports = plist_parser.parse_plist_file(clang50_trunk_plist, None, False) self.assertEqual(len(reports), 3) # Generate dummy file_ids which should come from the database. file_ids = {} for i, file_name in enumerate(files, 1): file_ids[file_name] = i msg = "This test is prepared to handle 3 reports." self.assertEqual(len(reports), 3, msg) report1_path = [ ttypes.BugPathPos(startLine=19, filePath=None, endCol=7, startCol=5, endLine=19, fileId=1), ttypes.BugPathPos(startLine=20, filePath=None, endCol=7, startCol=5, endLine=20, fileId=1), ttypes.BugPathPos(startLine=21, filePath=None, endCol=13, startCol=5, endLine=21, fileId=1), ttypes.BugPathPos(startLine=7, filePath=None, endCol=7, startCol=5, endLine=7, fileId=1), ttypes.BugPathPos(startLine=8, filePath=None, endCol=6, startCol=5, endLine=8, fileId=1), ttypes.BugPathPos(startLine=8, filePath=None, endCol=25, startCol=22, endLine=8, fileId=1), ttypes.BugPathPos(startLine=8, filePath=None, endCol=20, startCol=10, endLine=8, fileId=1), ttypes.BugPathPos(startLine=7, filePath=None, endCol=14, startCol=14, endLine=7, fileId=2) ] report1_events = [ ttypes.BugPathEvent(startLine=20, filePath=None, endCol=12, startCol=5, msg="'base' initialized to 0", endLine=20, fileId=1), ttypes.BugPathEvent(startLine=21, filePath=None, endCol=18, startCol=15, msg="Passing the value 0 via " "1st parameter 'base'", endLine=21, fileId=1), ttypes.BugPathEvent(startLine=21, filePath=None, endCol=19, startCol=5, msg="Calling 'test_func'", endLine=21, fileId=1), ttypes.BugPathEvent(startLine=6, filePath=None, endCol=1, startCol=1, msg="Entered call from 'main'", endLine=6, fileId=1), ttypes.BugPathEvent(startLine=8, filePath=None, endCol=25, startCol=22, msg="Passing the value 0 via " "1st parameter 'num'", endLine=8, fileId=1), ttypes.BugPathEvent(startLine=8, filePath=None, endCol=26, startCol=10, msg="Calling 'generate_id'", endLine=8, fileId=1), ttypes.BugPathEvent(startLine=6, filePath=None, endCol=1, startCol=1, msg="Entered call from 'test_func'", endLine=6, fileId=2), ttypes.BugPathEvent(startLine=7, filePath=None, endCol=17, startCol=12, msg='Division by zero', endLine=7, fileId=2) ] path1, events1, _ = store_handler.collect_paths_events(reports[0], file_ids, files) self.assertEqual(path1, report1_path) self.assertEqual(events1, report1_events) report2_path = [] report2_events = [ ttypes.BugPathEvent(startLine=8, filePath=None, endCol=26, startCol=10, msg="Value stored to 'id' is ""never read", endLine=8, fileId=1) ] path2, events2, _ = store_handler.collect_paths_events(reports[1], file_ids, files) self.assertEqual(path2, report2_path) self.assertEqual(events2, report2_events) report3_path = [ ttypes.BugPathPos(startLine=14, filePath=None, endCol=6, startCol=3, endLine=14, fileId=1), ttypes.BugPathPos(startLine=15, filePath=None, endCol=3, startCol=3, endLine=15, fileId=1), ttypes.BugPathPos(startLine=16, filePath=None, endCol=1, startCol=1, endLine=16, fileId=1) ] report3_events = [ ttypes.BugPathEvent(startLine=14, filePath=None, endCol=29, startCol=3, msg="Address of stack memory associated" " with local variable 'str'" " is still referred to by the global " "variable 'p' upon returning to the " "caller. This will be a dangling " "reference", endLine=14, fileId=1) ] path, events, _ = store_handler.collect_paths_events(reports[2], file_ids, files) self.assertEqual(path, report3_path) self.assertEqual(events, report3_events)
def collect_paths_events(report: ReportType, file_ids: Dict[str, int], files: Dict[str, str]) -> PathEvents: """ This function creates the BugPathPos and BugPathEvent objects which belong to a report. report -- A report object from the parsed plist file. file_ids -- A dictionary which maps the file paths to file IDs in the database. files -- A list containing the file paths from the parsed plist file. The order of this list must be the same as in the plist file. #TODO Multiple ranges could belong to an event or control node. Only the first range from the list of ranges is stored into the database. Further improvement can be to store and view all ranges if there are more than one. """ path_events = PathEvents([], [], []) events = [i for i in report.bug_path if i.get('kind') == 'event'] # Create remaining data for bugs and send them to the server. In plist # file the source and target of the arrows are provided as starting and # ending ranges of the arrow. The path A->B->C is given as A->B and # B->C, thus range B is provided twice. So in the loop only target # points of the arrows are stored, and an extra insertion is done for # the source of the first arrow before the loop. report_path = [i for i in report.bug_path if i.get('kind') == 'control'] if report_path: start_range = report_path[0]['edges'][0]['start'] start1_line = start_range[0]['line'] start1_col = start_range[0]['col'] start2_line = start_range[1]['line'] start2_col = start_range[1]['col'] source_file_path = files[start_range[1]['file']] path_events.paths.append( ttypes.BugPathPos(start1_line, start1_col, start2_line, start2_col, file_ids[source_file_path])) for path in report_path: try: end_range = path['edges'][0]['end'] end1_line = end_range[0]['line'] end1_col = end_range[0]['col'] end2_line = end_range[1]['line'] end2_col = end_range[1]['col'] source_file_path = files[end_range[1]['file']] path_events.paths.append( ttypes.BugPathPos(end1_line, end1_col, end2_line, end2_col, file_ids[source_file_path])) except IndexError: # Edges might be empty nothing can be stored. continue for event in events: file_path = files[event['location']['file']] start_loc = event['location'] end_loc = event['location'] # Range can provide more precise location information. # Use that if available. ranges = event.get("ranges") if ranges: start_loc = ranges[0][0] end_loc = ranges[0][1] path_events.events.append( ttypes.BugPathEvent(start_loc['line'], start_loc['col'], end_loc['line'], end_loc['col'], event['message'], file_ids[file_path])) for macro in report.macro_expansions: if not macro['expansion']: continue file_path = files[macro['location']['file']] start_loc = macro['location'] end_loc = macro['location'] # Range can provide more precise location information. # Use that if available. ranges = macro.get("ranges") if ranges: start_loc = ranges[0][0] end_loc = ranges[0][1] path_events.extended_data.append( ttypes.ExtendedReportData(ttypes.ExtendedReportDataType.MACRO, start_loc['line'], start_loc['col'], end_loc['line'], end_loc['col'], macro['expansion'], file_ids[file_path])) for note in report.notes: if not note['message']: continue file_path = files[note['location']['file']] start_loc = note['location'] end_loc = note['location'] # Range can provide more precise location information. # Use that if available. ranges = note.get("ranges") if ranges: start_loc = ranges[0][0] end_loc = ranges[0][1] path_events.extended_data.append( ttypes.ExtendedReportData(ttypes.ExtendedReportDataType.NOTE, start_loc['line'], start_loc['col'], end_loc['line'], end_loc['col'], note['message'], file_ids[file_path])) return path_events