def __init__(self, repo: SmartRepo, file_lines: List[bytes], ast_path: CursorPath): with file_from_text(file_lines, ast_path.file) as file: translation_unit = repo.get_cindex().parse(file.name) cursor = ast_path.locate(translation_unit, ast_path.file) parent_cursor = ast_path.drop(1).locate(translation_unit, ast_path.file) siblings = list(parent_cursor.get_children()) insertion_point = siblings.index(cursor) - 1 self.parent_path = ast_path.drop(1) if insertion_point == -1: from_location = cursor.extent.start self.predecessor_path = None if len(siblings) > 1: to_location = SourceLocation.from_offset( translation_unit, siblings[1].extent.start.file, siblings[1].extent.start.offset - 1) else: to_location = cursor.extent.end else: from_location = siblings[insertion_point].extent.end self.predecessor_path = ast_path.drop(1).appended( parent_cursor, siblings[insertion_point]) to_location = cursor.extent.end self.from_location = from_location.offset self.to_location = to_location.offset self.ast_path = ast_path self.file_lines = file_lines
def detect(cls, repo: SmartRepo, diff: git.DiffIndex) -> Iterable['SubASTInserted']: for m in diff.iter_change_type('M'): with repo.ast(m.a_blob) as a_ast, file_from_blob( m.b_blob) as b_file: b_file.seek(0) b_ast = repo.get_cindex().parse(b_file.name) for inserted_path in cls.detect_ast_insertions( a_ast.cursor, b_ast.cursor, CursorPath([m.a_path])): yield SubASTInserted(repo, b_file.readlines(), inserted_path)
def apply(self, repo: SmartRepo, repo_state: RepoState) -> None: file_text = repo_state[self.path.file] with file_from_text(file_text, self.path.file) as file: translation_unit = repo.get_cindex().parse(file.name) variable = self.path.locate(translation_unit, self.path.file) usages = search_ast(translation_unit, self.path.file, lambda cursor: cursor.kind == CursorKind.DECL_REF_EXPR and cursor.get_definition() == variable) replacements = [Replacement(variable.location.line - 1, variable.location.column - 1, variable.location.column + len(variable.spelling) - 1, self.new_name)] for usage_path in usages: usage = usage_path.locate(translation_unit, self.path.file) range: SourceRange = usage.extent start: SourceLocation = range.start end: SourceLocation = range.end assert start.line == end.line assert file_text[start.line - 1][start.column - 1:end.column - 1] == variable.spelling.encode('utf-8') replacements.append(Replacement(start.line - 1, start.column - 1, end.column - 1, self.new_name)) file_text = apply_replacements(file_text, replacements) repo_state[self.path.file] = file_text
def detect(cls: Type['VariableRenamed'], repo: SmartRepo, diff: git.DiffIndex) -> Iterable['VariableRenamed']: for m in diff.iter_change_type('M'): with file_from_blob(m.a_blob) as a, file_from_blob(m.b_blob) as b: for renamed, new_name in RenamingDetector(repo.get_cindex()).get_renamed_variables(m.a_path, a.name, b.name).items(): yield VariableRenamed(renamed, new_name)