Decrease field visibility
Introduction
Decrease field visibility refactoring
Decrease the visibility of a field from public to protected, protected to package or package to private.
Pre and post-conditions
Pre-conditions:
User must enter the field's name, and the source class's name for the refactoring in order to decrease the target field's visibility.
Post-conditions:
No specific post-condition
DecreaseFieldVisibilityListener (JavaParserLabeledListener)
To implement ِDecrease Field Visibility refactoring based on its actors.
Detects the required field and decreases/changes its visibility status.
Source code in codart\refactorings\decrease_field_visibility.py
class DecreaseFieldVisibilityListener(JavaParserLabeledListener):
"""
To implement ِDecrease Field Visibility refactoring based on its actors.
Detects the required field and decreases/changes its visibility status.
"""
def __init__(self, source_class, source_field, rewriter: TokenStreamRewriter):
"""
Args:
source_class (str): Name of the class in which the refactoring has to be done
source_field (str): Name of the field whose visibility status has to be changed
rewriter (CommonTokenStream): An instance of TokenStreamRewriter
Returns:
object (DecreaseFieldVisibilityListener): An instance of DecreaseFieldVisibilityListener
"""
self.source_class = source_class
self.source_field = source_field
self.in_class = False
self.in_field = False
self.detected_field = False
self.rewriter = rewriter
def enterClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext):
if ctx.IDENTIFIER().getText() == self.source_class:
self.in_class = True
def exitClassDeclaration(self, ctx: JavaParserLabeled.ClassDeclarationContext):
if ctx.IDENTIFIER().getText() == self.source_class:
self.in_class = False
def enterFieldDeclaration(self, ctx: JavaParserLabeled.FieldDeclarationContext):
self.in_field = True
def exitFieldDeclaration(self, ctx: JavaParserLabeled.FieldDeclarationContext):
self.in_field = False
def enterVariableDeclaratorId(self, ctx: JavaParserLabeled.VariableDeclaratorIdContext):
if ctx.IDENTIFIER().getText() == self.source_field and self.in_field:
self.detected_field = True
def exitClassBodyDeclaration2(self, ctx: JavaParserLabeled.ClassBodyDeclaration2Context):
if self.detected_field:
# print(ctx.getText())
if ctx.modifier(0) is not None:
if "@" in ctx.modifier(0).getText():
if ctx.modifier(1) is not None:
self.rewriter.replaceSingleToken(
token=ctx.modifier(1).start,
text="private "
)
else:
self.rewriter.replaceSingleToken(
ctx.memberDeclaration().getChild(0).getChild(0).start,
text="private " + ctx.memberDeclaration().getChild(0).getChild(0).getText()
)
else:
if ctx.modifier(0).getText() == 'public' or ctx.modifier(0).getText() == 'protected':
self.rewriter.replaceSingleToken(
token=ctx.modifier(0).start,
text="private "
)
else:
self.rewriter.insertBeforeToken(
token=ctx.modifier(0).start,
text="private "
)
else:
if ctx.memberDeclaration().getChild(0).getChild(0) is not None:
self.rewriter.insertBeforeToken(
ctx.memberDeclaration().getChild(0).getChild(0).start,
text="private "
)
# print("private " + ctx.memberDeclaration().getText())
self.detected_field = False
__init__(self, source_class, source_field, rewriter)
special
Parameters:
Name | Type | Description | Default |
---|---|---|---|
source_class |
str |
Name of the class in which the refactoring has to be done |
required |
source_field |
str |
Name of the field whose visibility status has to be changed |
required |
rewriter |
CommonTokenStream |
An instance of TokenStreamRewriter |
required |
Returns:
Type | Description |
---|---|
object (DecreaseFieldVisibilityListener) |
An instance of DecreaseFieldVisibilityListener |
Source code in codart\refactorings\decrease_field_visibility.py
def __init__(self, source_class, source_field, rewriter: TokenStreamRewriter):
"""
Args:
source_class (str): Name of the class in which the refactoring has to be done
source_field (str): Name of the field whose visibility status has to be changed
rewriter (CommonTokenStream): An instance of TokenStreamRewriter
Returns:
object (DecreaseFieldVisibilityListener): An instance of DecreaseFieldVisibilityListener
"""
self.source_class = source_class
self.source_field = source_field
self.in_class = False
self.in_field = False
self.detected_field = False
self.rewriter = rewriter
main(udb_path, source_package, source_class, source_field, *args, **kwargs)
Source code in codart\refactorings\decrease_field_visibility.py
def main(udb_path, source_package, source_class, source_field, *args, **kwargs):
"""
"""
db = und.open(udb_path)
field_ent = db.lookup(f"{source_package}.{source_class}.{source_field}", "Variable")
if len(field_ent) == 0:
logger.error("Invalid inputs.")
db.close()
return False
field_ent = field_ent[0]
if field_ent.simplename() != source_field:
logger.error("Invalid entity.")
db.close()
return False
# Strong overlay precondition
# if not field_ent.kind().check("Public"):
# logger.error("Field is not public.")
# db.close()
# return False
for ref in field_ent.refs("Useby,Setby"):
ent = ref.ent()
if f"{source_package}.{source_class}" not in ent.longname():
logger.debug(f"{source_package}.{source_class} not in {ent.longname()}")
logger.error("Field cannot set to private.")
db.close()
return False
parent = field_ent.parent()
while parent.parent() is not None:
parent = parent.parent()
main_file = parent.longname()
db.close()
parse_and_walk(
file_path=main_file,
listener_class=DecreaseFieldVisibilityListener,
has_write=True,
source_class=source_class,
source_field=source_field
)
return True