def __format_location(event, source_file): loc = event['location'] line = util.get_line(source_file, loc['line']) if line == '': return line marker_line = line[0:(loc['col'] - 1)] marker_line = ' ' * (len(marker_line) + marker_line.count('\t')) return '%s%s^' % (line.replace('\t', ' '), marker_line)
def generate_report_hash_no_bugpath(main_section, source_file): """ !!! NOT Compatible with the old hash generation method High level overview of the hash content: * file_name from the main diag section * checker message * line content from the source file if can be read up * column numbers from the main diag sections location * whitespaces from the beginning of the source content are removed """ try: m_loc = main_section.get('location') source_line = m_loc.get('line') from_col = m_loc.get('col') until_col = m_loc.get('col') # WARNING!!! Changing the error handling type for encoding errors # can influence the hash content! line_content = get_line(source_file, source_line, errors='ignore') # Remove whitespaces so the hash will be independet of the # source code indentation. line_content, new_col = \ remove_whitespace(line_content, from_col) # Update the column number in sync with the # removed whitespaces. until_col = until_col - (from_col - new_col) from_col = new_col if line_content == '' and not os.path.isfile(source_file): LOG.error("Failed to include soruce line in the report hash.") LOG.error('%s does not exists!', source_file) file_name = os.path.basename(source_file) msg = main_section.get('description') hash_content = [ file_name, msg, line_content, str(from_col), str(until_col) ] string_to_hash = '|||'.join(hash_content) return hashlib.md5(string_to_hash.encode()).hexdigest() except Exception as ex: LOG.error("Hash generation failed") LOG.error(ex) return ''
def test_util_getline(self): """ Lines in files with carriage return character should be handled as separate lines. """ test_file_path = os.path.dirname(os.path.realpath(__file__)) file_to_process = os.path.join(test_file_path, 'newline') line1 = get_line(file_to_process, 1) self.assertEqual(line1, 'line1\n') line2 = get_line(file_to_process, 2) self.assertEqual(line2, 'line2\n') line4 = get_line(file_to_process, 4) self.assertEqual(line4, 'line4\n') line5 = get_line(file_to_process, 5) self.assertEqual(line5, 'line5\n') line6 = get_line(file_to_process, 6) self.assertEqual(line6, 'line6\n')
def get_source_line_comments(self, bug_line): """ This function returns the available preprocessed source code comments for a bug line. """ source_file = self.__source_file LOG.debug("Checking for source code comments in the source file '{0}'" "at line {1}".format(self.__source_file, bug_line)) previous_line_num = bug_line - 1 # No more line. if previous_line_num < 1: return [] source_line_comments = [] curr_suppress_comment = [] # Iterate over lines while it has comments or we reached # the top of the file. while True: source_line = util.get_line(source_file, previous_line_num) # This is not a comment. if not SourceCodeCommentHandler.__check_if_comment(source_line): break curr_suppress_comment.append(source_line.strip()) has_any_marker = any( marker in source_line for marker in self.source_code_comment_markers) # It is a comment. if has_any_marker: rev = list(reversed(curr_suppress_comment)) suppress_comment = ''.join(rev).replace('//', '') source_line_comments.append( self.__process_source_line_comment(suppress_comment)) curr_suppress_comment = [] if previous_line_num > 0: previous_line_num -= 1 else: break return source_line_comments
def check_source_suppress(self): """ Return true if there is a suppress comment or false if not. """ source_file = self.__source_file LOG.debug('Checking for suppress comment in the source file: ' + self.__source_file) previous_line_num = self.__bug_line - 1 suppression_result = False if previous_line_num > 0: marker_found = False comment_line = True collected_lines = [] while not marker_found and comment_line: source_line = util.get_line(source_file, previous_line_num) if SourceSuppressHandler.__check_if_comment(source_line): # It is a comment. if self.suppress_marker in source_line: # Found the marker. collected_lines.append(source_line.strip()) marker_found = True break else: collected_lines.append(source_line.strip()) comment_line = True else: # This is not a comment. break if previous_line_num > 0: previous_line_num -= 1 else: break # Collected comment lines upward from bug line. rev = list(reversed(collected_lines)) if marker_found: suppression_result = self.__process_suppress_info(''.join(rev)) LOG.debug('Suppress comment found: ' + str(suppression_result)) return suppression_result
def generate_report_hash(path, source_file, check_name): """ !!! Compatible with the old hash before v6.0 Keep this until needed for transformation tools from the old hash to the new hash. Hash generation algoritm for older plist versions where no issue hash was generated or for the plists generated from clang-tidy where the issue hash generation feature is still missing. As the main diagnositc section the last element from the bug path is used. High level overview of the hash content: * file_name from the main diag section. * checker name * checker message * line content from the source file if can be read up * column numbers from the main diag section * range column numbers only from the control diag sections if column number in the range is not the same as the previous control diag section number in the bug path. If there are no control sections event section column numbers are used. """ def compare_ctrl_sections(curr, prev): """ Compare two sections and return column numbers which should be included in the path hash or None if the two compared sections ranges are identical. """ curr_edges = curr['edges'] curr_start_range_begin = curr_edges[0]['start'][0] curr_start_range_end = curr_edges[0]['start'][1] prev_edges = prev['edges'] prev_end_range_begin = prev_edges[0]['end'][0] prev_end_range_end = prev_edges[0]['end'][1] if curr_start_range_begin != prev_end_range_begin and \ curr_start_range_end != prev_end_range_end: return (curr_start_range_begin['col'], curr_start_range_end['col']) return None # The last diag section from the bug path used as a main # diagnostic section. try: ctrl_sections = [x for x in path if x.get('kind') == 'control'] main_section = path[-1] m_loc = main_section.get('location') source_line = m_loc.get('line') from_col = m_loc.get('col') until_col = m_loc.get('col') # WARNING!!! Changing the error handling type for encoding errors # can influence the hash content! line_content = get_line(source_file, source_line, errors='ignore') if line_content == '' and not os.path.isfile(source_file): LOG.error("Failed to generate report hash.") LOG.error('%s does not exists!' % source_file) file_name = os.path.basename(source_file) msg = main_section.get('message') hash_content = [ file_name, check_name, msg, line_content, str(from_col), str(until_col) ] hash_from_ctrl_section = True for i, section in enumerate(ctrl_sections): edges = section['edges'] try: start_range_begin = edges[0]['start'][0] start_range_end = edges[0]['start'][1] end_range_begin = edges[0]['end'][0] end_range_end = edges[0]['end'][1] if i > 0: prev = ctrl_sections[i - 1] col_to_append = compare_ctrl_sections(section, prev) if col_to_append: begin_col, end_col = col_to_append hash_content.append(str(begin_col)) hash_content.append(str(end_col)) else: hash_content.append(str(start_range_begin['col'])) hash_content.append(str(start_range_end['col'])) hash_content.append(str(end_range_begin['col'])) hash_content.append(str(end_range_end['col'])) except IndexError: # Edges might be empty. hash_from_ctrl_section = False # Hash generation from the control sections failed for some reason # use event section positions for hash generation. if not hash_from_ctrl_section: event_sections = [x for x in path if x.get('kind') == 'event'] for i, section in enumerate(event_sections): loc = section['location'] col_num = loc['col'] hash_content.append(str(col_num)) string_to_hash = '|||'.join(hash_content) return hashlib.md5(string_to_hash.encode()).hexdigest() except Exception as ex: LOG.error("Hash generation failed") LOG.error(ex) return ''
def get_source_line_comments(self, bug_line): """ This function returns the available preprocessed source code comments for a bug line. """ source_file = self.__source_file LOG.debug("Checking for source code comments in the source file '{0}'" "at line {1}".format(self.__source_file, bug_line)) previous_line_num = bug_line - 1 # No more line. if previous_line_num < 1: return [] source_line_comments = [] curr_suppress_comment = [] # Iterate over lines while it has comments or we reached # the top of the file. cstyle_end_found = False while True: source_line = util.get_line(source_file, previous_line_num) # cpp style comment is_comment = \ SourceCodeCommentHandler.__check_if_comment(source_line) # cstyle commment cstyle_start, cstyle_end = \ SourceCodeCommentHandler.__check_if_cstyle_comment(source_line) if not is_comment and not cstyle_start and not cstyle_end: if not cstyle_end_found: # Not a comment break if not cstyle_end_found and cstyle_end: cstyle_end_found = True curr_suppress_comment.append(source_line) has_any_marker = any(marker in source_line for marker in self.source_code_comment_markers) # It is a comment. if has_any_marker: rev = list(reversed(curr_suppress_comment)) orig_review_comment = ' '.join(rev).strip() if rev[0].strip().startswith('//'): review_comment = orig_review_comment.replace('//', '') else: r_comment = [] for comment in rev: comment = comment.strip() comment = comment.replace('/*', '').replace('*/', '') if comment.startswith('*'): r_comment.append(comment[1:]) else: r_comment.append(comment) review_comment = ' '.join(r_comment).strip() comment = self.__process_source_line_comment(review_comment) if comment: source_line_comments.append(comment) else: _, file_name = os.path.split(source_file) LOG.warning( "Misspelled review status comment in %s@%d: %s", file_name, previous_line_num, orig_review_comment) curr_suppress_comment = [] if previous_line_num > 0: previous_line_num -= 1 else: break if cstyle_start: break return source_line_comments