Skip to content

Increase field visibility

Introduction

Increase field visibility refactoring

Increase the visibility of a field from private to package, package to protected or protected to public.

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 increase the target field's visibility.

Post-conditions:

No specific post-condition

IncreaseFieldVisibilityListener (JavaParserLabeledListener)

To implement ِIncrease Field Visibility refactoring based on its actors.

Detects the required field and increases/changes its visibility status.

Source code in codart\refactorings\increase_field_visibility.py
class IncreaseFieldVisibilityListener(JavaParserLabeledListener):
    """

    To implement ِIncrease Field Visibility refactoring based on its actors.

    Detects the required field and increases/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 (IncreaseFieldVisibilityListener): An instance of IncreaseFieldVisibilityListener

        """

        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:
            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="public "
                        )
                    else:
                        self.rewriter.replaceSingleToken(
                            ctx.memberDeclaration().getChild(0).getChild(0).start,
                            text="public " + ctx.memberDeclaration().getChild(0).getChild(0).getText()
                        )
                else:
                    if ctx.modifier(0).getText() == 'private' or ctx.modifier(0).getText() == 'protected':
                        self.rewriter.replaceSingleToken(
                            token=ctx.modifier(0).start,
                            text="public "
                        )
                    else:
                        self.rewriter.insertBeforeToken(
                            token=ctx.modifier(0).start,
                            text="public "
                        )
            else:
                if ctx.memberDeclaration().getChild(0).getChild(0) is not None:
                    self.rewriter.insertBeforeToken(
                        ctx.memberDeclaration().getChild(0).getChild(0).start,
                        text="public "
                    )
            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 (IncreaseFieldVisibilityListener)

An instance of IncreaseFieldVisibilityListener

Source code in codart\refactorings\increase_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 (IncreaseFieldVisibilityListener): An instance of IncreaseFieldVisibilityListener

    """

    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\increase_field_visibility.py
def main(udb_path, source_package, source_class, source_field, *args, **kwargs):
    """


    """

    db = und.open(udb_path)
    fields = db.lookup(f"{source_package}.{source_class}.{source_field}", "Variable")

    if len(fields) == 0:
        logger.error("Invalid inputs.")
        db.close()
        return False

    field_ent = fields[0]
    if field_ent.simplename() != source_field:
        logger.error("Invalid entity.")
        db.close()
        return False

    # Strong overlay precondition
    # if not field_ent.kind().check("private"):
    #     logger.error("Field is not private.")
    #     db.close()
    #     return False

    parent = field_ent.parent()
    while parent.parent() is not None:
        parent = parent.parent()

    main_file = str(parent.longname())
    db.close()

    parse_and_walk(
        file_path=main_file,
        listener_class=IncreaseFieldVisibilityListener,
        has_write=True,
        source_class=source_class,
        source_field=source_field
    )
    # db.close()
    return True