def _parse_hunk_line(self, string): ''' Parse hunk line like '@@ -428,7 +428,7 @@ DEFINE_...'. The text after the second '@@' is a 'hunk note'. ''' self.spec = string string = ut.normalize_string(string, False) (_, old, new, tail) = string.split(' ', 3) if (tail == '@@'): # no hunk note self.note = '' else: self.note = tail.split(' ')[1] parts = old[1:].split(',') self.old_start = int(parts[0]) if (',' in old): # old has line count self.old_count = int(parts[1]) else: self.old_count = 1 parts = new[1:].split(',') self.new_start = int(parts[0]) if (',' in new): # new has line count self.new_count = int(parts[1]) else: self.new_count = 1
def _find_line(self, text, strings): ''' Try to find text in the source strings. Both text and strings are normalized to eliminate mismatches on varying whitespace. Source strings may contain items such as author name, etc. with unicode characters that can't be converted to ascii or latin-1, so we must not convert the strings to Python 2.x str objects. ''' text = ut.normalize_string(text, True) matches = [] for index in range(len(strings)): string = ut.normalize_string(strings[index], True) if (text == string): matches += [index] return matches
def _parse_diff_line(self, string): ''' Extract old and new paths from diff line, which has a format like: 'diff --git a/<path_to_file> b/<path_to_file>' We extract the paths and strip the leading 'a/' or 'b/'. ''' self.spec = string string = ut.normalize_string(string, False) parts = string.split(' ') self.a_path = parts[2][2:] # strip 'a/' self.b_path = parts[3][2:] # strip 'b/' # On rare occasions the diff line is corrupted if (self.a_path.endswith('/')): self.a_path = self.b_path
def _check_hunk_edits(self, filepath, edits, start, count, note, lines): """ Check edits against the "a" file. Report errors when lines to be deleted or merged are missing, and when lines to be added are present. Note that patch lines and source lines may have the same text, but differ in leading whitespace. We strip and normalize the strings before testing them. In 'find' mode, try to find missing lines. """ errors = warnings = 0 current = start mismatches = [] #index表示修改内容在该行中的index for (index, edit1, edit2) in self._get_edits(edits): op, text1 = edit1[0], edit1[1:] norm1 = ut.normalize_string(text1) line = lines[current - 1] # patch line numbers are 1-based norm3 = ut.normalize_string(line) #(edit1,edit2)表示变更(-,+),即先减后加 if (edit2 is not None): # change request text2 = edit2[1:] norm2 = ut.normalize_string(text2) if (norm2 == norm3): # Change already applied self._ok_msg( '"after" line found at %d: "%s"' % (current, text2), 3) elif (norm1 == norm3): # Change not yet applied self._info_msg( '"after" line not found at %d: "%s"' % (current, text2), 3) else: self._error_msg( '"before" line not found at %d: "%s"' % (current, text1), 3) current += 1 # advance to next edit line elif (op == '-'): # delete line # A line to be deleted by the patch should be at the specified location, # but may be elsewhere in the file. If self.find is True, we will look for it. # Doing so may return multiple matches. if (norm1 != norm3): self._error_msg( '"delete" line not found at %d: "%s"' % (current, text1), 3) mismatches += [(index, '-')] else: if (self.mode == 'complete'): self._ok_msg( '"delete" line found at %d: "%s"' % (current, text1), 3) current += 1 # advance to next edit line elif (op == '+'): # insert line # A line to be inserted by the patch should not be at the specified location, # but may be elsewhere in the file. If self.find is True, we will look for # significant "add" lines below. Doing so may return multiple matches. if (norm1 == norm3): self._error_msg( '"add" line found at %d: "%s"' % (current, text1), 3) errors += 1 else: if (self.mode == 'complete'): self._info_msg( '"add" line not found at next line: "%s"' % text1, 3) mismatches += [(index, '+')] else: # (op == ' '): # merge line # a line to be merged by the patch should be at the specified location, # but may be elsewhere in the file. If self.find is True, we will look for it. # Doing so may return multiple matches. if (norm1 != norm3): self._warn_msg( '"merge" line not found at %d: "%s"' % (current, text1), 3) warnings += 1 mismatches += [(index, ' ')] elif (self.mode == 'complete'): self._ok_msg( '"merge" line found at %d: "%s"' % (current, text1), 3) current += 1 # advance to next edit line if ((len(mismatches) > 0) and self.find): self._match(filepath, edits, lines, mismatches) return 1 else: return 0
def _change_hunk_edits(self, filepath, edits, start, count, note, lines): errors = warnings = 0 current = start new_edits = [] #-m,n中的m new_start = start context_start = start #+m,n中的n new_count = 0 #-m,n中的n context_count = 0 oldToNew = {} #index表示在edits中的下标 for (index, edit1, edit2) in self._get_edits(edits): op, text1 = edit1[0], edit1[1:] norm1 = ut.normalize_string(text1) print "lines: " + str(len(lines)) + "," + str(current) print "index: " + str(len(edits)) + "," + str(index) if (current > len(lines)): break line = lines[current - 1] # patch line numbers are 1-based norm3 = ut.normalize_string(line) print "begin changing for edit now" #(edit1,edit2)表示变更(-,+),即先减后加 if (edit2 is not None): # change request print " (-,+)" text2 = edit2[1:] norm2 = ut.normalize_string(text2) if (norm2 == norm3): # Change already applied self._ok_msg( '"after" line found at %d: "%s"' % (current, text2), 3) oldToNew[current] = -1 elif (norm1 == norm3): # Change not yet applied self._info_msg( '"after" line not found at %d: "%s"' % (current, text2), 3) oldToNew[current] = current new_edits.append(edit1) new_edits.append(edit2) new_count += 2 context_count += 1 else: self._error_msg( '"before" line not found at %d: "%s"' % (current, text1), 3) if (self._match2(filepath, edits, lines, index, current, oldToNew, new_edits, new_count, context_count)): new_edits.append(edit2) new_count += 1 context_count += 1 current += 1 # advance to next edit line elif (op == '-'): # delete line # A line to be deleted by the patch should be at the specified location, # but may be elsewhere in the file. If self.find is True, we will look for it. # Doing so may return multiple matches. print " -" if (norm1 != norm3): self._error_msg( '"delete" line not found at %d: "%s"' % (current, text1), 3) self._match2(filepath, edits, lines, index, current, oldToNew, new_edits, new_count, context_count) else: if (self.mode == 'complete'): self._ok_msg( '"delete" line found at %d: "%s"' % (current, text1), 3) oldToNew[current] = current new_edits.append(edit1) new_count += 1 context_count -= 1 current += 1 # advance to next edit line elif (op == '+'): # insert line # A line to be inserted by the patch should not be at the specified location, # but may be elsewhere in the file. If self.find is True, we will look for # significant "add" lines below. Doing so may return multiple matches. print " +" if (norm1 == norm3): self._error_msg( '"add" line found at %d: "%s"' % (current, text1), 3) oldToNew[current] = -1 errors += 1 else: if (self.mode == 'complete'): self._info_msg( '"add" line not found at next line: "%s"' % text1, 3) #查找上家的新位置,并+1作为自己的新位置 #current表示在lines中的位置,即实际的多少行 up = current - 1 #index表示在edits中的下标 up_index = index - 1 #查找上家的新位置 print " looking for new up" #如果当前已经是头了,则直接查找当前行的新位置 if (up <= 0): self._match2(filepath, edits, lines, index, current, oldToNew, new_edits, new_count, context_count) #如果还未到头,且 #上家尚未查找过新位置,或者上家的新位置没有找到(上家在新文件中已被删除) #那么查找上家的新位置,或者查找上家的上家 elif (not (oldToNew.has_key(up)) or oldToNew[up] == -1): #如果当前上家没找到新位置,则继续往上找 while (oldToNew.has_key(up) and oldToNew[up] == -1): up = up - 1 up_index = up_index - 1 #查找当前上家的新位置,若没有,则继续往上找 print " begin 2nd while" while (up > 0 and up_index > 0): edit_text = edits[up_index] text = edit_text[1:] print "text got" if (text.strip() == 'bool'): print " pass" pass if (self._is_landmark(filepath, text)): matches = self._find_line(text, lines) print " find matched for edit in old" if (matches): min = sys.maxint #若有多个match,选择其中离current最近的 for match in matches: if (abs(match - current) < min): min = match - current #记录找到的该行的新位置 oldToNew[up] = (min + current) + 1 print " matched: " + str( up) + "," + str(up_index) break else: print " not matched: " + str( up) + "," + str(up_index) up = up - 1 up_index = up_index - 1 #将找到的上家新位置+1,作为自己的新位置,并将当前行加入到new_edits中 if (not (oldToNew.has_key(up))): errors += 1 else: oldToNew[current] = oldToNew[up] + 1 new_edits.append(edit1) new_count += 1 context_count += 1 print " finding out up: " + str(up) current += 1 else: # (op == ' '): # merge line # a line to be merged by the patch should be at the specified location, # but may be elsewhere in the file. If self.find is True, we will look for it. # Doing so may return multiple matches. print " merge" if (norm1 != norm3): self._match2(filepath, edits, lines, index, current, oldToNew, new_edits, new_count, context_count) elif (self.mode == 'complete'): self._ok_msg( '"merge" line found at %d: "%s"' % (current, text1), 3) elif (norm1 == norm3): oldToNew[current] = current new_edits.append(edit1) new_count += 1 context_count += 1 current += 1 # advance to next edit line #记录新的起始位置 new_start = start while ((oldToNew.has_key(new_start)) and oldToNew[new_start] == -1): new_start += 1 #待修改 for edit in edits: op, text = edit[0], edit[1:] if (op == ' '): context_start = new_start break return new_edits, new_start, context_start, new_count, context_count
def _patch_hunk_edits(self, filepath, edits, start, count, note, lines): """ Check edits against the "a" file. Report errors when lines to be deleted or merged are missing, and when lines to be added are present. Note that patch lines and source lines may have the same text, but differ in leading whitespace. We strip and normalize the strings before testing them. In 'find' mode, try to find missing lines. """ errors = warnings = 0 current = start #[修改类型,该行修改前新位置,该行修改后新位置] new_place = [] mismatches = [] log = "" #index:记录在当前hunk中是第几行edit for (index, edit1, edit2) in self._get_edits(edits): op, text1 = edit1[0], edit1[1:] norm1 = ut.normalize_string(text1) if (current < len(lines)): line = lines[current - 1] # patch line numbers are 1-based norm3 = ut.normalize_string(line) else: break #(edit1,edit2)表示变更(-,+),即先减后加 if (edit2 is not None): # change request text2 = edit2[1:] norm2 = ut.normalize_string(text2) log += " change edit:\n" if (norm2 == norm3): # Change already applied self._ok_msg( '"after" line found at %d: "%s"' % (current, text2), 3) #此时change已经被应用,该两条连续edit可以被删除 log += " change is applied,delete this edit\n" elif (norm1 == norm3): # Change not yet applied self._info_msg( '"after" line not found at %d: "%s"' % (current, text2), 3) #此时change尚未被应用,该两条连续edit需要被添加进来 new_line_current = current new_line_edited = current new_place.append((edit1, new_line_current, -1)) new_place.append((edit2, -1, new_line_edited)) log += " change is not applied,added to new_place\n" else: self._error_msg( '"before" line not found at %d: "%s"' % (current, text1), 3) #此时edit1的内容不在原位,找到new中修改前的位置 new_line_current = self._find_new_place( text1, lines, current, filepath) #如果在new中能找到该行 log += " change line is not in place,try to find it in new\n" if (new_line_current != -1): #在new中修改后的位置为-1(被删除) new_line_edited = current #记录下该行edit的信息 new_place.append((edit1, new_line_current, -1)) new_place.append((edit2, -1, new_line_edited)) log += " find it,added to new_place\n" #若new中不存在该行,则删除之 else: log += " not found, delete this edit\n" pass current += 1 # advance to next edit line elif (op == '-'): # delete line # A line to be deleted by the patch should be at the specified location, # but may be elsewhere in the file. If self.find is True, we will look for it. # Doing so may return multiple matches. log += " - edit:\n" if (norm1 != norm3): self._error_msg( '"delete" line not found at %d: "%s"' % (current, text1), 3) mismatches += [(index, '-')] log += " delete line is not in place,try to find it in new\n" #找到new中修改前的位置 new_line_current = self._find_new_place( text1, lines, current, filepath) if (filepath.find("ASTConverter") != -1): log += "ASTConverter:\n" print("ASTConverter:") log += "delete line:" + text + " \n new place: " + str( new_line_current) + "\n" print("delete line:" + text + " \n new place: " + str(new_line_current)) #如果在new中能找到该行 if (new_line_current != -1): #在new中修改后的位置为-1(被删除) new_line_edited = -1 #记录下该行edit的信息 new_place.append( (edit1, new_line_current, new_line_edited)) log += " find it,add to new_place\n" #若new中不存在该行,则删除之 else: log += " not found, delete this edit\n" pass else: if (self.mode == 'complete'): self._ok_msg( '"delete" line found at %d: "%s"' % (current, text1), 3) #若该行还在原处,添加该行edit的信息,不变即可 new_line_current = current new_line_edited = -1 new_place.append( (edit1, new_line_current, new_line_edited)) log += " delete line is in place, add it to new_place\n" current += 1 # advance to next edit line elif (op == '+'): # insert line # A line to be inserted by the patch should not be at the specified location, # but may be elsewhere in the file. If self.find is True, we will look for # significant "add" lines below. Doing so may return multiple matches. log += " + edit:\n" if (norm1 == norm3): self._error_msg( '"add" line found at %d: "%s"' % (current, text1), 3) errors += 1 log += " add line is already in place,delete this edit\n" #new中该位置已有该行,该条edit可被删除 else: if (self.mode == 'complete'): self._info_msg( '"add" line not found at next line: "%s"' % text1, 3) mismatches += [(index, '+')] new_line_current = self._find_new_place( text1, lines, current, filepath) log += " try to find add line in new:\n" #若new中已有被添加的行,则删除这条edit # if (new_line_current != -1) : # print(" add line is already in new,delete this edit") # pass #否则: # else: if (True): #如果该行不是第一行edit if (len(new_place)): #取出上一条edit (last_edit, last_current, last_edited) = new_place[-1] last_op, last_text = last_edit[0], last_edit[1:] # if (last_op == '+' or last_op == ' '): new_line_edited = last_current + 1 new_line_current = -1 #否则,因为该行edit是+,且该行在new中并没有出现,所以可直接使用start作为修改后的新位置 else: new_line_current = -1 new_line_edited = start #添加该行edit new_place.append( (edit1, new_line_current, new_line_edited)) log += " add line is not in new,find a new place for this edit,add to new_place\n" else: # (op == ' '): # merge line # a line to be merged by the patch should be at the specified location, # but may be elsewhere in the file. If self.find is True, we will look for it. # Doing so may return multiple matches. log += " merge line:\n" if (norm1 != norm3): self._warn_msg( '"merge" line not found at %d: "%s"' % (current, text1), 3) warnings += 1 mismatches += [(index, ' ')] log += " merge line not in place,try to find it in new\n" #找到new中修改前的位置 new_line_current = self._find_new_place( text1, lines, current, filepath) #如果在new中能找到该行 if (new_line_current != -1): #在new中修改后的位置为相同位置 new_line_edited = new_line_current #记录下该行edit的信息 new_place.append( (edit1, new_line_current, new_line_edited)) log += " find it,add to new_place\n" #若new中不存在该行,则删除之 else: log += " not in new,delete this edit\n" pass elif (self.mode == 'complete'): self._ok_msg( '"merge" line found at %d: "%s"' % (current, text1), 3) #若该行还在原处,添加该行edit的信息,不变即可 new_line_current = current new_line_edited = current new_place.append( (edit1, new_line_current, new_line_edited)) log += " merge line in place, add it to new_place\n" current += 1 # advance to next edit line #查找起始的修改前后新位置 find_before = False find_after = False before_start = -1 after_start = -1 log += " find start's new place for this hunk,before and after edited\n" for (edit, before, after) in new_place: if (find_before == False and before != -1): before_start = before find_before = True if (find_after == False and after != -1): after_start = after find_after = True if (find_before and find_after): break #如果前后两条edit的修改前新位置之间还有中间部分,则将其添加进来作为merge lines last_before = 0 last_after = 0 log += " find some merge lines missed between two edits,add them\n" for i, (edit, before, after) in enumerate(new_place): if (i != 0 and before - last_before > 1): add = before + 1 #这里可能会add超过lines范围? while (add < last_before and add < len(lines)): add_line = lines[add] add_text = ut.normalize_string(add_line) new_place.insert(add, (" " + add_text, add, add)) add += 1 log += " add lines...\n" last_before = before last_after = after #查找结束的修改前后新位置 find_before = False find_after = False before_end = -1 after_end = -1 log += " find end's new place for this hunk,before and after edited\n" for (edit, before, after) in new_place[::-1]: if (find_before == False and before != -1): before_end = before find_before = True if (find_after == False and after != -1): after_end = after find_after = True if (find_before and find_after): break #计算修改前后的行数统计 before_count = before_end - before_start + 1 after_count = after_end - after_start + 1 return (new_place, before_start, before_count, after_start, after_count, log)
def _check_hunk_edits(self, filepath, edits, start, count, note, lines): """ Check edits against the "a" file. Report errors when lines to be deleted or merged are missing, and when lines to be added are present. Note that patch lines and source lines may have the same text, but differ in leading whitespace. We strip and normalize the strings before testing them. In 'find' mode, try to find missing lines. """ errors = warnings = 0 current = start mismatches = [] for (index, edit1, edit2) in self._get_edits(edits): op, text1 = edit1[0], edit1[1:] norm1 = ut.normalize_string(text1) line = lines[current - 1] # patch line numbers are 1-based norm3 = ut.normalize_string(line) if (edit2 is not None): # change request text2 = edit2[1:] norm2 = ut.normalize_string(text2) if (norm2 == norm3): # Change already applied self._ok_msg('"after" line found at %d: "%s"' % (current, text2), 3) elif (norm1 == norm3): # Change not yet applied self._info_msg('"after" line not found at %d: "%s"' % (current, text2), 3) else: self._error_msg('"before" line not found at %d: "%s"' % (current, text1), 3) current += 1 # advance to next edit line elif (op == '-'): # delete line # A line to be deleted by the patch should be at the specified location, # but may be elsewhere in the file. If self.find is True, we will look for it. # Doing so may return multiple matches. if (norm1 != norm3): self._error_msg('"delete" line not found at %d: "%s"' % (current, text1), 3) mismatches += [(index, '-')] else: if (self.mode == 'complete'): self._ok_msg('"delete" line found at %d: "%s"' % (current, text1), 3) current += 1 # advance to next edit line elif (op == '+'): # insert line # A line to be inserted by the patch should not be at the specified location, # but may be elsewhere in the file. If self.find is True, we will look for # significant "add" lines below. Doing so may return multiple matches. if (norm1 == norm3): self._error_msg('"add" line found at %d: "%s"' % (current, text1), 3) errors += 1 else: if (self.mode == 'complete'): self._info_msg('"add" line not found at next line: "%s"' % text1, 3) mismatches += [(index, '+')] else: # (op == ' '): # merge line # a line to be merged by the patch should be at the specified location, # but may be elsewhere in the file. If self.find is True, we will look for it. # Doing so may return multiple matches. if (norm1 != norm3): self._warn_msg('"merge" line not found at %d: "%s"' % (current, text1), 3) warnings += 1 mismatches += [(index, ' ')] elif (self.mode == 'complete'): self._ok_msg('"merge" line found at %d: "%s"' % (current, text1), 3) current += 1 # advance to next edit line if ((len(mismatches) > 0) and self.find): self._match(filepath, edits, lines, mismatches) return 1 else: return 0