def testToStringStartStop(self): input = InputStream('x = 3 * 0;') lexer = TestLexer2(input) stream = CommonTokenStream(lexer=lexer) stream.fill() rewriter = TokenStreamRewriter(tokens=stream) rewriter.replaceRange(4, 8, '0') self.assertEquals(rewriter.getDefaultText(), 'x = 0;') self.assertEquals(rewriter.getText('default', Interval(0, 9)), 'x = 0;') self.assertEquals(rewriter.getText('default', Interval(4, 8)), '0')
def testToStringStartStop(self): input = InputStream('x = 3 * 0;') lexer = TestLexer2(input) stream = CommonTokenStream(lexer=lexer) stream.fill() rewriter = TokenStreamRewriter(tokens=stream) rewriter.replaceRange(4, 8, '0') self.assertEqual(rewriter.getDefaultText(), 'x = 0;') self.assertEqual(rewriter.getText('default', 0, 9), 'x = 0;') self.assertEqual(rewriter.getText('default', 4, 8), '0')
class GetMethodTextPullUpMethodRefactoringListener(JavaParserLabeledListener): def __init__(self, common_token_stream: CommonTokenStream = None, child_class=None, moved_methods=None): if moved_methods is None: self.moved_methods = [] else: self.moved_methods = moved_methods if child_class is None: self.moved_methods = [] else: self.children_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.code = "" self.tempdeclarationcode = "" self.method_text = "" 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) else: return None def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): print("children class in get text refactor:", self.children_class) class_identifier = ctx.IDENTIFIER().getText() if class_identifier in self.children_class: self.is_children_class = True else: print("enter other class") self.is_children_class = False
def main(_): subject = """<?php $heredocString = <<<TXT HEREDOC TEXT TXT; $heredocString = <<<TXT HEREDOC TEXT TXT ; """ lexer = PhpLexer(InputStream(subject)) stream = CommonTokenStream(lexer) writer = TokenStreamRewriter(stream) sys.stdout.write( writer.getText(TokenStreamRewriter.DEFAULT_PROGRAM_NAME, (0, 100)))
class PullUpFieldGetTextFieldListener(JavaParserLabeledListener): def __init__(self, common_token_stream: CommonTokenStream, child=None, field=None): if common_token_stream is None: raise ValueError('common_token_stream is None') else: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) if child is None: raise ValueError("source_class is None") else: self.child = child if field is None: raise ValueError("field is None") else: self.field = field self.field_text = "" def enterFieldDeclaration(self, ctx: JavaParserLabeled.FieldDeclarationContext): ctx1 = ctx.parentCtx.parentCtx.parentCtx.parentCtx class_identifier = ctx1.IDENTIFIER().getText() if class_identifier in self.child: # field_identifier = ctx.variableDeclarators().getText().split(",") field_identifier = ctx.variableDeclarators().variableDeclarator( 0).variableDeclaratorId().IDENTIFIER().getText() if self.field 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)
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)))
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))
class MakeMethodNonStaticRefactoringListener(JavaParserLabeledListener): """ To implement Make Method None-Static refactoring based on its actors. """ 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.target_class_data = None self.is_target_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.target_class: self.is_target_class = True self.target_class_data = {'constructors': []} else: self.is_target_class = False def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): if self.is_target_class: have_default_constructor = False for constructor in self.target_class_data['constructor']: if len(constructor.parameters) == 0: have_default_constructor = True break if not have_default_constructor: self.token_stream_rewriter.insertBeforeIndex( index=ctx.stop.tokenIndex - 1, text= f'\n\t public {self.target_class_data["constructors"][0]} ()\n\t{{}}\n' ) self.is_target_class = False def enterMethodDeclaration( self, ctx: JavaParserLabeled.MethodDeclarationContext): if self.is_target_class: if ctx.IDENTIFIER().getText() in self.target_methods: grand_parent_ctx = ctx.parentCtx.parentCtx if grand_parent_ctx.modifier(): if len(grand_parent_ctx.modifier()) == 2: self.token_stream_rewriter.delete( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, from_idx=grand_parent_ctx.modifier( 1).start.tokenIndex - 1, to_idx=grand_parent_ctx.modifier( 1).stop.tokenIndex) else: if grand_parent_ctx.modifier(0).getText() == 'static': self.token_stream_rewriter.delete( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, from_idx=grand_parent_ctx.modifier( 0).start.tokenIndex - 1, to_idx=grand_parent_ctx.modifier( 0).stop.tokenIndex) else: return None def enterConstructorDeclaration( self, ctx: JavaParserLabeled.ConstructorDeclarationContext): if 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() + ' ' 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' self.target_class_data['constructors'].append( ConstructorOrMethod( name=self.target_class, parameters=[ Parameter(parameterType=p.typeType().getText(), name=p.variableDeclaratorId().IDENTIFIER(). getText()) for p in constructor_parameters ], text=constructor_text))
def do_refactor(self): program = get_program( self.source_filenames) # getting the program packages _sourceclass = program.packages[self.package_name].classes[ self.class_name] target_class_name = _sourceclass.superclass_name removemethod, removemethod1 = get_cons( program, self.package_name, target_class_name, self.class_name) # Similar cons in other classes _targetclass = program.packages[ self.package_name].classes[target_class_name] mets = program.packages[self.package_name].classes[ self.class_name].methods _method_name = [] for methodName, method in mets.items(): if method.is_constructor: _method_name = method break tokens_info = TokensInfo(_method_name.parser_context) if not _method_name.is_constructor: return False param_dict = {} len_params = {} Rewriter_ = Rewriter(program, self.filename_mapping) for remove in removemethod: flag2 = False _methodd = removemethod[remove] len_params[remove] = len(_methodd[0].split(",")) not_present = removemethod1 if _methodd is not None: _methodds = _methodd[0] _method = program.packages[ self.package_name].classes[remove].methods[str(_methodds)] params = "" params2 = "" for param in _method.parameters: flag = False for x in not_present: for y in x: if param[1] in y: flag = True flag2 = True if not flag: params += param[1] + "," params2 += param[0] + " " + param[1] + "," flag = False param_dict[remove] = params2[:-1] _method_token_info = TokensInfo(_method.parser_context) if flag2: str1 = "" for x in not_present: for y in x: str1 += y + ";" + "\n\t" Rewriter_.replace( _method_token_info, "public " + remove + "(" + params2[:-1] + ")" + "{\n\t" + "super(" + params[:-1] + ");" + "\n\t " + str1 + "}") else: Rewriter_.replace( _method_token_info, "public " + remove + "(" + params2[:-1] + ")" + "{\n\t" + "super(" + params[:-1] + ");" + "\n\t}") class_tokens_info = TokensInfo(_targetclass.parser_context.classBody()) class_tokens_info.stop = class_tokens_info.start key = min(len_params, key=len_params.get) _method_name1 = program.packages[ self.package_name].classes[key].methods[removemethod[key][0]] tokens_info = TokensInfo(_method_name1.parser_context) singlefileelement = SingleFileElement(_method_name1.parser_context, _method_name1.filename) token_stream_rewriter = TokenStreamRewriter( singlefileelement.get_token_stream()) strofmethod = token_stream_rewriter.getText( program_name=token_stream_rewriter.DEFAULT_PROGRAM_NAME, start=tokens_info.start, stop=tokens_info.stop) strofmethod = strofmethod.replace(_method_name1.class_name, target_class_name) Rewriter_.insert_after(tokens_info=class_tokens_info, text=strofmethod) Rewriter_.apply() return True
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 MoveClassRefactoringListener(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, dirname: str = None): """ :param common_token_stream: used to edit the content of the parsers """ self.enter_class = False self.token_stream = common_token_stream self.class_found = False self.class_fields = [] self.class_methods = [] # 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 dirname is not None: self.dirname = dirname else: raise ValueError("dirname 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.TAB = "\t" self.NEW_LINE = "\n" self.code = f"package {self.target_package};{self.NEW_LINE}{self.NEW_LINE}" # Exit a parse tree produced by JavaParserLabeled#importDeclaration. def exitImportDeclaration(self, ctx: JavaParserLabeled.ImportDeclarationContext): text_to_replace = "import " + ctx.qualifiedName().getText() + ';' if ctx.STATIC() is not None: text_to_replace = text_to_replace.replace("import", "import static") self.code += text_to_replace + self.NEW_LINE # Enter a parse tree produced by JavaParserLabeled#packageDeclaration. def enterPackageDeclaration(self, ctx: JavaParserLabeled.PackageDeclarationContext): package_name = ctx.getText()[7:-1] print(package_name) if package_name != self.source_package: raise ValueError(f"The package {package_name} in the file isn't equal to the source package!") # Exit a parse tree produced by JavaParserLabeled#classBodyDeclaration2. def exitClassBodyDeclaration2(self, ctx: JavaParserLabeled.ClassBodyDeclaration2Context): self.enter_class = False try: if ctx.memberDeclaration().classDeclaration().IDENTIFIER().getText() != self.class_identifier: return except Exception: return self.class_found = True start_index = ctx.start.tokenIndex stop_index = ctx.stop.tokenIndex # get the class body from the token_stream_rewriter class_body = self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, start=start_index, stop=stop_index ) self.code += f"import {self.source_package}.*;" self.code += self.NEW_LINE * 2 self.code += f"// Class \"{self.class_identifier}\" moved here " \ f"from package {self.source_package} by CodART" + self.NEW_LINE + \ f"{class_body}" # delete class declaration 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 ) 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("----------------------------") # Exit a parse tree produced by JavaParserLabeled#typeDeclaration. def exitTypeDeclaration(self, ctx: JavaParserLabeled.TypeDeclarationContext): if ctx.classDeclaration() is not None: self.enter_class = False if ctx.classDeclaration().IDENTIFIER().getText() != self.class_identifier: return self.enter_class = True self.class_found = True start_index = ctx.start.tokenIndex stop_index = ctx.stop.tokenIndex # get the class body from the token_stream_rewriter class_body = self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, start=start_index, stop=stop_index ) self.code += f"import {self.source_package}.*;" self.code += self.NEW_LINE * 2 self.code += f"// Class \"{self.class_identifier}\" moved here " \ f"from package {self.source_package} by CodART" + self.NEW_LINE + \ f"{class_body}" # delete class declaration 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 ) print("----------------------------") print("Class attributes: ", str(self.class_fields)) print("Class methods: ", str(self.class_methods)) print("----------------------------") # Enter a parse tree produced by JavaParserLabeled#fieldDeclaration. def enterFieldDeclaration(self, ctx: JavaParserLabeled.FieldDeclarationContext): if not self.enter_class: return list_of_fields = ctx.variableDeclarators().getText().split(",") for field in list_of_fields: self.class_fields.append(field) # Enter a parse tree produced by JavaParserLabeled#methodDeclaration. def enterMethodDeclaration(self, ctx: JavaParserLabeled.MethodDeclarationContext): if not self.enter_class: return method_name = ctx.IDENTIFIER().getText() self.class_methods.append(method_name) # Exit a parse tree produced by JavaParserLabeled#compilationUnit. def exitCompilationUnit(self, ctx: JavaParserLabeled.CompilationUnitContext): if not self.class_found: raise ValueError(f"Class \"{self.class_identifier}\" NOT FOUND!") file_address = self.dirname + '/' + self.target_package.replace('.', '/') + '/' + self.class_identifier + '.java' new_file = open(file_address, 'w') new_file.write(self.code.replace("\r", "")) print(f"The class \"{self.class_identifier}\" moved to the target package successfully!")
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, output_path: str = ""): 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.output_path = output_path self.is_source_class = False self.detected_field = None self.detected_method = None self.TAB = "\t" self.NEW_LINE = "\n" self.code = "" self.is_in_constructor = False def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): """ It checks if it is source class, we generate the declaration of the new class, by appending some text to self.code. """ 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 self.code += f"public {self.new_class}()" + "{ }" + self.NEW_LINE else: self.is_source_class = False def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): """ It close the opened curly brackets If it is the source class. """ if self.is_source_class: self.code += "}" self.is_source_class = False def exitCompilationUnit(self, ctx: JavaParserLabeled.CompilationUnitContext): """ it writes self.code in the output path. """ child_file_name = self.new_class + ".java" with open(os.path.join(self.output_path, child_file_name), "w+") as f: f.write(self.code.replace('\r\n', '\n')) def enterVariableDeclaratorId( self, ctx: JavaParserLabeled.VariableDeclaratorIdContext): """ It sets the detected field to the field if it is one of the moved fields. """ 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): """ It gets the field name, if the field is one of the moved fields, we move it and delete it from the source program. """ if not self.is_source_class: return None field_identifier = ctx.variableDeclarators().variableDeclarator( 0).variableDeclaratorId().IDENTIFIER().getText() field_names = list() field_names.append(field_identifier) # print("field_names=", field_names) grand_parent_ctx = ctx.parentCtx.parentCtx if self.detected_field in field_names: if (not grand_parent_ctx.modifier()): 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 ==>new start_index = ctx.parentCtx.parentCtx.start.tokenIndex stop_index = ctx.parentCtx.parentCtx.stop.tokenIndex self.token_stream_rewriter.delete( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, from_idx=start_index, to_idx=stop_index) self.detected_field = None def enterMethodDeclaration( self, ctx: JavaParserLabeled.MethodDeclarationContext): """ It sets the detected field to the method if it is one of the moved methods. """ 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): """ It gets the method name, if the method is one of the moved methods, we move it to the subclass and delete it from the source program. """ if not self.is_source_class: return None method_identifier = ctx.IDENTIFIER().getText() if self.detected_method == method_identifier: start_index = ctx.parentCtx.parentCtx.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 def enterConstructorDeclaration( self, ctx: JavaParserLabeled.ConstructorDeclarationContext): if self.is_source_class: self.is_in_constructor = True self.fields_in_constructor = [] self.methods_in_constructor = [] self.constructor_body = ctx.block() children = self.constructor_body.children def exitConstructorDeclaration( self, ctx: JavaParserLabeled.ConstructorDeclarationContext): if self.is_source_class and self.is_in_constructor: move_constructor_flag = False for field in self.fields_in_constructor: if field in self.moved_fields: move_constructor_flag = True for method in self.methods_in_constructor: if method in self.moved_methods: move_constructor_flag = True if move_constructor_flag: 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() + ' ' constructor_text += self.new_class 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' self.code += constructor_text start_index = ctx.parentCtx.parentCtx.start.tokenIndex stop_index = ctx.parentCtx.parentCtx.stop.tokenIndex self.token_stream_rewriter.delete( program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME, from_idx=start_index, to_idx=stop_index) self.is_in_constructor = False def enterExpression21(self, ctx: JavaParserLabeled.Expression21Context): if self.is_source_class and self.is_in_constructor: if len(ctx.children[0].children) == 1: self.fields_in_constructor.append(ctx.children[0].getText()) else: self.fields_in_constructor.append( ctx.children[0].children[-1].getText()) def enterMethodCall0(self, ctx: JavaParserLabeled.MethodCall0Context): if self.is_source_class and self.is_in_constructor: self.methods_in_constructor.append(ctx.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 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 RemoveControlFlagRefactoringListener(JavaParserLabeledListener): def __init__(self, common_token_stream: CommonTokenStream = None): self.isRelevant = False self.relevantVariable = None self.ifStmnt = None self.whileStmnt = None self.relevantVariableValue = None self.lastOccurance = dict() self.hasBlock = False if common_token_stream is not None: self.token_stream_rewriter = TokenStreamRewriter( common_token_stream) else: raise TypeError('common_token_stream is None') # Enter a parse tree produced by JavaParserLabeled#statement3. def enterStatement3(self, ctx: JavaParserLabeled.Statement3Context): if isinstance(ctx.statement(), JavaParserLabeled.Statement0Context): self.ifStmnt = ctx.statement().block().blockStatement( 0).statement() self.hasBlock = True if isinstance(self.ifStmnt, JavaParserLabeled.Statement2Context) and len( self.ifStmnt.children) <= 3: exp = self.ifStmnt.parExpression().expression() if isinstance(exp, JavaParserLabeled.Expression0Context): prm = exp.primary() if isinstance(prm, JavaParserLabeled.Primary4Context): self.isRelevant += 1 self.relevantVariable = prm.IDENTIFIER().getText() elif isinstance(exp, JavaParserLabeled.Expression8Context): exp2 = exp.expression() if isinstance(exp2, JavaParserLabeled.Expression0Context): prm = exp2.primary() if isinstance(prm, JavaParserLabeled.Primary4Context): self.isRelevant += 1 self.relevantVariable = prm.IDENTIFIER().getText() elif isinstance(ctx.statement(), JavaParserLabeled.Statement2Context) and len( ctx.statement().children) <= 3: self.hasBlock = False self.ifStmnt = ctx.statement() exp = self.ifStmnt.parExpression().expression() if isinstance(exp, JavaParserLabeled.Expression0Context): prm = exp.primary() if isinstance(prm, JavaParserLabeled.Primary4Context): self.isRelevant += 1 self.relevantVariable = prm.IDENTIFIER().getText() elif isinstance(exp, JavaParserLabeled.Expression8Context): exp2 = exp.expression() if isinstance(exp2, JavaParserLabeled.Expression0Context): prm = exp2.primary() if isinstance(prm, JavaParserLabeled.Primary4Context): self.isRelevant += 1 self.relevantVariable = prm.IDENTIFIER().getText() # Exit a parse tree produced by JavaParserLabeled#statement3. def exitStatement3(self, ctx: JavaParserLabeled.Statement3Context): if self.isRelevant: if (not self.hasBlock): interval = self.ifStmnt.getSourceInterval() stmnt = self.ifStmnt.statement(0) interval2 = stmnt.getSourceInterval() self.token_stream_rewriter.replaceRange( interval[0], interval[1], self.token_stream_rewriter.getText('default', interval2[0], interval2[1])) declarationInterval = self.lastOccurance[ self.relevantVariable].getSourceInterval() self.token_stream_rewriter.replaceRange( declarationInterval[0], declarationInterval[1], "") else: interval = self.ifStmnt.parentCtx.parentCtx.getSourceInterval() stmnt = self.ifStmnt.statement(0) interval2 = stmnt.getSourceInterval() self.token_stream_rewriter.replaceRange( interval[0], interval[1], self.token_stream_rewriter.getText('default', interval2[0], interval2[1])) declarationInterval = self.lastOccurance[ self.relevantVariable].getSourceInterval() self.token_stream_rewriter.replaceRange( declarationInterval[0], declarationInterval[1], "") self.isRelevant -= 1 # Enter a parse tree produced by JavaParserLabeled#statement4. def enterStatement4(self, ctx: JavaParserLabeled.Statement4Context): if isinstance(ctx.statement(), JavaParserLabeled.Statement0Context): self.whileStmnt = ctx exp = self.whileStmnt.parExpression().expression() if isinstance(exp, JavaParserLabeled.Expression0Context): prm = exp.primary() if isinstance(prm, JavaParserLabeled.Primary4Context): self.isRelevant += 1 self.relevantVariable = prm.IDENTIFIER().getText() elif isinstance(exp, JavaParserLabeled.Expression8Context): exp2 = exp.expression() if isinstance(exp2, JavaParserLabeled.Expression0Context): prm = exp2.primary() if isinstance(prm, JavaParserLabeled.Primary4Context): self.isRelevant += 1 self.relevantVariable = prm.IDENTIFIER().getText() # Exit a parse tree produced by JavaParserLabeled#statement4. def exitStatement4(self, ctx: JavaParserLabeled.Statement4Context): if self.isRelevant: interval = self.whileStmnt.parExpression().expression( ).getSourceInterval() self.token_stream_rewriter.replaceRange(interval[0], interval[1], "true") declarationInterval = self.lastOccurance[ self.relevantVariable].getSourceInterval() self.token_stream_rewriter.replaceRange(declarationInterval[0], declarationInterval[1], "") self.isRelevant -= 1 # Enter a parse tree produced by JavaParserLabeled#localVariableDeclaration. def enterLocalVariableDeclaration( self, ctx: JavaParserLabeled.LocalVariableDeclarationContext): if self.isRelevant: pass else: for child in ctx.variableDeclarators().variableDeclarator(): self.lastOccurance[ child.variableDeclaratorId().getText()] = ctx.parentCtx self.relevantVariableValue = child.variableInitializer( ).getText() # Enter a parse tree produced by JavaParserLabeled#expression1. def enterExpression21(self, ctx: JavaParserLabeled.Expression21Context): if self.isRelevant: if ctx.expression(0).getText() == self.relevantVariable: interval = ctx.getSourceInterval() self.token_stream_rewriter.replaceRange( interval[0], interval[1], "break")
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 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
def do_refactor(self): program = get_program(self.source_filenames) static = 0 if self.class_name not in program.packages[self.package_name].classes or self.target_class_name not in \ program.packages[ self.target_package_name].classes or self.method_key not in \ program.packages[self.package_name].classes[ self.class_name].methods: return False _sourceclass = program.packages[self.package_name].classes[ self.class_name] _targetclass = program.packages[self.target_package_name].classes[ self.target_class_name] _method = program.packages[self.package_name].classes[ self.class_name].methods[self.method_key] if _method.is_constructor: return False Rewriter_ = Rewriter(program, lambda x: x) tokens_info = TokensInfo( _method.parser_context) # tokens of ctx method param_tokens_info = TokensInfo(_method.formalparam_context) method_declaration_info = TokensInfo( _method.method_declaration_context) exp = [ ] # برای نگه داری متغیرهایی که داخل کلاس تعریف شدند و در بدنه متد استفاده شدند exps = tokens_info.get_token_index(tokens_info.token_stream.tokens, tokens_info.start, tokens_info.stop) # check that method is static or not for modifier in _method.modifiers: if modifier == "static": static = 1 for token in exps: if token.text in _sourceclass.fields: exp.append(token.tokenIndex) # check that where this method is call for package_names in program.packages: package = program.packages[package_names] for class_ in package.classes: _class = package.classes[class_] for method_ in _class.methods: __method = _class.methods[method_] for inv in __method.body_method_invocations: invc = __method.body_method_invocations[inv] method_name = self.method_key[:self.method_key.find('(' )] if invc[0] == method_name: inv_tokens_info = TokensInfo(inv) if static == 0: class_token_info = TokensInfo( _class.body_context) Rewriter_.insert_after_start( class_token_info, self.target_class_name + " " + str.lower(self.target_class_name) + "=" + "new " + self.target_class_name + "();") Rewriter_.apply() Rewriter_.insert_before_start( class_token_info, "import " + self.target_package_name + "." + self.target_class_name + ";") Rewriter_.replace(inv_tokens_info, self.target_class_name) Rewriter_.apply() class_tokens_info = TokensInfo(_targetclass.parser_context) package_tokens_info = TokensInfo( program.packages[self.target_package_name].package_ctx) singlefileelement = SingleFileElement(_method.parser_context, _method.filename) token_stream_rewriter = TokenStreamRewriter( singlefileelement.get_token_stream()) # insert name of source.java class befor param that define in body of classe (that use in method) for index in exp: token_stream_rewriter.insertBeforeIndex( index=index, text=str.lower(self.class_name) + ".") for inv in _method.body_method_invocations: if inv.getText() == self.target_class_name: inv_tokens_info_target = TokensInfo(inv) token_stream_rewriter.replaceRange( from_idx=inv_tokens_info_target.start, to_idx=inv_tokens_info_target.stop + 1, text=" ") # insert source.java class befor methods of sourcr class that used in method for i in _method.body_method_invocations_without_typename: if i.getText() == self.class_name: ii = _method.body_method_invocations_without_typename[i] i_tokens = TokensInfo(ii[0]) token_stream_rewriter.insertBeforeIndex( index=i_tokens.start, text=str.lower(self.class_name) + ".") # pass object of source.java class to method if param_tokens_info.start is not None: token_stream_rewriter.insertBeforeIndex( param_tokens_info.start, text=self.class_name + " " + str.lower(self.class_name) + ",") else: token_stream_rewriter.insertBeforeIndex( method_declaration_info.stop, text=self.class_name + " " + str.lower(self.class_name)) strofmethod = token_stream_rewriter.getText( program_name=token_stream_rewriter.DEFAULT_PROGRAM_NAME, start=tokens_info.start, stop=tokens_info.stop) Rewriter_.insert_before(tokens_info=class_tokens_info, text=strofmethod) Rewriter_.insert_after( package_tokens_info, "import " + self.target_package_name + "." + self.target_class_name + ";") Rewriter_.replace(tokens_info, "") Rewriter_.apply() return True
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 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
def do_refactor(self): program = get_program( self.source_filenames) # getting the program packages _sourceclass = program.packages[self.package_name].classes[ self.class_name] target_class_name = _sourceclass.superclass_name static = 0 removemethod = get_removemethods( program, self.package_name, target_class_name, self.method_key, self.class_name) # Similar methods in other classes _targetclass = program.packages[ self.package_name].classes[target_class_name] _method_name = program.packages[self.package_name].classes[ self.class_name].methods[self.method_key] tokens_info = TokensInfo(_method_name.parser_context) exps = tokens_info.get_token_index( tokens_info.token_stream.tokens, tokens_info.start, tokens_info. stop) # list of class variables that are used in the method if _method_name.is_constructor: return False # if method use param of class body return false for token in exps: if token.text in _sourceclass.fields: return False if bool(_method_name.body_method_invocations_without_typename): return False Rewriter_ = Rewriter(program, self.filename_mapping) for remove in removemethod: _methodd = removemethod[remove] if _methodd is not None: _methodds = _methodd[0] _method = program.packages[ self.package_name].classes[remove].methods[str(_methodds)] _method_token_info = TokensInfo(_method.parser_context) Rewriter_.replace(_method_token_info, " ") class_tokens_info = TokensInfo(_targetclass.parser_context) singlefileelement = SingleFileElement(_method_name.parser_context, _method_name.filename) token_stream_rewriter = TokenStreamRewriter( singlefileelement.get_token_stream()) strofmethod = token_stream_rewriter.getText( program_name=token_stream_rewriter.DEFAULT_PROGRAM_NAME, start=tokens_info.start, stop=tokens_info.stop) Rewriter_.insert_before(tokens_info=class_tokens_info, text=strofmethod) Rewriter_.apply() # The Method has to be updated anywhere else that it's used for package_names in program.packages: package = program.packages[package_names] for class_ in package.classes: _class = package.classes[class_] for method_ in _class.methods: __method = _class.methods[method_] for inv in __method.body_method_invocations: invc = __method.body_method_invocations[inv] method_name = self.method_key[:self.method_key.find('(' )] if invc[0] == method_name & package_names == self.package_name: inv_tokens_info = TokensInfo(inv) if static == 0: class_token_info = TokensInfo( _class.body_context) Rewriter_.insert_after_start( class_token_info, target_class_name + " " + str.lower(target_class_name) + "=" + "new " + target_class_name + "();") Rewriter_.apply() Rewriter_.replace(inv_tokens_info, target_class_name) Rewriter_.apply() return True
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 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)
def pullup_method_refactoring( source_filenames: list, package_name: str, class_name: str, method_key: str, filename_mapping=lambda x: x + ".rewritten.java"): program = get_program(source_filenames) #گرفتن پکیج های برنامه _sourceclass = program.packages[package_name].classes[class_name] target_class_name = _sourceclass.superclass_name static = 0 removemethod = get_removemethods( program, package_name, target_class_name, method_key, class_name) #متد های مشابه در کلاس های دیگر _targetclass = program.packages[package_name].classes[target_class_name] _method_name = program.packages[package_name].classes[class_name].methods[ method_key] tokens_info = TokensInfo(_method_name.parser_context) exps = tokens_info.get_token_index( tokens_info.token_stream.tokens, tokens_info.start, tokens_info.stop ) #لیست متغیر های داخل بدنه کلاس که داخل متد استفاده شده اند if _method_name.is_constructor: return False #if method use param of class body return false for token in exps: if token.text in _sourceclass.fields: return False if bool(_method_name.body_method_invocations_without_typename) == True: return False Rewriter_ = Rewriter(program, filename_mapping) for remove in removemethod: _methodd = removemethod[remove] if _methodd != None: _methodds = _methodd[0] _method = program.packages[package_name].classes[remove].methods[ str(_methodds)] _method_token_info = TokensInfo(_method.parser_context) Rewriter_.replace(_method_token_info, " ") class_tokens_info = TokensInfo(_targetclass.parser_context) singlefileelement = SingleFileElement(_method_name.parser_context, _method_name.filename) token_stream_rewriter = TokenStreamRewriter( singlefileelement.get_token_stream()) strofmethod = token_stream_rewriter.getText( program_name=token_stream_rewriter.DEFAULT_PROGRAM_NAME, start=tokens_info.start, stop=tokens_info.stop) Rewriter_.insert_before(tokens_info=class_tokens_info, text=strofmethod) Rewriter_.apply() #در کلاس های دیگر هر جا که از این متد استفاده شده باید اپدیت شود for package_names in program.packages: package = program.packages[package_names] for class_ in package.classes: _class = package.classes[class_] for method_ in _class.methods: __method = _class.methods[method_] for inv in __method.body_method_invocations: invc = __method.body_method_invocations[inv] method_name = method_key[:method_key.find('(')] if (invc[0] == method_name & package_names == package_name): inv_tokens_info = TokensInfo(inv) if (static == 0): class_token_info = TokensInfo(_class.body_context) Rewriter_.insert_after_start( class_token_info, target_class_name + " " + str.lower(target_class_name) + "=" + "new " + target_class_name + "();") Rewriter_.apply() Rewriter_.replace(inv_tokens_info, target_class_name) Rewriter_.apply() return True
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 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 ExtractClassRefactoringListener(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, method_map: dict = None): if method_map is None: self.method_map = {} else: self.method_map = method_map 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 = "" self.package_name = "" self.parameters = [] self.object_name = self.new_class.replace( self.new_class, self.new_class[0].lower() + self.new_class[1:]) self.modifiers = "" self.do_increase_visibility = False temp = [] for method in moved_methods: temp.append(self.method_map.get(method)) self.fields_to_increase_visibility = set().union(*temp) def enterPackageDeclaration( self, ctx: JavaParserLabeled.PackageDeclarationContext): if ctx.qualifiedName() and not self.package_name: self.package_name = ctx.qualifiedName().getText() self.code += f"package {self.package_name};{self.NEW_LINE}" def enterImportDeclaration( self, ctx: JavaParserLabeled.ImportDeclarationContext): i = self.token_stream_rewriter.getText( program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME, start=ctx.start.tokenIndex, stop=ctx.stop.tokenIndex) self.code += f"\n{i}\n" def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): class_identifier = str(ctx.children[1]) 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 enterClassBody(self, ctx: JavaParserLabeled.ClassBodyContext): if self.is_source_class: self.token_stream_rewriter.insertAfterToken( token=ctx.start, text="\n\t" + f"public {self.new_class} {self.object_name} = new {self.new_class}();", program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME) def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext): class_identifier = str(ctx.children[1]) if class_identifier == self.source_class: self.code += "}" self.is_source_class = False else: self.is_source_class = True def exitCompilationUnit(self, ctx: JavaParserLabeled.CompilationUnitContext): pass 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 enterFieldDeclaration(self, ctx: JavaParserLabeled.FieldDeclarationContext): field_names = ctx.variableDeclarators().getText().split(",") for field in field_names: if field in self.fields_to_increase_visibility: for modifier in ctx.parentCtx.parentCtx.modifier(): if modifier.getText() == "private": self.token_stream_rewriter.replaceSingleToken( token=modifier.start, text="public") def exitFieldDeclaration(self, ctx: JavaParserLabeled.FieldDeclarationContext): if not self.is_source_class: return None if not self.detected_field: return None field_names = ctx.variableDeclarators().getText() field_names = field_names.split(',') grand_parent_ctx = ctx.parentCtx.parentCtx if any([self.detected_field in i for i in field_names]): field_type = ctx.typeType().getText() if len(field_names) == 1: self.code += f"public {field_type} {field_names[0]};{self.NEW_LINE}" else: self.code += f"public {field_type} {self.detected_field};{self.NEW_LINE}" # delete field from source class for i in field_names: if self.detected_field in i: field_names.remove(i) if field_names: self.token_stream_rewriter.replaceRange( from_idx=grand_parent_ctx.start.tokenIndex, to_idx=grand_parent_ctx.stop.tokenIndex, text=f"public {field_type} {','.join(field_names)};\n") 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 enterFormalParameter(self, ctx: JavaParserLabeled.FormalParameterContext): if self.detected_method: self.parameters.append( ctx.variableDeclaratorId().IDENTIFIER().getText()) 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 + ("public " + method_text + self.NEW_LINE) # delegate method body in source class if self.method_map.get(method_identifier): self.parameters.append("this") self.token_stream_rewriter.replaceRange( from_idx=ctx.methodBody().start.tokenIndex, to_idx=stop_index, text="{" + f"\nreturn this.{self.object_name}.{self.detected_method}(" + ",".join(self.parameters) + ");\n" + "}") self.parameters = [] self.detected_method = None def enterExpression1(self, ctx: JavaParserLabeled.Expression1Context): identifier = ctx.IDENTIFIER() if identifier is not None: if identifier.getText( ) in self.moved_fields and self.detected_method not in self.moved_methods: # Found field usage! self.token_stream_rewriter.insertBeforeToken( token=ctx.stop, text=self.object_name + ".", program_name=self.token_stream_rewriter. DEFAULT_PROGRAM_NAME)