Rename class
Implementation 1
Introduction
When the name of a class does not explain what the class does (class's functionality), it needs to be changed.
Pre-conditions:
Todo: Add pre-conditions
Post-conditions:
Todo: Add post-conditions
RenameClassRefactoringListener (JavaParserLabeledListener)
The class performs Rename Class 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_class.py
class RenameClassRefactoringListener(JavaParserLabeledListener):
"""
The class performs Rename Class 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: CommonTokenStream = None,
class_new_name: str = None,
class_identifier: str = None,
package_identifier: str = None):
"""
Initializer of rename class refactoring listener
Args:
java_file_path(str): Address path to the test/source file
common_token_stream (CommonTokenStream): An instance of ANTLR4 CommonTokenStream class
class_new_name(str): The new name of the refactored class
class_identifier(str): Name of the class in which the refactoring has to be done
package_identifier(str): Name of the package in which the refactoring has to be done
Returns:
RenameMethodListener: An instance of RenameClassRefactoringListener class
"""
self.file_path = java_file_path
self.token_stream = common_token_stream
self.class_new_name = class_new_name
self.class_identifier = class_identifier
self.package_identifier = package_identifier
self.in_class = False
self.changed = False
self.declared_objects_names = []
self.is_package_imported = False
self.in_selected_package = False
self.in_selected_class = False
self.in_some_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):
self.in_some_package = True
if self.package_identifier is not None:
print(ctx.qualifiedName())
print(ctx.getText())
if self.package_identifier == ctx.qualifiedName().getText():
self.in_selected_package = True
print("Package Found")
def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext):
if self.package_identifier is None \
and not self.in_some_package \
or self.package_identifier is not None \
and self.in_selected_package:
if ctx.IDENTIFIER().getText() == self.class_identifier:
print("Class Found")
self.in_selected_class = True
self.token_stream_rewriter.replaceIndex(
index=ctx.start.tokenIndex + 2,
text=self.class_new_name)
self.changed = True
def enterImportDeclaration(self, ctx: JavaParserLabeled.ImportDeclarationContext):
if self.package_identifier is not None:
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
if ctx.getText() == "import" + self.package_identifier + "." + self.class_identifier + ";":
self.token_stream_rewriter.replaceIndex(
index=ctx.qualifiedName().start.tokenIndex + 2 * len(ctx.qualifiedName().IDENTIFIER()) - 2,
text=self.class_new_name)
self.changed = True
def enterConstructorDeclaration(self, ctx: JavaParserLabeled.ConstructorDeclarationContext):
if self.in_selected_package and ctx.IDENTIFIER().getText() == self.class_identifier:
self.token_stream_rewriter.replaceIndex(
index=ctx.start.tokenIndex,
text=self.class_new_name)
self.changed = True
def exitFieldDeclaration(self, ctx: JavaParserLabeled.FieldDeclarationContext):
if self.package_identifier is None \
or self.package_identifier is not None \
and self.is_package_imported:
if ctx.typeType().getText() == self.class_identifier:
# change the name class; (we find right class then change the name class)
self.token_stream_rewriter.replaceIndex(
index=ctx.typeType().start.tokenIndex,
text=self.class_new_name)
self.changed = True
print("class name has change to new_class_name")
# def enterExpressionName2(self, ctx:Java9_v2Parser.ExpressionName1Context):
# if self.is_package_imported \
# or self.package_identifier is None \
# or self.in_selected_package:
# if ctx.getText() == self.class_identifier:
# self.token_stream_rewriter.replaceIndex(
# index=ctx.start.tokenIndex,
# text=self.class_identifier)
#
def exitPrimary4(self, ctx: JavaParserLabeled.Primary4Context):
if self.is_package_imported \
or self.package_identifier is None \
or self.in_selected_package:
if ctx.getText() == self.class_identifier:
self.token_stream_rewriter.replaceIndex(
index=ctx.start.tokenIndex,
text=self.class_new_name)
self.changed = True
def enterCreatedName0(self, ctx: JavaParserLabeled.CreatedName0Context):
if self.is_package_imported \
or self.package_identifier is None \
or self.in_selected_package:
if ctx.getText() == self.class_identifier:
print("ClassInstanceCreationExpression_lfno_primary1")
self.token_stream_rewriter.replaceIndex(
index=ctx.start.tokenIndex,
text=self.class_new_name)
self.changed = True
__init__(self, java_file_path, common_token_stream=None, class_new_name=None, class_identifier=None, package_identifier=None)
special
Initializer of rename class refactoring listener
Parameters:
Name | Type | Description | Default |
---|---|---|---|
java_file_path(str) |
Address path to the test/source file |
required | |
common_token_stream |
CommonTokenStream |
An instance of ANTLR4 CommonTokenStream class |
None |
class_new_name(str) |
The new name of the refactored class |
required | |
class_identifier(str) |
Name of the class in which the refactoring has to be done |
required | |
package_identifier(str) |
Name of the package in which the refactoring has to be done |
required |
Returns:
Type | Description |
---|---|
RenameMethodListener |
An instance of RenameClassRefactoringListener class |
Source code in codart\refactorings\rename_class.py
def __init__(self, java_file_path,
common_token_stream: CommonTokenStream = None,
class_new_name: str = None,
class_identifier: str = None,
package_identifier: str = None):
"""
Initializer of rename class refactoring listener
Args:
java_file_path(str): Address path to the test/source file
common_token_stream (CommonTokenStream): An instance of ANTLR4 CommonTokenStream class
class_new_name(str): The new name of the refactored class
class_identifier(str): Name of the class in which the refactoring has to be done
package_identifier(str): Name of the package in which the refactoring has to be done
Returns:
RenameMethodListener: An instance of RenameClassRefactoringListener class
"""
self.file_path = java_file_path
self.token_stream = common_token_stream
self.class_new_name = class_new_name
self.class_identifier = class_identifier
self.package_identifier = package_identifier
self.in_class = False
self.changed = False
self.declared_objects_names = []
self.is_package_imported = False
self.in_selected_package = False
self.in_selected_class = False
self.in_some_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')
rename_class(java_file_path, package_identifier, class_identifier, class_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_class.py
def rename_class(java_file_path, package_identifier, class_identifier, class_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 = RenameClassRefactoringListener(
java_file_path=java_file_path,
common_token_stream=tokens,
class_new_name=class_new_name,
class_identifier=class_identifier,
package_identifier=package_identifier
)
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', ''))
# def enterTypeName1(self, ctx:Java9_v2Parser.TypeName1Context):
# if self.is_package_imported \
# or self.package_identifier is None \
# or self.in_selected_package:
# if ctx.identifier().getText() == self.class_identifier:
# print(" type name 1")
# self.token_stream_rewriter.replaceIndex(
# index=ctx.identifier().start.tokenIndex,
# text=self.class_new_name)
#
#
# 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')
Implementation 2
Introduction
When the name of a class does not explain what the class does (class's functionality), it needs to be changed.
The module implements a light-weight version of Rename Class refactoring described in rename_class.py
Pre-conditions:
Todo: Add pre-conditions
Post-conditions:
Todo: Add post-conditions
RenameClassRefactoringListener (JavaParserLabeledListener)
The class implements rename class refactoring
Source code in codart\refactorings\rename_class2.py
class RenameClassRefactoringListener(JavaParserLabeledListener):
"""
The class implements rename class refactoring
"""
def __init__(self,
common_token_stream: CommonTokenStream = None,
package_name: str = None,
class_identifier: str = None,
class_new_name: str = None):
"""
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
class_identifier(str): Name of the class in which the refactoring has to be done
class_new_name(str): The new name of the refactored class
Returns:
RenameMethodListener: An instance of RenameClassRefactoringListener class
"""
self.token_stream = common_token_stream
self.class_new_name = class_new_name
self.class_identifier = class_identifier
self.package_identifier = package_name
self.is_package_imported = False
self.in_selected_package = False
self.in_selected_class = False
self.in_some_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):
self.in_some_package = True
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")
if ctx.getText() == "import" + self.package_identifier + "." + self.class_identifier + ";":
self.token_stream_rewriter.replaceIndex(
index=ctx.qualifiedName().start.tokenIndex + 2 * len(ctx.qualifiedName().IDENTIFIER()) - 2,
text=self.class_new_name)
print("class name in package changed")
def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext):
if self.is_package_imported or self.in_selected_package:
if ctx.IDENTIFIER().getText() == self.class_identifier:
self.token_stream_rewriter.replaceIndex(
index=ctx.start.tokenIndex + 2,
text=self.class_new_name)
change_file_name(self.class_identifier, self.class_new_name)
print("class name : " + self.class_identifier + " in class declaration changed ")
def enterCreatedName0(self, ctx: JavaParserLabeled.CreatedName0Context):
if self.is_package_imported or self.in_selected_package:
if ctx.IDENTIFIER(0).getText() == self.class_identifier:
self.token_stream_rewriter.replaceIndex(
index=ctx.start.tokenIndex,
text=self.class_new_name)
print("class name in creator changed")
def enterClassOrInterfaceType(self, ctx:JavaParserLabeled.ClassOrInterfaceTypeContext):
if self.is_package_imported or self.in_selected_package:
if ctx.IDENTIFIER(0).getText() == self.class_identifier:
self.token_stream_rewriter.replaceIndex(
index=ctx.start.tokenIndex,
text=self.class_new_name)
print("class type changed")
def enterConstructorDeclaration(self, ctx: JavaParserLabeled.ConstructorDeclarationContext):
if self.is_package_imported or self.in_selected_package:
if ctx.IDENTIFIER().getText() == self.class_identifier:
self.token_stream_rewriter.replaceIndex(
index=ctx.start.tokenIndex,
text=self.class_new_name)
print("constructor name changed !")
__init__(self, common_token_stream=None, package_name=None, class_identifier=None, class_new_name=None)
special
Parameters:
Name | Type | Description | Default |
---|---|---|---|
common_token_stream |
CommonTokenStream |
An instance of ANTLR4 CommonTokenStream class |
None |
package_name(str) |
Name of the package in which the refactoring has to be done |
required | |
class_identifier(str) |
Name of the class in which the refactoring has to be done |
required | |
class_new_name(str) |
The new name of the refactored class |
required |
Returns:
Type | Description |
---|---|
RenameMethodListener |
An instance of RenameClassRefactoringListener class |
Source code in codart\refactorings\rename_class2.py
def __init__(self,
common_token_stream: CommonTokenStream = None,
package_name: str = None,
class_identifier: str = None,
class_new_name: str = None):
"""
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
class_identifier(str): Name of the class in which the refactoring has to be done
class_new_name(str): The new name of the refactored class
Returns:
RenameMethodListener: An instance of RenameClassRefactoringListener class
"""
self.token_stream = common_token_stream
self.class_new_name = class_new_name
self.class_identifier = class_identifier
self.package_identifier = package_name
self.is_package_imported = False
self.in_selected_package = False
self.in_selected_class = False
self.in_some_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')