Skip to content

Rename method

Implementation 1

Introduction

When the name of a method does not explain what the method does (method's functionality), it needs to be changed.

Pre and post conditions

Pre-conditions:

  1. User must enter the existing method's name, The source class's name for the refactoring, and the new method name in order to rename.

  2. Check if the method exist, then rename it.

Post-conditions:

  1. After refactoring, all the old method names in the project should be changed.

See whether the method is defined in a superclass or subclass. If so, you must repeat all steps in these classes too.

The next method is important for maintaining the functionality of the program during the refactoring process. Create a new method with a new name. Copy the code of the old method to it. Delete all the code in the old method and, instead of it, insert a call for the new method.

Find all references to the old method and replace them with references to the new one.

Delete the old method. If the old method is part of a public interface, don’t perform this step. Instead, mark the old method as deprecated.

RenameMethodListener (JavaParserLabeledListener)

The class implements Rename Method refactoring. The Main listener which parses the file based on the provided information, using ANTLR parser generator and tokenization methods

Source code in codart\refactorings\rename_method.py
class RenameMethodListener(JavaParserLabeledListener):
    """

    The class implements Rename Method refactoring.
    The Main listener which parses the file based on the provided information, \
        using ANTLR parser generator and tokenization methods

    """

    def __init__(self, java_file_path, common_token_stream, scope_class_name, target_method_name, new_name,
                 reference=None):
        """

        Initializer of rename method refactoring listener

            Args:

                java_file_path(str): Address path to the test/source file

                common_token_stream (CommonTokenStream): An instance of ANTLR4 CommonTokenStream class

                scope_class_name(str): Name of the class in which the refactoring has to be done

                target_method_name(str): Name of the method in which the refactoring has to be done

                new_name(str): The new name of the refactored method

            Returns:

                RenameMethodListener: An instance of RenameMethodListener class

        """

        self.file_path = java_file_path
        self.token_stream = common_token_stream
        self.token_stream_rewriter = TokenStreamRewriter(common_token_stream)
        self.class_name = scope_class_name
        self.method_name = target_method_name
        self.new_method_name = new_name
        self.in_class = False
        self.changed = False
        self.reference = reference

    def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext):
        name = ctx.IDENTIFIER().getText()
        if name == self.class_name:
            self.in_class = True

    def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext):
        name = ctx.IDENTIFIER().getText()
        if name == self.class_name:
            self.in_class = False

    def enterMethodDeclaration(self, ctx: JavaParserLabeled.MethodDeclarationContext):
        if self.in_class:
            name = ctx.IDENTIFIER()
            if name.getText() == self.method_name:
                node = name.getSymbol()
                self.token_stream_rewriter.replaceIndex(
                    node.tokenIndex,
                    self.new_method_name
                )
                self.changed = True

    def enterMethodCall0(self, ctx: JavaParserLabeled.MethodCall0Context):
        if self.in_class and self.reference:
            name = ctx.IDENTIFIER()
            if name.getText() == self.method_name:
                node = name.getSymbol()
                if node.line == self.reference["line"]:
                    self.token_stream_rewriter.replaceIndex(
                        node.tokenIndex,
                        self.new_method_name
                    )
                    self.changed = True

    def enterMethodCall1(self, ctx: JavaParserLabeled.MethodCall1Context):
        if self.in_class and self.reference:
            name = ctx.IDENTIFIER()
            if name.getText() == self.method_name:
                node = name.getSymbol()
                if node.line == self.reference["line"]:
                    self.token_stream_rewriter.replaceIndex(
                        node.tokenIndex,
                        self.new_method_name
                    )
                    self.changed = True

__init__(self, java_file_path, common_token_stream, scope_class_name, target_method_name, new_name, reference=None) special

Initializer of rename method refactoring listener

Args:

    java_file_path(str): Address path to the test/source file

    common_token_stream (CommonTokenStream): An instance of ANTLR4 CommonTokenStream class

    scope_class_name(str): Name of the class in which the refactoring has to be done

    target_method_name(str): Name of the method in which the refactoring has to be done

    new_name(str): The new name of the refactored method

Returns:

    RenameMethodListener: An instance of RenameMethodListener class
Source code in codart\refactorings\rename_method.py
def __init__(self, java_file_path, common_token_stream, scope_class_name, target_method_name, new_name,
             reference=None):
    """

    Initializer of rename method refactoring listener

        Args:

            java_file_path(str): Address path to the test/source file

            common_token_stream (CommonTokenStream): An instance of ANTLR4 CommonTokenStream class

            scope_class_name(str): Name of the class in which the refactoring has to be done

            target_method_name(str): Name of the method in which the refactoring has to be done

            new_name(str): The new name of the refactored method

        Returns:

            RenameMethodListener: An instance of RenameMethodListener class

    """

    self.file_path = java_file_path
    self.token_stream = common_token_stream
    self.token_stream_rewriter = TokenStreamRewriter(common_token_stream)
    self.class_name = scope_class_name
    self.method_name = target_method_name
    self.new_method_name = new_name
    self.in_class = False
    self.changed = False
    self.reference = reference

get_method_calls(udb_path, scope_class_name, new_name)

Finds all of the refactored method calls in the database file and returns all of the correct references

!!! args udb_path (str): Address path to the database file

 scope_class_name (str): Name of the class in which the refactoring has to be done

 new_name (str): The new name of the refactored method

!!! returns References

Source code in codart\refactorings\rename_method.py
def get_method_calls(udb_path, scope_class_name, new_name):
    # Open Database
    """Finds all of the refactored method calls in the database file
       and returns all of the correct references

        Args:
            udb_path (str): Address path to the database file

            scope_class_name (str): Name of the class in which the refactoring has to be done

            new_name (str): The new name of the refactored method

        Returns:
            References
    """
    if not os.path.exists(path=udb_path):
        raise ValueError("Database file does not exist!")
    db = und.open(udb_path)
    method_scope = scope_class_name + "." + new_name
    references = []
    # Find All Method Calls
    for ent in sorted(db.ents(), key=lambda ent: ent.name()):
        for ref in ent.refs(refkindstring="Call"):
            scope = str(ref.ent())
            if scope == method_scope:
                references.append({
                    "scope": str(ref.scope()),
                    "file_name": str(ref.file()),
                    "file_path": str(ref.file().longname()),
                    "line": ref.line(),
                    "column": ref.column()
                })
    db.close()
    return references

rename_method(java_file_path, scope_class_name, target_method_name, new_name, reference=None)

Main Entry Point to the Listener and Tree Walker

Parameters:

Name Type Description Default
java_file_path(str)

Address path to the test/source file

required
scope_class_name(str)

Name of the class in which the refactoring has to be done

required
target_method_name(str)

Name of the method in which the refactoring has to be done

required
new_name(str)

The new name of the refactored method

required
reference(str)

Keeping track for all of the method references in the project scope

required

Returns:

Type Description

No Returns

Source code in codart\refactorings\rename_method.py
def rename_method(java_file_path, scope_class_name, target_method_name, new_name, reference=None):
    """Main Entry Point to the Listener and Tree Walker

    Args:
        java_file_path(str): Address path to the test/source file

        scope_class_name(str): Name of the class in which the refactoring has to be done

        target_method_name(str): Name of the method in which the refactoring has to be done

        new_name(str): The new name of the refactored method

        reference(str): Keeping track for all of the method references in the project scope

    Returns:
        No Returns
   """
    stream = FileStream(java_file_path)
    lexer = JavaLexer(stream)
    tokens = CommonTokenStream(lexer)
    parser = JavaParserLabeled(tokens)
    tree = parser.compilationUnit()
    listener = RenameMethodListener(
        java_file_path=java_file_path,
        common_token_stream=tokens,
        scope_class_name=scope_class_name,
        target_method_name=target_method_name,
        new_name=new_name,
        reference=reference
    )
    walker = ParseTreeWalker()
    walker.walk(listener, tree)
    if listener.changed:
        # print(java_file_path)
        new_file = open(file=java_file_path, mode='w')
        new_file.write(listener.token_stream_rewriter.getDefaultText().replace('\r', ''))

Implementation 2

Introduction

When the name of a method does not explain what the method does (method's functionality), it needs to be changed.

The module implements a light-weight version of Rename Method refactoring described in rename_method.py

Pre-conditions:

Todo: Add pre-conditions

Post-conditions:

Todo: Add post-conditions

RenameMethodRefactoringListener (JavaParserLabeledListener)

The class implements Rename Method refactoring. The Main listener which parses the file based on the provided information, using ANTLR parser generator and tokenization methods

Source code in codart\refactorings\rename_method2.py
class RenameMethodRefactoringListener(JavaParserLabeledListener):
    """

    The class implements Rename Method refactoring.
    The Main listener which parses the file based on the provided information, \
        using ANTLR parser generator and tokenization methods

    """
    def __init__(self,
                 common_token_stream: CommonTokenStream = None,
                 package_name: str = None,
                 scope_class_name: str = None,
                 method_identifier: str = None,
                 method_new_name: str = None):
        """

        Initializer of rename method refactoring listener

            Args:

                common_token_stream (CommonTokenStream): An instance of ANTLR4 CommonTokenStream class

                package_name(str): Name of the package in which the refactoring has to be done

                scope_class_name(str): Name of the class in which the refactoring has to be done

                method_identifier(str): Name of the method in which the refactoring has to be done

                method_new_name(str): The new name of the refactored method

            Returns:

                RenameMethodListener: An instance of RenameMethodListener class
        """

        self.token_stream = common_token_stream
        self.class_identifier = scope_class_name
        self.method_identifier = method_identifier
        self.method_new_name = method_new_name
        self.package_identifier = package_name

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

    def enterPackageDeclaration(self, ctx: JavaParserLabeled.PackageDeclarationContext):
        if self.package_identifier == ctx.qualifiedName().getText():
            self.in_selected_package = True
            print("Package " + self.package_identifier + " Found")

    def enterImportDeclaration(self, ctx: JavaParserLabeled.ImportDeclarationContext):
        if ctx.getText() == "import" + self.package_identifier + "." + self.class_identifier + ";" \
                or ctx.getText() == "import" + self.package_identifier + ".*" + ";" \
                or ctx.getText() == "import" + self.package_identifier + ";":
            self.is_package_imported = True
            print("package " + self.package_identifier + " imported")

    def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext):
        if self.is_package_imported or self.in_selected_package:
            if ctx.IDENTIFIER().getText() == self.class_identifier:
                self.in_class = True

    def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext):
        if self.is_package_imported or self.in_selected_package:
            if ctx.IDENTIFIER().getText() == self.class_identifier:
                self.in_class = False

    def enterMethodDeclaration(self, ctx: JavaParserLabeled.MethodDeclarationContext):
        if self.is_package_imported or self.in_selected_package:
            if self.in_class:
                if ctx.IDENTIFIER().getText() == self.method_identifier:
                    self.token_stream_rewriter.replaceIndex(
                        index=ctx.start.tokenIndex + 2,
                        text=self.method_new_name)
                    print("method name changed !")

    def enterMethodCall0(self, ctx: JavaParserLabeled.MethodCall0Context):
        if self.is_package_imported or self.in_selected_package:
            if self.in_class:
                if ctx.IDENTIFIER().getText() == self.method_identifier:
                    self.token_stream_rewriter.replaceIndex(
                        index=ctx.start.tokenIndex,
                        text=self.method_new_name)
                    print("method call name changed !")

__init__(self, common_token_stream=None, package_name=None, scope_class_name=None, method_identifier=None, method_new_name=None) special

Initializer of rename method refactoring listener

Args:

    common_token_stream (CommonTokenStream): An instance of ANTLR4 CommonTokenStream class

    package_name(str): Name of the package in which the refactoring has to be done

    scope_class_name(str): Name of the class in which the refactoring has to be done

    method_identifier(str): Name of the method in which the refactoring has to be done

    method_new_name(str): The new name of the refactored method

Returns:

    RenameMethodListener: An instance of RenameMethodListener class
Source code in codart\refactorings\rename_method2.py
def __init__(self,
             common_token_stream: CommonTokenStream = None,
             package_name: str = None,
             scope_class_name: str = None,
             method_identifier: str = None,
             method_new_name: str = None):
    """

    Initializer of rename method refactoring listener

        Args:

            common_token_stream (CommonTokenStream): An instance of ANTLR4 CommonTokenStream class

            package_name(str): Name of the package in which the refactoring has to be done

            scope_class_name(str): Name of the class in which the refactoring has to be done

            method_identifier(str): Name of the method in which the refactoring has to be done

            method_new_name(str): The new name of the refactored method

        Returns:

            RenameMethodListener: An instance of RenameMethodListener class
    """

    self.token_stream = common_token_stream
    self.class_identifier = scope_class_name
    self.method_identifier = method_identifier
    self.method_new_name = method_new_name
    self.package_identifier = package_name

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