Beispiel #1
0
class MakeMethodStaticRefactoringListener(JavaParserLabeledListener):
    """
    To implement extract class refactoring based on its actors.
    Creates a new class and move fields and methods from the old class to the new one
    """
    def __init__(self,
                 common_token_stream: CommonTokenStream = None,
                 target_class: str = None,
                 target_methods: list = None):

        if common_token_stream is None:
            raise ValueError('common_token_stream is None')
        else:
            self.token_stream_rewriter = TokenStreamRewriter(
                common_token_stream)

        if target_class is None:
            raise ValueError("source_class is None")
        else:
            self.target_class = target_class
        if target_methods is None or len(target_methods) == 0:
            raise ValueError("target method must have one method name")
        else:
            self.target_methods = target_methods

        self.is_target_class = False
        self.detected_instance_of_target_class = []
        self.TAB = "\t"
        self.NEW_LINE = "\n"
        self.code = ""

    def enterClassDeclaration(self,
                              ctx: JavaParserLabeled.ClassDeclarationContext):
        class_identifier = ctx.IDENTIFIER().getText()
        if class_identifier == self.target_class:
            self.is_target_class = True
        else:
            self.is_target_class = False

    def exitClassDeclaration(self,
                             ctx: JavaParserLabeled.ClassDeclarationContext):
        if self.is_target_class:
            self.is_target_class = False

    def enterMethodDeclaration(
            self, ctx: JavaParserLabeled.MethodDeclarationContext):
        if self.is_target_class:
            if ctx.IDENTIFIER().getText() in self.target_methods:
                if 'this.' in ctx.getText():
                    raise ValueError("this method can not refactor")
                grand_parent_ctx = ctx.parentCtx.parentCtx
                if grand_parent_ctx.modifier():
                    if len(grand_parent_ctx.modifier()) == 2:
                        return None
                    else:
                        self.token_stream_rewriter.insertAfter(
                            index=grand_parent_ctx.modifier(0).stop.tokenIndex,
                            program_name=self.token_stream_rewriter.
                            DEFAULT_PROGRAM_NAME,
                            text=" static")
                else:
                    self.token_stream_rewriter.insertBeforeIndex(
                        index=ctx.start.tokenIndex, text="static ")

    def enterLocalVariableDeclaration(
            self, ctx: JavaParserLabeled.LocalVariableDeclarationContext):
        if ctx.typeType().getText() == self.target_class:
            self.detected_instance_of_target_class.append(
                ctx.variableDeclarators().variableDeclarator(
                    0).variableDeclaratorId().IDENTIFIER().getText())
            self.token_stream_rewriter.delete(
                program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME,
                from_idx=ctx.start.tokenIndex,
                to_idx=ctx.stop.tokenIndex + 1)

    def enterMethodCall0(self, ctx: JavaParserLabeled.MethodCall0Context):
        if ctx.IDENTIFIER().getText() in self.target_methods:
            if ctx.parentCtx.expression().getText(
            ) in self.detected_instance_of_target_class:
                self.token_stream_rewriter.replace(
                    program_name=self.token_stream_rewriter.
                    DEFAULT_PROGRAM_NAME,
                    from_idx=ctx.parentCtx.expression().start.tokenIndex,
                    to_idx=ctx.parentCtx.expression().stop.tokenIndex,
                    text=self.target_class)
Beispiel #2
0
class RemoveFieldRefactoringListener(JavaParserLabeledListener):
    def __init__(self, common_token_stream: CommonTokenStream = None, class_identifier: str = None,
                 fieldname: str = None, filename: str = None):
        """
        :param common_token_stream:
        """
        self.enter_class = False
        self.enter_field = False
        self.is_found_field = False
        self.is_found = False
        self.token_stream = common_token_stream
        self.class_identifier = class_identifier
        self.class_number = 0

        # Move all the tokens in the source code in a buffer, token_stream_rewriter.
        if common_token_stream is not None:
            self.token_stream_rewriter = TSR(common_token_stream)
        else:
            raise TypeError('common_token_stream is None')

        self.class_fields = []
        self.class_methods = []

        if class_identifier is not None:
            self.class_identifier = class_identifier
        else:
            raise ValueError("class_identifier is None")

        if filename is not None:
            self.filename = filename
        else:
            raise ValueError("filename is None")

        if fieldname is not None:
            self.fieldname = fieldname
        else:
            raise ValueError("fieldname is None")

    def enterClassDeclaration(self, ctx:JavaParserLabeled.ClassDeclarationContext):

        self.class_number += 1
        if ctx.IDENTIFIER().getText() != self.class_identifier:
            return
        self.enter_class = True

    # Enter a parse tree produced by Java9_v2Parser#normalClassDeclaration.
    # def enterNormalClassDeclaration(self, ctx: Java9_v2Parser.NormalClassDeclarationContext):
    #
    #     self.class_number += 1
    #     if ctx.identifier().getText() != self.class_identifier:
    #         return
    #     self.enter_class = True

    def exitClassDeclaration(self, ctx:JavaParserLabeled.ClassDeclarationContext):
        self.enter_class = False
        if ctx.IDENTIFIER().getText() != self.class_identifier:
            return

        old_file = open(self.filename, 'w')
        old_file.write(self.token_stream_rewriter.getDefaultText().replace("\r", ""))

    # Exit a parse tree produced by Java9_v2Parser#normalClassDeclaration.
    # def exitNormalClassDeclaration(self, ctx: Java9_v2Parser.NormalClassDeclarationContext):
    #     self.enter_class = False
    #     if ctx.identifier().getText() != self.class_identifier:
    #         return
    #
    #     old_file = open(self.filename, 'w')
    #     old_file.write(self.token_stream_rewriter.getDefaultText().replace("\r", ""))
    #
    #     # print("----------------------------")
    #     # print("Class attributes: ", str(self.class_fields))
    #     # print("Class methods: ", str(self.class_methods))
    #     # print("----------------------------")

    # Enter a parse tree produced by Java9_v2Parser#fieldDeclaration.

    def enterFieldDeclaration(self, ctx:JavaParserLabeled.FieldDeclarationContext):
        if not self.enter_class:
            return
        self.enter_field = True
        self.is_found_field = False

    # def enterFieldDeclaration(self, ctx:Java9_v2Parser.FieldDeclarationContext):
    #     if not self.enter_class:
    #         return
    #     self.enter_field = True
    #     self.is_found_field = False

    # Exit a parse tree produced by Java9_v2Parser#fieldDeclaration.

    def exitClassBodyDeclaration2(self, ctx:JavaParserLabeled.ClassBodyDeclaration2Context):
        if not self.enter_class:
            return

        # print("Enter 'exitFieldDeclaration' Methode")
        start = ctx.start.tokenIndex
        stop = ctx.stop.tokenIndex

        if (self.is_found_field):
            self.token_stream_rewriter.delete(program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME,
                                              from_idx=start,
                                              to_idx=stop)
            print(f'Field: "{self.fieldname}" SUCCESSFULLY REMOVED...')

    # def exitFieldDeclaration(self, ctx:JavaParserLabeled.FieldDeclarationContext):
    #     if not self.enter_class:
    #         return
    #
    #     # print("Enter 'exitFieldDeclaration' Methode")
    #     start = ctx.start.tokenIndex
    #     stop = ctx.stop.tokenIndex
    #
    #     if (self.is_found_field):
    #         self.token_stream_rewriter.delete(program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME,
    #                                           from_idx=start,
    #                                           to_idx=stop)
    #         print(f'Field: "{self.fieldname}" SUCCESSFULLY REMOVED...')

    # def exitFieldDeclaration(self, ctx: Java9_v2Parser.FieldDeclarationContext):
    #     if not self.enter_class:
    #         return
    #
    #     # print("Enter 'exitFieldDeclaration' Methode")
    #     start = ctx.start.tokenIndex
    #     stop = ctx.stop.tokenIndex
    #
    #     if (self.is_found_field):
    #         self.token_stream_rewriter.delete(program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME,
    #                                           from_idx=start,
    #                                           to_idx=stop)
    #         print(f'Field: "{self.fieldname}" SUCCESSFULLY REMOVED...')

    # Exit a parse tree produced by Java9_v2Parser#variableDeclaratorList.

    def exitVariableDeclarators(self, ctx:JavaParserLabeled.VariableDeclaratorsContext):
        if not (self.enter_class and self.enter_field):
            return
        # print("Enter 'exitVariableDeclaratorList' Methode")
        fields = ctx.getText().split(',')
        start = ctx.start.tokenIndex
        stop = ctx.stop.tokenIndex
        for index, field in enumerate(fields):
            if (self.fieldname == str(field).split('=')[0]):
                self.is_found = True
                self.is_found_field = True
                print(f'Find "{self.fieldname}", At: {start} - {stop}')
                if (len(fields) == 1):
                    return
                del fields[index]
                print('New: ' ,', '.join(str(field) for field in fields))
                self.token_stream_rewriter.replace(program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME,
                                                   from_idx=start,
                                                   to_idx=stop,
                                                   text=', '.join(str(field) for field in fields))
                self.is_found_field = False
                print(f'Field: "{self.fieldname}" SUCCESSFULLY REMOVED...')
                break

    # def exitVariableDeclaratorList(self, ctx:Java9_v2Parser.VariableDeclaratorListContext):
    #     if not (self.enter_class and self.enter_field):
    #         return
    #     # print("Enter 'exitVariableDeclaratorList' Methode")
    #     fields = ctx.getText().split(',')
    #     start = ctx.start.tokenIndex
    #     stop = ctx.stop.tokenIndex
    #     for index, field in enumerate(fields):
    #         if (self.fieldname == str(field).split('=')[0]):
    #             self.is_found = True
    #             self.is_found_field = True
    #             print(f'Find "{self.fieldname}", At: {start} - {stop}')
    #             if (len(fields) == 1):
    #                 return
    #             del fields[index]
    #             print('New: ' ,', '.join(str(field) for field in fields))
    #             self.token_stream_rewriter.replace(program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME,
    #                                                from_idx=start,
    #                                                to_idx=stop,
    #                                                text=', '.join(str(field) for field in fields))
    #             self.is_found_field = False
    #             print(f'Field: "{self.fieldname}" SUCCESSFULLY REMOVED...')
    #             break

    def exitCompilationUnit(self, ctx:JavaParserLabeled.CompilationUnitContext):
        if not self.is_found:
            print(f'Field "{self.fieldname}" NOT FOUND...')
Beispiel #3
0
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)
Beispiel #4
0
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
                )
Beispiel #5
0
class ReplaceDependentObjectsListener(JavaParserLabeledListener):
    """
    To implement the move class refactoring
    a stream of tokens is sent to the listener, to build an object token_stream_rewriter
    and we move all class methods and fields from the source package to the target package
    """

    def __init__(self, common_token_stream: CommonTokenStream = None, class_identifier: str = None,
                 source_package: str = None, target_package: str = None, filename: str = None, has_import: bool = None):
        """
        :param common_token_stream:
        """
        self.token_stream = common_token_stream

        # Move all the tokens in the source code in a buffer, token_stream_rewriter.
        if common_token_stream is not None:
            self.token_stream_rewriter = TokenStreamRewriter(common_token_stream)
        else:
            raise TypeError('common_token_stream is None')

        if class_identifier is not None:
            self.class_identifier = class_identifier
        else:
            raise ValueError("class_identifier is None")

        if filename is not None:
            self.filename = filename
        else:
            raise ValueError("filename is None")

        if has_import is not None:
            self.has_import = has_import
        else:
            raise ValueError("has_import is None")

        if source_package is not None:
            self.source_package = source_package
        else:
            raise ValueError("source_package is None")

        if target_package is not None:
            self.target_package = target_package
        else:
            raise ValueError("target_package is None")

        self.need_import = False
        self.TAB = "\t"
        self.NEW_LINE = "\n"
        self.code = ""
        self.mul_imports = []
        self.exact_imports = []

    # Enter a parse tree produced by CompilationUnitContext
    def enterCompilationUnit(self, ctx: JavaParserLabeled.CompilationUnitContext):
        # Iterate over the declarations of context to save all import statements
        # in exact_imports and mul_imports
        for declaration in ctx.children:
            if isinstance(declaration, JavaParserLabeled.ImportDeclarationContext):
                imported_package = ""
                mul = None
                if declaration.qualifiedName() is not None:
                    imported_package += declaration.qualifiedName().getText()
                if declaration.MUL() is not None:
                    mul = declaration.MUL().getText()
                    imported_package += ".*"

                if mul is not None:
                    self.mul_imports.append(imported_package)
                else:
                    self.exact_imports.append(imported_package)

    # Exit a parse tree produced by JavaParserLabeled#importDeclaration.
    def exitImportDeclaration(self, ctx: JavaParserLabeled.ImportDeclarationContext):
        # extract the imported package from context
        imported_package = ""
        mul = None
        if ctx.qualifiedName() is not None:
            imported_package += ctx.qualifiedName().getText()
        if ctx.MUL() is not None:
            mul = ctx.MUL().getText()
            imported_package += '.' + ctx.MUL().getText()

        # return if the current import statement is not relevant to source package
        if self.source_package not in imported_package or (self.class_identifier not in imported_package and '*' not in imported_package):
            return

        start_index = ctx.start.tokenIndex
        stop_index = ctx.stop.tokenIndex

        target_exact_package = f"{self.target_package}.{self.class_identifier}"
        target_exact_import = f"import {target_exact_package};"

        if ctx.STATIC() is not None:
            target_exact_import = target_exact_import.replace("import", "import ")

        # handle import scenarios in files dependent on the moved class
        if target_exact_package in self.exact_imports:
            if mul is None:
                self.token_stream_rewriter.delete(
                    program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME,
                    from_idx=start_index,
                    to_idx=stop_index + 1
                )
        else:
            if mul is not None:
                self.token_stream_rewriter.insertAfter(
                    program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME,
                    index=stop_index,
                    text=self.NEW_LINE + target_exact_import
                )
            else:
                print(ctx.getText())
                self.token_stream_rewriter.replace(
                    program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME,
                    from_idx=start_index,
                    to_idx=stop_index,
                    text=target_exact_import
                )
            self.exact_imports.append(target_exact_package)

    # Exit a parse tree produced by JavaParserLabeled#classOrInterfaceType.
    def exitClassOrInterfaceType(self, ctx: JavaParserLabeled.ClassOrInterfaceTypeContext):
        if not self.has_import or not self.need_import:
            if self.class_identifier in ctx.getText().split('.'):
                self.need_import = True

    # Exit a parse tree produced by JavaParserLabeled#createdName0.
    def exitCreatedName0(self, ctx: JavaParserLabeled.CreatedName0Context):
        if not self.has_import or not self.need_import:
            if self.class_identifier in ctx.getText().split('.'):
                self.need_import = True

    # Exit a parse tree produced by JavaParserLabeled#expression1.
    def exitExpression1(self, ctx: JavaParserLabeled.Expression1Context):
        if not self.has_import or not self.need_import:
            if ctx.expression().getText == self.class_identifier:
                self.need_import = True

    # Exit a parse tree produced by JavaParserLabeled#typeDeclaration.
    def exitTypeDeclaration(self, ctx: JavaParserLabeled.TypeDeclarationContext):
        if ctx.classDeclaration() is not None:
            if not self.has_import or self.need_import:
                index = ctx.start.tokenIndex

                # return if the file has already imported the package
                if (self.source_package + '.' + self.class_identifier not in self.exact_imports) \
                        or (self.target_package + '.' + self.class_identifier in self.exact_imports):
                    return

                # delete class declaration from source class
                self.token_stream_rewriter.insertBefore(
                    program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME,
                    index=index,
                    text="import " + self.target_package + '.' + self.class_identifier + ';' + self.NEW_LINE
                )
Beispiel #6
0
class ReplaceDependentObjectsListener(JavaParserLabeledListener):
    """
    To implement the move class refactoring
    a stream of tokens is sent to the listener, to build an object token_stream_rewriter
    and we move all class methods and fields from the source package to the target package
    """
    def __init__(self,
                 common_token_stream: CommonTokenStream = None,
                 class_identifier: str = None,
                 source_package: str = None,
                 target_package: str = None,
                 filename: str = None,
                 has_import: bool = None):
        """
        :param common_token_stream:
        """
        self.token_stream = common_token_stream

        # Move all the tokens in the source code in a buffer, token_stream_rewriter.
        if common_token_stream is not None:
            self.token_stream_rewriter = TokenStreamRewriter(
                common_token_stream)
        else:
            raise TypeError('common_token_stream is None')

        if class_identifier is not None:
            self.class_identifier = class_identifier
        else:
            raise ValueError("class_identifier is None")

        if filename is not None:
            self.filename = filename
        else:
            raise ValueError("filename is None")

        if has_import is not None:
            self.has_import = has_import
        else:
            raise ValueError("has_import is None")

        if source_package is not None:
            self.source_package = source_package
        else:
            raise ValueError("source_package is None")

        if target_package is not None:
            self.target_package = target_package
        else:
            raise ValueError("target_package is None")

        self.need_import = False
        self.TAB = "\t"
        self.NEW_LINE = "\n"
        self.code = ""

    # Exit a parse tree produced by JavaParserLabeled#importDeclaration.
    def exitImportDeclaration(self,
                              ctx: JavaParserLabeled.ImportDeclarationContext):
        if ctx.qualifiedName().getText(
        ) != self.source_package + '.' + self.class_identifier:
            return

        start_index = ctx.start.tokenIndex
        stop_index = ctx.stop.tokenIndex

        text_to_replace = "import " + self.target_package + '.' + self.class_identifier + ';'
        if ctx.STATIC() is not None:
            text_to_replace = text_to_replace.replace("import",
                                                      "import static")

        # replace the import source package with target package
        self.token_stream_rewriter.replace(
            program_name=self.token_stream_rewriter.DEFAULT_PROGRAM_NAME,
            from_idx=start_index,
            to_idx=stop_index,
            text=text_to_replace)

    # Exit a parse tree produced by JavaParserLabeled#classOrInterfaceType.
    def exitClassOrInterfaceType(
            self, ctx: JavaParserLabeled.ClassOrInterfaceTypeContext):
        if not self.has_import or not self.need_import:
            if self.class_identifier in ctx.getText().split('.'):
                self.need_import = True

    # Exit a parse tree produced by JavaParserLabeled#createdName0.
    def exitCreatedName0(self, ctx: JavaParserLabeled.CreatedName0Context):
        if not self.has_import or not self.need_import:
            if self.class_identifier in ctx.getText().split('.'):
                self.need_import = True

    # Exit a parse tree produced by JavaParserLabeled#expression1.
    def exitExpression1(self, ctx: JavaParserLabeled.Expression1Context):
        if not self.has_import or not self.need_import:
            if ctx.expression().getText == self.class_identifier:
                self.need_import = True

    # Exit a parse tree produced by JavaParserLabeled#typeDeclaration.
    def exitTypeDeclaration(self,
                            ctx: JavaParserLabeled.TypeDeclarationContext):
        if ctx.classDeclaration() is not None:
            if not self.has_import or self.need_import:
                index = ctx.start.tokenIndex

                # delete class declaration from source class
                self.token_stream_rewriter.insertBefore(
                    program_name=self.token_stream_rewriter.
                    DEFAULT_PROGRAM_NAME,
                    index=index,
                    text="import " + self.target_package + '.' +
                    self.class_identifier + ';' + self.NEW_LINE)