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.") return method_ent = method_ent[0] if method_ent.simplename() != source_method: logger.error("Invalid entity.") return if not method_ent.kind().check("Public"): logger.error("Method is not public.") return for ent in method_ent.ents("CallBy"): if f"{source_package}.{source_class}" not in ent.longname(): logger.error("Method cannot set to private.") return parent = method_ent.parent() while parent.parent() is not None: parent = parent.parent() main_file = parent.longname() parse_and_walk(file_path=main_file, listener_class=DecreaseMethodVisibilityListener, has_write=True, source_class=source_class, source_method=source_method) db.close()
def do_refactor(self): if not self.check_preconditions(): 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 os.remove(self.class_dir) # Write the new class with open(self.new_class_path, 'w') as f: package = "" if self.target_package != ROOT_PACKAGE: package = f"package {self.target_package};\n\n" imports = "" if self.source_package != ROOT_PACKAGE: imports = f"import {self.source_package}.*;\n\n" f.write(package + imports + self.class_content) return True
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.") return field_ent = field_ent[0] if field_ent.simplename() != source_field: logger.error("Invalid entity.") return if not field_ent.kind().check("Private"): logger.error("Field is not private.") return parent = field_ent.parent() while parent.parent() is not None: parent = parent.parent() main_file = parent.longname() parse_and_walk(file_path=main_file, listener_class=IncreaseFieldVisibilityListener, has_write=True, source_class=source_class, source_field=source_field) db.close()
def main(udb_path, source_package, source_class, method_name, target_classes: list, *args, **kwargs): 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: logger.error(f"Cannot find source class: {source_class}") return 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}") return method_ent = db.lookup(f"{source_package}.{source_class}.{method_name}", "Method") if len(method_ent) == 0: logger.error(f"Cannot find method to pushdown: {method_name}") return else: method_ent = method_ent[0] for ref in source_class_ent.refs("extendBy"): if ref.ent().simplename() not in target_classes: logger.error("Target classes are not children classes") return target_class_ents.append(ref.ent()) for ref in method_ent.refs("callBy"): if ref.file().simplename().split(".")[0] in target_classes: continue else: logger.error("Method has dependencies.") return # 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()
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.") return field_ent = field_ent[0] if field_ent.simplename() != source_field: logger.error("Invalid entity.") return if not field_ent.kind().check("Public"): logger.error("Field is not public.") return 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.") return parent = field_ent.parent() while parent.parent() is not None: parent = parent.parent() main_file = parent.longname() parse_and_walk(file_path=main_file, listener_class=DecreaseFieldVisibilityListener, has_write=True, source_class=source_class, source_field=source_field) db.close()
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 None 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 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 source_package not in con.parent().longname(): logger.error("Source package does not match.") db.close() return 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()
def main(source_class: str, source_package: str, target_class: str, target_package: str, field_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) # 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 None if source_package == target_package and source_class == target_class: logger.error("Can not move to self.") db.close() return None 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 None # 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 # 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()
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.refs("Extend ~Implicit, ExtendBy, Implement"): logger.error("Class is in inheritance or implements an interface.") db.close() return None # 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 None 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 None if source_package == target_package and source_class == target_class: logger.error("Can not move to self.") db.close() return None 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 None # 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 None # 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()