class PushDownMethodRefactoringListener(JavaParserLabeledListener): """ """ def __init__(self, common_token_stream: CommonTokenStream, source_class: str, source_method_text: str): """ """ self.source_method_text = source_method_text self.source_class = source_class self.token_stream_rewriter = TokenStreamRewriter(common_token_stream) self.is_safe = False def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): self.is_safe = ctx.IDENTIFIER().getText() == self.source_class def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): self.is_safe = not self.is_safe def enterClassBody(self, ctx: JavaParserLabeled.ClassBodyContext): if self.is_safe: self.token_stream_rewriter.insertBefore( index=ctx.stop.tokenIndex, text=self.source_method_text + "\n", program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME)
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 PropagationMakeAbstractClassRefactoringListener(JavaParserLabeledListener ): def __init__(self, common_token_stream: CommonTokenStream = None, Source_class=None, object_name=None, propagated_class_name=None): if Source_class is None: self.source_class = [] else: self.source_class = Source_class if object_name is None: self.object_name = [] else: self.object_name = object_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 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 def enterClassBody(self, ctx: JavaParserLabeled.ClassBodyContext): if not self.is_class: return None self.token_stream_rewriter.insertBefore( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, index=ctx.start.tokenIndex, text=' extends ' + self.source_class) def enterVariableDeclarator( self, ctx: JavaParserLabeled.VariableDeclaratorContext): if not self.is_class: return None ctx_grandparent = ctx.parentCtx.parentCtx if ctx.variableDeclaratorId().IDENTIFIER().getText( ) in self.object_name: self.objectName = ctx.variableDeclaratorId().IDENTIFIER().getText() if ctx_grandparent.typeType().classOrInterfaceType().IDENTIFIER( 0).getText() in self.source_class: self.token_stream_rewriter.delete( from_idx=ctx_grandparent.start.tokenIndex, to_idx=ctx_grandparent.stop.tokenIndex, program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME) def enterExpression(self, ctx: JavaParserLabeled.ExpressionContext): if not self.is_class: return None if ctx.expression(0) != None: if ctx.expression(0).primary() != None: if ctx.expression(0).primary().IDENTIFIER().getText( ) in self.object_name: count = ctx.getChildCount() if count == 3: self.token_stream_rewriter.replaceRange( from_idx=ctx.start.tokenIndex, to_idx=ctx.stop.tokenIndex, text=ctx.children[count - 1].getText())
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 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)