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:
-
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.
-
Check if the method exist, then rename it.
Post-conditions:
- 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')