def to_report(report: ReportData, get_file: Callable[[int, str], File]) -> Report: """ Create a Report object from the given thrift report data. """ severity = Severity._VALUES_TO_NAMES[report.severity] \ if report.severity else 'UNSPECIFIED' bug_path_events: List[BugPathEvent] = [] bug_path_positions: List[BugPathPosition] = [] notes: List[BugPathEvent] = [] macro_expansions: List[MacroExpansion] = [] details = report.details if details: for e in details.pathEvents: bug_path_events.append( BugPathEvent( e.msg, get_file(e.fileId, e.filePath), e.startLine, e.startCol, Range(e.startLine, e.startCol, e.endLine, e.endCol))) for p in details.executionPath: bug_path_positions.append( BugPathPosition( get_file(p.fileId, p.filePath), Range(p.startLine, p.startCol, p.endLine, p.endCol))) for e in details.extendedData: if e.type == ExtendedReportDataType.NOTE: notes.append( BugPathEvent( e.message, get_file(e.fileId, e.filePath), e.startLine, e.startCol, Range(e.startLine, e.startCol, e.endLine, e.endCol))) if e.type == ExtendedReportDataType.MACRO: name = '' macro_expansions.append( MacroExpansion( e.message, name, get_file(e.fileId, e.filePath), e.startLine, e.startCol, Range(e.startLine, e.startCol, e.endLine, e.endCol))) return Report(get_file(report.fileId, report.checkedFile), report.line, report.column, report.checkerMsg, report.checkerId, severity, report.bugHash, report.analyzerName, bug_path_events=bug_path_events or None, bug_path_positions=bug_path_positions, notes=notes, macro_expansions=macro_expansions)
def __get_bug_path_positions( self, diag, files: Dict[int, File] ) -> List[BugPathPosition]: """ Get bug path positions. 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 if multiple control event kinds are followed each other. So in the loop we will not store the start point if the previous path event was a control event. """ bug_path_positions = [] prev_control_item = None for item in diag.get('path', []): if item.get('kind') != 'control': continue try: edges = item['edges'][0] edge = None if prev_control_item: if not is_same_control_item(item, prev_control_item): edge = edges['start'] else: edge = edges['start'] if edge: bug_path_positions.append(BugPathPosition( file=files[edge[1]['file']], range=Range( edge[0]['line'], edge[0]['col'], edge[1]['line'], edge[1]['col']))) bug_path_positions.append(BugPathPosition( file=files[edges['end'][1]['file']], range=Range( edges['end'][0]['line'], edges['end'][0]['col'], edges['end'][1]['line'], edges['end'][1]['col']))) prev_control_item = item except IndexError: # Edges might be empty nothing can be stored. continue return bug_path_positions
def __get_macro_expansions( self, diag, files: Dict[int, File] ) -> List[MacroExpansion]: """ Get macro expansion. """ macro_expansions = [] for macro in diag.get('macro_expansions', []): if not macro['expansion']: continue location, start_loc, end_loc = self.__get_bug_event_locations( macro) macro_expansions.append(MacroExpansion( message=macro['expansion'], name=macro['name'], file=files[location['file']], line=location['line'], column=location['col'], range=Range( start_loc['line'], start_loc['col'], end_loc['line'], end_loc['col']))) return macro_expansions
def __get_notes(self, diag, files: Dict[int, File]) -> List[BugPathEvent]: """ Get notes. """ notes = [] for note in diag.get('notes', []): if not note['message']: continue location, start_loc, end_loc = self.__get_bug_event_locations(note) notes.append( BugPathEvent(message=note['message'], file=files[location['file']], line=location['line'], column=location['col'], range=Range(start_loc['line'], start_loc['col'], end_loc['line'], end_loc['col']))) return notes
def __get_bug_path_events(self, diag, files: Dict[int, File]) -> List[BugPathEvent]: """ Get bug path events. """ events = [] for item in diag.get('path', []): if item.get('kind') != 'event': continue location, start_loc, end_loc = self.__get_bug_event_locations(item) events.append( BugPathEvent(message=item['message'], file=files[location['file']], line=location['line'], column=location['col'], range=Range(start_loc['line'], start_loc['col'], end_loc['line'], end_loc['col']))) return events
File(os.path.join(gen_plist_dir_path, 'test.h')) ] # Base skeletons for reports where the checker name is already available. div_zero_skel = Report( SRC_FILES[1], 7, 14, 'Division by zero', 'core.DivideZero', report_hash='79e31a6ba028f0b7d9779faf4a6cb9cf', category='Logic error', type='Division by zero', bug_path_events=[ BugPathEvent("'base' initialized to 0", SRC_FILES[0], 20, 5, Range(20, 5, 20, 12)), BugPathEvent("Passing the value 0 via 1st parameter 'base'", SRC_FILES[0], 21, 15, Range(21, 15, 21, 18)), BugPathEvent("Calling 'test_func'", SRC_FILES[0], 21, 5, Range(21, 5, 21, 19)), BugPathEvent("Entered call from 'main'", SRC_FILES[0], 6, 1, Range(6, 1, 6, 1)), BugPathEvent("Passing the value 0 via 1st parameter 'num'", SRC_FILES[0], 8, 22, Range(8, 22, 8, 25)), BugPathEvent("Calling 'generate_id'", SRC_FILES[0], 8, 10, Range(8, 10, 8, 26)), BugPathEvent("Entered call from 'test_func'", SRC_FILES[1], 6, 1, Range(6, 1, 6, 1)), BugPathEvent("Division by zero", SRC_FILES[1], 7, 14, Range(7, 12, 7, 17)) ],
def _get_bug_path_event_range(self, event: BugPathEvent) -> Range: """ Get range for bug path event. """ if event.range: return event.range return Range(event.line, event.column, event.line, event.column)