示例#1
0
    def do_refactor(self):
        if not self.check_preconditions():
            config.logger.error("Pre conditions failed.")
            return False

        # Update usages
        for file_path in self.usages:
            parse_and_walk(file_path=file_path,
                           listener_class=UpdateImportsListener,
                           has_write=True,
                           source_package=self.source_package,
                           target_package=self.target_package,
                           class_name=self.class_name)

        # Delete source class
        # config.logger.debug(f'Current class path to be removed: {self._class_current_path}')
        os.remove(self._class_current_path)

        # Write the new class
        package = ""
        if self.target_package != ROOT_PACKAGE:
            package = f"package {self.target_package};\n"
        imports = ""
        if self.source_package != ROOT_PACKAGE:
            imports = f"import {self.source_package}.*;\n"

        # logger.debug(f'New class path to be added: {self._class_new_path}')
        with open(self._class_new_path,
                  mode='w',
                  encoding='utf8',
                  errors='ignore') as f:
            f.write(package + imports + self.class_content)

        return True
示例#2
0
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
def main(udb_path, source_package, source_class, source_method, *args,
         **kwargs):
    """


    """

    db = und.open(udb_path)
    method_ent = db.lookup(f"{source_package}.{source_class}.{source_method}",
                           "Method")

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

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

    # Strong overlay precondition
    # if not method_ent.kind().check("Public"):
    #     logger.error("Method is not public.")
    #     db.close()
    #     return False

    for ent in method_ent.ents("CallBy"):
        if f"{source_package}.{source_class}" not in ent.longname():
            logger.error("Method cannot set to private.")
            db.close()
            return False

    parent = method_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=DecreaseMethodVisibilityListener,
                   has_write=True,
                   source_class=source_class,
                   source_method=source_method)

    return True
示例#4
0
def main(udb_path, source_package, source_class, source_method, *args,
         **kwargs):
    """


    """

    db = und.open(udb_path)
    methods = db.lookup(f"{source_package}.{source_class}.{source_method}",
                        "Method")

    if methods is None or len(methods) == 0:
        logger.error("Invalid inputs.")
        db.close()
        return False

    method_entity = methods[0]
    if method_entity.simplename() != source_method:
        logger.error("Invalid entity.")
        db.close()
        return False

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

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

    main_file = parent.longname()  # The file that contain the method
    db.close()

    parse_and_walk(file_path=main_file,
                   listener_class=IncreaseMethodVisibilityListener,
                   has_write=True,
                   source_class=source_class,
                   source_method=source_method)
    # db.close()
    return True
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
示例#6
0
def main(source_class: str, source_package: str, target_class: str, target_package: str, method_name: str,
         udb_path: str, *args, **kwargs):
    """


    """

    import_statement = None
    if source_package != target_package:
        import_statement = f"\nimport {target_package}.{target_class};"
    instance_name = target_class.lower() + "ByCodArt"
    db = und.open(udb_path)
    method_map, class_ent = get_source_class_map(db, source_class)
    if class_ent is None:
        logger.error("Class entity is None")
        return False

    # Strong overlay precondition
    # if class_ent.refs("Extend ~Implicit, ExtendBy, Implement"):
    #     logger.error("Class is in inheritance or implements an interface.")
    #     db.close()
    #     return False

    # Check if method is static
    method_ent = db.lookup(f"{source_package}.{source_class}.{method_name}", "Method")
    if len(method_ent) >= 1:
        method_ent = method_ent[0]
    else:
        logger.error("Entity not found.")
        db.close()
        return False

    if method_ent.simplename() != method_name:
        logger.error("Can not move method duo to duplicated entities.")
        logger.info(f"{method_ent}, {method_ent.kindname()}")
        db.close()
        return False

    if source_package == target_package and source_class == target_class:
        logger.error("Can not move to self.")
        db.close()
        return False

    is_static = STATIC in method_ent.kindname()
    # Find usages
    usages = {}

    for ref in method_ent.refs("Callby"):
        file = ref.file().longname()
        if file in usages:
            usages[file].append(ref.line())
        else:
            usages[file] = [ref.line(), ]

    try:
        src_class_file = db.lookup(f"{source_package}.{source_class}.java", "File")[0].longname()
        target_class_file = db.lookup(f"{target_package}.{target_class}.java", "File")[0].longname()
    except IndexError:
        logger.error("This is a nested method.")
        logger.info(f"{source_package}.{source_class}.java")
        logger.info(f"{target_package}.{target_class}.java")
        db.close()
        return False

    db.close()

    # Check if there is an cycle
    listener = parse_and_walk(
        file_path=target_class_file,
        listener_class=CheckCycleListener,
        class_name=source_class
    )

    if not listener.is_valid:
        logger.error(f"Can not move method because there is a cycle between {source_class}, {target_class}")
        # db.close()
        return False

    # Propagate Changes
    for file in usages.keys():
        public_class_name = os.path.basename(file).split(".")[0]
        is_in_target_class = public_class_name == target_class
        parse_and_walk(
            file_path=file,
            listener_class=PropagateListener,
            has_write=True,
            method_name=method_name,
            new_name=f"{instance_name}.{method_name}",
            lines=usages[file],
            is_in_target_class=is_in_target_class,
            method_map=method_map,
        )
    # exit(-1)
    # Do the cut and paste!
    # Cut
    listener = parse_and_walk(
        file_path=src_class_file,
        listener_class=CutMethodListener,
        has_write=True,
        class_name=target_class,
        instance_name=instance_name,
        method_name=method_name,
        is_static=is_static,
        import_statement=import_statement,
    )

    method_text = listener.method_text

    # Paste
    listener = parse_and_walk(
        file_path=target_class_file,
        listener_class=PasteMethodListener,
        has_write=True,
        method_text=method_text,
        source_class=source_class,
        method_map=method_map,
        imports=listener.imports,
    )

    # Post-Paste: Reference Injection
    parse_and_walk(
        file_path=target_class_file,
        listener_class=ReferenceInjectorAndConstructorListener,
        has_write=True,
        method_text=method_text,
        source_class=source_class,
        method_map=method_map,
        imports=None,
        has_empty_cons=listener.has_empty_cons,
    )
    # db.close()
    return True
示例#7
0
def main(udb_path, source_package, target_class, class_names: list, *args,
         **kwargs):
    """

    """

    if len(class_names) < 2:
        logger.error("class_names is empty.")
        return False
    db = und.open(udb_path)
    parent_cons = []

    # Check children
    parent = db.lookup(f"{target_class}", "Public Class")
    if len(parent) != 1:
        logger.error("Count of target class is not 1.")
        db.close()
        return False
    parent = parent[0]
    parent_file = db.lookup(f"{target_class}.java", "File")[0].longname()

    for i in parent.ents("Define", "Constructor"):
        parent_cons.append(i.parameters())

    # Find constructor entities group by signature
    constructors = {}

    for child in class_names:
        cons = db.lookup(f"{child}.{child}", "Constructor")
        for con in cons:
            if con.parent() is not None:
                if source_package not in con.parent().longname():
                    logger.error("Source package does not match.")
                    db.close()
                    return False
            parameters = con.parameters()
            if parameters in constructors:
                constructors[parameters].append(con)
            else:
                constructors[parameters] = [con]

    # Find common statements
    for k in constructors:
        meta_data = {
            parent_file: {
                'is_father': True,
                'has_father_con': k in parent_cons,
                'class_name': parent.simplename()
            },
        }
        con = constructors[k][0]
        ents = []

        for ref in con.refs("Set"):
            data = {
                'is_father': False,
                'has_father_con': k in parent_cons,
                'class_name': con.parent().simplename()
            }
            if ref.file().longname() not in meta_data.keys():
                meta_data[ref.file().longname()] = data
            if target_class in ref.ent().longname():
                ents.append(ref.ent().simplename())

        for i in range(1, len(constructors[k])):
            con2 = constructors[k][i]
            for ref in con2.refs("Set"):
                data = {
                    'is_father': False,
                    'has_father_con': k in parent_cons,
                    'class_name': con2.parent().simplename()
                }
                if ref.file().longname() not in meta_data.keys():
                    meta_data[ref.file().longname()] = data
                if target_class in ref.ent().longname():
                    ents.append(ref.ent().simplename())

        ents = [
            item for item, count in collections.Counter(ents).items()
            if count > 1
        ]
        if len(meta_data.keys()) > 1:
            for file_name in meta_data:
                data = meta_data[file_name]
                parse_and_walk(file_name,
                               PullUpConstructorListener,
                               has_write=True,
                               is_father=data['is_father'],
                               has_father_con=data['has_father_con'],
                               common_sets=ents,
                               class_name=data['class_name'],
                               params=k)
    db.close()
    return True
示例#8
0
def main(source_class: str, source_package: str, target_class: str,
         target_package: str, field_name: str, udb_path: str, *args, **kwargs):
    """

    Move filed main API

    """

    import_statement = None
    if source_package != target_package:
        import_statement = f"\nimport {target_package}.{target_class};"
    instance_name = target_class.lower() + "ByCodArt"
    db = und.open(udb_path)

    # Check if field is static
    field_ent = db.lookup(f"{source_package}.{source_class}.{field_name}",
                          "Variable")
    if len(field_ent) == 0:
        logger.error(
            f"Entity not found with query: {source_package}.{source_class}.{field_name}."
        )
        db.close()
        return False

    if source_package == target_package and source_class == target_class:
        logger.error("Can not move to self.")
        db.close()
        return False

    field_ent = field_ent[0]
    is_static = field_ent.kindname() == STATIC

    if is_static:
        logger.warning("Field is static!")

    # Find usages
    usages = {}

    for ref in field_ent.refs("Setby, Useby"):
        file = ref.file().longname()
        if file in usages:
            usages[file].append(ref.line())
        else:
            usages[file] = [
                ref.line(),
            ]
    try:
        src_class_file = db.lookup(
            f"{source_package}.{source_class}.java")[0].longname()
        target_class_file = db.lookup(
            f"{target_package}.{target_class}.java")[0].longname()
    except IndexError:
        logger.error("This is a nested class.")
        logger.info(f"{source_package}.{source_class}.java")
        logger.info(f"{target_package}.{target_class}.java")
        db.close()
        return False

    db.close()

    # Check if there is an cycle
    listener = parse_and_walk(
        file_path=target_class_file,
        listener_class=CheckCycleListener,
        class_name=source_class,
    )

    if not listener.is_valid:
        logger.error(
            f"Can not move field because there is a cycle between {source_class}, {target_class}"
        )
        # db.close()
        return False

    # Propagate Changes
    for file in usages.keys():
        parse_and_walk(
            file_path=file,
            listener_class=PropagateListener,
            has_write=True,
            field_name=field_name,
            new_name=f"{instance_name}.{field_name}",
            lines=usages[file],
        )

    # Do the cut and paste!
    # Cut
    listener = parse_and_walk(file_path=src_class_file,
                              listener_class=CutFieldListener,
                              has_write=True,
                              class_name=target_class,
                              instance_name=instance_name,
                              field_name=field_name,
                              is_static=is_static,
                              import_statement=import_statement)

    field_text = listener.field_text

    # Paste
    parse_and_walk(
        file_path=target_class_file,
        listener_class=PasteFieldListener,
        has_write=True,
        field_text=field_text,
    )

    # db.close()
    return True
示例#9
0
def main(udb_path=None,
         source_package=None,
         source_class=None,
         field_name=None,
         target_classes: list = None,
         *args,
         **kwargs):
    """

    The main API for push-down field refactoring

    """

    if udb_path is None:
        db = und.open(codart.config.UDB_PATH)
    else:
        db = und.open(udb_path)

    source_class_ent = None
    source_class_ents = db.lookup(f"{source_package}.{source_class}", "Class")
    if len(source_class_ents) == 0:
        logger.error(f"Cannot find source class: {source_class}")
        db.close()
        return False
    else:
        for ent in source_class_ents:
            if ent.simplename() == source_class:
                source_class_ent = ent
                break

    if source_class_ent is None:
        logger.error(f"Cannot find source class: {source_class}")
        db.close()
        return False

    fields = db.lookup(f"{source_package}.{source_class}.{field_name}",
                       "Variable")
    if fields is None or len(fields) == 0:
        logger.error(f"Cannot find field to pushdown: {field_name}")
        db.close()
        return False
    else:
        field_ent = fields[0]

    target_class_ents_files = []
    target_class_ents_simplenames = []
    for ref in source_class_ent.refs("Extendby"):
        if ref.ent().simplename() not in target_classes:
            logger.error("Target classes are not children classes")
            db.close()
            return False
        target_class_ents_files.append(ref.ent().parent().longname())
        target_class_ents_simplenames.append(ref.ent().simplename())

    for ref in field_ent.refs("Useby, Setby"):
        if ref.file().simplename().split(".")[0] in target_classes:
            continue
        else:
            logger.error("Field has dependencies.")
            db.close()
            return False

    source_class_file = source_class_ent.parent().longname()
    db.close()

    # Remove field from source class
    listener = parse_and_walk(file_path=source_class_file,
                              listener_class=CutFieldListener,
                              has_write=True,
                              source_class=source_class,
                              field_name=field_name,
                              debug=False)

    # Insert field in children classes
    for i, target_class_file in enumerate(target_class_ents_files):
        parse_and_walk(file_path=target_class_file,
                       listener_class=PasteFieldListener,
                       has_write=True,
                       source_class=target_class_ents_simplenames[i],
                       field_content=listener.field_content,
                       import_statements=listener.import_statements,
                       debug=False)
    # db.close()
    return True
示例#10
0
def main(udb_path, source_package, source_class, method_name, target_classes: list, *args, **kwargs):
    """

    The main API for the push-down method refactoring (version 2)

    """

    db = und.open(udb_path)
    source_class_ents = db.lookup(f"{source_package}.{source_class}", "Class")
    target_class_ents = []
    source_class_ent = None

    if len(source_class_ents) == 0:
        config.logger.error(f"Cannot find source class: {source_class}")
        db.close()
        return False
    else:
        for ent in source_class_ents:
            if ent.simplename() == source_class:
                source_class_ent = ent
                break
    if source_class_ent is None:
        config.logger.error(f"Cannot find source class: {source_class}")
        db.close()
        return False

    method_ent = db.lookup(f"{source_package}.{source_class}.{method_name}", "Method")
    if len(method_ent) == 0:
        config.logger.error(f"Cannot find method to pushdown: {method_name}")
        db.close()
        return False
    else:
        method_ent = method_ent[0]

    for ref in source_class_ent.refs("extendBy"):
        if ref.ent().simplename() not in target_classes:
            config.logger.error("Target classes are not children classes")
            db.close()
            return False
        target_class_ents.append(ref.ent())

    for ref in method_ent.refs("callBy"):
        if ref.file().simplename().split(".")[0] in target_classes:
            continue
        else:
            config.logger.error("Method has dependencies.")
            db.close()
            return False

    # Remove field from source class
    listener = parse_and_walk(
        file_path=source_class_ent.parent().longname(),
        listener_class=CutMethodListener,
        has_write=True,
        source_class=source_class,
        method_name=method_name,
        debug=False
    )

    # Insert field in children classes
    for target_class in target_class_ents:
        parse_and_walk(
            file_path=target_class.parent().longname(),
            listener_class=PasteMethodListener,
            has_write=True,
            source_class=target_class.simplename(),
            method_content=listener.method_content,
            import_statements=listener.import_statements,
            debug=False
        )
    db.close()