def testInsertAfterLastIndex(self): input = InputStream('abc') lexer = TestLexer(input) stream = CommonTokenStream(lexer=lexer) stream.fill() rewriter = TokenStreamRewriter(tokens=stream) rewriter.insertAfter(10, 'x') self.assertEqual(rewriter.getDefaultText(), 'abcx')
class CollapseHierarchyRefactoringGetFieldTextListener(JavaParserLabeledListener): def __init__(self, common_token_stream: CommonTokenStream = None, child_class=None): if child_class is None: self.moved_fields = [] else: self.child_class = child_class if common_token_stream is None: raise ValueError('common_token_stream is None') else: self.token_stream_rewriter = TokenStreamRewriter(common_token_stream) self.is_children_class = False self.detected_field = None self.detected_method = None self.TAB = "\t" self.NEW_LINE = "\n" self.fieldcode = "" def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): class_identifier = ctx.IDENTIFIER().getText() if class_identifier == self.child_class: self.is_source_class = True self.fieldcode += self.NEW_LINE * 2 self.fieldcode += f"// child class({self.child_class}) fields: " + self.NEW_LINE else: self.is_source_class = False def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if self.is_source_class: self.is_source_class = False def exitCompilationUnit(self, ctx: JavaParserLabeled.CompilationUnitContext): self.token_stream_rewriter.insertAfter( index=ctx.stop.tokenIndex, text=self.fieldcode ) # def enterVariableDeclaratorId(self, ctx:JavaParserLabeled.VariableDeclaratorIdContext): # if not self.is_source_class: # return None # self.detected_field = ctx.IDENTIFIER().getText() def exitFieldDeclaration(self, ctx: JavaParserLabeled.FieldDeclarationContext): if not self.is_source_class: return None self.detected_field = ctx.variableDeclarators().getText().split(',') print("Here it is a field") grand_parent_ctx = ctx.parentCtx.parentCtx modifier = "" for i in range(0, len(grand_parent_ctx.modifier())): modifier += grand_parent_ctx.modifier(i).getText() modifier += " " field_type = ctx.typeType().getText() self.fieldcode += f"{self.TAB}{modifier} {field_type} {self.detected_field[0]};{self.NEW_LINE}"
def testInsertAfterLastIndex(self): input = InputStream('abc') lexer = TestLexer(input) stream = CommonTokenStream(lexer=lexer) stream.fill() rewriter = TokenStreamRewriter(tokens=stream) rewriter.insertAfter(10, 'x') self.assertEquals(rewriter.getDefaultText(), 'abcx')
def test2InsertBeforeAfterMiddleIndex(self): input = InputStream('abc') lexer = TestLexer(input) stream = CommonTokenStream(lexer=lexer) stream.fill() rewriter = TokenStreamRewriter(tokens=stream) rewriter.insertBeforeIndex(1, 'x') rewriter.insertAfter(1, 'x') self.assertEquals(rewriter.getDefaultText(), 'axbxc')
def testReplaceRangeThenInsertAfterRightEdge(self): input = InputStream('abcccba') lexer = TestLexer(input) stream = CommonTokenStream(lexer=lexer) stream.fill() rewriter = TokenStreamRewriter(tokens=stream) rewriter.replaceRange(2, 4, 'x') rewriter.insertAfter(4, 'y') self.assertEqual('abxyba', rewriter.getDefaultText())
def testReplaceThenInsertAfterLastIndex(self): input = InputStream('abc') lexer = TestLexer(input) stream = CommonTokenStream(lexer=lexer) stream.fill() rewriter = TokenStreamRewriter(tokens=stream) rewriter.replaceIndex(2, 'x') rewriter.insertAfter(2, 'y') self.assertEquals('abxy', rewriter.getDefaultText())
def testReplaceRangeThenInsertAfterRightEdge(self): input = InputStream('abcccba') lexer = TestLexer(input) stream = CommonTokenStream(lexer=lexer) stream.fill() rewriter = TokenStreamRewriter(tokens=stream) rewriter.replaceRange(2, 4, 'x') rewriter.insertAfter(4, 'y') self.assertEquals('abxyba', rewriter.getDefaultText())
def test2InsertBeforeAfterMiddleIndex(self): input = InputStream('abc') lexer = TestLexer(input) stream = CommonTokenStream(lexer=lexer) stream.fill() rewriter = TokenStreamRewriter(tokens=stream) rewriter.insertBeforeIndex(1, 'x') rewriter.insertAfter(1, 'x') self.assertEqual(rewriter.getDefaultText(), 'axbxc')
def testReplaceThenInsertAfterLastIndex(self): input = InputStream('abc') lexer = TestLexer(input) stream = CommonTokenStream(lexer=lexer) stream.fill() rewriter = TokenStreamRewriter(tokens=stream) rewriter.replaceIndex(2, 'x') rewriter.insertAfter(2, 'y') self.assertEqual('abxy', rewriter.getDefaultText())
class AddingImplementStatementToClass(JavaParserLabeledListener): def __init__(self, common_token_stream, class_name, interface_package, interface_name): self.common_token_stream = common_token_stream self.class_name = class_name self.interface_package = interface_package self.interface_name = interface_name self.last_import_token_index = None self.implement_token_index = None self.implement_state = [] if common_token_stream is not None: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) def enterPackageDeclaration( self, ctx: JavaParserLabeled.PackageDeclarationContext): self.last_import_token_index = ctx.stop.tokenIndex def enterImportDeclaration( self, ctx: JavaParserLabeled.ImportDeclarationContext): self.last_import_token_index = ctx.stop.tokenIndex def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if ctx.IDENTIFIER().getText() == self.class_name: self.implement_token_index = ctx.IDENTIFIER().symbol.tokenIndex if ctx.EXTENDS() is not None: self.implement_state.append(ctx.EXTENDS().getText()) self.implement_token_index = ctx.typeType().stop.tokenIndex if ctx.IMPLEMENTS() is not None: self.implement_state.append(ctx.IMPLEMENTS().getText()) self.implement_token_index = ctx.typeList().typeType( )[-1].stop.tokenIndex def exitCompilationUnit(self, ctx: JavaParserLabeled.CompilationUnitContext): import_text = f"\nimport {self.interface_package}.{self.interface_name};" self.token_stream_rewriter.insertAfter( self.last_import_token_index, import_text, program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME) if 'implements' in self.implement_state: implement_text = f",{self.interface_name}" else: implement_text = f" implements {self.interface_name}" self.token_stream_rewriter.insertAfter( self.implement_token_index, implement_text, program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME)
def testPreservesOrderOfContiguousInserts(self): """ Test for fix for: https://github.com/antlr/antlr4/issues/550 """ input = InputStream('aa') lexer = TestLexer(input) stream = CommonTokenStream(lexer=lexer) stream.fill() rewriter = TokenStreamRewriter(tokens=stream) rewriter.insertBeforeIndex(0, '<b>') rewriter.insertAfter(0, '</b>') rewriter.insertBeforeIndex(1, '<b>') rewriter.insertAfter(1, '</b>') self.assertEquals('<b>a</b><b>a</b>', rewriter.getDefaultText())
def testPreservesOrderOfContiguousInserts(self): """ Test for fix for: https://github.com/antlr/antlr4/issues/550 """ input = InputStream('aa') lexer = TestLexer(input) stream = CommonTokenStream(lexer=lexer) stream.fill() rewriter = TokenStreamRewriter(tokens=stream) rewriter.insertBeforeIndex(0, '<b>') rewriter.insertAfter(0, '</b>') rewriter.insertBeforeIndex(1, '<b>') rewriter.insertAfter(1, '</b>') self.assertEqual('<b>a</b><b>a</b>', rewriter.getDefaultText())
def testToStringStartStop2(self): input = InputStream('x = 3 * 0 + 2 * 0;') lexer = TestLexer2(input) stream = CommonTokenStream(lexer=lexer) stream.fill() rewriter = TokenStreamRewriter(tokens=stream) self.assertEqual('x = 3 * 0 + 2 * 0;', rewriter.getDefaultText()) # replace 3 * 0 with 0 rewriter.replaceRange(4, 8, '0') self.assertEqual('x = 0 + 2 * 0;', rewriter.getDefaultText()) self.assertEqual('x = 0 + 2 * 0;', rewriter.getText('default', 0, 17)) self.assertEqual('0', rewriter.getText('default', 4, 8)) self.assertEqual('x = 0', rewriter.getText('default', 0, 8)) self.assertEqual('2 * 0', rewriter.getText('default', 12, 16)) rewriter.insertAfter(17, "// comment") self.assertEqual('2 * 0;// comment', rewriter.getText('default', 12, 18)) self.assertEqual('x = 0', rewriter.getText('default', 0, 8))
def testToStringStartStop2(self): input = InputStream('x = 3 * 0 + 2 * 0;') lexer = TestLexer2(input) stream = CommonTokenStream(lexer=lexer) stream.fill() rewriter = TokenStreamRewriter(tokens=stream) self.assertEquals('x = 3 * 0 + 2 * 0;', rewriter.getDefaultText()) # replace 3 * 0 with 0 rewriter.replaceRange(4, 8, '0') self.assertEquals('x = 0 + 2 * 0;', rewriter.getDefaultText()) self.assertEquals('x = 0 + 2 * 0;', rewriter.getText('default', Interval(0, 17))) self.assertEquals('0', rewriter.getText('default', Interval(4, 8))) self.assertEquals('x = 0', rewriter.getText('default', Interval(0, 8))) self.assertEquals('2 * 0', rewriter.getText('default', Interval(12, 16))) rewriter.insertAfter(17, "// comment") self.assertEquals('2 * 0;// comment', rewriter.getText('default', Interval(12, 18))) self.assertEquals('x = 0', rewriter.getText('default', Interval(0, 8)))
class ReplaceParameterWithQueryListener(JavaParserLabeledListener): #constructor def __init__(self, common_token_stream: CommonTokenStream = None, target_class: str = None, target_method: str = None, target_parameters: list = None): if common_token_stream is None: raise ValueError("common token stream is None") else: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) if target_class is None: raise ValueError("target class is None") else: self.target_class = target_class if target_method is None: raise ValueError("target method is None") else: self.target_method = target_method if target_parameters is None: self.target_parameters = [] else: self.target_parameters = target_parameters self.current_class = None self.current_method = None self.current_method_call = None self.target_method_obj = None self.removed_expressions = [] self.local_variables = [] self.add_to_target_method = [] self.index_of_parameter = 0 def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): self.current_class = ctx.IDENTIFIER().getText() def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): self.current_class = None def enterMethodDeclaration( self, ctx: JavaParserLabeled.MethodDeclarationContext): self.current_method = ctx.IDENTIFIER().getText() if self.current_method == self.target_method and self.current_class == self.target_class: self.target_method_obj = ctx def exitMethodDeclaration(self, ctx: JavaParserLabeled.MethodDeclarationContext): self.FindObjrctIndex() def enterConstructorDeclaration( self, ctx: JavaParserLabeled.ConstructorDeclarationContext): self.current_method = ctx.IDENTIFIER().getText() if self.current_method == self.target_method and self.current_class == self.target_class: self.target_method_obj = ctx def exitConstructorDeclaration( self, ctx: JavaParserLabeled.ConstructorDeclarationContext): self.FindObjrctIndex() def FindObjrctIndex(self): i = 0 for expression in self.removed_expressions: #print("expression",expression.getText()) if type(expression) is JavaParserLabeled.Expression0Context and \ type(expression.primary()) is JavaParserLabeled.Primary4Context: self.removeExpression(expression) else: self.add_to_target_method.append(expression.getText()) #find index of target object self.index_of_parameter = i i += 1 self.removed_expressions = [] self.local_variables = [] self.current_method = None def enterLocalVariableDeclaration( self, ctx: JavaParserLabeled.LocalVariableDeclarationContext): self.local_variables.append(ctx.getText()) #print(self.local_variables) #delete in method call def removeExpression(self, expression): for local_variable in self.local_variables: flag = False variable_declarator = local_variable.variableDeclarators() print("$", variable_declarator.children) remaining_variables = [] for i in range(len(variable_declarator.children)): if i % 2 == 0: vd = variable_declarator.children[i] if expression.getText() != vd.variableDeclaratorId( ).getText(): remaining_variables.append(vd.getText()) else: self.add_to_target_method.append( vd.variableInitializer().getText()) flag = True if len(remaining_variables) == 0: parent_ctx = local_variable.parentCtx #print("parent",parent_ctx) self.token_stream_rewriter.delete( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, from_idx=parent_ctx.start.tokenIndex, to_idx=parent_ctx.stop.tokenIndex) elif len(remaining_variables) < ( len(variable_declarator.children) + 1) // 2: self.token_stream_rewriter.replaceRange( from_idx=variable_declarator.start.tokenIndex, to_idx=variable_declarator.stop.tokenIndex, text=f"{', '.join(remaining_variables)}") if flag: break def enterMethodCall0(self, ctx: JavaParserLabeled.MethodCall0Context): self.current_method_call = ctx.IDENTIFIER().getText() def exitMethodCall0(self, ctx: JavaParserLabeled.MethodCall0Context): self.current_method_call = None #in method call def enterExpressionList(self, ctx: JavaParserLabeled.ExpressionListContext): if self.current_method_call == self.target_method: #print("ex",ctx.getText()) expressions = [] for i in range(len(ctx.children)): if i % 2 == 0: if (i // 2) in self.target_parameters: self.removed_expressions.append(ctx.children[i]) else: expressions.append(ctx.children[i].getText()) #print(expressions) #else => ctx.children = , self.token_stream_rewriter.replaceRange( from_idx=ctx.start.tokenIndex, to_idx=ctx.stop.tokenIndex, text=f"{', '.join(expressions)}") #method body def exitCompilationUnit(self, ctx: JavaParserLabeled.CompilationUnitContext): temp = "" if self.target_method_obj is not None: #print("self",self.index_of_parameter) #declaration ctx = self.target_method_obj text = '' formal_parameter_list = ctx.formalParameters().formalParameterList( ) #print("b",ctx.formalParameters().formalParameterList().getText()[1]) survived_parameters = [] for j in range(len(formal_parameter_list.children)): #find object name to gain the name, insetr obj name in local variables if j % 2 == 0: if (j // 2) not in self.target_parameters: if j // 2 == self.index_of_parameter: parameter = formal_parameter_list.children[j] parameter_vdi = parameter.variableDeclaratorId( ).getText() temp = parameter_vdi for i in range(len(formal_parameter_list.children)): if i % 2 == 0: if (i // 2) in self.target_parameters: parameter = formal_parameter_list.children[i] parameter_type = parameter.typeType().getText() parameter_vdi = parameter.variableDeclaratorId( ).getText() #print("i",i) #print("target",parameter_vdi) parameter_initializer = self.add_to_target_method[0] print("temp", temp) text += parameter_type + ' ' + parameter_vdi + ' = ' + temp + '.' + parameter_initializer.split(".")[1] \ + ';' + "\n" + "\t" + "\t" self.add_to_target_method.remove(parameter_initializer) else: parameter = formal_parameter_list.children[i] parameter_type = parameter.typeType().getText() parameter_vdi = parameter.variableDeclaratorId( ).getText() survived_parameters.append(parameter_type + ' ' + parameter_vdi) #delete in declarition self.token_stream_rewriter.replaceRange( from_idx=formal_parameter_list.start.tokenIndex, to_idx=formal_parameter_list.stop.tokenIndex, text=f"{', '.join(survived_parameters)}") block_statement = ctx.methodBody().block().blockStatement()[0] self.token_stream_rewriter.insertAfter( index=block_statement.start.tokenIndex - 1, text=text)
class MoveMethodDownRefactoringListener(JavaParserLabeledListener): """ To implement extract class refactoring based on its actors. Creates a new class and move fields and methods from the old class to the new one """ def __init__(self, common_token_stream: CommonTokenStream = None, source_class: str = None, children_class=None, moved_methods: str = None, method_text: str = None): if method_text is None: self.method_text = [] else: self.method_text = method_text if moved_methods is None: self.moved_methods = [] else: self.moved_methods = moved_methods if children_class is None: self.moved_methods = [] else: self.children_class = children_class if common_token_stream is None: raise ValueError('common_token_stream is None') else: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) if source_class is None: raise ValueError("source_class is None") else: self.source_class = source_class # if destination_class is None: # raise ValueError("new_class is None") # else: # self.destibation_class = destination_class self.is_source_class = False self.detected_field = None self.detected_method = None self.TAB = "\t" self.NEW_LINE = "\n" self.code = "" self.tempdeclarationcode = "" def enterMethodDeclaration( self, ctx: JavaParserLabeled.MethodDeclarationContext): if self.is_source_class: # method_identifier = ctx.variableDeclarators().variableDeclarator().variableDeclaratorId().IDENTIFIER.getText() method_identifier = ctx.IDENTIFIER().getText() print(method_identifier) print(self.moved_methods) if self.moved_methods == method_identifier: methodDefctx = ctx.parentCtx.parentCtx start_index = methodDefctx.start.tokenIndex stop_index = methodDefctx.stop.tokenIndex self.method_text = self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, start=start_index, stop=stop_index) self.token_stream_rewriter.delete( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, from_idx=methodDefctx.start.tokenIndex, to_idx=methodDefctx.stop.tokenIndex) print("method text: ", self.method_text) else: return None def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): class_identifier = ctx.IDENTIFIER().getText() if class_identifier == self.source_class: self.is_source_class = True elif class_identifier == "B": print("enter B class") self.is_source_class = False def enterClassBody(self, ctx: JavaParserLabeled.ClassBodyContext): classDecctx = ctx.parentCtx class_identifier = classDecctx.IDENTIFIER().getText() if class_identifier in self.children_class: self.token_stream_rewriter.replaceRange( from_idx=ctx.start.tokenIndex + 1, to_idx=ctx.start.tokenIndex + 1, text="\n" + self.method_text + "\n") def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if self.is_source_class: self.is_source_class = False def exitCompilationUnit(self, ctx: JavaParserLabeled.CompilationUnitContext): self.token_stream_rewriter.insertAfter(index=ctx.stop.tokenIndex, text=self.code)
class ExtractClassRefactoringListener(Java9_v2Listener): """ To implement extract class refactoring based on its actors. Creates a new class and move fields and methods from the old class to the new one """ def __init__(self, common_token_stream: CommonTokenStream = None, source_class: str = None, new_class: str = None, moved_fields=None, moved_methods=None): if moved_methods is None: self.moved_methods = [] else: self.moved_methods = moved_methods if moved_fields is None: self.moved_fields = [] else: self.moved_fields = moved_fields if common_token_stream is None: raise ValueError('common_token_stream is None') else: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) if source_class is None: raise ValueError("source_class is None") else: self.source_class = source_class if new_class is None: raise ValueError("new_class is None") else: self.new_class = new_class self.is_source_class = False self.detected_field = None self.detected_method = None self.TAB = "\t" self.NEW_LINE = "\n" self.code = "" def enterNormalClassDeclaration( self, ctx: Java9_v2Parser.NormalClassDeclarationContext): print("Refactoring started, please wait...") class_identifier = ctx.identifier().getText() if class_identifier == self.source_class: self.is_source_class = True self.code += self.NEW_LINE * 2 self.code += f"// New class({self.new_class}) generated by CodART" + self.NEW_LINE self.code += f"class {self.new_class}{self.NEW_LINE}" + "{" + self.NEW_LINE else: self.is_source_class = False def exitNormalClassDeclaration( self, ctx: Java9_v2Parser.NormalClassDeclarationContext): if self.is_source_class: self.code += "}" self.is_source_class = False def exitOrdinaryCompilation( self, ctx: Java9_v2Parser.OrdinaryCompilationContext): print("Finished Processing...") self.token_stream_rewriter.insertAfter(index=ctx.stop.tokenIndex, text=self.code) def enterVariableDeclaratorId( self, ctx: Java9_v2Parser.VariableDeclaratorIdContext): if not self.is_source_class: return None field_identifier = ctx.identifier().getText() if field_identifier in self.moved_fields: self.detected_field = field_identifier def exitFieldDeclaration(self, ctx: Java9_v2Parser.FieldDeclarationContext): if not self.is_source_class: return None field_names = ctx.variableDeclaratorList().getText().split(",") if self.detected_field in field_names: modifier = ctx.fieldModifier(0).getText() field_type = ctx.unannType().getText() self.code += f"{self.TAB}{modifier} {field_type} {self.detected_field};{self.NEW_LINE}" # delete field from source class field_names.remove(self.detected_field) if field_names: self.token_stream_rewriter.replaceRange( from_idx=ctx.start.tokenIndex, to_idx=ctx.stop.tokenIndex, text=f"{modifier} {field_type} {','.join(field_names)};") else: self.token_stream_rewriter.delete( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, from_idx=ctx.start.tokenIndex, to_idx=ctx.stop.tokenIndex) self.detected_field = None def enterMethodDeclarator(self, ctx: Java9_v2Parser.MethodDeclaratorContext): if not self.is_source_class: return None method_identifier = ctx.identifier().getText() if method_identifier in self.moved_methods: self.detected_method = method_identifier def exitMethodDeclaration(self, ctx: Java9_v2Parser.MethodDeclarationContext): if not self.is_source_class: return None method_identifier = ctx.methodHeader().methodDeclarator().identifier( ).getText() if self.detected_method == method_identifier: start_index = ctx.start.tokenIndex stop_index = ctx.stop.tokenIndex method_text = self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, start=start_index, stop=stop_index) self.code += (self.NEW_LINE + self.TAB + method_text + self.NEW_LINE) # delete method from source class self.token_stream_rewriter.delete( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, from_idx=start_index, to_idx=stop_index) self.detected_method = None
class ExtractSubClassRefactoringListener(JavaParserLabeledListener): """ To implement extract class refactoring based on its actors. Creates a new class and move fields and methods from the old class to the new one """ def __init__(self, common_token_stream: CommonTokenStream = None, source_class: str = None, new_class: str = None, moved_fields=None, moved_methods=None): if moved_methods is None: self.moved_methods = [] else: self.moved_methods = moved_methods if moved_fields is None: self.moved_fields = [] else: self.moved_fields = moved_fields if common_token_stream is None: raise ValueError('common_token_stream is None') else: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) if source_class is None: raise ValueError("source_class is None") else: self.source_class = source_class if new_class is None: raise ValueError("new_class is None") else: self.new_class = new_class self.is_source_class = False self.detected_field = None self.detected_method = None self.TAB = "\t" self.NEW_LINE = "\n" self.code = "" def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): class_identifier = ctx.IDENTIFIER().getText() if class_identifier == self.source_class: self.is_source_class = True self.code += self.NEW_LINE * 2 self.code += f"// New class({self.new_class}) generated by CodART" + self.NEW_LINE self.code += f"class {self.new_class} extends {self.source_class}{self.NEW_LINE}" + "{" + self.NEW_LINE else: self.is_source_class = False def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if self.is_source_class: self.code += "}" self.is_source_class = False def exitCompilationUnit(self, ctx: JavaParserLabeled.CompilationUnitContext): self.token_stream_rewriter.insertAfter(index=ctx.stop.tokenIndex, text=self.code) def enterVariableDeclaratorId( self, ctx: JavaParserLabeled.VariableDeclaratorIdContext): if not self.is_source_class: return None field_identifier = ctx.IDENTIFIER().getText() if field_identifier in self.moved_fields: self.detected_field = field_identifier def exitFieldDeclaration(self, ctx: JavaParserLabeled.FieldDeclarationContext): if not self.is_source_class: return None # field_names = ctx.variableDeclarators().getText().split(",") field_identifier = ctx.variableDeclarators().variableDeclarator( 0).variableDeclaratorId().IDENTIFIER().getText() field_names = list() field_names.append(field_identifier) print("field_names=", field_names) print("Here") grand_parent_ctx = ctx.parentCtx.parentCtx if self.detected_field in field_names: if (not grand_parent_ctx.modifier()): # print("******************************************") modifier = "" else: modifier = grand_parent_ctx.modifier(0).getText() field_type = ctx.typeType().getText() self.code += f"{self.TAB}{modifier} {field_type} {self.detected_field};{self.NEW_LINE}" # delete field from source class # field_names.remove(self.detected_field) # if field_names: # self.token_stream_rewriter.replaceRange( # from_idx=grand_parent_ctx.start.tokenIndex, # to_idx=grand_parent_ctx.stop.tokenIndex, # text=f"{modifier} {field_type} {','.join(field_names)};" # ) # else: # self.token_stream_rewriter.delete( # program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, # from_idx=grand_parent_ctx.start.tokenIndex, # to_idx=grand_parent_ctx.stop.tokenIndex # ) self.detected_field = None def enterMethodDeclaration( self, ctx: JavaParserLabeled.MethodDeclarationContext): if not self.is_source_class: return None method_identifier = ctx.IDENTIFIER().getText() if method_identifier in self.moved_methods: self.detected_method = method_identifier def exitMethodDeclaration(self, ctx: JavaParserLabeled.MethodDeclarationContext): if not self.is_source_class: return None method_identifier = ctx.IDENTIFIER().getText() if self.detected_method == method_identifier: start_index = ctx.start.tokenIndex stop_index = ctx.stop.tokenIndex method_text = self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, start=start_index, stop=stop_index) self.code += (self.NEW_LINE + self.TAB + method_text + self.NEW_LINE) # delete method from source class # self.token_stream_rewriter.delete( # program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, # from_idx=start_index, # to_idx=stop_index # ) self.detected_method = None
class PropagationMakeConcreteClassRefactoringListener(JavaParserLabeledListener ): def __init__(self, common_token_stream: CommonTokenStream = None, Source_class=None, using_variable_name=None, used_method_name=None, propagated_class_name=None): if Source_class is None: self.source_class = [] else: self.source_class = Source_class if used_method_name is None: self.using_method_name = [] else: self.using_method_name = used_method_name if using_variable_name is None: self.using_variable_name = [] else: self.using_variable_name = using_variable_name if propagated_class_name is None: self.propagated_class_name = [] else: self.propagated_class_name = propagated_class_name if common_token_stream is None: raise ValueError('common_token_stream is None') else: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) self.is_class = False self.TAB = "\t" self.NEW_LINE = "\n" self.object = "" def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): print("Propagation started, please wait...") class_identifier = ctx.IDENTIFIER().getText() if class_identifier in self.propagated_class_name: self.is_class = True else: self.is_class = False if class_identifier in self.propagated_class_name: self.token_stream_rewriter.replaceRange( from_idx=ctx.start.tokenIndex, to_idx=ctx.typeType().stop.tokenIndex, text=ctx.CLASS().getText() + ' ' + ctx.IDENTIFIER().getText()) def enterClassBody(self, ctx: JavaParserLabeled.ClassBodyContext): if not self.is_class: return None self.object = 'obj' + str.capitalize(self.source_class) self.token_stream_rewriter.insertAfter( index=ctx.start.tokenIndex, text=self.NEW_LINE + self.TAB + self.TAB + self.source_class + ' ' + self.object + ' = ' + 'new ' + self.source_class + '(' + ')' + ';' + self.NEW_LINE, program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME) def enterVariableDeclarator( self, ctx: JavaParserLabeled.VariableDeclaratorContext): if not self.is_class: return None if ctx.variableDeclaratorId().IDENTIFIER().getText( ) in self.using_variable_name: count = ctx.getChildCount() if count == 3: self.token_stream_rewriter.insertBefore( index=ctx.variableInitializer().start.tokenIndex, text=self.object + '.', program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME) def enterExpression(self, ctx: JavaParserLabeled.ExpressionContext): if not self.is_class: return None if ctx != None: if ctx.methodCall() != None: if ctx.methodCall().IDENTIFIER().getText( ) in self.using_method_name: count = ctx.methodCall().getChildCount() if count == 3: self.token_stream_rewriter.insertBefore( index=ctx.start.tokenIndex, text=self.object + '.', program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME)
class FieldUsageListener(UtilsListener): """ FieldUsageListener finds all the usage of an specified field f, from a class c in package pkg. """ def __init__(self, filename: str, source_class: str, source_package: str, target_class: str, target_package: str, field_name: str, field_candidates: set, field_tobe_moved: Field): super(FieldUsageListener, self).__init__(filename) self.source_class = source_class self.source_package = source_package self.target_class = target_class self.target_package = target_package self.field_name = field_name self.has_imported_source = False self.has_imported_target = False self.usages = [] # current class name is the public class in each file. self.current_class_name = "" self.field_candidates = field_candidates self.rewriter = None # this represents the text to be added in target i.e. public int a; self.field_tobe_moved = field_tobe_moved self.methods_tobe_updated = [] def enterCompilationUnit(self, ctx: JavaParser.CompilationUnitContext): super().enterCompilationUnit(ctx) self.rewriter = TokenStreamRewriter(ctx.parser.getTokenStream()) def enterClassDeclaration(self, ctx: JavaParser.ClassDeclarationContext): super().enterClassDeclaration(ctx) if ctx.parentCtx.classOrInterfaceModifier()[0].getText() == "public": self.current_class_name = ctx.IDENTIFIER().getText() else: return self.has_imported_source = self.file_info.has_imported_package(self.package.name) or \ self.file_info.has_imported_class(self.package.name, self.source_class) # import target if we're not in Target and have not imported before if self.current_class_name != self.target_class: self.rewriter.insertBeforeIndex( ctx.parentCtx.start.tokenIndex, f"import {self.target_package}.{self.target_class};\n") def enterClassBody(self, ctx: JavaParser.ClassBodyContext): super().exitClassBody(ctx) if self.current_class_name == self.target_class: replacement_text = "" if self.field_tobe_moved.name == self.field_name: for mod in self.field_tobe_moved.modifiers: replacement_text += f"{mod} " replacement_text += f"{self.field_tobe_moved.datatype} {self.field_tobe_moved.name};" self.rewriter.insertAfter(ctx.start.tokenIndex, f"\n\t{replacement_text}\n") # add getter and setter name = self.field_tobe_moved.name method_name = self.field_tobe_moved.name.upper( ) + self.field_tobe_moved.name[1:-1] type = self.field_tobe_moved.datatype getter = f"\tpublic {type} get{method_name}() {{ return this.{name}; }}\n" setter = f"\tpublic void set{method_name}({type} {name}) {{ this.{name} = {name}; }}\n" self.rewriter.insertBeforeIndex(ctx.stop.tokenIndex, getter) self.rewriter.insertBeforeIndex(ctx.stop.tokenIndex, setter) def exitFieldDeclaration(self, ctx: JavaParser.FieldDeclarationContext): super().exitFieldDeclaration(ctx) if self.current_class_name != self.source_class: return if self.field_tobe_moved is None: field = self.package.classes[self.current_class_name].fields[ ctx.variableDeclarators().children[0].children[0].IDENTIFIER( ).getText()] if field.name == self.field_name: self.field_tobe_moved = field def exitClassBody(self, ctx: JavaParser.ClassBodyContext): super().exitClassBody(ctx) save(self.rewriter, self.filename) def exitMethodDeclaration(self, ctx: JavaParser.MethodDeclarationContext): super().exitMethodDeclaration(ctx) # we will remove getter and setter from source # and add it to target so there is no need to # find usages there if self.current_class_name == self.source_class and \ self.is_method_getter_or_setter(ctx.IDENTIFIER().getText()): self.rewriter.replaceRange( ctx.parentCtx.parentCtx.start.tokenIndex, ctx.parentCtx.parentCtx.stop.tokenIndex, "") def exitConstructorDeclaration( self, ctx: JavaParser.ConstructorDeclarationContext): self.current_method.name = ctx.IDENTIFIER().getText() self.current_method.returntype = self.current_method.class_name self.handleMethodUsage(ctx, True) super().exitConstructorDeclaration(ctx) def exitMethodBody(self, ctx: JavaParser.MethodBodyContext): super().exitMethodBody(ctx) self.handleMethodUsage(ctx, False) def handleMethodUsage(self, ctx, is_constructor: bool): method_identifier = ctx.IDENTIFIER().getText( ) if is_constructor else ctx.parentCtx.IDENTIFIER().getText() formal_params = ctx.formalParameters( ) if is_constructor else ctx.parentCtx.formalParameters() target_added = False target_param_name = "$$target" target_param = f"Target {target_param_name}" if \ len(self.current_method.parameters) == 0 \ else f", Target {target_param_name}" # if we have not imported source package or # Source class just ignore this if not self.has_imported_source: return local_candidates = set() if self.current_class_name == self.source_class: # we will remove getter and setter from source # and add it to target so there is no need to # find usages there if self.is_method_getter_or_setter(method_identifier): self.rewriter.replaceRange(ctx.start.tokenIndex, ctx.stop.tokenIndex, "") return local_candidates.add("this") # find parameters with type Source for t, identifier in self.current_method.parameters: if t == self.source_class: local_candidates.add(identifier) # find all local variables with type Source for var_or_exprs in self.current_method.body_local_vars_and_expr_names: if type(var_or_exprs) is LocalVariable: if var_or_exprs.datatype == self.source_class: local_candidates.add(var_or_exprs.identifier) should_ignore = False for var_or_exprs in self.current_method.body_local_vars_and_expr_names: if type(var_or_exprs) is ExpressionName: # we're going to find source.field try: local_ctx = var_or_exprs.parser_context.parentCtx.parentCtx.parentCtx.parentCtx.parentCtx.parentCtx creator = local_ctx.expression()[0].getText() if creator.__contains__( f"new{self.source_class}" ) and local_ctx.IDENTIFIER().getText() == self.field_name: self.propagate_field(local_ctx, target_param_name) except: pass if len(var_or_exprs.dot_separated_identifiers) < 2: continue if (var_or_exprs.dot_separated_identifiers[0] in local_candidates or var_or_exprs.dot_separated_identifiers[0] in self.field_candidates) and \ var_or_exprs.dot_separated_identifiers[1] == self.field_name: if not target_added: # add target to param self.rewriter.insertBeforeIndex( formal_params.stop.tokenIndex, target_param) self.methods_tobe_updated.append(self.current_method) target_added = True self.usages.append(var_or_exprs.parser_context) self.propagate_field(var_or_exprs.parser_context, target_param_name) elif type(var_or_exprs) is MethodInvocation: # we are going to find getter or setters # if len(var_or_exprs.dot_separated_identifiers) < 2: # continue if var_or_exprs.dot_separated_identifiers[ 0] == f"new{self.source_class}": if var_or_exprs.parser_context.methodCall() is not None and \ self.is_method_getter_or_setter( var_or_exprs.parser_context.methodCall().IDENTIFIER().getText()): self.propagate_getter_setter( var_or_exprs.parser_context, target_param_name) elif self.is_method_getter_or_setter( var_or_exprs.dot_separated_identifiers[0]): if not target_added: # add target to param self.rewriter.insertBeforeIndex( formal_params.stop.tokenIndex, target_param) self.methods_tobe_updated.append(self.current_method) target_added = True if not should_ignore and var_or_exprs.parser_context is not None and type( var_or_exprs.parser_context ) is not JavaParser.ExpressionContext: continue self.usages.append(var_or_exprs.parser_context) self.propagate_getter_setter_form2( var_or_exprs.parser_context, target_param_name) elif len(var_or_exprs.dot_separated_identifiers ) > 1 and self.is_getter_or_setter( var_or_exprs.dot_separated_identifiers[0], var_or_exprs.dot_separated_identifiers[1], local_candidates): if not target_added: # add target to param self.rewriter.insertBeforeIndex( formal_params.stop.tokenIndex, target_param) self.methods_tobe_updated.append(self.current_method) target_added = True self.usages.append(var_or_exprs.parser_context) self.propagate_getter_setter(var_or_exprs.parser_context, target_param_name) def is_getter_or_setter(self, first_id: str, second_id: str, local_candidates: set): return ( first_id in local_candidates or first_id in self.field_candidates ) and (second_id == f"set{self.field_name[0].upper() + self.field_name[1:-1]}" or second_id == f"get{self.field_name[0].upper() + self.field_name[1:-1]}" or second_id == f"has{self.field_name[0].upper() + self.field_name[1:-1]}" or second_id == f"is{self.field_name[0].upper() + self.field_name[1:-1]}") def is_method_getter_or_setter(self, method: str): return (method == f"set{self.field_name[0].upper() + self.field_name[1:-1]}" or method == f"get{self.field_name[0].upper() + self.field_name[1:-1]}" or method == f"has{self.field_name[0].upper() + self.field_name[1:-1]}" or method == f"is{self.field_name[0].upper() + self.field_name[1:-1]}") def propagate_getter_setter(self, ctx: JavaParser.ExpressionContext, target_name: str): index = ctx.DOT().symbol.tokenIndex self.rewriter.replaceRange(ctx.start.tokenIndex, index - 1, target_name) def propagate_getter_setter_form2(self, ctx: JavaParser.ExpressionContext, target_name: str): """ form 2 is getA() setA()... """ self.rewriter.insertBeforeIndex(ctx.start.tokenIndex, f"{target_name}.") def propagate_field(self, ctx: JavaParser.ExpressionContext, target_name: str): index = ctx.DOT().symbol.tokenIndex self.rewriter.replaceRange(ctx.start.tokenIndex, index - 1, target_name)
class ExtractMethodRefactoring(JavaParserLabeledListener): def __init__(self, common_token_stream: CommonTokenStream = None, class_name: str = "Main", new_method_name: str = "newMethod"): """ :param common_token_stream: :param class_name: the name of the class that duplications should be considered :param new_method_name: the name of the new method that contains that statements """ self.common_token_stream = common_token_stream self.tokens = common_token_stream.tokens self.refactor_class_name = class_name self.new_method_name = new_method_name # make a copy of the tokens if common_token_stream is None: raise ValueError('common_token_stream is None') else: self.token_stream_re_writer = TokenStreamRewriter( common_token_stream) self.method_statements = { } # dictionary that maps the methods to its statements # tree helper variables self.is_in_target_class = False self.is_in_a_method = False self.current_method_name = "" # refactoring self.duplicates = None # if it is None, then we don't have any duplications ###################################### # Collect statements from parse tree ###################################### def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): print("enterClassDeclaration") if is_equal(ctx.IDENTIFIER(), self.refactor_class_name): self.is_in_target_class = True def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if is_equal(ctx.IDENTIFIER(), self.refactor_class_name): self.is_in_target_class = False self.find_duplicates() # print(self.duplicates.duplications[0].statements[0].statement.getText()) if self.duplicates is not None and len( self.duplicates.duplications) > 0: self.refactor(ctx) def enterMethodDeclaration( self, ctx: JavaParserLabeled.MethodDeclarationContext): if self.is_in_target_class: self.is_in_a_method = True self.current_method_name = ctx.IDENTIFIER() self.method_statements[self.current_method_name] = [] def exitMethodDeclaration(self, ctx: JavaParserLabeled.MethodDeclarationContext): self.is_in_a_method = False def enterStatement15(self, ctx: JavaParserLabeled.Statement0Context): if self.is_in_target_class: if self.is_in_a_method: self.method_statements[self.current_method_name].append( Statement(ctx, [])) def log_statements_of_methods(self): """ It will print out statements of each method for the class. :return: """ for method_name in self.method_statements.keys(): print(method_name) statements = self.method_statements[method_name] for statement in statements: print(str(statement)) print("---------------") ########################## # Searching Duplications ########################## def check_semi_duplicate(self, sa, sb, k): """ It checks if the statements are similar or not. Two statements are similar if we can omit duplicated code with adding new method that has some arguments :param sa: first statements :param sb: second statement :param k: the k represent the index of the statements. :return: """ fta, ftb = sa.statement.start.tokenIndex, sb.statement.start.tokenIndex tta, ttb = sa.statement.stop.tokenIndex, sb.statement.stop.tokenIndex if tta - fta != ttb - ftb: return False, sa, sb count = 0 m = min(tta - fta, ttb - ftb) for i in range(m): txt_token_a = self.tokens[fta + i].text txt_token_b = self.tokens[ftb + i].text if txt_token_a != txt_token_b: if self.tokens[fta + i].type != self.tokens[ftb + i].type: return False, sa, sb else: history_a = list(map(lambda x: x[2], sa.variables)) history_b = list(map(lambda x: x[2], sb.variables)) count += 1 if txt_token_a not in history_a: sa.variables.append((self.tokens[fta + i].type, "variable{}Number{}{}".format( self.tokens[fta + i].type, k, count), txt_token_a)) if txt_token_b not in history_b: sb.variables.append((self.tokens[ftb + i].type, "variable{}Number{}{}".format( self.tokens[ftb + i].type, k, count), txt_token_b)) return True, sa, sb def get_duplicate_continues_statements(self, a_statements, b_statements): """ Find duplicate statements between two arrays of statements. :param a_statements: the first list of statements :param b_statements: the second list of statements :return: (k, i, j) that k represent number of duplicated statements, and i, j are the list of the statements. The length of each of them is k. return could be None if there was not any duplications. There might be lots of duplications, but it would return the one that has the most duplicated statements. """ len_a_statement = len(a_statements) len_b_statement = len(b_statements) # for any methods like such as getters or setters that have few number of # statements, we should return None. if len_b_statement <= 1 or len_a_statement <= 1: return None # diagnose exact duplications method_a_b_duplications = [] i = 0 while i < len_a_statement: j = 0 while j < len_b_statement: sa = a_statements[i] sb = b_statements[j] count_duplicate_statement = 0 a_duplicates = [] b_duplicates = [] k = 0 while is_equal(sa.statement.getText(), sb.statement.getText()) \ and i + k < len_a_statement and j + k < len_b_statement: sa = a_statements[i + k] sb = b_statements[j + k] count_duplicate_statement += 1 a_duplicates.append(sa) b_duplicates.append(sb) k += 1 if count_duplicate_statement != 0: method_a_b_duplications.append( (count_duplicate_statement, a_duplicates.copy(), b_duplicates.copy())) j += 1 i += 1 # calculate the maximum based on the number of duplications max_exact_duplicate = None if len(method_a_b_duplications) > 1: max_exact_duplicate = max(method_a_b_duplications, key=lambda x: x[0]) # diagnose semi duplications # here we search for duplications that can be avoided by passing variable method_a_b_semi_duplications = [] i = 0 while i < len_a_statement: j = 0 while j < len_b_statement: count_duplicate_statement = 0 a_duplicates = [] b_duplicates = [] k = 0 while i + k < len_a_statement and j + k < len_b_statement: sa = a_statements.copy()[i + k] sb = b_statements.copy()[j + k] if is_equal(sa.statement.getText(), sb.statement.getText()): count_duplicate_statement += 1 else: is_semi, sa, sb = self.check_semi_duplicate( sa.copy(), sb.copy(), k) if not is_semi: break count_duplicate_statement += 1 a_duplicates.append(sa.copy()) b_duplicates.append(sb.copy()) k += 1 if count_duplicate_statement != 0: method_a_b_semi_duplications.append( (count_duplicate_statement, a_duplicates.copy(), b_duplicates.copy())) j += 1 i += 1 # calculate the maximum based on the number of duplications max_semi_duplicate = None if len(method_a_b_semi_duplications) > 1: max_semi_duplicate = max(method_a_b_semi_duplications, key=lambda x: x[0]) return max(max_exact_duplicate, max_semi_duplicate, key=lambda x: x[0]) @staticmethod def log_duplication(duplicate, i, j, methods): """ It will show you a report about the a duplications. :param duplicate: is a tuple that (k, i, j): k is the number of duplications, and i, j are the statements. :param i: index of the first method :param j: index of the second method :param methods: a list of methods that are existed in the class. :return: """ print() print( "lines {}-{} in {} and lines {}-{} {} are duplicated. count: {}\n". format(duplicate[1][0].statement.start.line, duplicate[1][-1].statement.start.line, methods[i].getText(), duplicate[2][0].statement.start.line, duplicate[2][-1].statement.start.line, methods[j].getText(), duplicate[0]), list(map(lambda x: x.statement.getText(), duplicate[1]))) def find_duplicates(self): """ This method is responsible for choosing duplication and set it to self.duplicates. It will find the maximum lines of duplication, and search through all of the methods. This method compare each one of those methods using self.get_duplicate_continues_statements method. :return: """ # it is for representing the statements of each method # self.log_statements_of_methods() # Compare each one of methods with the other methods methods = list(self.method_statements.keys()) len_method = len(methods) i = 0 duplicates = { "statements": [], "lines": [], "text": "", "variables": [] } while i < len_method - 1: j = i + 1 while j < len_method: duplicate = self.get_duplicate_continues_statements( self.method_statements[methods[i]], self.method_statements[methods[j]]) # return value is None when not any duplications have been found. if duplicate is not None: self.log_duplication(duplicate, i, j, methods) if len(duplicates["statements"]) == 0: duplicates["statements"].append(duplicate[1]) duplicates["variables"] = duplicate[1] duplicates["lines"].append( duplicate[1][0].statement.start.line) for d in duplicate[1]: duplicates["text"] += d.statement.getText() # here we check how many duplications have been occurred. # trying to find out similar duplications to change them all together. for i in range(1, 3): print(duplicate[i][0].statement.start.line) if duplicate[i][ 0].statement.start.line not in duplicates[ "lines"]: temp = "" for d in duplicate[i]: temp += d.statement.getText() if temp == duplicates["text"]: duplicates["statements"].append(duplicate[i]) else: is_ok = True if len(duplicate[i]) != len( duplicates["statements"][0]): break else: for s1 in duplicates["statements"][0]: for s2 in duplicate[i]: if len(s1.variables) != len( s2.variables): is_ok = False break else: for v1 in s1.variables: for v2 in s2.variables: if v1[0] != v2[0]: is_ok = False break if is_ok: duplicates[ "statements"].append( duplicate[i]) j += 1 i += 1 self.duplicates = DuplicationRefactoring(duplicates["statements"]) ############### # Refactoring # Refactoring is in 2 steps. # First: Creating a new method at the end of the class. # Second: Deleting the duplications and replacing with new method. ############### def create_new_method(self, start_index): """ It creates a new method based on the given name to avoid duplication. :param start_index: the index of token. :return: """ # here we are creating the arguments d = self.duplicates.duplications[0] func_args = [] for s in d.statements: for v in s.variables: arg_type = v[0] arg_name = v[1] try: func_args.append(VariableTypes.MAP_TYPE[arg_type] + " " + arg_name) except: pass func_args = ", ".join(func_args) # adding the new method new_method = "\n" new_method += "\tpublic void " + self.new_method_name + "(" + func_args + ") {\n" k = 0 for statement_obj in self.duplicates.duplications[0].statements: if len(statement_obj.variables) == 0: new_method += "\t\t{}\n".format( statement_obj.statement.getText()) else: statement = "\t\t{}\n".format( statement_obj.statement.getText()) for v in statement_obj.variables: statement = statement.replace(v[2], v[1]) new_method += statement k += 1 new_method += "\t}\n" new_method += "\n" self.token_stream_re_writer.insertAfter(start_index, new_method) def replace_duplicate_code(self): """ Replaces all of the duplications with new method. :return: """ self.duplicates.duplications.sort(key=lambda x: x.to_line, reverse=True) for duplicate in self.duplicates.duplications: # arguments variables = [] for state in duplicate.statements: for v in state.variables: variables.append(v) variables = list(map(lambda x: x[2], variables)) # replacing start_index = duplicate.statements[0].statement.start.tokenIndex end_index = duplicate.statements[-1].statement.stop.tokenIndex self.token_stream_re_writer.replaceRange( start_index, end_index, "{}({});".format(self.new_method_name, ", ".join(variables))) # print(self.token_stream_re_writer.getDefaultText()) def refactor(self, ctx): """ Main method for refactoring. :param ctx: :return: """ self.create_new_method(ctx.stop.tokenIndex - 1) self.replace_duplicate_code()
class ReplaceConstructorWithFactoryFunctionRefactoringListener(JavaParserLabeledListener): def __init__(self, common_token_stream: CommonTokenStream = None, target_class: str = None): if common_token_stream is None: raise ValueError('common_token_stream is None') else: self.codeRewrite = TokenStreamRewriter(common_token_stream) if target_class is None: raise ValueError("source_class is None") else: self.target_class = target_class self.is_target_class = False self.have_constructor = False self.new_factory_function = False self.new_parameters = [] self.new_parameters_names = [] def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): # self.target_class = ctx.IDENTIFIER().getText() # have_constructor = False # if ctx.IDENTIFIER().getText() == class_identifier = ctx.IDENTIFIER().getText() if class_identifier == self.target_class: self.is_target_class = True # print("class name " + ctx.IDENTIFIER().getText()) else: self.is_target_class = False def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if self.is_target_class: self.is_target_class = False def enterConstructorDeclaration(self, ctx: JavaParserLabeled.ConstructorDeclarationContext): if self.is_target_class: # print("constructor name " + ctx.IDENTIFIER().getText()) # parameters = ctx.formalParameters().getText() # print(len(ctx.formalParameters().formalParameterList().formalParameter())) grandParentCtx = ctx.parentCtx.parentCtx if ctx.IDENTIFIER().getText() == self.target_class: self.have_constructor = True # do refactor """ Declare the constructor private. """ if grandParentCtx.modifier(): if 'public' == grandParentCtx.modifier(0).getText(): self.codeRewrite.replaceRange( from_idx=grandParentCtx.modifier(0).start.tokenIndex, to_idx=grandParentCtx.modifier(0).stop.tokenIndex, text='private') else: self.codeRewrite.insertBeforeIndex( index=ctx.start.tokenIndex, text="private " ) def exitConstructorDeclaration(self, ctx: JavaParserLabeled.ConstructorDeclarationContext): """ Create a factory method. Make its body a call to the current constructor. """ if self.is_target_class: grandParentCtx = ctx.parentCtx.parentCtx self.codeRewrite.insertAfter( index=grandParentCtx.stop.tokenIndex, text="\n public static " + ctx.IDENTIFIER().getText() + " Create( " + ", ".join( self.new_parameters) + "){\n return new " + ctx.IDENTIFIER().getText() + "(" + ", ".join( self.new_parameters_names) + ");\n}" ) self.new_parameters = [] self.new_parameters_names = [] def enterFormalParameterList0(self, ctx: JavaParserLabeled.FormalParameterList0Context): # print(len(ctx.formalParameter())) pass def exitFormalParameterList0(self, ctx: JavaParserLabeled.FormalParameterList0Context): pass def enterFormalParameter(self, ctx: JavaParserLabeled.FormalParameterContext): # print(ctx.typeType().getText()) # print(ctx.variableDeclaratorId().getText()) constructorName = ctx.parentCtx.parentCtx.parentCtx.IDENTIFIER().getText() if self.target_class == constructorName: text = ctx.typeType().getText() + " " + ctx.variableDeclaratorId().getText() self.new_parameters.append(text) self.new_parameters_names.append(ctx.variableDeclaratorId().getText()) def exitFormalParameter(self, ctx: JavaParserLabeled.FormalParameterContext): pass def enterExpression4(self, ctx: JavaParserLabeled.Expression4Context): """ Replace all constructor calls with calls to the factory method. """ # currentMethodOrClassCtx=ctx.parentCtx.parentCtx.parentCtx.parentCtx.parentCtx.parentCtx.parentCtx.parentCtx # print(ctx.parentCtx.parentCtx.parentCtx.parentCtx.parentCtx.parentCtx.parentCtx.parentCtx.getText()) if ctx.creator().createdName().getText() == self.target_class: self.codeRewrite.replaceRange( from_idx=ctx.start.tokenIndex, to_idx=ctx.stop.tokenIndex, text=self.target_class + "." + "Create" + ctx.creator().classCreatorRest().getText())
class SingletonRefactoringListener(JavaParserLabeledListener): def __init__(self, common_token_stream: CommonTokenStream = None, class_identifier: str = None): """ :param common_token_stream: """ self.enter_class = False self.token_stream = common_token_stream self.class_identifier = class_identifier self.ObjectIndex = [] # Move all the tokens in the source code in a buffer, token_stream_rewriter. if common_token_stream is not None: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) else: raise TypeError('common_token_stream is None') def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if ctx.IDENTIFIER().getText() == self.class_identifier: self.enter_class = True new_code = "\n\tprivate static " + self.class_identifier + " Instance = null;\n\t" self.token_stream_rewriter.insertAfter( ctx.classBody().start.tokenIndex + 1, new_code) self.addInstance = True def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if self.enter_class: self.enter_class = False new_code = ("\n\tpublic static " + self.class_identifier + " getInstance()\n\t{\n\t\tif (Instance == null)" + "\n\t\t\tInstance = new " + self.class_identifier + "();" + "\n\t\treturn Instance;\n\t}\n") self.token_stream_rewriter.insertAfter(ctx.stop.tokenIndex - 1, new_code) def enterConstructorDeclaration( self, ctx: JavaParserLabeled.ConstructorDeclarationContext): if self.enter_class: constructor_modifier = ctx.parentCtx.parentCtx if constructor_modifier.start.text == 'public': self.token_stream_rewriter.replaceRange( from_idx=constructor_modifier.start.tokenIndex, to_idx=constructor_modifier.start.tokenIndex, text='private') def enterFieldDeclaration(self, ctx: JavaParserLabeled.FieldDeclarationContext): if not self.enter_class: if ctx.start.text == self.class_identifier: start = ctx.variableDeclarators().variableDeclarator( 0).ASSIGN().symbol.tokenIndex + 1 end = ctx.stop.tokenIndex self.ObjectIndex.append([start, end]) def enterLocalVariableDeclaration( self, ctx: JavaParserLabeled.LocalVariableDeclarationContext): if not self.enter_class: if ctx.start.text == self.class_identifier: start = ctx.variableDeclarators().variableDeclarator( 0).ASSIGN().symbol.tokenIndex + 1 end = ctx.stop.tokenIndex self.ObjectIndex.append([start, end]) def exitCompilationUnit(self, ctx: JavaParserLabeled.CompilationUnitContext): for item in self.ObjectIndex: self.token_stream_rewriter.replaceRange( from_idx=item[0], to_idx=item[1], text=" " + self.class_identifier + ".getInstance()")
class EncapsulateFiledRefactoringListener(JavaParserLabeledListener): """ To implement encapsulate field refactoring. Makes a public field private and provide accessors and mutator methods. """ def __init__(self, common_token_stream: CommonTokenStream = None, package_name: str = None, source_class_name: str = None, field_identifier: str = None): """ Args: common_token_stream (CommonTokenStream): contains the program tokens package_name (str): The enclosing package of the field source_class_name (str): The enclosing class of the field field_identifier (str): The field name to be encapsulated Returns: object (DecreaseMethodVisibilityListener): An instance of EncapsulateFiledRefactoringListener """ self.token_stream = common_token_stream if package_name is None: self.package_name = '' else: self.package_name = package_name self.source_class_name = source_class_name self.field_identifier = field_identifier self.getter_exist = False self.setter_exist = False self.in_source_class = False self.in_selected_package = True if self.package_name == '' else False # Move all the tokens in the source code in a buffer, token_stream_rewriter. if common_token_stream is not None: self.token_stream_rewriter = \ TokenStreamRewriter(common_token_stream) else: raise TypeError('common_token_stream is None') def enterPackageDeclaration( self, ctx: JavaParserLabeled.PackageDeclarationContext): if self.package_name == ctx.qualifiedName().getText(): self.in_selected_package = True else: self.in_selected_package = False def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if ctx.IDENTIFIER().getText() == self.source_class_name: self.in_source_class = True def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): self.in_source_class = False def exitFieldDeclaration(self, ctx: JavaParserLabeled.FieldDeclarationContext): if self.in_source_class and self.in_selected_package: if ctx.variableDeclarators().variableDeclarator( 0).variableDeclaratorId().getText( ) == self.field_identifier: if not ctx.parentCtx.parentCtx.modifier(0): self.token_stream_rewriter.insertBeforeIndex( index=ctx.typeType().stop.tokenIndex, text='private ') elif ctx.parentCtx.parentCtx.modifier(0).getText() == 'public': self.token_stream_rewriter.replaceRange( from_idx=ctx.parentCtx.parentCtx.modifier( 0).start.tokenIndex, to_idx=ctx.parentCtx.parentCtx.modifier( 0).stop.tokenIndex, text='private') else: return for c in ctx.parentCtx.parentCtx.parentCtx.classBodyDeclaration( ): try: print('method name: ' + c.memberDeclaration(). methodDeclaration().IDENTIFIER().getText()) if c.memberDeclaration().methodDeclaration().IDENTIFIER() \ .getText() == 'get' + str.capitalize( self.field_identifier): self.getter_exist = True if c.memberDeclaration().methodDeclaration().IDENTIFIER() \ .getText() == 'set' + str.capitalize( self.field_identifier): self.setter_exist = True except: logger.error("not method !!!") logger.debug("setter find: " + str(self.setter_exist)) logger.debug("getter find: " + str(self.getter_exist)) # generate accessor and mutator methods # Accessor body new_code = '' if not self.getter_exist: new_code = '\n\t// new getter method\n\t' new_code += 'public ' + ctx.typeType().getText() + \ ' get' + str.capitalize(self.field_identifier) new_code += '() { \n\t\treturn this.' + self.field_identifier \ + ';' + '\n\t}\n' # Mutator body if not self.setter_exist: new_code += '\n\t// new setter method\n\t' new_code += 'public void set' + str.capitalize( self.field_identifier) new_code += '(' + ctx.typeType().getText() + ' ' \ + self.field_identifier + ') { \n\t\t' new_code += 'this.' + self.field_identifier + ' = ' \ + self.field_identifier + ';' + '\n\t}\n' self.token_stream_rewriter.insertAfter(ctx.stop.tokenIndex, new_code) hidden = self.token_stream.getHiddenTokensToRight( ctx.stop.tokenIndex) # self.token_stream_rewriter.replaceRange(from_idx=hidden[0].tokenIndex, # to_idx=hidden[-1].tokenIndex, # text='\n\t/*End of accessor and mutator methods!*/\n\n') def exitExpression21(self, ctx: JavaParserLabeled.Expression21Context): if self.in_source_class and self.in_selected_package: if ctx.expression(0).getText() == self.field_identifier or \ ctx.expression(0).getText() == 'this.' + self.field_identifier: expr_code = self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, start=ctx.expression(1).start.tokenIndex, stop=ctx.expression(1).stop.tokenIndex) new_code = 'this.set' + str.capitalize( self.field_identifier) + '(' + expr_code + ')' self.token_stream_rewriter.replaceRange( ctx.start.tokenIndex, ctx.stop.tokenIndex, new_code) def exitExpression0(self, ctx: JavaParserLabeled.Expression0Context): if self.in_source_class and self.in_selected_package: try: if ctx.parentCtx.getChild(1).getText() in ('=', '+=', '-=', '*=', '/=', '&=', '|=', '^=', '>>=', '>>>=', '<<=', '%=') and \ ctx.parentCtx.getChild(0) == ctx: return except: pass if ctx.getText() == self.field_identifier: new_code = 'this.get' + str.capitalize( self.field_identifier) + '()' self.token_stream_rewriter.replaceRange( ctx.start.tokenIndex, ctx.stop.tokenIndex, new_code) def exitExpression1(self, ctx: JavaParserLabeled.Expression1Context): if self.in_source_class and self.in_selected_package: try: if ctx.parentCtx.getChild(1).getText() in ('=', '+=', '-=', '*=', '/=', '&=', '|=', '^=', '>>=', '>>>=', '<<=', '%=') and \ ctx.parentCtx.getChild(0) == ctx: return except: pass if ctx.getText() == 'this.' + self.field_identifier: new_code = 'this.get' + str.capitalize( self.field_identifier) + '()' self.token_stream_rewriter.replaceRange( ctx.start.tokenIndex, ctx.stop.tokenIndex, new_code) def exitCompilationUnit(self, ctx: JavaParserLabeled.CompilationUnitContext): try: hidden = self.token_stream.getHiddenTokensToLeft( ctx.start.tokenIndex) self.token_stream_rewriter.replaceRange( from_idx=hidden[0].tokenIndex, to_idx=hidden[-1].tokenIndex, text='/*After refactoring (Refactored version)*/\n') except: pass
class ReplaceParameterWithQueryRefactoringListener(JavaParserLabeledListener): """ To implement replace parameter with query refactoring based on its actors. Find usages of target method and remove target parameters from these and add the removed parameters to top of target method. """ def __init__(self, common_token_stream: CommonTokenStream = None, target_class: str = None, target_method: str = None, target_parameters: list = None): if common_token_stream is None: raise ValueError("common_token_stream is None") else: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) if target_class is None: raise ValueError("target class is None") else: self.target_class = target_class if target_method is None: raise ValueError("target method is None") else: self.target_method = target_method if target_parameters is None: self.target_parameters = [] else: self.target_parameters = target_parameters self.current_class = None self.current_method = None self.current_method_call = None self.target_method_ctx = None self.removed_expressions = [] self.all_local_variable_declarators = [] self.add_to_top_of_target_method = [] self.TAB = "\t" self.NEW_LINE = "\n" self.code = "" def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): self.current_class = ctx.IDENTIFIER().getText() def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): self.current_class = None def enterMethodDeclaration( self, ctx: JavaParserLabeled.MethodDeclarationContext): self.current_method = ctx.IDENTIFIER().getText() if self.current_method == self.target_method and self.current_class == self.target_class: self.target_method_ctx = ctx def exitMethodDeclaration(self, ctx: JavaParserLabeled.MethodDeclarationContext): self.exit_method_or_constructor() def enterConstructorDeclaration( self, ctx: JavaParserLabeled.ConstructorDeclarationContext): self.current_method = ctx.IDENTIFIER().getText() if self.current_method == self.target_method and self.current_class == self.target_class: self.target_method_ctx = ctx def exitConstructorDeclaration( self, ctx: JavaParserLabeled.ConstructorDeclarationContext): self.exit_method_or_constructor() def enterLocalVariableDeclaration( self, ctx: JavaParserLabeled.LocalVariableDeclarationContext): self.all_local_variable_declarators.append(ctx) def remove_expression_declaration(self, expression): for lvd in self.all_local_variable_declarators: flag = False vds = lvd.variableDeclarators() survived_vds = [] for i in range(len(vds.children)): if i % 2 == 0: vd = vds.children[i] if expression.getText() != vd.variableDeclaratorId( ).getText(): survived_vds.append(vd.getText()) else: self.add_to_top_of_target_method.append( vd.variableInitializer().getText()) flag = True if len(survived_vds) == 0: parent_ctx = lvd.parentCtx print(type(parent_ctx)) self.token_stream_rewriter.delete( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, from_idx=parent_ctx.start.tokenIndex, to_idx=parent_ctx.stop.tokenIndex) elif len(survived_vds) < (len(vds.children) + 1) // 2: self.token_stream_rewriter.replaceRange( from_idx=vds.start.tokenIndex, to_idx=vds.stop.tokenIndex, text=f"{', '.join(survived_vds)}") if flag: break def exit_method_or_constructor(self): for expression in self.removed_expressions: if type(expression) is JavaParserLabeled.Expression0Context and \ type(expression.primary()) is JavaParserLabeled.Primary4Context: self.remove_expression_declaration(expression) else: self.add_to_top_of_target_method.append(expression.getText()) self.removed_expressions = [] self.all_local_variable_declarators = [] self.current_method = None def enterMethodCall0(self, ctx: JavaParserLabeled.MethodCall0Context): self.current_method_call = ctx.IDENTIFIER().getText() def exitMethodCall0(self, ctx: JavaParserLabeled.MethodCall0Context): self.current_method_call = None def enterExpressionList(self, ctx: JavaParserLabeled.ExpressionListContext): if self.current_method_call == self.target_method: parameters = [] for i in range(len(ctx.children)): if i % 2 == 0: if ((i // 2) + 1) in self.target_parameters: self.removed_expressions.append(ctx.children[i]) else: parameters.append(ctx.children[i].getText()) self.token_stream_rewriter.replaceRange( from_idx=ctx.start.tokenIndex, to_idx=ctx.stop.tokenIndex, text=f"{', '.join(parameters)}") def exitCompilationUnit(self, ctx: JavaParserLabeled.CompilationUnitContext): if self.target_method_ctx is not None: ctx = self.target_method_ctx text = '' formal_parameter_list = ctx.formalParameters().formalParameterList( ) survived_parameters = [] for i in range(len(formal_parameter_list.children)): if i % 2 == 0: if ((i // 2) + 1) in self.target_parameters: parameter = formal_parameter_list.children[i] parameter_type = parameter.typeType().getText() parameter_vdi = parameter.variableDeclaratorId( ).getText() parameter_initializer = self.add_to_top_of_target_method[ 0] text += \ parameter_type + ' ' + parameter_vdi + ' = ' + parameter_initializer + \ ';' + self.NEW_LINE + self.TAB + self.TAB self.add_to_top_of_target_method.remove( parameter_initializer) else: parameter = formal_parameter_list.children[i] parameter_type = parameter.typeType().getText() parameter_vdi = parameter.variableDeclaratorId( ).getText() survived_parameters.append(parameter_type + ' ' + parameter_vdi) self.token_stream_rewriter.replaceRange( from_idx=formal_parameter_list.start.tokenIndex, to_idx=formal_parameter_list.stop.tokenIndex, text=f"{', '.join(survived_parameters)}") block_statement = ctx.methodBody().block().blockStatement()[0] self.token_stream_rewriter.insertAfter( index=block_statement.start.tokenIndex - 1, text=text)
class RemoveFlagArgumentListener(JavaParserLabeledListener): """ To remove boolean flag argument which specifies method logic in if and else block . For more information visit Martin Frauler book . if(flag) { } else { } This listener is used to capture needed pattern and edit source method and extract two distinct logic in if and else blog there are several key assumption made at this momenent that the argument should be boolean and there must only been used in if else block and the structure of if and else should be in block format and single line if and else are not supported """ def __init__(self, common_token_stream: CommonTokenStream = None, source_class="", source_method="", argument_name: str = ""): """create removeflaglistener to extract and edit needed pattern Args: common_token_stream (CommonTokenStream, optional): default token stream passed by higher level api. Defaults to None. source_class (str, optional): name of the class which method rests in. Defaults to "". source_method (str, optional): name of the method to be edited. Defaults to "". argument_name (str, optional): name of the boolean argument which branchs the logic. Defaults to "". Raises: ValueError: if no common token stream is find will be raised since its is essential to the process """ self.argument_name = argument_name self.source_method = source_method self.source_class = source_class self.token_stream_rewriter_changed = False if common_token_stream is None: raise ValueError('common_token_stream is None') else: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) self.common_token_stream = common_token_stream self.is_source_class = False self.is_source_method = False self.is_if_block = False self.is_else_block = False def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): """check if the class is the source class Args: ctx (JavaParserLabeled.ClassDeclarationContext) """ print("Refactoring started, please wait...") self.is_source_class = ( ctx.IDENTIFIER().getText() == self.source_class) def enterMethodDeclaration( self, ctx: JavaParserLabeled.MethodDeclarationContext): """check if this is the intended method if so capture signature and remove boolean argument Args: ctx (JavaParserLabeled.MethodDeclarationContext): """ self.is_source_method = ( ctx.IDENTIFIER().getText() == self.source_method) if self.is_source_method: nextParam = None for idx, formalParameter in enumerate(ctx.formalParameters( ).formalParameterList().formalParameter()): if formalParameter.variableDeclaratorId().IDENTIFIER().getText( ) == self.argument_name: self.argument_token = formalParameter nextParam = ctx.formalParameters().formalParameterList().formalParameter()[idx + 1] \ if idx != len(ctx.formalParameters().formalParameterList().formalParameter()) - 1 else None break if nextParam: self.token_stream_rewriter.replaceRange( self.argument_token.start.tokenIndex, nextParam.start.tokenIndex - 1, '') else: self.token_stream_rewriter.replaceRange( self.argument_token.start.tokenIndex, self.argument_token.stop.tokenIndex, '') self.signature = self.token_stream_rewriter.getText( self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, ctx.start.tokenIndex, ctx.methodBody().start.tokenIndex) if self.token_stream_rewriter_changed == False: self.token_stream_rewriter = TokenStreamRewriter( self.common_token_stream) self.token_stream_rewriter_changed = True def exitMethodBody(self, ctx: JavaParserLabeled.MethodBodyContext): """after exiting the soure method create two new method for new method logics and call these in if and else block in the source method Args: ctx (JavaParserLabeled.MethodBodyContext) """ if self.is_source_method: signature1 = self.signature.split('(')[0].rstrip( ) + 'IsTrue' + ' (' + ''.join(self.signature.split('(')[1:]) signature2 = self.signature.split('(')[0].rstrip( ) + 'IsFalse' + ' (' + ''.join(self.signature.split('(')[1:]) res = '\n\t' + signature1 + self.body_1 + '\n\t' + signature2 + self.body_2 self.token_stream_rewriter.insertAfter(index=ctx.stop.tokenIndex, text=res) # self.token_stream_rewriter.insertAfter(index=ctx.stop.tokenIndex, text=self.body_2) # self.token_stream_rewriter.insertAfter(index=ctx.stop.tokenIndex, text=self.signature) # print(self.signature) arguments = [ s.rstrip().split(' ')[-1] for s in signature1.split('(')[1].split(')')[0].split(',') ] print("exit method") signature1_name = signature1.split('(')[0].rstrip().split()[-1] signature2_name = signature2.split('(')[0].rstrip().split()[-1] self.token_stream_rewriter.replaceRange( self.body_1_token.start.tokenIndex, self.body_1_token.stop.tokenIndex, '\t' + signature1_name + '( ' + ','.join(arguments) + ')') self.token_stream_rewriter.replaceRange( self.body_2_token.start.tokenIndex, self.body_2_token.stop.tokenIndex, '\t' + signature2_name + '( ' + ','.join(arguments) + ')') def enterStatement0(self, ctx: JavaParserLabeled.Statement0Context): if self.is_source_method: pass def enterStatement2(self, ctx: JavaParserLabeled.Statement2Context): """when entering if else block we get both of the logic in the block if this was source method and capture the token which is needed later to do the refactoring Args: ctx (JavaParserLabeled.Statement2Context) """ if self.is_source_method: try: primary = ctx.parExpression().expression().primary() if hasattr(primary, "IDENTIFIER"): if ctx.parExpression().expression().primary().IDENTIFIER( ).getText() == self.argument_name: iterator = iter(ctx.statement()) # TODO : handle on statements blocks .e.g. {} self.body_1, self.body_2 = [ self.common_token_stream.getText( s.block().start, s.block().stop)[1:] for s in ctx.statement() ] self.body_1_token, self.body_2_token = [ s.block() for s in ctx.statement() ] # print(ctx.getPayload()) # print(self.common_token_stream.getText(ctx.start, ctx.stop)) # print(dir(ctx.statement()[0].block())) # for s in ctx.statement(): # print(s.block().getText()) except: pass
class MakeMethodStaticRefactoringListener(JavaParserLabeledListener): """ To implement extract class refactoring based on its actors. Creates a new class and move fields and methods from the old class to the new one """ def __init__(self, common_token_stream: CommonTokenStream = None, target_class: str = None, target_methods: list = None): if common_token_stream is None: raise ValueError('common_token_stream is None') else: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) if target_class is None: raise ValueError("source_class is None") else: self.target_class = target_class if target_methods is None or len(target_methods) == 0: raise ValueError("target method must have one method name") else: self.target_methods = target_methods self.is_target_class = False self.detected_instance_of_target_class = [] self.TAB = "\t" self.NEW_LINE = "\n" self.code = "" def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): class_identifier = ctx.IDENTIFIER().getText() if class_identifier == self.target_class: self.is_target_class = True else: self.is_target_class = False def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if self.is_target_class: self.is_target_class = False def enterMethodDeclaration( self, ctx: JavaParserLabeled.MethodDeclarationContext): if self.is_target_class: if ctx.IDENTIFIER().getText() in self.target_methods: if 'this.' in ctx.getText(): raise ValueError("this method can not refactor") grand_parent_ctx = ctx.parentCtx.parentCtx if grand_parent_ctx.modifier(): if len(grand_parent_ctx.modifier()) == 2: return None else: self.token_stream_rewriter.insertAfter( index=grand_parent_ctx.modifier(0).stop.tokenIndex, program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, text=" static") else: self.token_stream_rewriter.insertBeforeIndex( index=ctx.start.tokenIndex, text="static ") def enterLocalVariableDeclaration( self, ctx: JavaParserLabeled.LocalVariableDeclarationContext): if ctx.typeType().getText() == self.target_class: self.detected_instance_of_target_class.append( ctx.variableDeclarators().variableDeclarator( 0).variableDeclaratorId().IDENTIFIER().getText()) self.token_stream_rewriter.delete( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, from_idx=ctx.start.tokenIndex, to_idx=ctx.stop.tokenIndex + 1) def enterMethodCall0(self, ctx: JavaParserLabeled.MethodCall0Context): if ctx.IDENTIFIER().getText() in self.target_methods: if ctx.parentCtx.expression().getText( ) in self.detected_instance_of_target_class: self.token_stream_rewriter.replace( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, from_idx=ctx.parentCtx.expression().start.tokenIndex, to_idx=ctx.parentCtx.expression().stop.tokenIndex, text=self.target_class)
class CollapseHierarchyRefactoringGetMethodTextListener( JavaParserLabeledListener): def __init__(self, common_token_stream: CommonTokenStream = None, child_class=None): if child_class is None: self.moved_methods = [] else: self.child_class = child_class if common_token_stream is None: raise ValueError('common_token_stream is None') else: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) self.is_children_class = False self.detected_field = None self.detected_method = None self.TAB = "\t" self.NEW_LINE = "\n" self.methodcode = "" def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): class_identifier = ctx.IDENTIFIER().getText() if class_identifier == self.child_class: self.is_source_class = True self.methodcode += self.NEW_LINE * 2 self.methodcode += f"// child class({self.child_class}) methods: " + self.NEW_LINE else: self.is_source_class = False def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if self.is_source_class: self.is_source_class = False def exitCompilationUnit(self, ctx: JavaParserLabeled.CompilationUnitContext): self.token_stream_rewriter.insertAfter(index=ctx.stop.tokenIndex, text=self.methodcode) def enterMethodDeclaration( self, ctx: JavaParserLabeled.MethodDeclarationContext): if not self.is_source_class: return None self.detected_method = ctx.IDENTIFIER().getText() def exitMethodDeclaration(self, ctx: JavaParserLabeled.MethodDeclarationContext): if not self.is_source_class: return None method_identifier = ctx.IDENTIFIER().getText() print("Here it is a method") grand_parent_ctx = ctx.parentCtx.parentCtx modifier = "" for i in range(0, len(grand_parent_ctx.modifier())): modifier += grand_parent_ctx.modifier(i).getText() modifier += " " if self.detected_method == method_identifier: start_index = ctx.start.tokenIndex stop_index = ctx.stop.tokenIndex method_text = self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, start=start_index, stop=stop_index) self.methodcode += (self.NEW_LINE + self.TAB + modifier + method_text + self.NEW_LINE)
class VisitorPatternRefactoringListener(JavaParserLabeledListener): """ implement the visitor pattern refactoring """ def __init__(self, common_token_stream: CommonTokenStream = None, SuperClass_identifier: str = None, SubClass_identifier: list = None): """ :param common_token_stream: """ self.enter_class = False self.token_stream = common_token_stream self.SuperClass_identifier = SuperClass_identifier self.SubClass_identifier = SubClass_identifier self.InSuperClass = False self.InSubClass = False self.InMainClass = False self.CurrentCC = None self.Visitors = {} # Move all the tokens in the source code in a buffer, token_stream_rewriter. if common_token_stream is not None: self.token_stream_rewriter = TokenStreamRewriter(common_token_stream) else: raise TypeError('common_token_stream is None') def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if ctx.IDENTIFIER().getText() == self.SuperClass_identifier: self.InSuperClass = True elif ctx.IDENTIFIER().getText() in self.SubClass_identifier: self.InSubClass = True elif ctx.IDENTIFIER().getText() == "Main": self.InMainClass = True if ctx.EXTENDS().__str__() == "extends": # SubClass Headers Rename self.token_stream_rewriter.insertAfter(ctx.start.tokenIndex + 4, "implements") self.token_stream_rewriter.deleteIndex(ctx.start.tokenIndex + 4) def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if self.InSuperClass: # SuperClass Interface Make interface_text = ( "interface " + self.SuperClass_identifier + "\n{\n\tpublic void accept (Visitor" + self.SuperClass_identifier + " visitor);\n}" ) self.token_stream_rewriter.insertAfter(ctx.start.tokenIndex - 1, "\n" + interface_text + "\n") # SuperClass Visitor interface Make interface_text_vistor = "interface Visitor" + self.SuperClass_identifier + "\n{" index = 0 for item in self.Visitors: interface_text_vistor += "\n\t" + "public void " + "visit(" + self.SubClass_identifier[ index] + " " + item + ");" index += 1 interface_text_vistor += "\n}" self.token_stream_rewriter.insertAfter(ctx.start.tokenIndex - 1, "\n" + interface_text_vistor + "\n") # SuperClass DoVisitor Make newSC = ( "\nclass DoVisitor" + self.SuperClass_identifier + " implements Visitor" + self.SuperClass_identifier + "\n{" ) method_body = "" index = 0 # SuperClassDoVisitor Mathods Make for item in self.Visitors: method_body = str_list(self.Visitors[item]) method_body = "{\n\t" + method_body[2:-2] + "\n\t}" newSC += "\n\t" + "@Override\n\tpublic void visit(" + self.SubClass_identifier[ index] + " " + item + ")\n\t" + method_body index += 1 newSC += "\n}" self.token_stream_rewriter.replaceRange(ctx.start.tokenIndex, ctx.stop.tokenIndex, newSC) self.InSuperClass = False self.InSubClass = False self.InMainClass = False def enterMethodDeclaration(self, ctx: JavaParserLabeled.MethodDeclarationContext): # Extract Methods Name & Methods body of SuperClass if self.InSuperClass: new_class_name = ctx.IDENTIFIER().getText() new_method_body = ctx.methodBody().getText() self.Visitors[new_class_name] = [new_method_body] def exitClassBody(self, ctx: JavaParserLabeled.ClassBodyContext): if self.InSubClass: # Implement Mathod of SuperClass InterFace override_text = ( "@Override\n\tpublic void accept(Visitor" + self.SuperClass_identifier + " visitor)\n\t{\n\t\tvisitor.visit(this);\n\t}" ) self.token_stream_rewriter.insertAfter(ctx.start.tokenIndex, "\n\t" + override_text) def enterMethodCall0(self, ctx: JavaParserLabeled.MethodCall0Context): if self.InMainClass: # Modify Main Method if ctx.IDENTIFIER().getText() in self.Visitors: self.token_stream_rewriter.replaceRange( from_idx=ctx.start.tokenIndex, to_idx=ctx.stop.tokenIndex, text="accept(new DoVisitor" + self.SuperClass_identifier + "())")
class FactoryMethodRefactoringListener(JavaParserLabeledListener): def __init__(self, common_token_stream: CommonTokenStream = None, creator_identifier: str = None, products_identifier: list = None): self.enter_class = False self.token_stream = common_token_stream self.creator_identifier = creator_identifier self.products_identifier = products_identifier self.interfaceName = "ProductsAbstract" self.inCreator = False self.inProducts = False self.productsMethod = {} self.productsClassIndex = [] self.productVarTypeIndex = [] self.productVarValueIndex = [] self.productConstructorMethod = [] self.productConstructorParam = {} self.currentClass = None # Move all the tokens in the source code in a buffer, token_stream_rewriter. if common_token_stream is not None: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) else: raise TypeError('common_token_stream is None') def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if ctx.IDENTIFIER().getText() == self.creator_identifier: self.inCreator = True self.CretorStartIndex = ctx.classBody().start.tokenIndex self.currentClass = ctx.IDENTIFIER().symbol.text elif ctx.IDENTIFIER().getText() in self.products_identifier: self.inProducts = True self.productsClassIndex.append(ctx.IDENTIFIER().symbol.tokenIndex) self.currentClass = ctx.IDENTIFIER().symbol.text def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): self.inCreator = False self.inProducts = False def enterMethodDeclaration( self, ctx: JavaParserLabeled.MethodDeclarationContext): if self.inProducts == True: methodModifire = ctx.parentCtx.parentCtx.start.text if methodModifire == 'public': MethodText = self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, start=ctx.parentCtx.parentCtx.start.tokenIndex, stop=ctx.formalParameters().RPAREN( ).symbol.tokenIndex) + ";" if MethodText not in self.productsMethod: self.productsMethod[MethodText] = [self.currentClass] else: self.productsMethod[MethodText].append(self.currentClass) def enterLocalVariableDeclaration( self, ctx: JavaParserLabeled.LocalVariableDeclarationContext): if self.inCreator == True: variableType = ctx.typeType().classOrInterfaceType().IDENTIFIER(0) if variableType.symbol.text in self.products_identifier: self.productVarTypeIndex.append(variableType.symbol.tokenIndex) self.productVarValueIndex.append([ variableType.symbol.text, ctx.variableDeclarators().variableDeclarator( 0).ASSIGN().symbol.tokenIndex, ctx.stop.tokenIndex ]) def enterFieldDeclaration(self, ctx: JavaParserLabeled.FieldDeclarationContext): if self.inCreator == True: variableType = ctx.typeType().classOrInterfaceType().IDENTIFIER(0) if variableType.symbol.text in self.products_identifier: self.productVarTypeIndex.append(variableType.symbol.tokenIndex) self.productVarValueIndex.append([ variableType.symbol.text, ctx.variableDeclarators().variableDeclarator( 0).ASSIGN().symbol.tokenIndex, ctx.stop.tokenIndex ]) def enterConstructorDeclaration( self, ctx: JavaParserLabeled.ConstructorDeclarationContext): if self.inProducts == True: Parameter = "" if ctx.formalParameters().children.__len__() > 0: ParamChild = ctx.formalParameters().children[1] for i in range(0, ParamChild.children.__len__(), 2): Parameter += ParamChild.children[i].stop.text + "," Parameter = Parameter[:-1] self.productConstructorParam[self.currentClass] = Parameter ParamList = self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, start=ctx.formalParameters().LPAREN().symbol.tokenIndex, stop=ctx.formalParameters().RPAREN().symbol.tokenIndex) Method = "\t" + self.interfaceName + " create" + \ self.currentClass + ParamList + \ "{\n\t\t" + "return new " + self.currentClass + "(" + Parameter + ");\n\t}\n" self.productConstructorMethod.append(Method) def exitCompilationUnit(self, ctx: JavaParserLabeled.CompilationUnitContext): # InterfaceChecked interfaceMethodList = [] for key, value in self.productsMethod.items(): if sorted(value) == sorted(self.products_identifier): interfaceMethodList.append(key) if interfaceMethodList.__len__() > 0: intefaceText = "public interface " + self.interfaceName + "{" for item in interfaceMethodList: intefaceText += "\n\t" + item intefaceText += "\n}\n\n" self.token_stream_rewriter.insertBefore( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, index=1, text=intefaceText) for item in self.productsClassIndex: self.token_stream_rewriter.insertAfter( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, index=item, text=" implements " + self.interfaceName) for item in self.productVarTypeIndex: self.token_stream_rewriter.replace( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, from_idx=item, to_idx=item, text=self.interfaceName) for item in self.productVarValueIndex: self.token_stream_rewriter.replace( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, from_idx=item[1] + 1, to_idx=item[2], text="create" + item[0] + " (" + self.productConstructorParam[item[0]] + ")") newProductMethod = "\n" for item in self.productConstructorMethod: newProductMethod += item self.token_stream_rewriter.insertAfter( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, index=self.CretorStartIndex, text=newProductMethod)
class StrategyPatternRefactoringListener(JavaParserLabeledListener): """ To implement the strategy pattern refactoring """ def __init__(self, common_token_stream: CommonTokenStream = None, method_identifier: str = None): """ :param common_token_stream: """ self.i = 0 self.enter_method = False self.token_stream = common_token_stream self.method_identifier = method_identifier self.class_identifier = "" self.currentClass = 1 self.enter_class = False self.method_selected = False self.ifelse = False self.inputPara = False self.newClasses = "" self.interface = "" self.para = "" self.newPara = [] self.oldPara = [] self.typePara = [] self.old_method_Declaration = "" self.new_method_Declaration = "" # Move all the tokens in the source code in a buffer, token_stream_rewriter. if common_token_stream is not None: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) else: raise TypeError('common_token_stream is None') def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): self.enter_class = True self.class_identifier = ctx.IDENTIFIER().getText() def enterMethodDeclaration( self, ctx: JavaParserLabeled.MethodDeclarationContext): grand_parent_ctx = ctx.parentCtx.parentCtx self.method_selected = False if ctx.IDENTIFIER().getText() == self.method_identifier: self.enter_method = True self.method_selected = True self.old_method_Declaration = self.token_stream_rewriter.getText( "", grand_parent_ctx.modifier(0).start.tokenIndex, ctx.formalParameters().stop.tokenIndex) self.old_method_Declaration = self.old_method_Declaration.replace( self.method_identifier, "doOperation") def enterStatement2(self, ctx: JavaParserLabeled.Statement2Context): if self.method_selected: self.ifelse = True self.para = ctx.parExpression().expression().getText().split('==') # Define new concrete strategy as subclass of strategy new_sub_class = ("\nclass SubNewClass" + str(self.currentClass) + " implements MyStrategy{\n\t" + "@Override\n\t" + self.old_method_Declaration + "\n\t") body = self.token_stream_rewriter.getText( "", ctx.statement(0).block().start.tokenIndex, ctx.statement(0).block().stop.tokenIndex) # Make body for new subclass if body[0] != "{": body = "{" + body + "}" self.newClasses += new_sub_class + body + "\n}" self.currentClass += 1 def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if self.enter_method: if self.ifelse and self.inputPara: # Create new class(Create an interface of strategy class named MyStrategy) self.interface = "\ninterface MyStrategy {\n\t" + self.new_method_Declaration + ";\n}" self.newClasses = self.newClasses.replace( self.old_method_Declaration, self.new_method_Declaration) self.token_stream_rewriter.insertAfter( ctx.start.tokenIndex - 1, text="\n" + self.interface + self.newClasses + "\n") self.enter_method = False self.enter_class = False def enterFormalParameter(self, ctx: JavaParserLabeled.FormalParameterContext): if self.method_selected: self.inputPara = True self.oldPara.append(ctx.typeType().getText() + " " + ctx.variableDeclaratorId().getText()) self.typePara.append(ctx.typeType().getText()) def exitMethodDeclaration(self, ctx: JavaParserLabeled.MethodDeclarationContext): if self.method_selected: # Make new method declaration if self.ifelse and self.inputPara: self.newPara = [] for item in self.oldPara: if not item.endswith(str(self.para[0])): self.newPara.append(item) self.newPara = ', '.join(self.newPara) LPRANindex = self.old_method_Declaration.index('(') self.new_method_Declaration = self.old_method_Declaration[: LPRANindex] + "(" + self.newPara + ")" new_name = self.old_method_Declaration.replace( "doOperation", self.method_identifier + "Strategy") temp1 = ', '.join(self.oldPara) temp1 = "(" + temp1 + ")" temp2 = "(" + self.newPara + ")" new_name = new_name.replace(temp1, temp2) for item in self.typePara: self.newPara = self.newPara.replace(item, "") # Modify original class newbody = (" private MyStrategy strategy;\n" + "\tpublic " + self.class_identifier + "(MyStrategy strategy){\n" + "\t\tthis.strategy = strategy;\n" + "\t}\n" + "\t" + new_name + "{\n" + "\t\treturn strategy.doOperation(" + self.newPara + ");\n" + "\t}") self.token_stream_rewriter.replaceRange( ctx.parentCtx.parentCtx.start.tokenIndex, ctx.stop.tokenIndex, newbody, )
class PullUpFieldRefactoringListener(JavaParserLabeledListener): """ To implement extract class refactoring based on its actors. Creates a new class and move fields and methods from the old class to the new one """ def __init__(self, common_token_stream: CommonTokenStream = None, destination_class: str = None, children_class=None, moved_fields=None, fieldtext=None): if moved_fields is None: self.moved_fields = [] else: self.moved_fields = moved_fields if children_class is None: self.moved_fields = [] else: self.children_class = children_class # if fieldtext is None: raise ValueError("fieldtext is None") else: self.fieldtext = fieldtext # if common_token_stream is None: raise ValueError('common_token_stream is None') else: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) if destination_class is None: raise ValueError("source_class is None") else: self.destination_class = destination_class # if destination_class is None: # raise ValueError("new_class is None") # else: # self.destibation_class = destination_class self.is_source_class = False self.detected_field = None self.detected_method = None self.TAB = "\t" self.NEW_LINE = "\n" self.code = "" self.tempdeclarationcode = "" self.field_text = "" # self.iscopyfieldtext=False def enterFieldDeclaration(self, ctx: JavaParserLabeled.FieldDeclarationContext): # if self.is_source_class: ctx1 = ctx.parentCtx.parentCtx.parentCtx.parentCtx class_identifier = ctx1.IDENTIFIER().getText() if class_identifier in self.children_class: # class_identifier = ctx.variableDeclarators().variableDeclarator().variableDeclaratorId().IDENTIFIER.getText() # field_identifier = ctx.variableDeclarators().getText().split(",") field_identifier = ctx.variableDeclarators().variableDeclarator( 0).variableDeclaratorId().IDENTIFIER().getText() # print(class_identifier) # for item in self.moved_fields: if self.moved_fields[0] in field_identifier: ctx1 = ctx.parentCtx.parentCtx start_index = ctx1.start.tokenIndex stop_index = ctx1.stop.tokenIndex self.field_text = self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, start=start_index, stop=stop_index) # delete field from source class # self.token_stream_rewriter.replaceRange( # from_idx=ctx1.start.tokenIndex, # to_idx=ctx1.stop.tokenIndex, # text=f"{modifier} {field_type} {','.join(field_names)};" # ) # else: self.token_stream_rewriter.delete( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, from_idx=ctx1.start.tokenIndex, to_idx=ctx1.stop.tokenIndex) # print(self.field_text) def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): class_identifier = ctx.IDENTIFIER().getText() if class_identifier == self.destination_class: self.is_source_class = True # self.code += self.NEW_LINE * 2 # self.code += f"// New class({self.destibation_class}) generated by CodART" + self.NEW_LINE # self.code += f"class {self.destibation_class}{self.NEW_LINE}" + "{" + self.NEW_LINE elif class_identifier == "B": print("enter B class") # self.token_stream_rewriter.replaceRange( # from_idx=ctx.start.tokenIndex, # to_idx=ctx.start.tokenIndex, # text=self.field_text # ) self.is_source_class = False # self.code += (self.field_text def enterClassBody(self, ctx: JavaParserLabeled.ClassBodyContext): print() ctx1 = ctx.parentCtx class_identifier = ctx1.IDENTIFIER().getText() print(class_identifier) if class_identifier == self.destination_class: # if not self.is_source_class: self.token_stream_rewriter.replaceRange( from_idx=ctx.start.tokenIndex + 1, to_idx=ctx.start.tokenIndex + 1, text="\n" + self.fieldtext + "\n") def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if self.is_source_class: # self.code += "}" self.is_source_class = False def exitCompilationUnit(self, ctx: JavaParserLabeled.CompilationUnitContext): # self.count+=1 # if(self.count==1): # my_listener = movefieldupRefactoringListener(common_token_stream=self.token_stream_rewriter, destination_class='A', # children_class=["B", "S"], moved_fields=['a'],) self.token_stream_rewriter.insertAfter(index=ctx.stop.tokenIndex, text=self.code) def enterVariableDeclaratorId( self, ctx: JavaParserLabeled.VariableDeclaratorIdContext): if not self.is_source_class: return None field_identifier = ctx.IDENTIFIER().getText() if field_identifier in self.moved_fields: self.detected_field = field_identifier
class MakeFieldStaticRefactoringListener(JavaParserLabeledListener): """ To implement the encapsulate filed refactored Encapsulate field: Make a public field private and provide accessors """ def __init__(self, common_token_stream: CommonTokenStream = None, field_identifier: str = None, class_identifier: str = None, package_identifier: str = None): """ :param common_token_stream: """ self.token_stream = common_token_stream self.field_identifier = field_identifier self.class_identifier = class_identifier self.package_identifier = package_identifier self.declared_objects_names = [] self.is_package_imported = False self.in_selected_package = False self.in_selected_class = False self.in_some_package = False # Move all the tokens in the source code in a buffer, token_stream_rewriter. if common_token_stream is not None: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) else: raise TypeError('common_token_stream is None') def enterPackageDeclaration( self, ctx: JavaParserLabeled.PackageDeclarationContext): self.in_some_package = True if self.package_identifier is not None: if self.package_identifier == ctx.qualifiedName().getText(): self.in_selected_package = True print("Package Found") def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if self.package_identifier is None and not self.in_some_package or\ self.package_identifier is not None and self.in_selected_package: if ctx.IDENTIFIER().getText() == self.class_identifier: print("Class Found") self.in_selected_class = True def enterImportDeclaration( self, ctx: JavaParserLabeled.ImportDeclarationContext): if self.package_identifier is not None: if ctx.getText() == "import" + self.package_identifier + "." + self.class_identifier + ";" \ or ctx.getText() == "import" + self.package_identifier + ".*" + ";" \ or ctx.getText() == "import" + self.package_identifier + ";": self.is_package_imported = True def exitFieldDeclaration(self, ctx: JavaParserLabeled.FieldDeclarationContext): if self.package_identifier is None and not self.in_some_package\ or self.package_identifier is not None and self.in_selected_package: if self.in_selected_class: if ctx.variableDeclarators().variableDeclarator(0)\ .variableDeclaratorId().getText() == self.field_identifier: grand_parent_ctx = ctx.parentCtx.parentCtx if len(grand_parent_ctx.modifier()) == 0: self.token_stream_rewriter.insertBeforeIndex( index=ctx.parentCtx.start.tokenIndex, text=' static ') else: is_static = False for modifier in grand_parent_ctx.modifier(): if modifier.getText() == "static": is_static = True break if not is_static: self.token_stream_rewriter.insertAfter( index=grand_parent_ctx.start.tokenIndex + len(grand_parent_ctx.modifier()), text=' static ') if self.package_identifier is None or self.package_identifier is not None and self.is_package_imported: if ctx.typeType().classOrInterfaceType() is not None: if ctx.typeType().classOrInterfaceType().getText( ) == self.class_identifier: self.declared_objects_names.append( ctx.variableDeclarators().variableDeclarator( 0).variableDeclaratorId().getText()) print("Object " + ctx.variableDeclarators().variableDeclarator(0).variableDeclaratorId().getText()\ + " of type " + self.class_identifier + " found.") def enterExpression1(self, ctx: JavaParserLabeled.Expression1Context): if self.is_package_imported or self.package_identifier is None or self.in_selected_package: for object_name in self.declared_objects_names: if ctx.getText() == object_name + "." + self.field_identifier: self.token_stream_rewriter.replaceIndex( index=ctx.start.tokenIndex, text=self.class_identifier)
class PullUpMethodRefactoringListener(JavaParserLabeledListener): """ To implement pull-up method refactoring based on its actors. """ def __init__(self, common_token_stream: CommonTokenStream = None, destination_class: str = None, children_class: list = None, moved_methods=None, method_text: str = None): """ """ if method_text is None: self.mothod_text = [] else: self.method_text = method_text if moved_methods is None: self.moved_methods = [] else: self.moved_methods = moved_methods if children_class is None: self.children_class = [] else: self.children_class = children_class if common_token_stream is None: raise ValueError('common_token_stream is None') else: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) if destination_class is None: raise ValueError("source_class is None") else: self.destination_class = destination_class self.is_children_class = False self.detected_field = None self.detected_method = None self.TAB = "\t" self.NEW_LINE = "\n" self.code = "" self.tempdeclarationcode = "" def enterMethodDeclaration( self, ctx: JavaParserLabeled.MethodDeclarationContext): if self.is_children_class: method_identifier = ctx.IDENTIFIER().getText() if self.moved_methods == method_identifier: methodDefctx = ctx.parentCtx.parentCtx start_index = methodDefctx.start.tokenIndex stop_index = methodDefctx.stop.tokenIndex self.method_text = self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, start=start_index, stop=stop_index) self.token_stream_rewriter.delete( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, from_idx=methodDefctx.start.tokenIndex, to_idx=methodDefctx.stop.tokenIndex) else: return None def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): class_identifier = ctx.IDENTIFIER().getText() if class_identifier in self.children_class: self.is_children_class = True else: # Enter another class self.is_children_class = False def enterClassBody(self, ctx: JavaParserLabeled.ClassBodyContext): classDecctx = ctx.parentCtx if hasattr(classDecctx, "IDENTIFIER"): class_identifier = classDecctx.IDENTIFIER().getText() if class_identifier in self.destination_class: self.token_stream_rewriter.replaceRange( from_idx=ctx.start.tokenIndex + 1, to_idx=ctx.start.tokenIndex + 1, text="\n" + self.method_text + "\n") def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if self.is_children_class: self.is_children_class = False def exitCompilationUnit(self, ctx: JavaParserLabeled.CompilationUnitContext): self.token_stream_rewriter.insertAfter(index=ctx.stop.tokenIndex, text=self.code)
class EncapsulateFiledRefactoringListener(Java9_v2Listener): """ To implement the encapsulate filed refactored Encapsulate field: Make a public field private and provide accessors """ def __init__(self, common_token_stream: CommonTokenStream = None, field_identifier: str = None): """ :param common_token_stream: """ self.token_stream = common_token_stream self.field_identifier = field_identifier # Move all the tokens in the source code in a buffer, token_stream_rewriter. if common_token_stream is not None: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) else: raise TypeError('common_token_stream is None') def exitFieldDeclaration(self, ctx: Java9_v2Parser.FieldDeclarationContext): if ctx.variableDeclaratorList().getText() == self.field_identifier: if ctx.fieldModifier(0).getText() == 'public': self.token_stream_rewriter.replaceRange( from_idx=ctx.fieldModifier(0).start.tokenIndex, to_idx=ctx.fieldModifier(0).stop.tokenIndex, text='private') # generate accessor and mutator methods # Accessor body new_code = '\n\t' new_code += 'public ' + ctx.unannType().getText( ) + ' get' + str.capitalize(self.field_identifier) new_code += '() { \n\t\t return this.' + self.field_identifier + ';' + '\n\t}' # Mutator body new_code += '\n\t' new_code += 'public void set' + str.capitalize( self.field_identifier) new_code += '(' + ctx.unannType().getText( ) + ' ' + self.field_identifier + ') { \n\t\t' new_code += 'this.' + self.field_identifier + ' = ' + self.field_identifier + ';' + '\n\t}\n' self.token_stream_rewriter.insertAfter(ctx.stop.tokenIndex, new_code) hidden = self.token_stream.getHiddenTokensToRight( ctx.stop.tokenIndex) self.token_stream_rewriter.replaceRange( from_idx=hidden[0].tokenIndex, to_idx=hidden[-1].tokenIndex, text='\t/*End of accessor and mutator methods!*/\n\n') def exitAssignment(self, ctx: Java9_v2Parser.AssignmentContext): if ctx.leftHandSide().getText() == self.field_identifier or \ ctx.leftHandSide().getText() == 'this.' + self.field_identifier: expr_code = self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, start=ctx.expression().start.tokenIndex, stop=ctx.expression().stop.tokenIndex) # new_code = 'this.set' + str.capitalize(self.field_identifier) + '(' + ctx.expression().getText() + ')' new_code = 'this.set' + str.capitalize( self.field_identifier) + '(' + expr_code + ')' self.token_stream_rewriter.replaceRange(ctx.start.tokenIndex, ctx.stop.tokenIndex, new_code) def exitPrimary(self, ctx: Java9_v2Parser.PrimaryContext): if ctx.getChildCount() == 2: if ctx.getText() == 'this.' + self.field_identifier or ctx.getText( ) == self.field_identifier: new_code = 'this.get' + str.capitalize( self.field_identifier) + '()' self.token_stream_rewriter.replaceRange( ctx.start.tokenIndex, ctx.stop.tokenIndex, new_code) def enterCompilationUnit1(self, ctx: Java9_v2Parser.CompilationUnit1Context): hidden = self.token_stream.getHiddenTokensToLeft(ctx.start.tokenIndex) self.token_stream_rewriter.replaceRange( from_idx=hidden[0].tokenIndex, to_idx=hidden[-1].tokenIndex, text='/*After refactoring (Refactored version)*/\n')
class IncreaseFieldVisibilityRefactoringListener(JavaParserLabeledListener): """ ## Introduction Increase the visibility of a field from private to package, package to protected or protected to public. ## Pre and Post Conditions ### Pre Conditions: 1. User must enter the field's name, and the source class's name for the refactoring in order to increase the target field's visibility. ### Post Conditions: No specific Post Condition """ def __init__(self, common_token_stream: CommonTokenStream = None, source_class=None, field_name: str = None): """To implement Increase Field Visibility refactoring based on its actors. Detects the required field and increases/changes its visibility status. Args: common_token_stream (CommonTokenStream): A stream of tokens generated by parsing the main file using the ANTLR parser generator source_class (str): Name of the class in which the refactoring has to be done field_name (str): Name of the field whose visibility status has to be changed Returns: No returns """ if field_name is None: self.field_name = "" else: self.field_name = field_name if source_class is None: self.source_class = "" else: self.source_class = source_class if common_token_stream is None: raise ValueError('common_token_stream is None') else: self.token_stream_rewriter = TokenStreamRewriter(common_token_stream) self.is_source_class = False self.detected_field = None self.detected_method = None self.TAB = "\t" self.NEW_LINE = "\n" self.code = "" self.tempdeclarationcode = "" def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): class_identifier = ctx.IDENTIFIER().getText() if class_identifier == self.source_class: self.is_source_class = True else: self.is_source_class = False def exitFieldDeclaration(self, ctx: JavaParserLabeled.FieldDeclarationContext): if not self.is_source_class: return None grand_parent_ctx = ctx.parentCtx.parentCtx # field_identifier = ctx.variableDeclarators().getText().split(",") field_identifier = ctx.variableDeclarators().variableDeclarator(0).variableDeclaratorId().IDENTIFIER().getText() if self.field_name in field_identifier: if grand_parent_ctx.modifier() == []: self.token_stream_rewriter.replaceRange( from_idx=ctx.typeType().start.tokenIndex, to_idx=ctx.typeType().stop.tokenIndex, text='private ' + ctx.typeType().getText() ) elif grand_parent_ctx.modifier(0).getText() == 'public': self.token_stream_rewriter.replaceRange( from_idx=grand_parent_ctx.modifier(0).start.tokenIndex, to_idx=grand_parent_ctx.modifier(0).stop.tokenIndex, text='private') elif grand_parent_ctx.modifier(0).getText() != 'private': self.token_stream_rewriter.replaceRange( from_idx=grand_parent_ctx.modifier(0).start.tokenIndex, to_idx=grand_parent_ctx.modifier(0).stop.tokenIndex, text='private ' + grand_parent_ctx.modifier(0).getText()) # generate accessor and mutator methods # Accessor body new_code = '\n\t' new_code += 'public ' + ctx.typeType().getText() + ' get' + str.capitalize(self.field_name) new_code += '() { \n\t\t return this.' + self.field_name + ';' + '\n\t}' # Mutator body new_code += '\n\t' new_code += 'public void set' + str.capitalize(self.field_name) new_code += '(' + ctx.typeType().getText() + ' ' + self.field_name + ') { \n\t\t' new_code += 'this.' + self.field_name + ' = ' + self.field_name + ';' + '\n\t}\n' self.token_stream_rewriter.insertAfter(ctx.stop.tokenIndex, new_code)