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 RemoveFieldRefactoringListener(JavaParserLabeledListener): def __init__(self, common_token_stream: CommonTokenStream = None, class_identifier: str = None, fieldname: str = None, filename: str = None): """ :param common_token_stream: """ self.enter_class = False self.enter_field = False self.is_found_field = False self.is_found = False self.token_stream = common_token_stream self.class_identifier = class_identifier self.class_number = 0 # 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 = TSR(common_token_stream) else: raise TypeError('common_token_stream is None') self.class_fields = [] self.class_methods = [] if class_identifier is not None: self.class_identifier = class_identifier else: raise ValueError("class_identifier is None") if filename is not None: self.filename = filename else: raise ValueError("filename is None") if fieldname is not None: self.fieldname = fieldname else: raise ValueError("fieldname is None") def enterClassDeclaration(self, ctx:JavaParserLabeled.ClassDeclarationContext): self.class_number += 1 if ctx.IDENTIFIER().getText() != self.class_identifier: return self.enter_class = True # Enter a parse tree produced by Java9_v2Parser#normalClassDeclaration. # def enterNormalClassDeclaration(self, ctx: Java9_v2Parser.NormalClassDeclarationContext): # # self.class_number += 1 # if ctx.identifier().getText() != self.class_identifier: # return # self.enter_class = True def exitClassDeclaration(self, ctx:JavaParserLabeled.ClassDeclarationContext): self.enter_class = False if ctx.IDENTIFIER().getText() != self.class_identifier: return old_file = open(self.filename, 'w') old_file.write(self.token_stream_rewriter.getDefaultText().replace("\r", "")) # Exit a parse tree produced by Java9_v2Parser#normalClassDeclaration. # def exitNormalClassDeclaration(self, ctx: Java9_v2Parser.NormalClassDeclarationContext): # self.enter_class = False # if ctx.identifier().getText() != self.class_identifier: # return # # old_file = open(self.filename, 'w') # old_file.write(self.token_stream_rewriter.getDefaultText().replace("\r", "")) # # # print("----------------------------") # # print("Class attributes: ", str(self.class_fields)) # # print("Class methods: ", str(self.class_methods)) # # print("----------------------------") # Enter a parse tree produced by Java9_v2Parser#fieldDeclaration. def enterFieldDeclaration(self, ctx:JavaParserLabeled.FieldDeclarationContext): if not self.enter_class: return self.enter_field = True self.is_found_field = False # def enterFieldDeclaration(self, ctx:Java9_v2Parser.FieldDeclarationContext): # if not self.enter_class: # return # self.enter_field = True # self.is_found_field = False # Exit a parse tree produced by Java9_v2Parser#fieldDeclaration. def exitClassBodyDeclaration2(self, ctx:JavaParserLabeled.ClassBodyDeclaration2Context): if not self.enter_class: return # print("Enter 'exitFieldDeclaration' Methode") start = ctx.start.tokenIndex stop = ctx.stop.tokenIndex if (self.is_found_field): self.token_stream_rewriter.delete(program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, from_idx=start, to_idx=stop) print(f'Field: "{self.fieldname}" SUCCESSFULLY REMOVED...') # def exitFieldDeclaration(self, ctx:JavaParserLabeled.FieldDeclarationContext): # if not self.enter_class: # return # # # print("Enter 'exitFieldDeclaration' Methode") # start = ctx.start.tokenIndex # stop = ctx.stop.tokenIndex # # if (self.is_found_field): # self.token_stream_rewriter.delete(program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, # from_idx=start, # to_idx=stop) # print(f'Field: "{self.fieldname}" SUCCESSFULLY REMOVED...') # def exitFieldDeclaration(self, ctx: Java9_v2Parser.FieldDeclarationContext): # if not self.enter_class: # return # # # print("Enter 'exitFieldDeclaration' Methode") # start = ctx.start.tokenIndex # stop = ctx.stop.tokenIndex # # if (self.is_found_field): # self.token_stream_rewriter.delete(program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, # from_idx=start, # to_idx=stop) # print(f'Field: "{self.fieldname}" SUCCESSFULLY REMOVED...') # Exit a parse tree produced by Java9_v2Parser#variableDeclaratorList. def exitVariableDeclarators(self, ctx:JavaParserLabeled.VariableDeclaratorsContext): if not (self.enter_class and self.enter_field): return # print("Enter 'exitVariableDeclaratorList' Methode") fields = ctx.getText().split(',') start = ctx.start.tokenIndex stop = ctx.stop.tokenIndex for index, field in enumerate(fields): if (self.fieldname == str(field).split('=')[0]): self.is_found = True self.is_found_field = True print(f'Find "{self.fieldname}", At: {start} - {stop}') if (len(fields) == 1): return del fields[index] print('New: ' ,', '.join(str(field) for field in fields)) self.token_stream_rewriter.replace(program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, from_idx=start, to_idx=stop, text=', '.join(str(field) for field in fields)) self.is_found_field = False print(f'Field: "{self.fieldname}" SUCCESSFULLY REMOVED...') break # def exitVariableDeclaratorList(self, ctx:Java9_v2Parser.VariableDeclaratorListContext): # if not (self.enter_class and self.enter_field): # return # # print("Enter 'exitVariableDeclaratorList' Methode") # fields = ctx.getText().split(',') # start = ctx.start.tokenIndex # stop = ctx.stop.tokenIndex # for index, field in enumerate(fields): # if (self.fieldname == str(field).split('=')[0]): # self.is_found = True # self.is_found_field = True # print(f'Find "{self.fieldname}", At: {start} - {stop}') # if (len(fields) == 1): # return # del fields[index] # print('New: ' ,', '.join(str(field) for field in fields)) # self.token_stream_rewriter.replace(program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, # from_idx=start, # to_idx=stop, # text=', '.join(str(field) for field in fields)) # self.is_found_field = False # print(f'Field: "{self.fieldname}" SUCCESSFULLY REMOVED...') # break def exitCompilationUnit(self, ctx:JavaParserLabeled.CompilationUnitContext): if not self.is_found: print(f'Field "{self.fieldname}" NOT FOUND...')
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 InlineClassRefactoringListener(JavaParserLabeledListener): """ To implement inline class refactoring based on its actors. Creates a new class and move fields and methods from two old class to the new one, then delete the two class """ def __init__( self, common_token_stream: CommonTokenStream = None, source_class: str = None, source_class_data: dict = None, target_class: str = None, target_class_data: dict = None, is_complete: bool = False): """ """ 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 target_class is None: raise ValueError("new_class is None") else: self.target_class = target_class if target_class: self.target_class = target_class if source_class_data: self.source_class_data = source_class_data else: self.source_class_data = {'fields': [], 'methods': [], 'constructors': []} if target_class_data: self.target_class_data = target_class_data else: self.target_class_data = {'fields': [], 'methods': [], 'constructors': []} self.field_that_has_source = [] self.has_source_new = False self.is_complete = is_complete self.is_target_class = False 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.is_target_class = False elif class_identifier == self.target_class: self.is_target_class = True self.is_source_class = False else: self.is_target_class = False self.is_source_class = False def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if self.is_target_class and (self.source_class_data['fields'] or self.source_class_data['constructors'] or self.source_class_data['methods']): if not self.is_complete: final_fields = merge_fields(self.source_class_data['fields'], self.target_class_data['fields'], self.target_class) final_constructors = merge_constructors(self.source_class_data['constructors'], self.target_class_data['constructors']) final_methods = merge_methods(self.source_class_data['methods'], self.target_class_data['methods']) text = '\t' for field in final_fields: text += field.text + '\n' for constructor in final_constructors: text += constructor.text + '\n' for method in final_methods: text += method.text + '\n' self.token_stream_rewriter.insertBeforeIndex( index=ctx.stop.tokenIndex, text=text ) self.is_complete = True else: self.is_target_class = False elif self.is_source_class: if ctx.parentCtx.classOrInterfaceModifier(0) is None: return self.is_source_class = False self.token_stream_rewriter.delete( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, from_idx=ctx.parentCtx.classOrInterfaceModifier(0).start.tokenIndex, to_idx=ctx.stop.tokenIndex ) def enterClassBody(self, ctx: JavaParserLabeled.ClassBodyContext): if self.is_source_class: self.code += self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, start=ctx.start.tokenIndex + 1, stop=ctx.stop.tokenIndex - 1 ) self.token_stream_rewriter.delete( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, from_idx=ctx.parentCtx.start.tokenIndex, to_idx=ctx.parentCtx.stop.tokenIndex ) else: return None def enterFieldDeclaration(self, ctx: JavaParserLabeled.FieldDeclarationContext): if self.is_source_class or self.is_target_class: field_text = '' for child in ctx.children: if child.getText() == ';': field_text = field_text[:len(field_text) - 1] + ';' break field_text += child.getText() + ' ' name = ctx.variableDeclarators().variableDeclarator(0).variableDeclaratorId().IDENTIFIER().getText() if ctx.typeType().classOrInterfaceType() is not None and \ ctx.typeType().classOrInterfaceType().getText() == self.source_class: self.field_that_has_source.append(name) return modifier_text = '' for modifier in ctx.parentCtx.parentCtx.modifier(): modifier_text += modifier.getText() + ' ' field_text = modifier_text + field_text if self.is_source_class: self.source_class_data['fields'].append(Field(name=name, text=field_text)) else: self.target_class_data['fields'].append(Field(name=name, text=field_text)) def exitFieldDeclaration(self, ctx: JavaParserLabeled.FieldDeclarationContext): if self.is_target_class: if ctx.typeType().classOrInterfaceType().getText() == self.source_class: grand_parent_ctx = ctx.parentCtx.parentCtx 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) def enterConstructorDeclaration(self, ctx: JavaParserLabeled.ConstructorDeclarationContext): if self.is_source_class or self.is_target_class: if ctx.formalParameters().formalParameterList(): constructor_parameters = [ctx.formalParameters().formalParameterList().children[i] for i in range(len(ctx.formalParameters().formalParameterList().children)) if i % 2 == 0] else: constructor_parameters = [] constructor_text = '' for modifier in ctx.parentCtx.parentCtx.modifier(): constructor_text += modifier.getText() + ' ' if self.is_source_class: constructor_text += self.target_class else: constructor_text += ctx.IDENTIFIER().getText() constructor_text += ' ( ' for parameter in constructor_parameters: constructor_text += parameter.typeType().getText() + ' ' constructor_text += parameter.variableDeclaratorId().getText() + ', ' if constructor_parameters: constructor_text = constructor_text[:len(constructor_text) - 2] constructor_text += ')\n\t{' constructor_text += self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, start=ctx.block().start.tokenIndex + 1, stop=ctx.block().stop.tokenIndex - 1 ) constructor_text += '}\n' if self.is_source_class: self.source_class_data['constructors'].append(ConstructorOrMethod( name=self.target_class, parameters=[Parameter(parameter_type=p.typeType().getText(), name=p.variableDeclaratorId().IDENTIFIER().getText()) for p in constructor_parameters], text=constructor_text, constructor_body=self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, start=ctx.block().start.tokenIndex + 1, stop=ctx.block().stop.tokenIndex - 1 ))) else: self.target_class_data['constructors'].append(ConstructorOrMethod( name=self.target_class, parameters=[Parameter(parameter_type=p.typeType().getText(), name=p.variableDeclaratorId().IDENTIFIER().getText()) for p in constructor_parameters], text=constructor_text, constructor_body=self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, start=ctx.block().start.tokenIndex + 1, stop=ctx.block().stop.tokenIndex - 1 ))) proper_constructor = get_proper_constructor(self.target_class_data['constructors'][-1], self.source_class_data['constructors']) if proper_constructor is None: return self.token_stream_rewriter.insertBeforeIndex( index=ctx.stop.tokenIndex, text=proper_constructor.constructorBody ) def enterMethodDeclaration(self, ctx: JavaParserLabeled.MethodDeclarationContext): if self.is_source_class or self.is_target_class: if ctx.formalParameters().formalParameterList(): method_parameters = [ctx.formalParameters().formalParameterList().children[i] for i in range(len(ctx.formalParameters().formalParameterList().children)) if i % 2 == 0] else: method_parameters = [] method_text = '' for modifier in ctx.parentCtx.parentCtx.modifier(): method_text += modifier.getText() + ' ' type_text = ctx.typeTypeOrVoid().getText() if type_text == self.source_class: type_text = self.target_class if self.is_target_class: self.token_stream_rewriter.replace( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, from_idx=ctx.typeTypeOrVoid().start.tokenIndex, to_idx=ctx.typeTypeOrVoid().stop.tokenIndex, text=type_text ) method_text += type_text + ' ' + ctx.IDENTIFIER().getText() method_text += ' ( ' for parameter in method_parameters: method_text += parameter.typeType().getText() + ' ' method_text += parameter.variableDeclaratorId().getText() + ', ' if method_parameters: method_text = method_text[:len(method_text) - 2] method_text += ')\n\t{' method_text += self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, start=ctx.methodBody().start.tokenIndex + 1, stop=ctx.methodBody().stop.tokenIndex - 1 ) method_text += '}\n' if self.is_source_class: self.source_class_data['methods'].append(ConstructorOrMethod( name=ctx.IDENTIFIER().getText(), parameters=[Parameter( parameter_type=p.typeType().getText(), name=p.variableDeclaratorId().IDENTIFIER().getText()) for p in method_parameters], text=method_text)) else: self.target_class_data['methods'].append(ConstructorOrMethod( name=ctx.IDENTIFIER().getText(), parameters=[Parameter( parameter_type=p.typeType().getText(), name=p.variableDeclaratorId().IDENTIFIER().getText()) for p in method_parameters], text=method_text)) def enterExpression1(self, ctx: JavaParserLabeled.Expression1Context): if ctx.IDENTIFIER() is None and ctx.IDENTIFIER().getText() in self.field_that_has_source: field_text = ctx.expression().getText() self.token_stream_rewriter.replace( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, from_idx=ctx.start.tokenIndex, to_idx=ctx.stop.tokenIndex, text=field_text ) def exitExpression21(self, ctx: JavaParserLabeled.Expression21Context): if self.has_source_new: self.has_source_new = False 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 enterExpression4(self, ctx: JavaParserLabeled.Expression4Context): if ctx.children[-1].children[0].getText() == self.source_class: self.has_source_new = True def enterCreatedName0(self, ctx: JavaParserLabeled.CreatedName0Context): if ctx.IDENTIFIER(0).getText() == self.source_class and self.target_class: self.token_stream_rewriter.replaceIndex( index=ctx.start.tokenIndex, text=self.target_class ) def enterCreatedName1(self, ctx: JavaParserLabeled.CreatedName1Context): if ctx.getText() == self.source_class and self.target_class: self.token_stream_rewriter.replaceIndex( index=ctx.start.tokenIndex, text=self.target_class ) def enterFormalParameter(self, ctx: JavaParserLabeled.FormalParameterContext): class_type = ctx.typeType().classOrInterfaceType() if class_type: if class_type.IDENTIFIER(0).getText() == self.source_class and self.target_class: self.token_stream_rewriter.replaceIndex( index=class_type.start.tokenIndex, text=self.target_class ) def enterQualifiedName(self, ctx: JavaParserLabeled.QualifiedNameContext): if ctx.IDENTIFIER(0).getText() == self.source_class and self.target_class: self.token_stream_rewriter.replaceIndex( index=ctx.start.tokenIndex, text=self.target_class ) def exitExpression0(self, ctx: JavaParserLabeled.Expression0Context): if ctx.primary().getText() == self.source_class and self.target_class: self.token_stream_rewriter.replaceIndex( index=ctx.start.tokenIndex, text=self.target_class ) def enterLocalVariableDeclaration(self, ctx: JavaParserLabeled.LocalVariableDeclarationContext): if ctx.typeType().classOrInterfaceType(): if ctx.typeType().classOrInterfaceType().getText() == self.source_class and self.target_class: self.token_stream_rewriter.replace( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, from_idx=ctx.typeType().start.tokenIndex, to_idx=ctx.typeType().stop.tokenIndex, text=self.target_class )
class ReplaceDependentObjectsListener(JavaParserLabeledListener): """ To implement the move class refactoring a stream of tokens is sent to the listener, to build an object token_stream_rewriter and we move all class methods and fields from the source package to the target package """ def __init__(self, common_token_stream: CommonTokenStream = None, class_identifier: str = None, source_package: str = None, target_package: str = None, filename: str = None, has_import: bool = None): """ :param common_token_stream: """ self.token_stream = common_token_stream # 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') if class_identifier is not None: self.class_identifier = class_identifier else: raise ValueError("class_identifier is None") if filename is not None: self.filename = filename else: raise ValueError("filename is None") if has_import is not None: self.has_import = has_import else: raise ValueError("has_import is None") if source_package is not None: self.source_package = source_package else: raise ValueError("source_package is None") if target_package is not None: self.target_package = target_package else: raise ValueError("target_package is None") self.need_import = False self.TAB = "\t" self.NEW_LINE = "\n" self.code = "" self.mul_imports = [] self.exact_imports = [] # Enter a parse tree produced by CompilationUnitContext def enterCompilationUnit(self, ctx: JavaParserLabeled.CompilationUnitContext): # Iterate over the declarations of context to save all import statements # in exact_imports and mul_imports for declaration in ctx.children: if isinstance(declaration, JavaParserLabeled.ImportDeclarationContext): imported_package = "" mul = None if declaration.qualifiedName() is not None: imported_package += declaration.qualifiedName().getText() if declaration.MUL() is not None: mul = declaration.MUL().getText() imported_package += ".*" if mul is not None: self.mul_imports.append(imported_package) else: self.exact_imports.append(imported_package) # Exit a parse tree produced by JavaParserLabeled#importDeclaration. def exitImportDeclaration(self, ctx: JavaParserLabeled.ImportDeclarationContext): # extract the imported package from context imported_package = "" mul = None if ctx.qualifiedName() is not None: imported_package += ctx.qualifiedName().getText() if ctx.MUL() is not None: mul = ctx.MUL().getText() imported_package += '.' + ctx.MUL().getText() # return if the current import statement is not relevant to source package if self.source_package not in imported_package or (self.class_identifier not in imported_package and '*' not in imported_package): return start_index = ctx.start.tokenIndex stop_index = ctx.stop.tokenIndex target_exact_package = f"{self.target_package}.{self.class_identifier}" target_exact_import = f"import {target_exact_package};" if ctx.STATIC() is not None: target_exact_import = target_exact_import.replace("import", "import ") # handle import scenarios in files dependent on the moved class if target_exact_package in self.exact_imports: if mul is None: self.token_stream_rewriter.delete( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, from_idx=start_index, to_idx=stop_index + 1 ) else: if mul is not None: self.token_stream_rewriter.insertAfter( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, index=stop_index, text=self.NEW_LINE + target_exact_import ) else: print(ctx.getText()) self.token_stream_rewriter.replace( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, from_idx=start_index, to_idx=stop_index, text=target_exact_import ) self.exact_imports.append(target_exact_package) # Exit a parse tree produced by JavaParserLabeled#classOrInterfaceType. def exitClassOrInterfaceType(self, ctx: JavaParserLabeled.ClassOrInterfaceTypeContext): if not self.has_import or not self.need_import: if self.class_identifier in ctx.getText().split('.'): self.need_import = True # Exit a parse tree produced by JavaParserLabeled#createdName0. def exitCreatedName0(self, ctx: JavaParserLabeled.CreatedName0Context): if not self.has_import or not self.need_import: if self.class_identifier in ctx.getText().split('.'): self.need_import = True # Exit a parse tree produced by JavaParserLabeled#expression1. def exitExpression1(self, ctx: JavaParserLabeled.Expression1Context): if not self.has_import or not self.need_import: if ctx.expression().getText == self.class_identifier: self.need_import = True # Exit a parse tree produced by JavaParserLabeled#typeDeclaration. def exitTypeDeclaration(self, ctx: JavaParserLabeled.TypeDeclarationContext): if ctx.classDeclaration() is not None: if not self.has_import or self.need_import: index = ctx.start.tokenIndex # return if the file has already imported the package if (self.source_package + '.' + self.class_identifier not in self.exact_imports) \ or (self.target_package + '.' + self.class_identifier in self.exact_imports): return # delete class declaration from source class self.token_stream_rewriter.insertBefore( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, index=index, text="import " + self.target_package + '.' + self.class_identifier + ';' + self.NEW_LINE )
class ReplaceDependentObjectsListener(JavaParserLabeledListener): """ To implement the move class refactoring a stream of tokens is sent to the listener, to build an object token_stream_rewriter and we move all class methods and fields from the source package to the target package """ def __init__(self, common_token_stream: CommonTokenStream = None, class_identifier: str = None, source_package: str = None, target_package: str = None, filename: str = None, has_import: bool = None): """ :param common_token_stream: """ self.token_stream = common_token_stream # 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') if class_identifier is not None: self.class_identifier = class_identifier else: raise ValueError("class_identifier is None") if filename is not None: self.filename = filename else: raise ValueError("filename is None") if has_import is not None: self.has_import = has_import else: raise ValueError("has_import is None") if source_package is not None: self.source_package = source_package else: raise ValueError("source_package is None") if target_package is not None: self.target_package = target_package else: raise ValueError("target_package is None") self.need_import = False self.TAB = "\t" self.NEW_LINE = "\n" self.code = "" # Exit a parse tree produced by JavaParserLabeled#importDeclaration. def exitImportDeclaration(self, ctx: JavaParserLabeled.ImportDeclarationContext): if ctx.qualifiedName().getText( ) != self.source_package + '.' + self.class_identifier: return start_index = ctx.start.tokenIndex stop_index = ctx.stop.tokenIndex text_to_replace = "import " + self.target_package + '.' + self.class_identifier + ';' if ctx.STATIC() is not None: text_to_replace = text_to_replace.replace("import", "import static") # replace the import source package with target package self.token_stream_rewriter.replace( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, from_idx=start_index, to_idx=stop_index, text=text_to_replace) # Exit a parse tree produced by JavaParserLabeled#classOrInterfaceType. def exitClassOrInterfaceType( self, ctx: JavaParserLabeled.ClassOrInterfaceTypeContext): if not self.has_import or not self.need_import: if self.class_identifier in ctx.getText().split('.'): self.need_import = True # Exit a parse tree produced by JavaParserLabeled#createdName0. def exitCreatedName0(self, ctx: JavaParserLabeled.CreatedName0Context): if not self.has_import or not self.need_import: if self.class_identifier in ctx.getText().split('.'): self.need_import = True # Exit a parse tree produced by JavaParserLabeled#expression1. def exitExpression1(self, ctx: JavaParserLabeled.Expression1Context): if not self.has_import or not self.need_import: if ctx.expression().getText == self.class_identifier: self.need_import = True # Exit a parse tree produced by JavaParserLabeled#typeDeclaration. def exitTypeDeclaration(self, ctx: JavaParserLabeled.TypeDeclarationContext): if ctx.classDeclaration() is not None: if not self.has_import or self.need_import: index = ctx.start.tokenIndex # delete class declaration from source class self.token_stream_rewriter.insertBefore( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, index=index, text="import " + self.target_package + '.' + self.class_identifier + ';' + self.NEW_LINE)